From 33e84ea69dc622d5361a813c0ffc69702a1c8172 Mon Sep 17 00:00:00 2001 From: Tom Yu Date: Thu, 9 Aug 2007 22:07:13 +0000 Subject: [PATCH] fix svn:eol-style git-svn-id: svn://anonsvn.mit.edu/krb5/branches/krb5-1-6@19772 dc483132-0cff-0310-8789-dd5450dbe970 --- src/windows/build/bkw.pl | 60 +- src/windows/identity/doc/cred_aquisition.h | 426 +- src/windows/identity/doc/cred_data_types.h | 528 +- src/windows/identity/doc/cred_main.h | 72 +- src/windows/identity/doc/cred_msgs.h | 96 +- src/windows/identity/doc/cred_prop_pages.h | 168 +- src/windows/identity/doc/main_page.h | 332 +- src/windows/identity/doc/plugin_framework.h | 366 +- src/windows/identity/doc/plugin_locale.h | 218 +- src/windows/identity/doc/plugin_main.h | 230 +- src/windows/identity/doc/plugin_structure.h | 110 +- src/windows/identity/doc/ui_actions.h | 60 +- src/windows/identity/doc/ui_context.h | 376 +- src/windows/identity/doc/ui_main.h | 72 +- src/windows/identity/doc/ui_menus.h | 60 +- src/windows/identity/help/khhelp.h | 66 +- src/windows/identity/include/khdefs.h | 476 +- src/windows/identity/include/kherror.h | 370 +- src/windows/identity/include/khlist.h | 428 +- src/windows/identity/include/khmsgtypes.h | 1634 +-- src/windows/identity/include/netidmgr.h | 86 +- src/windows/identity/kconfig/api.c | 5312 ++++---- src/windows/identity/kconfig/kconfig.h | 1920 +-- .../identity/kconfig/kconfiginternal.h | 258 +- src/windows/identity/kconfig/kconfigmain.c | 74 +- src/windows/identity/kconfig/registry.c | 56 +- src/windows/identity/kconfig/test/utiltest.c | 414 +- src/windows/identity/kcreddb/attrib.c | 1756 +-- src/windows/identity/kcreddb/attrib.h | 110 +- src/windows/identity/kcreddb/buf.c | 782 +- src/windows/identity/kcreddb/buf.h | 156 +- src/windows/identity/kcreddb/credential.c | 2184 +-- src/windows/identity/kcreddb/credential.h | 142 +- src/windows/identity/kcreddb/credset.c | 2354 ++-- src/windows/identity/kcreddb/credset.h | 150 +- src/windows/identity/kcreddb/credtype.c | 816 +- src/windows/identity/kcreddb/credtype.h | 110 +- src/windows/identity/kcreddb/identity.c | 3198 ++--- src/windows/identity/kcreddb/identity.h | 120 +- src/windows/identity/kcreddb/init.c | 182 +- src/windows/identity/kcreddb/kcreddb.h | 6658 +++++----- .../identity/kcreddb/kcreddbinternal.h | 122 +- src/windows/identity/kcreddb/kcreddbmain.c | 80 +- src/windows/identity/kcreddb/langres.h | 96 +- src/windows/identity/kcreddb/resource.h | 54 +- src/windows/identity/kcreddb/type.c | 2772 ++-- src/windows/identity/kcreddb/type.h | 432 +- src/windows/identity/kherr/kherr.c | 2642 ++-- src/windows/identity/kherr/kherr.h | 2188 +-- src/windows/identity/kherr/kherrinternal.h | 138 +- src/windows/identity/kherr/kherrmain.c | 104 +- src/windows/identity/kmm/kmm.c | 384 +- src/windows/identity/kmm/kmm.h | 2136 +-- src/windows/identity/kmm/kmm_module.c | 1352 +- src/windows/identity/kmm/kmm_plugin.c | 828 +- src/windows/identity/kmm/kmm_reg.c | 672 +- src/windows/identity/kmm/kmm_registrar.c | 2076 +-- src/windows/identity/kmm/kmminternal.h | 516 +- src/windows/identity/kmm/kmmmain.c | 318 +- src/windows/identity/kmm/kplugin.h | 292 +- src/windows/identity/kmq/consumer.c | 1146 +- src/windows/identity/kmq/init.c | 626 +- src/windows/identity/kmq/kmq.h | 1402 +- src/windows/identity/kmq/kmqinternal.h | 478 +- src/windows/identity/kmq/kmqmain.c | 94 +- src/windows/identity/kmq/msgtype.c | 776 +- src/windows/identity/kmq/publisher.c | 1112 +- src/windows/identity/nidmgrdll/dllmain.c | 228 +- .../identity/plugins/common/dynimport.c | 954 +- .../identity/plugins/common/dynimport.h | 722 +- .../identity/plugins/common/krb5common.c | 902 +- .../identity/plugins/common/krb5common.h | 112 +- .../identity/plugins/krb4/errorfuncs.c | 452 +- .../identity/plugins/krb4/errorfuncs.h | 130 +- .../identity/plugins/krb4/krb4configdlg.c | 1078 +- src/windows/identity/plugins/krb4/krb4funcs.c | 1794 +-- src/windows/identity/plugins/krb4/krb4funcs.h | 264 +- src/windows/identity/plugins/krb4/krb4main.c | 314 +- .../identity/plugins/krb4/krb4newcreds.c | 1746 +-- .../identity/plugins/krb4/krb4plugin.c | 594 +- src/windows/identity/plugins/krb4/krbcred.h | 272 +- src/windows/identity/plugins/krb4/langres.h | 98 +- src/windows/identity/plugins/krb5/datarep.c | 814 +- src/windows/identity/plugins/krb5/datarep.h | 152 +- .../identity/plugins/krb5/errorfuncs.c | 594 +- .../identity/plugins/krb5/errorfuncs.h | 150 +- .../identity/plugins/krb5/krb5configcc.c | 1142 +- .../identity/plugins/krb5/krb5configid.c | 710 +- .../identity/plugins/krb5/krb5configids.c | 540 +- src/windows/identity/plugins/krb5/krb5funcs.c | 6974 +++++----- src/windows/identity/plugins/krb5/krb5funcs.h | 434 +- .../identity/plugins/krb5/krb5identpro.c | 3762 +++--- src/windows/identity/plugins/krb5/krb5main.c | 994 +- .../identity/plugins/krb5/krb5newcreds.c | 5494 ++++---- .../identity/plugins/krb5/krb5plugin.c | 530 +- src/windows/identity/plugins/krb5/krb5props.c | 352 +- src/windows/identity/plugins/krb5/krbcred.h | 488 +- src/windows/identity/plugins/krb5/langres.h | 432 +- .../sample/templates/credprov/config_id.c | 236 +- .../sample/templates/credprov/config_ids.c | 192 +- .../sample/templates/credprov/config_main.c | 198 +- .../sample/templates/credprov/credacq.c | 810 +- .../sample/templates/credprov/credprov.h | 352 +- .../sample/templates/credprov/credtype.c | 104 +- .../sample/templates/credprov/langres.h | 68 +- .../identity/sample/templates/credprov/main.c | 342 +- .../sample/templates/credprov/plugin.c | 764 +- .../sample/templates/credprov/proppage.c | 118 +- src/windows/identity/ui/aboutwnd.c | 308 +- src/windows/identity/ui/aboutwnd.h | 66 +- src/windows/identity/ui/addrchange.c | 188 +- src/windows/identity/ui/addrchange.h | 72 +- src/windows/identity/ui/appglobal.h | 286 +- src/windows/identity/ui/cfg_appear_wnd.c | 870 +- src/windows/identity/ui/cfg_general_wnd.c | 838 +- src/windows/identity/ui/cfg_identities_wnd.c | 3046 ++--- src/windows/identity/ui/cfg_notif_wnd.c | 682 +- src/windows/identity/ui/cfg_plugins_wnd.c | 1292 +- src/windows/identity/ui/configwnd.c | 2438 ++-- src/windows/identity/ui/configwnd.h | 176 +- src/windows/identity/ui/credfuncs.c | 2796 ++-- src/windows/identity/ui/credfuncs.h | 186 +- src/windows/identity/ui/credwnd.c | 10994 ++++++++-------- src/windows/identity/ui/credwnd.h | 600 +- src/windows/identity/ui/debugfuncs.c | 512 +- src/windows/identity/ui/debugfuncs.h | 74 +- src/windows/identity/ui/htwnd.c | 2572 ++-- src/windows/identity/ui/htwnd.h | 114 +- src/windows/identity/ui/khmapp.h | 140 +- src/windows/identity/ui/main.c | 1794 +-- src/windows/identity/ui/mainmenu.c | 2278 ++-- src/windows/identity/ui/mainmenu.h | 136 +- src/windows/identity/ui/mainwnd.h | 164 +- src/windows/identity/ui/notifier.c | 6320 ++++----- src/windows/identity/ui/notifier.h | 126 +- src/windows/identity/ui/passwnd.c | 266 +- src/windows/identity/ui/passwnd.h | 78 +- src/windows/identity/ui/propertywnd.c | 496 +- src/windows/identity/ui/propertywnd.h | 72 +- src/windows/identity/ui/reqdaemon.c | 906 +- src/windows/identity/ui/reqdaemon.h | 84 +- src/windows/identity/ui/resource.h | 830 +- src/windows/identity/ui/statusbar.c | 416 +- src/windows/identity/ui/statusbar.h | 110 +- src/windows/identity/ui/timer.c | 2030 +-- src/windows/identity/ui/timer.h | 200 +- src/windows/identity/ui/toolbar.c | 942 +- src/windows/identity/ui/toolbar.h | 104 +- src/windows/identity/uilib/action.c | 3312 ++--- src/windows/identity/uilib/alert.c | 874 +- src/windows/identity/uilib/configui.c | 2170 +-- src/windows/identity/uilib/configui.h | 148 +- src/windows/identity/uilib/creddlg.c | 1436 +- src/windows/identity/uilib/intaction.h | 216 +- src/windows/identity/uilib/khaction.h | 2010 +-- src/windows/identity/uilib/khactiondef.h | 336 +- src/windows/identity/uilib/khalerts.h | 806 +- src/windows/identity/uilib/khconfigui.h | 1254 +- src/windows/identity/uilib/khhtlink.h | 154 +- src/windows/identity/uilib/khnewcred.h | 1970 +-- src/windows/identity/uilib/khprops.h | 418 +- src/windows/identity/uilib/khremote.h | 168 +- src/windows/identity/uilib/khrescache.h | 200 +- src/windows/identity/uilib/khtracker.h | 228 +- src/windows/identity/uilib/khuidefs.h | 292 +- src/windows/identity/uilib/propsheet.c | 460 +- src/windows/identity/uilib/propwnd.c | 74 +- src/windows/identity/uilib/rescache.c | 606 +- src/windows/identity/uilib/trackerwnd.c | 948 +- src/windows/identity/uilib/uibind.c | 118 +- src/windows/identity/uilib/uilibmain.c | 88 +- src/windows/identity/uilib/version.c | 166 +- src/windows/identity/util/hashtable.c | 342 +- src/windows/identity/util/hashtable.h | 462 +- src/windows/identity/util/mstring.c | 1020 +- src/windows/identity/util/mstring.h | 722 +- src/windows/identity/util/perfstat.c | 822 +- src/windows/identity/util/perfstat.h | 148 +- src/windows/identity/util/sync.c | 260 +- src/windows/identity/util/sync.h | 256 +- src/windows/identity/util/utils.h | 74 +- src/windows/kfwlogon/kfwcommon.c | 2704 ++-- src/windows/kfwlogon/kfwcpcc.c | 78 +- src/windows/kfwlogon/kfwlogon.c | 1268 +- src/windows/kfwlogon/kfwlogon.h | 430 +- src/windows/winlevel.h | 66 +- 186 files changed, 82474 insertions(+), 82460 deletions(-) diff --git a/src/windows/build/bkw.pl b/src/windows/build/bkw.pl index 08a168243..94cc86dbd 100644 --- a/src/windows/build/bkw.pl +++ b/src/windows/build/bkw.pl @@ -237,22 +237,34 @@ sub main { if ($vverbose) {print "Debug -- Config: ".Dumper($config);} # Test the unix find command: - if (! exists $odr->{unixfind}->{value}) { - $odr->{unixfind}->{value} = "C:\\tools\\cygwin\\bin"; - } - local $unixfind = $odr->{unixfind}->{value}; - - local $savedPATH = $ENV{PATH}; - $ENV{PATH} = $unixfind.";".$savedPATH; - print "Info -- chdir to ".`cd`."\n" if ($verbose); - if (-e "a.tmp") {!system("rm a.tmp") or die "Fatal -- Couldn't clean temporary file a.tmp.";} - !system("find . -maxdepth 0 -name a.tmp > b.tmp 2>&1") or die "Fatal -- find test failed."; - local $filesize = -s "b.tmp"; - $ENV{PATH} = $savedPATH; - if ($filesize > 0) { - die "Fatal -- $unixfind does not appear to be a path to a UNIX find command."; + # List of directories where it might be: + my @find_dirs = ('c:\\cygwin\\bin', 'c:\\tools\\cygwin\\bin'); + if (exists $odr->{unixfind}->{value}) { ## Was an additional place to look specified? + push (@find_dirs, $odr->{unixfind}->{value}); } - + my $bFindFound = 0; + foreach my $dir (@find_dirs) { + if (-d $dir) { + local $savedPATH = $ENV{PATH}; + $ENV{PATH} = $dir.";".$savedPATH; + if (-e "a.tmp") {!system("rm a.tmp") or die "Fatal -- Couldn't clean temporary file a.tmp.";} + !system("find . -maxdepth 0 -name a.tmp > b.tmp 2>&1") or die "Fatal -- find test failed."; + local $filesize = -s "b.tmp"; + $ENV{PATH} = $savedPATH; + if ($filesize <= 0) { + $bFindFound = 1; + $odr->{unixfind}->{value} = $dir; + last; + } + } + } + if (! $bFindFound) { + print "Fatal -- unix find command not found in \n"; + map {print " $_ "} @find_dirs; + print "\n"; + die; + } + # Don't allow /svntag and /svnbranch simultaneously: if ( (length $odr->{svntag}->{value} > 0) && (length $odr->{svnbranch}->{value} > 0) ) { @@ -282,14 +294,6 @@ sub main { } } - print "Executing $cmdline\n"; - local $argvsize = @ARGV; - if ($argvsize > 0) { - print "\nArguments for NMAKE: "; - map {print " $_ "} @ARGV; - print "\n"; - } - # (------------------------------------------------) if ( (-d $wd) && ( ($rverb =~ /export/) || ($rverb =~ /checkout/) ) ) { print "\n\nHEADS UP!!\n\n"; @@ -311,6 +315,16 @@ sub main { $l->no_die_handler; ## Needed so XML::Simple won't throw exceptions. } + print "Executing $cmdline\n"; + local $argvsize = @ARGV; + if ($argvsize > 0) { + print "\nArguments for NMAKE: "; + map {print " $_ "} @ARGV; + print "\n"; + } + + print "Info -- Using unix find in $odr->{unixfind}->{value}\n" if ($verbose); + ##++ Begin repository action: if ($rverb =~ /skip/) {print "Info -- *** Skipping repository access.\n" if ($verbose);} else { diff --git a/src/windows/identity/doc/cred_aquisition.h b/src/windows/identity/doc/cred_aquisition.h index 30f626f8e..bce826dc8 100644 --- a/src/windows/identity/doc/cred_aquisition.h +++ b/src/windows/identity/doc/cred_aquisition.h @@ -1,213 +1,213 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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$ */ - -/*! \page cred_acq Managed credential acquisition - - Credential providers and identity providers must participate in - managed credential acquisition in order to respond to the user's - requests to obtain new credentials for an identity or to renew - credentials for an existing identity. - - There are two major processes that result in managed credential - acuqisition. One is the acquisition of credentials, while the - other is credential renewal. During a renewal, existing - credentials are used to obtain new credentials which expire later - than the existing credential. Typically, the identity provider - performs the task of obtaining renewed initial credentials while - the other credential providers obtain new credentials based on - these initial credentials. - - \section cred_acq_new New Credentials - - When a user initiates the process of initial credential - acquisition, Network Identity Manager broadcasts a - <::KMSG_CRED,::KMSG_CRED_NEW_CREDS> message. Credential providers - which need to participate in the credential acquisition should - respond to this message as detailed in \ref cred_acq_handle. - - \section cred_acq_renew Renew Credentials - - Network Identity Manager broadcasts a - <::KMSG_CRED,::KMSG_CRED_RENEW_CREDS> message to initiate the - process of renewing credentials. This may be triggered - automatically or by a user action. Credential providers which - need to participate in the renewal should respond to this message - as detailed in \ref cred_acq_handle. - - The following pages provide detailed information: - - - \subpage cred_acq_new_resp - - \subpage cred_acq_dlgproc - */ - -/*! \page cred_acq_new_resp Handling new credentials acquisition - - The process of acquiring credentials happens as follows: - - - Network Identity Manager creates a ::khui_new_creds object and a - credentials acquisition window. - - - <::KMSG_CRED,::KMSG_CRED_RENEW_CREDS> or - <::KMSG_CRED,::KMSG_CRED_NEW_CREDS> is sent to all the - credentials providers. - - - The credential providers create the panels (where appropriate) - for customizing their respective credential types. The type, - panel and any dependency information is populated into a - ::khui_new_creds_by_type structure and added to the - ::khui_new_creds structure. (See khui_cw_add_type()). - - - <::KMSG_CRED, ::KMSG_CRED_DIALOG_PRESTART> is sent to all the - credentials providers. Credentials providers should use this - message to finialize initialization in preparation of showing - the credentials acquisition window, such as by initializing the - controls of the individual panels. - - - <::KMSG_CRED, ::KMSG_CRED_DIALOG_START> is sent to all the - credentials providers. - - - The dialog for obtaining credentials is displayed. - Notifications between the main dialog and the individual panels - are done through ::KHUI_WM_NC_NOTIFY messages to the dialog - procedures. - - - Once the dialog processing is done, a ::WMNC_DIALOG_PREPROCESS - message is sent to the dialog procedure. - - - Network Identity Manager posts - <::KMSG_CRED,::KMSG_CRED_DIALOG_PROCESS> message to all the - credentials providers. Each provider should check if the user - cancelled the dialog or indicated that the new credentials - should be obtained and act accordingly. The \a result field of - the ::khui_new_creds structure will be set to either - ::KHUI_NC_RESULT_PROCESS or ::KHUI_NC_RESULT_CANCEL to indicate - whether the user wishes to acquire credentials or cancel the - operation. - - - A <::KMSG_CRED, ::KMSG_CRED_END> message signals the end of the - credentials acquisition process. Each credentials provider is - responsible for removing the ::khui_new_creds_by_type structre - from the ::khui_new_creds structure and freeing up any resources - it allocated earlier in preparation for obtaining new - credentials. - - \section cred_acq_handle Responding to credential acquisition messages - - The credential acquisition messages are - <::KMSG_CRED,::KMSG_CRED_NEW_CREDS> and <::KMSG_CRED, - ::KMSG_CRED_RENEW_CREDS>. They are structured as follows: - - - \b type : ::KMSG_CRED - - \b subtype: ::KMSG_CRED_NEW_CREDS or ::KMSG_CRED_RENEW_CREDS - - \b uparam : 0 (unused) - - \b vparam : a pointer to a ::khui_new_creds structure. - - The \a vparam parameter of the message, as shown above, is a - pointer to a ::khui_new_creds structure. You can use the \a - subtype field of this structure to determine whether this is a new - credentials acquisition or a renewal. - - In response to this message, a credentials provider is expected to - provide a configuration panel which the user can use to customize - how the credentials of this type are to be obtained. The panel is - described by the ::khui_new_creds_by_type structure. - - \subsection cred_acq_panel_spec Specifying the credentials type panel - - The credentials type panel is used by the user to customize how - credentials of the specified type are to be obtained. The - ::khui_new_creds_by_type structure that describes the panel can be - used to specify a number of parameters that guide how the panel is - to be displayed in the new credentials acquisition dialog. - - The \a name field defines a localized string that will be - displayed in the tab control that houses the panel. If it is \a - NULL, then the name of the credentials type is used. Optionally, - an icon can be specified in the \a icon field which will appear - alongside the name. A tooltip may be provided in the \a tooltip - field which will be displayed when the user hovers the mouse over - the tab. - - In order to assert that the tab appears at a specific position in - the list of tabs, you can specify a positive number in the \a - ordinal field. Zero does not count as a valid ordinal. The - panels with positive ordinals are arranged first in increasing - order of ordinal (conflicts are resolved by sorting along the \a - name). Then the panels without a positive ordianl are arranged - behind these in increasing order of \a name. - - Currently, the credentials provider must specify a dialog template - that will be used to create the embedded dialog for configuring - new credentials for the type. This is done by setting the - khui_new_creds_by_type::h_module, khui_new_creds_by_type::dlg_proc - and khui_new_creds_by_type::dlg_template fields. - - Following is example code which suggests how this could be done: - - \code - // Message handling code for KMSG_CRED_NEW_CREDS or - // KMSG_CRED_INIT_CREDS - ... - khui_new_creds * c; - khui_new_creds_by_type * t; - - c = (khui_new_creds *) vparam; - t = PMALLOC(sizeof(*t)); - ZeroMemory(t, sizeof(*t)); - - t->type = my_cred_type; - - // set look and feel params - t->ordinal = 3; // third in line - t->name = L"My panel name"; - t->icon = LoadIcon(my_hInstance, MAKEINTRESOURCE(IDI_PANEL_ICON)); - t->tooltip = L"Configure credentials of my type"; - - // specify the dialog template to use - t->h_module = my_hInstance; - t->dlg_proc = my_dialog_procedure; - t->dlg_template = MAKEINTRESOURCE(IDD_NEW_CREDS); - - if(KHM_FAILED(khui_cw_add_type(c,t))) { - // handle error - } - \endcode - - It is important to note that the ::khui_new_creds_by_type pointer - that is passed into khui_cw_add_type() points to an allocated - block of memory which should remain in memory until - <::KMSG_CRED,::KMSG_CRED_END> message is received. - - For information on how the dialog procedure should be written, see - \ref cred_acq_dlgproc . - -*/ - -/*! \page cred_acq_dlgproc Writing the dialog procedure for a cred type panel - - -*/ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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$ */ + +/*! \page cred_acq Managed credential acquisition + + Credential providers and identity providers must participate in + managed credential acquisition in order to respond to the user's + requests to obtain new credentials for an identity or to renew + credentials for an existing identity. + + There are two major processes that result in managed credential + acuqisition. One is the acquisition of credentials, while the + other is credential renewal. During a renewal, existing + credentials are used to obtain new credentials which expire later + than the existing credential. Typically, the identity provider + performs the task of obtaining renewed initial credentials while + the other credential providers obtain new credentials based on + these initial credentials. + + \section cred_acq_new New Credentials + + When a user initiates the process of initial credential + acquisition, Network Identity Manager broadcasts a + <::KMSG_CRED,::KMSG_CRED_NEW_CREDS> message. Credential providers + which need to participate in the credential acquisition should + respond to this message as detailed in \ref cred_acq_handle. + + \section cred_acq_renew Renew Credentials + + Network Identity Manager broadcasts a + <::KMSG_CRED,::KMSG_CRED_RENEW_CREDS> message to initiate the + process of renewing credentials. This may be triggered + automatically or by a user action. Credential providers which + need to participate in the renewal should respond to this message + as detailed in \ref cred_acq_handle. + + The following pages provide detailed information: + + - \subpage cred_acq_new_resp + - \subpage cred_acq_dlgproc + */ + +/*! \page cred_acq_new_resp Handling new credentials acquisition + + The process of acquiring credentials happens as follows: + + - Network Identity Manager creates a ::khui_new_creds object and a + credentials acquisition window. + + - <::KMSG_CRED,::KMSG_CRED_RENEW_CREDS> or + <::KMSG_CRED,::KMSG_CRED_NEW_CREDS> is sent to all the + credentials providers. + + - The credential providers create the panels (where appropriate) + for customizing their respective credential types. The type, + panel and any dependency information is populated into a + ::khui_new_creds_by_type structure and added to the + ::khui_new_creds structure. (See khui_cw_add_type()). + + - <::KMSG_CRED, ::KMSG_CRED_DIALOG_PRESTART> is sent to all the + credentials providers. Credentials providers should use this + message to finialize initialization in preparation of showing + the credentials acquisition window, such as by initializing the + controls of the individual panels. + + - <::KMSG_CRED, ::KMSG_CRED_DIALOG_START> is sent to all the + credentials providers. + + - The dialog for obtaining credentials is displayed. + Notifications between the main dialog and the individual panels + are done through ::KHUI_WM_NC_NOTIFY messages to the dialog + procedures. + + - Once the dialog processing is done, a ::WMNC_DIALOG_PREPROCESS + message is sent to the dialog procedure. + + - Network Identity Manager posts + <::KMSG_CRED,::KMSG_CRED_DIALOG_PROCESS> message to all the + credentials providers. Each provider should check if the user + cancelled the dialog or indicated that the new credentials + should be obtained and act accordingly. The \a result field of + the ::khui_new_creds structure will be set to either + ::KHUI_NC_RESULT_PROCESS or ::KHUI_NC_RESULT_CANCEL to indicate + whether the user wishes to acquire credentials or cancel the + operation. + + - A <::KMSG_CRED, ::KMSG_CRED_END> message signals the end of the + credentials acquisition process. Each credentials provider is + responsible for removing the ::khui_new_creds_by_type structre + from the ::khui_new_creds structure and freeing up any resources + it allocated earlier in preparation for obtaining new + credentials. + + \section cred_acq_handle Responding to credential acquisition messages + + The credential acquisition messages are + <::KMSG_CRED,::KMSG_CRED_NEW_CREDS> and <::KMSG_CRED, + ::KMSG_CRED_RENEW_CREDS>. They are structured as follows: + + - \b type : ::KMSG_CRED + - \b subtype: ::KMSG_CRED_NEW_CREDS or ::KMSG_CRED_RENEW_CREDS + - \b uparam : 0 (unused) + - \b vparam : a pointer to a ::khui_new_creds structure. + + The \a vparam parameter of the message, as shown above, is a + pointer to a ::khui_new_creds structure. You can use the \a + subtype field of this structure to determine whether this is a new + credentials acquisition or a renewal. + + In response to this message, a credentials provider is expected to + provide a configuration panel which the user can use to customize + how the credentials of this type are to be obtained. The panel is + described by the ::khui_new_creds_by_type structure. + + \subsection cred_acq_panel_spec Specifying the credentials type panel + + The credentials type panel is used by the user to customize how + credentials of the specified type are to be obtained. The + ::khui_new_creds_by_type structure that describes the panel can be + used to specify a number of parameters that guide how the panel is + to be displayed in the new credentials acquisition dialog. + + The \a name field defines a localized string that will be + displayed in the tab control that houses the panel. If it is \a + NULL, then the name of the credentials type is used. Optionally, + an icon can be specified in the \a icon field which will appear + alongside the name. A tooltip may be provided in the \a tooltip + field which will be displayed when the user hovers the mouse over + the tab. + + In order to assert that the tab appears at a specific position in + the list of tabs, you can specify a positive number in the \a + ordinal field. Zero does not count as a valid ordinal. The + panels with positive ordinals are arranged first in increasing + order of ordinal (conflicts are resolved by sorting along the \a + name). Then the panels without a positive ordianl are arranged + behind these in increasing order of \a name. + + Currently, the credentials provider must specify a dialog template + that will be used to create the embedded dialog for configuring + new credentials for the type. This is done by setting the + khui_new_creds_by_type::h_module, khui_new_creds_by_type::dlg_proc + and khui_new_creds_by_type::dlg_template fields. + + Following is example code which suggests how this could be done: + + \code + // Message handling code for KMSG_CRED_NEW_CREDS or + // KMSG_CRED_INIT_CREDS + ... + khui_new_creds * c; + khui_new_creds_by_type * t; + + c = (khui_new_creds *) vparam; + t = PMALLOC(sizeof(*t)); + ZeroMemory(t, sizeof(*t)); + + t->type = my_cred_type; + + // set look and feel params + t->ordinal = 3; // third in line + t->name = L"My panel name"; + t->icon = LoadIcon(my_hInstance, MAKEINTRESOURCE(IDI_PANEL_ICON)); + t->tooltip = L"Configure credentials of my type"; + + // specify the dialog template to use + t->h_module = my_hInstance; + t->dlg_proc = my_dialog_procedure; + t->dlg_template = MAKEINTRESOURCE(IDD_NEW_CREDS); + + if(KHM_FAILED(khui_cw_add_type(c,t))) { + // handle error + } + \endcode + + It is important to note that the ::khui_new_creds_by_type pointer + that is passed into khui_cw_add_type() points to an allocated + block of memory which should remain in memory until + <::KMSG_CRED,::KMSG_CRED_END> message is received. + + For information on how the dialog procedure should be written, see + \ref cred_acq_dlgproc . + +*/ + +/*! \page cred_acq_dlgproc Writing the dialog procedure for a cred type panel + + +*/ diff --git a/src/windows/identity/doc/cred_data_types.h b/src/windows/identity/doc/cred_data_types.h index dcd115219..f2a412211 100644 --- a/src/windows/identity/doc/cred_data_types.h +++ b/src/windows/identity/doc/cred_data_types.h @@ -1,264 +1,264 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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$ */ - -/*! \page cred_data_types Data types in Network Identity Manager - - Network Identity Manager's Credentials Database supports several - useful data types. In addition, plug-ins can define custom data - types. Only a few operations are expected of these data types - since the core KCDB delegates fine grained operations to other - entities that understand the underlying format. - - A field in a credential can have any one of these data types, but - it must have some data type. Each value can be at most \a - KCDB_TYPE_MAXCB bytes in length regardless of the data type. - - Some data types have a fixed size (such as \a Int32), while others - are variable size. The required memory for each field in a - credential is allocated as needed. - - \section kcdb_pg_dt Data types - - Descriptions of individual data types are below. - - \subsection kcdb_pg_idt Individual data types - - \subsubsection kcdb_pg_idt_v Void - - Type identifier : ::KCDB_TYPE_VOID - - The Void data type is used to indicate that the associated object - does not contain any data. - - \subsubsection kcdb_pg_idt_s String - - Type identifier : ::KCDB_TYPE_STRING - - A unicode string that is terminated with a unicode NULL (L'\\0'). - By default, the type has the following flags: - - \a KCDB_TYPE_FLAG_CB_AUTO - - This is because, as long as the string is terminated with a unicode NULL, - the length of the string, and therefore it's size in bytes, can be inferred - from the data itself. - - \subsubsection kcdb_pg_idt_d Date - - Type identifier : ::KCDB_TYPE_DATE - - Dates and times in Network Identity Manager are stored in \a - FILETIME structures. Utility functions are provided for - converting from other formats such as \a time_t. - - \subsubsection kcdb_pg_idt_i Interval - - Type identifier : ::KCDB_TYPE_INTERVAL - - Stores an interval of time. Stored as a 64-bit signed integer. The - string representation of this data type is different from the \a - Date data type and designates an interval of time. - - The special value _I64_MAX (which is defined in limits.h as - 0x7fffffffffffffff, or in other words, the largest positive value - that can be stored in a 64-bit signed integer) is used to - represent an interval of unknown length. - - The string representations of a data value of Interval type are - defined as follows for English (US): - - - "(Unknown)" if the value is _I64_MAX - - - "(Expired)" if the value is less than zero - - - "%d days %d hours" if the value is greater than 24 hours - - - "%d hours %d mins" if the value is greater than 1 hour - - - "%d mins %d secs" if the value is greater than 1 minute - - - "%d seconds" otherwise - - \subsubsection kcdb_pg_idt_i32 Int32 - - Type identifier : ::KCDB_TYPE_INT32 - - A signed 32-bit integer. - - \subsubsection kcdb_pg_idt_i64 Int64 - - Type identifier : ::KCDB_TYPE_INT64 - - A signed 64-bit integer. - - \subsubsection kcdb_pg_idt_da Data - - Type identifier : ::KCDB_TYPE_DATA - - Raw data. Can contain a byte stream. This data type can be used - by plug-ins to associate raw data with a credential. However, - there is no built-in string representation for this data type. As - such, this is not meant to be used for storing anything that has - to be displayed to the user verbatim. - - \section kcdb_pg_cust Custom data types - - \subsection kcdb_pg_cb Custom data type call backs - - Custom data types in the Network Identity Manager Credentials - Database are defined using \a kcdb_type structures that must - include several callback functions. The expected behavior of - these callback functions is documented below. - - \subsubsection kcdb_pg_cb_ts toString - - \code - khm_int32 toString( - const void * data, - khm_int32 cb_data, - wchar_t *buffer, - khm_int32 *pcb_buffer, - khm_int32 flags); - \endcode - - Produce the localized string representation of the object pointed to by - \a data. The size of the data block is specified by the \a cb_data - parameter. If the data type specified the \a KCDB_TYPE_FLAG_CB_AUTO flag - then \a cb_data can be \a KCDB_CBSIZE_AUTO, in which case the size of the - data block is to be inferred. - - \a toString should assume that the block of data pointed to by \a data is - valid for this data type. - - The \a pcb_buffer parameter is always a valid pointer to an \a khm_int32 - variable. - - The \a buffer parameter is a pointer to a \a wchar_t buffer which is to - receive the unicode string representing the object. \a buffer may be - \a NULL, in which case the required size of the buffer should be returned - in \a pcb_buffer. In this case, the function should return - \a KHM_ERROR_TOO_LONG. - - If the \a buffer parameter is not \a NULL and the \a pcb_buffer specifies - that the buffer is large enough to hold the string representation, the - function should copy the string representation to the buffer, set the - \a pcb_buffer to the number of bytes that were copied including the - terminating \a NULL, and return \a KHM_ERROR_SUCCESS. - - If the \a buffer parameter is not \a NULL and the \a pcb_buffer specifies - a buffer that is not large enough, the function should set \a pcb_buffer - to the required size (including the terminating \a NULL) and then return - \a KHM_ERROR_TOO_LONG. - - \subsubsection kcdb_pg_cb_cmp comp - - \code - khm_int32 comp( - const void * data1, - khm_int32 cb_data1, - const void * data2, - khm_int32 cb_d2); - \endcode - - Compares two objects and returns a value indicating the relative ordering. - - Since the KCDB does not interpret any data type, it relies on a loose - definition of what a relative ordering is. It is left up to each data - type callback to interpret what 'ascending' and 'descending' mean. - - The return value \a r should be as follows: - - \a r < 0 : if \a data1 < \a data2 - - \a r > 0 : if \a data1 > \a data2 - - \a r = 0 : if \a data1 = \a data2 or no relative ordering can be determined - for the two objects \a data1 and \a data2. - - The function should assume that both objects are valid for this data type. - - The size specifiers \a cb_data1 and \a cb_data2 can (either or both) be - \a KCDB_CBSIZE_AUTO if the data type specified \a KCDB_TYPE_FLAG_CB_AUTO - flag. - - \subsubsection kcdb_pg_cb_dup dup - - \code - khm_int32 dup( - const void * d_src, - khm_int32 cb_src, - void * d_dst, - khm_int32 * pcb_dst); - \endcode - - Duplicate an object. The object pointed to by \a d_src is to be copied to - the buffer pointed to by \a d_dst. The function is to assume that \a d_src - object is valid. The size specifier \a cb_src may be \a KCDB_CBSIZE_AUTO - if \a KCDB_TYPE_FLAG_CB_AUTO was specified for the data type. - - If \a d_dst pointer is \a NULL, then the required buffer size should be - returned in \a pcb_dst. In this case, the function itself should return - \a KHM_ERROR_TOO_LONG. The same behavior should occur if \a d_dst is non - \a NULL and \a pcb_dst indicates that the buffer is not sufficient. - - If \a d_dst is not \a NULL and \a pcb_dst indicates that the buffer is - sufficient, then a copy of the object in \a d_src should be placed in - \a d_dst. The function shold return \a KHM_ERROR_SUCCESS and set - \a pcb_dst to the number of bytes that were copied. - - This callback will only be called when the credentials database is - retrieving objects from the outside. Once it receives an object it may be - copied or moved as required. Hence the object should not assume to reside - in a specific location of memory. Also, \a dup is not intended to perform - such functions as reference counting which require knowledge of a precise - number of instances of an object, as the credentials database may copy - the object simply by copying the block of memory. - - Note that whenever \a pcb_dst is to be set, it MUST be set to a valid byte - count. It can not be assigned \a KCDB_CBSIZE_AUTO even if the data type - supports it. The \a pcb_dst parameter is used internally to allocate - memory for the object. - - \subsubsection kcdb_pg_cb_iv isValid - - \code - khm_boolean isValid( - const void * data, - khm_int32 cb_data); - \endcode - - Checks if the object pointed to by the \a data pointer is a valid object - for this data type. If the data type specified the \a KCDB_TYPE_CB_AUTO - flag, then the \a cb_data parameter may be \a KCDB_CBSIZE_AUTO, in which - the size of the object should be inferred from the data. - - The function should be able to determine the validity of the object and - return \a TRUE if it is valid. Return \a FALSE if it isn't, or if the - size of the object can not be inferred from the given data, or if the - inferred size exceeds \a KCDB_TYPE_MAXCB. - -*/ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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$ */ + +/*! \page cred_data_types Data types in Network Identity Manager + + Network Identity Manager's Credentials Database supports several + useful data types. In addition, plug-ins can define custom data + types. Only a few operations are expected of these data types + since the core KCDB delegates fine grained operations to other + entities that understand the underlying format. + + A field in a credential can have any one of these data types, but + it must have some data type. Each value can be at most \a + KCDB_TYPE_MAXCB bytes in length regardless of the data type. + + Some data types have a fixed size (such as \a Int32), while others + are variable size. The required memory for each field in a + credential is allocated as needed. + + \section kcdb_pg_dt Data types + + Descriptions of individual data types are below. + + \subsection kcdb_pg_idt Individual data types + + \subsubsection kcdb_pg_idt_v Void + + Type identifier : ::KCDB_TYPE_VOID + + The Void data type is used to indicate that the associated object + does not contain any data. + + \subsubsection kcdb_pg_idt_s String + + Type identifier : ::KCDB_TYPE_STRING + + A unicode string that is terminated with a unicode NULL (L'\\0'). + By default, the type has the following flags: + + \a KCDB_TYPE_FLAG_CB_AUTO + + This is because, as long as the string is terminated with a unicode NULL, + the length of the string, and therefore it's size in bytes, can be inferred + from the data itself. + + \subsubsection kcdb_pg_idt_d Date + + Type identifier : ::KCDB_TYPE_DATE + + Dates and times in Network Identity Manager are stored in \a + FILETIME structures. Utility functions are provided for + converting from other formats such as \a time_t. + + \subsubsection kcdb_pg_idt_i Interval + + Type identifier : ::KCDB_TYPE_INTERVAL + + Stores an interval of time. Stored as a 64-bit signed integer. The + string representation of this data type is different from the \a + Date data type and designates an interval of time. + + The special value _I64_MAX (which is defined in limits.h as + 0x7fffffffffffffff, or in other words, the largest positive value + that can be stored in a 64-bit signed integer) is used to + represent an interval of unknown length. + + The string representations of a data value of Interval type are + defined as follows for English (US): + + - "(Unknown)" if the value is _I64_MAX + + - "(Expired)" if the value is less than zero + + - "%d days %d hours" if the value is greater than 24 hours + + - "%d hours %d mins" if the value is greater than 1 hour + + - "%d mins %d secs" if the value is greater than 1 minute + + - "%d seconds" otherwise + + \subsubsection kcdb_pg_idt_i32 Int32 + + Type identifier : ::KCDB_TYPE_INT32 + + A signed 32-bit integer. + + \subsubsection kcdb_pg_idt_i64 Int64 + + Type identifier : ::KCDB_TYPE_INT64 + + A signed 64-bit integer. + + \subsubsection kcdb_pg_idt_da Data + + Type identifier : ::KCDB_TYPE_DATA + + Raw data. Can contain a byte stream. This data type can be used + by plug-ins to associate raw data with a credential. However, + there is no built-in string representation for this data type. As + such, this is not meant to be used for storing anything that has + to be displayed to the user verbatim. + + \section kcdb_pg_cust Custom data types + + \subsection kcdb_pg_cb Custom data type call backs + + Custom data types in the Network Identity Manager Credentials + Database are defined using \a kcdb_type structures that must + include several callback functions. The expected behavior of + these callback functions is documented below. + + \subsubsection kcdb_pg_cb_ts toString + + \code + khm_int32 toString( + const void * data, + khm_int32 cb_data, + wchar_t *buffer, + khm_int32 *pcb_buffer, + khm_int32 flags); + \endcode + + Produce the localized string representation of the object pointed to by + \a data. The size of the data block is specified by the \a cb_data + parameter. If the data type specified the \a KCDB_TYPE_FLAG_CB_AUTO flag + then \a cb_data can be \a KCDB_CBSIZE_AUTO, in which case the size of the + data block is to be inferred. + + \a toString should assume that the block of data pointed to by \a data is + valid for this data type. + + The \a pcb_buffer parameter is always a valid pointer to an \a khm_int32 + variable. + + The \a buffer parameter is a pointer to a \a wchar_t buffer which is to + receive the unicode string representing the object. \a buffer may be + \a NULL, in which case the required size of the buffer should be returned + in \a pcb_buffer. In this case, the function should return + \a KHM_ERROR_TOO_LONG. + + If the \a buffer parameter is not \a NULL and the \a pcb_buffer specifies + that the buffer is large enough to hold the string representation, the + function should copy the string representation to the buffer, set the + \a pcb_buffer to the number of bytes that were copied including the + terminating \a NULL, and return \a KHM_ERROR_SUCCESS. + + If the \a buffer parameter is not \a NULL and the \a pcb_buffer specifies + a buffer that is not large enough, the function should set \a pcb_buffer + to the required size (including the terminating \a NULL) and then return + \a KHM_ERROR_TOO_LONG. + + \subsubsection kcdb_pg_cb_cmp comp + + \code + khm_int32 comp( + const void * data1, + khm_int32 cb_data1, + const void * data2, + khm_int32 cb_d2); + \endcode + + Compares two objects and returns a value indicating the relative ordering. + + Since the KCDB does not interpret any data type, it relies on a loose + definition of what a relative ordering is. It is left up to each data + type callback to interpret what 'ascending' and 'descending' mean. + + The return value \a r should be as follows: + + \a r < 0 : if \a data1 < \a data2 + + \a r > 0 : if \a data1 > \a data2 + + \a r = 0 : if \a data1 = \a data2 or no relative ordering can be determined + for the two objects \a data1 and \a data2. + + The function should assume that both objects are valid for this data type. + + The size specifiers \a cb_data1 and \a cb_data2 can (either or both) be + \a KCDB_CBSIZE_AUTO if the data type specified \a KCDB_TYPE_FLAG_CB_AUTO + flag. + + \subsubsection kcdb_pg_cb_dup dup + + \code + khm_int32 dup( + const void * d_src, + khm_int32 cb_src, + void * d_dst, + khm_int32 * pcb_dst); + \endcode + + Duplicate an object. The object pointed to by \a d_src is to be copied to + the buffer pointed to by \a d_dst. The function is to assume that \a d_src + object is valid. The size specifier \a cb_src may be \a KCDB_CBSIZE_AUTO + if \a KCDB_TYPE_FLAG_CB_AUTO was specified for the data type. + + If \a d_dst pointer is \a NULL, then the required buffer size should be + returned in \a pcb_dst. In this case, the function itself should return + \a KHM_ERROR_TOO_LONG. The same behavior should occur if \a d_dst is non + \a NULL and \a pcb_dst indicates that the buffer is not sufficient. + + If \a d_dst is not \a NULL and \a pcb_dst indicates that the buffer is + sufficient, then a copy of the object in \a d_src should be placed in + \a d_dst. The function shold return \a KHM_ERROR_SUCCESS and set + \a pcb_dst to the number of bytes that were copied. + + This callback will only be called when the credentials database is + retrieving objects from the outside. Once it receives an object it may be + copied or moved as required. Hence the object should not assume to reside + in a specific location of memory. Also, \a dup is not intended to perform + such functions as reference counting which require knowledge of a precise + number of instances of an object, as the credentials database may copy + the object simply by copying the block of memory. + + Note that whenever \a pcb_dst is to be set, it MUST be set to a valid byte + count. It can not be assigned \a KCDB_CBSIZE_AUTO even if the data type + supports it. The \a pcb_dst parameter is used internally to allocate + memory for the object. + + \subsubsection kcdb_pg_cb_iv isValid + + \code + khm_boolean isValid( + const void * data, + khm_int32 cb_data); + \endcode + + Checks if the object pointed to by the \a data pointer is a valid object + for this data type. If the data type specified the \a KCDB_TYPE_CB_AUTO + flag, then the \a cb_data parameter may be \a KCDB_CBSIZE_AUTO, in which + the size of the object should be inferred from the data. + + The function should be able to determine the validity of the object and + return \a TRUE if it is valid. Return \a FALSE if it isn't, or if the + size of the object can not be inferred from the given data, or if the + inferred size exceeds \a KCDB_TYPE_MAXCB. + +*/ diff --git a/src/windows/identity/doc/cred_main.h b/src/windows/identity/doc/cred_main.h index a9949aedb..97ac0c2af 100644 --- a/src/windows/identity/doc/cred_main.h +++ b/src/windows/identity/doc/cred_main.h @@ -1,36 +1,36 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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$ */ - -/*! \page cred Credentials Providers - - \section cred_contents Contents - - - \subpage cred_data_types - - \subpage cred_acq - - \subpage cred_prop_pages - - \subpage cred_msgs -*/ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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$ */ + +/*! \page cred Credentials Providers + + \section cred_contents Contents + + - \subpage cred_data_types + - \subpage cred_acq + - \subpage cred_prop_pages + - \subpage cred_msgs +*/ diff --git a/src/windows/identity/doc/cred_msgs.h b/src/windows/identity/doc/cred_msgs.h index 6d7cd3d1b..405acef45 100644 --- a/src/windows/identity/doc/cred_msgs.h +++ b/src/windows/identity/doc/cred_msgs.h @@ -1,48 +1,48 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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$ */ - -/*! \page cred_msgs Handling credentials provider messages - -A credentials provider plug-in receives a number of messages during the -course of execution. This section describes the appropriate ways of -handling these messages. - -\section pi_credmsg_system System mesages - -There are only two system messages that a credentials provider needs -to handle. Both of these are explained elsewhere as they deal with -initialization and uninitialization of the plug-in. See the following -two sections for details on handling these messages. - -- <::KMSG_SYSTEM,::KMSG_SYSTEM_INIT> \ref pi_pt_cred_init -- <::KMSG_SYSTEM,::KMSG_SYSTEM_EXIT> \ref pi_pt_cred_exit - -\section pi_credmsg_cred Credential messages - - - -*/ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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$ */ + +/*! \page cred_msgs Handling credentials provider messages + +A credentials provider plug-in receives a number of messages during the +course of execution. This section describes the appropriate ways of +handling these messages. + +\section pi_credmsg_system System mesages + +There are only two system messages that a credentials provider needs +to handle. Both of these are explained elsewhere as they deal with +initialization and uninitialization of the plug-in. See the following +two sections for details on handling these messages. + +- <::KMSG_SYSTEM,::KMSG_SYSTEM_INIT> \ref pi_pt_cred_init +- <::KMSG_SYSTEM,::KMSG_SYSTEM_EXIT> \ref pi_pt_cred_exit + +\section pi_credmsg_cred Credential messages + + + +*/ diff --git a/src/windows/identity/doc/cred_prop_pages.h b/src/windows/identity/doc/cred_prop_pages.h index fd1da5ad6..ac82e1c5d 100644 --- a/src/windows/identity/doc/cred_prop_pages.h +++ b/src/windows/identity/doc/cred_prop_pages.h @@ -1,84 +1,84 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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$ */ - -/*! \page cred_prop_pages Property Pages for Credentials - - This section describes the logistics of property pages. When a - user selects the 'Properties' option from a menu (either the File - menu or a context menu), then a KHUI_ACTION_PROPERTIES action is - triggered. This is handled by the credentials window and triggers - the launch of a property sheet if there is a valid context to - extract properties from. - - Sequence of actions: - - - KHUI_ACTION_PROPERTIES action is triggered. - - - The main window dispatches the action to the credentials window. - - - If there is a valid context, then the credentials window calls - khui_ps_create_sheet() to create an empty property sheet - structure of type ::khui_property_sheet. The \a ctx member of - the structure is populated with the property context obtained - through khui_context_get(). - - - A global message is broadcast of type - <::KMSG_CRED,::KMSG_CRED_PP_BEGIN> with the parameter blob that - is a pointer to the ::khui_property_sheet structure. - - - Subscribers to <::KMSG_CRED> messages handle the message, check - the \a ctx member of the structure and determine whether or not - and what type property pages to add to the property sheet. New - property sheets are added by calling khui_ps_add_page(). - - - Once all the pages are added, a - <::KMSG_CRED,::KMSG_CRED_PP_PRECREATE> message is broadcast. - This is a chance for the property page providers to do any - processing before the property page is created. - - - The property sheet is created and made visible with a call to - khui_ps_show_sheet(). - - - The Network Identity Manager message loop takes over. Further interaction - including notifications of 'Ok','Cancel','Apply' and other - property sheet related actions are handled through WIN32 - messages. - - - Once the user closes the property sheet, a - <::KMSG_CRED,::KMSG_CRED_PP_END> message is sent to all - subscribers. Individual subscribers who added pages to the - property sheet must free up any associated resources at this - point. - - - All the ::khui_property_page structures that were allocated as - well as the ::khui_property_sheet structure are freed up with a - call to khui_ps_destroy_sheet(). - -The maximum number of property sheets that can be open at one time is -currently set to 256. Each property sheet can have a maximum of 16 -property pages. - */ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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$ */ + +/*! \page cred_prop_pages Property Pages for Credentials + + This section describes the logistics of property pages. When a + user selects the 'Properties' option from a menu (either the File + menu or a context menu), then a KHUI_ACTION_PROPERTIES action is + triggered. This is handled by the credentials window and triggers + the launch of a property sheet if there is a valid context to + extract properties from. + + Sequence of actions: + + - KHUI_ACTION_PROPERTIES action is triggered. + + - The main window dispatches the action to the credentials window. + + - If there is a valid context, then the credentials window calls + khui_ps_create_sheet() to create an empty property sheet + structure of type ::khui_property_sheet. The \a ctx member of + the structure is populated with the property context obtained + through khui_context_get(). + + - A global message is broadcast of type + <::KMSG_CRED,::KMSG_CRED_PP_BEGIN> with the parameter blob that + is a pointer to the ::khui_property_sheet structure. + + - Subscribers to <::KMSG_CRED> messages handle the message, check + the \a ctx member of the structure and determine whether or not + and what type property pages to add to the property sheet. New + property sheets are added by calling khui_ps_add_page(). + + - Once all the pages are added, a + <::KMSG_CRED,::KMSG_CRED_PP_PRECREATE> message is broadcast. + This is a chance for the property page providers to do any + processing before the property page is created. + + - The property sheet is created and made visible with a call to + khui_ps_show_sheet(). + + - The Network Identity Manager message loop takes over. Further interaction + including notifications of 'Ok','Cancel','Apply' and other + property sheet related actions are handled through WIN32 + messages. + + - Once the user closes the property sheet, a + <::KMSG_CRED,::KMSG_CRED_PP_END> message is sent to all + subscribers. Individual subscribers who added pages to the + property sheet must free up any associated resources at this + point. + + - All the ::khui_property_page structures that were allocated as + well as the ::khui_property_sheet structure are freed up with a + call to khui_ps_destroy_sheet(). + +The maximum number of property sheets that can be open at one time is +currently set to 256. Each property sheet can have a maximum of 16 +property pages. + */ diff --git a/src/windows/identity/doc/main_page.h b/src/windows/identity/doc/main_page.h index 55ccb69dc..58aece3fc 100644 --- a/src/windows/identity/doc/main_page.h +++ b/src/windows/identity/doc/main_page.h @@ -1,166 +1,166 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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$ */ - -/*! \mainpage Network Identity Manager - - \image html khimaira_logo.png - - \section main_dev Documentation for Developers - - Network Identity Manager is a credentials manager, which is - capable of managing Kerberos v5, Kerberos v4, Andrew File System, - and Kerberized Certificate Authority credentials. This document - describes the API that is implemented by the Khimaira framework - upon which Network Identity Manager is based. - - See the following sections for more information : - - \subpage license - - \subpage bugs - - \subpage releases - - © 2004-2007 Massachusetts Institute of Technology - - © 2005-2007 Secure Endpoints Inc. -*/ - -/*! - \page license License agreement and credits - - Network Identity Manager is distributed under the MIT License. - - \section license_l MIT License - - Copyright © 2004,2005,2006,2007 Massachusetts Institute of Technology - - Copyright © 2005,2006,2007 Secure Endpoints Inc. - - 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. - - \section license_credits Credits - - Network Identity Manager was developed at the Massachusetts Institute of - Technology in partnership with Secure Endpoints Inc. - - Information Services and - Technology at Massachusetts - Institute of Technology - - Secure Endpoints Inc. -*/ - -/*! \page bugs Reporting bugs - - Network Identity Manager bugs can be reported to - kfw-bugs@mit.edu or - netidmgr@secure-endpoints.com - - When reporting bugs, please include as much information as - possible to help reproduce the problem. - - \image html khimaira_logo_small.png -*/ - -/*! \page releases Prior releases - - The following is a list of releases of Network Identity Manager. - Whenever there is an addition to the API or a significant change - in behavior, the API version is incremented. A plug-in that is - developed against a particular version of the API will be - compatible with any release of Network Identity Manager that - implements that version of the API. - - The Network Identity Manager version number is set as the file and - product version of nidmgr32.dll. - - - 1.2.0.2 Kerberos for Windows 3.2 Beta 2 Apr 11, 2007\n - API version : 8 - - - 1.2.0.1 Apr 06, 2007\n - API version : 8 - - - 1.2.0.0 Kerberos for Windows 3.2 Beta 1 Mar 29, 2007\n - API version : 8 - - - 1.1.11.0 Mar 20, 2007\n - API version : 8 - - - 1.1.10.0 Feb 28, 2007\n - API version : 8 - - - 1.1.9.0 Jan 20, 2007\n - API version : 7 - - - 1.1.8.0 Kerberos for Windows 3.1 Final Nov 22, 2006\n - API version : 6 - - - 1.1.6.0 Kerberos for Windows 3.1 Beta 4 Nov 17, 2006\n - API version : 6 - - - 1.1.4.0 Kerberos for Windows 3.1 Beta 3 Nov 08, 2006\n - API version : 6 - - - 1.1.2.0 Oct 09, 2006\n - API version : 6 - - - 1.1.0.2 Sep 21, 2006\n - API version : 6 - - - 1.1.0.1 Jul 19, 2006\n - API version : 5 - - - 1.1.0.0 Mar 08, 2006\n - API version : 5 - - - 1.0.0.0 Kerberos for Windows 3.0 Dec 05, 2005\n - API version : 4 - - - 0.1.2.0 Second Alpha release Nov 30, 2005\n - API version : 3\n - Released along with Kerberos for Windows 3.0 beta 2. - - - 0.1.1 First Alpha release Nov 01, 2005\n - Released along with Kerberos for Windows 3.0 beta. - -*/ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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$ */ + +/*! \mainpage Network Identity Manager + + \image html khimaira_logo.png + + \section main_dev Documentation for Developers + + Network Identity Manager is a credentials manager, which is + capable of managing Kerberos v5, Kerberos v4, Andrew File System, + and Kerberized Certificate Authority credentials. This document + describes the API that is implemented by the Khimaira framework + upon which Network Identity Manager is based. + + See the following sections for more information : + - \subpage license + - \subpage bugs + - \subpage releases + + © 2004-2007 Massachusetts Institute of Technology + + © 2005-2007 Secure Endpoints Inc. +*/ + +/*! + \page license License agreement and credits + + Network Identity Manager is distributed under the MIT License. + + \section license_l MIT License + + Copyright © 2004,2005,2006,2007 Massachusetts Institute of Technology + + Copyright © 2005,2006,2007 Secure Endpoints Inc. + + 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. + + \section license_credits Credits + + Network Identity Manager was developed at the Massachusetts Institute of + Technology in partnership with Secure Endpoints Inc. + + Information Services and + Technology at Massachusetts + Institute of Technology + + Secure Endpoints Inc. +*/ + +/*! \page bugs Reporting bugs + + Network Identity Manager bugs can be reported to + kfw-bugs@mit.edu or + netidmgr@secure-endpoints.com + + When reporting bugs, please include as much information as + possible to help reproduce the problem. + + \image html khimaira_logo_small.png +*/ + +/*! \page releases Prior releases + + The following is a list of releases of Network Identity Manager. + Whenever there is an addition to the API or a significant change + in behavior, the API version is incremented. A plug-in that is + developed against a particular version of the API will be + compatible with any release of Network Identity Manager that + implements that version of the API. + + The Network Identity Manager version number is set as the file and + product version of nidmgr32.dll. + + - 1.2.0.2 Kerberos for Windows 3.2 Beta 2 Apr 11, 2007\n + API version : 8 + + - 1.2.0.1 Apr 06, 2007\n + API version : 8 + + - 1.2.0.0 Kerberos for Windows 3.2 Beta 1 Mar 29, 2007\n + API version : 8 + + - 1.1.11.0 Mar 20, 2007\n + API version : 8 + + - 1.1.10.0 Feb 28, 2007\n + API version : 8 + + - 1.1.9.0 Jan 20, 2007\n + API version : 7 + + - 1.1.8.0 Kerberos for Windows 3.1 Final Nov 22, 2006\n + API version : 6 + + - 1.1.6.0 Kerberos for Windows 3.1 Beta 4 Nov 17, 2006\n + API version : 6 + + - 1.1.4.0 Kerberos for Windows 3.1 Beta 3 Nov 08, 2006\n + API version : 6 + + - 1.1.2.0 Oct 09, 2006\n + API version : 6 + + - 1.1.0.2 Sep 21, 2006\n + API version : 6 + + - 1.1.0.1 Jul 19, 2006\n + API version : 5 + + - 1.1.0.0 Mar 08, 2006\n + API version : 5 + + - 1.0.0.0 Kerberos for Windows 3.0 Dec 05, 2005\n + API version : 4 + + - 0.1.2.0 Second Alpha release Nov 30, 2005\n + API version : 3\n + Released along with Kerberos for Windows 3.0 beta 2. + + - 0.1.1 First Alpha release Nov 01, 2005\n + Released along with Kerberos for Windows 3.0 beta. + +*/ diff --git a/src/windows/identity/doc/plugin_framework.h b/src/windows/identity/doc/plugin_framework.h index a10af2a6f..5f225b811 100644 --- a/src/windows/identity/doc/plugin_framework.h +++ b/src/windows/identity/doc/plugin_framework.h @@ -1,183 +1,183 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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$ */ - -/*! -\page pi_framework Plug-in Framework - -\section pi_fw_pnm Introduction to Plug-ins, Modules and Messages - -\subsection pi_fw_pnm_p Plug-ins - -A plug-in is a package that implements a defined API that will perform -credentials management or related tasks on behalf of Network Identity -Manager. - -The Network Identity Manager architecture is message based. The core -of each plug-in is a message handler. The plug-in integrates with the -application by subscribing to, and handling specific types of -messages. - -The plug-in message handler runs in its own thread and receive -asynchronous messages. There are exceptions, such as when one plug-in -requires another plug-in to handle a specific message before it can -handle the message. In addition, during certain operations that -require user interaction, each plug-in can delegate code that will run -in the main application thread (the user interface thread) to process -window messages. - -\subsection pi_fw_pnw_m Modules - -One or more plug-ins can be bundled together into a module. A module -is a dynamically loadable library which exports a specific set of -callbacks. Currently, the only two required callbacks for a module -are : - -- init_module(), and -- exit_module() - -For more information about how a module is structured, see \ref -pi_structure . - -\subsection pi_fw_pnm_msg Messages and Message Queues - -An integral part of this framework is the messaging system. Most of -the communication between the Network Identity Manager application and -plug-ins is conducted through passing messages. - -A message has a type and subtype and is denoted in this documentation -as \< \e message_type, \e message_subtype\>. For example, when a -plug-in is loaded, the first message it receives is \< ::KMSG_SYSTEM, -::KMSG_SYSTEM_INIT \>. - -Each thread in the application, specially threads that were created -for individual plug-in messages handlers, has an associated message -queue that stores and manages all the messages that have been sent to -subscribers in that thread. - -The most common recipient of a message is a message callback function -(see ::kmq_callback_t ). The message handler for a plug-in is one such -example. A message callback function receives the message type, -subtype and two optional parameters for the message. - -Any acceptable recipient can subscribe to broadcast messages of any -type. Once subscribed, whenever a message of that type is broadcast, -the message will get queued on the corresponding message queue. Then, -one of the dispatch functions can dispatch the message to the correct -callback function. (see ::kmq_dispatch). - -Next \subpage pi_fw_pm ... - -*/ - -/*! - -\page pi_fw_pm Module Manager - -The module manager is tasked with loading, unloading and managing the -plug-in message processing. It maintains a separate thread for loading -and registering modules. When a module is successfully loaded and it -registers one or more plug-ins, a new thread is created for each -plug-in. Plug-in specific initialization and other callback functions -are called from within this new thread. This is to prevent one -plug-in from "hanging" other plug-ins and the main Network Identity -Manager user interface threads. - -Read more : -- \ref pi_structure - -\subsection pi_fw_pm_load Load sequence - -When kmm_load_module() is called to load a specific module, the -following sequence of events occur: - -- The registration information for the module is located on the - registry key \c - \Software\MIT\NetIDMgr\PluginManager\Modules\[ModuleName]. - -- The \c ImagePath value from the registration information is used to - locate the module binary. If it is not an absolute path, then the - binary is located using the standard system search path starting - from the directory in which Network Identity Manager binaries are - located. - -- The binary is loaded into the address space of Network Identity - Manager along with any dependencies not already loaded. - -- If the Network Identity Manager core binary is signed, then the - signature is checked against the system and user certificate stores. - If this fails, the module is unloaded. See \ref pi_fw_pm_unload. - -- The init_module() entry point for the loaded module is called. If - this function returns an error or if no plug-ins are registered, - then the module is immediately unloaded. See \ref pi_fw_pm_unload. - -- During processing of init_module(), if any localized resource - libraries are specified using kmm_set_locale_info(), then one of the - localized libraries will be loaded. See \ref pi_localization - -- During processing of init_module(), the module registers all the - plug-ins that it is implementing by calling kmm_register_plugin() for - each. - -- Once init_module() returns, each plug-in is initialized. The method - by which a plug-in is initialized depends on the plug-in type. The - initialization code for the plug-in may indicate that it didn't - initialize properly, in which case the plug-in is immediately - unregistered. No further calls are made to the plug-in. - -- If no plug-in is successfully loaded, the module is unloaded. See - \ref pi_fw_pm_unload. - -- During normal operation, any registered plug-ins for a module can be - unloaded explicitly, or the plug-in itself may signal that it should - be unloaded. If at anytime, all the plug-ins for the module are - unloaded, then the module itself is also unloaded unless the \c - NoUnload registry value is set in the module key. - -\subsection pi_fw_pm_unload Unload sequence - -- For each of the plug-ins that are registered for a module, the exit - code is invoked. The method by which this happens depends on the - plug-in type. The plug-in is not given a chance to veto the - decision to unload. Each plug-in is responsible for performing - cleanup tasks, freeing resources and unsubscribing from any message - classes that it has subscribed to. - -- The exit_module() entry point is called for the module. - -- If any localized resource libraries were loaded for the module, they - are unloaded. - -- The module is unloaded. - -The following diagram illustrates the relationship between modules and -plug-ins as implemented in the Kerberos 5 plug-in distributed with -Network Identity Manager. - -\image html modules_plugins_krb5.png - - */ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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$ */ + +/*! +\page pi_framework Plug-in Framework + +\section pi_fw_pnm Introduction to Plug-ins, Modules and Messages + +\subsection pi_fw_pnm_p Plug-ins + +A plug-in is a package that implements a defined API that will perform +credentials management or related tasks on behalf of Network Identity +Manager. + +The Network Identity Manager architecture is message based. The core +of each plug-in is a message handler. The plug-in integrates with the +application by subscribing to, and handling specific types of +messages. + +The plug-in message handler runs in its own thread and receive +asynchronous messages. There are exceptions, such as when one plug-in +requires another plug-in to handle a specific message before it can +handle the message. In addition, during certain operations that +require user interaction, each plug-in can delegate code that will run +in the main application thread (the user interface thread) to process +window messages. + +\subsection pi_fw_pnw_m Modules + +One or more plug-ins can be bundled together into a module. A module +is a dynamically loadable library which exports a specific set of +callbacks. Currently, the only two required callbacks for a module +are : + +- init_module(), and +- exit_module() + +For more information about how a module is structured, see \ref +pi_structure . + +\subsection pi_fw_pnm_msg Messages and Message Queues + +An integral part of this framework is the messaging system. Most of +the communication between the Network Identity Manager application and +plug-ins is conducted through passing messages. + +A message has a type and subtype and is denoted in this documentation +as \< \e message_type, \e message_subtype\>. For example, when a +plug-in is loaded, the first message it receives is \< ::KMSG_SYSTEM, +::KMSG_SYSTEM_INIT \>. + +Each thread in the application, specially threads that were created +for individual plug-in messages handlers, has an associated message +queue that stores and manages all the messages that have been sent to +subscribers in that thread. + +The most common recipient of a message is a message callback function +(see ::kmq_callback_t ). The message handler for a plug-in is one such +example. A message callback function receives the message type, +subtype and two optional parameters for the message. + +Any acceptable recipient can subscribe to broadcast messages of any +type. Once subscribed, whenever a message of that type is broadcast, +the message will get queued on the corresponding message queue. Then, +one of the dispatch functions can dispatch the message to the correct +callback function. (see ::kmq_dispatch). + +Next \subpage pi_fw_pm ... + +*/ + +/*! + +\page pi_fw_pm Module Manager + +The module manager is tasked with loading, unloading and managing the +plug-in message processing. It maintains a separate thread for loading +and registering modules. When a module is successfully loaded and it +registers one or more plug-ins, a new thread is created for each +plug-in. Plug-in specific initialization and other callback functions +are called from within this new thread. This is to prevent one +plug-in from "hanging" other plug-ins and the main Network Identity +Manager user interface threads. + +Read more : +- \ref pi_structure + +\subsection pi_fw_pm_load Load sequence + +When kmm_load_module() is called to load a specific module, the +following sequence of events occur: + +- The registration information for the module is located on the + registry key \c + \Software\MIT\NetIDMgr\PluginManager\Modules\[ModuleName]. + +- The \c ImagePath value from the registration information is used to + locate the module binary. If it is not an absolute path, then the + binary is located using the standard system search path starting + from the directory in which Network Identity Manager binaries are + located. + +- The binary is loaded into the address space of Network Identity + Manager along with any dependencies not already loaded. + +- If the Network Identity Manager core binary is signed, then the + signature is checked against the system and user certificate stores. + If this fails, the module is unloaded. See \ref pi_fw_pm_unload. + +- The init_module() entry point for the loaded module is called. If + this function returns an error or if no plug-ins are registered, + then the module is immediately unloaded. See \ref pi_fw_pm_unload. + +- During processing of init_module(), if any localized resource + libraries are specified using kmm_set_locale_info(), then one of the + localized libraries will be loaded. See \ref pi_localization + +- During processing of init_module(), the module registers all the + plug-ins that it is implementing by calling kmm_register_plugin() for + each. + +- Once init_module() returns, each plug-in is initialized. The method + by which a plug-in is initialized depends on the plug-in type. The + initialization code for the plug-in may indicate that it didn't + initialize properly, in which case the plug-in is immediately + unregistered. No further calls are made to the plug-in. + +- If no plug-in is successfully loaded, the module is unloaded. See + \ref pi_fw_pm_unload. + +- During normal operation, any registered plug-ins for a module can be + unloaded explicitly, or the plug-in itself may signal that it should + be unloaded. If at anytime, all the plug-ins for the module are + unloaded, then the module itself is also unloaded unless the \c + NoUnload registry value is set in the module key. + +\subsection pi_fw_pm_unload Unload sequence + +- For each of the plug-ins that are registered for a module, the exit + code is invoked. The method by which this happens depends on the + plug-in type. The plug-in is not given a chance to veto the + decision to unload. Each plug-in is responsible for performing + cleanup tasks, freeing resources and unsubscribing from any message + classes that it has subscribed to. + +- The exit_module() entry point is called for the module. + +- If any localized resource libraries were loaded for the module, they + are unloaded. + +- The module is unloaded. + +The following diagram illustrates the relationship between modules and +plug-ins as implemented in the Kerberos 5 plug-in distributed with +Network Identity Manager. + +\image html modules_plugins_krb5.png + + */ diff --git a/src/windows/identity/doc/plugin_locale.h b/src/windows/identity/doc/plugin_locale.h index 646f89570..3c6a236e6 100644 --- a/src/windows/identity/doc/plugin_locale.h +++ b/src/windows/identity/doc/plugin_locale.h @@ -1,109 +1,109 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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$ */ - -/*! -\page pi_localization Localization - -If a module requires localized resources, it can register the -localized resource libraries with the module manager when it receives -the init_module() callback. Note that you can only register localized -resource libraries during init_module(). - -The localized resource library is global to a module. Each plug-in is -not allowed to define its own localization library, although it is -free to load and use any library as it sees fit. The module manager -does not manage these libraries for the plug-in. - -\section pi_loc_spec Specification of localized resources - -In order to register localized resource libraries, a module calls -kmm_set_locale_info(). The \a locales parameter to the function holds -a pointer to an array of ::kmm_module_locale records. Each record -specifies one language code and a filename of a library that holds the -language resources for that language. - -It is recommended that you use the LOCALE_DEF convenience macro when -defining locale records for use with kmm_set_locale_info(). This will -ensure that future changes in the API will only minimally affect your -code. For example: - -\code -kmm_module_locale my_locales[] = { -LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), L"english.dll", KMM_MLOC_FLAG_DEFAULT), -LOCALE_DEF(MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH), L"dutch.dll", 0), -LOCALE_DEF(MAKELANGID(LANG_SPANISH,SUBLANG_SPANISH_MODERN), L"spanish.dll", 0) -}; - -int n_locales = sizeof(my_locales)/sizeof(my_locales[0]); - -... - -kmm_set_locale_info(h_module, my_locales, n_locales); - -... -\endcode - -See kmm_set_locale_info() and ::kmm_module_locale for more info. - -\section pi_loc_how Selection of localized resource library - -The module manager searches the array of ::kmm_module_locale objects -passed into the kmm_set_locale_info() function for one that matches -the current user locale (as opposed to the current system locale). A -record matches the locale if it has the same language ID. - -If a match is found, that library is selected. Otherwise, the list is -searched for one that is compatible with the current user locale. A -locale record is compatible with the user locale if the primary -language matches. - -If a match is still not found, the first record in the locale array -that has the ::KMM_MLOC_FLAG_DEFAULT flag set will be selected. - -If a match is still not found, then the kmm_set_locale_info() will -return ::KHM_ERROR_NOT_FOUND. - -\section pi_loc_usage Using localization - -The following convenience macros are available for using a module -handle to load resources from the corresponding resource library. -However, for performance reasons, it is advisable to obtain a handle -to the resource library loaded by the module manager using -kmm_get_resource_module() and then use it to access resources using -the regular WIN32 API. - -- ::kmm_LoadAccelerators -- ::kmm_LoadBitmap -- ::kmm_LoadCursor -- ::kmm_LoadIcon -- ::kmm_LoadImage -- ::kmm_LoadMenu -- ::kmm_LoadString - -*/ - - +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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$ */ + +/*! +\page pi_localization Localization + +If a module requires localized resources, it can register the +localized resource libraries with the module manager when it receives +the init_module() callback. Note that you can only register localized +resource libraries during init_module(). + +The localized resource library is global to a module. Each plug-in is +not allowed to define its own localization library, although it is +free to load and use any library as it sees fit. The module manager +does not manage these libraries for the plug-in. + +\section pi_loc_spec Specification of localized resources + +In order to register localized resource libraries, a module calls +kmm_set_locale_info(). The \a locales parameter to the function holds +a pointer to an array of ::kmm_module_locale records. Each record +specifies one language code and a filename of a library that holds the +language resources for that language. + +It is recommended that you use the LOCALE_DEF convenience macro when +defining locale records for use with kmm_set_locale_info(). This will +ensure that future changes in the API will only minimally affect your +code. For example: + +\code +kmm_module_locale my_locales[] = { +LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), L"english.dll", KMM_MLOC_FLAG_DEFAULT), +LOCALE_DEF(MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH), L"dutch.dll", 0), +LOCALE_DEF(MAKELANGID(LANG_SPANISH,SUBLANG_SPANISH_MODERN), L"spanish.dll", 0) +}; + +int n_locales = sizeof(my_locales)/sizeof(my_locales[0]); + +... + +kmm_set_locale_info(h_module, my_locales, n_locales); + +... +\endcode + +See kmm_set_locale_info() and ::kmm_module_locale for more info. + +\section pi_loc_how Selection of localized resource library + +The module manager searches the array of ::kmm_module_locale objects +passed into the kmm_set_locale_info() function for one that matches +the current user locale (as opposed to the current system locale). A +record matches the locale if it has the same language ID. + +If a match is found, that library is selected. Otherwise, the list is +searched for one that is compatible with the current user locale. A +locale record is compatible with the user locale if the primary +language matches. + +If a match is still not found, the first record in the locale array +that has the ::KMM_MLOC_FLAG_DEFAULT flag set will be selected. + +If a match is still not found, then the kmm_set_locale_info() will +return ::KHM_ERROR_NOT_FOUND. + +\section pi_loc_usage Using localization + +The following convenience macros are available for using a module +handle to load resources from the corresponding resource library. +However, for performance reasons, it is advisable to obtain a handle +to the resource library loaded by the module manager using +kmm_get_resource_module() and then use it to access resources using +the regular WIN32 API. + +- ::kmm_LoadAccelerators +- ::kmm_LoadBitmap +- ::kmm_LoadCursor +- ::kmm_LoadIcon +- ::kmm_LoadImage +- ::kmm_LoadMenu +- ::kmm_LoadString + +*/ + + diff --git a/src/windows/identity/doc/plugin_main.h b/src/windows/identity/doc/plugin_main.h index 70040b285..9542150a8 100644 --- a/src/windows/identity/doc/plugin_main.h +++ b/src/windows/identity/doc/plugin_main.h @@ -1,115 +1,115 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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$ */ - -/*! - -\page plug-ins Network Identity Manager Modules and Plug-ins - - The Network Identity Manager application does not include any - ability to manage any specific type of credential. Instead it - exposes a framework on which plug-ins can be implemented to manage - credentials. - - Plug-ins and localization are handled by the Network Identity - Manager Module Manager API. - - The following sections describe plug-ins in detail: - - - \subpage pi_framework - - \subpage pi_pt - - \subpage pi_structure - - \subpage pi_localization -*/ - -/*! \page pi_pt Plug-in Types - -The types of plug-ins that are currently supported by Network Identity -Manager are : - -\section pi_pt_cred Credential Provider - -A credential provider plug-in essentially acts as an interface between -Network Identity Manager and some entity which defines the credentials -for the purpose of managing those credentials. - -There can be more than one credential provider in a module. - -\subsection pi_pt_cred_comm Communication - -Communication between Network Identity Manager and a credential -provider occurs through a message processor. When registering a -credential provider, the module initialization code in init_module() -specifies ::KHM_PITYPE_CRED as the \a type member and sets \a msg_proc -member to a valid message processor in the ::khm_plugin record. - -\subsection pi_pt_cred_init Initialization - -Once init_module() has completed, the module manager sends a -<::KMSG_SYSTEM,::KMSG_SYSTEM_INIT> message to the message processor. - -For credential provider plug-ins, <::KMSG_SYSTEM,::KMSG_SYSTEM_INIT> is -guaranteed to be the first message it receives. - -The callback function should return KHM_ERROR_SUCCESS if it -initializes properly or some other value otherwise. If the return -value signals an error, then the plug-in is assumed to have failed -initialization and is immediately unloaded. - -The message processor is automatically subscribed to the following -message types: -- ::KMSG_SYSTEM -- ::KMSG_KCDB - -Although a plug-in can use the <::KMSG_SYSTEM,::KMSG_SYSTEM_INIT> -message enumerate existing credentials in the system, it should not -obtain new credentials. This is because other plug-ins that may depend -on the new credential messages may not be loaded at this time. See the -section on \ref cred_msgs for more information. - -\subsection pi_pt_cred_exit Uninitialization - -When the plug-in is to be removed, the module manager sends a -<::KMSG_SYSTEM,::KMSG_SYSTEM_EXIT> to the message processor. The -plug-in must perform any necessary shutdown operations, free up -resources and unsubscribe from any messages that it has subscribed to. - -This message is guaranteed to be the last message received by a -credentials manager plug-in if the plug-in unsubsribes from all -additional message classes that it subsribed to. - -The message types that the message processor is automatically -subscribed to (See \ref pi_pt_cred_init) do not have to be -unsubscribed from as they are automatically removed. - -\subsection pi_pt_cred_other Other Notes - -Since credential managers may receive privileged information, the -signature requirements for credential managers are specially strict. - -*/ - - +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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$ */ + +/*! + +\page plug-ins Network Identity Manager Modules and Plug-ins + + The Network Identity Manager application does not include any + ability to manage any specific type of credential. Instead it + exposes a framework on which plug-ins can be implemented to manage + credentials. + + Plug-ins and localization are handled by the Network Identity + Manager Module Manager API. + + The following sections describe plug-ins in detail: + + - \subpage pi_framework + - \subpage pi_pt + - \subpage pi_structure + - \subpage pi_localization +*/ + +/*! \page pi_pt Plug-in Types + +The types of plug-ins that are currently supported by Network Identity +Manager are : + +\section pi_pt_cred Credential Provider + +A credential provider plug-in essentially acts as an interface between +Network Identity Manager and some entity which defines the credentials +for the purpose of managing those credentials. + +There can be more than one credential provider in a module. + +\subsection pi_pt_cred_comm Communication + +Communication between Network Identity Manager and a credential +provider occurs through a message processor. When registering a +credential provider, the module initialization code in init_module() +specifies ::KHM_PITYPE_CRED as the \a type member and sets \a msg_proc +member to a valid message processor in the ::khm_plugin record. + +\subsection pi_pt_cred_init Initialization + +Once init_module() has completed, the module manager sends a +<::KMSG_SYSTEM,::KMSG_SYSTEM_INIT> message to the message processor. + +For credential provider plug-ins, <::KMSG_SYSTEM,::KMSG_SYSTEM_INIT> is +guaranteed to be the first message it receives. + +The callback function should return KHM_ERROR_SUCCESS if it +initializes properly or some other value otherwise. If the return +value signals an error, then the plug-in is assumed to have failed +initialization and is immediately unloaded. + +The message processor is automatically subscribed to the following +message types: +- ::KMSG_SYSTEM +- ::KMSG_KCDB + +Although a plug-in can use the <::KMSG_SYSTEM,::KMSG_SYSTEM_INIT> +message enumerate existing credentials in the system, it should not +obtain new credentials. This is because other plug-ins that may depend +on the new credential messages may not be loaded at this time. See the +section on \ref cred_msgs for more information. + +\subsection pi_pt_cred_exit Uninitialization + +When the plug-in is to be removed, the module manager sends a +<::KMSG_SYSTEM,::KMSG_SYSTEM_EXIT> to the message processor. The +plug-in must perform any necessary shutdown operations, free up +resources and unsubscribe from any messages that it has subscribed to. + +This message is guaranteed to be the last message received by a +credentials manager plug-in if the plug-in unsubsribes from all +additional message classes that it subsribed to. + +The message types that the message processor is automatically +subscribed to (See \ref pi_pt_cred_init) do not have to be +unsubscribed from as they are automatically removed. + +\subsection pi_pt_cred_other Other Notes + +Since credential managers may receive privileged information, the +signature requirements for credential managers are specially strict. + +*/ + + diff --git a/src/windows/identity/doc/plugin_structure.h b/src/windows/identity/doc/plugin_structure.h index 452029e4f..68cee13e7 100644 --- a/src/windows/identity/doc/plugin_structure.h +++ b/src/windows/identity/doc/plugin_structure.h @@ -1,55 +1,55 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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$ */ - -/*! - -\page pi_structure Structure of a module - -A Network Identity Manager module is a dynamically loadable library -with a specific set of exported symbols. Each export symbol and -general notes about writing a plug-in module are documented below. - -\section pi_str_reg Registration and Version Information - -[TODO] - -\section pi_str_init Initialization - -Do not use DllMain or other system specific callback routines to -perform intilization tasks other than creating mutexes, initializing -thread local storage and other tasks that must be performed at that -stage. Specifically, do not call any Network Identity Manager API functions from -within DllMain. - -\section pi_str_cb Callbacks - -The callbacks that must be implemented by a module are: - -- init_module() -- exit_module() - - */ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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$ */ + +/*! + +\page pi_structure Structure of a module + +A Network Identity Manager module is a dynamically loadable library +with a specific set of exported symbols. Each export symbol and +general notes about writing a plug-in module are documented below. + +\section pi_str_reg Registration and Version Information + +[TODO] + +\section pi_str_init Initialization + +Do not use DllMain or other system specific callback routines to +perform intilization tasks other than creating mutexes, initializing +thread local storage and other tasks that must be performed at that +stage. Specifically, do not call any Network Identity Manager API functions from +within DllMain. + +\section pi_str_cb Callbacks + +The callbacks that must be implemented by a module are: + +- init_module() +- exit_module() + + */ diff --git a/src/windows/identity/doc/ui_actions.h b/src/windows/identity/doc/ui_actions.h index 43bf3a94f..04f9aa6f2 100644 --- a/src/windows/identity/doc/ui_actions.h +++ b/src/windows/identity/doc/ui_actions.h @@ -1,30 +1,30 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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$ */ - -/*! \page khui_actions Actions - - */ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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$ */ + +/*! \page khui_actions Actions + + */ diff --git a/src/windows/identity/doc/ui_context.h b/src/windows/identity/doc/ui_context.h index 12843fb46..9799b5c4a 100644 --- a/src/windows/identity/doc/ui_context.h +++ b/src/windows/identity/doc/ui_context.h @@ -1,188 +1,188 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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$ */ - -/*! \page khui_context Contexts - - \section khui_context_contents Contents - - - \ref khui_context_intro "Introduction" - - \subpage khui_context_using - - \section khui_context_intro Introduction - - Several ::KMSG_CRED messages and many messages depend on the - selections that the user has made on the user interface. The UI - context functions and data structures provide access to this - information. - - The Network Identity Manager user interface presents an outline view of all the - credentials that were provided by credentials providers. This - view consists of headers representing the outline levels and rows - representing individual credentials. - - Users can make multiple selections of credentials or headers from - this view. If all the credentials and subheaders under a - particular outline level are selected, then the header itself is - automatically selected. There may be multiple disjointed - selections of headers and credentials. - - In addition, the current cursor position also acts as a selector. - The credential or header under the cursor may not actually be - selected. The cursor is not the mouse pointer, but the focus - rectangle that may be moved either using the keyboard or by - clicking on a credential or header. - - Thus there are two independent groups of selections: - - - Credentials and headers which are in a selected state at some - specific point in time (the current selection). - - - The current credential or selection which the cursor is on (the - cursor selection). - - There are a few notes on how credentials are selected: - - - An "empty" header (a header that does not contain any credential - rows) does not appear in a UI context. However they can appear - as the current cursor context. - - - At its current implementation, cursor selections of identity, - credential type, and individual credentials are treated as - special cases since they are the most common. - - How the UI context is used when processing a specific action or - message depends on the action or message. If an action operates - on a group of credentials, then the current selection may be used, - and on the other hand if an action or message relates to just one - credential, identity or credential type is invoked, then the - cursor selection is invoked. - - For example, double-clicking a credential, or right clicking and - selecting 'Properties' from the context menu launches the property - window for a credential. This operates on the cursor selection - since that reflects where the user double clicked. However, - choosing 'Destroy' from the context menu invokes a command that - can be applied to a group of credential, and hence uses the - current selection. - - Next: \ref khui_context_using "Using Contexts" - */ - -/*! \page khui_context_using Using Contexts - - \section khui_context_using_1 Obtaining the context - - Typically, messages sent by actions that rely on UI context will - obtain and store the context in a location that is accessible to - the handlers of the message. - - If a plug-in needs to obtain the UI context, it should do so by - calling khui_context_get() and passing in a pointer to a - ::khui_action_context structure. - - Once obtained, the contents of the ::khui_action_context structure - should be considered read-only. When the plug-in is done with the - structure, it should call ::khui_context_release(). This cleans - up any additional memory allocated for storing the context as well - as releasing all the objects that were referenced from the - context. - - \section khui_context_sel_ctx Selection context - - The selection context is specified in the ::khui_action_context - structure in the \a sel_creds and \a n_sel_creds fields. These - combined provide an array of handles to credentials which are - selected. - - \note If \a n_sel_creds is zero, then \a sel_creds may be NULL. - - \section khui_context_cur_ctx Cursor context - - The scope of the cursor context is specified in the \a scope field - of the ::khui_action_context strucutre. The scope can be one of: - - - ::KHUI_SCOPE_NONE - - ::KHUI_SCOPE_IDENT - - ::KHUI_SCOPE_CREDTYPE - - ::KHUI_SCOPE_GROUP - - ::KHUI_SCOPE_CRED - - Depending on the scope, several other members of the strucre may - also be set. - - In general, the cursor context can be a single credential or an - entire outline level. Unlike the selection context, since this - specifies a single point of selection it can not be disjointed. - - The contents of the \a identity, \a cred_type, \a cred, \a headers - and \a n_headers are described in the documentation of each of the - scope values above. - - \subsection khui_context_sel_ctx_grp KHUI_SCOPE_GROUP - - The ::KHUI_SCOPE_GROUP scope is the generic scope which describes - a cursor selection that can not be simplified into any other - scope. - - In this case, the selection is described by an array of - ::khui_header elements each of which specify a criterion for - narrowing down the selection of credentials. The ::khui_header - structure specifies an attribute in the \a attr_id field and a - value in the \a data and \a cb_data fields. The credentials that - are selected are those in the root credential set whose repective - attributes contain the values specified in each of the - ::khui_header elements. - - For example, the following selection: - - \image html credview-select-outline.jpg - - will result in the following header specification: - - \code - ctx.n_headers = 3; - - ctx.headers[0].attr_id = KCDB_ATTR_LOCATION; - ctx.headers[0].data = L"grailauth@KHMTEST"; - ctx.headers[0].cb_data = sizeof(L"grailauth@KHMTEST"); - - ctx.headers[1].attr_id = KCDB_ATTR_ID; - ctx.headers[1].data = &handle_to_identity; - ctx.headers[1].cb_data = sizeof(khm_handle); - - ctx.headers[2].attr_id = KCDB_ATTR_TYPE; - ctx.headers[2].data = &kerberos_5_credtype; - ctx.headers[2].cb_data = sizeof(khm_int32); - \endcode - - \note The attribute that is used to specify the header is not the - display attribute, but the canonical attribute. For example, - in the above, the second header was actually - KCDB_ATTR_ID_NAME. But KCDB_ATTR_ID was used since that is - the canonical source for KCDB_ATTR_ID_NAME. See ::kcdb_attrib - for more information on canonical attributes. -*/ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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$ */ + +/*! \page khui_context Contexts + + \section khui_context_contents Contents + + - \ref khui_context_intro "Introduction" + - \subpage khui_context_using + + \section khui_context_intro Introduction + + Several ::KMSG_CRED messages and many messages depend on the + selections that the user has made on the user interface. The UI + context functions and data structures provide access to this + information. + + The Network Identity Manager user interface presents an outline view of all the + credentials that were provided by credentials providers. This + view consists of headers representing the outline levels and rows + representing individual credentials. + + Users can make multiple selections of credentials or headers from + this view. If all the credentials and subheaders under a + particular outline level are selected, then the header itself is + automatically selected. There may be multiple disjointed + selections of headers and credentials. + + In addition, the current cursor position also acts as a selector. + The credential or header under the cursor may not actually be + selected. The cursor is not the mouse pointer, but the focus + rectangle that may be moved either using the keyboard or by + clicking on a credential or header. + + Thus there are two independent groups of selections: + + - Credentials and headers which are in a selected state at some + specific point in time (the current selection). + + - The current credential or selection which the cursor is on (the + cursor selection). + + There are a few notes on how credentials are selected: + + - An "empty" header (a header that does not contain any credential + rows) does not appear in a UI context. However they can appear + as the current cursor context. + + - At its current implementation, cursor selections of identity, + credential type, and individual credentials are treated as + special cases since they are the most common. + + How the UI context is used when processing a specific action or + message depends on the action or message. If an action operates + on a group of credentials, then the current selection may be used, + and on the other hand if an action or message relates to just one + credential, identity or credential type is invoked, then the + cursor selection is invoked. + + For example, double-clicking a credential, or right clicking and + selecting 'Properties' from the context menu launches the property + window for a credential. This operates on the cursor selection + since that reflects where the user double clicked. However, + choosing 'Destroy' from the context menu invokes a command that + can be applied to a group of credential, and hence uses the + current selection. + + Next: \ref khui_context_using "Using Contexts" + */ + +/*! \page khui_context_using Using Contexts + + \section khui_context_using_1 Obtaining the context + + Typically, messages sent by actions that rely on UI context will + obtain and store the context in a location that is accessible to + the handlers of the message. + + If a plug-in needs to obtain the UI context, it should do so by + calling khui_context_get() and passing in a pointer to a + ::khui_action_context structure. + + Once obtained, the contents of the ::khui_action_context structure + should be considered read-only. When the plug-in is done with the + structure, it should call ::khui_context_release(). This cleans + up any additional memory allocated for storing the context as well + as releasing all the objects that were referenced from the + context. + + \section khui_context_sel_ctx Selection context + + The selection context is specified in the ::khui_action_context + structure in the \a sel_creds and \a n_sel_creds fields. These + combined provide an array of handles to credentials which are + selected. + + \note If \a n_sel_creds is zero, then \a sel_creds may be NULL. + + \section khui_context_cur_ctx Cursor context + + The scope of the cursor context is specified in the \a scope field + of the ::khui_action_context strucutre. The scope can be one of: + + - ::KHUI_SCOPE_NONE + - ::KHUI_SCOPE_IDENT + - ::KHUI_SCOPE_CREDTYPE + - ::KHUI_SCOPE_GROUP + - ::KHUI_SCOPE_CRED + + Depending on the scope, several other members of the strucre may + also be set. + + In general, the cursor context can be a single credential or an + entire outline level. Unlike the selection context, since this + specifies a single point of selection it can not be disjointed. + + The contents of the \a identity, \a cred_type, \a cred, \a headers + and \a n_headers are described in the documentation of each of the + scope values above. + + \subsection khui_context_sel_ctx_grp KHUI_SCOPE_GROUP + + The ::KHUI_SCOPE_GROUP scope is the generic scope which describes + a cursor selection that can not be simplified into any other + scope. + + In this case, the selection is described by an array of + ::khui_header elements each of which specify a criterion for + narrowing down the selection of credentials. The ::khui_header + structure specifies an attribute in the \a attr_id field and a + value in the \a data and \a cb_data fields. The credentials that + are selected are those in the root credential set whose repective + attributes contain the values specified in each of the + ::khui_header elements. + + For example, the following selection: + + \image html credview-select-outline.jpg + + will result in the following header specification: + + \code + ctx.n_headers = 3; + + ctx.headers[0].attr_id = KCDB_ATTR_LOCATION; + ctx.headers[0].data = L"grailauth@KHMTEST"; + ctx.headers[0].cb_data = sizeof(L"grailauth@KHMTEST"); + + ctx.headers[1].attr_id = KCDB_ATTR_ID; + ctx.headers[1].data = &handle_to_identity; + ctx.headers[1].cb_data = sizeof(khm_handle); + + ctx.headers[2].attr_id = KCDB_ATTR_TYPE; + ctx.headers[2].data = &kerberos_5_credtype; + ctx.headers[2].cb_data = sizeof(khm_int32); + \endcode + + \note The attribute that is used to specify the header is not the + display attribute, but the canonical attribute. For example, + in the above, the second header was actually + KCDB_ATTR_ID_NAME. But KCDB_ATTR_ID was used since that is + the canonical source for KCDB_ATTR_ID_NAME. See ::kcdb_attrib + for more information on canonical attributes. +*/ diff --git a/src/windows/identity/doc/ui_main.h b/src/windows/identity/doc/ui_main.h index d7bc6be00..ae6700847 100644 --- a/src/windows/identity/doc/ui_main.h +++ b/src/windows/identity/doc/ui_main.h @@ -1,36 +1,36 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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$ */ - -/*! \page khui User Interface Topics - - \section khui_contents Contents - - - \subpage khui_actions - - \subpage khui_menus - - \subpage khui_context - - \subpage khui_htwnd - */ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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$ */ + +/*! \page khui User Interface Topics + + \section khui_contents Contents + + - \subpage khui_actions + - \subpage khui_menus + - \subpage khui_context + - \subpage khui_htwnd + */ diff --git a/src/windows/identity/doc/ui_menus.h b/src/windows/identity/doc/ui_menus.h index 794aef6ca..e46ee0840 100644 --- a/src/windows/identity/doc/ui_menus.h +++ b/src/windows/identity/doc/ui_menus.h @@ -1,30 +1,30 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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$ */ - -/*! \page khui_menus Menus - - */ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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$ */ + +/*! \page khui_menus Menus + + */ diff --git a/src/windows/identity/help/khhelp.h b/src/windows/identity/help/khhelp.h index fbfef6047..f6fbd3f78 100644 --- a/src/windows/identity/help/khhelp.h +++ b/src/windows/identity/help/khhelp.h @@ -1,33 +1,33 @@ -#define IDH_WELCOME 1000 -#define IDH_WIN_MAIN 1001 - -#define IDH_MENU_FILE 1501 -#define IDH_MENU_CRED 1502 -#define IDH_MENU_VIEW 1503 -#define IDH_MENU_OPTIONS 1504 -#define IDH_MENU_HELP 1505 - -#define IDH_ACTION_PROPERTIES 2000 -#define IDH_ACTION_EXIT 2001 -#define IDH_ACTION_NEW_ID 2002 -#define IDH_ACTION_SET_DEF_ID 2003 -#define IDH_ACTION_SET_SRCH_ID 2004 -#define IDH_ACTION_DESTROY_ID 2005 -#define IDH_ACTION_RENEW_ID 2006 -#define IDH_ACTION_PASSWD_ID 2007 -#define IDH_ACTION_NEW_CRED 2008 -#define IDH_ACTION_CHOOSE_COLS 2009 -#define IDH_ACTION_DEBUG_WINDOW 2010 -#define IDH_ACTION_VIEW_REFRESH 2011 -#define IDH_ACTION_OPT_KHIM 2012 -#define IDH_ACTION_OPT_INIT 2013 -#define IDH_ACTION_OPT_NOTIF 2014 - -#define IDH_NC_CREDWND 3000 -#define IDH_NC_OK 3001 -#define IDH_NC_CANCEL 3002 -#define IDH_NC_HELP 3003 -#define IDH_NC_TABBUTTON 3004 -#define IDH_NC_ADVANCED 3005 -#define IDH_NC_TABMAIN 3006 -#define IDH_NC_SETDEF 3007 +#define IDH_WELCOME 1000 +#define IDH_WIN_MAIN 1001 + +#define IDH_MENU_FILE 1501 +#define IDH_MENU_CRED 1502 +#define IDH_MENU_VIEW 1503 +#define IDH_MENU_OPTIONS 1504 +#define IDH_MENU_HELP 1505 + +#define IDH_ACTION_PROPERTIES 2000 +#define IDH_ACTION_EXIT 2001 +#define IDH_ACTION_NEW_ID 2002 +#define IDH_ACTION_SET_DEF_ID 2003 +#define IDH_ACTION_SET_SRCH_ID 2004 +#define IDH_ACTION_DESTROY_ID 2005 +#define IDH_ACTION_RENEW_ID 2006 +#define IDH_ACTION_PASSWD_ID 2007 +#define IDH_ACTION_NEW_CRED 2008 +#define IDH_ACTION_CHOOSE_COLS 2009 +#define IDH_ACTION_DEBUG_WINDOW 2010 +#define IDH_ACTION_VIEW_REFRESH 2011 +#define IDH_ACTION_OPT_KHIM 2012 +#define IDH_ACTION_OPT_INIT 2013 +#define IDH_ACTION_OPT_NOTIF 2014 + +#define IDH_NC_CREDWND 3000 +#define IDH_NC_OK 3001 +#define IDH_NC_CANCEL 3002 +#define IDH_NC_HELP 3003 +#define IDH_NC_TABBUTTON 3004 +#define IDH_NC_ADVANCED 3005 +#define IDH_NC_TABMAIN 3006 +#define IDH_NC_SETDEF 3007 diff --git a/src/windows/identity/include/khdefs.h b/src/windows/identity/include/khdefs.h index 6b81f4ca0..0d32356f6 100644 --- a/src/windows/identity/include/khdefs.h +++ b/src/windows/identity/include/khdefs.h @@ -1,238 +1,238 @@ -/* - * 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_KHDEFS_H__ -#define __KHIMAIRA_KHDEFS_H__ - -/*! \defgroup khdef Core definitions - - Key type definitions used throughout NetIDMgr. - */ -/*@{*/ -#include -#include -#include - -/*!\typedef khm_octet - \brief A byte (8 bit unsigned)*/ - -/*!\typedef khm_int16 - \brief A signed 16 bit quantity */ - -/*!\typedef khm_ui_2 - \brief An unsigned 16 bit quantity */ - -/*!\typedef khm_int32 - \brief A signed 32 bit quantity */ - -/*!\typedef khm_ui_4 - \brief An unsigned 32 bit quantity */ - -/*!\typedef khm_int64 - \brief A signed 64 bit quantity */ - -/*!\typedef khm_ui_8 - \brief An unsigned 64 bit quantity */ - -typedef unsigned __int8 khm_octet; - -typedef __int16 khm_int16; -typedef unsigned __int16 khm_ui_2; - -typedef __int32 khm_int32; -typedef unsigned __int32 khm_ui_4; - -typedef __int64 khm_int64; -typedef unsigned __int64 khm_ui_8; - -#define VALID_INT_BITS INT_MAX -#define VALID_UINT_BITS UINT_MAX - -#define KHM_UINT32_MAX 4294967295 - -#define KHM_INT32_MAX 2147483647 -/* this strange form is necessary since - is a unary operator, not a sign - indicator */ -#define KHM_INT32_MIN (-KHM_INT32_MAX-1) - -#define KHM_UINT16_MAX 65535 - -#define KHM_INT16_MAX 32767 -/* this strange form is necessary since - is a unary operator, not a sign - indicator */ -#define KHM_INT16_MIN (-KHM_INT16_MAX-1) - -/*! \brief Generic handle type. - - Handles in NetIDMgr are generic pointers. -*/ -typedef void * khm_handle; - -/*! \brief The invalid handle - - Just used to indicate that this handle does not point to anything useful. - Usually returned by a function that returns a handle as a signal that the - operation failed. -*/ -#define KHM_INVALID_HANDLE ((khm_handle) NULL) - -/*! \brief Boolean. -*/ -typedef khm_int32 khm_boolean; - -/*! \brief A size - */ -typedef size_t khm_size; - -/*! \typedef ssize_t - \brief Signed size specifier - - Just a signed version of size_t - */ - -#ifndef _SSIZE_T_DEFINED -#ifdef _WIN64 -typedef __int64 ssize_t; -#else -typedef _W64 int ssize_t; -#endif -#define _SSIZE_T_DEFINED -#endif - -typedef ssize_t khm_ssize; - -#if defined(_WIN64) -typedef unsigned __int64 khm_wparm; -/*TODO: is this enough? */ -typedef unsigned __int64 khm_lparm; -#elif defined(_WIN32) -typedef unsigned __int32 khm_wparm; -typedef unsigned __int64 khm_lparm; -#else -#error khm_wparm and khm_lparm need to be defined for this platform -#endif - -/*!\def KHMAPI - \brief Calling convention for NetIDMgr exported functions - - The caling convention for all NetIDMgr exported functions is \b - __stdcall , unless otherwise noted. - */ - -/*!\def KHMEXP - \brief Export prefix for NetIDMgr exported functions - - When compiling source that exports functions, those exported - function declarations will be done as follows: - - \code - __declspec(dllexport) khm_int32 __stdcall function_name(arguments...); - \endcode - - This eliminates the need for a separate exports definition file. - However, it doesn't preserve ordinals, but we aren't guaranteeing - that anyway. - - On the other hand, if a particular function is going to be imported - from a DLL, it should declared as follows: - - \code - __declspec(dllimport) khm_int32 __stdcall function_name(arguments...); - \endcode - - This allows the compiler to properly instrument the import. If the - function is not declared this way, there will be a stub function - generated that will just jump to the proper import, generating - redundant instructions and wasting execution time. - - This macro encapsulates the proper declaration specifier. - */ - -#ifdef _WIN32 -#define KHMAPI __stdcall - -#define KHMEXP_EXP __declspec(dllexport) -#define KHMEXP_IMP __declspec(dllimport) - -#define KHMEXP KHMEXP_EXP -#endif - -/* Generic permission values */ -/*! \brief Generic read permission or request */ -#define KHM_PERM_READ 0x100 - -/*! \brief Generic write permission or request */ -#define KHM_PERM_WRITE 0x200 - -/* Generic flags */ -/*! \brief Generic create request - - For most lookup functions, specifying this flag indicates that if - the requested object is not found it should be created. -*/ -#define KHM_FLAG_CREATE 0x1000 - -/*! \brief Wrap to DWORD boundary - - Returns the smallest integer greater than or equal to the - parameter that is a multiple of 4. - - \note Only use with positive integers. */ -#define UBOUND32(d) ((((d)-1)&~3) + 4) - -/*! \brief Offset a pointer by a number of bytes - - Given a pointer, returns a void pointer that is a given number of - bytes offset from the pointer. - */ -#define BYTEOFFSET(p,off) ((void *)(((char *) (p)) + (off))) - -/*! \brief Check for powers of 2 - - Return TRUE if the operand is a positive power of 2 or 0*/ -#define IS_POW2(d) ((d)>=0 && !((d) & ((d) - 1))) - -/*! \brief Wrap to upper bound based on start and step size - - Return the smallest element in the series s, s+t, s+2*t, - s+3*t, ... that is greater than or equal to \c v. -*/ -#define UBOUNDSS(v,start,step) (((v)<=(start))?(start):(start)+((((v)-((start)+1))/(step))+1)*(step)) - -/* \brief Length of an array -*/ -#define ARRAYLENGTH(x) (sizeof(x)/sizeof(x[0])) - -/*! \brief Generic version type*/ -typedef struct tag_khm_version { - khm_ui_2 major; /*!< Major version number */ - khm_ui_2 minor; /*!< Minor version number */ - khm_ui_2 patch; /*!< Patch level */ - khm_ui_2 aux; /*!< Auxilary level (usually carries a build number) */ -} khm_version; - -/*@}*/ -#endif +/* + * 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_KHDEFS_H__ +#define __KHIMAIRA_KHDEFS_H__ + +/*! \defgroup khdef Core definitions + + Key type definitions used throughout NetIDMgr. + */ +/*@{*/ +#include +#include +#include + +/*!\typedef khm_octet + \brief A byte (8 bit unsigned)*/ + +/*!\typedef khm_int16 + \brief A signed 16 bit quantity */ + +/*!\typedef khm_ui_2 + \brief An unsigned 16 bit quantity */ + +/*!\typedef khm_int32 + \brief A signed 32 bit quantity */ + +/*!\typedef khm_ui_4 + \brief An unsigned 32 bit quantity */ + +/*!\typedef khm_int64 + \brief A signed 64 bit quantity */ + +/*!\typedef khm_ui_8 + \brief An unsigned 64 bit quantity */ + +typedef unsigned __int8 khm_octet; + +typedef __int16 khm_int16; +typedef unsigned __int16 khm_ui_2; + +typedef __int32 khm_int32; +typedef unsigned __int32 khm_ui_4; + +typedef __int64 khm_int64; +typedef unsigned __int64 khm_ui_8; + +#define VALID_INT_BITS INT_MAX +#define VALID_UINT_BITS UINT_MAX + +#define KHM_UINT32_MAX 4294967295 + +#define KHM_INT32_MAX 2147483647 +/* this strange form is necessary since - is a unary operator, not a sign + indicator */ +#define KHM_INT32_MIN (-KHM_INT32_MAX-1) + +#define KHM_UINT16_MAX 65535 + +#define KHM_INT16_MAX 32767 +/* this strange form is necessary since - is a unary operator, not a sign + indicator */ +#define KHM_INT16_MIN (-KHM_INT16_MAX-1) + +/*! \brief Generic handle type. + + Handles in NetIDMgr are generic pointers. +*/ +typedef void * khm_handle; + +/*! \brief The invalid handle + + Just used to indicate that this handle does not point to anything useful. + Usually returned by a function that returns a handle as a signal that the + operation failed. +*/ +#define KHM_INVALID_HANDLE ((khm_handle) NULL) + +/*! \brief Boolean. +*/ +typedef khm_int32 khm_boolean; + +/*! \brief A size + */ +typedef size_t khm_size; + +/*! \typedef ssize_t + \brief Signed size specifier + + Just a signed version of size_t + */ + +#ifndef _SSIZE_T_DEFINED +#ifdef _WIN64 +typedef __int64 ssize_t; +#else +typedef _W64 int ssize_t; +#endif +#define _SSIZE_T_DEFINED +#endif + +typedef ssize_t khm_ssize; + +#if defined(_WIN64) +typedef unsigned __int64 khm_wparm; +/*TODO: is this enough? */ +typedef unsigned __int64 khm_lparm; +#elif defined(_WIN32) +typedef unsigned __int32 khm_wparm; +typedef unsigned __int64 khm_lparm; +#else +#error khm_wparm and khm_lparm need to be defined for this platform +#endif + +/*!\def KHMAPI + \brief Calling convention for NetIDMgr exported functions + + The caling convention for all NetIDMgr exported functions is \b + __stdcall , unless otherwise noted. + */ + +/*!\def KHMEXP + \brief Export prefix for NetIDMgr exported functions + + When compiling source that exports functions, those exported + function declarations will be done as follows: + + \code + __declspec(dllexport) khm_int32 __stdcall function_name(arguments...); + \endcode + + This eliminates the need for a separate exports definition file. + However, it doesn't preserve ordinals, but we aren't guaranteeing + that anyway. + + On the other hand, if a particular function is going to be imported + from a DLL, it should declared as follows: + + \code + __declspec(dllimport) khm_int32 __stdcall function_name(arguments...); + \endcode + + This allows the compiler to properly instrument the import. If the + function is not declared this way, there will be a stub function + generated that will just jump to the proper import, generating + redundant instructions and wasting execution time. + + This macro encapsulates the proper declaration specifier. + */ + +#ifdef _WIN32 +#define KHMAPI __stdcall + +#define KHMEXP_EXP __declspec(dllexport) +#define KHMEXP_IMP __declspec(dllimport) + +#define KHMEXP KHMEXP_EXP +#endif + +/* Generic permission values */ +/*! \brief Generic read permission or request */ +#define KHM_PERM_READ 0x100 + +/*! \brief Generic write permission or request */ +#define KHM_PERM_WRITE 0x200 + +/* Generic flags */ +/*! \brief Generic create request + + For most lookup functions, specifying this flag indicates that if + the requested object is not found it should be created. +*/ +#define KHM_FLAG_CREATE 0x1000 + +/*! \brief Wrap to DWORD boundary + + Returns the smallest integer greater than or equal to the + parameter that is a multiple of 4. + + \note Only use with positive integers. */ +#define UBOUND32(d) ((((d)-1)&~3) + 4) + +/*! \brief Offset a pointer by a number of bytes + + Given a pointer, returns a void pointer that is a given number of + bytes offset from the pointer. + */ +#define BYTEOFFSET(p,off) ((void *)(((char *) (p)) + (off))) + +/*! \brief Check for powers of 2 + + Return TRUE if the operand is a positive power of 2 or 0*/ +#define IS_POW2(d) ((d)>=0 && !((d) & ((d) - 1))) + +/*! \brief Wrap to upper bound based on start and step size + + Return the smallest element in the series s, s+t, s+2*t, + s+3*t, ... that is greater than or equal to \c v. +*/ +#define UBOUNDSS(v,start,step) (((v)<=(start))?(start):(start)+((((v)-((start)+1))/(step))+1)*(step)) + +/* \brief Length of an array +*/ +#define ARRAYLENGTH(x) (sizeof(x)/sizeof(x[0])) + +/*! \brief Generic version type*/ +typedef struct tag_khm_version { + khm_ui_2 major; /*!< Major version number */ + khm_ui_2 minor; /*!< Minor version number */ + khm_ui_2 patch; /*!< Patch level */ + khm_ui_2 aux; /*!< Auxilary level (usually carries a build number) */ +} khm_version; + +/*@}*/ +#endif diff --git a/src/windows/identity/include/kherror.h b/src/windows/identity/include/kherror.h index ae381ff56..a8ee64505 100644 --- a/src/windows/identity/include/kherror.h +++ b/src/windows/identity/include/kherror.h @@ -1,185 +1,185 @@ -/* - * 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$ */ - -/* Exported */ -#ifndef __KHIMAIRA_KHERROR_H -#define __KHIMAIRA_KHERROR_H - -/*! \defgroup kherror NetIDMgr errors - -@{*/ -/*! \brief Base for error codes - - NetIDMgr errors range from \a KHM_ERROR_BASE to KHM_ERROR_BASE + - KHM_ERROR_RANGE, with the exception of KHM_ERROR_SUCCESS and - KHM_ERROR_NONE. - */ -#define KHM_ERROR_BASE 0x40000000L - -/*! \brief Range for error codes - - NetIDMgr errors range from \a KHM_ERROR_BASE to - KHM_ERROR_BASE + KHM_ERROR_RANGE. -*/ -#define KHM_ERROR_RANGE 256L - -/*! \defgroup kherror_codes Error codes - @{*/ - -/*! \brief No error */ -#define KHM_ERROR_NONE 0x00000000L - -/*! \brief Success. Same as \a KHM_ERROR_NONE */ -#define KHM_ERROR_SUCCESS KHM_ERROR_NONE - -/*! \brief The supplied name was invalid */ -#define KHM_ERROR_INVALID_NAME (KHM_ERROR_BASE + 1) - -/*! \brief Too much data - - A supplied buffer was invalid, was of insufficient size, or a - buffer was of a larger size than expected - */ -#define KHM_ERROR_TOO_LONG (KHM_ERROR_BASE + 2) - -/*! \brief One or more parameters supplied to a function were invalid */ -#define KHM_ERROR_INVALID_PARAM (KHM_ERROR_BASE + 3) - -/*! \brief A duplicate. - - Usually means that something that should have been unique was - found to be not. - */ -#define KHM_ERROR_DUPLICATE (KHM_ERROR_BASE + 4) - -/*! \brief An object was not found - - An object referenced in a parameter was not found. - */ -#define KHM_ERROR_NOT_FOUND (KHM_ERROR_BASE + 5) - -/*! \brief The relevant subsystem is not ready - - Indicates that initialization has not been completed for a - subsystem. - */ -#define KHM_ERROR_NOT_READY (KHM_ERROR_BASE + 6) - -/*! \brief No more resources - - A limited resource has been exhausted. - */ -#define KHM_ERROR_NO_RESOURCES (KHM_ERROR_BASE + 7) - -/*! \brief Type mismatch - */ -#define KHM_ERROR_TYPE_MISMATCH (KHM_ERROR_BASE + 8) - -/*! \brief Already exists - - Usually indicates that an exclusive create operation failed due to - the existence of a similar object. Subtly different from - ::KHM_ERROR_DUPLICATE - */ -#define KHM_ERROR_EXISTS (KHM_ERROR_BASE + 9) - -/*! \brief Operation timed out - */ -#define KHM_ERROR_TIMEOUT (KHM_ERROR_BASE + 10) - -/*! \brief An EXIT message was received - */ -#define KHM_ERROR_EXIT (KHM_ERROR_BASE + 11) - -/*! \brief Unknown or unspecified error - */ -#define KHM_ERROR_UNKNOWN (KHM_ERROR_BASE + 12) - -/*! \brief General error - */ -#define KHM_ERROR_GENERAL KHM_ERROR_UNKNOWN - -/*! \brief An index was out of bounds - */ -#define KHM_ERROR_OUT_OF_BOUNDS (KHM_ERROR_BASE + 13) - -/*! \brief Object already deleted - - One or more objects that were referenced were found to have been - already deleted. - */ -#define KHM_ERROR_DELETED (KHM_ERROR_BASE + 14) - -/*! \brief Invalid operation - - The operation was not permitted to continue for some reason. - Usually because the necessary conditions for the operation haven't - been met yet or the operation can only be performed at certain - times during the execution of NetIDMgr. - */ -#define KHM_ERROR_INVALID_OPERATION (KHM_ERROR_BASE + 15) - -/*! \brief Signature check failed - */ -#define KHM_ERROR_INVALID_SIGNATURE (KHM_ERROR_BASE + 16) - -/*! \brief Not implemented yet - - The operation that was attempted involved invoking functionality - that has not been implemented yet. - */ -#define KHM_ERROR_NOT_IMPLEMENTED (KHM_ERROR_BASE + 17) - -/*! \brief The objects were equivalent - */ -#define KHM_ERROR_EQUIVALENT (KHM_ERROR_BASE + 18) - -/*! \brief No provider exists to service the request -*/ -#define KHM_ERROR_NO_PROVIDER (KHM_ERROR_BASE + 19) - -/*! \brief The operation succeeded, but with errors -*/ -#define KHM_ERROR_PARTIAL (KHM_ERROR_BASE + 20) - -/*! \brief An incompatibility was found */ -#define KHM_ERROR_INCOMPATIBLE (KHM_ERROR_BASE + 21) - -/*! \brief The operation was put on hold - - A request was put on hold or postponed. */ -#define KHM_ERROR_HELD (KHM_ERROR_BASE + 22) - -/*@}*/ /*kherror_codes*/ - -/*! \brief Tests whether a return value indicates success */ -#define KHM_SUCCEEDED(rv) ((rv)==KHM_ERROR_NONE) - -/*! \brief Tests whether a return value indicates failure */ -#define KHM_FAILED(rv) ((rv)!=KHM_ERROR_NONE) - -/*@}*/ -#endif +/* + * 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$ */ + +/* Exported */ +#ifndef __KHIMAIRA_KHERROR_H +#define __KHIMAIRA_KHERROR_H + +/*! \defgroup kherror NetIDMgr errors + +@{*/ +/*! \brief Base for error codes + + NetIDMgr errors range from \a KHM_ERROR_BASE to KHM_ERROR_BASE + + KHM_ERROR_RANGE, with the exception of KHM_ERROR_SUCCESS and + KHM_ERROR_NONE. + */ +#define KHM_ERROR_BASE 0x40000000L + +/*! \brief Range for error codes + + NetIDMgr errors range from \a KHM_ERROR_BASE to + KHM_ERROR_BASE + KHM_ERROR_RANGE. +*/ +#define KHM_ERROR_RANGE 256L + +/*! \defgroup kherror_codes Error codes + @{*/ + +/*! \brief No error */ +#define KHM_ERROR_NONE 0x00000000L + +/*! \brief Success. Same as \a KHM_ERROR_NONE */ +#define KHM_ERROR_SUCCESS KHM_ERROR_NONE + +/*! \brief The supplied name was invalid */ +#define KHM_ERROR_INVALID_NAME (KHM_ERROR_BASE + 1) + +/*! \brief Too much data + + A supplied buffer was invalid, was of insufficient size, or a + buffer was of a larger size than expected + */ +#define KHM_ERROR_TOO_LONG (KHM_ERROR_BASE + 2) + +/*! \brief One or more parameters supplied to a function were invalid */ +#define KHM_ERROR_INVALID_PARAM (KHM_ERROR_BASE + 3) + +/*! \brief A duplicate. + + Usually means that something that should have been unique was + found to be not. + */ +#define KHM_ERROR_DUPLICATE (KHM_ERROR_BASE + 4) + +/*! \brief An object was not found + + An object referenced in a parameter was not found. + */ +#define KHM_ERROR_NOT_FOUND (KHM_ERROR_BASE + 5) + +/*! \brief The relevant subsystem is not ready + + Indicates that initialization has not been completed for a + subsystem. + */ +#define KHM_ERROR_NOT_READY (KHM_ERROR_BASE + 6) + +/*! \brief No more resources + + A limited resource has been exhausted. + */ +#define KHM_ERROR_NO_RESOURCES (KHM_ERROR_BASE + 7) + +/*! \brief Type mismatch + */ +#define KHM_ERROR_TYPE_MISMATCH (KHM_ERROR_BASE + 8) + +/*! \brief Already exists + + Usually indicates that an exclusive create operation failed due to + the existence of a similar object. Subtly different from + ::KHM_ERROR_DUPLICATE + */ +#define KHM_ERROR_EXISTS (KHM_ERROR_BASE + 9) + +/*! \brief Operation timed out + */ +#define KHM_ERROR_TIMEOUT (KHM_ERROR_BASE + 10) + +/*! \brief An EXIT message was received + */ +#define KHM_ERROR_EXIT (KHM_ERROR_BASE + 11) + +/*! \brief Unknown or unspecified error + */ +#define KHM_ERROR_UNKNOWN (KHM_ERROR_BASE + 12) + +/*! \brief General error + */ +#define KHM_ERROR_GENERAL KHM_ERROR_UNKNOWN + +/*! \brief An index was out of bounds + */ +#define KHM_ERROR_OUT_OF_BOUNDS (KHM_ERROR_BASE + 13) + +/*! \brief Object already deleted + + One or more objects that were referenced were found to have been + already deleted. + */ +#define KHM_ERROR_DELETED (KHM_ERROR_BASE + 14) + +/*! \brief Invalid operation + + The operation was not permitted to continue for some reason. + Usually because the necessary conditions for the operation haven't + been met yet or the operation can only be performed at certain + times during the execution of NetIDMgr. + */ +#define KHM_ERROR_INVALID_OPERATION (KHM_ERROR_BASE + 15) + +/*! \brief Signature check failed + */ +#define KHM_ERROR_INVALID_SIGNATURE (KHM_ERROR_BASE + 16) + +/*! \brief Not implemented yet + + The operation that was attempted involved invoking functionality + that has not been implemented yet. + */ +#define KHM_ERROR_NOT_IMPLEMENTED (KHM_ERROR_BASE + 17) + +/*! \brief The objects were equivalent + */ +#define KHM_ERROR_EQUIVALENT (KHM_ERROR_BASE + 18) + +/*! \brief No provider exists to service the request +*/ +#define KHM_ERROR_NO_PROVIDER (KHM_ERROR_BASE + 19) + +/*! \brief The operation succeeded, but with errors +*/ +#define KHM_ERROR_PARTIAL (KHM_ERROR_BASE + 20) + +/*! \brief An incompatibility was found */ +#define KHM_ERROR_INCOMPATIBLE (KHM_ERROR_BASE + 21) + +/*! \brief The operation was put on hold + + A request was put on hold or postponed. */ +#define KHM_ERROR_HELD (KHM_ERROR_BASE + 22) + +/*@}*/ /*kherror_codes*/ + +/*! \brief Tests whether a return value indicates success */ +#define KHM_SUCCEEDED(rv) ((rv)==KHM_ERROR_NONE) + +/*! \brief Tests whether a return value indicates failure */ +#define KHM_FAILED(rv) ((rv)!=KHM_ERROR_NONE) + +/*@}*/ +#endif diff --git a/src/windows/identity/include/khlist.h b/src/windows/identity/include/khlist.h index 8bf43695b..ab60ca37d 100644 --- a/src/windows/identity/include/khlist.h +++ b/src/windows/identity/include/khlist.h @@ -1,214 +1,214 @@ -/* - * 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$ */ - -/* Not exported */ -#ifndef _KHIMAIRA_KHLIST_H -#define _KHIMAIRA_KHLIST_H - -/* Note that most of these are "unsafe" macros. Not for general use */ - -/* LIFO lists */ -#define LDCL(type) \ - type * next; \ - type * prev - -#define LINIT(pe) \ - do { \ - (pe)->next = NULL; \ - (pe)->prev = NULL; } while(0) - -#define LPUSH(pph,pe) \ - do { \ - (pe)->next = *pph; \ - (pe)->prev = NULL; \ - if(*(pph)) (*(pph))->prev = (pe); \ - (*(pph)) = (pe); } while(0) - -#define LPOP(pph,ppe) \ - do { \ - *(ppe) = *(pph); \ - if(*(pph)) *(pph) = (*(pph))->next; \ - if(*(pph)) (*(pph))->prev = NULL; \ - if(*(ppe)) (*(ppe))->next = NULL; \ - } while(0) - -#define LDELETE(pph,pe) \ - do { \ - if((pe)->prev) (pe)->prev->next = (pe)->next; \ - if((pe)->next) (pe)->next->prev = (pe)->prev; \ - if(*(pph) == (pe)) *(pph) = (pe)->next; \ - (pe)->next = (pe)->prev = NULL; \ - } while(0) - -#define LEMPTY(pph) (*(pph) == NULL) - -#define LNEXT(pe) ((pe)?(pe)->next:NULL) - -#define LPREV(pe) ((pe)?(pe)->prev:NULL) - -/* Trees with LIFO child lists */ -#define TDCL(type) \ - LDCL(type); \ - type * children; \ - type * parent - -#define TINIT(pe) \ - do { \ - (pe)->children = NULL; \ - (pe)->parent = NULL; } while(0) - -#define TADDCHILD(pt,pe) \ - do { \ - LPUSH(&((pt)->children),(pe)); \ - (pe)->parent = (pt); } while(0) - -#define TFIRSTCHILD(pt) ((pt)?(pt)->children:NULL) - -#define TPOPCHILD(pt, ppe) \ - do { \ - LPOP(&((pt)->children), ppe); \ - if(*(ppe)) (*(ppe))->parent = NULL; \ - } while(0) - -#define TDELCHILD(pt, pe) \ - do { \ - LDELETE(&((pt)->children), (pe)); \ - (pe)->parent = NULL; } while(0) - -#define TPARENT(pe) ((pe)?(pe)->parent:NULL) - -/* FIFO lists */ -#define QDCL(type) \ - type * head; \ - type * tail - -#define QINIT(pq) \ - do { \ - (pq)->head = (pq)->tail = NULL; \ - } while(0) - -#define QPUT(pq, pe) \ - do { \ - LPUSH(&(pq)->tail, (pe)); \ - if(!(pq)->head) (pq)->head = (pe); \ - } while(0) - -#define QPUSH(pq, pe) \ - do { \ - (pe)->next = NULL; \ - (pe)->prev = (pq)->head; \ - if((pq)->head) (pq)->head->next = (pe); \ - if(!(pq)->tail) (pq)->tail = (pe); \ - (pq)->head = (pe); \ - } while (0) - -#define QGET(pq, ppe) \ - do { \ - *(ppe) = (pq)->head; \ - if(*(ppe)) { \ - (pq)->head = (*(ppe))->prev; \ - if( (*(ppe))->prev ) (*(ppe))->prev->next = NULL; \ - (*(ppe))->prev = NULL; \ - if( (pq)->tail == *(ppe)) (pq)->tail = NULL; \ - } \ - } while(0) - -#define QDEL(pq, pe) \ - do { \ - if((pq)->head == (pe)) (pq)->head = LPREV(pe); \ - LDELETE(&((pq)->tail), (pe)); \ - } while(0) - - -#define QGETT(pq,ppe) \ - do { \ - *(ppe) = (pq)->tail; \ - if(*(ppe)) { \ - (pq)->tail = (*(ppe))->next; \ - if( (*(ppe))->next ) (*(ppe))->next->prev = NULL; \ - (*(ppe))->next = NULL; \ - if( (pq)->head == *(ppe)) (pq)->head = NULL; \ - } \ - } while(0) - -#define QTOP(pq) ((pq)->head) -#define QBOTTOM(pq) ((pq)->tail) -#define QNEXT(pe) ((pe)->prev) -#define QPREV(pe) ((pe)->next) - -#define QINSERT(pt, pre, pe) \ - do { \ - if ((pre) == NULL || \ - QNEXT(pre) == NULL) { QPUT(pt, pe); } \ - else { \ - (pe)->prev = (pre)->prev; \ - (pe)->next = (pre); \ - (pre)->prev->next = (pe); \ - (pre)->prev = (pe); \ - }} while(0) - -/* Trees with FIFO child lists */ -#define TQDCL(type) \ - LDCL(type); \ - QDCL(type); \ - type * parent - -#define TQINIT(pe) \ - do { \ - LINIT(pe); \ - QINIT(pe); \ - (pe)->parent = NULL; } while(0) - -#define TQPUTCHILD(pt,pe) \ - do { \ - QPUT((pt), (pe)); \ - (pe)->parent = (pt); } while(0) - -#define TQINSERT(pt, pre, pe) \ - do { \ - QINSERT(pt, pre, pe); \ - (pe)->parent = (pt); } while(0) - -#define TQGETCHILD(pt,ppe) \ - do { \ - QGET(pt, ppe); \ - if (*(ppe)) { *(ppe)->parent = NULL; } \ - } while(0) - -#define TQDELCHILD(pt, pe) \ - do { \ - QDEL(pt, pe); \ - (pe)->parent = NULL; } while(0) - -#define TQFIRSTCHILD(pt) ((pt)?QTOP(pt):NULL) - -#define TQNEXTCHILD(pe) QNEXT(pe) - -#define TQPREVCHILD(pe) QPREV(pe) - -#define TQPARENT(pe) ((pe)?(pe)->parent:NULL) - -#endif +/* + * 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$ */ + +/* Not exported */ +#ifndef _KHIMAIRA_KHLIST_H +#define _KHIMAIRA_KHLIST_H + +/* Note that most of these are "unsafe" macros. Not for general use */ + +/* LIFO lists */ +#define LDCL(type) \ + type * next; \ + type * prev + +#define LINIT(pe) \ + do { \ + (pe)->next = NULL; \ + (pe)->prev = NULL; } while(0) + +#define LPUSH(pph,pe) \ + do { \ + (pe)->next = *pph; \ + (pe)->prev = NULL; \ + if(*(pph)) (*(pph))->prev = (pe); \ + (*(pph)) = (pe); } while(0) + +#define LPOP(pph,ppe) \ + do { \ + *(ppe) = *(pph); \ + if(*(pph)) *(pph) = (*(pph))->next; \ + if(*(pph)) (*(pph))->prev = NULL; \ + if(*(ppe)) (*(ppe))->next = NULL; \ + } while(0) + +#define LDELETE(pph,pe) \ + do { \ + if((pe)->prev) (pe)->prev->next = (pe)->next; \ + if((pe)->next) (pe)->next->prev = (pe)->prev; \ + if(*(pph) == (pe)) *(pph) = (pe)->next; \ + (pe)->next = (pe)->prev = NULL; \ + } while(0) + +#define LEMPTY(pph) (*(pph) == NULL) + +#define LNEXT(pe) ((pe)?(pe)->next:NULL) + +#define LPREV(pe) ((pe)?(pe)->prev:NULL) + +/* Trees with LIFO child lists */ +#define TDCL(type) \ + LDCL(type); \ + type * children; \ + type * parent + +#define TINIT(pe) \ + do { \ + (pe)->children = NULL; \ + (pe)->parent = NULL; } while(0) + +#define TADDCHILD(pt,pe) \ + do { \ + LPUSH(&((pt)->children),(pe)); \ + (pe)->parent = (pt); } while(0) + +#define TFIRSTCHILD(pt) ((pt)?(pt)->children:NULL) + +#define TPOPCHILD(pt, ppe) \ + do { \ + LPOP(&((pt)->children), ppe); \ + if(*(ppe)) (*(ppe))->parent = NULL; \ + } while(0) + +#define TDELCHILD(pt, pe) \ + do { \ + LDELETE(&((pt)->children), (pe)); \ + (pe)->parent = NULL; } while(0) + +#define TPARENT(pe) ((pe)?(pe)->parent:NULL) + +/* FIFO lists */ +#define QDCL(type) \ + type * head; \ + type * tail + +#define QINIT(pq) \ + do { \ + (pq)->head = (pq)->tail = NULL; \ + } while(0) + +#define QPUT(pq, pe) \ + do { \ + LPUSH(&(pq)->tail, (pe)); \ + if(!(pq)->head) (pq)->head = (pe); \ + } while(0) + +#define QPUSH(pq, pe) \ + do { \ + (pe)->next = NULL; \ + (pe)->prev = (pq)->head; \ + if((pq)->head) (pq)->head->next = (pe); \ + if(!(pq)->tail) (pq)->tail = (pe); \ + (pq)->head = (pe); \ + } while (0) + +#define QGET(pq, ppe) \ + do { \ + *(ppe) = (pq)->head; \ + if(*(ppe)) { \ + (pq)->head = (*(ppe))->prev; \ + if( (*(ppe))->prev ) (*(ppe))->prev->next = NULL; \ + (*(ppe))->prev = NULL; \ + if( (pq)->tail == *(ppe)) (pq)->tail = NULL; \ + } \ + } while(0) + +#define QDEL(pq, pe) \ + do { \ + if((pq)->head == (pe)) (pq)->head = LPREV(pe); \ + LDELETE(&((pq)->tail), (pe)); \ + } while(0) + + +#define QGETT(pq,ppe) \ + do { \ + *(ppe) = (pq)->tail; \ + if(*(ppe)) { \ + (pq)->tail = (*(ppe))->next; \ + if( (*(ppe))->next ) (*(ppe))->next->prev = NULL; \ + (*(ppe))->next = NULL; \ + if( (pq)->head == *(ppe)) (pq)->head = NULL; \ + } \ + } while(0) + +#define QTOP(pq) ((pq)->head) +#define QBOTTOM(pq) ((pq)->tail) +#define QNEXT(pe) ((pe)->prev) +#define QPREV(pe) ((pe)->next) + +#define QINSERT(pt, pre, pe) \ + do { \ + if ((pre) == NULL || \ + QNEXT(pre) == NULL) { QPUT(pt, pe); } \ + else { \ + (pe)->prev = (pre)->prev; \ + (pe)->next = (pre); \ + (pre)->prev->next = (pe); \ + (pre)->prev = (pe); \ + }} while(0) + +/* Trees with FIFO child lists */ +#define TQDCL(type) \ + LDCL(type); \ + QDCL(type); \ + type * parent + +#define TQINIT(pe) \ + do { \ + LINIT(pe); \ + QINIT(pe); \ + (pe)->parent = NULL; } while(0) + +#define TQPUTCHILD(pt,pe) \ + do { \ + QPUT((pt), (pe)); \ + (pe)->parent = (pt); } while(0) + +#define TQINSERT(pt, pre, pe) \ + do { \ + QINSERT(pt, pre, pe); \ + (pe)->parent = (pt); } while(0) + +#define TQGETCHILD(pt,ppe) \ + do { \ + QGET(pt, ppe); \ + if (*(ppe)) { *(ppe)->parent = NULL; } \ + } while(0) + +#define TQDELCHILD(pt, pe) \ + do { \ + QDEL(pt, pe); \ + (pe)->parent = NULL; } while(0) + +#define TQFIRSTCHILD(pt) ((pt)?QTOP(pt):NULL) + +#define TQNEXTCHILD(pe) QNEXT(pe) + +#define TQPREVCHILD(pe) QPREV(pe) + +#define TQPARENT(pe) ((pe)?(pe)->parent:NULL) + +#endif diff --git a/src/windows/identity/include/khmsgtypes.h b/src/windows/identity/include/khmsgtypes.h index 77397f90b..cfb43f94e 100644 --- a/src/windows/identity/include/khmsgtypes.h +++ b/src/windows/identity/include/khmsgtypes.h @@ -1,817 +1,817 @@ -/* - * 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_KHMSGTYPES_H -#define __KHIMAIRA_KHMSGTYPES_H - -/*! \addtogroup kmq -@{*/ -/*! \defgroup kmq_msg Message Types -@{*/ - -/*! \name Global message types -@{*/ - -/*! \brief System messages. - - All subscribers are subscribed to the system message class by default. - - \see \ref kmq_msg_system -*/ -#define KMSG_SYSTEM 0 - -/*! \brief Ad-hoc messages. - - These are messages that are sent through add hoc publishers and - subscribers. -*/ -#define KMSG_ADHOC 1 - -/*! \brief NetIDMgr Credentials Database messages - - These messages notify subscribers of events related to the - credentials database, such as the registration, unregistration and - modification of identities, attributes, attribute types and - credential types. It also provides notifications of changes to - the root crednetial set. - - \see \ref kmq_msg_kcdb -*/ -#define KMSG_KCDB 2 - -/*! \brief NetIDMgr Module Manager messages - - \see \ref kmq_msg_kmm -*/ -#define KMSG_KMM 3 - -/*! \brief NetIDMgr Credential messages - - Notifications of crednetial events. These are the most important - events that a credentials provider should respond to. The - notifications provide co-oridination between credential providers - for performing basic credentials management tasks such as - obtaining new credentials for an identity, deleting credentials - for an identity, obtaining or deleting credentials of a particular - type for an identity etc. - - \see \ref cred_msgs - \see \ref kmq_msg_cred - */ -#define KMSG_CRED 4 - -/*! \brief Action list messages - - Notifications of changes in action state and firing of custom - actions. - - \see \ref kmq_msg_act - */ -#define KMSG_ACT 5 - -/*! \brief Alert messages - - Notifier is the component which displays alerts and error messages - when the NetIDMgr window is normally in operation and which - displays balloon prompts when the window is minimized to alert the - user to important messages such as credentials expiring etc. - - \note This is an internal message class. Components that are not - the notifier should not be subscribing to alert messages. - - \see \ref kmq_msg_alert - */ -#define KMSG_ALERT 6 - -/*! \brief Identity messages - - These are messages that are sent to the identity provider. These - are generally dispatched through a specific subscription object - and are not broadcast. - - \see \ref kmq_msg_ident - */ -#define KMSG_IDENT 7 - -/*! \brief Base message type ID for customized message types - */ -#define KMSGBASE_USER 16 - -/*@}*/ - -/*! \defgroup kmq_msg_system KMSG_SYSTEM subtypes -@{*/ -/*! \brief Generic initialization message - - This message is used by specific components to signal that the - recipient is to perform initialization tasks. As a convention, - the recipient should return KHM_ERROR_SUCCESS if it successfully - performed the initlization tasks or some other value if it failed - to do so. Failure to successfully initialize is usually taken to - mean that the recipient component is not able to perform its - function. - - Usually this is the first message to be received by the recipient. - - \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 - perform uninitilization tasks in preparation of termination. The - return value of this message is not used. - - Usually this is the last message to be received by the recipient. - - \see \ref pi_pt_cred_exit - */ -#define KMSG_SYSTEM_EXIT 2 - -/*! \brief Message completion - - This is an internal message - */ -#define KMSG_SYSTEM_COMPLETION 3 -/*@}*/ - -/*! \defgroup kmq_msg_kcdb KMSG_KCDB subtypes -@{*/ -#define KMSG_KCDB_IDENT 1 -#define KMSG_KCDB_CREDTYPE 2 -#define KMSG_KCDB_ATTRIB 3 -#define KMSG_KCDB_TYPE 4 - -/*! \brief Generic credentials request - - \see ::kcdb_cred_request for more information - */ -#define KMSG_KCDB_REQUEST 256 -/*@}*/ - -/*! \defgroup kmq_msg_kmm KMSG_KMM subtypes -@{*/ -#define KMSG_KMM_I_REG 1 - -#define KMSG_KMM_I_DONE 2 -/*@}*/ - -/*! \defgroup kmq_msg_act KMSG_ACT subtypes - @{*/ - -/*! \brief One or more actions changed state - - This message is sent in response to a call to - khui_enable_actions() or khui_enable_action() and indicates that - one or more actions have changed their state. - */ -#define KMSG_ACT_ENABLE 1 - -/*! \brief One or more actions changed check state - - Sent in response to khui_check_radio_action() or - khui_check_action() and indicates that one or more actions have - either been checked or unchecked. - */ -#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 - -/*! \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 - -/*! \brief Internal */ -#define KMSG_ACT_END_CMDLINE 131 - -/*@}*/ - -/*! \defgroup kmq_msg_cred KMSG_CRED subtypes - @{*/ -/*! \brief Root credential set changed - - This message is issued when the root credential set successfully - collected credentials from another credential set. - - \a uparam of the message is set to a bitmask indicating the change - that occured. It is a combination of ::KCDB_DELTA_ADD, - ::KCDB_DELTA_DEL and ::KCDB_DELTA_MODIFY. - */ -#define KMSG_CRED_ROOTDELTA 1 - -/*! \brief Re-enumerate credentials - - A notice to all credential providers to re-enumerate their - respective credentials. - - \note May be sent to individual credential subscriptions. - */ -#define KMSG_CRED_REFRESH 2 - -/*! \brief Change the password - - This message notifies credentials providers that a password change - request has been received. - - A plug-in handling this message that wishes to participate in the - password change operation is expected to add a - ::khui_new_creds_by_type to the list of participants in the - ::khui_new_creds structure by calling khui_cw_add_type(). - - The password change operation requires user interaction. Any - plug-ins that are participating in the operation need to provide a - user-interface. - - Message parameters: - - \b vparam : pointer to a ::khui_new_creds structure - - \see khui_cw_add_type(), ::khui_new_creds, ::khui_new_creds_by_type - */ -#define KMSG_CRED_PASSWORD 16 - -/*! \brief Initiate the process of obtaining new credentials - - The UI sends this message to start the process of obtaining new - credentials. See \ref cred_acq for more information about - handling this message. - - A plug-in handling this message that wishes to participate in the - new credentials acquisition operation is expected to add a - ::khui_new_creds_by_type to hte list of participants in the - ::khui_new_creds structure by calling khui_cw_add_type(). - - Message parameters: - - \b vparam : pointer to a ::khui_new_creds structure - - \see \ref cred_acq, khui_cw_add_type(), ::khui_new_creds, - ::khui_new_creds_by_type - */ -#define KMSG_CRED_NEW_CREDS 17 - -/*! \brief Renew credentials - - This is a notification sent to individual credentials providers - that a specified identity's credentials should be renewed. - - A plug-in handling this message that wishes to participate in the - renew credentials operation is expected to add a - ::khui_new_creds_by_type to the list of participants in the - ::khui_new_creds structure by calling khui_cw_add_type(). - - Message parameters: - - \b vparam : Pointer to a khui_new_creds object - - \see khui_cw_add_type(), ::khui_new_creds, - ::khui_new_creds_by_type - */ -#define KMSG_CRED_RENEW_CREDS 18 - -/*! \brief Dialog setup - - 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 - finalizing dialog creation operations. - - Message parameters: - - \b vparam : pointer to a ::khui_new_creds structure - - \note May be sent to individual credential subscriptions. - */ -#define KMSG_CRED_DIALOG_SETUP 19 - -/*! \brief Dialog pre-start - - Sent after all the credentials providers have responded to - ::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. - - Message parameters: - - \b vparam : pointer to a ::khui_new_creds structure - - \note May be sent to individual credential subscriptions. - */ -#define KMSG_CRED_DIALOG_PRESTART 20 - -/*! \brief Dialog start - - A notification that the dialog is now in progress. - - Message parameters: - - \b vparam : pointer to a ::khui_new_creds structure - - \note May be sent to individual credential subscriptions. - */ -#define KMSG_CRED_DIALOG_START 21 - -/*! \brief The primary identity of the new credentials dialog has changed - - This message is not sent out by the UI, but is reserved here for - use by individual credentials providers. The message may be sent - from the dialog procedure to the plugin. - - Message parameters: - - \b vparam : pointer to a ::khui_new_creds structure - - \note Be careful when sending this message. All messages that are - not sent by the system should not be sent via broadcast. - Instead, create a subscription using kmq_create_subscription() - for the individual plugin that you want to send the message - and use one of the per-subscription message functions to send - the actual message. - */ -#define KMSG_CRED_DIALOG_NEW_IDENTITY 22 - -/*! \brief New credentials options have changed. - - This message is not sent out by the UI, but is reserved here for - use by individual credentials providers. The message may be sent - from the dialog procedure to the plugin. - - Message parameters: - - \b vparam : pointer to a ::khui_new_creds structure - - \note Be careful when sending this message. All messages that are - not sent by the system should not be sent via broadcast. - Instead, create a subscription using kmq_create_subscription() - for the individual plugin that you want to send the message - and use one of the per-subscription message functions to send - the actual message. - */ -#define KMSG_CRED_DIALOG_NEW_OPTIONS 23 - -/*! \brief Process dialog - - Sent to all the credential providers to look at the contents of - the given ::khui_new_creds structure and do any required - processing. - - If the \a result field in the structure is set to - ::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. - - Message parameters: - - \b vparam : pointer to a ::khui_new_creds structure - - \note May be sent to individual credential subscriptions. - */ -#define KMSG_CRED_PROCESS 24 - -/*! \brief End a credentials acquisition operation - - A notification that the credentials acquisition operation has - ended. - - Message parameters: - - \b vparam : pointer to a ::khui_new_creds structure - - \note May be sent to individual credential subscriptions. - */ -#define KMSG_CRED_END 25 - -/*! \brief Import credentials from the operating system - - Notification to all credentials providers to import any available - credentials from the operating system. - - Message parameters: - - This message does not have any parameters -*/ -#define KMSG_CRED_IMPORT 26 - -/*! \brief Destroy credentials - - Notification that the specified credentials should be destroyed. - Once this message has completed processing a ::KMSG_CRED_REFRESH - message will be issued. - - The credentials that should be destroyed are specified by a - ::khui_action_context structure. The context that should be used - is the selection context. Hence, the credentials that must be - destroyed are the ones lised in the credential set (\a credset). - - Message parameters: - - - \b upram : Unused. Zero. - - - \b vparam : pointer to a ::khui_action_context structure which - describes which credentials need to be destroyed. - - */ -#define KMSG_CRED_DESTROY_CREDS 32 - -#if 0 -/*! \brief Parse an identity - - \note May be sent to individual credential subscriptions. - */ -#define KMSG_CRED_IDENT_PARSE 65 -#endif - -/*! \brief A property page is being launced - - Handlers of this message should determine whether or not they - should participate in the property sheet and if so, add a - ::khui_property_page structure to the property sheet. - - Message parameters: - - \b vparam : pointer to a ::khui_property_sheet structure - */ -#define KMSG_CRED_PP_BEGIN 128 - -/*! \brief A property page is about to be created - - Message parameters: - - \b vparam : pointer to a ::khui_property_sheet structure - - \note This message is merely a notification that the property - sheet is being created. Handlers should not modify the state - of the property sheet or pages at this time. - */ -#define KMSG_CRED_PP_PRECREATE 129 - -/*! \brief A property page has finished processing - - Handlers of this message should remove any ::khui_property_page - structures they added when processing ::KMSG_CRED_PP_BEGIN. - - Message parameters: - - \b vparam : pointer to a ::khui_property_sheet structure - */ -#define KMSG_CRED_PP_END 130 - -/*! \brief A property page has been destroyed - - Message parameters: - - \b vparam : pointer to a ::khui_property_sheet structure - - \note This is a notification that the property sheet processing - has been completed and that the property sheet data structures - should be freed. Any property page data structures should - have already been freed while processing KMSG_CRED_PP_END. - The validity of the ::khui_property_sheet structure should not - be relied upon while processing this message. - */ -#define KMSG_CRED_PP_DESTROY 131 - -/*! \brief An IP address change occurred - - There are no parameters for this message. The NetIDMgr - application handles this message and depending on configuration, - posts message for the individual credentials providers to either - obtain new credentials or renew old ones. - */ -#define KMSG_CRED_ADDR_CHANGE 140 - -/*! \brief Check if a KMSG_CRED subtype is a credentials acquisition message - - Dialog messages are those that deal with the new or initial - credentials acquisition dialog, from initial announcement to - dialog completion. - - Currently, the dialog messages are: - - ::KMSG_CRED_NEW_CREDS - - ::KMSG_CRED_RENEW_CREDS - - ::KMSG_CRED_DIALOG_SETUP - - ::KMSG_CRED_DIALOG_PRESTART - - ::KMSG_CRED_DIALOG_START - - ::KMSG_CRED_DIALOG_NEW_IDENTITY - - ::KMSG_CRED_DIALOG_NEW_OPTIONS - - ::KMSG_CRED_PROCESS - - ::KMSG_CRED_END - - All dialog message numbers are allocated in a contigous block. - - Note that while ::KMSG_CRED_PROCESS and ::KMSG_CRED_END are not - specific to dialogs, they are still included in this predicate - because they are also part of the dialog message sequence. - */ -#define IS_CRED_ACQ_MSG(msg) ((msg) >= 16 && (msg) <=31) - -/*@}*/ /* /KMSG_CRED subtypes */ - -/*! \defgroup kmq_msg_alert KMSG_ALERT Subtypes - @{*/ - -/*! \brief Show an alert - - Message parameters: - - \b vparam : held pointer to a ::khui_alert object - - \note The ::khui_alert object will be released when the processing - of this message completes. - */ -#define KMSG_ALERT_SHOW 1 - -/*! \brief Add an alert to the alert queue - - 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_QUEUE 2 - -/*! \brief Show the next queued alert - - There are no message parameters - */ -#define KMSG_ALERT_SHOW_QUEUED 3 - -/*! \brief Check if there are any queued messages and, if so, update the statusbar - - There are no message parameters - */ -#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 - @{*/ - -/*! \brief Initialize and start the identity provider - - - Sent by the KCDB to notify the identity provider that it is now - the current identity provider. - - Note that unlike regular plugins, an identity provider can be - loaded and inert (not provide any services). Also, the user may - switch between multiple identity providers on the fly. - */ -#define KMSG_IDENT_INIT 1 - -/*! \brief Stop the identity provider - - Sent by the KCDB as notificaton that the identity provider is no - longer the current provider. - */ -#define KMSG_IDENT_EXIT 2 - -/*! \brief Check if an identity name is valid - - This message is sent to the identity provider to verify the syntax - of an identity name. Note that only the syntax of the name is to - be verfied and not the actual physical existence of said identity. - - Message parameters: - - - \b vparam : pointer to ::kcdb_ident_name_xfer object. The - 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, 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: - - - KHM_ERROR_SUCCESS : The name was valid - - KHM_ERROR_INVALID_NAME : The name was invalid - */ -#define KMSG_IDENT_VALIDATE_NAME 3 - -/*! \brief Check if an identity is valid - - Sent to the identity provider to verify the validity of the given - identity. The provider should verify that the identity exists and - is in a state where it can be actively used. - - Depending on the result of the validation, the flags of the - identity should be updated. - - Message parameters: - - \b vparam : Handle to an identity cast as a void pointer. - */ -#define KMSG_IDENT_VALIDATE_IDENTITY 4 - -/*! \brief Canonicalize identity name - - The identity provider will be given a name, which it should put in - canonical form, adjusting case and any character replacement or - doing any relevant expansions if applicable, and place it in the - supplied buffer. - - Message parameters: - - - \b vparam : Pointer to a ::kcdb_ident_name_xfer structure - which provides the identity name to canonicalize in the \a - name_src member, and the buffer to store the canonical name - in the \a name_dest member. The \a name_dest buffer is - guaranteed to be at least KCDB_IDENT_MAXCCH_NAME characters - in size. - - If the name cannot be canonicalized for some reason, the - destination buffer should be set to a zero-length string and the - \a result member of the ::kcdb_ident_name_xfer structure should be - set to the error code. If the destination buffer is set to a - zero-length string and \a result is KHM_ERROR_SUCCESS, then the - original name provided in \a name_src is assumed to be already in - canonical form. - */ -#define KMSG_IDENT_CANON_NAME 5 - -/*! \brief Compare names - - Compare two identity names. The names that are given aren't - guaranteed to be in canonical form. The return value should be - akin to strcmp(). - - Message parameters: - - - \b vparam : A pointer to a ::kcdb_ident_name_xfer structure. - The \a name_src member points at the first name, and the \a - name_alt member specifies the second name. The result of the - comparison should be place in \a result. - */ -#define KMSG_IDENT_COMPARE_NAME 6 - -/*! \brief Set the default identity - - Set or unset the default identity. To set the default identity, - the \a uparam parameter will be set to a non-zero value and a - handle to the identity will be specified in \a vparam. To unset - the default identity (i.e. not have a default identity), a zero - value will be specified in \a uparam and no identities will be - specified in \a vparam. - - When setting a default identity, the identity provider will - receive this message prior to the ::KCDB_IDENT_FLAG_DEFAULT bit - being set or reset on any identity. It should return - KHM_ERROR_SUCCESS if the requested operation can be performed. - Returning any other value will abort the operation and will leave - the default identity unchanged. - - When resetting the default identity, this message should be - treated only as a notification. - - Message parameters: - - - \a uparam : Is non-zero if an identity is being made default. If - this is zero, then identity should be the default. - - - \a vparam : A handle to the identity to be made default if \a - uparam is non-zero. NULL otherwise. - - Return value: - - - KHM_ERROR_SUCCESS : The identity should be marked as default - - Any other value : The identity should not be marked as default - - */ -#define KMSG_IDENT_SET_DEFAULT 7 - -/*! \brief Set an identity as searchable - - Set or reset the searchable bit on an identity. If the \a uparam - parameter is non-zero, then the searchable bit is being set. - Otherwise it is being reset. The identity provider should return - KHM_ERROR_SUCCESS in order to indicate that the identity should be - marked as searchable. Any other value will result in the - searchable bit being reset on the identity. - - Message parameters: - - - \a uparam : Is non-zero if the searchable bit is being set. Zero - otherwise. - - - \a vparam : Handle to the identity - - Return value: - - - KHM_ERROR_SUCCESS: The identity should be marked as searchable - - Any other value : The identity should not be marked as default - */ -#define KMSG_IDENT_SET_SEARCHABLE 8 - -/*! \brief Get information about an identity - - */ -#define KMSG_IDENT_GET_INFO 9 - -/*! \brief Enumerate known and accessible identities - */ -#define KMSG_IDENT_ENUM_KNOWN 10 - -/*! \brief Update information about an identity - */ -#define KMSG_IDENT_UPDATE 11 - -/*! \brief Retrieve the user interface callback function - - When obtaining new credentials, the user interface needs to obtain - a callback function which will provide identity selection - controls. - - Message parameters: - - - \a uparam : Not used - - - \a vparam : pointer to a ::khui_ident_new_creds_cb which will - receive the call back. - */ -#define KMSG_IDENT_GET_UI_CALLBACK 12 - -/*! \brief Notification of the creation of an identity - - This should be considered just a notification. The identit - provider does not have an opportunity to veto the creation of an - identity whose name has been found to be valid. However, when - handing this notification, the identity provider can: - - - Change the flags of the identity and/or marking the identity as - invalid. - - - Change the default identity. - - Note that this notification is sent before the general :;KMSG_KCDB - notification of the identity creation is sent. - - Message parameters: - - - \a uparam : Not used. - - - \p vparam : handle to the identity - */ -#define KMSG_IDENT_NOTIFY_CREATE 13 - -/*@}*/ /* /KMSG_IDENT subtypes */ - -/*@}*/ /* / message types */ -/*@}*/ /* / kmq */ - -#endif +/* + * 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_KHMSGTYPES_H +#define __KHIMAIRA_KHMSGTYPES_H + +/*! \addtogroup kmq +@{*/ +/*! \defgroup kmq_msg Message Types +@{*/ + +/*! \name Global message types +@{*/ + +/*! \brief System messages. + + All subscribers are subscribed to the system message class by default. + + \see \ref kmq_msg_system +*/ +#define KMSG_SYSTEM 0 + +/*! \brief Ad-hoc messages. + + These are messages that are sent through add hoc publishers and + subscribers. +*/ +#define KMSG_ADHOC 1 + +/*! \brief NetIDMgr Credentials Database messages + + These messages notify subscribers of events related to the + credentials database, such as the registration, unregistration and + modification of identities, attributes, attribute types and + credential types. It also provides notifications of changes to + the root crednetial set. + + \see \ref kmq_msg_kcdb +*/ +#define KMSG_KCDB 2 + +/*! \brief NetIDMgr Module Manager messages + + \see \ref kmq_msg_kmm +*/ +#define KMSG_KMM 3 + +/*! \brief NetIDMgr Credential messages + + Notifications of crednetial events. These are the most important + events that a credentials provider should respond to. The + notifications provide co-oridination between credential providers + for performing basic credentials management tasks such as + obtaining new credentials for an identity, deleting credentials + for an identity, obtaining or deleting credentials of a particular + type for an identity etc. + + \see \ref cred_msgs + \see \ref kmq_msg_cred + */ +#define KMSG_CRED 4 + +/*! \brief Action list messages + + Notifications of changes in action state and firing of custom + actions. + + \see \ref kmq_msg_act + */ +#define KMSG_ACT 5 + +/*! \brief Alert messages + + Notifier is the component which displays alerts and error messages + when the NetIDMgr window is normally in operation and which + displays balloon prompts when the window is minimized to alert the + user to important messages such as credentials expiring etc. + + \note This is an internal message class. Components that are not + the notifier should not be subscribing to alert messages. + + \see \ref kmq_msg_alert + */ +#define KMSG_ALERT 6 + +/*! \brief Identity messages + + These are messages that are sent to the identity provider. These + are generally dispatched through a specific subscription object + and are not broadcast. + + \see \ref kmq_msg_ident + */ +#define KMSG_IDENT 7 + +/*! \brief Base message type ID for customized message types + */ +#define KMSGBASE_USER 16 + +/*@}*/ + +/*! \defgroup kmq_msg_system KMSG_SYSTEM subtypes +@{*/ +/*! \brief Generic initialization message + + This message is used by specific components to signal that the + recipient is to perform initialization tasks. As a convention, + the recipient should return KHM_ERROR_SUCCESS if it successfully + performed the initlization tasks or some other value if it failed + to do so. Failure to successfully initialize is usually taken to + mean that the recipient component is not able to perform its + function. + + Usually this is the first message to be received by the recipient. + + \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 + perform uninitilization tasks in preparation of termination. The + return value of this message is not used. + + Usually this is the last message to be received by the recipient. + + \see \ref pi_pt_cred_exit + */ +#define KMSG_SYSTEM_EXIT 2 + +/*! \brief Message completion + + This is an internal message + */ +#define KMSG_SYSTEM_COMPLETION 3 +/*@}*/ + +/*! \defgroup kmq_msg_kcdb KMSG_KCDB subtypes +@{*/ +#define KMSG_KCDB_IDENT 1 +#define KMSG_KCDB_CREDTYPE 2 +#define KMSG_KCDB_ATTRIB 3 +#define KMSG_KCDB_TYPE 4 + +/*! \brief Generic credentials request + + \see ::kcdb_cred_request for more information + */ +#define KMSG_KCDB_REQUEST 256 +/*@}*/ + +/*! \defgroup kmq_msg_kmm KMSG_KMM subtypes +@{*/ +#define KMSG_KMM_I_REG 1 + +#define KMSG_KMM_I_DONE 2 +/*@}*/ + +/*! \defgroup kmq_msg_act KMSG_ACT subtypes + @{*/ + +/*! \brief One or more actions changed state + + This message is sent in response to a call to + khui_enable_actions() or khui_enable_action() and indicates that + one or more actions have changed their state. + */ +#define KMSG_ACT_ENABLE 1 + +/*! \brief One or more actions changed check state + + Sent in response to khui_check_radio_action() or + khui_check_action() and indicates that one or more actions have + either been checked or unchecked. + */ +#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 + +/*! \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 + +/*! \brief Internal */ +#define KMSG_ACT_END_CMDLINE 131 + +/*@}*/ + +/*! \defgroup kmq_msg_cred KMSG_CRED subtypes + @{*/ +/*! \brief Root credential set changed + + This message is issued when the root credential set successfully + collected credentials from another credential set. + + \a uparam of the message is set to a bitmask indicating the change + that occured. It is a combination of ::KCDB_DELTA_ADD, + ::KCDB_DELTA_DEL and ::KCDB_DELTA_MODIFY. + */ +#define KMSG_CRED_ROOTDELTA 1 + +/*! \brief Re-enumerate credentials + + A notice to all credential providers to re-enumerate their + respective credentials. + + \note May be sent to individual credential subscriptions. + */ +#define KMSG_CRED_REFRESH 2 + +/*! \brief Change the password + + This message notifies credentials providers that a password change + request has been received. + + A plug-in handling this message that wishes to participate in the + password change operation is expected to add a + ::khui_new_creds_by_type to the list of participants in the + ::khui_new_creds structure by calling khui_cw_add_type(). + + The password change operation requires user interaction. Any + plug-ins that are participating in the operation need to provide a + user-interface. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \see khui_cw_add_type(), ::khui_new_creds, ::khui_new_creds_by_type + */ +#define KMSG_CRED_PASSWORD 16 + +/*! \brief Initiate the process of obtaining new credentials + + The UI sends this message to start the process of obtaining new + credentials. See \ref cred_acq for more information about + handling this message. + + A plug-in handling this message that wishes to participate in the + new credentials acquisition operation is expected to add a + ::khui_new_creds_by_type to hte list of participants in the + ::khui_new_creds structure by calling khui_cw_add_type(). + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \see \ref cred_acq, khui_cw_add_type(), ::khui_new_creds, + ::khui_new_creds_by_type + */ +#define KMSG_CRED_NEW_CREDS 17 + +/*! \brief Renew credentials + + This is a notification sent to individual credentials providers + that a specified identity's credentials should be renewed. + + A plug-in handling this message that wishes to participate in the + renew credentials operation is expected to add a + ::khui_new_creds_by_type to the list of participants in the + ::khui_new_creds structure by calling khui_cw_add_type(). + + Message parameters: + - \b vparam : Pointer to a khui_new_creds object + + \see khui_cw_add_type(), ::khui_new_creds, + ::khui_new_creds_by_type + */ +#define KMSG_CRED_RENEW_CREDS 18 + +/*! \brief Dialog setup + + 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 + finalizing dialog creation operations. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \note May be sent to individual credential subscriptions. + */ +#define KMSG_CRED_DIALOG_SETUP 19 + +/*! \brief Dialog pre-start + + Sent after all the credentials providers have responded to + ::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. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \note May be sent to individual credential subscriptions. + */ +#define KMSG_CRED_DIALOG_PRESTART 20 + +/*! \brief Dialog start + + A notification that the dialog is now in progress. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \note May be sent to individual credential subscriptions. + */ +#define KMSG_CRED_DIALOG_START 21 + +/*! \brief The primary identity of the new credentials dialog has changed + + This message is not sent out by the UI, but is reserved here for + use by individual credentials providers. The message may be sent + from the dialog procedure to the plugin. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \note Be careful when sending this message. All messages that are + not sent by the system should not be sent via broadcast. + Instead, create a subscription using kmq_create_subscription() + for the individual plugin that you want to send the message + and use one of the per-subscription message functions to send + the actual message. + */ +#define KMSG_CRED_DIALOG_NEW_IDENTITY 22 + +/*! \brief New credentials options have changed. + + This message is not sent out by the UI, but is reserved here for + use by individual credentials providers. The message may be sent + from the dialog procedure to the plugin. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \note Be careful when sending this message. All messages that are + not sent by the system should not be sent via broadcast. + Instead, create a subscription using kmq_create_subscription() + for the individual plugin that you want to send the message + and use one of the per-subscription message functions to send + the actual message. + */ +#define KMSG_CRED_DIALOG_NEW_OPTIONS 23 + +/*! \brief Process dialog + + Sent to all the credential providers to look at the contents of + the given ::khui_new_creds structure and do any required + processing. + + If the \a result field in the structure is set to + ::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. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \note May be sent to individual credential subscriptions. + */ +#define KMSG_CRED_PROCESS 24 + +/*! \brief End a credentials acquisition operation + + A notification that the credentials acquisition operation has + ended. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \note May be sent to individual credential subscriptions. + */ +#define KMSG_CRED_END 25 + +/*! \brief Import credentials from the operating system + + Notification to all credentials providers to import any available + credentials from the operating system. + + Message parameters: + - This message does not have any parameters +*/ +#define KMSG_CRED_IMPORT 26 + +/*! \brief Destroy credentials + + Notification that the specified credentials should be destroyed. + Once this message has completed processing a ::KMSG_CRED_REFRESH + message will be issued. + + The credentials that should be destroyed are specified by a + ::khui_action_context structure. The context that should be used + is the selection context. Hence, the credentials that must be + destroyed are the ones lised in the credential set (\a credset). + + Message parameters: + + - \b upram : Unused. Zero. + + - \b vparam : pointer to a ::khui_action_context structure which + describes which credentials need to be destroyed. + + */ +#define KMSG_CRED_DESTROY_CREDS 32 + +#if 0 +/*! \brief Parse an identity + + \note May be sent to individual credential subscriptions. + */ +#define KMSG_CRED_IDENT_PARSE 65 +#endif + +/*! \brief A property page is being launced + + Handlers of this message should determine whether or not they + should participate in the property sheet and if so, add a + ::khui_property_page structure to the property sheet. + + Message parameters: + - \b vparam : pointer to a ::khui_property_sheet structure + */ +#define KMSG_CRED_PP_BEGIN 128 + +/*! \brief A property page is about to be created + + Message parameters: + - \b vparam : pointer to a ::khui_property_sheet structure + + \note This message is merely a notification that the property + sheet is being created. Handlers should not modify the state + of the property sheet or pages at this time. + */ +#define KMSG_CRED_PP_PRECREATE 129 + +/*! \brief A property page has finished processing + + Handlers of this message should remove any ::khui_property_page + structures they added when processing ::KMSG_CRED_PP_BEGIN. + + Message parameters: + - \b vparam : pointer to a ::khui_property_sheet structure + */ +#define KMSG_CRED_PP_END 130 + +/*! \brief A property page has been destroyed + + Message parameters: + - \b vparam : pointer to a ::khui_property_sheet structure + + \note This is a notification that the property sheet processing + has been completed and that the property sheet data structures + should be freed. Any property page data structures should + have already been freed while processing KMSG_CRED_PP_END. + The validity of the ::khui_property_sheet structure should not + be relied upon while processing this message. + */ +#define KMSG_CRED_PP_DESTROY 131 + +/*! \brief An IP address change occurred + + There are no parameters for this message. The NetIDMgr + application handles this message and depending on configuration, + posts message for the individual credentials providers to either + obtain new credentials or renew old ones. + */ +#define KMSG_CRED_ADDR_CHANGE 140 + +/*! \brief Check if a KMSG_CRED subtype is a credentials acquisition message + + Dialog messages are those that deal with the new or initial + credentials acquisition dialog, from initial announcement to + dialog completion. + + Currently, the dialog messages are: + - ::KMSG_CRED_NEW_CREDS + - ::KMSG_CRED_RENEW_CREDS + - ::KMSG_CRED_DIALOG_SETUP + - ::KMSG_CRED_DIALOG_PRESTART + - ::KMSG_CRED_DIALOG_START + - ::KMSG_CRED_DIALOG_NEW_IDENTITY + - ::KMSG_CRED_DIALOG_NEW_OPTIONS + - ::KMSG_CRED_PROCESS + - ::KMSG_CRED_END + + All dialog message numbers are allocated in a contigous block. + + Note that while ::KMSG_CRED_PROCESS and ::KMSG_CRED_END are not + specific to dialogs, they are still included in this predicate + because they are also part of the dialog message sequence. + */ +#define IS_CRED_ACQ_MSG(msg) ((msg) >= 16 && (msg) <=31) + +/*@}*/ /* /KMSG_CRED subtypes */ + +/*! \defgroup kmq_msg_alert KMSG_ALERT Subtypes + @{*/ + +/*! \brief Show an alert + + Message parameters: + - \b vparam : held pointer to a ::khui_alert object + + \note The ::khui_alert object will be released when the processing + of this message completes. + */ +#define KMSG_ALERT_SHOW 1 + +/*! \brief Add an alert to the alert queue + + 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_QUEUE 2 + +/*! \brief Show the next queued alert + + There are no message parameters + */ +#define KMSG_ALERT_SHOW_QUEUED 3 + +/*! \brief Check if there are any queued messages and, if so, update the statusbar + + There are no message parameters + */ +#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 + @{*/ + +/*! \brief Initialize and start the identity provider + + + Sent by the KCDB to notify the identity provider that it is now + the current identity provider. + + Note that unlike regular plugins, an identity provider can be + loaded and inert (not provide any services). Also, the user may + switch between multiple identity providers on the fly. + */ +#define KMSG_IDENT_INIT 1 + +/*! \brief Stop the identity provider + + Sent by the KCDB as notificaton that the identity provider is no + longer the current provider. + */ +#define KMSG_IDENT_EXIT 2 + +/*! \brief Check if an identity name is valid + + This message is sent to the identity provider to verify the syntax + of an identity name. Note that only the syntax of the name is to + be verfied and not the actual physical existence of said identity. + + Message parameters: + + - \b vparam : pointer to ::kcdb_ident_name_xfer object. The + 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, 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: + + - KHM_ERROR_SUCCESS : The name was valid + - KHM_ERROR_INVALID_NAME : The name was invalid + */ +#define KMSG_IDENT_VALIDATE_NAME 3 + +/*! \brief Check if an identity is valid + + Sent to the identity provider to verify the validity of the given + identity. The provider should verify that the identity exists and + is in a state where it can be actively used. + + Depending on the result of the validation, the flags of the + identity should be updated. + + Message parameters: + - \b vparam : Handle to an identity cast as a void pointer. + */ +#define KMSG_IDENT_VALIDATE_IDENTITY 4 + +/*! \brief Canonicalize identity name + + The identity provider will be given a name, which it should put in + canonical form, adjusting case and any character replacement or + doing any relevant expansions if applicable, and place it in the + supplied buffer. + + Message parameters: + + - \b vparam : Pointer to a ::kcdb_ident_name_xfer structure + which provides the identity name to canonicalize in the \a + name_src member, and the buffer to store the canonical name + in the \a name_dest member. The \a name_dest buffer is + guaranteed to be at least KCDB_IDENT_MAXCCH_NAME characters + in size. + + If the name cannot be canonicalized for some reason, the + destination buffer should be set to a zero-length string and the + \a result member of the ::kcdb_ident_name_xfer structure should be + set to the error code. If the destination buffer is set to a + zero-length string and \a result is KHM_ERROR_SUCCESS, then the + original name provided in \a name_src is assumed to be already in + canonical form. + */ +#define KMSG_IDENT_CANON_NAME 5 + +/*! \brief Compare names + + Compare two identity names. The names that are given aren't + guaranteed to be in canonical form. The return value should be + akin to strcmp(). + + Message parameters: + + - \b vparam : A pointer to a ::kcdb_ident_name_xfer structure. + The \a name_src member points at the first name, and the \a + name_alt member specifies the second name. The result of the + comparison should be place in \a result. + */ +#define KMSG_IDENT_COMPARE_NAME 6 + +/*! \brief Set the default identity + + Set or unset the default identity. To set the default identity, + the \a uparam parameter will be set to a non-zero value and a + handle to the identity will be specified in \a vparam. To unset + the default identity (i.e. not have a default identity), a zero + value will be specified in \a uparam and no identities will be + specified in \a vparam. + + When setting a default identity, the identity provider will + receive this message prior to the ::KCDB_IDENT_FLAG_DEFAULT bit + being set or reset on any identity. It should return + KHM_ERROR_SUCCESS if the requested operation can be performed. + Returning any other value will abort the operation and will leave + the default identity unchanged. + + When resetting the default identity, this message should be + treated only as a notification. + + Message parameters: + + - \a uparam : Is non-zero if an identity is being made default. If + this is zero, then identity should be the default. + + - \a vparam : A handle to the identity to be made default if \a + uparam is non-zero. NULL otherwise. + + Return value: + + - KHM_ERROR_SUCCESS : The identity should be marked as default + - Any other value : The identity should not be marked as default + + */ +#define KMSG_IDENT_SET_DEFAULT 7 + +/*! \brief Set an identity as searchable + + Set or reset the searchable bit on an identity. If the \a uparam + parameter is non-zero, then the searchable bit is being set. + Otherwise it is being reset. The identity provider should return + KHM_ERROR_SUCCESS in order to indicate that the identity should be + marked as searchable. Any other value will result in the + searchable bit being reset on the identity. + + Message parameters: + + - \a uparam : Is non-zero if the searchable bit is being set. Zero + otherwise. + + - \a vparam : Handle to the identity + + Return value: + + - KHM_ERROR_SUCCESS: The identity should be marked as searchable + - Any other value : The identity should not be marked as default + */ +#define KMSG_IDENT_SET_SEARCHABLE 8 + +/*! \brief Get information about an identity + + */ +#define KMSG_IDENT_GET_INFO 9 + +/*! \brief Enumerate known and accessible identities + */ +#define KMSG_IDENT_ENUM_KNOWN 10 + +/*! \brief Update information about an identity + */ +#define KMSG_IDENT_UPDATE 11 + +/*! \brief Retrieve the user interface callback function + + When obtaining new credentials, the user interface needs to obtain + a callback function which will provide identity selection + controls. + + Message parameters: + + - \a uparam : Not used + + - \a vparam : pointer to a ::khui_ident_new_creds_cb which will + receive the call back. + */ +#define KMSG_IDENT_GET_UI_CALLBACK 12 + +/*! \brief Notification of the creation of an identity + + This should be considered just a notification. The identit + provider does not have an opportunity to veto the creation of an + identity whose name has been found to be valid. However, when + handing this notification, the identity provider can: + + - Change the flags of the identity and/or marking the identity as + invalid. + + - Change the default identity. + + Note that this notification is sent before the general :;KMSG_KCDB + notification of the identity creation is sent. + + Message parameters: + + - \a uparam : Not used. + + - \p vparam : handle to the identity + */ +#define KMSG_IDENT_NOTIFY_CREATE 13 + +/*@}*/ /* /KMSG_IDENT subtypes */ + +/*@}*/ /* / message types */ +/*@}*/ /* / kmq */ + +#endif diff --git a/src/windows/identity/include/netidmgr.h b/src/windows/identity/include/netidmgr.h index 94e188ff1..cc680fcad 100644 --- a/src/windows/identity/include/netidmgr.h +++ b/src/windows/identity/include/netidmgr.h @@ -1,43 +1,43 @@ -/* - * 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_H -#define __NETIDMGR_H - -#include "khdefs.h" - -#include "utils.h" -#include "khuidefs.h" -#include "kmq.h" -#include "khmsgtypes.h" -#include "kcreddb.h" -#include "kherr.h" -#include "kherror.h" -#include "kconfig.h" -#include "kmm.h" -#include "kplugin.h" - -#endif +/* + * 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_H +#define __NETIDMGR_H + +#include "khdefs.h" + +#include "utils.h" +#include "khuidefs.h" +#include "kmq.h" +#include "khmsgtypes.h" +#include "kcreddb.h" +#include "kherr.h" +#include "kherror.h" +#include "kconfig.h" +#include "kmm.h" +#include "kplugin.h" + +#endif diff --git a/src/windows/identity/kconfig/api.c b/src/windows/identity/kconfig/api.c index 60984358f..6c7ac8e47 100644 --- a/src/windows/identity/kconfig/api.c +++ b/src/windows/identity/kconfig/api.c @@ -1,2656 +1,2656 @@ -/* -* 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 - -kconf_conf_space * conf_root = NULL; -kconf_handle * conf_handles = NULL; -kconf_handle * conf_free_handles = NULL; - -CRITICAL_SECTION cs_conf_global; -CRITICAL_SECTION cs_conf_handle; -LONG conf_init = 0; -LONG conf_status = 0; - -void init_kconf(void) { - if(InterlockedIncrement(&conf_init) == 1L) { - /* we are the first */ - InitializeCriticalSection(&cs_conf_global); - EnterCriticalSection(&cs_conf_global); - conf_root = khcint_create_empty_space(); - conf_root->name = PWCSDUP(L"Root"); - conf_root->regpath = PWCSDUP(CONFIG_REGPATHW); - conf_root->refcount++; - conf_status = 1; - InitializeCriticalSection(&cs_conf_handle); - LeaveCriticalSection(&cs_conf_global); - } - /* else assume we are already initialized */ -} - -void exit_kconf(void) { - if(khc_is_config_running()) { - kconf_handle * h; - - EnterCriticalSection(&cs_conf_global); - - conf_init = 0; - conf_status = 0; - - khcint_free_space(conf_root); - - LeaveCriticalSection(&cs_conf_global); - DeleteCriticalSection(&cs_conf_global); - - EnterCriticalSection(&cs_conf_handle); - while(conf_free_handles) { - LPOP(&conf_free_handles, &h); - if(h) { - PFREE(h); - } - } - - while(conf_handles) { - LPOP(&conf_handles, &h); - if(h) { - PFREE(h); - } - } - LeaveCriticalSection(&cs_conf_handle); - DeleteCriticalSection(&cs_conf_handle); - } -} - -#if defined(DEBUG) && (defined(KH_BUILD_PRIVATE) || defined(KH_BUILD_SPECIAL)) - -#include - -static void -khcint_dump_space(FILE * f, kconf_conf_space * sp) { - - kconf_conf_space * sc; - - fprintf(f, "c12\t[%S]\t[%S]\t%d\t0x%x\tWin(%s|%s)|%s\n", - ((sp->regpath) ? sp->regpath : L"!No Reg path"), - sp->name, - (int) sp->refcount, - (int) sp->flags, - ((sp->regkey_user)? "HKCU" : ""), - ((sp->regkey_machine)? "HKLM" : ""), - ((sp->schema)? "Schema" : "")); - - - sc = TFIRSTCHILD(sp); - while(sc) { - - khcint_dump_space(f, sc); - - sc = LNEXT(sc); - } -} - -KHMEXP void KHMAPI -khcint_dump_handles(FILE * f) { - if (khc_is_config_running()) { - kconf_handle * h, * sh; - - EnterCriticalSection(&cs_conf_handle); - EnterCriticalSection(&cs_conf_global); - - fprintf(f, "c00\t*** Active handles ***\n"); - fprintf(f, "c01\tHandle\tName\tFlags\tRegpath\n"); - - h = conf_handles; - while(h) { - kconf_conf_space * sp; - - sp = h->space; - - if (!khc_is_handle(h) || sp == NULL) { - - fprintf(f, "c02\t!!INVALID HANDLE!!\n"); - - } else { - - fprintf(f, "c02\t0x%p\t[%S]\t0x%x\t[%S]\n", - h, - sp->name, - h->flags, - sp->regpath); - - sh = khc_shadow(h); - - while(sh) { - - sp = sh->space; - - if (!khc_is_handle(sh) || sp == NULL) { - - fprintf(f, "c02\t0x%p:Shadow:0x%p\t[!!INVALID HANDLE!!]\n", - h, sh); - - } else { - - fprintf(f, "c02\t0x%p:Shadow:0x%p,[%S]\t0x%x\t[%S]\n", - h, sh, - sp->name, - sh->flags, - sp->regpath); - - } - - sh = khc_shadow(sh); - } - - } - - h = LNEXT(h); - } - - fprintf(f, "c03\t------ End ---------\n"); - - fprintf(f, "c10\t*** Active Configuration Spaces ***\n"); - fprintf(f, "c11\tReg path\tName\tRefcount\tFlags\tLayers\n"); - - khcint_dump_space(f, conf_root); - - fprintf(f, "c13\t------ End ---------\n"); - - LeaveCriticalSection(&cs_conf_global); - LeaveCriticalSection(&cs_conf_handle); - - } else { - fprintf(f, "c00\t------- KHC Configuration not running -------\n"); - } -} - -#endif - -/* obtains cs_conf_handle/cs_conf_global */ -kconf_handle * -khcint_handle_from_space(kconf_conf_space * s, khm_int32 flags) -{ - kconf_handle * h; - - EnterCriticalSection(&cs_conf_handle); - LPOP(&conf_free_handles, &h); - if(!h) { - h = PMALLOC(sizeof(kconf_handle)); - assert(h != NULL); - } - ZeroMemory((void *) h, sizeof(kconf_handle)); - - h->magic = KCONF_HANDLE_MAGIC; - khcint_space_hold(s); - h->space = s; - h->flags = flags; - - LPUSH(&conf_handles, h); - LeaveCriticalSection(&cs_conf_handle); - - return h; -} - -/* obtains cs_conf_handle/cs_conf_global */ -void -khcint_handle_free(kconf_handle * h) -{ - kconf_handle * lower; - - EnterCriticalSection(&cs_conf_handle); -#ifdef DEBUG - /* check if the handle is actually in use */ - { - kconf_handle * a; - a = conf_handles; - while(a) { - if(h == a) - break; - a = LNEXT(a); - } - - if(a == NULL) { - DebugBreak(); - - /* hmm. the handle was not in the in-use list */ - LeaveCriticalSection(&cs_conf_handle); - return; - } - } -#endif - while(h) { - LDELETE(&conf_handles, h); - if(h->space) { - khcint_space_release(h->space); - h->space = NULL; - } - lower = h->lower; - h->magic = 0; - LPUSH(&conf_free_handles, h); - h = lower; - } - LeaveCriticalSection(&cs_conf_handle); -} - -/* obains cs_conf_handle/cs_conf_global */ -kconf_handle * -khcint_handle_dup(kconf_handle * o) -{ - kconf_handle * h; - kconf_handle * r; - - r = khcint_handle_from_space(o->space, o->flags); - h = r; - - while(o->lower) { - h->lower = khcint_handle_from_space(o->lower->space, o->lower->flags); - - o = o->lower; - h = h->lower; - } - - return r; -} - -/* obtains cs_conf_global */ -void -khcint_space_hold(kconf_conf_space * s) { - EnterCriticalSection(&cs_conf_global); - s->refcount ++; - LeaveCriticalSection(&cs_conf_global); -} - -/* called with cs_conf_global */ -void -khcint_try_free_space(kconf_conf_space * s) { - - if (TFIRSTCHILD(s) == NULL && - s->refcount == 0 && - s->schema == NULL) { - - kconf_conf_space * p; - - p = TPARENT(s); - - if (p == NULL) - return; - - TDELCHILD(p, s); - - khcint_free_space(s); - - khcint_try_free_space(p); - } -} - -/* obtains cs_conf_global */ -void -khcint_space_release(kconf_conf_space * s) { - khm_int32 l; - - EnterCriticalSection(&cs_conf_global); - - l = -- s->refcount; - if (l == 0) { - if(s->regkey_machine) - RegCloseKey(s->regkey_machine); - if(s->regkey_user) - RegCloseKey(s->regkey_user); - s->regkey_machine = NULL; - s->regkey_user = NULL; - - if (s->flags & - (KCONF_SPACE_FLAG_DELETE_M | - KCONF_SPACE_FLAG_DELETE_U)) { - khcint_remove_space(s, s->flags); - } else { -#ifdef USE_TRY_FREE - /* even if the refcount is zero, we shouldn't free a - configuration space just yet since that doesn't play - well with the configuration space enumeration mechanism - which expects the spaces to dangle around if there is a - corresponding registry key or schema. */ - khcint_try_free_space(s); -#endif - } - } - - LeaveCriticalSection(&cs_conf_global); -} - -/* case sensitive replacement for RegOpenKeyEx */ -LONG -khcint_RegOpenKeyEx(HKEY hkey, LPCWSTR sSubKey, DWORD ulOptions, - REGSAM samDesired, PHKEY phkResult) { - int i; - wchar_t sk_name[KCONF_MAXCCH_NAME]; - FILETIME ft; - size_t cch; - HKEY hkp = NULL; - const wchar_t * t; - LONG rv = ERROR_SUCCESS; - - hkp = hkey; - t = sSubKey; - - /* check for case insensitive prefix first */ - if (!_wcsnicmp(sSubKey, CONFIG_REGPATHW, ARRAYLENGTH(CONFIG_REGPATHW) - 1)) { - HKEY hkt; - - t = sSubKey + (ARRAYLENGTH(CONFIG_REGPATHW) - 1); - -#ifdef DEBUG - assert(*t == L'\0' || *t == L'\\'); -#endif - - rv = RegOpenKeyEx(hkp, - CONFIG_REGPATHW, - ulOptions, - samDesired, - &hkt); - - if (rv != ERROR_SUCCESS) - return rv; - - if (*t == L'\0') { - *phkResult = hkt; - return rv; - } - - t++; - hkp = hkt; - } - - /* descend down the components of the subkey */ - while(TRUE) { - wchar_t * slash; - HKEY hkt; - - slash = wcschr(t, L'\\'); - if (slash == NULL) - break; - - if (FAILED(StringCchCopyN(sk_name, ARRAYLENGTH(sk_name), - t, slash - t))) { - rv = ERROR_CANTOPEN; - goto _cleanup; - } - - sk_name[slash - t] = L'\0'; - t = slash+1; - - if (khcint_RegOpenKeyEx(hkp, sk_name, ulOptions, samDesired, &hkt) == - ERROR_SUCCESS) { - - if (hkp != hkey) - RegCloseKey(hkp); - hkp = hkt; - - } else { - - rv = ERROR_CANTOPEN; - goto _cleanup; - - } - } - - /* by now hkp is a handle to the parent of the last component in - the subkey. t is a pointer to the last component. */ - - if (FAILED(StringCchLength(t, KCONF_MAXCCH_NAME, &cch))) { - rv = ERROR_CANTOPEN; - goto _cleanup; - } - - /* go through and find the case sensitive match for the key */ - - for (i=0; ;i++) { - LONG l; - DWORD dw; - - dw = ARRAYLENGTH(sk_name); - l = RegEnumKeyEx(hkp, i, sk_name, &dw, - NULL, NULL, NULL, &ft); - - if (l != ERROR_SUCCESS) { - rv = ERROR_CANTOPEN; - goto _cleanup; - } - - if (!(wcsncmp(sk_name, t, cch))) { - /* bingo! ?? */ - if (cch < KCONF_MAXCCH_NAME && - (sk_name[cch] == L'\0' || - sk_name[cch] == L'~')) { - rv = RegOpenKeyEx(hkp, sk_name, ulOptions, - samDesired, phkResult); - goto _cleanup; - } - } - } - - _cleanup: - if (hkp != hkey && hkp != NULL) - RegCloseKey(hkp); - - return rv; -} - -/*! \internal - - \note This function is not a good replacement for RegDeleteKey since - it deletes all the subkeys in addition to the key being deleted. - */ -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'~')) { - - /* instead of calling RegDeleteKey we call SHDeleteKey - because we want to blow off all the subkeys as - well. This is different from the behavior of - RegDeleteKey making khcint_RegDeleteKey not a very - good case sensitive replacement for - RegDeleteKey. */ - - rv = SHDeleteKey(hKey, sk_name); - goto _cleanup; - } - } - } - - _cleanup: - return rv; -} - -LONG -khcint_RegCreateKeyEx(HKEY hKey, - LPCWSTR lpSubKey, - DWORD Reserved, - LPWSTR lpClass, - DWORD dwOptions, - REGSAM samDesired, - LPSECURITY_ATTRIBUTES lpSecurityAttributes, - PHKEY phkResult, - LPDWORD lpdwDisposition) { - LONG l; - int i; - long index = 0; - wchar_t sk_name[KCONF_MAXCCH_NAME]; /* hard limit in Windows */ - FILETIME ft; - size_t cch; - const wchar_t * t; - LONG rv = ERROR_SUCCESS; - HKEY hkp = NULL; - - hkp = hKey; - t = lpSubKey; - - /* check for case insensitive prefix first */ - if (!_wcsnicmp(lpSubKey, CONFIG_REGPATHW, ARRAYLENGTH(CONFIG_REGPATHW) - 1)) { - HKEY hkt; - - t = lpSubKey + (ARRAYLENGTH(CONFIG_REGPATHW) - 1); - -#ifdef DEBUG - assert(*t == L'\0' || *t == L'\\'); -#endif - - rv = RegCreateKeyEx(hkp, - CONFIG_REGPATHW, - Reserved, - lpClass, - dwOptions, - samDesired, - lpSecurityAttributes, - &hkt, - lpdwDisposition); - - if (rv != ERROR_SUCCESS) - return rv; - - if (*t == L'\0') { - *phkResult = hkt; - return rv; - } - - t++; - hkp = hkt; - } - - while(TRUE) { - wchar_t * slash; - HKEY hkt; - - slash = wcschr(t, L'\\'); - if (slash == NULL) - break; - - if (FAILED(StringCchCopyN(sk_name, ARRAYLENGTH(sk_name), - t, slash - t))) { - rv = ERROR_CANTOPEN; - goto _cleanup; - } - - sk_name[slash - t] = L'\0'; - t = slash+1; - - if (khcint_RegOpenKeyEx(hkp, sk_name, 0, samDesired, &hkt) == - ERROR_SUCCESS) { - - if (hkp != hKey) - RegCloseKey(hkp); - hkp = hkt; - } else { - - rv = RegCreateKeyEx(hKey, - lpSubKey, - Reserved, - lpClass, - dwOptions, - samDesired, - lpSecurityAttributes, - phkResult, - lpdwDisposition); - goto _cleanup; - } - } - - if (FAILED(StringCchLength(t, KCONF_MAXCCH_NAME, &cch))) { - rv = ERROR_CANTOPEN; - goto _cleanup; - } - - for (i=0; ;i++) { - DWORD dw; - - dw = ARRAYLENGTH(sk_name); - l = RegEnumKeyEx(hkp, i, sk_name, &dw, - NULL, NULL, NULL, &ft); - - if (l != ERROR_SUCCESS) - break; - - if (!(wcsncmp(sk_name, t, cch))) { - /* bingo! ?? */ - if (sk_name[cch] == L'\0' || - sk_name[cch] == L'~') { - l = RegOpenKeyEx(hkp, sk_name, 0, - samDesired, phkResult); - if (l == ERROR_SUCCESS && lpdwDisposition) - *lpdwDisposition = REG_OPENED_EXISTING_KEY; - rv = l; - goto _cleanup; - } - } - - if (!_wcsnicmp(sk_name, t, cch) && - (sk_name[cch] == L'\0' || - sk_name[cch] == L'~')) { - long new_idx; - - if (sk_name[cch] == L'\0') - new_idx = 1; - else if (cch + 1 < KCONF_MAXCCH_NAME) - new_idx = wcstol(sk_name + (cch + 1), NULL, 10); - else - return ERROR_BUFFER_OVERFLOW; - - assert(new_idx > 0); - - if (new_idx > index) - index = new_idx; - } - } - - if (index != 0) { - if (FAILED(StringCbPrintf(sk_name, sizeof(sk_name), - L"%s~%d", t, index))) - return ERROR_BUFFER_OVERFLOW; - } else { - StringCbCopy(sk_name, sizeof(sk_name), t); - } - - rv = RegCreateKeyEx(hkp, - sk_name, - Reserved, - lpClass, - dwOptions, - samDesired, - lpSecurityAttributes, - phkResult, - lpdwDisposition); - - _cleanup: - - if (hkp != hKey && hkp != NULL) - RegCloseKey(hkp); - - return rv; -} - -/* obtains cs_conf_global */ -HKEY -khcint_space_open_key(kconf_conf_space * s, khm_int32 flags) { - HKEY hk = NULL; - int nflags = 0; - DWORD disp; - if(flags & KCONF_FLAG_MACHINE) { - if(s->regkey_machine) - return s->regkey_machine; - if((khcint_RegOpenKeyEx(HKEY_LOCAL_MACHINE, s->regpath, 0, - KEY_READ | KEY_WRITE, &hk) != - ERROR_SUCCESS) && - !(flags & KHM_PERM_WRITE)) { - - if(khcint_RegOpenKeyEx(HKEY_LOCAL_MACHINE, s->regpath, 0, - KEY_READ, &hk) == ERROR_SUCCESS) { - nflags = KHM_PERM_READ; - } - - } - if(!hk && (flags & KHM_FLAG_CREATE)) { - - khcint_RegCreateKeyEx(HKEY_LOCAL_MACHINE, - s->regpath, - 0, - NULL, - REG_OPTION_NON_VOLATILE, - KEY_READ | KEY_WRITE, - NULL, - &hk, - &disp); - } - if(hk) { - EnterCriticalSection(&cs_conf_global); - s->regkey_machine = hk; - s->regkey_machine_flags = nflags; - LeaveCriticalSection(&cs_conf_global); - } - - return hk; - } else { - if(s->regkey_user) - return s->regkey_user; - if((khcint_RegOpenKeyEx(HKEY_CURRENT_USER, s->regpath, 0, - KEY_READ | KEY_WRITE, &hk) != - ERROR_SUCCESS) && - !(flags & KHM_PERM_WRITE)) { - if(khcint_RegOpenKeyEx(HKEY_CURRENT_USER, s->regpath, 0, - KEY_READ, &hk) == ERROR_SUCCESS) { - nflags = KHM_PERM_READ; - } - } - if(!hk && (flags & KHM_FLAG_CREATE)) { - khcint_RegCreateKeyEx(HKEY_CURRENT_USER, - s->regpath, 0, NULL, - REG_OPTION_NON_VOLATILE, - KEY_READ | KEY_WRITE, - NULL, &hk, &disp); - } - if(hk) { - EnterCriticalSection(&cs_conf_global); - s->regkey_user = hk; - s->regkey_user_flags = nflags; - LeaveCriticalSection(&cs_conf_global); - } - - return hk; - } -} - -/* obtains cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_shadow_space(khm_handle upper, khm_handle lower) -{ - kconf_handle * h; - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - if(!khc_is_handle(upper)) { -#ifdef DEBUG - DebugBreak(); -#endif - return KHM_ERROR_INVALID_PARAM; - } - - h = (kconf_handle *) upper; - - EnterCriticalSection(&cs_conf_handle); - if(h->lower) { - EnterCriticalSection(&cs_conf_global); - khcint_handle_free(h->lower); - LeaveCriticalSection(&cs_conf_global); - h->lower = NULL; - } - - if(khc_is_handle(lower)) { - kconf_handle * l; - kconf_handle * lc; - - l = (kconf_handle *) lower; - lc = khcint_handle_dup(l); - h->lower = lc; - } - LeaveCriticalSection(&cs_conf_handle); - - return KHM_ERROR_SUCCESS; -} - -/* no locks */ -kconf_conf_space * -khcint_create_empty_space(void) { - kconf_conf_space * r; - - r = PMALLOC(sizeof(kconf_conf_space)); - assert(r != NULL); - ZeroMemory(r,sizeof(kconf_conf_space)); - - return r; -} - -/* called with cs_conf_global */ -void -khcint_free_space(kconf_conf_space * r) { - kconf_conf_space * c; - - if(!r) - return; - - TPOPCHILD(r, &c); - while(c) { - khcint_free_space(c); - TPOPCHILD(r, &c); - } - - if(r->name) - PFREE(r->name); - - if(r->regpath) - PFREE(r->regpath); - - if(r->regkey_machine) - RegCloseKey(r->regkey_machine); - - if(r->regkey_user) - RegCloseKey(r->regkey_user); - - PFREE(r); -} - -/* obtains cs_conf_global */ -khm_int32 -khcint_open_space(kconf_conf_space * parent, - const wchar_t * sname, size_t n_sname, - khm_int32 flags, kconf_conf_space **result) { - kconf_conf_space * p; - kconf_conf_space * c; - HKEY pkey = NULL; - HKEY ckey = NULL; - wchar_t buf[KCONF_MAXCCH_NAME]; - size_t cb_regpath = 0; - - if(!parent) - p = conf_root; - else - p = parent; - - if(n_sname >= KCONF_MAXCCH_NAME || n_sname <= 0) - return KHM_ERROR_INVALID_PARAM; - - StringCchCopyN(buf, ARRAYLENGTH(buf), sname, n_sname); - - /* see if there is already a config space by this name. if so, - return it. Note that if the configuration space is specified - in a schema, we would find it here. */ - EnterCriticalSection(&cs_conf_global); - c = TFIRSTCHILD(p); - while(c) { - if(c->name && !wcscmp(c->name, buf)) - break; - - c = LNEXT(c); - } - LeaveCriticalSection(&cs_conf_global); - - if(c) { - - if (c->flags & KCONF_SPACE_FLAG_DELETED) { - if (flags & KHM_FLAG_CREATE) { - c->flags &= ~(KCONF_SPACE_FLAG_DELETED | - KCONF_SPACE_FLAG_DELETE_M | - KCONF_SPACE_FLAG_DELETE_U); - } else { - *result = NULL; - return KHM_ERROR_NOT_FOUND; - } - } - - khcint_space_hold(c); - *result = c; - return KHM_ERROR_SUCCESS; - } - - if(!(flags & KHM_FLAG_CREATE)) { - - /* we are not creating the space, so it must exist in the form of a - registry key in HKLM or HKCU. If it existed as a schema, we - would have already retured it above. */ - - if (flags & KCONF_FLAG_USER) - pkey = khcint_space_open_key(p, KHM_PERM_READ | KCONF_FLAG_USER); - - if((!pkey || - (khcint_RegOpenKeyEx(pkey, buf, 0, KEY_READ, &ckey) != - ERROR_SUCCESS)) - && (flags & KCONF_FLAG_MACHINE)) { - - pkey = khcint_space_open_key(p, KHM_PERM_READ | KCONF_FLAG_MACHINE); - if(!pkey || - (khcint_RegOpenKeyEx(pkey, buf, 0, KEY_READ, &ckey) != - ERROR_SUCCESS)) { - *result = NULL; - - return KHM_ERROR_NOT_FOUND; - } - } - - if(ckey) { - RegCloseKey(ckey); - ckey = NULL; - } - } - - c = khcint_create_empty_space(); - - /*SAFE: buf: is of known length < KCONF_MAXCCH_NAME */ - c->name = PWCSDUP(buf); - - /*SAFE: p->regpath: is valid since it was set using this same - function. */ - /*SAFE: buf: see above */ - cb_regpath = (wcslen(p->regpath) + wcslen(buf) + 2) * sizeof(wchar_t); - c->regpath = PMALLOC(cb_regpath); - - assert(c->regpath != NULL); - - /*SAFE: c->regpath: allocated above to be big enough */ - /*SAFE: p->regpath: see above */ - StringCbCopy(c->regpath, cb_regpath, p->regpath); - StringCbCat(c->regpath, cb_regpath, L"\\"); - - /*SAFE: buf: see above */ - StringCbCat(c->regpath, cb_regpath, buf); - - khcint_space_hold(c); - - EnterCriticalSection(&cs_conf_global); - TADDCHILD(p,c); - LeaveCriticalSection(&cs_conf_global); - - *result = c; - return KHM_ERROR_SUCCESS; -} - -/* obtains cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -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; - const wchar_t * str; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!khc_is_config_running()) { - return KHM_ERROR_NOT_READY; - } - - if(!result || (parent && !khc_is_handle(parent))) { -#ifdef DEBUG - DebugBreak(); -#endif - return KHM_ERROR_INVALID_PARAM; - } - - if(!parent) - p = conf_root; - else { - h = (kconf_handle *) parent; - p = khc_space_from_handle(parent); - } - - khcint_space_hold(p); - - /* if none of these flags are specified, make it seem like all of - them were */ - if(!(flags & KCONF_FLAG_USER) && - !(flags & KCONF_FLAG_MACHINE) && - !(flags & KCONF_FLAG_SCHEMA)) - flags |= KCONF_FLAG_USER | KCONF_FLAG_MACHINE | KCONF_FLAG_SCHEMA; - - if(cspace == NULL) { - *result = (khm_handle) khcint_handle_from_space(p, flags); - khcint_space_release(p); - return KHM_ERROR_SUCCESS; - } - - if(FAILED(StringCbLength(cspace, KCONF_MAXCB_PATH, &cbsize))) { - khcint_space_release(p); - *result = NULL; - return KHM_ERROR_INVALID_PARAM; - } - - str = cspace; - while(TRUE) { - const wchar_t * end = NULL; - - if (!(flags & KCONF_FLAG_NOPARSENAME)) { - - end = wcschr(str, L'\\'); /* safe because cspace was - validated above */ - } - - if(!end) { - if(flags & KCONF_FLAG_TRAILINGVALUE) { - /* we are at the value component */ - c = p; - khcint_space_hold(c); - break; - } else - end = str + wcslen(str); /* safe because cspace was - validated above */ - } - - rv = khcint_open_space(p, str, end - str, flags, &c); - - if(KHM_SUCCEEDED(rv) && (*end == L'\\')) { - khcint_space_release(p); - p = c; - c = NULL; - str = end+1; - } - else - break; - } - - khcint_space_release(p); - if(KHM_SUCCEEDED(rv)) { - *result = khcint_handle_from_space(c, flags); - } else - *result = NULL; - - if (c) - khcint_space_release(c); - - return rv; -} - -/* obtains cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_close_space(khm_handle csp) { - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - if(!khc_is_handle(csp)) { -#ifdef DEBUG - DebugBreak(); -#endif - return KHM_ERROR_INVALID_PARAM; - } - - khcint_handle_free((kconf_handle *) csp); - return KHM_ERROR_SUCCESS; -} - -/* obtains cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_read_string(khm_handle pconf, - const wchar_t * pvalue, - wchar_t * buf, - khm_size * bufsize) -{ - kconf_conf_space * c; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - do { - HKEY hku = NULL; - HKEY hkm = NULL; - const wchar_t * value = NULL; - int free_space = 0; - khm_handle conf = NULL; - DWORD size; - DWORD type; - LONG hr; - - int i; - - if((value = wcsrchr(pvalue, L'\\')) != NULL) { - - if(KHM_FAILED(khc_open_space( - pconf, - pvalue, - KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), - &conf))) - goto _shadow; - - free_space = 1; - - if (value) { - value++; - } else { -#ifdef DEBUG - assert(FALSE); -#endif - } - } else { - value = pvalue; - conf = pconf; - free_space = 0; - } - - if(!khc_is_handle(conf)) - goto _shadow; - - c = khc_space_from_handle(conf); - - if(khc_is_user_handle(conf)) - hku = khcint_space_open_key(c, KHM_PERM_READ); - - if(khc_is_machine_handle(conf)) - hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); - - size = (DWORD) *bufsize; - if(hku) { - hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size); - if(hr == ERROR_SUCCESS) { - if(type != REG_SZ) { - rv = KHM_ERROR_TYPE_MISMATCH; - goto _exit; - } - else { - *bufsize = size; - /* if buf==NULL, RegQueryValueEx will return success and just return the - required buffer size in 'size' */ - rv = (buf)? KHM_ERROR_SUCCESS: KHM_ERROR_TOO_LONG; - goto _exit; - } - } else { - if(hr == ERROR_MORE_DATA) { - *bufsize = size; - rv = KHM_ERROR_TOO_LONG; - goto _exit; - } - } - } - - size = (DWORD) *bufsize; - if(hkm) { - hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size); - if(hr == ERROR_SUCCESS) { - if(type != REG_SZ) { - rv = KHM_ERROR_TYPE_MISMATCH; - goto _exit; - } - else { - *bufsize = size; - rv = (buf)? KHM_ERROR_SUCCESS: KHM_ERROR_TOO_LONG; - goto _exit; - } - } else { - if(hr == ERROR_MORE_DATA) { - *bufsize = size; - rv = KHM_ERROR_TOO_LONG; - goto _exit; - } - } - } - - if(c->schema && khc_is_schema_handle(conf)) { - for(i=0;inSchema;i++) { - if(c->schema[i].type == KC_STRING && !wcscmp(value, c->schema[i].name)) { - /* found it */ - size_t cbsize = 0; - - if(!c->schema[i].value) { - rv = KHM_ERROR_NOT_FOUND; - goto _exit; - } - - if(FAILED(StringCbLength((wchar_t *) c->schema[i].value, KCONF_MAXCB_STRING, &cbsize))) { - rv = KHM_ERROR_NOT_FOUND; - goto _exit; - } - cbsize += sizeof(wchar_t); - - if(!buf || *bufsize < cbsize) { - *bufsize = cbsize; - rv = KHM_ERROR_TOO_LONG; - goto _exit; - } - - StringCbCopy(buf, *bufsize, (wchar_t *) c->schema[i].value); - *bufsize = cbsize; - rv = KHM_ERROR_SUCCESS; - goto _exit; - } - } - } - -_shadow: - if(free_space && conf) - khc_close_space(conf); - - if(khc_is_shadowed(pconf)) { - pconf = khc_shadow(pconf); - continue; - } else { - rv = KHM_ERROR_NOT_FOUND; - break; - } - -_exit: - if(free_space && conf) - khc_close_space(conf); - break; - - } while(TRUE); - - return rv; -} - -/* obtains cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_read_int32(khm_handle pconf, const wchar_t * pvalue, khm_int32 * buf) { - kconf_conf_space * c; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - if(!buf || !pvalue) - return KHM_ERROR_INVALID_PARAM; - - do { - DWORD size; - DWORD type; - LONG hr; - HKEY hku = NULL; - HKEY hkm = NULL; - - const wchar_t * value = NULL; - int free_space = 0; - khm_handle conf = NULL; - - int i; - - if((value = wcsrchr(pvalue, L'\\')) != NULL) { - if(KHM_FAILED(khc_open_space( - pconf, - pvalue, - KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), - &conf))) - goto _shadow; - free_space = 1; - - if (value) { - value++; - } else { -#ifdef DEBUG - assert(FALSE); -#endif - } - } else { - value = pvalue; - conf = pconf; - free_space = 0; - } - - if(!khc_is_handle(conf) || !buf) - goto _shadow; - - c = khc_space_from_handle(conf); - - if(khc_is_user_handle(conf)) - hku = khcint_space_open_key(c, KHM_PERM_READ); - - if(khc_is_machine_handle(conf)) - hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); - - size = sizeof(DWORD); - if(hku) { - hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size); - if(hr == ERROR_SUCCESS) { - if(type != REG_DWORD) { - rv = KHM_ERROR_TYPE_MISMATCH; - goto _exit; - } - else { - rv = KHM_ERROR_SUCCESS; - goto _exit; - } - } - } - - size = sizeof(DWORD); - if(hkm) { - hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size); - if(hr == ERROR_SUCCESS) { - if(type != REG_DWORD) { - rv= KHM_ERROR_TYPE_MISMATCH; - goto _exit; - } - else { - rv= KHM_ERROR_SUCCESS; - goto _exit; - } - } - } - - if(c->schema && khc_is_schema_handle(conf)) { - for(i=0;inSchema;i++) { - if(c->schema[i].type == KC_INT32 && !wcscmp(value, c->schema[i].name)) { - *buf = (khm_int32) c->schema[i].value; - rv = KHM_ERROR_SUCCESS; - goto _exit; - } - } - } -_shadow: - if(free_space && conf) - khc_close_space(conf); - - if(khc_is_shadowed(pconf)) { - pconf = khc_shadow(pconf); - continue; - } else { - rv = KHM_ERROR_NOT_FOUND; - break; - } -_exit: - if(free_space && conf) - khc_close_space(conf); - break; - } - while(TRUE); - - return rv; -} - -/* obtains cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_read_int64(khm_handle pconf, const wchar_t * pvalue, khm_int64 * buf) { - kconf_conf_space * c; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - do { - DWORD size; - DWORD type; - LONG hr; - HKEY hku = NULL; - HKEY hkm = NULL; - - const wchar_t * value = NULL; - int free_space = 0; - khm_handle conf = NULL; - - int i; - - if((value = wcsrchr(pvalue, L'\\')) != NULL) { - if(KHM_FAILED(khc_open_space( - pconf, - pvalue, - KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), - &conf))) - goto _shadow; - free_space = 1; - - if (value) { - value++; - } else { -#ifdef DEBUG - assert(FALSE); -#endif - } - } else { - value = pvalue; - conf = pconf; - free_space = 0; - } - - if(!khc_is_handle(conf) || !buf) - goto _shadow; - - c = khc_space_from_handle(conf); - - if(khc_is_user_handle(conf)) - hku = khcint_space_open_key(c, KHM_PERM_READ); - - if(khc_is_machine_handle(conf)) - hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); - - size = sizeof(khm_int64); - if(hku) { - hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size); - if(hr == ERROR_SUCCESS) { - if(type != REG_QWORD) { - rv= KHM_ERROR_TYPE_MISMATCH; - goto _exit; - } - else { - rv = KHM_ERROR_SUCCESS; - goto _exit; - } - } - } - - size = sizeof(khm_int64); - if(hkm) { - hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size); - if(hr == ERROR_SUCCESS) { - if(type != REG_QWORD) { - rv = KHM_ERROR_TYPE_MISMATCH; - goto _exit; - } - else { - rv = KHM_ERROR_SUCCESS; - goto _exit; - } - } - } - - if(c->schema && khc_is_schema_handle(conf)) { - for(i=0;inSchema;i++) { - if(c->schema[i].type == KC_INT64 && !wcscmp(value, c->schema[i].name)) { - *buf = (khm_int64) c->schema[i].value; - rv = KHM_ERROR_SUCCESS; - goto _exit; - } - } - } - -_shadow: - if(free_space && conf) - khc_close_space(conf); - if(khc_is_shadowed(pconf)) { - pconf = khc_shadow(pconf); - continue; - } else { - rv = KHM_ERROR_NOT_FOUND; - break; - } - -_exit: - if(free_space && conf) - khc_close_space(conf); - break; - - } while(TRUE); - return rv; -} - -/* obtaincs cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_read_binary(khm_handle pconf, const wchar_t * pvalue, - void * buf, khm_size * bufsize) { - kconf_conf_space * c; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - do { - DWORD size; - DWORD type; - LONG hr; - HKEY hku = NULL; - HKEY hkm = NULL; - - const wchar_t * value = NULL; - int free_space = 0; - khm_handle conf = NULL; - - if((value = wcsrchr(pvalue, L'\\')) != NULL) { - if(KHM_FAILED(khc_open_space( - pconf, - pvalue, - KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), - &conf))) - goto _shadow; - free_space = 1; - - if (value) { - value++; - } else { -#ifdef DEBUG - assert(FALSE); -#endif - } - } else { - value = pvalue; - conf = pconf; - free_space = 0; - } - - if(!khc_is_handle(conf)) - goto _shadow; - - c = khc_space_from_handle(conf); - - if(khc_is_user_handle(conf)) - hku = khcint_space_open_key(c, KHM_PERM_READ); - - if(khc_is_machine_handle(conf)) - hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); - - size = (DWORD) *bufsize; - if(hku) { - hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size); - if(hr == ERROR_SUCCESS) { - if(type != REG_BINARY) { - rv = KHM_ERROR_TYPE_MISMATCH; - goto _exit; - } - else { - *bufsize = size; - rv = KHM_ERROR_SUCCESS; - goto _exit; - } - } else { - if(hr == ERROR_MORE_DATA) { - *bufsize = size; - rv = KHM_ERROR_TOO_LONG; - goto _exit; - } - } - } - - size = (DWORD) *bufsize; - if(hkm) { - hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size); - if(hr == ERROR_SUCCESS) { - if(type != REG_BINARY) { - rv = KHM_ERROR_TYPE_MISMATCH; - goto _exit; - } - else { - *bufsize = size; - rv = KHM_ERROR_SUCCESS; - goto _exit; - } - } else { - if(hr == ERROR_MORE_DATA) { - *bufsize = size; - rv = KHM_ERROR_TOO_LONG; - goto _exit; - } - } - } - - /* binary values aren't supported in schema */ -_shadow: - if(free_space && conf) - khc_close_space(conf); - if(khc_is_shadowed(pconf)) { - pconf = khc_shadow(pconf); - continue; - } else { - rv = KHM_ERROR_NOT_FOUND; - break; - } - -_exit: - if(free_space && conf) - khc_close_space(conf); - break; - - }while (TRUE); - - return rv; -} - -/* obtains cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_write_string(khm_handle pconf, - const wchar_t * pvalue, - wchar_t * buf) -{ - HKEY pk = NULL; - kconf_conf_space * c; - khm_int32 rv = KHM_ERROR_SUCCESS; - LONG hr; - size_t cbsize; - const wchar_t * value = NULL; - int free_space = 0; - khm_handle conf = NULL; - - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf)) - return KHM_ERROR_INVALID_OPERATION; - - if(FAILED(StringCbLength(buf, KCONF_MAXCB_STRING, &cbsize))) { - rv = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - cbsize += sizeof(wchar_t); - - if (khc_handle_flags(pconf) & KCONF_FLAG_WRITEIFMOD) { - wchar_t tmpbuf[512]; - wchar_t * buffer; - size_t tmpsize = cbsize; - khm_boolean is_equal = FALSE; - - if (cbsize <= sizeof(tmpbuf)) { - buffer = tmpbuf; - } else { - buffer = PMALLOC(cbsize); - } - - if (KHM_SUCCEEDED(khc_read_string(pconf, pvalue, buffer, &tmpsize)) && - tmpsize == cbsize) { - if (khc_handle_flags(pconf) & KCONF_FLAG_IFMODCI) - is_equal = !_wcsicmp(buffer, buf); - else - is_equal = !wcscmp(buffer, buf); - } - - if (buffer != tmpbuf) - PFREE(buffer); - - if (is_equal) { - return KHM_ERROR_SUCCESS; - } - } - - if((value = wcsrchr(pvalue, L'\\')) != NULL) { - if(KHM_FAILED(khc_open_space(pconf, pvalue, - KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), - &conf))) - return KHM_ERROR_INVALID_PARAM; - free_space = 1; - - if (value) { - value ++; - } else { -#ifdef DEBUG - assert(FALSE); -#endif - } - } else { - value = pvalue; - conf = pconf; - free_space = 0; - } - - if(!khc_is_handle(conf) || !buf) { - rv = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - c = khc_space_from_handle(conf); - - if(khc_is_user_handle(conf)) { - pk = khcint_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE); - } else { - pk = khcint_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE); - } - - hr = RegSetValueEx(pk, value, 0, REG_SZ, (LPBYTE) buf, (DWORD) cbsize); - - if(hr != ERROR_SUCCESS) - rv = KHM_ERROR_INVALID_OPERATION; - -_exit: - if(free_space) - khc_close_space(conf); - return rv; -} - -/* obtaincs cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_write_int32(khm_handle pconf, - const wchar_t * pvalue, - khm_int32 buf) -{ - HKEY pk = NULL; - kconf_conf_space * c; - khm_int32 rv = KHM_ERROR_SUCCESS; - LONG hr; - const wchar_t * value = NULL; - int free_space = 0; - khm_handle conf = NULL; - - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf)) - return KHM_ERROR_INVALID_OPERATION; - - if (khc_handle_flags(pconf) & KCONF_FLAG_WRITEIFMOD) { - khm_int32 tmpvalue; - - if (KHM_SUCCEEDED(khc_read_int32(pconf, pvalue, &tmpvalue)) && - tmpvalue == buf) { - return KHM_ERROR_SUCCESS; - } - } - - if((value = wcsrchr(pvalue, L'\\')) != NULL) { - if(KHM_FAILED(khc_open_space( - pconf, - pvalue, - KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), - &conf))) - return KHM_ERROR_INVALID_PARAM; - free_space = 1; - - if (value) { - value ++; - } else { -#ifdef DEBUG - assert(FALSE); -#endif - } - } else { - value = pvalue; - conf = pconf; - free_space = 0; - } - - if(!khc_is_handle(conf)) - return KHM_ERROR_INVALID_PARAM; - - c = khc_space_from_handle( conf); - - if(khc_is_user_handle(conf)) { - pk = khcint_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE); - } else { - pk = khcint_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE); - } - - hr = RegSetValueEx(pk, value, 0, REG_DWORD, (LPBYTE) &buf, sizeof(khm_int32)); - - if(hr != ERROR_SUCCESS) - rv = KHM_ERROR_INVALID_OPERATION; - - if(free_space) - khc_close_space(conf); - - return rv; -} - -/* obtains cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_write_int64(khm_handle pconf, const wchar_t * pvalue, khm_int64 buf) { - HKEY pk = NULL; - kconf_conf_space * c; - khm_int32 rv = KHM_ERROR_SUCCESS; - LONG hr; - const wchar_t * value = NULL; - int free_space = 0; - khm_handle conf = NULL; - - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf)) - return KHM_ERROR_INVALID_OPERATION; - - if (khc_handle_flags(pconf) & KCONF_FLAG_WRITEIFMOD) { - khm_int64 tmpvalue; - - if (KHM_SUCCEEDED(khc_read_int64(pconf, pvalue, &tmpvalue)) && - tmpvalue == buf) { - return KHM_ERROR_SUCCESS; - } - } - - if((value = wcsrchr(pvalue, L'\\')) != NULL) { - if(KHM_FAILED(khc_open_space( - pconf, - pvalue, - KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), - &conf))) - return KHM_ERROR_INVALID_PARAM; - free_space = 1; - - if (value) { - value ++; - } else { -#ifdef DEBUG - assert(FALSE); -#endif - } - } else { - value = pvalue; - conf = pconf; - free_space = 0; - } - - if(!khc_is_handle(conf)) - return KHM_ERROR_INVALID_PARAM; - - c = khc_space_from_handle( conf); - - if(khc_is_user_handle(conf)) { - pk = khcint_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE); - } else { - pk = khcint_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE); - } - - hr = RegSetValueEx(pk, value, 0, REG_QWORD, (LPBYTE) &buf, sizeof(khm_int64)); - - if(hr != ERROR_SUCCESS) - rv = KHM_ERROR_INVALID_OPERATION; - - if(free_space) - khc_close_space(conf); - - return rv; -} - -/* obtains cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_write_binary(khm_handle pconf, - const wchar_t * pvalue, - void * buf, khm_size bufsize) { - HKEY pk = NULL; - kconf_conf_space * c; - khm_int32 rv = KHM_ERROR_SUCCESS; - LONG hr; - const wchar_t * value = NULL; - int free_space = 0; - khm_handle conf = NULL; - - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf)) - return KHM_ERROR_INVALID_OPERATION; - - if((value = wcsrchr(pvalue, L'\\')) != NULL) { - if(KHM_FAILED(khc_open_space( - pconf, - pvalue, - KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), - &conf))) - return KHM_ERROR_INVALID_PARAM; - free_space = 1; - - if (value) { - value ++; - } else { -#ifdef DEBUG - assert(FALSE); -#endif - } - } else { - value = pvalue; - conf = pconf; - free_space = 0; - } - - if(!khc_is_handle(conf)) - return KHM_ERROR_INVALID_PARAM; - - c = khc_space_from_handle(conf); - - if(khc_is_user_handle(conf)) { - pk = khcint_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE); - } else { - pk = khcint_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE); - } - - hr = RegSetValueEx(pk, value, 0, REG_BINARY, buf, (DWORD) bufsize); - - if(hr != ERROR_SUCCESS) - rv = KHM_ERROR_INVALID_OPERATION; - - if(free_space) - khc_close_space(conf); - - return rv; -} - -/* no locks */ -KHMEXP khm_int32 KHMAPI -khc_get_config_space_name(khm_handle conf, - wchar_t * buf, khm_size * bufsize) { - kconf_conf_space * c; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - if(!khc_is_handle(conf)) - return KHM_ERROR_INVALID_PARAM; - - c = khc_space_from_handle(conf); - - if(!c->name) { - if(buf && *bufsize > 0) - buf[0] = L'\0'; - else { - *bufsize = sizeof(wchar_t); - rv = KHM_ERROR_TOO_LONG; - } - } else { - size_t cbsize; - - if(FAILED(StringCbLength(c->name, KCONF_MAXCB_NAME, &cbsize))) - return KHM_ERROR_UNKNOWN; - - cbsize += sizeof(wchar_t); - - if(!buf || cbsize > *bufsize) { - *bufsize = cbsize; - rv = KHM_ERROR_TOO_LONG; - } else { - StringCbCopy(buf, *bufsize, c->name); - *bufsize = cbsize; - } - } - - return rv; -} - -/* obtains cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_get_config_space_parent(khm_handle conf, khm_handle * parent) { - kconf_conf_space * c; - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - if(!khc_is_handle(conf)) - return KHM_ERROR_INVALID_PARAM; - - c = khc_space_from_handle(conf); - - if(c == conf_root || c->parent == conf_root) - *parent = NULL; - else - *parent = khcint_handle_from_space(c->parent, khc_handle_flags(conf)); - - return KHM_ERROR_SUCCESS; -} - -/* obtains cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_get_type(khm_handle conf, const wchar_t * value) { - HKEY hkm = NULL; - HKEY hku = NULL; - kconf_conf_space * c; - khm_int32 rv; - LONG hr = ERROR_SUCCESS; - DWORD type = 0; - - if(!khc_is_config_running()) - return KC_NONE; - - if(!khc_is_handle(conf)) - return KC_NONE; - - c = khc_space_from_handle(conf); - - if(!khc_is_machine_handle(conf)) - hku = khcint_space_open_key(c, KHM_PERM_READ); - hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); - - if(hku) - hr = RegQueryValueEx(hku, value, NULL, &type, NULL, NULL); - if(!hku || hr != ERROR_SUCCESS) - hr = RegQueryValueEx(hkm, value, NULL, &type, NULL, NULL); - if(((!hku && !hkm) || hr != ERROR_SUCCESS) && c->schema) { - int i; - - for(i=0; inSchema; i++) { - if(!wcscmp(c->schema[i].name, value)) { - return c->schema[i].type; - } - } - - return KC_NONE; - } - - switch(type) { - case REG_MULTI_SZ: - case REG_SZ: - rv = KC_STRING; - break; - case REG_DWORD: - rv = KC_INT32; - break; - case REG_QWORD: - rv = KC_INT64; - break; - case REG_BINARY: - rv = KC_BINARY; - break; - default: - rv = KC_NONE; - } - - return rv; -} - -/* obtains cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_value_exists(khm_handle conf, const wchar_t * value) { - HKEY hku = NULL; - HKEY hkm = NULL; - kconf_conf_space * c; - khm_int32 rv = 0; - DWORD t; - int i; - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - if(!khc_is_handle(conf)) - return KHM_ERROR_INVALID_PARAM; - - do { - c = khc_space_from_handle(conf); - - if (khc_is_user_handle(conf)) - hku = khcint_space_open_key(c, KHM_PERM_READ); - 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 && khc_is_schema_handle(conf)) { - for(i=0; inSchema; i++) { - if(!wcscmp(c->schema[i].name, value)) { - rv |= KCONF_FLAG_SCHEMA; - break; - } - } - } - - /* if the value is not found at this level and the handle is - shadowed, try the next level down. */ - if (rv == 0 && khc_is_shadowed(conf)) - conf = khc_shadow(conf); - else - break; - } while (conf); - - return rv; -} - -/* obtains cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_remove_value(khm_handle conf, const wchar_t * value, khm_int32 flags) { - HKEY hku = NULL; - HKEY hkm = NULL; - kconf_conf_space * c; - khm_int32 rv = KHM_ERROR_NOT_FOUND; - DWORD t; - LONG l; - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - if(!khc_is_handle(conf)) - return KHM_ERROR_INVALID_PARAM; - - c = khc_space_from_handle(conf); - - if(!khc_is_machine_handle(conf)) - hku = khcint_space_open_key(c, KHM_PERM_READ); - hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); - - if((flags == 0 || - (flags & KCONF_FLAG_USER)) && - hku && (RegQueryValueEx(hku, value, NULL, - &t, NULL, NULL) == ERROR_SUCCESS)) { - l = RegDeleteValue(hku, value); - if (l == ERROR_SUCCESS) - rv = KHM_ERROR_SUCCESS; - else - rv = KHM_ERROR_UNKNOWN; - } - if((flags == 0 || - (flags & KCONF_FLAG_MACHINE)) && - hkm && (RegQueryValueEx(hkm, value, NULL, - &t, NULL, NULL) == ERROR_SUCCESS)) { - l = RegDeleteValue(hkm, value); - if (l == ERROR_SUCCESS) - rv = (rv == KHM_ERROR_UNKNOWN)?KHM_ERROR_PARTIAL: - KHM_ERROR_SUCCESS; - else - rv = (rv == KHM_ERROR_SUCCESS)?KHM_ERROR_PARTIAL: - KHM_ERROR_UNKNOWN; - } - - 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); - - khcint_remove_space(cc, flags); - - cc = cn; - } - - cc = TFIRSTCHILD(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 all the registry spaces have been marked as deleted and - there is no schema, we should mark the space as deleted as - well. Note that ideally we only need to check for stores - which have data corresponding to this configuration space, - but this is a bit problematic since we don't monitor the - registry for changes. */ - if ((c->flags & - (KCONF_SPACE_FLAG_DELETE_M | - KCONF_SPACE_FLAG_DELETE_U)) == - (KCONF_SPACE_FLAG_DELETE_M | - KCONF_SPACE_FLAG_DELETE_U) && - (!c->schema || c->nSchema == 0)) - - c->flags |= KCONF_SPACE_FLAG_DELETED; - } - - 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; -} - -/* obtains cs_conf_global */ -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 - repository to delete the space from. (user/machine) - - - When each subspace is released, check if it has been marked - for deletion. If so, delete the marked spaces as well as - removing the space from kconf space tree. - - - When removing a subspace from a space, check if the parent - space has any children left. If there are none, check if the - parent space is also marked for deletion. - */ - kconf_conf_space * c; - khm_int32 rv = KHM_ERROR_SUCCESS; - khm_int32 flags = 0; - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - if(!khc_is_handle(conf)) - return KHM_ERROR_INVALID_PARAM; - - c = khc_space_from_handle(conf); - - EnterCriticalSection(&cs_conf_global); - - if (khc_is_machine_handle(conf)) - flags |= KCONF_SPACE_FLAG_DELETE_M; - if (khc_is_user_handle(conf)) - flags |= KCONF_SPACE_FLAG_DELETE_U; - - rv = khcint_remove_space(c, flags); - - LeaveCriticalSection(&cs_conf_global); - - return rv; -} - -/* no locks */ -khm_boolean -khcint_is_valid_name(wchar_t * name) -{ - size_t cbsize; - if(FAILED(StringCbLength(name, KCONF_MAXCB_NAME, &cbsize))) - return FALSE; - return TRUE; -} - -/* no locks */ -khm_int32 -khcint_validate_schema(const kconf_schema * schema, - int begin, - int *end) -{ - int i; - int state = 0; - int end_found = 0; - - i=begin; - while(!end_found) { - switch(state) { - case 0: /* initial. this record should start a config space */ - if(!khcint_is_valid_name(schema[i].name) || - schema[i].type != KC_SPACE) - return KHM_ERROR_INVALID_PARAM; - state = 1; - break; - - case 1: /* we are inside a config space, in the values area */ - if(!khcint_is_valid_name(schema[i].name)) - return KHM_ERROR_INVALID_PARAM; - if(schema[i].type == KC_SPACE) { - if(KHM_FAILED(khcint_validate_schema(schema, i, &i))) - return KHM_ERROR_INVALID_PARAM; - state = 2; - } else if(schema[i].type == KC_ENDSPACE) { - end_found = 1; - if(end) - *end = i; - } else { - if(schema[i].type != KC_STRING && - schema[i].type != KC_INT32 && - schema[i].type != KC_INT64 && - schema[i].type != KC_BINARY) - return KHM_ERROR_INVALID_PARAM; - } - break; - - case 2: /* we are inside a config space, in the subspace area */ - if(schema[i].type == KC_SPACE) { - if(KHM_FAILED(khcint_validate_schema(schema, i, &i))) - return KHM_ERROR_INVALID_PARAM; - } else if(schema[i].type == KC_ENDSPACE) { - end_found = 1; - if(end) - *end = i; - } else { - return KHM_ERROR_INVALID_PARAM; - } - break; - - default: - /* unreachable */ - return KHM_ERROR_INVALID_PARAM; - } - i++; - } - - return KHM_ERROR_SUCCESS; -} - -/* obtains cs_conf_handle/cs_conf_global; called with cs_conf_global */ -khm_int32 -khcint_load_schema_i(khm_handle parent, const kconf_schema * schema, - int begin, int * end) -{ - int i; - int state = 0; - int end_found = 0; - kconf_conf_space * thisconf = NULL; - khm_handle h = NULL; - - i=begin; - while(!end_found) { - switch(state) { - case 0: /* initial. this record should start a config space */ - LeaveCriticalSection(&cs_conf_global); - if(KHM_FAILED(khc_open_space(parent, schema[i].name, - KHM_FLAG_CREATE, &h))) { - EnterCriticalSection(&cs_conf_global); - return KHM_ERROR_INVALID_PARAM; - } - EnterCriticalSection(&cs_conf_global); - thisconf = khc_space_from_handle(h); - thisconf->schema = schema + (begin + 1); - thisconf->nSchema = 0; - state = 1; - break; - - case 1: /* we are inside a config space, in the values area */ - if(schema[i].type == KC_SPACE) { - thisconf->nSchema = i - (begin + 1); - if(KHM_FAILED(khcint_load_schema_i(h, schema, i, &i))) - return KHM_ERROR_INVALID_PARAM; - state = 2; - } else if(schema[i].type == KC_ENDSPACE) { - thisconf->nSchema = i - (begin + 1); - end_found = 1; - if(end) - *end = i; - LeaveCriticalSection(&cs_conf_global); - khc_close_space(h); - EnterCriticalSection(&cs_conf_global); - } - break; - - case 2: /* we are inside a config space, in the subspace area */ - if(schema[i].type == KC_SPACE) { - if(KHM_FAILED(khcint_load_schema_i(h, schema, i, &i))) - return KHM_ERROR_INVALID_PARAM; - } else if(schema[i].type == KC_ENDSPACE) { - end_found = 1; - if(end) - *end = i; - LeaveCriticalSection(&cs_conf_global); - khc_close_space(h); - EnterCriticalSection(&cs_conf_global); - } else { - return KHM_ERROR_INVALID_PARAM; - } - break; - - default: - /* unreachable */ - return KHM_ERROR_INVALID_PARAM; - } - i++; - } - - return KHM_ERROR_SUCCESS; -} - -/* obtains cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_load_schema(khm_handle conf, const kconf_schema * schema) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - if(conf && !khc_is_handle(conf)) - return KHM_ERROR_INVALID_PARAM; - - if(KHM_FAILED(khcint_validate_schema(schema, 0, NULL))) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_conf_global); - rv = khcint_load_schema_i(conf, schema, 0, NULL); - LeaveCriticalSection(&cs_conf_global); - - return rv; -} - -/* obtains cs_conf_handle/cs_conf_global; called with cs_conf_global */ -khm_int32 -khcint_unload_schema_i(khm_handle parent, const kconf_schema * schema, - int begin, int * end) -{ - int i; - int state = 0; - int end_found = 0; - kconf_conf_space * thisconf = NULL; - khm_handle h = NULL; - - i=begin; - while(!end_found) { - switch(state) { - case 0: /* initial. this record should start a config space */ - LeaveCriticalSection(&cs_conf_global); - if(KHM_FAILED(khc_open_space(parent, schema[i].name, 0, &h))) { - EnterCriticalSection(&cs_conf_global); - return KHM_ERROR_INVALID_PARAM; - } - EnterCriticalSection(&cs_conf_global); - thisconf = khc_space_from_handle(h); - if(thisconf->schema == (schema + (begin + 1))) { - thisconf->schema = NULL; - thisconf->nSchema = 0; - } - state = 1; - break; - - case 1: /* we are inside a config space, in the values area */ - if(schema[i].type == KC_SPACE) { - if(KHM_FAILED(khcint_unload_schema_i(h, schema, i, &i))) - return KHM_ERROR_INVALID_PARAM; - state = 2; - } else if(schema[i].type == KC_ENDSPACE) { - end_found = 1; - if(end) - *end = i; - LeaveCriticalSection(&cs_conf_global); - khc_close_space(h); - EnterCriticalSection(&cs_conf_global); - } - break; - - case 2: /* we are inside a config space, in the subspace area */ - if(schema[i].type == KC_SPACE) { - if(KHM_FAILED(khcint_unload_schema_i(h, schema, i, &i))) - return KHM_ERROR_INVALID_PARAM; - } else if(schema[i].type == KC_ENDSPACE) { - end_found = 1; - if(end) - *end = i; - LeaveCriticalSection(&cs_conf_global); - khc_close_space(h); - EnterCriticalSection(&cs_conf_global); - } else { - return KHM_ERROR_INVALID_PARAM; - } - break; - - default: - /* unreachable */ - return KHM_ERROR_INVALID_PARAM; - } - i++; - } - - return KHM_ERROR_SUCCESS; -} - -/* obtains cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_unload_schema(khm_handle conf, const kconf_schema * schema) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - if(conf && !khc_is_handle(conf)) - return KHM_ERROR_INVALID_PARAM; - - if(KHM_FAILED(khcint_validate_schema(schema, 0, NULL))) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_conf_global); - rv = khcint_unload_schema_i(conf, schema, 0, NULL); - LeaveCriticalSection(&cs_conf_global); - - return rv; -} - -/* obtaincs cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_enum_subspaces(khm_handle conf, - khm_handle prev, - khm_handle * next) -{ - kconf_conf_space * s; - kconf_conf_space * c; - kconf_conf_space * p; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - if(!khc_is_handle(conf) || next == NULL || - (prev != NULL && !khc_is_handle(prev))) - return KHM_ERROR_INVALID_PARAM; - - s = khc_space_from_handle(conf); - - if(prev == NULL) { - /* first off, we enumerate all the registry spaces regardless of - whether the handle is applicable for some registry space or not. - See notes for khc_begin_enum_subspaces() for reasons as to why - this is done (notes are in kconfig.h)*/ - - /* go through the user hive first */ - { - HKEY hk_conf; - - hk_conf = khcint_space_open_key(s, 0); - if(hk_conf) { - wchar_t name[KCONF_MAXCCH_NAME]; - khm_handle h; - int idx; - - idx = 0; - while(RegEnumKey(hk_conf, idx, - name, ARRAYLENGTH(name)) == ERROR_SUCCESS) { - wchar_t * tilde; - tilde = wcschr(name, L'~'); - if (tilde) - *tilde = 0; - if(KHM_SUCCEEDED(khc_open_space(conf, name, 0, &h))) - khc_close_space(h); - idx++; - } - } - } - - /* go through the machine hive next */ - { - HKEY hk_conf; - - hk_conf = khcint_space_open_key(s, KCONF_FLAG_MACHINE); - if(hk_conf) { - wchar_t name[KCONF_MAXCCH_NAME]; - khm_handle h; - int idx; - - idx = 0; - while(RegEnumKey(hk_conf, idx, - name, ARRAYLENGTH(name)) == ERROR_SUCCESS) { - wchar_t * tilde; - tilde = wcschr(name, L'~'); - if (tilde) - *tilde = 0; - - if(KHM_SUCCEEDED(khc_open_space(conf, name, - KCONF_FLAG_MACHINE, &h))) - khc_close_space(h); - idx++; - } - } - } - - /* don't need to go through schema, because that was already - done when the schema was loaded. */ - } - - /* at last we are now ready to return the results */ - EnterCriticalSection(&cs_conf_global); - if(prev == NULL) { - c = TFIRSTCHILD(s); - rv = KHM_ERROR_SUCCESS; - } else { - p = khc_space_from_handle(prev); - if(TPARENT(p) == s) - c = LNEXT(p); - else - c = NULL; - } - LeaveCriticalSection(&cs_conf_global); - - if(prev != NULL) - khc_close_space(prev); - - if(c) { - *next = khcint_handle_from_space(c, khc_handle_flags(conf)); - rv = KHM_ERROR_SUCCESS; - } else { - *next = NULL; - rv = KHM_ERROR_NOT_FOUND; - } - - return rv; -} - -/* obtains cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_write_multi_string(khm_handle conf, const wchar_t * value, wchar_t * buf) -{ - size_t cb; - wchar_t vbuf[KCONF_MAXCCH_STRING]; - wchar_t *tb; - khm_int32 rv; - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - if(!khc_is_handle(conf) || buf == NULL || value == NULL) - return KHM_ERROR_INVALID_PARAM; - - if(multi_string_to_csv(NULL, &cb, buf) != KHM_ERROR_TOO_LONG) - return KHM_ERROR_INVALID_PARAM; - - if (cb < sizeof(vbuf)) - tb = vbuf; - else - tb = PMALLOC(cb); - - assert(tb != NULL); - - multi_string_to_csv(tb, &cb, buf); - rv = khc_write_string(conf, value, tb); - - if (tb != vbuf) - PFREE(tb); - return rv; -} - -/* obtains cs_conf_handle/cs_conf_global */ -KHMEXP khm_int32 KHMAPI -khc_read_multi_string(khm_handle conf, const wchar_t * value, - wchar_t * buf, khm_size * bufsize) -{ - wchar_t vbuf[KCONF_MAXCCH_STRING]; - wchar_t * tb; - khm_size cbbuf; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!khc_is_config_running()) - return KHM_ERROR_NOT_READY; - - if(!bufsize) - return KHM_ERROR_INVALID_PARAM; - - rv = khc_read_string(conf, value, NULL, &cbbuf); - if(rv != KHM_ERROR_TOO_LONG) - return rv; - - if (cbbuf < sizeof(vbuf)) - tb = vbuf; - else - tb = PMALLOC(cbbuf); - - assert(tb != NULL); - - rv = khc_read_string(conf, value, tb, &cbbuf); - - if(KHM_FAILED(rv)) - goto _exit; - - rv = csv_to_multi_string(buf, bufsize, tb); - -_exit: - if (tb != vbuf) - PFREE(tb); - - return rv; -} +/* +* 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 + +kconf_conf_space * conf_root = NULL; +kconf_handle * conf_handles = NULL; +kconf_handle * conf_free_handles = NULL; + +CRITICAL_SECTION cs_conf_global; +CRITICAL_SECTION cs_conf_handle; +LONG conf_init = 0; +LONG conf_status = 0; + +void init_kconf(void) { + if(InterlockedIncrement(&conf_init) == 1L) { + /* we are the first */ + InitializeCriticalSection(&cs_conf_global); + EnterCriticalSection(&cs_conf_global); + conf_root = khcint_create_empty_space(); + conf_root->name = PWCSDUP(L"Root"); + conf_root->regpath = PWCSDUP(CONFIG_REGPATHW); + conf_root->refcount++; + conf_status = 1; + InitializeCriticalSection(&cs_conf_handle); + LeaveCriticalSection(&cs_conf_global); + } + /* else assume we are already initialized */ +} + +void exit_kconf(void) { + if(khc_is_config_running()) { + kconf_handle * h; + + EnterCriticalSection(&cs_conf_global); + + conf_init = 0; + conf_status = 0; + + khcint_free_space(conf_root); + + LeaveCriticalSection(&cs_conf_global); + DeleteCriticalSection(&cs_conf_global); + + EnterCriticalSection(&cs_conf_handle); + while(conf_free_handles) { + LPOP(&conf_free_handles, &h); + if(h) { + PFREE(h); + } + } + + while(conf_handles) { + LPOP(&conf_handles, &h); + if(h) { + PFREE(h); + } + } + LeaveCriticalSection(&cs_conf_handle); + DeleteCriticalSection(&cs_conf_handle); + } +} + +#if defined(DEBUG) && (defined(KH_BUILD_PRIVATE) || defined(KH_BUILD_SPECIAL)) + +#include + +static void +khcint_dump_space(FILE * f, kconf_conf_space * sp) { + + kconf_conf_space * sc; + + fprintf(f, "c12\t[%S]\t[%S]\t%d\t0x%x\tWin(%s|%s)|%s\n", + ((sp->regpath) ? sp->regpath : L"!No Reg path"), + sp->name, + (int) sp->refcount, + (int) sp->flags, + ((sp->regkey_user)? "HKCU" : ""), + ((sp->regkey_machine)? "HKLM" : ""), + ((sp->schema)? "Schema" : "")); + + + sc = TFIRSTCHILD(sp); + while(sc) { + + khcint_dump_space(f, sc); + + sc = LNEXT(sc); + } +} + +KHMEXP void KHMAPI +khcint_dump_handles(FILE * f) { + if (khc_is_config_running()) { + kconf_handle * h, * sh; + + EnterCriticalSection(&cs_conf_handle); + EnterCriticalSection(&cs_conf_global); + + fprintf(f, "c00\t*** Active handles ***\n"); + fprintf(f, "c01\tHandle\tName\tFlags\tRegpath\n"); + + h = conf_handles; + while(h) { + kconf_conf_space * sp; + + sp = h->space; + + if (!khc_is_handle(h) || sp == NULL) { + + fprintf(f, "c02\t!!INVALID HANDLE!!\n"); + + } else { + + fprintf(f, "c02\t0x%p\t[%S]\t0x%x\t[%S]\n", + h, + sp->name, + h->flags, + sp->regpath); + + sh = khc_shadow(h); + + while(sh) { + + sp = sh->space; + + if (!khc_is_handle(sh) || sp == NULL) { + + fprintf(f, "c02\t0x%p:Shadow:0x%p\t[!!INVALID HANDLE!!]\n", + h, sh); + + } else { + + fprintf(f, "c02\t0x%p:Shadow:0x%p,[%S]\t0x%x\t[%S]\n", + h, sh, + sp->name, + sh->flags, + sp->regpath); + + } + + sh = khc_shadow(sh); + } + + } + + h = LNEXT(h); + } + + fprintf(f, "c03\t------ End ---------\n"); + + fprintf(f, "c10\t*** Active Configuration Spaces ***\n"); + fprintf(f, "c11\tReg path\tName\tRefcount\tFlags\tLayers\n"); + + khcint_dump_space(f, conf_root); + + fprintf(f, "c13\t------ End ---------\n"); + + LeaveCriticalSection(&cs_conf_global); + LeaveCriticalSection(&cs_conf_handle); + + } else { + fprintf(f, "c00\t------- KHC Configuration not running -------\n"); + } +} + +#endif + +/* obtains cs_conf_handle/cs_conf_global */ +kconf_handle * +khcint_handle_from_space(kconf_conf_space * s, khm_int32 flags) +{ + kconf_handle * h; + + EnterCriticalSection(&cs_conf_handle); + LPOP(&conf_free_handles, &h); + if(!h) { + h = PMALLOC(sizeof(kconf_handle)); + assert(h != NULL); + } + ZeroMemory((void *) h, sizeof(kconf_handle)); + + h->magic = KCONF_HANDLE_MAGIC; + khcint_space_hold(s); + h->space = s; + h->flags = flags; + + LPUSH(&conf_handles, h); + LeaveCriticalSection(&cs_conf_handle); + + return h; +} + +/* obtains cs_conf_handle/cs_conf_global */ +void +khcint_handle_free(kconf_handle * h) +{ + kconf_handle * lower; + + EnterCriticalSection(&cs_conf_handle); +#ifdef DEBUG + /* check if the handle is actually in use */ + { + kconf_handle * a; + a = conf_handles; + while(a) { + if(h == a) + break; + a = LNEXT(a); + } + + if(a == NULL) { + DebugBreak(); + + /* hmm. the handle was not in the in-use list */ + LeaveCriticalSection(&cs_conf_handle); + return; + } + } +#endif + while(h) { + LDELETE(&conf_handles, h); + if(h->space) { + khcint_space_release(h->space); + h->space = NULL; + } + lower = h->lower; + h->magic = 0; + LPUSH(&conf_free_handles, h); + h = lower; + } + LeaveCriticalSection(&cs_conf_handle); +} + +/* obains cs_conf_handle/cs_conf_global */ +kconf_handle * +khcint_handle_dup(kconf_handle * o) +{ + kconf_handle * h; + kconf_handle * r; + + r = khcint_handle_from_space(o->space, o->flags); + h = r; + + while(o->lower) { + h->lower = khcint_handle_from_space(o->lower->space, o->lower->flags); + + o = o->lower; + h = h->lower; + } + + return r; +} + +/* obtains cs_conf_global */ +void +khcint_space_hold(kconf_conf_space * s) { + EnterCriticalSection(&cs_conf_global); + s->refcount ++; + LeaveCriticalSection(&cs_conf_global); +} + +/* called with cs_conf_global */ +void +khcint_try_free_space(kconf_conf_space * s) { + + if (TFIRSTCHILD(s) == NULL && + s->refcount == 0 && + s->schema == NULL) { + + kconf_conf_space * p; + + p = TPARENT(s); + + if (p == NULL) + return; + + TDELCHILD(p, s); + + khcint_free_space(s); + + khcint_try_free_space(p); + } +} + +/* obtains cs_conf_global */ +void +khcint_space_release(kconf_conf_space * s) { + khm_int32 l; + + EnterCriticalSection(&cs_conf_global); + + l = -- s->refcount; + if (l == 0) { + if(s->regkey_machine) + RegCloseKey(s->regkey_machine); + if(s->regkey_user) + RegCloseKey(s->regkey_user); + s->regkey_machine = NULL; + s->regkey_user = NULL; + + if (s->flags & + (KCONF_SPACE_FLAG_DELETE_M | + KCONF_SPACE_FLAG_DELETE_U)) { + khcint_remove_space(s, s->flags); + } else { +#ifdef USE_TRY_FREE + /* even if the refcount is zero, we shouldn't free a + configuration space just yet since that doesn't play + well with the configuration space enumeration mechanism + which expects the spaces to dangle around if there is a + corresponding registry key or schema. */ + khcint_try_free_space(s); +#endif + } + } + + LeaveCriticalSection(&cs_conf_global); +} + +/* case sensitive replacement for RegOpenKeyEx */ +LONG +khcint_RegOpenKeyEx(HKEY hkey, LPCWSTR sSubKey, DWORD ulOptions, + REGSAM samDesired, PHKEY phkResult) { + int i; + wchar_t sk_name[KCONF_MAXCCH_NAME]; + FILETIME ft; + size_t cch; + HKEY hkp = NULL; + const wchar_t * t; + LONG rv = ERROR_SUCCESS; + + hkp = hkey; + t = sSubKey; + + /* check for case insensitive prefix first */ + if (!_wcsnicmp(sSubKey, CONFIG_REGPATHW, ARRAYLENGTH(CONFIG_REGPATHW) - 1)) { + HKEY hkt; + + t = sSubKey + (ARRAYLENGTH(CONFIG_REGPATHW) - 1); + +#ifdef DEBUG + assert(*t == L'\0' || *t == L'\\'); +#endif + + rv = RegOpenKeyEx(hkp, + CONFIG_REGPATHW, + ulOptions, + samDesired, + &hkt); + + if (rv != ERROR_SUCCESS) + return rv; + + if (*t == L'\0') { + *phkResult = hkt; + return rv; + } + + t++; + hkp = hkt; + } + + /* descend down the components of the subkey */ + while(TRUE) { + wchar_t * slash; + HKEY hkt; + + slash = wcschr(t, L'\\'); + if (slash == NULL) + break; + + if (FAILED(StringCchCopyN(sk_name, ARRAYLENGTH(sk_name), + t, slash - t))) { + rv = ERROR_CANTOPEN; + goto _cleanup; + } + + sk_name[slash - t] = L'\0'; + t = slash+1; + + if (khcint_RegOpenKeyEx(hkp, sk_name, ulOptions, samDesired, &hkt) == + ERROR_SUCCESS) { + + if (hkp != hkey) + RegCloseKey(hkp); + hkp = hkt; + + } else { + + rv = ERROR_CANTOPEN; + goto _cleanup; + + } + } + + /* by now hkp is a handle to the parent of the last component in + the subkey. t is a pointer to the last component. */ + + if (FAILED(StringCchLength(t, KCONF_MAXCCH_NAME, &cch))) { + rv = ERROR_CANTOPEN; + goto _cleanup; + } + + /* go through and find the case sensitive match for the key */ + + for (i=0; ;i++) { + LONG l; + DWORD dw; + + dw = ARRAYLENGTH(sk_name); + l = RegEnumKeyEx(hkp, i, sk_name, &dw, + NULL, NULL, NULL, &ft); + + if (l != ERROR_SUCCESS) { + rv = ERROR_CANTOPEN; + goto _cleanup; + } + + if (!(wcsncmp(sk_name, t, cch))) { + /* bingo! ?? */ + if (cch < KCONF_MAXCCH_NAME && + (sk_name[cch] == L'\0' || + sk_name[cch] == L'~')) { + rv = RegOpenKeyEx(hkp, sk_name, ulOptions, + samDesired, phkResult); + goto _cleanup; + } + } + } + + _cleanup: + if (hkp != hkey && hkp != NULL) + RegCloseKey(hkp); + + return rv; +} + +/*! \internal + + \note This function is not a good replacement for RegDeleteKey since + it deletes all the subkeys in addition to the key being deleted. + */ +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'~')) { + + /* instead of calling RegDeleteKey we call SHDeleteKey + because we want to blow off all the subkeys as + well. This is different from the behavior of + RegDeleteKey making khcint_RegDeleteKey not a very + good case sensitive replacement for + RegDeleteKey. */ + + rv = SHDeleteKey(hKey, sk_name); + goto _cleanup; + } + } + } + + _cleanup: + return rv; +} + +LONG +khcint_RegCreateKeyEx(HKEY hKey, + LPCWSTR lpSubKey, + DWORD Reserved, + LPWSTR lpClass, + DWORD dwOptions, + REGSAM samDesired, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + PHKEY phkResult, + LPDWORD lpdwDisposition) { + LONG l; + int i; + long index = 0; + wchar_t sk_name[KCONF_MAXCCH_NAME]; /* hard limit in Windows */ + FILETIME ft; + size_t cch; + const wchar_t * t; + LONG rv = ERROR_SUCCESS; + HKEY hkp = NULL; + + hkp = hKey; + t = lpSubKey; + + /* check for case insensitive prefix first */ + if (!_wcsnicmp(lpSubKey, CONFIG_REGPATHW, ARRAYLENGTH(CONFIG_REGPATHW) - 1)) { + HKEY hkt; + + t = lpSubKey + (ARRAYLENGTH(CONFIG_REGPATHW) - 1); + +#ifdef DEBUG + assert(*t == L'\0' || *t == L'\\'); +#endif + + rv = RegCreateKeyEx(hkp, + CONFIG_REGPATHW, + Reserved, + lpClass, + dwOptions, + samDesired, + lpSecurityAttributes, + &hkt, + lpdwDisposition); + + if (rv != ERROR_SUCCESS) + return rv; + + if (*t == L'\0') { + *phkResult = hkt; + return rv; + } + + t++; + hkp = hkt; + } + + while(TRUE) { + wchar_t * slash; + HKEY hkt; + + slash = wcschr(t, L'\\'); + if (slash == NULL) + break; + + if (FAILED(StringCchCopyN(sk_name, ARRAYLENGTH(sk_name), + t, slash - t))) { + rv = ERROR_CANTOPEN; + goto _cleanup; + } + + sk_name[slash - t] = L'\0'; + t = slash+1; + + if (khcint_RegOpenKeyEx(hkp, sk_name, 0, samDesired, &hkt) == + ERROR_SUCCESS) { + + if (hkp != hKey) + RegCloseKey(hkp); + hkp = hkt; + } else { + + rv = RegCreateKeyEx(hKey, + lpSubKey, + Reserved, + lpClass, + dwOptions, + samDesired, + lpSecurityAttributes, + phkResult, + lpdwDisposition); + goto _cleanup; + } + } + + if (FAILED(StringCchLength(t, KCONF_MAXCCH_NAME, &cch))) { + rv = ERROR_CANTOPEN; + goto _cleanup; + } + + for (i=0; ;i++) { + DWORD dw; + + dw = ARRAYLENGTH(sk_name); + l = RegEnumKeyEx(hkp, i, sk_name, &dw, + NULL, NULL, NULL, &ft); + + if (l != ERROR_SUCCESS) + break; + + if (!(wcsncmp(sk_name, t, cch))) { + /* bingo! ?? */ + if (sk_name[cch] == L'\0' || + sk_name[cch] == L'~') { + l = RegOpenKeyEx(hkp, sk_name, 0, + samDesired, phkResult); + if (l == ERROR_SUCCESS && lpdwDisposition) + *lpdwDisposition = REG_OPENED_EXISTING_KEY; + rv = l; + goto _cleanup; + } + } + + if (!_wcsnicmp(sk_name, t, cch) && + (sk_name[cch] == L'\0' || + sk_name[cch] == L'~')) { + long new_idx; + + if (sk_name[cch] == L'\0') + new_idx = 1; + else if (cch + 1 < KCONF_MAXCCH_NAME) + new_idx = wcstol(sk_name + (cch + 1), NULL, 10); + else + return ERROR_BUFFER_OVERFLOW; + + assert(new_idx > 0); + + if (new_idx > index) + index = new_idx; + } + } + + if (index != 0) { + if (FAILED(StringCbPrintf(sk_name, sizeof(sk_name), + L"%s~%d", t, index))) + return ERROR_BUFFER_OVERFLOW; + } else { + StringCbCopy(sk_name, sizeof(sk_name), t); + } + + rv = RegCreateKeyEx(hkp, + sk_name, + Reserved, + lpClass, + dwOptions, + samDesired, + lpSecurityAttributes, + phkResult, + lpdwDisposition); + + _cleanup: + + if (hkp != hKey && hkp != NULL) + RegCloseKey(hkp); + + return rv; +} + +/* obtains cs_conf_global */ +HKEY +khcint_space_open_key(kconf_conf_space * s, khm_int32 flags) { + HKEY hk = NULL; + int nflags = 0; + DWORD disp; + if(flags & KCONF_FLAG_MACHINE) { + if(s->regkey_machine) + return s->regkey_machine; + if((khcint_RegOpenKeyEx(HKEY_LOCAL_MACHINE, s->regpath, 0, + KEY_READ | KEY_WRITE, &hk) != + ERROR_SUCCESS) && + !(flags & KHM_PERM_WRITE)) { + + if(khcint_RegOpenKeyEx(HKEY_LOCAL_MACHINE, s->regpath, 0, + KEY_READ, &hk) == ERROR_SUCCESS) { + nflags = KHM_PERM_READ; + } + + } + if(!hk && (flags & KHM_FLAG_CREATE)) { + + khcint_RegCreateKeyEx(HKEY_LOCAL_MACHINE, + s->regpath, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, + &hk, + &disp); + } + if(hk) { + EnterCriticalSection(&cs_conf_global); + s->regkey_machine = hk; + s->regkey_machine_flags = nflags; + LeaveCriticalSection(&cs_conf_global); + } + + return hk; + } else { + if(s->regkey_user) + return s->regkey_user; + if((khcint_RegOpenKeyEx(HKEY_CURRENT_USER, s->regpath, 0, + KEY_READ | KEY_WRITE, &hk) != + ERROR_SUCCESS) && + !(flags & KHM_PERM_WRITE)) { + if(khcint_RegOpenKeyEx(HKEY_CURRENT_USER, s->regpath, 0, + KEY_READ, &hk) == ERROR_SUCCESS) { + nflags = KHM_PERM_READ; + } + } + if(!hk && (flags & KHM_FLAG_CREATE)) { + khcint_RegCreateKeyEx(HKEY_CURRENT_USER, + s->regpath, 0, NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, &hk, &disp); + } + if(hk) { + EnterCriticalSection(&cs_conf_global); + s->regkey_user = hk; + s->regkey_user_flags = nflags; + LeaveCriticalSection(&cs_conf_global); + } + + return hk; + } +} + +/* obtains cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_shadow_space(khm_handle upper, khm_handle lower) +{ + kconf_handle * h; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!khc_is_handle(upper)) { +#ifdef DEBUG + DebugBreak(); +#endif + return KHM_ERROR_INVALID_PARAM; + } + + h = (kconf_handle *) upper; + + EnterCriticalSection(&cs_conf_handle); + if(h->lower) { + EnterCriticalSection(&cs_conf_global); + khcint_handle_free(h->lower); + LeaveCriticalSection(&cs_conf_global); + h->lower = NULL; + } + + if(khc_is_handle(lower)) { + kconf_handle * l; + kconf_handle * lc; + + l = (kconf_handle *) lower; + lc = khcint_handle_dup(l); + h->lower = lc; + } + LeaveCriticalSection(&cs_conf_handle); + + return KHM_ERROR_SUCCESS; +} + +/* no locks */ +kconf_conf_space * +khcint_create_empty_space(void) { + kconf_conf_space * r; + + r = PMALLOC(sizeof(kconf_conf_space)); + assert(r != NULL); + ZeroMemory(r,sizeof(kconf_conf_space)); + + return r; +} + +/* called with cs_conf_global */ +void +khcint_free_space(kconf_conf_space * r) { + kconf_conf_space * c; + + if(!r) + return; + + TPOPCHILD(r, &c); + while(c) { + khcint_free_space(c); + TPOPCHILD(r, &c); + } + + if(r->name) + PFREE(r->name); + + if(r->regpath) + PFREE(r->regpath); + + if(r->regkey_machine) + RegCloseKey(r->regkey_machine); + + if(r->regkey_user) + RegCloseKey(r->regkey_user); + + PFREE(r); +} + +/* obtains cs_conf_global */ +khm_int32 +khcint_open_space(kconf_conf_space * parent, + const wchar_t * sname, size_t n_sname, + khm_int32 flags, kconf_conf_space **result) { + kconf_conf_space * p; + kconf_conf_space * c; + HKEY pkey = NULL; + HKEY ckey = NULL; + wchar_t buf[KCONF_MAXCCH_NAME]; + size_t cb_regpath = 0; + + if(!parent) + p = conf_root; + else + p = parent; + + if(n_sname >= KCONF_MAXCCH_NAME || n_sname <= 0) + return KHM_ERROR_INVALID_PARAM; + + StringCchCopyN(buf, ARRAYLENGTH(buf), sname, n_sname); + + /* see if there is already a config space by this name. if so, + return it. Note that if the configuration space is specified + in a schema, we would find it here. */ + EnterCriticalSection(&cs_conf_global); + c = TFIRSTCHILD(p); + while(c) { + if(c->name && !wcscmp(c->name, buf)) + break; + + c = LNEXT(c); + } + LeaveCriticalSection(&cs_conf_global); + + if(c) { + + if (c->flags & KCONF_SPACE_FLAG_DELETED) { + if (flags & KHM_FLAG_CREATE) { + c->flags &= ~(KCONF_SPACE_FLAG_DELETED | + KCONF_SPACE_FLAG_DELETE_M | + KCONF_SPACE_FLAG_DELETE_U); + } else { + *result = NULL; + return KHM_ERROR_NOT_FOUND; + } + } + + khcint_space_hold(c); + *result = c; + return KHM_ERROR_SUCCESS; + } + + if(!(flags & KHM_FLAG_CREATE)) { + + /* we are not creating the space, so it must exist in the form of a + registry key in HKLM or HKCU. If it existed as a schema, we + would have already retured it above. */ + + if (flags & KCONF_FLAG_USER) + pkey = khcint_space_open_key(p, KHM_PERM_READ | KCONF_FLAG_USER); + + if((!pkey || + (khcint_RegOpenKeyEx(pkey, buf, 0, KEY_READ, &ckey) != + ERROR_SUCCESS)) + && (flags & KCONF_FLAG_MACHINE)) { + + pkey = khcint_space_open_key(p, KHM_PERM_READ | KCONF_FLAG_MACHINE); + if(!pkey || + (khcint_RegOpenKeyEx(pkey, buf, 0, KEY_READ, &ckey) != + ERROR_SUCCESS)) { + *result = NULL; + + return KHM_ERROR_NOT_FOUND; + } + } + + if(ckey) { + RegCloseKey(ckey); + ckey = NULL; + } + } + + c = khcint_create_empty_space(); + + /*SAFE: buf: is of known length < KCONF_MAXCCH_NAME */ + c->name = PWCSDUP(buf); + + /*SAFE: p->regpath: is valid since it was set using this same + function. */ + /*SAFE: buf: see above */ + cb_regpath = (wcslen(p->regpath) + wcslen(buf) + 2) * sizeof(wchar_t); + c->regpath = PMALLOC(cb_regpath); + + assert(c->regpath != NULL); + + /*SAFE: c->regpath: allocated above to be big enough */ + /*SAFE: p->regpath: see above */ + StringCbCopy(c->regpath, cb_regpath, p->regpath); + StringCbCat(c->regpath, cb_regpath, L"\\"); + + /*SAFE: buf: see above */ + StringCbCat(c->regpath, cb_regpath, buf); + + khcint_space_hold(c); + + EnterCriticalSection(&cs_conf_global); + TADDCHILD(p,c); + LeaveCriticalSection(&cs_conf_global); + + *result = c; + return KHM_ERROR_SUCCESS; +} + +/* obtains cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +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; + const wchar_t * str; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) { + return KHM_ERROR_NOT_READY; + } + + if(!result || (parent && !khc_is_handle(parent))) { +#ifdef DEBUG + DebugBreak(); +#endif + return KHM_ERROR_INVALID_PARAM; + } + + if(!parent) + p = conf_root; + else { + h = (kconf_handle *) parent; + p = khc_space_from_handle(parent); + } + + khcint_space_hold(p); + + /* if none of these flags are specified, make it seem like all of + them were */ + if(!(flags & KCONF_FLAG_USER) && + !(flags & KCONF_FLAG_MACHINE) && + !(flags & KCONF_FLAG_SCHEMA)) + flags |= KCONF_FLAG_USER | KCONF_FLAG_MACHINE | KCONF_FLAG_SCHEMA; + + if(cspace == NULL) { + *result = (khm_handle) khcint_handle_from_space(p, flags); + khcint_space_release(p); + return KHM_ERROR_SUCCESS; + } + + if(FAILED(StringCbLength(cspace, KCONF_MAXCB_PATH, &cbsize))) { + khcint_space_release(p); + *result = NULL; + return KHM_ERROR_INVALID_PARAM; + } + + str = cspace; + while(TRUE) { + const wchar_t * end = NULL; + + if (!(flags & KCONF_FLAG_NOPARSENAME)) { + + end = wcschr(str, L'\\'); /* safe because cspace was + validated above */ + } + + if(!end) { + if(flags & KCONF_FLAG_TRAILINGVALUE) { + /* we are at the value component */ + c = p; + khcint_space_hold(c); + break; + } else + end = str + wcslen(str); /* safe because cspace was + validated above */ + } + + rv = khcint_open_space(p, str, end - str, flags, &c); + + if(KHM_SUCCEEDED(rv) && (*end == L'\\')) { + khcint_space_release(p); + p = c; + c = NULL; + str = end+1; + } + else + break; + } + + khcint_space_release(p); + if(KHM_SUCCEEDED(rv)) { + *result = khcint_handle_from_space(c, flags); + } else + *result = NULL; + + if (c) + khcint_space_release(c); + + return rv; +} + +/* obtains cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_close_space(khm_handle csp) { + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!khc_is_handle(csp)) { +#ifdef DEBUG + DebugBreak(); +#endif + return KHM_ERROR_INVALID_PARAM; + } + + khcint_handle_free((kconf_handle *) csp); + return KHM_ERROR_SUCCESS; +} + +/* obtains cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_read_string(khm_handle pconf, + const wchar_t * pvalue, + wchar_t * buf, + khm_size * bufsize) +{ + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + do { + HKEY hku = NULL; + HKEY hkm = NULL; + const wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + DWORD size; + DWORD type; + LONG hr; + + int i; + + if((value = wcsrchr(pvalue, L'\\')) != NULL) { + + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + goto _shadow; + + free_space = 1; + + if (value) { + value++; + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf)) + goto _shadow; + + c = khc_space_from_handle(conf); + + if(khc_is_user_handle(conf)) + hku = khcint_space_open_key(c, KHM_PERM_READ); + + if(khc_is_machine_handle(conf)) + hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); + + size = (DWORD) *bufsize; + if(hku) { + hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size); + if(hr == ERROR_SUCCESS) { + if(type != REG_SZ) { + rv = KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + else { + *bufsize = size; + /* if buf==NULL, RegQueryValueEx will return success and just return the + required buffer size in 'size' */ + rv = (buf)? KHM_ERROR_SUCCESS: KHM_ERROR_TOO_LONG; + goto _exit; + } + } else { + if(hr == ERROR_MORE_DATA) { + *bufsize = size; + rv = KHM_ERROR_TOO_LONG; + goto _exit; + } + } + } + + size = (DWORD) *bufsize; + if(hkm) { + hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size); + if(hr == ERROR_SUCCESS) { + if(type != REG_SZ) { + rv = KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + else { + *bufsize = size; + rv = (buf)? KHM_ERROR_SUCCESS: KHM_ERROR_TOO_LONG; + goto _exit; + } + } else { + if(hr == ERROR_MORE_DATA) { + *bufsize = size; + rv = KHM_ERROR_TOO_LONG; + goto _exit; + } + } + } + + if(c->schema && khc_is_schema_handle(conf)) { + for(i=0;inSchema;i++) { + if(c->schema[i].type == KC_STRING && !wcscmp(value, c->schema[i].name)) { + /* found it */ + size_t cbsize = 0; + + if(!c->schema[i].value) { + rv = KHM_ERROR_NOT_FOUND; + goto _exit; + } + + if(FAILED(StringCbLength((wchar_t *) c->schema[i].value, KCONF_MAXCB_STRING, &cbsize))) { + rv = KHM_ERROR_NOT_FOUND; + goto _exit; + } + cbsize += sizeof(wchar_t); + + if(!buf || *bufsize < cbsize) { + *bufsize = cbsize; + rv = KHM_ERROR_TOO_LONG; + goto _exit; + } + + StringCbCopy(buf, *bufsize, (wchar_t *) c->schema[i].value); + *bufsize = cbsize; + rv = KHM_ERROR_SUCCESS; + goto _exit; + } + } + } + +_shadow: + if(free_space && conf) + khc_close_space(conf); + + if(khc_is_shadowed(pconf)) { + pconf = khc_shadow(pconf); + continue; + } else { + rv = KHM_ERROR_NOT_FOUND; + break; + } + +_exit: + if(free_space && conf) + khc_close_space(conf); + break; + + } while(TRUE); + + return rv; +} + +/* obtains cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_read_int32(khm_handle pconf, const wchar_t * pvalue, khm_int32 * buf) { + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!buf || !pvalue) + return KHM_ERROR_INVALID_PARAM; + + do { + DWORD size; + DWORD type; + LONG hr; + HKEY hku = NULL; + HKEY hkm = NULL; + + const wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + int i; + + if((value = wcsrchr(pvalue, L'\\')) != NULL) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + goto _shadow; + free_space = 1; + + if (value) { + value++; + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf) || !buf) + goto _shadow; + + c = khc_space_from_handle(conf); + + if(khc_is_user_handle(conf)) + hku = khcint_space_open_key(c, KHM_PERM_READ); + + if(khc_is_machine_handle(conf)) + hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); + + size = sizeof(DWORD); + if(hku) { + hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size); + if(hr == ERROR_SUCCESS) { + if(type != REG_DWORD) { + rv = KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + else { + rv = KHM_ERROR_SUCCESS; + goto _exit; + } + } + } + + size = sizeof(DWORD); + if(hkm) { + hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size); + if(hr == ERROR_SUCCESS) { + if(type != REG_DWORD) { + rv= KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + else { + rv= KHM_ERROR_SUCCESS; + goto _exit; + } + } + } + + if(c->schema && khc_is_schema_handle(conf)) { + for(i=0;inSchema;i++) { + if(c->schema[i].type == KC_INT32 && !wcscmp(value, c->schema[i].name)) { + *buf = (khm_int32) c->schema[i].value; + rv = KHM_ERROR_SUCCESS; + goto _exit; + } + } + } +_shadow: + if(free_space && conf) + khc_close_space(conf); + + if(khc_is_shadowed(pconf)) { + pconf = khc_shadow(pconf); + continue; + } else { + rv = KHM_ERROR_NOT_FOUND; + break; + } +_exit: + if(free_space && conf) + khc_close_space(conf); + break; + } + while(TRUE); + + return rv; +} + +/* obtains cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_read_int64(khm_handle pconf, const wchar_t * pvalue, khm_int64 * buf) { + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + do { + DWORD size; + DWORD type; + LONG hr; + HKEY hku = NULL; + HKEY hkm = NULL; + + const wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + int i; + + if((value = wcsrchr(pvalue, L'\\')) != NULL) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + goto _shadow; + free_space = 1; + + if (value) { + value++; + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf) || !buf) + goto _shadow; + + c = khc_space_from_handle(conf); + + if(khc_is_user_handle(conf)) + hku = khcint_space_open_key(c, KHM_PERM_READ); + + if(khc_is_machine_handle(conf)) + hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); + + size = sizeof(khm_int64); + if(hku) { + hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size); + if(hr == ERROR_SUCCESS) { + if(type != REG_QWORD) { + rv= KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + else { + rv = KHM_ERROR_SUCCESS; + goto _exit; + } + } + } + + size = sizeof(khm_int64); + if(hkm) { + hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size); + if(hr == ERROR_SUCCESS) { + if(type != REG_QWORD) { + rv = KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + else { + rv = KHM_ERROR_SUCCESS; + goto _exit; + } + } + } + + if(c->schema && khc_is_schema_handle(conf)) { + for(i=0;inSchema;i++) { + if(c->schema[i].type == KC_INT64 && !wcscmp(value, c->schema[i].name)) { + *buf = (khm_int64) c->schema[i].value; + rv = KHM_ERROR_SUCCESS; + goto _exit; + } + } + } + +_shadow: + if(free_space && conf) + khc_close_space(conf); + if(khc_is_shadowed(pconf)) { + pconf = khc_shadow(pconf); + continue; + } else { + rv = KHM_ERROR_NOT_FOUND; + break; + } + +_exit: + if(free_space && conf) + khc_close_space(conf); + break; + + } while(TRUE); + return rv; +} + +/* obtaincs cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_read_binary(khm_handle pconf, const wchar_t * pvalue, + void * buf, khm_size * bufsize) { + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + do { + DWORD size; + DWORD type; + LONG hr; + HKEY hku = NULL; + HKEY hkm = NULL; + + const wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + if((value = wcsrchr(pvalue, L'\\')) != NULL) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + goto _shadow; + free_space = 1; + + if (value) { + value++; + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf)) + goto _shadow; + + c = khc_space_from_handle(conf); + + if(khc_is_user_handle(conf)) + hku = khcint_space_open_key(c, KHM_PERM_READ); + + if(khc_is_machine_handle(conf)) + hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); + + size = (DWORD) *bufsize; + if(hku) { + hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size); + if(hr == ERROR_SUCCESS) { + if(type != REG_BINARY) { + rv = KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + else { + *bufsize = size; + rv = KHM_ERROR_SUCCESS; + goto _exit; + } + } else { + if(hr == ERROR_MORE_DATA) { + *bufsize = size; + rv = KHM_ERROR_TOO_LONG; + goto _exit; + } + } + } + + size = (DWORD) *bufsize; + if(hkm) { + hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size); + if(hr == ERROR_SUCCESS) { + if(type != REG_BINARY) { + rv = KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + else { + *bufsize = size; + rv = KHM_ERROR_SUCCESS; + goto _exit; + } + } else { + if(hr == ERROR_MORE_DATA) { + *bufsize = size; + rv = KHM_ERROR_TOO_LONG; + goto _exit; + } + } + } + + /* binary values aren't supported in schema */ +_shadow: + if(free_space && conf) + khc_close_space(conf); + if(khc_is_shadowed(pconf)) { + pconf = khc_shadow(pconf); + continue; + } else { + rv = KHM_ERROR_NOT_FOUND; + break; + } + +_exit: + if(free_space && conf) + khc_close_space(conf); + break; + + }while (TRUE); + + return rv; +} + +/* obtains cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_write_string(khm_handle pconf, + const wchar_t * pvalue, + wchar_t * buf) +{ + HKEY pk = NULL; + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + LONG hr; + size_t cbsize; + const wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf)) + return KHM_ERROR_INVALID_OPERATION; + + if(FAILED(StringCbLength(buf, KCONF_MAXCB_STRING, &cbsize))) { + rv = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cbsize += sizeof(wchar_t); + + if (khc_handle_flags(pconf) & KCONF_FLAG_WRITEIFMOD) { + wchar_t tmpbuf[512]; + wchar_t * buffer; + size_t tmpsize = cbsize; + khm_boolean is_equal = FALSE; + + if (cbsize <= sizeof(tmpbuf)) { + buffer = tmpbuf; + } else { + buffer = PMALLOC(cbsize); + } + + if (KHM_SUCCEEDED(khc_read_string(pconf, pvalue, buffer, &tmpsize)) && + tmpsize == cbsize) { + if (khc_handle_flags(pconf) & KCONF_FLAG_IFMODCI) + is_equal = !_wcsicmp(buffer, buf); + else + is_equal = !wcscmp(buffer, buf); + } + + if (buffer != tmpbuf) + PFREE(buffer); + + if (is_equal) { + return KHM_ERROR_SUCCESS; + } + } + + if((value = wcsrchr(pvalue, L'\\')) != NULL) { + if(KHM_FAILED(khc_open_space(pconf, pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + return KHM_ERROR_INVALID_PARAM; + free_space = 1; + + if (value) { + value ++; + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf) || !buf) { + rv = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + c = khc_space_from_handle(conf); + + if(khc_is_user_handle(conf)) { + pk = khcint_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE); + } else { + pk = khcint_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE); + } + + hr = RegSetValueEx(pk, value, 0, REG_SZ, (LPBYTE) buf, (DWORD) cbsize); + + if(hr != ERROR_SUCCESS) + rv = KHM_ERROR_INVALID_OPERATION; + +_exit: + if(free_space) + khc_close_space(conf); + return rv; +} + +/* obtaincs cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_write_int32(khm_handle pconf, + const wchar_t * pvalue, + khm_int32 buf) +{ + HKEY pk = NULL; + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + LONG hr; + const wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf)) + return KHM_ERROR_INVALID_OPERATION; + + if (khc_handle_flags(pconf) & KCONF_FLAG_WRITEIFMOD) { + khm_int32 tmpvalue; + + if (KHM_SUCCEEDED(khc_read_int32(pconf, pvalue, &tmpvalue)) && + tmpvalue == buf) { + return KHM_ERROR_SUCCESS; + } + } + + if((value = wcsrchr(pvalue, L'\\')) != NULL) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + return KHM_ERROR_INVALID_PARAM; + free_space = 1; + + if (value) { + value ++; + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + c = khc_space_from_handle( conf); + + if(khc_is_user_handle(conf)) { + pk = khcint_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE); + } else { + pk = khcint_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE); + } + + hr = RegSetValueEx(pk, value, 0, REG_DWORD, (LPBYTE) &buf, sizeof(khm_int32)); + + if(hr != ERROR_SUCCESS) + rv = KHM_ERROR_INVALID_OPERATION; + + if(free_space) + khc_close_space(conf); + + return rv; +} + +/* obtains cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_write_int64(khm_handle pconf, const wchar_t * pvalue, khm_int64 buf) { + HKEY pk = NULL; + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + LONG hr; + const wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf)) + return KHM_ERROR_INVALID_OPERATION; + + if (khc_handle_flags(pconf) & KCONF_FLAG_WRITEIFMOD) { + khm_int64 tmpvalue; + + if (KHM_SUCCEEDED(khc_read_int64(pconf, pvalue, &tmpvalue)) && + tmpvalue == buf) { + return KHM_ERROR_SUCCESS; + } + } + + if((value = wcsrchr(pvalue, L'\\')) != NULL) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + return KHM_ERROR_INVALID_PARAM; + free_space = 1; + + if (value) { + value ++; + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + c = khc_space_from_handle( conf); + + if(khc_is_user_handle(conf)) { + pk = khcint_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE); + } else { + pk = khcint_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE); + } + + hr = RegSetValueEx(pk, value, 0, REG_QWORD, (LPBYTE) &buf, sizeof(khm_int64)); + + if(hr != ERROR_SUCCESS) + rv = KHM_ERROR_INVALID_OPERATION; + + if(free_space) + khc_close_space(conf); + + return rv; +} + +/* obtains cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_write_binary(khm_handle pconf, + const wchar_t * pvalue, + void * buf, khm_size bufsize) { + HKEY pk = NULL; + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + LONG hr; + const wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf)) + return KHM_ERROR_INVALID_OPERATION; + + if((value = wcsrchr(pvalue, L'\\')) != NULL) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + return KHM_ERROR_INVALID_PARAM; + free_space = 1; + + if (value) { + value ++; + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + c = khc_space_from_handle(conf); + + if(khc_is_user_handle(conf)) { + pk = khcint_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE); + } else { + pk = khcint_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE); + } + + hr = RegSetValueEx(pk, value, 0, REG_BINARY, buf, (DWORD) bufsize); + + if(hr != ERROR_SUCCESS) + rv = KHM_ERROR_INVALID_OPERATION; + + if(free_space) + khc_close_space(conf); + + return rv; +} + +/* no locks */ +KHMEXP khm_int32 KHMAPI +khc_get_config_space_name(khm_handle conf, + wchar_t * buf, khm_size * bufsize) { + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + c = khc_space_from_handle(conf); + + if(!c->name) { + if(buf && *bufsize > 0) + buf[0] = L'\0'; + else { + *bufsize = sizeof(wchar_t); + rv = KHM_ERROR_TOO_LONG; + } + } else { + size_t cbsize; + + if(FAILED(StringCbLength(c->name, KCONF_MAXCB_NAME, &cbsize))) + return KHM_ERROR_UNKNOWN; + + cbsize += sizeof(wchar_t); + + if(!buf || cbsize > *bufsize) { + *bufsize = cbsize; + rv = KHM_ERROR_TOO_LONG; + } else { + StringCbCopy(buf, *bufsize, c->name); + *bufsize = cbsize; + } + } + + return rv; +} + +/* obtains cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_get_config_space_parent(khm_handle conf, khm_handle * parent) { + kconf_conf_space * c; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + c = khc_space_from_handle(conf); + + if(c == conf_root || c->parent == conf_root) + *parent = NULL; + else + *parent = khcint_handle_from_space(c->parent, khc_handle_flags(conf)); + + return KHM_ERROR_SUCCESS; +} + +/* obtains cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_get_type(khm_handle conf, const wchar_t * value) { + HKEY hkm = NULL; + HKEY hku = NULL; + kconf_conf_space * c; + khm_int32 rv; + LONG hr = ERROR_SUCCESS; + DWORD type = 0; + + if(!khc_is_config_running()) + return KC_NONE; + + if(!khc_is_handle(conf)) + return KC_NONE; + + c = khc_space_from_handle(conf); + + if(!khc_is_machine_handle(conf)) + hku = khcint_space_open_key(c, KHM_PERM_READ); + hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); + + if(hku) + hr = RegQueryValueEx(hku, value, NULL, &type, NULL, NULL); + if(!hku || hr != ERROR_SUCCESS) + hr = RegQueryValueEx(hkm, value, NULL, &type, NULL, NULL); + if(((!hku && !hkm) || hr != ERROR_SUCCESS) && c->schema) { + int i; + + for(i=0; inSchema; i++) { + if(!wcscmp(c->schema[i].name, value)) { + return c->schema[i].type; + } + } + + return KC_NONE; + } + + switch(type) { + case REG_MULTI_SZ: + case REG_SZ: + rv = KC_STRING; + break; + case REG_DWORD: + rv = KC_INT32; + break; + case REG_QWORD: + rv = KC_INT64; + break; + case REG_BINARY: + rv = KC_BINARY; + break; + default: + rv = KC_NONE; + } + + return rv; +} + +/* obtains cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_value_exists(khm_handle conf, const wchar_t * value) { + HKEY hku = NULL; + HKEY hkm = NULL; + kconf_conf_space * c; + khm_int32 rv = 0; + DWORD t; + int i; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + do { + c = khc_space_from_handle(conf); + + if (khc_is_user_handle(conf)) + hku = khcint_space_open_key(c, KHM_PERM_READ); + 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 && khc_is_schema_handle(conf)) { + for(i=0; inSchema; i++) { + if(!wcscmp(c->schema[i].name, value)) { + rv |= KCONF_FLAG_SCHEMA; + break; + } + } + } + + /* if the value is not found at this level and the handle is + shadowed, try the next level down. */ + if (rv == 0 && khc_is_shadowed(conf)) + conf = khc_shadow(conf); + else + break; + } while (conf); + + return rv; +} + +/* obtains cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_remove_value(khm_handle conf, const wchar_t * value, khm_int32 flags) { + HKEY hku = NULL; + HKEY hkm = NULL; + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_NOT_FOUND; + DWORD t; + LONG l; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + c = khc_space_from_handle(conf); + + if(!khc_is_machine_handle(conf)) + hku = khcint_space_open_key(c, KHM_PERM_READ); + hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); + + if((flags == 0 || + (flags & KCONF_FLAG_USER)) && + hku && (RegQueryValueEx(hku, value, NULL, + &t, NULL, NULL) == ERROR_SUCCESS)) { + l = RegDeleteValue(hku, value); + if (l == ERROR_SUCCESS) + rv = KHM_ERROR_SUCCESS; + else + rv = KHM_ERROR_UNKNOWN; + } + if((flags == 0 || + (flags & KCONF_FLAG_MACHINE)) && + hkm && (RegQueryValueEx(hkm, value, NULL, + &t, NULL, NULL) == ERROR_SUCCESS)) { + l = RegDeleteValue(hkm, value); + if (l == ERROR_SUCCESS) + rv = (rv == KHM_ERROR_UNKNOWN)?KHM_ERROR_PARTIAL: + KHM_ERROR_SUCCESS; + else + rv = (rv == KHM_ERROR_SUCCESS)?KHM_ERROR_PARTIAL: + KHM_ERROR_UNKNOWN; + } + + 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); + + khcint_remove_space(cc, flags); + + cc = cn; + } + + cc = TFIRSTCHILD(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 all the registry spaces have been marked as deleted and + there is no schema, we should mark the space as deleted as + well. Note that ideally we only need to check for stores + which have data corresponding to this configuration space, + but this is a bit problematic since we don't monitor the + registry for changes. */ + if ((c->flags & + (KCONF_SPACE_FLAG_DELETE_M | + KCONF_SPACE_FLAG_DELETE_U)) == + (KCONF_SPACE_FLAG_DELETE_M | + KCONF_SPACE_FLAG_DELETE_U) && + (!c->schema || c->nSchema == 0)) + + c->flags |= KCONF_SPACE_FLAG_DELETED; + } + + 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; +} + +/* obtains cs_conf_global */ +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 + repository to delete the space from. (user/machine) + + - When each subspace is released, check if it has been marked + for deletion. If so, delete the marked spaces as well as + removing the space from kconf space tree. + + - When removing a subspace from a space, check if the parent + space has any children left. If there are none, check if the + parent space is also marked for deletion. + */ + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_int32 flags = 0; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + c = khc_space_from_handle(conf); + + EnterCriticalSection(&cs_conf_global); + + if (khc_is_machine_handle(conf)) + flags |= KCONF_SPACE_FLAG_DELETE_M; + if (khc_is_user_handle(conf)) + flags |= KCONF_SPACE_FLAG_DELETE_U; + + rv = khcint_remove_space(c, flags); + + LeaveCriticalSection(&cs_conf_global); + + return rv; +} + +/* no locks */ +khm_boolean +khcint_is_valid_name(wchar_t * name) +{ + size_t cbsize; + if(FAILED(StringCbLength(name, KCONF_MAXCB_NAME, &cbsize))) + return FALSE; + return TRUE; +} + +/* no locks */ +khm_int32 +khcint_validate_schema(const kconf_schema * schema, + int begin, + int *end) +{ + int i; + int state = 0; + int end_found = 0; + + i=begin; + while(!end_found) { + switch(state) { + case 0: /* initial. this record should start a config space */ + if(!khcint_is_valid_name(schema[i].name) || + schema[i].type != KC_SPACE) + return KHM_ERROR_INVALID_PARAM; + state = 1; + break; + + case 1: /* we are inside a config space, in the values area */ + if(!khcint_is_valid_name(schema[i].name)) + return KHM_ERROR_INVALID_PARAM; + if(schema[i].type == KC_SPACE) { + if(KHM_FAILED(khcint_validate_schema(schema, i, &i))) + return KHM_ERROR_INVALID_PARAM; + state = 2; + } else if(schema[i].type == KC_ENDSPACE) { + end_found = 1; + if(end) + *end = i; + } else { + if(schema[i].type != KC_STRING && + schema[i].type != KC_INT32 && + schema[i].type != KC_INT64 && + schema[i].type != KC_BINARY) + return KHM_ERROR_INVALID_PARAM; + } + break; + + case 2: /* we are inside a config space, in the subspace area */ + if(schema[i].type == KC_SPACE) { + if(KHM_FAILED(khcint_validate_schema(schema, i, &i))) + return KHM_ERROR_INVALID_PARAM; + } else if(schema[i].type == KC_ENDSPACE) { + end_found = 1; + if(end) + *end = i; + } else { + return KHM_ERROR_INVALID_PARAM; + } + break; + + default: + /* unreachable */ + return KHM_ERROR_INVALID_PARAM; + } + i++; + } + + return KHM_ERROR_SUCCESS; +} + +/* obtains cs_conf_handle/cs_conf_global; called with cs_conf_global */ +khm_int32 +khcint_load_schema_i(khm_handle parent, const kconf_schema * schema, + int begin, int * end) +{ + int i; + int state = 0; + int end_found = 0; + kconf_conf_space * thisconf = NULL; + khm_handle h = NULL; + + i=begin; + while(!end_found) { + switch(state) { + case 0: /* initial. this record should start a config space */ + LeaveCriticalSection(&cs_conf_global); + if(KHM_FAILED(khc_open_space(parent, schema[i].name, + KHM_FLAG_CREATE, &h))) { + EnterCriticalSection(&cs_conf_global); + return KHM_ERROR_INVALID_PARAM; + } + EnterCriticalSection(&cs_conf_global); + thisconf = khc_space_from_handle(h); + thisconf->schema = schema + (begin + 1); + thisconf->nSchema = 0; + state = 1; + break; + + case 1: /* we are inside a config space, in the values area */ + if(schema[i].type == KC_SPACE) { + thisconf->nSchema = i - (begin + 1); + if(KHM_FAILED(khcint_load_schema_i(h, schema, i, &i))) + return KHM_ERROR_INVALID_PARAM; + state = 2; + } else if(schema[i].type == KC_ENDSPACE) { + thisconf->nSchema = i - (begin + 1); + end_found = 1; + if(end) + *end = i; + LeaveCriticalSection(&cs_conf_global); + khc_close_space(h); + EnterCriticalSection(&cs_conf_global); + } + break; + + case 2: /* we are inside a config space, in the subspace area */ + if(schema[i].type == KC_SPACE) { + if(KHM_FAILED(khcint_load_schema_i(h, schema, i, &i))) + return KHM_ERROR_INVALID_PARAM; + } else if(schema[i].type == KC_ENDSPACE) { + end_found = 1; + if(end) + *end = i; + LeaveCriticalSection(&cs_conf_global); + khc_close_space(h); + EnterCriticalSection(&cs_conf_global); + } else { + return KHM_ERROR_INVALID_PARAM; + } + break; + + default: + /* unreachable */ + return KHM_ERROR_INVALID_PARAM; + } + i++; + } + + return KHM_ERROR_SUCCESS; +} + +/* obtains cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_load_schema(khm_handle conf, const kconf_schema * schema) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(conf && !khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + if(KHM_FAILED(khcint_validate_schema(schema, 0, NULL))) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_conf_global); + rv = khcint_load_schema_i(conf, schema, 0, NULL); + LeaveCriticalSection(&cs_conf_global); + + return rv; +} + +/* obtains cs_conf_handle/cs_conf_global; called with cs_conf_global */ +khm_int32 +khcint_unload_schema_i(khm_handle parent, const kconf_schema * schema, + int begin, int * end) +{ + int i; + int state = 0; + int end_found = 0; + kconf_conf_space * thisconf = NULL; + khm_handle h = NULL; + + i=begin; + while(!end_found) { + switch(state) { + case 0: /* initial. this record should start a config space */ + LeaveCriticalSection(&cs_conf_global); + if(KHM_FAILED(khc_open_space(parent, schema[i].name, 0, &h))) { + EnterCriticalSection(&cs_conf_global); + return KHM_ERROR_INVALID_PARAM; + } + EnterCriticalSection(&cs_conf_global); + thisconf = khc_space_from_handle(h); + if(thisconf->schema == (schema + (begin + 1))) { + thisconf->schema = NULL; + thisconf->nSchema = 0; + } + state = 1; + break; + + case 1: /* we are inside a config space, in the values area */ + if(schema[i].type == KC_SPACE) { + if(KHM_FAILED(khcint_unload_schema_i(h, schema, i, &i))) + return KHM_ERROR_INVALID_PARAM; + state = 2; + } else if(schema[i].type == KC_ENDSPACE) { + end_found = 1; + if(end) + *end = i; + LeaveCriticalSection(&cs_conf_global); + khc_close_space(h); + EnterCriticalSection(&cs_conf_global); + } + break; + + case 2: /* we are inside a config space, in the subspace area */ + if(schema[i].type == KC_SPACE) { + if(KHM_FAILED(khcint_unload_schema_i(h, schema, i, &i))) + return KHM_ERROR_INVALID_PARAM; + } else if(schema[i].type == KC_ENDSPACE) { + end_found = 1; + if(end) + *end = i; + LeaveCriticalSection(&cs_conf_global); + khc_close_space(h); + EnterCriticalSection(&cs_conf_global); + } else { + return KHM_ERROR_INVALID_PARAM; + } + break; + + default: + /* unreachable */ + return KHM_ERROR_INVALID_PARAM; + } + i++; + } + + return KHM_ERROR_SUCCESS; +} + +/* obtains cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_unload_schema(khm_handle conf, const kconf_schema * schema) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(conf && !khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + if(KHM_FAILED(khcint_validate_schema(schema, 0, NULL))) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_conf_global); + rv = khcint_unload_schema_i(conf, schema, 0, NULL); + LeaveCriticalSection(&cs_conf_global); + + return rv; +} + +/* obtaincs cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_enum_subspaces(khm_handle conf, + khm_handle prev, + khm_handle * next) +{ + kconf_conf_space * s; + kconf_conf_space * c; + kconf_conf_space * p; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!khc_is_handle(conf) || next == NULL || + (prev != NULL && !khc_is_handle(prev))) + return KHM_ERROR_INVALID_PARAM; + + s = khc_space_from_handle(conf); + + if(prev == NULL) { + /* first off, we enumerate all the registry spaces regardless of + whether the handle is applicable for some registry space or not. + See notes for khc_begin_enum_subspaces() for reasons as to why + this is done (notes are in kconfig.h)*/ + + /* go through the user hive first */ + { + HKEY hk_conf; + + hk_conf = khcint_space_open_key(s, 0); + if(hk_conf) { + wchar_t name[KCONF_MAXCCH_NAME]; + khm_handle h; + int idx; + + idx = 0; + while(RegEnumKey(hk_conf, idx, + name, ARRAYLENGTH(name)) == ERROR_SUCCESS) { + wchar_t * tilde; + tilde = wcschr(name, L'~'); + if (tilde) + *tilde = 0; + if(KHM_SUCCEEDED(khc_open_space(conf, name, 0, &h))) + khc_close_space(h); + idx++; + } + } + } + + /* go through the machine hive next */ + { + HKEY hk_conf; + + hk_conf = khcint_space_open_key(s, KCONF_FLAG_MACHINE); + if(hk_conf) { + wchar_t name[KCONF_MAXCCH_NAME]; + khm_handle h; + int idx; + + idx = 0; + while(RegEnumKey(hk_conf, idx, + name, ARRAYLENGTH(name)) == ERROR_SUCCESS) { + wchar_t * tilde; + tilde = wcschr(name, L'~'); + if (tilde) + *tilde = 0; + + if(KHM_SUCCEEDED(khc_open_space(conf, name, + KCONF_FLAG_MACHINE, &h))) + khc_close_space(h); + idx++; + } + } + } + + /* don't need to go through schema, because that was already + done when the schema was loaded. */ + } + + /* at last we are now ready to return the results */ + EnterCriticalSection(&cs_conf_global); + if(prev == NULL) { + c = TFIRSTCHILD(s); + rv = KHM_ERROR_SUCCESS; + } else { + p = khc_space_from_handle(prev); + if(TPARENT(p) == s) + c = LNEXT(p); + else + c = NULL; + } + LeaveCriticalSection(&cs_conf_global); + + if(prev != NULL) + khc_close_space(prev); + + if(c) { + *next = khcint_handle_from_space(c, khc_handle_flags(conf)); + rv = KHM_ERROR_SUCCESS; + } else { + *next = NULL; + rv = KHM_ERROR_NOT_FOUND; + } + + return rv; +} + +/* obtains cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_write_multi_string(khm_handle conf, const wchar_t * value, wchar_t * buf) +{ + size_t cb; + wchar_t vbuf[KCONF_MAXCCH_STRING]; + wchar_t *tb; + khm_int32 rv; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + if(!khc_is_handle(conf) || buf == NULL || value == NULL) + return KHM_ERROR_INVALID_PARAM; + + if(multi_string_to_csv(NULL, &cb, buf) != KHM_ERROR_TOO_LONG) + return KHM_ERROR_INVALID_PARAM; + + if (cb < sizeof(vbuf)) + tb = vbuf; + else + tb = PMALLOC(cb); + + assert(tb != NULL); + + multi_string_to_csv(tb, &cb, buf); + rv = khc_write_string(conf, value, tb); + + if (tb != vbuf) + PFREE(tb); + return rv; +} + +/* obtains cs_conf_handle/cs_conf_global */ +KHMEXP khm_int32 KHMAPI +khc_read_multi_string(khm_handle conf, const wchar_t * value, + wchar_t * buf, khm_size * bufsize) +{ + wchar_t vbuf[KCONF_MAXCCH_STRING]; + wchar_t * tb; + khm_size cbbuf; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!bufsize) + return KHM_ERROR_INVALID_PARAM; + + rv = khc_read_string(conf, value, NULL, &cbbuf); + if(rv != KHM_ERROR_TOO_LONG) + return rv; + + if (cbbuf < sizeof(vbuf)) + tb = vbuf; + else + tb = PMALLOC(cbbuf); + + assert(tb != NULL); + + rv = khc_read_string(conf, value, tb, &cbbuf); + + if(KHM_FAILED(rv)) + goto _exit; + + rv = csv_to_multi_string(buf, bufsize, tb); + +_exit: + if (tb != vbuf) + PFREE(tb); + + return rv; +} diff --git a/src/windows/identity/kconfig/kconfig.h b/src/windows/identity/kconfig/kconfig.h index b550d1358..691fe7115 100644 --- a/src/windows/identity/kconfig/kconfig.h +++ b/src/windows/identity/kconfig/kconfig.h @@ -1,960 +1,960 @@ -/* - * 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_KCONFIG_H -#define __KHIMAIRA_KCONFIG_H - -#include -#include - -/*! \defgroup kconf NetIDMgr Configuration Provider */ -/*@{*/ - -/*! \brief Configuration schema descriptor record - - The schema descriptor is a convenient way to provide a default set - of configuration options for a part of an application. It - describes the configuration spaces and the values and subspaces - contained in each space. - - \see kconf_load_schema() -*/ -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. - Names can be upto KCONF_MAXCCH_NAME - characters in length. */ - khm_int32 type; /*!< type of the object. Can be one of - KC_SPACE, KC_ENDSPACE, KC_INT32, - KC_INT64, KC_STRING or KC_BINARY */ - khm_ui_8 value; /*!< the value of the object. It is not - used for KC_SPACE and KC_ENDSPACE - typed objects. For a KC_STRING, this - contains a pointer to the string - value. The string should not be - longer than KCONF_MAXCCH_STRING - characters. KC_INT32 and KC_INT64 - objects store the value directly in - this field, while KC_BINARY objects do - not support defining a default value - here. */ - wchar_t * description;/*!< a friendly description of the value - or configuration space. */ -} kconf_schema; - -/*! \name Configuration data types - @{*/ -/*! \brief Not a known type */ -#define KC_NONE 0 - -/*! \brief When used as ::kconf_schema \a type, defines the start of a configuration space. - - There should be a subsequent KC_ENDSPACE record in the schema - which defines the end of this configuration space. - - \a name specifies the name of the configuration space. Optionally - use \a description to provide a description.*/ -#define KC_SPACE 1 - -/*! \brief Ends a configuration space started with KC_SPACE */ -#define KC_ENDSPACE 2 - -/*! \brief A 32 bit integer - - Specifies a configuration parameter named \a name which is of this - type. Use \a description to provide an optional description of - the value. - - \a value specifies a default value for this parameter in the lower - 32 bits. -*/ -#define KC_INT32 3 - -/*! \brief A 64 bit integer - - Specifies a configuration parameter named \a name which is of this - type. Use \a description to provide an optional description of - the value. - - \a value specifies a default value for this parameter. -*/ -#define KC_INT64 4 - -/*! \brief A unicode string - - Specifies a configuration parameter named \a name which is of this - type. Use \a description to provide an optional description of - the value. - - \a value specifies a default value for this parameter which should - be a pointer to a NULL terminated unicode string of no more than - ::KCONF_MAXCCH_STRING characters. -*/ -#define KC_STRING 5 - -/*! \brief An unparsed binary stream - - Specifies a configuration parameter named \a name which is of this - type. Use \a description to provide an optional description of - the value. - - Default values are not supported for binary streams. \a value is - ignored. -*/ -#define KC_BINARY 6 -/*@}*/ - -/*! \brief This is the root configuration space */ -#define KCONF_FLAG_ROOT 0x00000001 - -/*! \brief Indicates the configuration store which stores user-specific information */ -#define KCONF_FLAG_USER 0x00000002 - -/*! \brief Indicates the configuration store which stores machine-specific information */ -#define KCONF_FLAG_MACHINE 0x00000004 - -/*! \brief Indicates the configuration store which stores the schema */ -#define KCONF_FLAG_SCHEMA 0x00000008 - -/*! \brief Indicates that the last component of the given configuration path is to be considered to be a configuration value */ -#define KCONF_FLAG_TRAILINGVALUE 0x00000020 - -/*! \brief Only write values back there is a change - - Any write operations using the handle with check if the value - being written is different from the value being read from the - handle. It will only be written if the value is different. - - \note Note that the value being read from a handle takes schema and - shadowed configuration handles into consideration while the value - being written is only written to the topmost layer of - configuration that can be written to. - - \note Note also that this flag does not affect binary values. - */ -#define KCONF_FLAG_WRITEIFMOD 0x00000040 - -/*! \brief Use case-insensitive comparison for KCONF_FLAG_WRITEIFMOD - - When used in combination with \a KCONF_FLAG_WRITEIFMOD , the - string comparison used when determining whether the string read - from the configuration handle is the same as the string being - written will be case insensitive. If this flag is not set, the - comparison will be case sensitive. - */ -#define KCONF_FLAG_IFMODCI 0x00000080 - -/*! \brief Do not parse the configuration space name - - If set, disables the parsing of the configuration space for - subspaces. The space name is taken verbatim to be a configuration - space name. This can be used when there can be forward slashes or - backslahes in the name which are not escaped. - - By default, the configuration space name, - - \code - 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. - */ -#define KCONF_FLAG_NOPARSENAME 0x00000040 - -/*! \brief Maximum number of allowed characters (including terminating NULL) in a name - - \note This is a hard limit in Windows, since we are mapping - configuration spaces to registry keys. -*/ -#define KCONF_MAXCCH_NAME 256 - -/*! \brief Maximum number of allowed bytes (including terminating NULL) in a name */ -#define KCONF_MAXCB_NAME (KCONF_MAXCCH_NAME * sizeof(wchar_t)) - -/*! \brief Maximum level of nesting for configuration spaces - */ -#define KCONF_MAX_DEPTH 16 - -/*! \brief Maximum number of allowed characters (including terminating NULL) in a configuration path */ -#define KCONF_MAXCCH_PATH (KCONF_MAXCCH_NAME * KCONF_MAX_DEPTH) - -/*! \brief Maximum number of allowed bytes (including terminating NULL) in a configuration path */ -#define KCONF_MAXCB_PATH (KCONF_MAXCCH_PATH * sizeof(wchar_t)) - -/*! \brief Maximum number of allowed characters (including terminating NULL) in a string */ -#define KCONF_MAXCCH_STRING KHM_MAXCCH_STRING - -/*! \brief Maximum number of allowed bytes (including terminating NULL) in a string */ -#define KCONF_MAXCB_STRING (KCONF_MAXCCH_STRING * sizeof(wchar_t)) - -/*! \brief Open a configuration space - - Opens the configuration space specified by \a cspace. By default, - the opened space includes user,machine and schema configuration - stores. However, you can specify a subset of these. - - If the configuration space does not exist and the \a flags specify - KHM_FLAG_CREATE, then the configuration space is created. The - stores that are affected by the create operation depend on \a - flags. If the \a flags only specifies ::KCONF_FLAG_MACHINE, then - the configuration space is created in the machine store. If \a - flags specifies any combination of stores including \a - ::KCONF_FLAG_USER, then the configuration space is created in the - user store. Note that ::KCONF_FLAG_SCHEMA is readonly. - - Once opened, use khc_close_space() to close the configuration - space. - - \param[in] parent The parent configuration space. The path - specified in \a cspace is relative to the parent. Set this to - NULL to indicate the root configuration space. - - \param[in] cspace The confiuration path. This can be up to - ::KCONF_MAXCCH_PATH characters in length. Use either - backslashes or forward slashes to specify hiearchy. Set this - to NULL to reopen the parent configuration space. - - \param[in] flags Flags. This can be a combination of KCONF_FLAG_* - constants and KHM_FLAG_CREATE. If none of ::KCONF_FLAG_USER, - ::KCONF_FLAG_MACHINE or ::KCONF_FLAG_SCHEMA is specified, then - it defaults to all three. - - \param[out] result Pointer to a handle which receives the handle - to the opened configuration space if the call succeeds. - - \note You can re-open a configuration space with different flags - such as ::KCONF_FLAG_MACHINE by specifying NULL for \a cspace - and settings \a flags to the required flags. - -*/ -KHMEXP khm_int32 KHMAPI -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 - - The handle specified by \a lower becomes a shadow for the handle - specified by \a upper. Any configuration value that is queried in - \a upper that does not exist in \a upper will be queried in \a - lower. - - If \a upper already had a shadow handle, that handle will be - replaced by \a lower. The handle \a lower still needs to be - closed by a call to khc_close_space(). However, closing \a lower - will not affect \a upper which will still treat the configuration - space pointed to by \a lower to be it's shadow. - - Shadows are specific to handles and not configuration spaces. - Shadowing a configuration space using one handle does not affect - any other handles which may be obtained for the same configuration - space. - - Specify NULL for \a lower to remove any prior shadow. - */ -KHMEXP khm_int32 KHMAPI -khc_shadow_space(khm_handle upper, khm_handle lower); - -/*! \brief Close a handle opened with khc_open_space() -*/ -KHMEXP khm_int32 KHMAPI -khc_close_space(khm_handle conf); - -/*! \brief Read a string value from a configuration space - - The \a value_name parameter specifies the value to read from the - configuration space. This can be either a value name or a value - path consisting of a series nested configuration space names - followed by the value name all separated by backslashes or forward - slashes. - - For example: If \a conf is a handle to the configuration space \c - 'A/B/C', then the value name \c 'D/E/v' refers to the value named - \c 'v' in the configuration space \c 'A/B/C/D/E'. - - The specific configuration store that is used to access the value - depends on the flags that were specified in the call to - khc_open_space(). The precedence of configuration stores are as - follows: - - - If KCONF_FLAG_USER was specified, then the user configuration - space. - - - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine - configuration space. - - - Otherwise, if KCONF_FLAG_SCHEMA was specified, the the schema - store. - - Note that not specifying any of the configuration store specifiers - in the call to khc_open_space() is equivalent to specifying all - three. - - If the value is not found in the configuration space and any - shadowed configuration spaces, the function returns \a - KHM_ERROR_NOT_FOUND. In this case, the buffer is left unmodified. - - \param[in] buf Buffer to copy the string to. Specify NULL to just - retrieve the number of required bytes. - - \param[in,out] bufsize On entry, specifies the number of bytes of - space available at the location specified by \a buf. On exit - specifies the number of bytes actually copied or the size of - the required buffer if \a buf is NULL or insufficient. - - \retval KHM_ERROR_NOT_READY The configuration provider has not started - \retval KHM_ERROR_INVALID_PARAM One or more of the supplied parameters are not valid - \retval KHM_ERROR_TYPE_MISMATCH The specified value is not a string - \retval KHM_ERROR_TOO_LONG \a buf was NULL or the size of the buffer was insufficient. The required size is in bufsize. - \retval KHM_ERROR_SUCCESS Success. The number of bytes copied is in bufsize. - \retval KHM_ERROR_NOT_FOUND The value was not found. - - \see khc_open_space() -*/ -KHMEXP khm_int32 KHMAPI -khc_read_string(khm_handle conf, - const wchar_t * value_name, - wchar_t * buf, - khm_size * bufsize); - -/*! \brief Read a multi-string value from a configuration space - - The \a value_name parameter specifies the value to read from the - configuration space. This can be either a value name or a value - path consisting of a series nested configuration space names - followed by the value name all separated by backslashes or forward - slashes. - - For example: If \a conf is a handle to the configuration space \c - 'A/B/C', then the value name \c 'D/E/v' refers to the value named - \c 'v' in the configuration space \c 'A/B/C/D/E'. - - The specific configuration store that is used to access the value - depends on the flags that were specified in the call to - khc_open_space(). The precedence of configuration stores are as - follows: - - - If KCONF_FLAG_USER was specified, then the user configuration - space. - - - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine - configuration space. - - - Otherwise, if KCONF_FLAG_SCHEMA was specified, the the schema - store. - - A multi-string is a pseudo data type. The value in the - configuration store should contain a CSV string. Each comma - separated value in the CSV string is considered to be a separate - value. Empty values are not allowed. The buffer pointed to by \a - buf will receive these values in the form of a series of NULL - terminated strings terminated by an empty string (or equivalently, - the last string will be terminated by a double NULL). - - Note that not specifying any of the configuration store specifiers - in the call to khc_open_space() is equivalent to specifying all - three. - - If the value is not found in the configuration space and any - shadowed configuration spaces, the function returns \a - KHM_ERROR_NOT_FOUND. In this case, the buffer is left unmodified. - - \param[in] buf Buffer to copy the multi-string to. Specify NULL - to just retrieve the number of required bytes. - - \param[in,out] bufsize On entry, specifies the number of bytes of - space available at the location specified by \a buf. On exit - specifies the number of bytes actually copied or the size of - the required buffer if \a buf is NULL or insufficient. - - \retval KHM_ERROR_NOT_READY The configuration provider has not started - \retval KHM_ERROR_INVALID_PARAM One or more of the supplied parameters are not valid - \retval KHM_ERROR_TYPE_MISMATCH The specified value is not a string - \retval KHM_ERROR_TOO_LONG \a buf was NULL or the size of the buffer was insufficient. The required size is in bufsize. - \retval KHM_ERROR_SUCCESS Success. The number of bytes copied is in bufsize. - \retval KHM_ERROR_NOT_FOUND The value was not found. - - \see khc_open_space() -*/ -KHMEXP khm_int32 KHMAPI -khc_read_multi_string(khm_handle conf, - const wchar_t * value_name, - wchar_t * buf, - khm_size * bufsize); - -/*! \brief Read a 32 bit integer value from a configuration space - - The \a value_name parameter specifies the value to read from the - configuration space. This can be either a value name or a value - path consisting of a series nested configuration space names - followed by the value name all separated by backslashes or forward - slashes. - - For example: If \a conf is a handle to the configuration space \c - 'A/B/C', then the value name \c 'D/E/v' refers to the value named - \c 'v' in the configuration space \c 'A/B/C/D/E'. - - The specific configuration store that is used to access the value - depends on the flags that were specified in the call to - khc_open_space(). The precedence of configuration stores are as - follows: - - - If KCONF_FLAG_USER was specified, then the user configuration - space. - - - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine - configuration space. - - - Otherwise, if KCONF_FLAG_SCHEMA was specified, the the schema - store. - - Note that not specifying any of the configuration store specifiers - in the call to khc_open_space() is equivalent to specifying all - three. - - If the value is not found in the configuration space and any - shadowed configuration spaces, the function returns \a - KHM_ERROR_NOT_FOUND. In this case, the buffer is left unmodified. - - \param[in] conf Handle to a configuration space - \param[in] value The value to query - \param[out] buf The buffer to receive the value - - \retval KHM_ERROR_NOT_READY The configuration provider has not started. - \retval KHM_ERROR_SUCCESS Success. The value that was read was placed in \a buf - \retval KHM_ERROR_NOT_FOUND The specified value was not found - \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid - \retval KHM_ERROR_TYPE_MISMATCH The specified value was found but was not of the correct type. - \see khc_open_space() -*/ -KHMEXP khm_int32 KHMAPI -khc_read_int32(khm_handle conf, - const wchar_t * value_name, - khm_int32 * buf); - -/*! \brief Read a 64 bit integer value from a configuration space - - The \a value_name parameter specifies the value to read from the - configuration space. This can be either a value name or a value - path consisting of a series nested configuration space names - followed by the value name all separated by backslashes or forward - slashes. - - For example: If \a conf is a handle to the configuration space \c - 'A/B/C', then the value name \c 'D/E/v' refers to the value named - \c 'v' in the configuration space \c 'A/B/C/D/E'. - - The specific configuration store that is used to access the value - depends on the flags that were specified in the call to - khc_open_space(). The precedence of configuration stores are as - follows: - - - If KCONF_FLAG_USER was specified, then the user configuration - space. - - - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine - configuration space. - - - Otherwise, if KCONF_FLAG_SCHEMA was specified, the the schema - store. - - Note that not specifying any of the configuration store specifiers - in the call to khc_open_space() is equivalent to specifying all - three. - - If the value is not found in the configuration space and any - shadowed configuration spaces, the function returns \a - KHM_ERROR_NOT_FOUND. In this case, the buffer is left unmodified. - - \param[in] conf Handle to a configuration space - \param[in] value_name The value to query - \param[out] buf The buffer to receive the value - - \retval KHM_ERROR_NOT_READY The configuration provider has not started - \retval KHM_ERROR_SUCCESS Success. The value that was read was placed in \a buf - \retval KHM_ERROR_NOT_FOUND The specified value was not found - \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid - \retval KHM_ERROR_TYPE_MISMATCH The specified value was found but was not the correct data type. - - \see khc_open_space() -*/ -KHMEXP khm_int32 KHMAPI -khc_read_int64(khm_handle conf, - const wchar_t * value_name, - khm_int64 * buf); - -/*! \brief Read a binary value from a configuration space - - The \a value_name parameter specifies the value to read from the - configuration space. This can be either a value name or a value - path consisting of a series nested configuration space names - followed by the value name all separated by backslashes or forward - slashes. - - For example: If \a conf is a handle to the configuration space \c - 'A/B/C', then the value name \c 'D/E/v' refers to the value named - \c 'v' in the configuration space \c 'A/B/C/D/E'. - - The specific configuration store that is used to access the value - depends on the flags that were specified in the call to - khc_open_space(). The precedence of configuration stores are as - follows: - - - If KCONF_FLAG_USER was specified, then the user configuration - space. - - - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine - configuration space. - - Note that not specifying any of the configuration store specifiers - in the call to khc_open_space() is equivalent to specifying all - three. Also note that the schema store (KCONF_FLAG_SCHEMA) does - not support binary values. - - If the value is not found in the configuration space and any - shadowed configuration spaces, the function returns \a - KHM_ERROR_NOT_FOUND. In this case, the buffer is left unmodified. - - \param[in] buf Buffer to copy the string to. Specify NULL to just - retrieve the number of required bytes. - - \param[in,out] bufsize On entry, specifies the number of bytes of - space available at the location specified by \a buf. On exit - specifies the number of bytes actually copied or the size of - the required buffer if \a buf is NULL or insufficient. - - \retval KHM_ERROR_SUCCESS Success. The data was copied to \a buf. The number of bytes copied is stored in \a bufsize - \retval KHM_ERROR_NOT_FOUND The specified value was not found - \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid. - - \see khc_open_space() -*/ -KHMEXP khm_int32 KHMAPI -khc_read_binary(khm_handle conf, - const wchar_t * value_name, - void * buf, - khm_size * bufsize); - -/*! \brief Write a string value to a configuration space - - The \a value_name parameter specifies the value to write to the - configuration space. This can be either a value name or a value - path consisting of a series nested configuration space names - followed by the value name all separated by backslashes or forward - slashes. - - For example: If \a conf is a handle to the configuration space \c - 'A/B/C', then the value name \c 'D/E/v' refers to the value named - \c 'v' in the configuration space \c 'A/B/C/D/E'. - - The specific configuration store that is used to write the value - depends on the flags that were specified in the call to - khc_open_space(). The precedence of configuration stores are as - follows: - - - If \a KCONF_FLAG_USER was specified, then the user configuration - space. - - - Otherwise, if \a KCONF_FLAG_MACHINE was specified, then the - machine configuration space. - - Note that not specifying any of the configuration store specifiers - in the call to khc_open_space() is equivalent to specifying all - three. Also note that the schema store (KCONF_FLAG_SCHEMA) is - readonly. - - If the \a KCONF_FLAG_WRITEIFMOD flag is specified in the call to - khc_open_space() for obtaining the configuration handle, the - specified string will only be written if it is different from the - value being read from the handle. - - If the \a KCONF_FLAG_IFMODCI flag is specified along with the \a - KCONF_FLAG_WRITEIFMOD flag, then the string comparison used will - be case insensitive. - - \param[in] conf Handle to a configuration space - \param[in] value_name Name of value to write - \param[in] buf A NULL terminated unicode string not exceeding KCONF_MAXCCH_STRING in characters including terminating NULL - - \see khc_open_space() -*/ -KHMEXP khm_int32 KHMAPI -khc_write_string(khm_handle conf, - const wchar_t * value_name, - wchar_t * buf); - -/*! \brief Write a multi-string value to a configuration space - - The \a value_name parameter specifies the value to write to the - configuration space. This can be either a value name or a value - path consisting of a series nested configuration space names - followed by the value name all separated by backslashes or forward - slashes. - - For example: If \a conf is a handle to the configuration space \c - 'A/B/C', then the value name \c 'D/E/v' refers to the value named - \c 'v' in the configuration space \c 'A/B/C/D/E'. - - The specific configuration store that is used to write the value - depends on the flags that were specified in the call to - khc_open_space(). The precedence of configuration stores are as - follows: - - A multi-string is a pseudo data type. The buffer pointed to by \a - buf should contain a sequence of NULL terminated strings - terminated by an empty string (or equivalently, the last string - should terminate with a double NULL). This will be stored in the - value as a CSV string. - - - If KCONF_FLAG_USER was specified, then the user configuration - space. - - - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine - configuration space. - - Note that not specifying any of the configuration store specifiers - in the call to khc_open_space() is equivalent to specifying all - three. Also note that the schema store (KCONF_FLAG_SCHEMA) is - readonly. - - If the \a KCONF_FLAG_WRITEIFMOD flag is specified in the call to - khc_open_space() for obtaining the configuration handle, the - specified string will only be written if it is different from the - value being read from the handle. - - If the \a KCONF_FLAG_IFMODCI flag is specified along with the \a - KCONF_FLAG_WRITEIFMOD flag, then the string comparison used will - be case insensitive. - - \see khc_open_space() -*/ -KHMEXP khm_int32 KHMAPI -khc_write_multi_string(khm_handle conf, - const wchar_t * value_name, - wchar_t * buf); - -/*! \brief Write a 32 bit integer value to a configuration space - - The \a value_name parameter specifies the value to write to the - configuration space. This can be either a value name or a value - path consisting of a series nested configuration space names - followed by the value name all separated by backslashes or forward - slashes. - - For example: If \a conf is a handle to the configuration space \c - 'A/B/C', then the value name \c 'D/E/v' refers to the value named - \c 'v' in the configuration space \c 'A/B/C/D/E'. - - The specific configuration store that is used to write the value - depends on the flags that were specified in the call to - khc_open_space(). The precedence of configuration stores are as - follows: - - - If KCONF_FLAG_USER was specified, then the user configuration - space. - - - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine - configuration space. - - Note that not specifying any of the configuration store specifiers - in the call to khc_open_space() is equivalent to specifying all - three. Also note that the schema store (KCONF_FLAG_SCHEMA) is - readonly. - - If the \a KCONF_FLAG_WRITEIFMOD flag is specified in the call to - khc_open_space() for obtaining the configuration handle, the - specified string will only be written if it is different from the - value being read from the handle. - - \see khc_open_space() -*/ -KHMEXP khm_int32 KHMAPI -khc_write_int32(khm_handle conf, - const wchar_t * value_name, - khm_int32 buf); - -/*! \brief Write a 64 bit integer value to a configuration space - - The \a value_name parameter specifies the value to write to the - configuration space. This can be either a value name or a value - path consisting of a series nested configuration space names - followed by the value name all separated by backslashes or forward - slashes. - - For example: If \a conf is a handle to the configuration space \c - 'A/B/C', then the value name \c 'D/E/v' refers to the value named - \c 'v' in the configuration space \c 'A/B/C/D/E'. - - The specific configuration store that is used to write the value - depends on the flags that were specified in the call to - khc_open_space(). The precedence of configuration stores are as - follows: - - - If KCONF_FLAG_USER was specified, then the user configuration - space. - - - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine - configuration space. - - Note that not specifying any of the configuration store specifiers - in the call to khc_open_space() is equivalent to specifying all - three. Also note that the schema store (KCONF_FLAG_SCHEMA) is - readonly. - - If the \a KCONF_FLAG_WRITEIFMOD flag is specified in the call to - khc_open_space() for obtaining the configuration handle, the - specified string will only be written if it is different from the - value being read from the handle. - - \see khc_open_space() -*/ -KHMEXP khm_int32 KHMAPI -khc_write_int64(khm_handle conf, - const wchar_t * value_name, - khm_int64 buf); - -/*! \brief Write a binary value to a configuration space - - The \a value_name parameter specifies the value to write to the - configuration space. This can be either a value name or a value - path consisting of a series nested configuration space names - followed by the value name all separated by backslashes or forward - slashes. - - For example: If \a conf is a handle to the configuration space \c - 'A/B/C', then the value name \c 'D/E/v' refers to the value named - \c 'v' in the configuration space \c 'A/B/C/D/E'. - - The specific configuration store that is used to write the value - depends on the flags that were specified in the call to - khc_open_space(). The precedence of configuration stores are as - follows: - - - If KCONF_FLAG_USER was specified, then the user configuration - space. - - - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine - configuration space. - - Note that not specifying any of the configuration store specifiers - in the call to khc_open_space() is equivalent to specifying all - three. Also note that the schema store (KCONF_FLAG_SCHEMA) is - readonly. - - \see khc_open_space() -*/ -KHMEXP khm_int32 KHMAPI -khc_write_binary(khm_handle conf, - const wchar_t * value_name, - void * buf, - khm_size bufsize); - -/*! \brief Get the type of a value in a configuration space - - \return The return value is the type of the specified value, or - KC_NONE if the value does not exist. - */ -KHMEXP khm_int32 KHMAPI -khc_get_type(khm_handle conf, const wchar_t * value_name); - -/*! \brief Check which configuration stores contain a specific value. - - Each value in a configuration space can be contained in zero or - more configuration stores. Use this function to determine which - configuration stores contain the specific value. - - The returned bitmask always indicates a subset of the - configuration stores that were specified when opening the - configuration space corresponding to \a conf. - - If the specified handle is shadowed (see khc_shadow_space()) and - the value is not found in any of the visible stores for the - topmost handle, each of the shadowed handles will be tried in turn - until the value is found. The return value will correspond to the - handle where the value is first found. - - \return A combination of ::KCONF_FLAG_MACHINE, ::KCONF_FLAG_USER - and ::KCONF_FLAG_SCHEMA indicating which stores contain the - value. - */ -KHMEXP khm_int32 KHMAPI -khc_value_exists(khm_handle conf, const wchar_t * value); - -/*! \brief Remove a value from a configuration space - - Removes a value from one or more configuration stores. - - A value can exist in multiple configuration stores. Only the - values that are stored in writable stores can be removed. When - the function searches for values to remove, it will only look in - configuration stores that are specified in the handle. In - addition, the configuration stores affected can be further - narrowed by specifying them in the \a flags parameter. If \a - flags is zero, then all the stores visible to the handle are - searched. If \a flags specifies ::KCONF_FLAG_USER or - ::KCONF_FLAG_MACHINE or both, then only the specified stores are - searched, provided that the stores are visible to the handle. - - This function only operates on the topmost configuration space - visible to the handle. If the configuration handle is shadowed, - the shadowed configuration spaces are unaffected by the removal. - - \param[in] conf Handle to configuration space to remove value from - - \param[in] value_name Value to remove - - \param[in] flags Specifies which configuration stores will be - affected by the removal. See above. - - \retval KHM_ERROR_SUCCESS The value was removed from all the - specified configuration stores. - - \retval KHM_ERROR_NOT_FOUND The value was not found. - - \retval KHM_ERROR_UNKNOWN An unknown error occurred while trying - to remove the value. - - \retval KHM_ERROR_PARTIAL The value was successfully removed from - one or more stores, but the operation failed on one or more - other stores. - */ -KHMEXP khm_int32 KHMAPI -khc_remove_value(khm_handle conf, const wchar_t * value_name, khm_int32 flags); - -/*! \brief Get the name of a configuration space - - \param[in] conf Handle to a configuration space - - \param[out] buf The buffer to receive the name. Set to NULL if - only the size of the buffer is required. - - \param[in,out] bufsize On entry, holds the size of the buffer - pointed to by \a buf. On exit, holds the number of bytes - copied into the buffer including the NULL terminator. - */ -KHMEXP khm_int32 KHMAPI -khc_get_config_space_name(khm_handle conf, - wchar_t * buf, - khm_size * bufsize); - -/*! \brief Get a handle to the parent space - - \param[in] conf Handle to a configuration space - - \param[out] parent Handle to the parent configuration space if the - call succeeds. Receives NULL otherwise. The returned handle - must be closed using khc_close_space() - */ -KHMEXP khm_int32 KHMAPI -khc_get_config_space_parent(khm_handle conf, - khm_handle * parent); - -/*! \brief Load a configuration schema into the specified configuration space - - \param[in] conf Handle to a configuration space or NULL to use the - root configuration space. - - \param[in] schema The schema to load. The schema is assumed to be - well formed. - - \see khc_unload_schema() - */ -KHMEXP khm_int32 KHMAPI -khc_load_schema(khm_handle conf, - const kconf_schema * schema); - -/*! \brief Unload a schema from a configuration space - */ -KHMEXP khm_int32 KHMAPI -khc_unload_schema(khm_handle conf, - const kconf_schema * schema); - -/*! \brief Enumerate the subspaces of a configuration space - - Prepares a configuration space for enumeration and returns the - child spaces in no particular order. - - \param[in] conf The configuration space to enumerate child spaces - - \param[in] prev The previous configuration space returned by - khc_enum_subspaces() or NULL if this is the first call. If - this is not NULL, then the handle passed in \a prev will be - freed. - - \param[out] next If \a prev was NULL, receives the first sub space - found in \a conf. You must \b either call - khc_enum_subspaces() again with the returned handle or call - khc_close_space() to free the returned handle if no more - subspaces are required. \a next can point to the same handle - specified in \a prev. - - \retval KHM_ERROR_SUCCESS The call succeeded. There is a valid - handle to a configuration space in \a first_subspace. - - \retval KHM_ERROR_INVALID_PARAM Either \a conf or \a prev was not a - valid configuration space handle or \a first_subspace is NULL. - Note that \a prev can be NULL. - - \retval KHM_ERROR_NOT_FOUND There were no subspaces in the - configuration space pointed to by \a conf. - - \note The configuration spaces that are enumerated directly belong - to the configuration space given by \a conf. This function - does not enumerate subspaces of shadowed configuration spaces - (see khc_shadow_space()). Even if \a conf was obtained on a - restricted domain (i.e. you specified one or more - configuration stores when you openend the handle and didn't - include all the configuration stores. See khc_open_space()), - the subspaces that are returned are the union of all - configuration spaces in all the configuration stores. This is - not a bug. This is a feature. In NetIDMgr, a configuartion - space exists if some configuration store defines it (or it was - created with a call to khc_open_space() even if no - configuration store defines it yet). This is the tradeoff you - make when using a layered configuration system. - - However, the returned handle has the same domain restrictions - as \a conf. - */ -KHMEXP khm_int32 KHMAPI -khc_enum_subspaces(khm_handle conf, - khm_handle prev, - khm_handle * next); - -/*! \brief Remove a configuration space - - The configuration space will be marked for removal. Once all the - handles for the space have been released, it will be deleted. The - configuration stores that will be affected are the write enabled - configuration stores for the handle. - */ -KHMEXP khm_int32 KHMAPI -khc_remove_space(khm_handle conf); -/*@}*/ - -#endif +/* + * 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_KCONFIG_H +#define __KHIMAIRA_KCONFIG_H + +#include +#include + +/*! \defgroup kconf NetIDMgr Configuration Provider */ +/*@{*/ + +/*! \brief Configuration schema descriptor record + + The schema descriptor is a convenient way to provide a default set + of configuration options for a part of an application. It + describes the configuration spaces and the values and subspaces + contained in each space. + + \see kconf_load_schema() +*/ +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. + Names can be upto KCONF_MAXCCH_NAME + characters in length. */ + khm_int32 type; /*!< type of the object. Can be one of + KC_SPACE, KC_ENDSPACE, KC_INT32, + KC_INT64, KC_STRING or KC_BINARY */ + khm_ui_8 value; /*!< the value of the object. It is not + used for KC_SPACE and KC_ENDSPACE + typed objects. For a KC_STRING, this + contains a pointer to the string + value. The string should not be + longer than KCONF_MAXCCH_STRING + characters. KC_INT32 and KC_INT64 + objects store the value directly in + this field, while KC_BINARY objects do + not support defining a default value + here. */ + wchar_t * description;/*!< a friendly description of the value + or configuration space. */ +} kconf_schema; + +/*! \name Configuration data types + @{*/ +/*! \brief Not a known type */ +#define KC_NONE 0 + +/*! \brief When used as ::kconf_schema \a type, defines the start of a configuration space. + + There should be a subsequent KC_ENDSPACE record in the schema + which defines the end of this configuration space. + + \a name specifies the name of the configuration space. Optionally + use \a description to provide a description.*/ +#define KC_SPACE 1 + +/*! \brief Ends a configuration space started with KC_SPACE */ +#define KC_ENDSPACE 2 + +/*! \brief A 32 bit integer + + Specifies a configuration parameter named \a name which is of this + type. Use \a description to provide an optional description of + the value. + + \a value specifies a default value for this parameter in the lower + 32 bits. +*/ +#define KC_INT32 3 + +/*! \brief A 64 bit integer + + Specifies a configuration parameter named \a name which is of this + type. Use \a description to provide an optional description of + the value. + + \a value specifies a default value for this parameter. +*/ +#define KC_INT64 4 + +/*! \brief A unicode string + + Specifies a configuration parameter named \a name which is of this + type. Use \a description to provide an optional description of + the value. + + \a value specifies a default value for this parameter which should + be a pointer to a NULL terminated unicode string of no more than + ::KCONF_MAXCCH_STRING characters. +*/ +#define KC_STRING 5 + +/*! \brief An unparsed binary stream + + Specifies a configuration parameter named \a name which is of this + type. Use \a description to provide an optional description of + the value. + + Default values are not supported for binary streams. \a value is + ignored. +*/ +#define KC_BINARY 6 +/*@}*/ + +/*! \brief This is the root configuration space */ +#define KCONF_FLAG_ROOT 0x00000001 + +/*! \brief Indicates the configuration store which stores user-specific information */ +#define KCONF_FLAG_USER 0x00000002 + +/*! \brief Indicates the configuration store which stores machine-specific information */ +#define KCONF_FLAG_MACHINE 0x00000004 + +/*! \brief Indicates the configuration store which stores the schema */ +#define KCONF_FLAG_SCHEMA 0x00000008 + +/*! \brief Indicates that the last component of the given configuration path is to be considered to be a configuration value */ +#define KCONF_FLAG_TRAILINGVALUE 0x00000020 + +/*! \brief Only write values back there is a change + + Any write operations using the handle with check if the value + being written is different from the value being read from the + handle. It will only be written if the value is different. + + \note Note that the value being read from a handle takes schema and + shadowed configuration handles into consideration while the value + being written is only written to the topmost layer of + configuration that can be written to. + + \note Note also that this flag does not affect binary values. + */ +#define KCONF_FLAG_WRITEIFMOD 0x00000040 + +/*! \brief Use case-insensitive comparison for KCONF_FLAG_WRITEIFMOD + + When used in combination with \a KCONF_FLAG_WRITEIFMOD , the + string comparison used when determining whether the string read + from the configuration handle is the same as the string being + written will be case insensitive. If this flag is not set, the + comparison will be case sensitive. + */ +#define KCONF_FLAG_IFMODCI 0x00000080 + +/*! \brief Do not parse the configuration space name + + If set, disables the parsing of the configuration space for + subspaces. The space name is taken verbatim to be a configuration + space name. This can be used when there can be forward slashes or + backslahes in the name which are not escaped. + + By default, the configuration space name, + + \code + 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. + */ +#define KCONF_FLAG_NOPARSENAME 0x00000040 + +/*! \brief Maximum number of allowed characters (including terminating NULL) in a name + + \note This is a hard limit in Windows, since we are mapping + configuration spaces to registry keys. +*/ +#define KCONF_MAXCCH_NAME 256 + +/*! \brief Maximum number of allowed bytes (including terminating NULL) in a name */ +#define KCONF_MAXCB_NAME (KCONF_MAXCCH_NAME * sizeof(wchar_t)) + +/*! \brief Maximum level of nesting for configuration spaces + */ +#define KCONF_MAX_DEPTH 16 + +/*! \brief Maximum number of allowed characters (including terminating NULL) in a configuration path */ +#define KCONF_MAXCCH_PATH (KCONF_MAXCCH_NAME * KCONF_MAX_DEPTH) + +/*! \brief Maximum number of allowed bytes (including terminating NULL) in a configuration path */ +#define KCONF_MAXCB_PATH (KCONF_MAXCCH_PATH * sizeof(wchar_t)) + +/*! \brief Maximum number of allowed characters (including terminating NULL) in a string */ +#define KCONF_MAXCCH_STRING KHM_MAXCCH_STRING + +/*! \brief Maximum number of allowed bytes (including terminating NULL) in a string */ +#define KCONF_MAXCB_STRING (KCONF_MAXCCH_STRING * sizeof(wchar_t)) + +/*! \brief Open a configuration space + + Opens the configuration space specified by \a cspace. By default, + the opened space includes user,machine and schema configuration + stores. However, you can specify a subset of these. + + If the configuration space does not exist and the \a flags specify + KHM_FLAG_CREATE, then the configuration space is created. The + stores that are affected by the create operation depend on \a + flags. If the \a flags only specifies ::KCONF_FLAG_MACHINE, then + the configuration space is created in the machine store. If \a + flags specifies any combination of stores including \a + ::KCONF_FLAG_USER, then the configuration space is created in the + user store. Note that ::KCONF_FLAG_SCHEMA is readonly. + + Once opened, use khc_close_space() to close the configuration + space. + + \param[in] parent The parent configuration space. The path + specified in \a cspace is relative to the parent. Set this to + NULL to indicate the root configuration space. + + \param[in] cspace The confiuration path. This can be up to + ::KCONF_MAXCCH_PATH characters in length. Use either + backslashes or forward slashes to specify hiearchy. Set this + to NULL to reopen the parent configuration space. + + \param[in] flags Flags. This can be a combination of KCONF_FLAG_* + constants and KHM_FLAG_CREATE. If none of ::KCONF_FLAG_USER, + ::KCONF_FLAG_MACHINE or ::KCONF_FLAG_SCHEMA is specified, then + it defaults to all three. + + \param[out] result Pointer to a handle which receives the handle + to the opened configuration space if the call succeeds. + + \note You can re-open a configuration space with different flags + such as ::KCONF_FLAG_MACHINE by specifying NULL for \a cspace + and settings \a flags to the required flags. + +*/ +KHMEXP khm_int32 KHMAPI +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 + + The handle specified by \a lower becomes a shadow for the handle + specified by \a upper. Any configuration value that is queried in + \a upper that does not exist in \a upper will be queried in \a + lower. + + If \a upper already had a shadow handle, that handle will be + replaced by \a lower. The handle \a lower still needs to be + closed by a call to khc_close_space(). However, closing \a lower + will not affect \a upper which will still treat the configuration + space pointed to by \a lower to be it's shadow. + + Shadows are specific to handles and not configuration spaces. + Shadowing a configuration space using one handle does not affect + any other handles which may be obtained for the same configuration + space. + + Specify NULL for \a lower to remove any prior shadow. + */ +KHMEXP khm_int32 KHMAPI +khc_shadow_space(khm_handle upper, khm_handle lower); + +/*! \brief Close a handle opened with khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_close_space(khm_handle conf); + +/*! \brief Read a string value from a configuration space + + The \a value_name parameter specifies the value to read from the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to access the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + - Otherwise, if KCONF_FLAG_SCHEMA was specified, the the schema + store. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. + + If the value is not found in the configuration space and any + shadowed configuration spaces, the function returns \a + KHM_ERROR_NOT_FOUND. In this case, the buffer is left unmodified. + + \param[in] buf Buffer to copy the string to. Specify NULL to just + retrieve the number of required bytes. + + \param[in,out] bufsize On entry, specifies the number of bytes of + space available at the location specified by \a buf. On exit + specifies the number of bytes actually copied or the size of + the required buffer if \a buf is NULL or insufficient. + + \retval KHM_ERROR_NOT_READY The configuration provider has not started + \retval KHM_ERROR_INVALID_PARAM One or more of the supplied parameters are not valid + \retval KHM_ERROR_TYPE_MISMATCH The specified value is not a string + \retval KHM_ERROR_TOO_LONG \a buf was NULL or the size of the buffer was insufficient. The required size is in bufsize. + \retval KHM_ERROR_SUCCESS Success. The number of bytes copied is in bufsize. + \retval KHM_ERROR_NOT_FOUND The value was not found. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_read_string(khm_handle conf, + const wchar_t * value_name, + wchar_t * buf, + khm_size * bufsize); + +/*! \brief Read a multi-string value from a configuration space + + The \a value_name parameter specifies the value to read from the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to access the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + - Otherwise, if KCONF_FLAG_SCHEMA was specified, the the schema + store. + + A multi-string is a pseudo data type. The value in the + configuration store should contain a CSV string. Each comma + separated value in the CSV string is considered to be a separate + value. Empty values are not allowed. The buffer pointed to by \a + buf will receive these values in the form of a series of NULL + terminated strings terminated by an empty string (or equivalently, + the last string will be terminated by a double NULL). + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. + + If the value is not found in the configuration space and any + shadowed configuration spaces, the function returns \a + KHM_ERROR_NOT_FOUND. In this case, the buffer is left unmodified. + + \param[in] buf Buffer to copy the multi-string to. Specify NULL + to just retrieve the number of required bytes. + + \param[in,out] bufsize On entry, specifies the number of bytes of + space available at the location specified by \a buf. On exit + specifies the number of bytes actually copied or the size of + the required buffer if \a buf is NULL or insufficient. + + \retval KHM_ERROR_NOT_READY The configuration provider has not started + \retval KHM_ERROR_INVALID_PARAM One or more of the supplied parameters are not valid + \retval KHM_ERROR_TYPE_MISMATCH The specified value is not a string + \retval KHM_ERROR_TOO_LONG \a buf was NULL or the size of the buffer was insufficient. The required size is in bufsize. + \retval KHM_ERROR_SUCCESS Success. The number of bytes copied is in bufsize. + \retval KHM_ERROR_NOT_FOUND The value was not found. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_read_multi_string(khm_handle conf, + const wchar_t * value_name, + wchar_t * buf, + khm_size * bufsize); + +/*! \brief Read a 32 bit integer value from a configuration space + + The \a value_name parameter specifies the value to read from the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to access the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + - Otherwise, if KCONF_FLAG_SCHEMA was specified, the the schema + store. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. + + If the value is not found in the configuration space and any + shadowed configuration spaces, the function returns \a + KHM_ERROR_NOT_FOUND. In this case, the buffer is left unmodified. + + \param[in] conf Handle to a configuration space + \param[in] value The value to query + \param[out] buf The buffer to receive the value + + \retval KHM_ERROR_NOT_READY The configuration provider has not started. + \retval KHM_ERROR_SUCCESS Success. The value that was read was placed in \a buf + \retval KHM_ERROR_NOT_FOUND The specified value was not found + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + \retval KHM_ERROR_TYPE_MISMATCH The specified value was found but was not of the correct type. + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_read_int32(khm_handle conf, + const wchar_t * value_name, + khm_int32 * buf); + +/*! \brief Read a 64 bit integer value from a configuration space + + The \a value_name parameter specifies the value to read from the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to access the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + - Otherwise, if KCONF_FLAG_SCHEMA was specified, the the schema + store. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. + + If the value is not found in the configuration space and any + shadowed configuration spaces, the function returns \a + KHM_ERROR_NOT_FOUND. In this case, the buffer is left unmodified. + + \param[in] conf Handle to a configuration space + \param[in] value_name The value to query + \param[out] buf The buffer to receive the value + + \retval KHM_ERROR_NOT_READY The configuration provider has not started + \retval KHM_ERROR_SUCCESS Success. The value that was read was placed in \a buf + \retval KHM_ERROR_NOT_FOUND The specified value was not found + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + \retval KHM_ERROR_TYPE_MISMATCH The specified value was found but was not the correct data type. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_read_int64(khm_handle conf, + const wchar_t * value_name, + khm_int64 * buf); + +/*! \brief Read a binary value from a configuration space + + The \a value_name parameter specifies the value to read from the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to access the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. Also note that the schema store (KCONF_FLAG_SCHEMA) does + not support binary values. + + If the value is not found in the configuration space and any + shadowed configuration spaces, the function returns \a + KHM_ERROR_NOT_FOUND. In this case, the buffer is left unmodified. + + \param[in] buf Buffer to copy the string to. Specify NULL to just + retrieve the number of required bytes. + + \param[in,out] bufsize On entry, specifies the number of bytes of + space available at the location specified by \a buf. On exit + specifies the number of bytes actually copied or the size of + the required buffer if \a buf is NULL or insufficient. + + \retval KHM_ERROR_SUCCESS Success. The data was copied to \a buf. The number of bytes copied is stored in \a bufsize + \retval KHM_ERROR_NOT_FOUND The specified value was not found + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_read_binary(khm_handle conf, + const wchar_t * value_name, + void * buf, + khm_size * bufsize); + +/*! \brief Write a string value to a configuration space + + The \a value_name parameter specifies the value to write to the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to write the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If \a KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if \a KCONF_FLAG_MACHINE was specified, then the + machine configuration space. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. Also note that the schema store (KCONF_FLAG_SCHEMA) is + readonly. + + If the \a KCONF_FLAG_WRITEIFMOD flag is specified in the call to + khc_open_space() for obtaining the configuration handle, the + specified string will only be written if it is different from the + value being read from the handle. + + If the \a KCONF_FLAG_IFMODCI flag is specified along with the \a + KCONF_FLAG_WRITEIFMOD flag, then the string comparison used will + be case insensitive. + + \param[in] conf Handle to a configuration space + \param[in] value_name Name of value to write + \param[in] buf A NULL terminated unicode string not exceeding KCONF_MAXCCH_STRING in characters including terminating NULL + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_write_string(khm_handle conf, + const wchar_t * value_name, + wchar_t * buf); + +/*! \brief Write a multi-string value to a configuration space + + The \a value_name parameter specifies the value to write to the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to write the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + A multi-string is a pseudo data type. The buffer pointed to by \a + buf should contain a sequence of NULL terminated strings + terminated by an empty string (or equivalently, the last string + should terminate with a double NULL). This will be stored in the + value as a CSV string. + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. Also note that the schema store (KCONF_FLAG_SCHEMA) is + readonly. + + If the \a KCONF_FLAG_WRITEIFMOD flag is specified in the call to + khc_open_space() for obtaining the configuration handle, the + specified string will only be written if it is different from the + value being read from the handle. + + If the \a KCONF_FLAG_IFMODCI flag is specified along with the \a + KCONF_FLAG_WRITEIFMOD flag, then the string comparison used will + be case insensitive. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_write_multi_string(khm_handle conf, + const wchar_t * value_name, + wchar_t * buf); + +/*! \brief Write a 32 bit integer value to a configuration space + + The \a value_name parameter specifies the value to write to the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to write the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. Also note that the schema store (KCONF_FLAG_SCHEMA) is + readonly. + + If the \a KCONF_FLAG_WRITEIFMOD flag is specified in the call to + khc_open_space() for obtaining the configuration handle, the + specified string will only be written if it is different from the + value being read from the handle. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_write_int32(khm_handle conf, + const wchar_t * value_name, + khm_int32 buf); + +/*! \brief Write a 64 bit integer value to a configuration space + + The \a value_name parameter specifies the value to write to the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to write the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. Also note that the schema store (KCONF_FLAG_SCHEMA) is + readonly. + + If the \a KCONF_FLAG_WRITEIFMOD flag is specified in the call to + khc_open_space() for obtaining the configuration handle, the + specified string will only be written if it is different from the + value being read from the handle. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_write_int64(khm_handle conf, + const wchar_t * value_name, + khm_int64 buf); + +/*! \brief Write a binary value to a configuration space + + The \a value_name parameter specifies the value to write to the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to write the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. Also note that the schema store (KCONF_FLAG_SCHEMA) is + readonly. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_write_binary(khm_handle conf, + const wchar_t * value_name, + void * buf, + khm_size bufsize); + +/*! \brief Get the type of a value in a configuration space + + \return The return value is the type of the specified value, or + KC_NONE if the value does not exist. + */ +KHMEXP khm_int32 KHMAPI +khc_get_type(khm_handle conf, const wchar_t * value_name); + +/*! \brief Check which configuration stores contain a specific value. + + Each value in a configuration space can be contained in zero or + more configuration stores. Use this function to determine which + configuration stores contain the specific value. + + The returned bitmask always indicates a subset of the + configuration stores that were specified when opening the + configuration space corresponding to \a conf. + + If the specified handle is shadowed (see khc_shadow_space()) and + the value is not found in any of the visible stores for the + topmost handle, each of the shadowed handles will be tried in turn + until the value is found. The return value will correspond to the + handle where the value is first found. + + \return A combination of ::KCONF_FLAG_MACHINE, ::KCONF_FLAG_USER + and ::KCONF_FLAG_SCHEMA indicating which stores contain the + value. + */ +KHMEXP khm_int32 KHMAPI +khc_value_exists(khm_handle conf, const wchar_t * value); + +/*! \brief Remove a value from a configuration space + + Removes a value from one or more configuration stores. + + A value can exist in multiple configuration stores. Only the + values that are stored in writable stores can be removed. When + the function searches for values to remove, it will only look in + configuration stores that are specified in the handle. In + addition, the configuration stores affected can be further + narrowed by specifying them in the \a flags parameter. If \a + flags is zero, then all the stores visible to the handle are + searched. If \a flags specifies ::KCONF_FLAG_USER or + ::KCONF_FLAG_MACHINE or both, then only the specified stores are + searched, provided that the stores are visible to the handle. + + This function only operates on the topmost configuration space + visible to the handle. If the configuration handle is shadowed, + the shadowed configuration spaces are unaffected by the removal. + + \param[in] conf Handle to configuration space to remove value from + + \param[in] value_name Value to remove + + \param[in] flags Specifies which configuration stores will be + affected by the removal. See above. + + \retval KHM_ERROR_SUCCESS The value was removed from all the + specified configuration stores. + + \retval KHM_ERROR_NOT_FOUND The value was not found. + + \retval KHM_ERROR_UNKNOWN An unknown error occurred while trying + to remove the value. + + \retval KHM_ERROR_PARTIAL The value was successfully removed from + one or more stores, but the operation failed on one or more + other stores. + */ +KHMEXP khm_int32 KHMAPI +khc_remove_value(khm_handle conf, const wchar_t * value_name, khm_int32 flags); + +/*! \brief Get the name of a configuration space + + \param[in] conf Handle to a configuration space + + \param[out] buf The buffer to receive the name. Set to NULL if + only the size of the buffer is required. + + \param[in,out] bufsize On entry, holds the size of the buffer + pointed to by \a buf. On exit, holds the number of bytes + copied into the buffer including the NULL terminator. + */ +KHMEXP khm_int32 KHMAPI +khc_get_config_space_name(khm_handle conf, + wchar_t * buf, + khm_size * bufsize); + +/*! \brief Get a handle to the parent space + + \param[in] conf Handle to a configuration space + + \param[out] parent Handle to the parent configuration space if the + call succeeds. Receives NULL otherwise. The returned handle + must be closed using khc_close_space() + */ +KHMEXP khm_int32 KHMAPI +khc_get_config_space_parent(khm_handle conf, + khm_handle * parent); + +/*! \brief Load a configuration schema into the specified configuration space + + \param[in] conf Handle to a configuration space or NULL to use the + root configuration space. + + \param[in] schema The schema to load. The schema is assumed to be + well formed. + + \see khc_unload_schema() + */ +KHMEXP khm_int32 KHMAPI +khc_load_schema(khm_handle conf, + const kconf_schema * schema); + +/*! \brief Unload a schema from a configuration space + */ +KHMEXP khm_int32 KHMAPI +khc_unload_schema(khm_handle conf, + const kconf_schema * schema); + +/*! \brief Enumerate the subspaces of a configuration space + + Prepares a configuration space for enumeration and returns the + child spaces in no particular order. + + \param[in] conf The configuration space to enumerate child spaces + + \param[in] prev The previous configuration space returned by + khc_enum_subspaces() or NULL if this is the first call. If + this is not NULL, then the handle passed in \a prev will be + freed. + + \param[out] next If \a prev was NULL, receives the first sub space + found in \a conf. You must \b either call + khc_enum_subspaces() again with the returned handle or call + khc_close_space() to free the returned handle if no more + subspaces are required. \a next can point to the same handle + specified in \a prev. + + \retval KHM_ERROR_SUCCESS The call succeeded. There is a valid + handle to a configuration space in \a first_subspace. + + \retval KHM_ERROR_INVALID_PARAM Either \a conf or \a prev was not a + valid configuration space handle or \a first_subspace is NULL. + Note that \a prev can be NULL. + + \retval KHM_ERROR_NOT_FOUND There were no subspaces in the + configuration space pointed to by \a conf. + + \note The configuration spaces that are enumerated directly belong + to the configuration space given by \a conf. This function + does not enumerate subspaces of shadowed configuration spaces + (see khc_shadow_space()). Even if \a conf was obtained on a + restricted domain (i.e. you specified one or more + configuration stores when you openend the handle and didn't + include all the configuration stores. See khc_open_space()), + the subspaces that are returned are the union of all + configuration spaces in all the configuration stores. This is + not a bug. This is a feature. In NetIDMgr, a configuartion + space exists if some configuration store defines it (or it was + created with a call to khc_open_space() even if no + configuration store defines it yet). This is the tradeoff you + make when using a layered configuration system. + + However, the returned handle has the same domain restrictions + as \a conf. + */ +KHMEXP khm_int32 KHMAPI +khc_enum_subspaces(khm_handle conf, + khm_handle prev, + khm_handle * next); + +/*! \brief Remove a configuration space + + The configuration space will be marked for removal. Once all the + handles for the space have been released, it will be deleted. The + configuration stores that will be affected are the write enabled + configuration stores for the handle. + */ +KHMEXP khm_int32 KHMAPI +khc_remove_space(khm_handle conf); +/*@}*/ + +#endif diff --git a/src/windows/identity/kconfig/kconfiginternal.h b/src/windows/identity/kconfig/kconfiginternal.h index b4c39ee2d..dc1bfa363 100644 --- a/src/windows/identity/kconfig/kconfiginternal.h +++ b/src/windows/identity/kconfig/kconfiginternal.h @@ -1,129 +1,129 @@ -/* - * 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_KCONFIGINTERNAL_H -#define __KHIMAIRA_KCONFIGINTERNAL_H - -#include -#include -#include -#include -#include -#include - -/* TODO: Implement configuration provider interfaces - -typedef struct kconf_provider_t { - -} kconf_provider; -*/ - -typedef struct kconf_conf_space_t { - wchar_t * name; - - /* kconf_provider * provider; */ - - /* the regpath is the cumulative path starting from a hive root */ - wchar_t * regpath; - HKEY regkey_user; - khm_int32 regkey_user_flags; - HKEY regkey_machine; - khm_int32 regkey_machine_flags; - - khm_int32 refcount; - khm_int32 flags; - - const kconf_schema * schema; - khm_int32 nSchema; - - TDCL(struct kconf_conf_space_t); -} kconf_conf_space; - -#define KCONF_SPACE_FLAG_DELETE_U 0x00000040 -#define KCONF_SPACE_FLAG_DELETE_M 0x00000080 -#define KCONF_SPACE_FLAG_DELETED 0x00000100 - -typedef struct kconf_conf_handle_t { - khm_int32 magic; - khm_int32 flags; - kconf_conf_space * space; - - struct kconf_conf_handle_t * lower; - - LDCL(struct kconf_conf_handle_t); -} kconf_handle; - -#define KCONF_HANDLE_MAGIC 0x38eb49d2 -#define khc_is_handle(h) ((h) && ((kconf_handle *)h)->magic == KCONF_HANDLE_MAGIC) -#define khc_shadow(h) (((kconf_handle *)h)->lower) -#define khc_is_shadowed(h) (khc_is_handle(h) && khc_shadow(h) != NULL) - -extern kconf_conf_space * conf_root; -extern kconf_handle * conf_handles; -extern kconf_handle * conf_free_handles; -extern CRITICAL_SECTION cs_conf_global; -extern LONG conf_init; -extern LONG conf_status; - -#define khc_is_config_running() (conf_init && conf_status) - -#define CONFIG_REGPATHW L"Software\\MIT\\NetIDMgr" - -void init_kconf(void); -void exit_kconf(void); - -/* handle operations */ -#define khc_space_from_handle(h) (((kconf_handle *) h)->space) -#define khc_is_schema_handle(h) (((kconf_handle *) h)->flags & KCONF_FLAG_SCHEMA) -#define khc_is_user_handle(h) (((kconf_handle *) h)->flags & KCONF_FLAG_USER) -#define khc_is_machine_handle(h) (((kconf_handle *) h)->flags & KCONF_FLAG_MACHINE) -#define khc_handle_flags(h) (((kconf_handle *) h)->flags) - -kconf_handle * -khcint_handle_from_space(kconf_conf_space * s, khm_int32 flags); - -void -khcint_handle_free(kconf_handle * h); - -kconf_conf_space * -khcint_create_empty_space(void); - -void -khcint_free_space(kconf_conf_space * r); - -void -khcint_space_hold(kconf_conf_space * s); - -void -khcint_space_release(kconf_conf_space * s); - -HKEY -khcint_space_open_key(kconf_conf_space * s, khm_int32 flags); - -khm_int32 -khcint_remove_space(kconf_conf_space * c, khm_int32 flags); - -#endif +/* + * 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_KCONFIGINTERNAL_H +#define __KHIMAIRA_KCONFIGINTERNAL_H + +#include +#include +#include +#include +#include +#include + +/* TODO: Implement configuration provider interfaces + +typedef struct kconf_provider_t { + +} kconf_provider; +*/ + +typedef struct kconf_conf_space_t { + wchar_t * name; + + /* kconf_provider * provider; */ + + /* the regpath is the cumulative path starting from a hive root */ + wchar_t * regpath; + HKEY regkey_user; + khm_int32 regkey_user_flags; + HKEY regkey_machine; + khm_int32 regkey_machine_flags; + + khm_int32 refcount; + khm_int32 flags; + + const kconf_schema * schema; + khm_int32 nSchema; + + TDCL(struct kconf_conf_space_t); +} kconf_conf_space; + +#define KCONF_SPACE_FLAG_DELETE_U 0x00000040 +#define KCONF_SPACE_FLAG_DELETE_M 0x00000080 +#define KCONF_SPACE_FLAG_DELETED 0x00000100 + +typedef struct kconf_conf_handle_t { + khm_int32 magic; + khm_int32 flags; + kconf_conf_space * space; + + struct kconf_conf_handle_t * lower; + + LDCL(struct kconf_conf_handle_t); +} kconf_handle; + +#define KCONF_HANDLE_MAGIC 0x38eb49d2 +#define khc_is_handle(h) ((h) && ((kconf_handle *)h)->magic == KCONF_HANDLE_MAGIC) +#define khc_shadow(h) (((kconf_handle *)h)->lower) +#define khc_is_shadowed(h) (khc_is_handle(h) && khc_shadow(h) != NULL) + +extern kconf_conf_space * conf_root; +extern kconf_handle * conf_handles; +extern kconf_handle * conf_free_handles; +extern CRITICAL_SECTION cs_conf_global; +extern LONG conf_init; +extern LONG conf_status; + +#define khc_is_config_running() (conf_init && conf_status) + +#define CONFIG_REGPATHW L"Software\\MIT\\NetIDMgr" + +void init_kconf(void); +void exit_kconf(void); + +/* handle operations */ +#define khc_space_from_handle(h) (((kconf_handle *) h)->space) +#define khc_is_schema_handle(h) (((kconf_handle *) h)->flags & KCONF_FLAG_SCHEMA) +#define khc_is_user_handle(h) (((kconf_handle *) h)->flags & KCONF_FLAG_USER) +#define khc_is_machine_handle(h) (((kconf_handle *) h)->flags & KCONF_FLAG_MACHINE) +#define khc_handle_flags(h) (((kconf_handle *) h)->flags) + +kconf_handle * +khcint_handle_from_space(kconf_conf_space * s, khm_int32 flags); + +void +khcint_handle_free(kconf_handle * h); + +kconf_conf_space * +khcint_create_empty_space(void); + +void +khcint_free_space(kconf_conf_space * r); + +void +khcint_space_hold(kconf_conf_space * s); + +void +khcint_space_release(kconf_conf_space * s); + +HKEY +khcint_space_open_key(kconf_conf_space * s, khm_int32 flags); + +khm_int32 +khcint_remove_space(kconf_conf_space * c, khm_int32 flags); + +#endif diff --git a/src/windows/identity/kconfig/kconfigmain.c b/src/windows/identity/kconfig/kconfigmain.c index c49364ab2..bcf14625e 100644 --- a/src/windows/identity/kconfig/kconfigmain.c +++ b/src/windows/identity/kconfig/kconfigmain.c @@ -1,37 +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$ */ - -#include - -void -kconfig_process_attach(void) { - init_kconf(); -} - -void -kconfig_process_detach(void) { - exit_kconf(); -} +/* + * 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 + +void +kconfig_process_attach(void) { + init_kconf(); +} + +void +kconfig_process_detach(void) { + exit_kconf(); +} diff --git a/src/windows/identity/kconfig/registry.c b/src/windows/identity/kconfig/registry.c index 03b49b2c0..d1e4009f2 100644 --- a/src/windows/identity/kconfig/registry.c +++ b/src/windows/identity/kconfig/registry.c @@ -1,28 +1,28 @@ -/* - * 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 - +/* + * 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 + diff --git a/src/windows/identity/kconfig/test/utiltest.c b/src/windows/identity/kconfig/test/utiltest.c index 0652c63b9..f999dfa71 100644 --- a/src/windows/identity/kconfig/test/utiltest.c +++ b/src/windows/identity/kconfig/test/utiltest.c @@ -1,207 +1,207 @@ -#include -#include -#include - -struct string_pair { - wchar_t * ms; - wchar_t * csv; -}; - -struct string_pair strings[] = { - {L"foo\0bar\0baz,quux\0ab\"cd\0", L"foo,bar,\"baz,quux\",\"ab\"\"cd\""}, - {L"a\0b\0c\0d\0e\0", L"a,b,c,d,e"}, - {L"1\0", L"1"}, - {L"\0", L""}, - {L"b\0a\0", L"b,a"}, - {L"c\0a\0b\0", L"c,a,b"}, - {L"c\0a\0B\0", L"c,a,B"}, - {L"sdf\0Bar\0Foo\0BBB\0", L"sdf,Bar,Foo,BBB"} -}; - -int n_strings = ARRAYLENGTH(strings); - -void print_ms(wchar_t * ms) { - wchar_t * s; - size_t cch; - - s = ms; - while(*s) { - printf("%S\\0", s); - StringCchLength(s, 512, &cch); - s += cch + 1; - } -} - -int ms_to_csv_test(void) { - wchar_t wbuf[512]; - int i; - khm_int32 code = 0; - size_t cbbuf; - size_t cbr; - size_t cbnull; - - printf("khc_multi_string_to_csv() test:\n"); - - for(i=0; i"); - code = khc_multi_string_to_csv(NULL, &cbnull, strings[i].ms); - code = khc_multi_string_to_csv(wbuf, &cbbuf, strings[i].ms); - if(code) { - printf(" returned %d\n", code); - return code; - } - printf("CSV[%S]", wbuf); - if(wcscmp(wbuf, strings[i].csv)) { - printf(" MISMATCH!"); - return 1; - } - - StringCbLength(wbuf, sizeof(wbuf), &cbr); - cbr+= sizeof(wchar_t); - - if(cbr != cbbuf) { - printf(" Length mismatch"); - return 1; - } - - if(cbnull != cbr) { - printf(" NULL length mismatch"); - return 1; - } - - printf("\n"); - } - - return code; -} - -int csv_to_ms_test(void) { - wchar_t wbuf[512]; - int i; - khm_int32 code = 0; - size_t cbbuf; - size_t cbr; - size_t cbnull; - - printf("khc_csv_to_multi_string() test:\n"); - - for(i=0; i", strings[i].csv); - code = khc_csv_to_multi_string(NULL, &cbnull, strings[i].csv); - code = khc_csv_to_multi_string(wbuf, &cbbuf, strings[i].csv); - if(code) { - printf(" returned %d\n", code); - return code; - } - printf("MS["); - print_ms(wbuf); - printf("]"); - - if(cbnull != cbbuf) { - printf(" NULL length mismatch"); - return 1; - } - - printf("\n"); - - printf(" Byte length:%d\n", cbbuf); - } - - return code; -} - -int ms_append_test(void) -{ - wchar_t wbuf[512]; - size_t cbbuf; - khm_int32 code; - int i; - - printf("khc_multi_string_append() test:\n"); - - for(i=0; i +#include +#include + +struct string_pair { + wchar_t * ms; + wchar_t * csv; +}; + +struct string_pair strings[] = { + {L"foo\0bar\0baz,quux\0ab\"cd\0", L"foo,bar,\"baz,quux\",\"ab\"\"cd\""}, + {L"a\0b\0c\0d\0e\0", L"a,b,c,d,e"}, + {L"1\0", L"1"}, + {L"\0", L""}, + {L"b\0a\0", L"b,a"}, + {L"c\0a\0b\0", L"c,a,b"}, + {L"c\0a\0B\0", L"c,a,B"}, + {L"sdf\0Bar\0Foo\0BBB\0", L"sdf,Bar,Foo,BBB"} +}; + +int n_strings = ARRAYLENGTH(strings); + +void print_ms(wchar_t * ms) { + wchar_t * s; + size_t cch; + + s = ms; + while(*s) { + printf("%S\\0", s); + StringCchLength(s, 512, &cch); + s += cch + 1; + } +} + +int ms_to_csv_test(void) { + wchar_t wbuf[512]; + int i; + khm_int32 code = 0; + size_t cbbuf; + size_t cbr; + size_t cbnull; + + printf("khc_multi_string_to_csv() test:\n"); + + for(i=0; i"); + code = khc_multi_string_to_csv(NULL, &cbnull, strings[i].ms); + code = khc_multi_string_to_csv(wbuf, &cbbuf, strings[i].ms); + if(code) { + printf(" returned %d\n", code); + return code; + } + printf("CSV[%S]", wbuf); + if(wcscmp(wbuf, strings[i].csv)) { + printf(" MISMATCH!"); + return 1; + } + + StringCbLength(wbuf, sizeof(wbuf), &cbr); + cbr+= sizeof(wchar_t); + + if(cbr != cbbuf) { + printf(" Length mismatch"); + return 1; + } + + if(cbnull != cbr) { + printf(" NULL length mismatch"); + return 1; + } + + printf("\n"); + } + + return code; +} + +int csv_to_ms_test(void) { + wchar_t wbuf[512]; + int i; + khm_int32 code = 0; + size_t cbbuf; + size_t cbr; + size_t cbnull; + + printf("khc_csv_to_multi_string() test:\n"); + + for(i=0; i", strings[i].csv); + code = khc_csv_to_multi_string(NULL, &cbnull, strings[i].csv); + code = khc_csv_to_multi_string(wbuf, &cbbuf, strings[i].csv); + if(code) { + printf(" returned %d\n", code); + return code; + } + printf("MS["); + print_ms(wbuf); + printf("]"); + + if(cbnull != cbbuf) { + printf(" NULL length mismatch"); + return 1; + } + + printf("\n"); + + printf(" Byte length:%d\n", cbbuf); + } + + return code; +} + +int ms_append_test(void) +{ + wchar_t wbuf[512]; + size_t cbbuf; + khm_int32 code; + int i; + + printf("khc_multi_string_append() test:\n"); + + for(i=0; i -#include - -CRITICAL_SECTION cs_attrib; -hashtable * kcdb_attrib_namemap = NULL; -kcdb_attrib_i ** kcdb_attrib_tbl = NULL; -kcdb_attrib_i ** kcdb_property_tbl = NULL; -kcdb_attrib_i * kcdb_attribs = NULL; - -void -kcdb_attrib_add_ref_func(const void * key, void * va) -{ - kcdb_attrib_hold((kcdb_attrib_i *) va); -} - -void -kcdb_attrib_del_ref_func(const void * key, void * va) -{ - kcdb_attrib_release((kcdb_attrib_i *) va); -} - -void -kcdb_attrib_msg_completion(kmq_message * m) -{ - if(m && m->vparam) { - kcdb_attrib_release((kcdb_attrib_i *) m->vparam); - } -} - -khm_int32 -kcdb_attrib_hold(kcdb_attrib_i * ai) -{ - if(!ai) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_attrib); - ai->refcount++; - LeaveCriticalSection(&cs_attrib); - return KHM_ERROR_SUCCESS; -} - -khm_int32 -kcdb_attrib_release(kcdb_attrib_i * ai) -{ - if(!ai) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_attrib); - ai->refcount--; - LeaveCriticalSection(&cs_attrib); - return KHM_ERROR_SUCCESS; -} - -void -kcdb_attrib_post_message(khm_int32 op, kcdb_attrib_i * ai) -{ - kcdb_attrib_hold(ai); - kmq_post_message(KMSG_KCDB, KMSG_KCDB_ATTRIB, op, (void *) ai); -} - -khm_int32 KHMAPI -kcdb_attr_sys_cb(khm_handle vcred, - khm_int32 attr, - void * buf, - khm_size * pcb_buf) -{ - kcdb_cred * c; - - c = (kcdb_cred *) vcred; - - switch(attr) { - case KCDB_ATTR_NAME: - return kcdb_cred_get_name(vcred, buf, pcb_buf); - - case KCDB_ATTR_ID: - if(buf && *pcb_buf >= sizeof(khm_ui_8)) { - *pcb_buf = sizeof(khm_int64); - *((khm_ui_8 *) buf) = (khm_ui_8) c->identity; - return KHM_ERROR_SUCCESS; - } else { - *pcb_buf = sizeof(khm_ui_8); - return KHM_ERROR_TOO_LONG; - } - - case KCDB_ATTR_ID_NAME: - return kcdb_identity_get_name((khm_handle) c->identity, - (wchar_t *) buf, pcb_buf); - - case KCDB_ATTR_TYPE: - if(buf && *pcb_buf >= sizeof(khm_int32)) { - *pcb_buf = sizeof(khm_int32); - *((khm_int32 *) buf) = c->type; - return KHM_ERROR_SUCCESS; - } else { - *pcb_buf = sizeof(khm_int32); - return KHM_ERROR_TOO_LONG; - } - - case KCDB_ATTR_TYPE_NAME: - return kcdb_credtype_describe(c->type, buf, - pcb_buf, KCDB_TS_SHORT); - - case KCDB_ATTR_TIMELEFT: - { - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!buf || *pcb_buf < sizeof(FILETIME)) { - *pcb_buf = sizeof(FILETIME); - rv = KHM_ERROR_TOO_LONG; - } else if(!kcdb_cred_buf_exist(c,KCDB_ATTR_EXPIRE)) { - *pcb_buf = sizeof(FILETIME); - /* setting the timeleft to _I64_MAX has the - interpretation that this credential does not - expire, which is the default behavior if the - expiration time is not known */ - *((FILETIME *) buf) = IntToFt(_I64_MAX); - } else { - FILETIME ftc; - khm_int64 iftc; - - GetSystemTimeAsFileTime(&ftc); - iftc = FtToInt(&ftc); - - *((FILETIME *) buf) = - IntToFt(FtToInt((FILETIME *) - kcdb_cred_buf_get(c,KCDB_ATTR_EXPIRE)) - - iftc); - *pcb_buf = sizeof(FILETIME); - } - - return rv; - } - - case KCDB_ATTR_RENEW_TIMELEFT: - { - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!buf || *pcb_buf < sizeof(FILETIME)) { - *pcb_buf = sizeof(FILETIME); - rv = KHM_ERROR_TOO_LONG; - } else if(!kcdb_cred_buf_exist(c,KCDB_ATTR_RENEW_EXPIRE)) { - *pcb_buf = sizeof(FILETIME); - /* setting the timeleft to _I64_MAX has the - interpretation that this credential does not - expire, which is the default behavior if the - expiration time is not known */ - *((FILETIME *) buf) = IntToFt(_I64_MAX); - } else { - FILETIME ftc; - khm_int64 i_re; - khm_int64 i_ct; - - GetSystemTimeAsFileTime(&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); - } - - return rv; - } - - case KCDB_ATTR_FLAGS: - if(buf && *pcb_buf >= sizeof(khm_int32)) { - *pcb_buf = sizeof(khm_int32); - *((khm_int32 *) buf) = c->flags; - return KHM_ERROR_SUCCESS; - } else { - *pcb_buf = sizeof(khm_int32); - return KHM_ERROR_TOO_LONG; - } - - default: - return KHM_ERROR_NOT_FOUND; - } -} - -void -kcdb_attrib_init(void) -{ - kcdb_attrib attrib; - wchar_t sbuf[256]; - - InitializeCriticalSection(&cs_attrib); - kcdb_attrib_namemap = - hash_new_hashtable(KCDB_ATTRIB_HASH_SIZE, - hash_string, - hash_string_comp, - kcdb_attrib_add_ref_func, - kcdb_attrib_del_ref_func); - - kcdb_attrib_tbl = - PMALLOC(sizeof(kcdb_attrib_i *) * (KCDB_ATTR_MAX_ID + 1)); - assert(kcdb_attrib_tbl != NULL); - ZeroMemory(kcdb_attrib_tbl, - sizeof(kcdb_attrib_i *) * (KCDB_ATTR_MAX_ID + 1)); - - kcdb_property_tbl = - PMALLOC(sizeof(kcdb_attrib_i *) * KCDB_ATTR_MAX_PROPS); - assert(kcdb_property_tbl != NULL); - ZeroMemory(kcdb_property_tbl, - sizeof(kcdb_attrib_i *) * KCDB_ATTR_MAX_PROPS); - - kcdb_attribs = NULL; - - /* register standard attributes */ - - /* Name */ - attrib.id = KCDB_ATTR_NAME; - attrib.name = KCDB_ATTRNAME_NAME; - attrib.type = KCDB_TYPE_STRING; - LoadString(hinst_kcreddb, IDS_NAME, sbuf, ARRAYLENGTH(sbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = NULL; - attrib.flags = - KCDB_ATTR_FLAG_REQUIRED | - KCDB_ATTR_FLAG_COMPUTED | - KCDB_ATTR_FLAG_SYSTEM; - attrib.compute_cb = kcdb_attr_sys_cb; - attrib.compute_min_cbsize = sizeof(wchar_t); - attrib.compute_max_cbsize = KCDB_MAXCB_NAME; - - kcdb_attrib_register(&attrib, NULL); - - /* ID */ - attrib.id = KCDB_ATTR_ID; - attrib.name = KCDB_ATTRNAME_ID; - attrib.type = KCDB_TYPE_INT64; - LoadString(hinst_kcreddb, IDS_IDENTITY, sbuf, ARRAYLENGTH(sbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = NULL; - attrib.flags = - KCDB_ATTR_FLAG_REQUIRED | - KCDB_ATTR_FLAG_COMPUTED | - KCDB_ATTR_FLAG_SYSTEM | - KCDB_ATTR_FLAG_HIDDEN; - attrib.compute_cb = kcdb_attr_sys_cb; - attrib.compute_min_cbsize = sizeof(khm_int32); - attrib.compute_max_cbsize = sizeof(khm_int32); - - kcdb_attrib_register(&attrib, NULL); - - /* ID Name */ - attrib.id = KCDB_ATTR_ID_NAME; - attrib.alt_id = KCDB_ATTR_ID; - attrib.name = KCDB_ATTRNAME_ID_NAME; - attrib.type = KCDB_TYPE_STRING; - LoadString(hinst_kcreddb, IDS_IDENTITY, sbuf, ARRAYLENGTH(sbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = NULL; - attrib.flags = - KCDB_ATTR_FLAG_REQUIRED | - KCDB_ATTR_FLAG_COMPUTED | - KCDB_ATTR_FLAG_ALTVIEW | - KCDB_ATTR_FLAG_SYSTEM; - attrib.compute_cb = kcdb_attr_sys_cb; - attrib.compute_min_cbsize = sizeof(wchar_t); - attrib.compute_max_cbsize = KCDB_IDENT_MAXCB_NAME; - - kcdb_attrib_register(&attrib, NULL); - - /* Type */ - attrib.id = KCDB_ATTR_TYPE; - attrib.name = KCDB_ATTRNAME_TYPE; - attrib.type = KCDB_TYPE_INT32; - LoadString(hinst_kcreddb, IDS_TYPE, sbuf, ARRAYLENGTH(sbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = NULL; - attrib.flags = - KCDB_ATTR_FLAG_REQUIRED | - KCDB_ATTR_FLAG_COMPUTED | - KCDB_ATTR_FLAG_SYSTEM | - KCDB_ATTR_FLAG_HIDDEN; - attrib.compute_cb = kcdb_attr_sys_cb; - attrib.compute_min_cbsize = sizeof(khm_int32); - attrib.compute_max_cbsize = sizeof(khm_int32); - - kcdb_attrib_register(&attrib, NULL); - - /* Type Name */ - attrib.id = KCDB_ATTR_TYPE_NAME; - attrib.alt_id = KCDB_ATTR_TYPE; - attrib.name = KCDB_ATTRNAME_TYPE_NAME; - attrib.type = KCDB_TYPE_STRING; - LoadString(hinst_kcreddb, IDS_TYPE, sbuf, ARRAYLENGTH(sbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = NULL; - attrib.flags = - KCDB_ATTR_FLAG_REQUIRED | - KCDB_ATTR_FLAG_COMPUTED | - KCDB_ATTR_FLAG_ALTVIEW | - KCDB_ATTR_FLAG_SYSTEM; - attrib.compute_cb = kcdb_attr_sys_cb; - attrib.compute_min_cbsize = sizeof(wchar_t); - attrib.compute_max_cbsize = KCDB_MAXCB_NAME; - - kcdb_attrib_register(&attrib, NULL); - - /* Parent Name */ - attrib.id = KCDB_ATTR_PARENT_NAME; - attrib.name = KCDB_ATTRNAME_PARENT_NAME; - attrib.type = KCDB_TYPE_STRING; - LoadString(hinst_kcreddb, IDS_PARENT, sbuf, ARRAYLENGTH(sbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = NULL; - attrib.flags = KCDB_ATTR_FLAG_SYSTEM | KCDB_ATTR_FLAG_HIDDEN; - attrib.compute_cb = NULL; - attrib.compute_min_cbsize = 0; - attrib.compute_max_cbsize = 0; - - kcdb_attrib_register(&attrib, NULL); - - /* Issed On */ - attrib.id = KCDB_ATTR_ISSUE; - attrib.name = KCDB_ATTRNAME_ISSUE; - attrib.type = KCDB_TYPE_DATE; - LoadString(hinst_kcreddb, IDS_ISSUED, sbuf, ARRAYLENGTH(sbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = NULL; - attrib.flags = KCDB_ATTR_FLAG_SYSTEM; - attrib.compute_cb = NULL; - attrib.compute_min_cbsize = 0; - attrib.compute_max_cbsize = 0; - - kcdb_attrib_register(&attrib, NULL); - - /* Expires On */ - attrib.id = KCDB_ATTR_EXPIRE; - attrib.name = KCDB_ATTRNAME_EXPIRE; - attrib.type = KCDB_TYPE_DATE; - LoadString(hinst_kcreddb, IDS_EXPIRES, sbuf, ARRAYLENGTH(sbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = NULL; - attrib.flags = KCDB_ATTR_FLAG_SYSTEM; - attrib.compute_cb = NULL; - attrib.compute_min_cbsize = 0; - attrib.compute_max_cbsize = 0; - - kcdb_attrib_register(&attrib, NULL); - - /* Renewable Time Expires On */ - attrib.id = KCDB_ATTR_RENEW_EXPIRE; - attrib.name = KCDB_ATTRNAME_RENEW_EXPIRE; - attrib.type = KCDB_TYPE_DATE; - LoadString(hinst_kcreddb, IDS_RENEW_EXPIRES, - sbuf, ARRAYLENGTH(sbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = NULL; - attrib.flags = KCDB_ATTR_FLAG_SYSTEM; - attrib.compute_cb = NULL; - attrib.compute_min_cbsize = 0; - attrib.compute_max_cbsize = 0; - - kcdb_attrib_register(&attrib, NULL); - - /* Time Left */ - attrib.id = KCDB_ATTR_TIMELEFT; - attrib.alt_id = KCDB_ATTR_EXPIRE; - attrib.name = KCDB_ATTRNAME_TIMELEFT; - attrib.type = KCDB_TYPE_INTERVAL; - LoadString(hinst_kcreddb, IDS_TIMELEFT, sbuf, ARRAYLENGTH(sbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = NULL; - attrib.flags = KCDB_ATTR_FLAG_SYSTEM | - KCDB_ATTR_FLAG_COMPUTED | - KCDB_ATTR_FLAG_ALTVIEW | - KCDB_ATTR_FLAG_VOLATILE; - attrib.compute_cb = kcdb_attr_sys_cb; - attrib.compute_min_cbsize = sizeof(FILETIME); - attrib.compute_max_cbsize = sizeof(FILETIME); - - kcdb_attrib_register(&attrib, NULL); - - /* Renewable Time Left */ - attrib.id = KCDB_ATTR_RENEW_TIMELEFT; - attrib.alt_id = KCDB_ATTR_RENEW_EXPIRE; - attrib.name = KCDB_ATTRNAME_RENEW_TIMELEFT; - attrib.type = KCDB_TYPE_INTERVAL; - LoadString(hinst_kcreddb, - IDS_RENEW_TIMELEFT, sbuf, ARRAYLENGTH(sbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = NULL; - attrib.flags = KCDB_ATTR_FLAG_SYSTEM | - KCDB_ATTR_FLAG_COMPUTED | - KCDB_ATTR_FLAG_ALTVIEW | - KCDB_ATTR_FLAG_VOLATILE; - attrib.compute_cb = kcdb_attr_sys_cb; - attrib.compute_min_cbsize = sizeof(FILETIME); - attrib.compute_max_cbsize = sizeof(FILETIME); - - kcdb_attrib_register(&attrib, NULL); - - /* Location of Credential */ - attrib.id = KCDB_ATTR_LOCATION; - attrib.name = KCDB_ATTRNAME_LOCATION; - attrib.type = KCDB_TYPE_STRING; - LoadString(hinst_kcreddb, IDS_LOCATION, sbuf, ARRAYLENGTH(sbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = NULL; - attrib.flags = KCDB_ATTR_FLAG_SYSTEM; - attrib.compute_cb = NULL; - attrib.compute_min_cbsize = 0; - attrib.compute_max_cbsize = 0; - - kcdb_attrib_register(&attrib, NULL); - - /* Lifetime */ - attrib.id = KCDB_ATTR_LIFETIME; - attrib.name = KCDB_ATTRNAME_LIFETIME; - attrib.type = KCDB_TYPE_INTERVAL; - LoadString(hinst_kcreddb, IDS_LIFETIME, sbuf, ARRAYLENGTH(sbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = NULL; - attrib.flags = KCDB_ATTR_FLAG_SYSTEM; - attrib.compute_cb = NULL; - attrib.compute_min_cbsize = 0; - attrib.compute_max_cbsize = 0; - - kcdb_attrib_register(&attrib, NULL); - - /* Renewable Lifetime */ - attrib.id = KCDB_ATTR_RENEW_LIFETIME; - attrib.name = KCDB_ATTRNAME_RENEW_LIFETIME; - attrib.type = KCDB_TYPE_INTERVAL; - LoadString(hinst_kcreddb, - IDS_RENEW_LIFETIME, sbuf, ARRAYLENGTH(sbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = NULL; - attrib.flags = KCDB_ATTR_FLAG_SYSTEM; - attrib.compute_cb = NULL; - attrib.compute_min_cbsize = 0; - attrib.compute_max_cbsize = 0; - - kcdb_attrib_register(&attrib, NULL); - - /* Flags */ - attrib.id = KCDB_ATTR_FLAGS; - attrib.name = KCDB_ATTRNAME_FLAGS; - attrib.type = KCDB_TYPE_INT32; - LoadString(hinst_kcreddb, IDS_FLAGS, sbuf, ARRAYLENGTH(sbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = NULL; - attrib.flags = - KCDB_ATTR_FLAG_REQUIRED | - KCDB_ATTR_FLAG_COMPUTED | - KCDB_ATTR_FLAG_SYSTEM | - KCDB_ATTR_FLAG_HIDDEN; - attrib.compute_cb = kcdb_attr_sys_cb; - attrib.compute_min_cbsize = sizeof(khm_int32); - attrib.compute_max_cbsize = sizeof(khm_int32); - - kcdb_attrib_register(&attrib, NULL); -} - -void -kcdb_attrib_exit(void) -{ - DeleteCriticalSection(&cs_attrib); - - if(kcdb_attrib_tbl) - PFREE(kcdb_attrib_tbl); - - if(kcdb_property_tbl) - PFREE(kcdb_property_tbl); -} - -KHMEXP khm_int32 KHMAPI -kcdb_attrib_get_id(const wchar_t *name, khm_int32 * id) -{ - kcdb_attrib_i * ai; - - if(!name) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_attrib); - ai = hash_lookup(kcdb_attrib_namemap, (void *) name); - LeaveCriticalSection(&cs_attrib); - - if(ai) { - *id = ai->attr.id; - return KHM_ERROR_SUCCESS; - } else { - *id = KCDB_ATTR_INVALID; - return KHM_ERROR_NOT_FOUND; - } -} - -KHMEXP khm_int32 KHMAPI -kcdb_attrib_register(const kcdb_attrib * attrib, khm_int32 * new_id) -{ - kcdb_attrib_i * ai; - size_t cb_name; - size_t cb_short_desc; - size_t cb_long_desc; - khm_int32 attr_id; - khm_boolean prop = FALSE; - - if(!attrib || - KHM_FAILED(kcdb_type_get_info(attrib->type, NULL)) || - !attrib->name) - return KHM_ERROR_INVALID_PARAM; - - if(FAILED(StringCbLength(attrib->name, KCDB_MAXCB_NAME, &cb_name))) - return KHM_ERROR_TOO_LONG; - cb_name += sizeof(wchar_t); - - if(attrib->short_desc) { - if(FAILED(StringCbLength(attrib->short_desc, KCDB_MAXCB_SHORT_DESC, &cb_short_desc))) - return KHM_ERROR_TOO_LONG; - cb_short_desc += sizeof(wchar_t); - } else - cb_short_desc = 0; - - if(attrib->long_desc) { - if(FAILED(StringCbLength(attrib->long_desc, KCDB_MAXCB_LONG_DESC, &cb_long_desc))) - return KHM_ERROR_TOO_LONG; - cb_long_desc += sizeof(wchar_t); - } else - cb_long_desc = 0; - - if((attrib->flags & KCDB_ATTR_FLAG_COMPUTED) && - (!attrib->compute_cb || - attrib->compute_min_cbsize <= 0 || - attrib->compute_max_cbsize < attrib->compute_min_cbsize)) - return KHM_ERROR_INVALID_PARAM; - - if ((attrib->flags & KCDB_ATTR_FLAG_ALTVIEW) && - KHM_FAILED(kcdb_attrib_get_info(attrib->alt_id, - NULL))) - return KHM_ERROR_INVALID_PARAM; - - prop = !!(attrib->flags & KCDB_ATTR_FLAG_PROPERTY); - - EnterCriticalSection(&cs_attrib); - - if(!prop && - (attrib->id < 0 || attrib->id > KCDB_ATTR_MAX_ID)) - { - if(KHM_FAILED(kcdb_attrib_next_free_id(&attr_id))) { - LeaveCriticalSection(&cs_attrib); - return KHM_ERROR_NO_RESOURCES; - } - } else if (prop && - (attrib->id < KCDB_ATTR_MIN_PROP_ID || - attrib->id > KCDB_ATTR_MAX_PROP_ID)) { - - if(KHM_FAILED(kcdb_attrib_next_free_prop_id(&attr_id))) { - LeaveCriticalSection(&cs_attrib); - return KHM_ERROR_NO_RESOURCES; - } - - } else { - attr_id = attrib->id; - } - -#ifdef DEBUG - assert(!prop || (attr_id >= KCDB_ATTR_MIN_PROP_ID && attr_id <= KCDB_ATTR_MAX_PROP_ID)); - assert(prop || (attr_id >= 0 && attr_id <= KCDB_ATTR_MAX_ID)); -#endif - - if((!prop && kcdb_attrib_tbl[attr_id]) || - (prop && kcdb_property_tbl[attr_id - KCDB_ATTR_MIN_PROP_ID])) { - - LeaveCriticalSection(&cs_attrib); - return KHM_ERROR_DUPLICATE; - - } - - ai = PMALLOC(sizeof(kcdb_attrib_i)); - ZeroMemory(ai, sizeof(kcdb_attrib_i)); - - ai->attr.type = attrib->type; - ai->attr.id = attr_id; - ai->attr.alt_id = attrib->alt_id; - ai->attr.flags = attrib->flags; - ai->attr.compute_cb = attrib->compute_cb; - ai->attr.compute_max_cbsize = attrib->compute_max_cbsize; - ai->attr.compute_min_cbsize = attrib->compute_min_cbsize; - ai->attr.name = PMALLOC(cb_name); - StringCbCopy(ai->attr.name, cb_name, attrib->name); - if(cb_short_desc) { - ai->attr.short_desc = PMALLOC(cb_short_desc); - StringCbCopy(ai->attr.short_desc, cb_short_desc, attrib->short_desc); - } - if(cb_long_desc) { - ai->attr.long_desc = PMALLOC(cb_long_desc); - StringCbCopy(ai->attr.long_desc, cb_long_desc, attrib->long_desc); - } - - LINIT(ai); - - if(!prop) - kcdb_attrib_tbl[attr_id] = ai; - else - kcdb_property_tbl[attr_id - KCDB_ATTR_MIN_PROP_ID] = ai; - - LPUSH(&kcdb_attribs, ai); - - hash_add(kcdb_attrib_namemap, (void *) ai->attr.name, ai); - - LeaveCriticalSection(&cs_attrib); - - kcdb_attrib_post_message(KCDB_OP_INSERT, ai); - - if(new_id) - *new_id = attr_id; - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI kcdb_attrib_get_info( - khm_int32 id, - kcdb_attrib ** attrib) -{ - kcdb_attrib_i * ai; - khm_boolean prop; - - if(id >= 0 && id <= KCDB_ATTR_MAX_ID) - prop = FALSE; - else if(id >= KCDB_ATTR_MIN_PROP_ID && id <= KCDB_ATTR_MAX_PROP_ID) - prop = TRUE; - else - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_attrib); - if(prop) - ai = kcdb_property_tbl[id - KCDB_ATTR_MIN_PROP_ID]; - else - ai = kcdb_attrib_tbl[id]; - LeaveCriticalSection(&cs_attrib); - - if(ai) { - if(attrib) { - *attrib = &(ai->attr); - kcdb_attrib_hold(ai); - } - return KHM_ERROR_SUCCESS; - } else { - if(attrib) - *attrib = NULL; - return KHM_ERROR_NOT_FOUND; - } -} - -KHMEXP khm_int32 KHMAPI kcdb_attrib_release_info(kcdb_attrib * attrib) -{ - if(attrib) - kcdb_attrib_release((kcdb_attrib_i *) attrib); - return KHM_ERROR_SUCCESS; -} - - -KHMEXP khm_int32 KHMAPI kcdb_attrib_unregister(khm_int32 id) -{ - /*TODO: implement this */ - return KHM_ERROR_NOT_IMPLEMENTED; -} - -KHMEXP khm_int32 KHMAPI kcdb_attrib_describe( - khm_int32 id, - wchar_t * buffer, - khm_size * cbsize, - khm_int32 flags) -{ - kcdb_attrib_i * ai; - size_t cb_size = 0; - khm_boolean prop = FALSE; - - if(!cbsize) - return KHM_ERROR_INVALID_PARAM; - - if(id >= 0 && id <= KCDB_ATTR_MAX_ID) - prop = FALSE; - else if(id >= KCDB_ATTR_MIN_PROP_ID && id <= KCDB_ATTR_MAX_PROP_ID) - prop = TRUE; - else - return KHM_ERROR_INVALID_PARAM; - - if(prop) - ai = kcdb_property_tbl[id - KCDB_ATTR_MIN_PROP_ID]; - else - ai = kcdb_attrib_tbl[id]; - - if(!ai) - return KHM_ERROR_NOT_FOUND; - - if((flags & KCDB_TS_SHORT) && - ai->attr.short_desc) - { - if(FAILED(StringCbLength(ai->attr.short_desc, KCDB_MAXCB_SHORT_DESC, &cb_size))) - return KHM_ERROR_UNKNOWN; - cb_size += sizeof(wchar_t); - - if(!buffer || *cbsize < cb_size) { - *cbsize = cb_size; - return KHM_ERROR_TOO_LONG; - } - - StringCbCopy(buffer, *cbsize, ai->attr.short_desc); - - *cbsize = cb_size; - - return KHM_ERROR_SUCCESS; - } else { - if(FAILED(StringCbLength(ai->attr.long_desc, KCDB_MAXCB_LONG_DESC, &cb_size))) - return KHM_ERROR_UNKNOWN; - cb_size += sizeof(wchar_t); - - if(!buffer || *cbsize < cb_size) { - *cbsize = cb_size; - return KHM_ERROR_TOO_LONG; - } - - StringCbCopy(buffer, *cbsize, ai->attr.long_desc); - - *cbsize = cb_size; - - return KHM_ERROR_SUCCESS; - } -} - -khm_int32 kcdb_attrib_next_free_prop_id(khm_int32 * id) -{ - int i; - - if(!id) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_attrib); - for(i=0;i < KCDB_ATTR_MAX_PROPS; i++) { - if(!kcdb_property_tbl[i]) - break; - } - LeaveCriticalSection(&cs_attrib); - - if(i < KCDB_ATTR_MAX_PROPS) { - *id = i + KCDB_ATTR_MIN_PROP_ID; - return KHM_ERROR_SUCCESS; - } else { - *id = KCDB_ATTR_INVALID; - return KHM_ERROR_NO_RESOURCES; - } -} - -khm_int32 kcdb_attrib_next_free_id(khm_int32 * id) -{ - int i; - - if(!id) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_attrib); - for(i=0;i<= KCDB_ATTR_MAX_ID; i++) { - if(!kcdb_attrib_tbl[i]) - break; - } - LeaveCriticalSection(&cs_attrib); - - if(i <= KCDB_ATTR_MAX_ID) { - *id = i; - return KHM_ERROR_SUCCESS; - } else { - *id = KCDB_ATTR_INVALID; - return KHM_ERROR_NO_RESOURCES; - } -} - -KHMEXP khm_int32 KHMAPI kcdb_attrib_get_count( - khm_int32 and_flags, - khm_int32 eq_flags, - khm_size * pcount) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - khm_size count = 0; - int i; - - if(pcount == NULL) - return KHM_ERROR_INVALID_PARAM; - - eq_flags &= and_flags; - - EnterCriticalSection(&cs_attrib); - for(i = 0; i <= KCDB_ATTR_MAX_ID; i++) { - if(kcdb_attrib_tbl[i] && - (kcdb_attrib_tbl[i]->attr.flags & and_flags) == eq_flags) - count++; - } - - for(i = 0; i < KCDB_ATTR_MAX_PROPS; i++) { - if(kcdb_property_tbl[i] && - (kcdb_property_tbl[i]->attr.flags & and_flags) == eq_flags) - count++; - } - LeaveCriticalSection(&cs_attrib); - - *pcount = count; - - return rv; -} - -KHMEXP khm_int32 KHMAPI kcdb_attrib_get_ids( - khm_int32 and_flags, - khm_int32 eq_flags, - khm_int32 * plist, - khm_size * pcsize) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - khm_size count = 0; - int i; - - if(plist == NULL || pcsize == NULL) - return KHM_ERROR_INVALID_PARAM; - - eq_flags &= and_flags; - - EnterCriticalSection(&cs_attrib); - for(i = 0; i <= KCDB_ATTR_MAX_ID; i++) { - if(kcdb_attrib_tbl[i] && - (kcdb_attrib_tbl[i]->attr.flags & and_flags) == eq_flags) { - if(count >= *pcsize) { - rv = KHM_ERROR_TOO_LONG; - count++; - } else - plist[count++] = i; - } - } - - for(i = 0; i < KCDB_ATTR_MAX_PROPS; i++) { - if(kcdb_property_tbl[i] && - (kcdb_property_tbl[i]->attr.flags & and_flags) == eq_flags) { - if(count >= *pcsize) { - rv = KHM_ERROR_TOO_LONG; - count++; - } else - plist[count++] = i + KCDB_ATTR_MIN_PROP_ID; - } - } - LeaveCriticalSection(&cs_attrib); - - *pcsize = count; - - return rv; -} +/* + * 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 + +CRITICAL_SECTION cs_attrib; +hashtable * kcdb_attrib_namemap = NULL; +kcdb_attrib_i ** kcdb_attrib_tbl = NULL; +kcdb_attrib_i ** kcdb_property_tbl = NULL; +kcdb_attrib_i * kcdb_attribs = NULL; + +void +kcdb_attrib_add_ref_func(const void * key, void * va) +{ + kcdb_attrib_hold((kcdb_attrib_i *) va); +} + +void +kcdb_attrib_del_ref_func(const void * key, void * va) +{ + kcdb_attrib_release((kcdb_attrib_i *) va); +} + +void +kcdb_attrib_msg_completion(kmq_message * m) +{ + if(m && m->vparam) { + kcdb_attrib_release((kcdb_attrib_i *) m->vparam); + } +} + +khm_int32 +kcdb_attrib_hold(kcdb_attrib_i * ai) +{ + if(!ai) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_attrib); + ai->refcount++; + LeaveCriticalSection(&cs_attrib); + return KHM_ERROR_SUCCESS; +} + +khm_int32 +kcdb_attrib_release(kcdb_attrib_i * ai) +{ + if(!ai) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_attrib); + ai->refcount--; + LeaveCriticalSection(&cs_attrib); + return KHM_ERROR_SUCCESS; +} + +void +kcdb_attrib_post_message(khm_int32 op, kcdb_attrib_i * ai) +{ + kcdb_attrib_hold(ai); + kmq_post_message(KMSG_KCDB, KMSG_KCDB_ATTRIB, op, (void *) ai); +} + +khm_int32 KHMAPI +kcdb_attr_sys_cb(khm_handle vcred, + khm_int32 attr, + void * buf, + khm_size * pcb_buf) +{ + kcdb_cred * c; + + c = (kcdb_cred *) vcred; + + switch(attr) { + case KCDB_ATTR_NAME: + return kcdb_cred_get_name(vcred, buf, pcb_buf); + + case KCDB_ATTR_ID: + if(buf && *pcb_buf >= sizeof(khm_ui_8)) { + *pcb_buf = sizeof(khm_int64); + *((khm_ui_8 *) buf) = (khm_ui_8) c->identity; + return KHM_ERROR_SUCCESS; + } else { + *pcb_buf = sizeof(khm_ui_8); + return KHM_ERROR_TOO_LONG; + } + + case KCDB_ATTR_ID_NAME: + return kcdb_identity_get_name((khm_handle) c->identity, + (wchar_t *) buf, pcb_buf); + + case KCDB_ATTR_TYPE: + if(buf && *pcb_buf >= sizeof(khm_int32)) { + *pcb_buf = sizeof(khm_int32); + *((khm_int32 *) buf) = c->type; + return KHM_ERROR_SUCCESS; + } else { + *pcb_buf = sizeof(khm_int32); + return KHM_ERROR_TOO_LONG; + } + + case KCDB_ATTR_TYPE_NAME: + return kcdb_credtype_describe(c->type, buf, + pcb_buf, KCDB_TS_SHORT); + + case KCDB_ATTR_TIMELEFT: + { + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!buf || *pcb_buf < sizeof(FILETIME)) { + *pcb_buf = sizeof(FILETIME); + rv = KHM_ERROR_TOO_LONG; + } else if(!kcdb_cred_buf_exist(c,KCDB_ATTR_EXPIRE)) { + *pcb_buf = sizeof(FILETIME); + /* setting the timeleft to _I64_MAX has the + interpretation that this credential does not + expire, which is the default behavior if the + expiration time is not known */ + *((FILETIME *) buf) = IntToFt(_I64_MAX); + } else { + FILETIME ftc; + khm_int64 iftc; + + GetSystemTimeAsFileTime(&ftc); + iftc = FtToInt(&ftc); + + *((FILETIME *) buf) = + IntToFt(FtToInt((FILETIME *) + kcdb_cred_buf_get(c,KCDB_ATTR_EXPIRE)) + - iftc); + *pcb_buf = sizeof(FILETIME); + } + + return rv; + } + + case KCDB_ATTR_RENEW_TIMELEFT: + { + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!buf || *pcb_buf < sizeof(FILETIME)) { + *pcb_buf = sizeof(FILETIME); + rv = KHM_ERROR_TOO_LONG; + } else if(!kcdb_cred_buf_exist(c,KCDB_ATTR_RENEW_EXPIRE)) { + *pcb_buf = sizeof(FILETIME); + /* setting the timeleft to _I64_MAX has the + interpretation that this credential does not + expire, which is the default behavior if the + expiration time is not known */ + *((FILETIME *) buf) = IntToFt(_I64_MAX); + } else { + FILETIME ftc; + khm_int64 i_re; + khm_int64 i_ct; + + GetSystemTimeAsFileTime(&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); + } + + return rv; + } + + case KCDB_ATTR_FLAGS: + if(buf && *pcb_buf >= sizeof(khm_int32)) { + *pcb_buf = sizeof(khm_int32); + *((khm_int32 *) buf) = c->flags; + return KHM_ERROR_SUCCESS; + } else { + *pcb_buf = sizeof(khm_int32); + return KHM_ERROR_TOO_LONG; + } + + default: + return KHM_ERROR_NOT_FOUND; + } +} + +void +kcdb_attrib_init(void) +{ + kcdb_attrib attrib; + wchar_t sbuf[256]; + + InitializeCriticalSection(&cs_attrib); + kcdb_attrib_namemap = + hash_new_hashtable(KCDB_ATTRIB_HASH_SIZE, + hash_string, + hash_string_comp, + kcdb_attrib_add_ref_func, + kcdb_attrib_del_ref_func); + + kcdb_attrib_tbl = + PMALLOC(sizeof(kcdb_attrib_i *) * (KCDB_ATTR_MAX_ID + 1)); + assert(kcdb_attrib_tbl != NULL); + ZeroMemory(kcdb_attrib_tbl, + sizeof(kcdb_attrib_i *) * (KCDB_ATTR_MAX_ID + 1)); + + kcdb_property_tbl = + PMALLOC(sizeof(kcdb_attrib_i *) * KCDB_ATTR_MAX_PROPS); + assert(kcdb_property_tbl != NULL); + ZeroMemory(kcdb_property_tbl, + sizeof(kcdb_attrib_i *) * KCDB_ATTR_MAX_PROPS); + + kcdb_attribs = NULL; + + /* register standard attributes */ + + /* Name */ + attrib.id = KCDB_ATTR_NAME; + attrib.name = KCDB_ATTRNAME_NAME; + attrib.type = KCDB_TYPE_STRING; + LoadString(hinst_kcreddb, IDS_NAME, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = + KCDB_ATTR_FLAG_REQUIRED | + KCDB_ATTR_FLAG_COMPUTED | + KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = kcdb_attr_sys_cb; + attrib.compute_min_cbsize = sizeof(wchar_t); + attrib.compute_max_cbsize = KCDB_MAXCB_NAME; + + kcdb_attrib_register(&attrib, NULL); + + /* ID */ + attrib.id = KCDB_ATTR_ID; + attrib.name = KCDB_ATTRNAME_ID; + attrib.type = KCDB_TYPE_INT64; + LoadString(hinst_kcreddb, IDS_IDENTITY, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = + KCDB_ATTR_FLAG_REQUIRED | + KCDB_ATTR_FLAG_COMPUTED | + KCDB_ATTR_FLAG_SYSTEM | + KCDB_ATTR_FLAG_HIDDEN; + attrib.compute_cb = kcdb_attr_sys_cb; + attrib.compute_min_cbsize = sizeof(khm_int32); + attrib.compute_max_cbsize = sizeof(khm_int32); + + kcdb_attrib_register(&attrib, NULL); + + /* ID Name */ + attrib.id = KCDB_ATTR_ID_NAME; + attrib.alt_id = KCDB_ATTR_ID; + attrib.name = KCDB_ATTRNAME_ID_NAME; + attrib.type = KCDB_TYPE_STRING; + LoadString(hinst_kcreddb, IDS_IDENTITY, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = + KCDB_ATTR_FLAG_REQUIRED | + KCDB_ATTR_FLAG_COMPUTED | + KCDB_ATTR_FLAG_ALTVIEW | + KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = kcdb_attr_sys_cb; + attrib.compute_min_cbsize = sizeof(wchar_t); + attrib.compute_max_cbsize = KCDB_IDENT_MAXCB_NAME; + + kcdb_attrib_register(&attrib, NULL); + + /* Type */ + attrib.id = KCDB_ATTR_TYPE; + attrib.name = KCDB_ATTRNAME_TYPE; + attrib.type = KCDB_TYPE_INT32; + LoadString(hinst_kcreddb, IDS_TYPE, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = + KCDB_ATTR_FLAG_REQUIRED | + KCDB_ATTR_FLAG_COMPUTED | + KCDB_ATTR_FLAG_SYSTEM | + KCDB_ATTR_FLAG_HIDDEN; + attrib.compute_cb = kcdb_attr_sys_cb; + attrib.compute_min_cbsize = sizeof(khm_int32); + attrib.compute_max_cbsize = sizeof(khm_int32); + + kcdb_attrib_register(&attrib, NULL); + + /* Type Name */ + attrib.id = KCDB_ATTR_TYPE_NAME; + attrib.alt_id = KCDB_ATTR_TYPE; + attrib.name = KCDB_ATTRNAME_TYPE_NAME; + attrib.type = KCDB_TYPE_STRING; + LoadString(hinst_kcreddb, IDS_TYPE, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = + KCDB_ATTR_FLAG_REQUIRED | + KCDB_ATTR_FLAG_COMPUTED | + KCDB_ATTR_FLAG_ALTVIEW | + KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = kcdb_attr_sys_cb; + attrib.compute_min_cbsize = sizeof(wchar_t); + attrib.compute_max_cbsize = KCDB_MAXCB_NAME; + + kcdb_attrib_register(&attrib, NULL); + + /* Parent Name */ + attrib.id = KCDB_ATTR_PARENT_NAME; + attrib.name = KCDB_ATTRNAME_PARENT_NAME; + attrib.type = KCDB_TYPE_STRING; + LoadString(hinst_kcreddb, IDS_PARENT, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM | KCDB_ATTR_FLAG_HIDDEN; + attrib.compute_cb = NULL; + attrib.compute_min_cbsize = 0; + attrib.compute_max_cbsize = 0; + + kcdb_attrib_register(&attrib, NULL); + + /* Issed On */ + attrib.id = KCDB_ATTR_ISSUE; + attrib.name = KCDB_ATTRNAME_ISSUE; + attrib.type = KCDB_TYPE_DATE; + LoadString(hinst_kcreddb, IDS_ISSUED, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = NULL; + attrib.compute_min_cbsize = 0; + attrib.compute_max_cbsize = 0; + + kcdb_attrib_register(&attrib, NULL); + + /* Expires On */ + attrib.id = KCDB_ATTR_EXPIRE; + attrib.name = KCDB_ATTRNAME_EXPIRE; + attrib.type = KCDB_TYPE_DATE; + LoadString(hinst_kcreddb, IDS_EXPIRES, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = NULL; + attrib.compute_min_cbsize = 0; + attrib.compute_max_cbsize = 0; + + kcdb_attrib_register(&attrib, NULL); + + /* Renewable Time Expires On */ + attrib.id = KCDB_ATTR_RENEW_EXPIRE; + attrib.name = KCDB_ATTRNAME_RENEW_EXPIRE; + attrib.type = KCDB_TYPE_DATE; + LoadString(hinst_kcreddb, IDS_RENEW_EXPIRES, + sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = NULL; + attrib.compute_min_cbsize = 0; + attrib.compute_max_cbsize = 0; + + kcdb_attrib_register(&attrib, NULL); + + /* Time Left */ + attrib.id = KCDB_ATTR_TIMELEFT; + attrib.alt_id = KCDB_ATTR_EXPIRE; + attrib.name = KCDB_ATTRNAME_TIMELEFT; + attrib.type = KCDB_TYPE_INTERVAL; + LoadString(hinst_kcreddb, IDS_TIMELEFT, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM | + KCDB_ATTR_FLAG_COMPUTED | + KCDB_ATTR_FLAG_ALTVIEW | + KCDB_ATTR_FLAG_VOLATILE; + attrib.compute_cb = kcdb_attr_sys_cb; + attrib.compute_min_cbsize = sizeof(FILETIME); + attrib.compute_max_cbsize = sizeof(FILETIME); + + kcdb_attrib_register(&attrib, NULL); + + /* Renewable Time Left */ + attrib.id = KCDB_ATTR_RENEW_TIMELEFT; + attrib.alt_id = KCDB_ATTR_RENEW_EXPIRE; + attrib.name = KCDB_ATTRNAME_RENEW_TIMELEFT; + attrib.type = KCDB_TYPE_INTERVAL; + LoadString(hinst_kcreddb, + IDS_RENEW_TIMELEFT, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM | + KCDB_ATTR_FLAG_COMPUTED | + KCDB_ATTR_FLAG_ALTVIEW | + KCDB_ATTR_FLAG_VOLATILE; + attrib.compute_cb = kcdb_attr_sys_cb; + attrib.compute_min_cbsize = sizeof(FILETIME); + attrib.compute_max_cbsize = sizeof(FILETIME); + + kcdb_attrib_register(&attrib, NULL); + + /* Location of Credential */ + attrib.id = KCDB_ATTR_LOCATION; + attrib.name = KCDB_ATTRNAME_LOCATION; + attrib.type = KCDB_TYPE_STRING; + LoadString(hinst_kcreddb, IDS_LOCATION, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = NULL; + attrib.compute_min_cbsize = 0; + attrib.compute_max_cbsize = 0; + + kcdb_attrib_register(&attrib, NULL); + + /* Lifetime */ + attrib.id = KCDB_ATTR_LIFETIME; + attrib.name = KCDB_ATTRNAME_LIFETIME; + attrib.type = KCDB_TYPE_INTERVAL; + LoadString(hinst_kcreddb, IDS_LIFETIME, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = NULL; + attrib.compute_min_cbsize = 0; + attrib.compute_max_cbsize = 0; + + kcdb_attrib_register(&attrib, NULL); + + /* Renewable Lifetime */ + attrib.id = KCDB_ATTR_RENEW_LIFETIME; + attrib.name = KCDB_ATTRNAME_RENEW_LIFETIME; + attrib.type = KCDB_TYPE_INTERVAL; + LoadString(hinst_kcreddb, + IDS_RENEW_LIFETIME, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = NULL; + attrib.compute_min_cbsize = 0; + attrib.compute_max_cbsize = 0; + + kcdb_attrib_register(&attrib, NULL); + + /* Flags */ + attrib.id = KCDB_ATTR_FLAGS; + attrib.name = KCDB_ATTRNAME_FLAGS; + attrib.type = KCDB_TYPE_INT32; + LoadString(hinst_kcreddb, IDS_FLAGS, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = + KCDB_ATTR_FLAG_REQUIRED | + KCDB_ATTR_FLAG_COMPUTED | + KCDB_ATTR_FLAG_SYSTEM | + KCDB_ATTR_FLAG_HIDDEN; + attrib.compute_cb = kcdb_attr_sys_cb; + attrib.compute_min_cbsize = sizeof(khm_int32); + attrib.compute_max_cbsize = sizeof(khm_int32); + + kcdb_attrib_register(&attrib, NULL); +} + +void +kcdb_attrib_exit(void) +{ + DeleteCriticalSection(&cs_attrib); + + if(kcdb_attrib_tbl) + PFREE(kcdb_attrib_tbl); + + if(kcdb_property_tbl) + PFREE(kcdb_property_tbl); +} + +KHMEXP khm_int32 KHMAPI +kcdb_attrib_get_id(const wchar_t *name, khm_int32 * id) +{ + kcdb_attrib_i * ai; + + if(!name) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_attrib); + ai = hash_lookup(kcdb_attrib_namemap, (void *) name); + LeaveCriticalSection(&cs_attrib); + + if(ai) { + *id = ai->attr.id; + return KHM_ERROR_SUCCESS; + } else { + *id = KCDB_ATTR_INVALID; + return KHM_ERROR_NOT_FOUND; + } +} + +KHMEXP khm_int32 KHMAPI +kcdb_attrib_register(const kcdb_attrib * attrib, khm_int32 * new_id) +{ + kcdb_attrib_i * ai; + size_t cb_name; + size_t cb_short_desc; + size_t cb_long_desc; + khm_int32 attr_id; + khm_boolean prop = FALSE; + + if(!attrib || + KHM_FAILED(kcdb_type_get_info(attrib->type, NULL)) || + !attrib->name) + return KHM_ERROR_INVALID_PARAM; + + if(FAILED(StringCbLength(attrib->name, KCDB_MAXCB_NAME, &cb_name))) + return KHM_ERROR_TOO_LONG; + cb_name += sizeof(wchar_t); + + if(attrib->short_desc) { + if(FAILED(StringCbLength(attrib->short_desc, KCDB_MAXCB_SHORT_DESC, &cb_short_desc))) + return KHM_ERROR_TOO_LONG; + cb_short_desc += sizeof(wchar_t); + } else + cb_short_desc = 0; + + if(attrib->long_desc) { + if(FAILED(StringCbLength(attrib->long_desc, KCDB_MAXCB_LONG_DESC, &cb_long_desc))) + return KHM_ERROR_TOO_LONG; + cb_long_desc += sizeof(wchar_t); + } else + cb_long_desc = 0; + + if((attrib->flags & KCDB_ATTR_FLAG_COMPUTED) && + (!attrib->compute_cb || + attrib->compute_min_cbsize <= 0 || + attrib->compute_max_cbsize < attrib->compute_min_cbsize)) + return KHM_ERROR_INVALID_PARAM; + + if ((attrib->flags & KCDB_ATTR_FLAG_ALTVIEW) && + KHM_FAILED(kcdb_attrib_get_info(attrib->alt_id, + NULL))) + return KHM_ERROR_INVALID_PARAM; + + prop = !!(attrib->flags & KCDB_ATTR_FLAG_PROPERTY); + + EnterCriticalSection(&cs_attrib); + + if(!prop && + (attrib->id < 0 || attrib->id > KCDB_ATTR_MAX_ID)) + { + if(KHM_FAILED(kcdb_attrib_next_free_id(&attr_id))) { + LeaveCriticalSection(&cs_attrib); + return KHM_ERROR_NO_RESOURCES; + } + } else if (prop && + (attrib->id < KCDB_ATTR_MIN_PROP_ID || + attrib->id > KCDB_ATTR_MAX_PROP_ID)) { + + if(KHM_FAILED(kcdb_attrib_next_free_prop_id(&attr_id))) { + LeaveCriticalSection(&cs_attrib); + return KHM_ERROR_NO_RESOURCES; + } + + } else { + attr_id = attrib->id; + } + +#ifdef DEBUG + assert(!prop || (attr_id >= KCDB_ATTR_MIN_PROP_ID && attr_id <= KCDB_ATTR_MAX_PROP_ID)); + assert(prop || (attr_id >= 0 && attr_id <= KCDB_ATTR_MAX_ID)); +#endif + + if((!prop && kcdb_attrib_tbl[attr_id]) || + (prop && kcdb_property_tbl[attr_id - KCDB_ATTR_MIN_PROP_ID])) { + + LeaveCriticalSection(&cs_attrib); + return KHM_ERROR_DUPLICATE; + + } + + ai = PMALLOC(sizeof(kcdb_attrib_i)); + ZeroMemory(ai, sizeof(kcdb_attrib_i)); + + ai->attr.type = attrib->type; + ai->attr.id = attr_id; + ai->attr.alt_id = attrib->alt_id; + ai->attr.flags = attrib->flags; + ai->attr.compute_cb = attrib->compute_cb; + ai->attr.compute_max_cbsize = attrib->compute_max_cbsize; + ai->attr.compute_min_cbsize = attrib->compute_min_cbsize; + ai->attr.name = PMALLOC(cb_name); + StringCbCopy(ai->attr.name, cb_name, attrib->name); + if(cb_short_desc) { + ai->attr.short_desc = PMALLOC(cb_short_desc); + StringCbCopy(ai->attr.short_desc, cb_short_desc, attrib->short_desc); + } + if(cb_long_desc) { + ai->attr.long_desc = PMALLOC(cb_long_desc); + StringCbCopy(ai->attr.long_desc, cb_long_desc, attrib->long_desc); + } + + LINIT(ai); + + if(!prop) + kcdb_attrib_tbl[attr_id] = ai; + else + kcdb_property_tbl[attr_id - KCDB_ATTR_MIN_PROP_ID] = ai; + + LPUSH(&kcdb_attribs, ai); + + hash_add(kcdb_attrib_namemap, (void *) ai->attr.name, ai); + + LeaveCriticalSection(&cs_attrib); + + kcdb_attrib_post_message(KCDB_OP_INSERT, ai); + + if(new_id) + *new_id = attr_id; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_attrib_get_info( + khm_int32 id, + kcdb_attrib ** attrib) +{ + kcdb_attrib_i * ai; + khm_boolean prop; + + if(id >= 0 && id <= KCDB_ATTR_MAX_ID) + prop = FALSE; + else if(id >= KCDB_ATTR_MIN_PROP_ID && id <= KCDB_ATTR_MAX_PROP_ID) + prop = TRUE; + else + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_attrib); + if(prop) + ai = kcdb_property_tbl[id - KCDB_ATTR_MIN_PROP_ID]; + else + ai = kcdb_attrib_tbl[id]; + LeaveCriticalSection(&cs_attrib); + + if(ai) { + if(attrib) { + *attrib = &(ai->attr); + kcdb_attrib_hold(ai); + } + return KHM_ERROR_SUCCESS; + } else { + if(attrib) + *attrib = NULL; + return KHM_ERROR_NOT_FOUND; + } +} + +KHMEXP khm_int32 KHMAPI kcdb_attrib_release_info(kcdb_attrib * attrib) +{ + if(attrib) + kcdb_attrib_release((kcdb_attrib_i *) attrib); + return KHM_ERROR_SUCCESS; +} + + +KHMEXP khm_int32 KHMAPI kcdb_attrib_unregister(khm_int32 id) +{ + /*TODO: implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} + +KHMEXP khm_int32 KHMAPI kcdb_attrib_describe( + khm_int32 id, + wchar_t * buffer, + khm_size * cbsize, + khm_int32 flags) +{ + kcdb_attrib_i * ai; + size_t cb_size = 0; + khm_boolean prop = FALSE; + + if(!cbsize) + return KHM_ERROR_INVALID_PARAM; + + if(id >= 0 && id <= KCDB_ATTR_MAX_ID) + prop = FALSE; + else if(id >= KCDB_ATTR_MIN_PROP_ID && id <= KCDB_ATTR_MAX_PROP_ID) + prop = TRUE; + else + return KHM_ERROR_INVALID_PARAM; + + if(prop) + ai = kcdb_property_tbl[id - KCDB_ATTR_MIN_PROP_ID]; + else + ai = kcdb_attrib_tbl[id]; + + if(!ai) + return KHM_ERROR_NOT_FOUND; + + if((flags & KCDB_TS_SHORT) && + ai->attr.short_desc) + { + if(FAILED(StringCbLength(ai->attr.short_desc, KCDB_MAXCB_SHORT_DESC, &cb_size))) + return KHM_ERROR_UNKNOWN; + cb_size += sizeof(wchar_t); + + if(!buffer || *cbsize < cb_size) { + *cbsize = cb_size; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buffer, *cbsize, ai->attr.short_desc); + + *cbsize = cb_size; + + return KHM_ERROR_SUCCESS; + } else { + if(FAILED(StringCbLength(ai->attr.long_desc, KCDB_MAXCB_LONG_DESC, &cb_size))) + return KHM_ERROR_UNKNOWN; + cb_size += sizeof(wchar_t); + + if(!buffer || *cbsize < cb_size) { + *cbsize = cb_size; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buffer, *cbsize, ai->attr.long_desc); + + *cbsize = cb_size; + + return KHM_ERROR_SUCCESS; + } +} + +khm_int32 kcdb_attrib_next_free_prop_id(khm_int32 * id) +{ + int i; + + if(!id) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_attrib); + for(i=0;i < KCDB_ATTR_MAX_PROPS; i++) { + if(!kcdb_property_tbl[i]) + break; + } + LeaveCriticalSection(&cs_attrib); + + if(i < KCDB_ATTR_MAX_PROPS) { + *id = i + KCDB_ATTR_MIN_PROP_ID; + return KHM_ERROR_SUCCESS; + } else { + *id = KCDB_ATTR_INVALID; + return KHM_ERROR_NO_RESOURCES; + } +} + +khm_int32 kcdb_attrib_next_free_id(khm_int32 * id) +{ + int i; + + if(!id) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_attrib); + for(i=0;i<= KCDB_ATTR_MAX_ID; i++) { + if(!kcdb_attrib_tbl[i]) + break; + } + LeaveCriticalSection(&cs_attrib); + + if(i <= KCDB_ATTR_MAX_ID) { + *id = i; + return KHM_ERROR_SUCCESS; + } else { + *id = KCDB_ATTR_INVALID; + return KHM_ERROR_NO_RESOURCES; + } +} + +KHMEXP khm_int32 KHMAPI kcdb_attrib_get_count( + khm_int32 and_flags, + khm_int32 eq_flags, + khm_size * pcount) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_size count = 0; + int i; + + if(pcount == NULL) + return KHM_ERROR_INVALID_PARAM; + + eq_flags &= and_flags; + + EnterCriticalSection(&cs_attrib); + for(i = 0; i <= KCDB_ATTR_MAX_ID; i++) { + if(kcdb_attrib_tbl[i] && + (kcdb_attrib_tbl[i]->attr.flags & and_flags) == eq_flags) + count++; + } + + for(i = 0; i < KCDB_ATTR_MAX_PROPS; i++) { + if(kcdb_property_tbl[i] && + (kcdb_property_tbl[i]->attr.flags & and_flags) == eq_flags) + count++; + } + LeaveCriticalSection(&cs_attrib); + + *pcount = count; + + return rv; +} + +KHMEXP khm_int32 KHMAPI kcdb_attrib_get_ids( + khm_int32 and_flags, + khm_int32 eq_flags, + khm_int32 * plist, + khm_size * pcsize) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_size count = 0; + int i; + + if(plist == NULL || pcsize == NULL) + return KHM_ERROR_INVALID_PARAM; + + eq_flags &= and_flags; + + EnterCriticalSection(&cs_attrib); + for(i = 0; i <= KCDB_ATTR_MAX_ID; i++) { + if(kcdb_attrib_tbl[i] && + (kcdb_attrib_tbl[i]->attr.flags & and_flags) == eq_flags) { + if(count >= *pcsize) { + rv = KHM_ERROR_TOO_LONG; + count++; + } else + plist[count++] = i; + } + } + + for(i = 0; i < KCDB_ATTR_MAX_PROPS; i++) { + if(kcdb_property_tbl[i] && + (kcdb_property_tbl[i]->attr.flags & and_flags) == eq_flags) { + if(count >= *pcsize) { + rv = KHM_ERROR_TOO_LONG; + count++; + } else + plist[count++] = i + KCDB_ATTR_MIN_PROP_ID; + } + } + LeaveCriticalSection(&cs_attrib); + + *pcsize = count; + + return rv; +} diff --git a/src/windows/identity/kcreddb/attrib.h b/src/windows/identity/kcreddb/attrib.h index f5647d67a..2f0cc0f8e 100644 --- a/src/windows/identity/kcreddb/attrib.h +++ b/src/windows/identity/kcreddb/attrib.h @@ -1,55 +1,55 @@ -/* - * 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_KCDB_ATTRIB_H -#define __KHIMAIRA_KCDB_ATTRIB_H - -/* Attributes */ - -typedef struct kcdb_attrib_i_t { - kcdb_attrib attr; - - khm_int32 refcount; - - struct kcdb_attrib_i_t * next; - struct kcdb_attrib_i_t * prev; -} kcdb_attrib_i; - -#define KCDB_ATTRIB_HASH_SIZE 31 - -void kcdb_attrib_init(void); -void kcdb_attrib_exit(void); -void kcdb_attrib_add_ref_func(const void * key, void * va); -void kcdb_attrib_del_ref_func(const void * key, void * va); -void kcdb_attrib_msg_completion(kmq_message * m); -khm_int32 kcdb_attrib_next_free_prop_id(khm_int32 * id); -khm_int32 kcdb_attrib_next_free_id(khm_int32 * id); -khm_int32 kcdb_attrib_hold(kcdb_attrib_i * ai); -khm_int32 kcdb_attrib_release(kcdb_attrib_i * ai); -void kcdb_attrib_post_message(khm_int32 op, kcdb_attrib_i * ai); -khm_int32 KHMAPI kcdb_attr_sys_cb(khm_handle cred, khm_int32 attr, void * buf, khm_size * pcb_buf); - -#endif +/* + * 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_KCDB_ATTRIB_H +#define __KHIMAIRA_KCDB_ATTRIB_H + +/* Attributes */ + +typedef struct kcdb_attrib_i_t { + kcdb_attrib attr; + + khm_int32 refcount; + + struct kcdb_attrib_i_t * next; + struct kcdb_attrib_i_t * prev; +} kcdb_attrib_i; + +#define KCDB_ATTRIB_HASH_SIZE 31 + +void kcdb_attrib_init(void); +void kcdb_attrib_exit(void); +void kcdb_attrib_add_ref_func(const void * key, void * va); +void kcdb_attrib_del_ref_func(const void * key, void * va); +void kcdb_attrib_msg_completion(kmq_message * m); +khm_int32 kcdb_attrib_next_free_prop_id(khm_int32 * id); +khm_int32 kcdb_attrib_next_free_id(khm_int32 * id); +khm_int32 kcdb_attrib_hold(kcdb_attrib_i * ai); +khm_int32 kcdb_attrib_release(kcdb_attrib_i * ai); +void kcdb_attrib_post_message(khm_int32 op, kcdb_attrib_i * ai); +khm_int32 KHMAPI kcdb_attr_sys_cb(khm_handle cred, khm_int32 attr, void * buf, khm_size * pcb_buf); + +#endif diff --git a/src/windows/identity/kcreddb/buf.c b/src/windows/identity/kcreddb/buf.c index 6272924e5..521baeb97 100644 --- a/src/windows/identity/kcreddb/buf.c +++ b/src/windows/identity/kcreddb/buf.c @@ -1,391 +1,391 @@ -/* - * 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 - -void kcdb_buf_new(kcdb_buf * buf, khm_size n_fields) -{ - buf->buffer = PMALLOC(KCDB_BUF_CBBUF_INITIAL); - buf->cb_buffer = KCDB_BUF_CBBUF_INITIAL; - buf->cb_used = 0; - - if(n_fields == KCDB_BUF_DEFAULT) - n_fields = KCDB_BUF_FIELDS_INITIAL; - - assert(n_fields < KCDB_BUF_MAX_SLOTS); - - buf->n_fields = n_fields; - buf->nc_fields = UBOUNDSS(n_fields, KCDB_BUF_FIELDS_INITIAL, KCDB_BUF_FIELDS_GROWTH); - buf->fields = PMALLOC(sizeof(buf->fields[0]) * buf->n_fields); - ZeroMemory(buf->fields, sizeof(buf->fields[0]) * buf->n_fields); -} - -void kcdb_buf_delete(kcdb_buf * buf) -{ - buf->cb_buffer = 0; - buf->cb_used = 0; - if(buf->buffer) - PFREE(buf->buffer); - buf->buffer = NULL; - - buf->n_fields = 0; - buf->nc_fields = 0; - if(buf->fields) - PFREE(buf->fields); - buf->fields = NULL; -} - -static void kcdb_buf_assert_size(kcdb_buf * buf, khm_size cbsize) -{ - khm_size new_size; - void * new_buf; - - /* should be less than or equal to the max signed 32 bit int */ - assert(cbsize <= KHM_INT32_MAX); - if(cbsize <= buf->cb_buffer) - return; - - new_size = UBOUNDSS(cbsize, KCDB_BUF_CBBUF_INITIAL, KCDB_BUF_CBBUF_GROWTH); - - assert(new_size > buf->cb_buffer && new_size > 0); - - new_buf = PMALLOC(new_size); - assert(new_buf != NULL); - - memcpy(new_buf, buf->buffer, buf->cb_used); - PFREE(buf->buffer); - buf->buffer = new_buf; -} - -void kcdb_buf_alloc(kcdb_buf * buf, khm_size slot, khm_ui_2 id, khm_size cbsize) -{ - khm_size cbnew; - khm_ssize cbdelta; - khm_size cbold; - kcdb_buf_field * f; - - cbnew = UBOUND32(cbsize); - - assert(slot <= KCDB_BUF_APPEND); - - if(slot == KCDB_BUF_APPEND) { - slot = kcdb_buf_slot_by_id(buf, id); - if(slot == KCDB_BUF_INVALID_SLOT) - slot = buf->n_fields; - } - - assert(slot < KCDB_BUF_MAX_SLOTS); - - if((slot + 1) > buf->nc_fields) { - kcdb_buf_field * nf; - khm_size ns; - - ns = UBOUNDSS((slot + 1), KCDB_BUF_FIELDS_INITIAL, KCDB_BUF_FIELDS_GROWTH); - - nf = PMALLOC(sizeof(buf->fields[0]) * ns); - memcpy(nf, buf->fields, sizeof(buf->fields[0]) * buf->n_fields); - - if(ns > buf->n_fields) - memset(&(nf[buf->n_fields]), 0, sizeof(buf->fields[0]) * (ns - buf->n_fields)); - - PFREE(buf->fields); - buf->fields = nf; - buf->nc_fields = ns; - } - - if((slot + 1) > buf->n_fields) - buf->n_fields = slot + 1; - - f = &(buf->fields[slot]); - - if(f->flags & KCDB_CREDF_FLAG_ALLOCD) { - /* there's already an allocation. we have to resize it to - accomodate the new size */ - cbold = UBOUND32(f->cbsize); - /* demote before substraction */ - cbdelta = ((khm_ssize) cbnew) - (khm_ssize) cbold; - - if(cbnew > cbold) { - kcdb_buf_assert_size(buf, buf->cb_used + cbdelta); - } - - if(buf->cb_used > f->offset + cbold) { - khm_size i; - - memmove( - ((BYTE *) buf->buffer) + (f->offset + cbnew), - ((BYTE *) buf->buffer) + (f->offset + cbold), - buf->cb_used - (f->offset + cbold)); - - for(i=0; i < (int) buf->n_fields; i++) { - if(i != slot && - (buf->fields[i].flags & KCDB_CREDF_FLAG_ALLOCD) && - buf->fields[i].offset > f->offset) - { - buf->fields[i].offset = - (khm_ui_4)(((khm_ssize) buf->fields[i].offset) + cbdelta); - } - } - } - - /* demote integer before adding signed quantity */ - buf->cb_used = (khm_size)(((khm_ssize) buf->cb_used) + cbdelta); - - f->cbsize = (khm_ui_4) cbsize; - - } else { - kcdb_buf_assert_size(buf, buf->cb_used + cbnew); - f->offset = (khm_ui_4) buf->cb_used; - f->cbsize = (khm_ui_4) cbsize; - buf->cb_used += cbnew; - } - - if(cbsize == 0) { - f->flags &= ~KCDB_CREDF_FLAG_ALLOCD; - f->flags &= ~KCDB_CREDF_FLAG_DATA; - f->id = KCDB_BUFF_ID_INVALID; - } else { - f->flags |= KCDB_CREDF_FLAG_ALLOCD; - f->id = id; - } -} - -void kcdb_buf_dup(kcdb_buf * dest, const kcdb_buf * src) -{ - khm_size cb_buf; - khm_size nc_fields; - - cb_buf = UBOUNDSS(src->cb_used, KCDB_BUF_CBBUF_INITIAL, KCDB_BUF_CBBUF_GROWTH); -#if 0 - /* replaced by UBOUNDSS() above */ - (src->cb_used <= kcdb_cred_initial_size)? kcdb_cred_initial_size: - kcdb_cred_initial_size + - (((src->cb_used - (kcdb_cred_initial_size + 1)) / kcdb_cred_growth_factor + 1) * kcdb_cred_growth_factor); -#endif - - kcdb_buf_delete(dest); - - dest->cb_buffer = cb_buf; - dest->cb_used = src->cb_used; - dest->buffer = PMALLOC(cb_buf); - memcpy(dest->buffer, src->buffer, src->cb_used); - - nc_fields = UBOUNDSS(src->n_fields, KCDB_BUF_FIELDS_INITIAL, KCDB_BUF_FIELDS_GROWTH); - dest->nc_fields = nc_fields; - dest->n_fields = src->n_fields; - dest->fields = PMALLOC(nc_fields * sizeof(dest->fields[0])); - memcpy(dest->fields, src->fields, src->n_fields * sizeof(dest->fields[0])); - if(dest->n_fields < dest->nc_fields) - memset(&(dest->fields[dest->n_fields]), 0, (src->nc_fields - src->n_fields) * sizeof(dest->fields[0])); -} - -void kcdb_buf_set_value(kcdb_buf * buf, khm_size slot, khm_ui_2 id, void * src, khm_size cb_src) -{ - void * dest; - kcdb_buf_alloc(buf, slot, id, cb_src); - if(slot == KCDB_BUF_APPEND) { - slot = kcdb_buf_slot_by_id(buf, id); - if(slot == KCDB_BUF_INVALID_SLOT) { -#ifdef DEBUG - assert(FALSE); -#else - return; -#endif - } - } - if(kcdb_buf_exist(buf, slot)) { - dest = kcdb_buf_get(buf, slot); - memcpy(dest, src, cb_src); - - buf->fields[slot].flags |= KCDB_CREDF_FLAG_DATA; - } -} - -int kcdb_buf_exist(kcdb_buf * buf, khm_size slot) -{ - if(slot >= buf->n_fields) - return 0; - return (buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD); -} - -int kcdb_buf_val_exist(kcdb_buf * buf, khm_size slot) -{ - if(slot >= buf->n_fields) - return 0; - return (buf->fields[slot].flags & KCDB_CREDF_FLAG_DATA); -} - -void * kcdb_buf_get(kcdb_buf * buf, khm_size slot) -{ - if(slot >= buf->n_fields || - !(buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD)) - return NULL; - return (((BYTE *) buf->buffer) + buf->fields[slot].offset); -} - -khm_size kcdb_buf_size(kcdb_buf * buf, khm_size slot) -{ - if(slot >= buf->n_fields || - !(buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD)) - return 0; - return (buf->fields[slot].cbsize); -} - -void kcdb_buf_set_value_flag(kcdb_buf * buf, khm_size slot) -{ - if(slot >= buf->n_fields || - !(buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD)) - return; - - (buf->fields[slot].flags |= KCDB_CREDF_FLAG_DATA); -} - -khm_size kcdb_buf_slot_by_id(kcdb_buf * buf, khm_ui_2 id) -{ - int i; - - for(i=0; i < (int) buf->n_fields; i++) { - if(buf->fields[i].id == id) - break; - } - - if(i < (int) buf->n_fields) - return i; - else - return KCDB_BUF_INVALID_SLOT; -} - -/* API for accessing generic buffers */ - -KHMEXP khm_int32 KHMAPI kcdb_buf_get_attr( - khm_handle record, - khm_int32 attr_id, - khm_int32 * attr_type, - void * buffer, - khm_size * pcb_buf) -{ - if(kcdb_cred_is_active_cred(record)) - return kcdb_cred_get_attr(record, attr_id, attr_type, buffer, pcb_buf); - else if(kcdb_is_active_identity(record)) - return kcdb_identity_get_attr(record, attr_id, attr_type, buffer, pcb_buf); - else - return KHM_ERROR_INVALID_PARAM; -} - -KHMEXP khm_int32 KHMAPI kcdb_buf_get_attrib( - khm_handle record, - const wchar_t * attr_name, - khm_int32 * attr_type, - void * buffer, - khm_size * pcb_buf) -{ - if(kcdb_cred_is_active_cred(record)) - return kcdb_cred_get_attrib(record, attr_name, attr_type, buffer, pcb_buf); - else if(kcdb_is_active_identity(record)) - return kcdb_identity_get_attrib(record, attr_name, attr_type, buffer, pcb_buf); - else - return KHM_ERROR_INVALID_PARAM; -} - -KHMEXP khm_int32 KHMAPI kcdb_buf_get_attr_string( - khm_handle record, - khm_int32 attr_id, - wchar_t * buffer, - khm_size * pcbbuf, - khm_int32 flags) -{ - if(kcdb_cred_is_active_cred(record)) - return kcdb_cred_get_attr_string(record, attr_id, buffer, pcbbuf, flags); - else if(kcdb_is_active_identity(record)) - return kcdb_identity_get_attr_string(record, attr_id, buffer, pcbbuf, flags); - else - return KHM_ERROR_INVALID_PARAM; -} - -KHMEXP khm_int32 KHMAPI kcdb_buf_get_attrib_string( - khm_handle record, - const wchar_t * attr_name, - wchar_t * buffer, - khm_size * pcbbuf, - khm_int32 flags) -{ - if(kcdb_cred_is_active_cred(record)) - return kcdb_cred_get_attrib_string(record, attr_name, buffer, pcbbuf, flags); - else if(kcdb_is_active_identity(record)) - return kcdb_identity_get_attrib_string(record, attr_name, buffer, pcbbuf, flags); - else - return KHM_ERROR_INVALID_PARAM; -} - -KHMEXP khm_int32 KHMAPI kcdb_buf_set_attr( - khm_handle record, - khm_int32 attr_id, - void * buffer, - khm_size cbbuf) -{ - if(kcdb_cred_is_active_cred(record)) - return kcdb_cred_set_attr(record, attr_id, buffer, cbbuf); - else if(kcdb_is_active_identity(record)) - return kcdb_identity_set_attr(record, attr_id, buffer, cbbuf); - else - return KHM_ERROR_INVALID_PARAM; -} - -KHMEXP khm_int32 KHMAPI kcdb_buf_set_attrib( - khm_handle record, - const wchar_t * attr_name, - void * buffer, - khm_size cbbuf) -{ - if(kcdb_cred_is_active_cred(record)) - return kcdb_cred_set_attrib(record, attr_name, buffer, cbbuf); - else if(kcdb_is_active_identity(record)) - return kcdb_identity_set_attrib(record, attr_name, buffer, cbbuf); - else - return KHM_ERROR_INVALID_PARAM; -} - -KHMEXP khm_int32 KHMAPI kcdb_buf_hold(khm_handle record) -{ - if(kcdb_cred_is_active_cred(record)) - return kcdb_cred_hold(record); - else if(kcdb_is_active_identity(record)) - return kcdb_identity_hold(record); - else - return KHM_ERROR_INVALID_PARAM; -} - -KHMEXP khm_int32 KHMAPI kcdb_buf_release(khm_handle record) -{ - if(kcdb_cred_is_active_cred(record)) - return kcdb_cred_release(record); - else if(kcdb_is_active_identity(record)) - return kcdb_identity_release(record); - else - return KHM_ERROR_INVALID_PARAM; -} - +/* + * 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 + +void kcdb_buf_new(kcdb_buf * buf, khm_size n_fields) +{ + buf->buffer = PMALLOC(KCDB_BUF_CBBUF_INITIAL); + buf->cb_buffer = KCDB_BUF_CBBUF_INITIAL; + buf->cb_used = 0; + + if(n_fields == KCDB_BUF_DEFAULT) + n_fields = KCDB_BUF_FIELDS_INITIAL; + + assert(n_fields < KCDB_BUF_MAX_SLOTS); + + buf->n_fields = n_fields; + buf->nc_fields = UBOUNDSS(n_fields, KCDB_BUF_FIELDS_INITIAL, KCDB_BUF_FIELDS_GROWTH); + buf->fields = PMALLOC(sizeof(buf->fields[0]) * buf->n_fields); + ZeroMemory(buf->fields, sizeof(buf->fields[0]) * buf->n_fields); +} + +void kcdb_buf_delete(kcdb_buf * buf) +{ + buf->cb_buffer = 0; + buf->cb_used = 0; + if(buf->buffer) + PFREE(buf->buffer); + buf->buffer = NULL; + + buf->n_fields = 0; + buf->nc_fields = 0; + if(buf->fields) + PFREE(buf->fields); + buf->fields = NULL; +} + +static void kcdb_buf_assert_size(kcdb_buf * buf, khm_size cbsize) +{ + khm_size new_size; + void * new_buf; + + /* should be less than or equal to the max signed 32 bit int */ + assert(cbsize <= KHM_INT32_MAX); + if(cbsize <= buf->cb_buffer) + return; + + new_size = UBOUNDSS(cbsize, KCDB_BUF_CBBUF_INITIAL, KCDB_BUF_CBBUF_GROWTH); + + assert(new_size > buf->cb_buffer && new_size > 0); + + new_buf = PMALLOC(new_size); + assert(new_buf != NULL); + + memcpy(new_buf, buf->buffer, buf->cb_used); + PFREE(buf->buffer); + buf->buffer = new_buf; +} + +void kcdb_buf_alloc(kcdb_buf * buf, khm_size slot, khm_ui_2 id, khm_size cbsize) +{ + khm_size cbnew; + khm_ssize cbdelta; + khm_size cbold; + kcdb_buf_field * f; + + cbnew = UBOUND32(cbsize); + + assert(slot <= KCDB_BUF_APPEND); + + if(slot == KCDB_BUF_APPEND) { + slot = kcdb_buf_slot_by_id(buf, id); + if(slot == KCDB_BUF_INVALID_SLOT) + slot = buf->n_fields; + } + + assert(slot < KCDB_BUF_MAX_SLOTS); + + if((slot + 1) > buf->nc_fields) { + kcdb_buf_field * nf; + khm_size ns; + + ns = UBOUNDSS((slot + 1), KCDB_BUF_FIELDS_INITIAL, KCDB_BUF_FIELDS_GROWTH); + + nf = PMALLOC(sizeof(buf->fields[0]) * ns); + memcpy(nf, buf->fields, sizeof(buf->fields[0]) * buf->n_fields); + + if(ns > buf->n_fields) + memset(&(nf[buf->n_fields]), 0, sizeof(buf->fields[0]) * (ns - buf->n_fields)); + + PFREE(buf->fields); + buf->fields = nf; + buf->nc_fields = ns; + } + + if((slot + 1) > buf->n_fields) + buf->n_fields = slot + 1; + + f = &(buf->fields[slot]); + + if(f->flags & KCDB_CREDF_FLAG_ALLOCD) { + /* there's already an allocation. we have to resize it to + accomodate the new size */ + cbold = UBOUND32(f->cbsize); + /* demote before substraction */ + cbdelta = ((khm_ssize) cbnew) - (khm_ssize) cbold; + + if(cbnew > cbold) { + kcdb_buf_assert_size(buf, buf->cb_used + cbdelta); + } + + if(buf->cb_used > f->offset + cbold) { + khm_size i; + + memmove( + ((BYTE *) buf->buffer) + (f->offset + cbnew), + ((BYTE *) buf->buffer) + (f->offset + cbold), + buf->cb_used - (f->offset + cbold)); + + for(i=0; i < (int) buf->n_fields; i++) { + if(i != slot && + (buf->fields[i].flags & KCDB_CREDF_FLAG_ALLOCD) && + buf->fields[i].offset > f->offset) + { + buf->fields[i].offset = + (khm_ui_4)(((khm_ssize) buf->fields[i].offset) + cbdelta); + } + } + } + + /* demote integer before adding signed quantity */ + buf->cb_used = (khm_size)(((khm_ssize) buf->cb_used) + cbdelta); + + f->cbsize = (khm_ui_4) cbsize; + + } else { + kcdb_buf_assert_size(buf, buf->cb_used + cbnew); + f->offset = (khm_ui_4) buf->cb_used; + f->cbsize = (khm_ui_4) cbsize; + buf->cb_used += cbnew; + } + + if(cbsize == 0) { + f->flags &= ~KCDB_CREDF_FLAG_ALLOCD; + f->flags &= ~KCDB_CREDF_FLAG_DATA; + f->id = KCDB_BUFF_ID_INVALID; + } else { + f->flags |= KCDB_CREDF_FLAG_ALLOCD; + f->id = id; + } +} + +void kcdb_buf_dup(kcdb_buf * dest, const kcdb_buf * src) +{ + khm_size cb_buf; + khm_size nc_fields; + + cb_buf = UBOUNDSS(src->cb_used, KCDB_BUF_CBBUF_INITIAL, KCDB_BUF_CBBUF_GROWTH); +#if 0 + /* replaced by UBOUNDSS() above */ + (src->cb_used <= kcdb_cred_initial_size)? kcdb_cred_initial_size: + kcdb_cred_initial_size + + (((src->cb_used - (kcdb_cred_initial_size + 1)) / kcdb_cred_growth_factor + 1) * kcdb_cred_growth_factor); +#endif + + kcdb_buf_delete(dest); + + dest->cb_buffer = cb_buf; + dest->cb_used = src->cb_used; + dest->buffer = PMALLOC(cb_buf); + memcpy(dest->buffer, src->buffer, src->cb_used); + + nc_fields = UBOUNDSS(src->n_fields, KCDB_BUF_FIELDS_INITIAL, KCDB_BUF_FIELDS_GROWTH); + dest->nc_fields = nc_fields; + dest->n_fields = src->n_fields; + dest->fields = PMALLOC(nc_fields * sizeof(dest->fields[0])); + memcpy(dest->fields, src->fields, src->n_fields * sizeof(dest->fields[0])); + if(dest->n_fields < dest->nc_fields) + memset(&(dest->fields[dest->n_fields]), 0, (src->nc_fields - src->n_fields) * sizeof(dest->fields[0])); +} + +void kcdb_buf_set_value(kcdb_buf * buf, khm_size slot, khm_ui_2 id, void * src, khm_size cb_src) +{ + void * dest; + kcdb_buf_alloc(buf, slot, id, cb_src); + if(slot == KCDB_BUF_APPEND) { + slot = kcdb_buf_slot_by_id(buf, id); + if(slot == KCDB_BUF_INVALID_SLOT) { +#ifdef DEBUG + assert(FALSE); +#else + return; +#endif + } + } + if(kcdb_buf_exist(buf, slot)) { + dest = kcdb_buf_get(buf, slot); + memcpy(dest, src, cb_src); + + buf->fields[slot].flags |= KCDB_CREDF_FLAG_DATA; + } +} + +int kcdb_buf_exist(kcdb_buf * buf, khm_size slot) +{ + if(slot >= buf->n_fields) + return 0; + return (buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD); +} + +int kcdb_buf_val_exist(kcdb_buf * buf, khm_size slot) +{ + if(slot >= buf->n_fields) + return 0; + return (buf->fields[slot].flags & KCDB_CREDF_FLAG_DATA); +} + +void * kcdb_buf_get(kcdb_buf * buf, khm_size slot) +{ + if(slot >= buf->n_fields || + !(buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD)) + return NULL; + return (((BYTE *) buf->buffer) + buf->fields[slot].offset); +} + +khm_size kcdb_buf_size(kcdb_buf * buf, khm_size slot) +{ + if(slot >= buf->n_fields || + !(buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD)) + return 0; + return (buf->fields[slot].cbsize); +} + +void kcdb_buf_set_value_flag(kcdb_buf * buf, khm_size slot) +{ + if(slot >= buf->n_fields || + !(buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD)) + return; + + (buf->fields[slot].flags |= KCDB_CREDF_FLAG_DATA); +} + +khm_size kcdb_buf_slot_by_id(kcdb_buf * buf, khm_ui_2 id) +{ + int i; + + for(i=0; i < (int) buf->n_fields; i++) { + if(buf->fields[i].id == id) + break; + } + + if(i < (int) buf->n_fields) + return i; + else + return KCDB_BUF_INVALID_SLOT; +} + +/* API for accessing generic buffers */ + +KHMEXP khm_int32 KHMAPI kcdb_buf_get_attr( + khm_handle record, + khm_int32 attr_id, + khm_int32 * attr_type, + void * buffer, + khm_size * pcb_buf) +{ + if(kcdb_cred_is_active_cred(record)) + return kcdb_cred_get_attr(record, attr_id, attr_type, buffer, pcb_buf); + else if(kcdb_is_active_identity(record)) + return kcdb_identity_get_attr(record, attr_id, attr_type, buffer, pcb_buf); + else + return KHM_ERROR_INVALID_PARAM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_get_attrib( + khm_handle record, + const wchar_t * attr_name, + khm_int32 * attr_type, + void * buffer, + khm_size * pcb_buf) +{ + if(kcdb_cred_is_active_cred(record)) + return kcdb_cred_get_attrib(record, attr_name, attr_type, buffer, pcb_buf); + else if(kcdb_is_active_identity(record)) + return kcdb_identity_get_attrib(record, attr_name, attr_type, buffer, pcb_buf); + else + return KHM_ERROR_INVALID_PARAM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_get_attr_string( + khm_handle record, + khm_int32 attr_id, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags) +{ + if(kcdb_cred_is_active_cred(record)) + return kcdb_cred_get_attr_string(record, attr_id, buffer, pcbbuf, flags); + else if(kcdb_is_active_identity(record)) + return kcdb_identity_get_attr_string(record, attr_id, buffer, pcbbuf, flags); + else + return KHM_ERROR_INVALID_PARAM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_get_attrib_string( + khm_handle record, + const wchar_t * attr_name, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags) +{ + if(kcdb_cred_is_active_cred(record)) + return kcdb_cred_get_attrib_string(record, attr_name, buffer, pcbbuf, flags); + else if(kcdb_is_active_identity(record)) + return kcdb_identity_get_attrib_string(record, attr_name, buffer, pcbbuf, flags); + else + return KHM_ERROR_INVALID_PARAM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_set_attr( + khm_handle record, + khm_int32 attr_id, + void * buffer, + khm_size cbbuf) +{ + if(kcdb_cred_is_active_cred(record)) + return kcdb_cred_set_attr(record, attr_id, buffer, cbbuf); + else if(kcdb_is_active_identity(record)) + return kcdb_identity_set_attr(record, attr_id, buffer, cbbuf); + else + return KHM_ERROR_INVALID_PARAM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_set_attrib( + khm_handle record, + const wchar_t * attr_name, + void * buffer, + khm_size cbbuf) +{ + if(kcdb_cred_is_active_cred(record)) + return kcdb_cred_set_attrib(record, attr_name, buffer, cbbuf); + else if(kcdb_is_active_identity(record)) + return kcdb_identity_set_attrib(record, attr_name, buffer, cbbuf); + else + return KHM_ERROR_INVALID_PARAM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_hold(khm_handle record) +{ + if(kcdb_cred_is_active_cred(record)) + return kcdb_cred_hold(record); + else if(kcdb_is_active_identity(record)) + return kcdb_identity_hold(record); + else + return KHM_ERROR_INVALID_PARAM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_release(khm_handle record) +{ + if(kcdb_cred_is_active_cred(record)) + return kcdb_cred_release(record); + else if(kcdb_is_active_identity(record)) + return kcdb_identity_release(record); + else + return KHM_ERROR_INVALID_PARAM; +} + diff --git a/src/windows/identity/kcreddb/buf.h b/src/windows/identity/kcreddb/buf.h index f47bd0a2a..723253036 100644 --- a/src/windows/identity/kcreddb/buf.h +++ b/src/windows/identity/kcreddb/buf.h @@ -1,78 +1,78 @@ -/* - * 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_KCDB_BUF_H -#define __KHIMAIRA_KCDB_BUF_H - -typedef struct tag_kcdb_buf_field { - khm_ui_2 id; - khm_ui_2 flags; - khm_ui_4 offset; - khm_ui_4 cbsize; -} kcdb_buf_field; - -#define KCDB_CREDF_FLAG_EMPTY 0 -#define KCDB_CREDF_FLAG_DATA 1 -#define KCDB_CREDF_FLAG_INLINE 2 -#define KCDB_CREDF_FLAG_ALLOCD 4 - -#define KCDB_BUFF_ID_INVALID 0xffff - -typedef struct tag_kcdb_buf { - void * buffer; - khm_size cb_buffer; - khm_size cb_used; - - kcdb_buf_field * fields; - khm_size n_fields; - khm_size nc_fields; -} kcdb_buf; - -#define KCDB_BUF_CBBUF_INITIAL 4096 -#define KCDB_BUF_CBBUF_GROWTH 4096 -#define KCDB_BUF_FIELDS_INITIAL 16 -#define KCDB_BUF_FIELDS_GROWTH 16 - -#define KCDB_BUF_APPEND 0x8000 - -#define KCDB_BUF_INVALID_SLOT 0xf0000000 -#define KCDB_BUF_DEFAULT 0xe0000000 - -#define KCDB_BUF_MAX_SLOTS 0x00004000 - -void kcdb_buf_new(kcdb_buf * buf, khm_size n_slots); -void kcdb_buf_delete(kcdb_buf * buf); -void kcdb_buf_alloc(kcdb_buf * buf, khm_size slot, khm_ui_2 id, khm_size cbsize); -void kcdb_buf_dup(kcdb_buf * dest, const kcdb_buf * src); -void kcdb_buf_set_value(kcdb_buf * buf, khm_size slot, khm_ui_2 id, void * src, khm_size cb_src); -int kcdb_buf_exist(kcdb_buf * buf, khm_size slot); -int kcdb_buf_val_exist(kcdb_buf * buf, khm_size slot); -void * kcdb_buf_get(kcdb_buf * buf, khm_size slot); -khm_size kcdb_buf_size(kcdb_buf * buf, khm_size slot); -void kcdb_buf_set_value_flag(kcdb_buf * buf, khm_size slot); -khm_size kcdb_buf_slot_by_id(kcdb_buf * buf, khm_ui_2 id); - -#endif +/* + * 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_KCDB_BUF_H +#define __KHIMAIRA_KCDB_BUF_H + +typedef struct tag_kcdb_buf_field { + khm_ui_2 id; + khm_ui_2 flags; + khm_ui_4 offset; + khm_ui_4 cbsize; +} kcdb_buf_field; + +#define KCDB_CREDF_FLAG_EMPTY 0 +#define KCDB_CREDF_FLAG_DATA 1 +#define KCDB_CREDF_FLAG_INLINE 2 +#define KCDB_CREDF_FLAG_ALLOCD 4 + +#define KCDB_BUFF_ID_INVALID 0xffff + +typedef struct tag_kcdb_buf { + void * buffer; + khm_size cb_buffer; + khm_size cb_used; + + kcdb_buf_field * fields; + khm_size n_fields; + khm_size nc_fields; +} kcdb_buf; + +#define KCDB_BUF_CBBUF_INITIAL 4096 +#define KCDB_BUF_CBBUF_GROWTH 4096 +#define KCDB_BUF_FIELDS_INITIAL 16 +#define KCDB_BUF_FIELDS_GROWTH 16 + +#define KCDB_BUF_APPEND 0x8000 + +#define KCDB_BUF_INVALID_SLOT 0xf0000000 +#define KCDB_BUF_DEFAULT 0xe0000000 + +#define KCDB_BUF_MAX_SLOTS 0x00004000 + +void kcdb_buf_new(kcdb_buf * buf, khm_size n_slots); +void kcdb_buf_delete(kcdb_buf * buf); +void kcdb_buf_alloc(kcdb_buf * buf, khm_size slot, khm_ui_2 id, khm_size cbsize); +void kcdb_buf_dup(kcdb_buf * dest, const kcdb_buf * src); +void kcdb_buf_set_value(kcdb_buf * buf, khm_size slot, khm_ui_2 id, void * src, khm_size cb_src); +int kcdb_buf_exist(kcdb_buf * buf, khm_size slot); +int kcdb_buf_val_exist(kcdb_buf * buf, khm_size slot); +void * kcdb_buf_get(kcdb_buf * buf, khm_size slot); +khm_size kcdb_buf_size(kcdb_buf * buf, khm_size slot); +void kcdb_buf_set_value_flag(kcdb_buf * buf, khm_size slot); +khm_size kcdb_buf_slot_by_id(kcdb_buf * buf, khm_ui_2 id); + +#endif diff --git a/src/windows/identity/kcreddb/credential.c b/src/windows/identity/kcreddb/credential.c index 12b8c5fc5..c8a423a2a 100644 --- a/src/windows/identity/kcreddb/credential.c +++ b/src/windows/identity/kcreddb/credential.c @@ -1,1092 +1,1092 @@ -/* - * 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 - -/* cs_creds protects the *collection* of credentials, while l_creds - protects the *contents* of individual credentials. */ -CRITICAL_SECTION cs_creds; -kcdb_cred * kcdb_creds = NULL; - -/* a read lock must be obtained when querying any existing credential. - a write lock must be obtained when modifying any existing credential. - */ -RWLOCK l_creds; - -/* serial number */ -khm_ui_8 kcdb_cred_id = 0; - -void kcdb_cred_init(void) -{ - InitializeCriticalSection(&cs_creds); - InitializeRwLock(&l_creds); - kcdb_cred_id = 0; -} - -void kcdb_cred_exit(void) -{ - /*TODO: Free the credentials */ - DeleteCriticalSection(&cs_creds); - DeleteRwLock(&l_creds); -} - -/*! \internal - - can be called by kcdb_cred_dup with a write lock on l_creds and in other - places with a read lock on l_creds. New credentials must be creatable while - holding either lock. */ -KHMEXP khm_int32 KHMAPI -kcdb_cred_create(const wchar_t * name, - khm_handle identity, - khm_int32 cred_type, - khm_handle * result) -{ - kcdb_cred * cred; - size_t cb_name; - - if(!name || !result || - FAILED(StringCbLength(name, KCDB_CRED_MAXCB_NAME, &cb_name)) || - KHM_FAILED(kcdb_credtype_get_info(cred_type, NULL)) || - KHM_FAILED(kcdb_identity_hold(identity))) { - return KHM_ERROR_INVALID_PARAM; - } - - cb_name += sizeof(wchar_t); - - cred = PMALLOC(sizeof(kcdb_cred)); - ZeroMemory(cred, sizeof(kcdb_cred)); - - cred->magic = KCDB_CRED_MAGIC; - cred->identity = identity; - cred->name = PMALLOC(cb_name); - StringCbCopy(cred->name, cb_name, name); - cred->type = cred_type; - - cred->refcount = 1; /* initially held */ - - LINIT(cred); - - kcdb_buf_new(&cred->buf, KCDB_ATTR_MAX_ID + 1); - - /* Not obtaining a write lock on l_cred on purpose. - Well, because no one should be referencing this credential until - this function returns. */ - EnterCriticalSection(&cs_creds); - cred->id = kcdb_cred_id++; - LPUSH(&kcdb_creds, cred); - LeaveCriticalSection(&cs_creds); - - *result = cred; - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI kcdb_cred_update(khm_handle vdest, - khm_handle vsrc) -{ - khm_int32 rv = KHM_ERROR_EQUIVALENT; - kcdb_cred * src; - kcdb_cred * dest; - kcdb_type * t; - kcdb_attrib * a; - void * srcbuf; - void * destbuf; - khm_size cbsrcbuf; - khm_size cbdestbuf; - - int i; - - kcdb_cred_lock_write(); - - if(!kcdb_cred_is_active_cred(vsrc) || - !kcdb_cred_is_active_cred(vdest)) - goto _exit; - - src = (kcdb_cred *) vsrc; - dest = (kcdb_cred *) vdest; - - for(i=0;iflags & KCDB_ATTR_FLAG_COMPUTED) || - KHM_FAILED(kcdb_type_get_info(a->type, &t))) { - kcdb_attrib_release_info(a); - continue; - } - - srcbuf = kcdb_cred_buf_get(src,i); - cbsrcbuf = kcdb_cred_buf_size(src, i); - - if(kcdb_cred_val_exist(dest, i)) { - destbuf = kcdb_cred_buf_get(dest, i); - cbdestbuf = kcdb_cred_buf_size(dest, i); - - if(!t->comp(srcbuf, cbsrcbuf, destbuf, cbdestbuf)) - goto _skip_copy; - } - - kcdb_buf_set_value(&dest->buf, i, i, srcbuf, cbsrcbuf); - rv = KHM_ERROR_SUCCESS; - - _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) { - khm_int32 old_flags; - - old_flags = dest->flags; - - dest->flags = (src->flags & ~KCDB_CRED_FLAGMASK_ADDITIVE) | - ((src->flags | dest->flags) & KCDB_CRED_FLAGMASK_ADDITIVE); - - if (dest->flags != old_flags) - rv = KHM_ERROR_SUCCESS; - } - - _exit: - kcdb_cred_unlock_write(); - return rv; -} - -KHMEXP khm_int32 KHMAPI kcdb_cred_dup( - khm_handle vcred, - khm_handle * pnewcred) -{ - khm_int32 code = KHM_ERROR_SUCCESS; - kcdb_cred * cred; - kcdb_cred * newcred; - khm_handle vnewcred; - - if(!pnewcred) - return KHM_ERROR_INVALID_PARAM; - - *pnewcred = NULL; - - kcdb_cred_lock_write(); - - if(!kcdb_cred_is_active_cred(vcred)) { - code = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - cred = (kcdb_cred *) vcred; - - if(KHM_FAILED(kcdb_cred_create(cred->name, - cred->identity, - cred->type, - &vnewcred))) - { - code = KHM_ERROR_UNKNOWN; - goto _exit; - } - - newcred = (kcdb_cred *) vnewcred; - - newcred->flags = cred->flags; - - kcdb_buf_dup(&newcred->buf, &cred->buf); - - /* newcred is already held from the call to kcdb_cred_create */ - *pnewcred = (khm_handle) newcred; - -_exit: - kcdb_cred_unlock_write(); - return code; -} - -KHMEXP khm_int32 KHMAPI kcdb_cred_get_serial( - khm_handle vcred, - khm_ui_8 * pserial) -{ - kcdb_cred * c; - - if(!pserial) - return KHM_ERROR_INVALID_PARAM; - - kcdb_cred_lock_read(); - - if(!kcdb_cred_is_active_cred(vcred)) { - kcdb_cred_unlock_read(); - return KHM_ERROR_INVALID_PARAM; - } - - c = (kcdb_cred *) vcred; - - *pserial = c->id; - - kcdb_cred_unlock_read(); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI kcdb_cred_set_identity( - khm_handle vcred, - khm_handle id) -{ - kcdb_cred * c; - - if(!kcdb_is_identity(id)) - return KHM_ERROR_INVALID_PARAM; - - kcdb_cred_lock_write(); - if(!kcdb_cred_is_active_cred(vcred)) { - kcdb_cred_unlock_write(); - return KHM_ERROR_INVALID_PARAM; - } - - c = (kcdb_cred *) vcred; - - if(c->identity) { - kcdb_identity_release((khm_handle) c->identity); - } - kcdb_identity_hold(id); - c->identity = (kcdb_identity *) id; - - kcdb_cred_unlock_write(); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI kcdb_cred_get_type( - khm_handle vcred, - khm_int32 * type) -{ - kcdb_cred * c; - - if(!type) - return KHM_ERROR_INVALID_PARAM; - - kcdb_cred_lock_read(); - - if(!kcdb_cred_is_active_cred(vcred)) { - kcdb_cred_unlock_read(); - return KHM_ERROR_INVALID_PARAM; - } - - c = (kcdb_cred *) vcred; - - *type = c->type; - - kcdb_cred_unlock_read(); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI kcdb_cred_set_attrib( - khm_handle cred, - const wchar_t * name, - void * buffer, - khm_size cbbuf) -{ - khm_int32 attr_id = -1; - - if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id))) - return KHM_ERROR_INVALID_PARAM; - - return kcdb_cred_set_attr( - cred, - attr_id, - buffer, - cbbuf); -} - -KHMEXP khm_int32 KHMAPI kcdb_cred_set_attr( - khm_handle vcred, - khm_int32 attr_id, - void * buffer, - khm_size cbbuf) -{ - kcdb_cred * cred; - kcdb_type * type = NULL; - kcdb_attrib * attrib = NULL; - khm_size cbdest; - khm_int32 code = KHM_ERROR_SUCCESS; - - if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID) - return KHM_ERROR_INVALID_PARAM; - - kcdb_cred_lock_write(); - - if(!kcdb_cred_is_active_cred(vcred)) { - kcdb_cred_unlock_write(); - return KHM_ERROR_INVALID_PARAM; - } - - cred = (kcdb_cred *) vcred; - - if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { - kcdb_cred_unlock_write(); - return KHM_ERROR_INVALID_PARAM; - } - - if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) - { - kcdb_cred_unlock_write(); - kcdb_attrib_release_info(attrib); - return KHM_ERROR_INVALID_OPERATION; - } - - if (buffer == 0) { - /* we are removing the value */ - kcdb_buf_alloc(&cred->buf, attr_id, attr_id, 0); - code = KHM_ERROR_SUCCESS; - goto _exit; - } - - if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { - kcdb_cred_unlock_write(); - kcdb_attrib_release_info(attrib); - return KHM_ERROR_INVALID_PARAM; - } - - if(!(type->isValid(buffer,cbbuf))) { - code = KHM_ERROR_TYPE_MISMATCH; - goto _exit; - } - - if((type->dup(buffer, cbbuf, NULL, &cbdest)) != KHM_ERROR_TOO_LONG) { - code = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - kcdb_buf_alloc(&cred->buf, attr_id, attr_id, cbdest); - if(!kcdb_cred_buf_exist(cred, attr_id)) { - code = KHM_ERROR_NO_RESOURCES; - goto _exit; - } - - if(KHM_FAILED(code = - type->dup(buffer, cbbuf, kcdb_cred_buf_get(cred,attr_id), &cbdest))) - { - kcdb_buf_alloc(&cred->buf, attr_id, attr_id, 0); - goto _exit; - } - - kcdb_buf_set_value_flag(&cred->buf, attr_id); - -_exit: - kcdb_cred_unlock_write(); - - if(attrib) - kcdb_attrib_release_info(attrib); - if(type) - kcdb_type_release_info(type); - - return code; -} - -KHMEXP khm_int32 KHMAPI kcdb_cred_get_attrib( - khm_handle cred, - const wchar_t * name, - khm_int32 * attr_type, - void * buffer, - khm_size * cbbuf) -{ - khm_int32 attr_id = -1; - - if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id))) - return KHM_ERROR_NOT_FOUND; - - return kcdb_cred_get_attr( - cred, - attr_id, - attr_type, - buffer, - cbbuf); -} - -KHMEXP khm_int32 KHMAPI kcdb_cred_get_attrib_string( - khm_handle cred, - const wchar_t * name, - wchar_t * buffer, - khm_size * cbbuf, - khm_int32 flags) -{ - khm_int32 attr_id = -1; - - if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id))) - return KHM_ERROR_NOT_FOUND; - - return kcdb_cred_get_attr_string( - cred, - attr_id, - buffer, - cbbuf, - flags); -} - -KHMEXP khm_int32 KHMAPI -kcdb_cred_get_attr(khm_handle vcred, - khm_int32 attr_id, - khm_int32 * attr_type, - void * buffer, - khm_size * pcbbuf) -{ - khm_int32 code = KHM_ERROR_SUCCESS; - kcdb_cred * cred = NULL; - kcdb_attrib * attrib = NULL; - kcdb_type * type = NULL; - - if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID) - return KHM_ERROR_INVALID_PARAM; - - if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { - return KHM_ERROR_INVALID_PARAM; - } - - if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { - kcdb_attrib_release_info(attrib); - return KHM_ERROR_UNKNOWN; - } - - if(attr_type) - *attr_type = attrib->type; - - kcdb_cred_lock_read(); - if(!kcdb_cred_is_active_cred(vcred)) { - code = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - cred = (kcdb_cred *) vcred; - - if(!buffer && !pcbbuf) { - /* in this case the caller is only trying to determine if the - field contains data. We assume that computed fields are - always non-null. */ - code = (kcdb_cred_val_exist(cred, attr_id) || - (attrib->flags & KCDB_ATTR_FLAG_COMPUTED))?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND; - goto _exit; - } - - if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) { - code = attrib->compute_cb( - vcred, - attr_id, - buffer, - pcbbuf); - } else if (kcdb_cred_val_exist(cred, attr_id)) { - code = type->dup( - kcdb_cred_buf_get(cred, attr_id), - kcdb_cred_buf_size(cred, attr_id), - buffer, - pcbbuf); - } else { - code = KHM_ERROR_NOT_FOUND; - } - -_exit: - kcdb_cred_unlock_read(); - if(type) - kcdb_type_release_info(type); - if(attrib) - kcdb_attrib_release_info(attrib); - - return code; -} - -KHMEXP khm_int32 KHMAPI kcdb_cred_get_attr_string( - khm_handle vcred, - khm_int32 attr_id, - wchar_t * buffer, - khm_size * pcbbuf, - khm_int32 flags) -{ - khm_int32 code = KHM_ERROR_SUCCESS; - kcdb_cred * cred = NULL; - kcdb_attrib * attrib = NULL; - kcdb_type * type = NULL; - - if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID) - return KHM_ERROR_INVALID_PARAM; - - if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { - code = KHM_ERROR_INVALID_PARAM; - goto _exit_nolock; - } - - if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { - code = KHM_ERROR_UNKNOWN; - goto _exit_nolock; - } - - kcdb_cred_lock_read(); - if(!kcdb_cred_is_active_cred(vcred)) { - code = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - cred = (kcdb_cred *) vcred; - - if(!buffer && !pcbbuf) { - /* in this case the caller is only trying to determine if the - field contains data. We assume that computed fields are - always non-null. */ - code = (kcdb_cred_val_exist(cred, attr_id) || - (attrib->flags & KCDB_ATTR_FLAG_COMPUTED))?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND; - goto _exit; - } - - if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) { - void * buf; - khm_size cbbuf; - - code = attrib->compute_cb(vcred, - attr_id, - NULL, - &cbbuf); - if(code == KHM_ERROR_TOO_LONG) { - wchar_t vbuf[KCDB_MAXCCH_NAME]; - - if (cbbuf < sizeof(vbuf)) - buf = vbuf; - else - buf = PMALLOC(cbbuf); - - code = attrib->compute_cb(vcred, - attr_id, - buf, - &cbbuf); - if(KHM_SUCCEEDED(code)) { - code = type->toString(buf, - cbbuf, - buffer, - pcbbuf, - flags); - } - - if (buf != vbuf) - PFREE(buf); - } - } else { - if(kcdb_cred_buf_exist(cred, attr_id)) { - code = type->toString( - kcdb_cred_buf_get(cred, attr_id), - kcdb_cred_buf_size(cred, attr_id), - buffer, - pcbbuf, - flags); - } else - code = KHM_ERROR_NOT_FOUND; - } - - _exit: - kcdb_cred_unlock_read(); - _exit_nolock: - if(type) - kcdb_type_release_info(type); - if(attrib) - kcdb_attrib_release_info(attrib); - - return code; -} - - -KHMEXP khm_int32 KHMAPI kcdb_cred_get_name( - khm_handle vcred, - wchar_t * buffer, - khm_size * cbbuf) -{ - khm_int32 code = KHM_ERROR_SUCCESS; - kcdb_cred * cred = NULL; - size_t cbsize; - - if(!cbbuf) - return KHM_ERROR_INVALID_PARAM; - - kcdb_cred_lock_read(); - - if(!kcdb_cred_is_active_cred(vcred)) { - code = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - cred = (kcdb_cred *) vcred; - - if(FAILED(StringCbLength(cred->name, KCDB_CRED_MAXCB_NAME, &cbsize))) { - code = KHM_ERROR_UNKNOWN; - goto _exit; - } - - cbsize += sizeof(wchar_t); - - if(!buffer || *cbbuf < cbsize) { - *cbbuf = cbsize; - code = KHM_ERROR_TOO_LONG; - goto _exit; - } - - StringCbCopy(buffer, *cbbuf, cred->name); - - *cbbuf = cbsize; - -_exit: - - kcdb_cred_unlock_read(); - return code; -} - -KHMEXP khm_int32 KHMAPI kcdb_cred_get_identity( - khm_handle vcred, - khm_handle * identity) -{ - khm_int32 code = KHM_ERROR_SUCCESS; - kcdb_cred * cred; - - if(!identity) - return KHM_ERROR_INVALID_PARAM; - - kcdb_cred_lock_read(); - - if(!kcdb_cred_is_active_cred(vcred)) { - code = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - cred = (kcdb_cred *) vcred; - - kcdb_identity_hold((khm_handle) cred->identity); - - *identity = cred->identity; - -_exit: - kcdb_cred_unlock_read(); - return code; -} - -KHMEXP khm_int32 KHMAPI kcdb_cred_hold(khm_handle vcred) -{ - khm_int32 code = KHM_ERROR_SUCCESS; - kcdb_cred * cred; - - kcdb_cred_lock_write(); - - if(!kcdb_cred_is_cred(vcred)) { - code = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - cred = (kcdb_cred *) vcred; - - cred->refcount++; - -_exit: - kcdb_cred_unlock_write(); - return code; -} - -KHMEXP khm_int32 KHMAPI kcdb_cred_release(khm_handle vcred) -{ - khm_int32 code = KHM_ERROR_SUCCESS; - kcdb_cred * cred; - - kcdb_cred_lock_write(); - - if(!kcdb_cred_is_cred(vcred)) { - code = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - cred = (kcdb_cred *) vcred; - - cred->refcount--; - -_exit: - kcdb_cred_unlock_write(); - - kcdb_cred_check_and_delete(vcred); - - return code; -} - -void kcdb_cred_check_and_delete(khm_handle vcred) -{ - kcdb_cred * cred; - - kcdb_cred_lock_read(); - if(!kcdb_cred_is_cred(vcred)) { - goto _exit; - } - - cred = (kcdb_cred *) vcred; - - if(cred->refcount) - goto _exit; - - kcdb_cred_unlock_read(); - kcdb_cred_lock_write(); - if(!kcdb_cred_is_cred(vcred)) { - /* did we lose the race? */ - goto _exit2; - } - - cred->magic = 0; /* no longer a cred */ - kcdb_identity_release(cred->identity); - - EnterCriticalSection(&cs_creds); - LDELETE(&kcdb_creds, cred); - LeaveCriticalSection(&cs_creds); - - kcdb_buf_delete(&cred->buf); - PFREE(cred->name); - PFREE(cred); - - /*TODO: notifications */ - -_exit2: - kcdb_cred_unlock_write(); - return; - -_exit: - kcdb_cred_unlock_read(); -} - -KHMEXP khm_int32 KHMAPI kcdb_cred_delete(khm_handle vcred) -{ - khm_int32 code = KHM_ERROR_SUCCESS; - kcdb_cred * cred; - - kcdb_cred_lock_write(); - - if(!kcdb_cred_is_active_cred(vcred)) { - code = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - cred = (kcdb_cred *) vcred; - - cred->flags |= KCDB_CRED_FLAG_DELETED; - -_exit: - kcdb_cred_unlock_write(); - - kcdb_cred_check_and_delete(vcred); - - return code; -} - -KHMEXP khm_int32 KHMAPI -kcdb_creds_comp_attrib(khm_handle cred1, - khm_handle cred2, - const wchar_t * name) -{ - khm_int32 attr_id; - - if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id))) - return 0; - - return kcdb_creds_comp_attr(cred1, cred2, attr_id); -} - -KHMEXP khm_int32 KHMAPI -kcdb_creds_comp_attr(khm_handle vcred1, - khm_handle vcred2, - khm_int32 attr_id) -{ - khm_int32 code = 0; - kcdb_cred * cred1; - kcdb_cred * cred2; - kcdb_attrib * attrib = NULL; - kcdb_type * type = NULL; - - if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID) - return 0; - - cred1 = (kcdb_cred *) vcred1; - cred2 = (kcdb_cred *) vcred2; - - kcdb_cred_lock_read(); - if( - !kcdb_cred_is_active_cred(vcred1) || - !kcdb_cred_is_active_cred(vcred2)) - goto _exit; - - cred1 = (kcdb_cred *) vcred1; - cred2 = (kcdb_cred *) vcred2; - - if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) - goto _exit; - - if(!(attrib->flags & KCDB_ATTR_FLAG_COMPUTED)) { - int nc = 0; - - if(!kcdb_cred_val_exist(cred1, attr_id)) { - code = -1; - nc = 1; - } - if(!kcdb_cred_val_exist(cred2, attr_id)) { - code += 1; - nc = 1; - } - - if(nc) - goto _exit; - } - - if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) - goto _exit; - - if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) { - khm_octet vbuf[KCDB_MAXCB_NAME * 2]; - void * buf1 = NULL; - void * buf2 = NULL; - khm_size cb1; - khm_size cb2; - - code = 0; - - if(attrib->compute_cb(vcred1, attr_id, - NULL, &cb1) != KHM_ERROR_TOO_LONG) - goto _exit_1; - - if(attrib->compute_cb(vcred2, attr_id, - NULL, &cb2) != KHM_ERROR_TOO_LONG) - goto _exit_1; - - if(cb1) { - if (cb1 < sizeof(vbuf)) - buf1 = vbuf; - else - buf1 = PMALLOC(cb1); - - if(KHM_FAILED(attrib->compute_cb(vcred1, attr_id, buf1, &cb1))) - goto _exit_1; - } - - if(cb2) { - if (cb1 + cb2 < sizeof(vbuf)) - buf2 = vbuf + cb1; - else - buf2 = PMALLOC(cb2); - - if(KHM_FAILED(attrib->compute_cb(vcred2, attr_id, buf2, &cb2))) - goto _exit_1; - } - - code = type->comp(buf1, cb1, - buf2, cb2); -_exit_1: - if(buf1 && (buf1 < (void *)vbuf || - buf1 >= (void*)(vbuf + sizeof(vbuf)))) - PFREE(buf1); - if(buf2 && (buf2 < (void *)vbuf || - buf2 >= (void *)(vbuf + sizeof(vbuf)))) - PFREE(buf2); - } else { - code = type->comp( - kcdb_cred_buf_get(cred1, attr_id), - kcdb_cred_buf_size(cred1, attr_id), - kcdb_cred_buf_get(cred2, attr_id), - kcdb_cred_buf_size(cred2, attr_id)); - } - -_exit: - kcdb_cred_unlock_read(); - if(attrib) - kcdb_attrib_release_info(attrib); - if(type) - kcdb_type_release_info(type); - return code; -} - -KHMEXP khm_int32 KHMAPI -kcdb_creds_is_equal(khm_handle vcred1, - khm_handle vcred2) -{ - khm_int32 code = 0; - kcdb_cred * cred1; - kcdb_cred * cred2; - - kcdb_cred_lock_read(); - if(!kcdb_cred_is_active_cred(vcred1) || - !kcdb_cred_is_active_cred(vcred2)) { - - code = FALSE; - goto _exit; - - } - - if(vcred1 == vcred2) { - - code = TRUE; - goto _exit; - - } - - cred1 = vcred1; - cred2 = vcred2; - - if(cred1->identity == cred2->identity && - cred1->type == cred2->type && - !wcscmp(cred1->name, cred2->name)) { - - kcdb_credtype * type; - - code = TRUE; - - if (KHM_SUCCEEDED(kcdb_credtype_get_info(cred1->type, &type))) { - if (type->is_equal && - (*type->is_equal)(vcred1, vcred2, NULL)) - code = 0; - - kcdb_credtype_release_info(type); - } - } - -_exit: - kcdb_cred_unlock_read(); - return code; -} - -KHMEXP khm_int32 KHMAPI -kcdb_cred_get_flags(khm_handle vcred, - khm_int32 * pflags) -{ - khm_int32 f; - khm_int32 rv = KHM_ERROR_SUCCESS; - kcdb_cred * cred; - int release_lock = TRUE; - - if (pflags == NULL) - return KHM_ERROR_INVALID_PARAM; - - kcdb_cred_lock_read(); - if (!kcdb_cred_is_active_cred(vcred)) { - *pflags = 0; - rv = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - cred = vcred; - f = cred->flags; - - /* Update flags if necessary */ - - if (!(f & KCDB_CRED_FLAG_EXPIRED) && - kcdb_cred_buf_exist(cred, KCDB_ATTR_EXPIRE)) { - - FILETIME ftc; - - GetSystemTimeAsFileTime(&ftc); - if (CompareFileTime(&ftc, ((FILETIME *) - kcdb_cred_buf_get(cred, KCDB_ATTR_EXPIRE))) - >= 0) - f |= KCDB_CRED_FLAG_EXPIRED; - } - -#if 0 - /* Commented out: if the credential has expired, then checking the - renewable time is not useful */ - if (!(f & KCDB_CRED_FLAG_INVALID)) { - if (f & KCDB_CRED_FLAG_RENEWABLE) { - if (kcdb_cred_buf_exist(cred, KCDB_ATTR_RENEW_EXPIRE)) { - FILETIME ftc; - - GetSystemTimeAsFileTime(&ftc); - if (CompareFileTime(&ftc, ((FILETIME *) - kcdb_cred_buf_get(cred, KCDB_ATTR_RENEW_EXPIRE))) >= 0) - f |= KCDB_CRED_FLAG_INVALID; - } - } else { - if (f & KCDB_CRED_FLAG_EXPIRED) - f |= KCDB_CRED_FLAG_INVALID; - } - } - - /* Commented out: this is a read operation. We shouldn't attempt - to lock for writing */ - if (f != cred->flags) { - kcdb_cred_unlock_read(); - kcdb_cred_lock_write(); - /* Did we lose a race? */ - if (kcdb_cred_is_active_cred(vcred)) - cred->flags = f; - else { - rv = KHM_ERROR_INVALID_PARAM; - f = 0; - } - kcdb_cred_unlock_write(); - release_lock = FALSE; - } -#endif - - *pflags = f; - - _exit: - if (release_lock) - kcdb_cred_unlock_read(); - - return rv; -} - -KHMEXP khm_int32 KHMAPI kcdb_cred_set_flags( - khm_handle vcred, - khm_int32 flags, - khm_int32 mask) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - kcdb_cred * cred; - - kcdb_cred_lock_write(); - if(!kcdb_cred_is_active_cred(vcred)) { - rv = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - cred = vcred; - - flags &= ~(KCDB_CRED_FLAG_DELETED); - mask &= ~(KCDB_CRED_FLAG_DELETED); - - cred->flags = - (cred->flags & (~mask)) | - (flags & mask); - - _exit: - kcdb_cred_unlock_write(); - return rv; -} +/* + * 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 + +/* cs_creds protects the *collection* of credentials, while l_creds + protects the *contents* of individual credentials. */ +CRITICAL_SECTION cs_creds; +kcdb_cred * kcdb_creds = NULL; + +/* a read lock must be obtained when querying any existing credential. + a write lock must be obtained when modifying any existing credential. + */ +RWLOCK l_creds; + +/* serial number */ +khm_ui_8 kcdb_cred_id = 0; + +void kcdb_cred_init(void) +{ + InitializeCriticalSection(&cs_creds); + InitializeRwLock(&l_creds); + kcdb_cred_id = 0; +} + +void kcdb_cred_exit(void) +{ + /*TODO: Free the credentials */ + DeleteCriticalSection(&cs_creds); + DeleteRwLock(&l_creds); +} + +/*! \internal + + can be called by kcdb_cred_dup with a write lock on l_creds and in other + places with a read lock on l_creds. New credentials must be creatable while + holding either lock. */ +KHMEXP khm_int32 KHMAPI +kcdb_cred_create(const wchar_t * name, + khm_handle identity, + khm_int32 cred_type, + khm_handle * result) +{ + kcdb_cred * cred; + size_t cb_name; + + if(!name || !result || + FAILED(StringCbLength(name, KCDB_CRED_MAXCB_NAME, &cb_name)) || + KHM_FAILED(kcdb_credtype_get_info(cred_type, NULL)) || + KHM_FAILED(kcdb_identity_hold(identity))) { + return KHM_ERROR_INVALID_PARAM; + } + + cb_name += sizeof(wchar_t); + + cred = PMALLOC(sizeof(kcdb_cred)); + ZeroMemory(cred, sizeof(kcdb_cred)); + + cred->magic = KCDB_CRED_MAGIC; + cred->identity = identity; + cred->name = PMALLOC(cb_name); + StringCbCopy(cred->name, cb_name, name); + cred->type = cred_type; + + cred->refcount = 1; /* initially held */ + + LINIT(cred); + + kcdb_buf_new(&cred->buf, KCDB_ATTR_MAX_ID + 1); + + /* Not obtaining a write lock on l_cred on purpose. + Well, because no one should be referencing this credential until + this function returns. */ + EnterCriticalSection(&cs_creds); + cred->id = kcdb_cred_id++; + LPUSH(&kcdb_creds, cred); + LeaveCriticalSection(&cs_creds); + + *result = cred; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_update(khm_handle vdest, + khm_handle vsrc) +{ + khm_int32 rv = KHM_ERROR_EQUIVALENT; + kcdb_cred * src; + kcdb_cred * dest; + kcdb_type * t; + kcdb_attrib * a; + void * srcbuf; + void * destbuf; + khm_size cbsrcbuf; + khm_size cbdestbuf; + + int i; + + kcdb_cred_lock_write(); + + if(!kcdb_cred_is_active_cred(vsrc) || + !kcdb_cred_is_active_cred(vdest)) + goto _exit; + + src = (kcdb_cred *) vsrc; + dest = (kcdb_cred *) vdest; + + for(i=0;iflags & KCDB_ATTR_FLAG_COMPUTED) || + KHM_FAILED(kcdb_type_get_info(a->type, &t))) { + kcdb_attrib_release_info(a); + continue; + } + + srcbuf = kcdb_cred_buf_get(src,i); + cbsrcbuf = kcdb_cred_buf_size(src, i); + + if(kcdb_cred_val_exist(dest, i)) { + destbuf = kcdb_cred_buf_get(dest, i); + cbdestbuf = kcdb_cred_buf_size(dest, i); + + if(!t->comp(srcbuf, cbsrcbuf, destbuf, cbdestbuf)) + goto _skip_copy; + } + + kcdb_buf_set_value(&dest->buf, i, i, srcbuf, cbsrcbuf); + rv = KHM_ERROR_SUCCESS; + + _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) { + khm_int32 old_flags; + + old_flags = dest->flags; + + dest->flags = (src->flags & ~KCDB_CRED_FLAGMASK_ADDITIVE) | + ((src->flags | dest->flags) & KCDB_CRED_FLAGMASK_ADDITIVE); + + if (dest->flags != old_flags) + rv = KHM_ERROR_SUCCESS; + } + + _exit: + kcdb_cred_unlock_write(); + return rv; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_dup( + khm_handle vcred, + khm_handle * pnewcred) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred * cred; + kcdb_cred * newcred; + khm_handle vnewcred; + + if(!pnewcred) + return KHM_ERROR_INVALID_PARAM; + + *pnewcred = NULL; + + kcdb_cred_lock_write(); + + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + if(KHM_FAILED(kcdb_cred_create(cred->name, + cred->identity, + cred->type, + &vnewcred))) + { + code = KHM_ERROR_UNKNOWN; + goto _exit; + } + + newcred = (kcdb_cred *) vnewcred; + + newcred->flags = cred->flags; + + kcdb_buf_dup(&newcred->buf, &cred->buf); + + /* newcred is already held from the call to kcdb_cred_create */ + *pnewcred = (khm_handle) newcred; + +_exit: + kcdb_cred_unlock_write(); + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_get_serial( + khm_handle vcred, + khm_ui_8 * pserial) +{ + kcdb_cred * c; + + if(!pserial) + return KHM_ERROR_INVALID_PARAM; + + kcdb_cred_lock_read(); + + if(!kcdb_cred_is_active_cred(vcred)) { + kcdb_cred_unlock_read(); + return KHM_ERROR_INVALID_PARAM; + } + + c = (kcdb_cred *) vcred; + + *pserial = c->id; + + kcdb_cred_unlock_read(); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_set_identity( + khm_handle vcred, + khm_handle id) +{ + kcdb_cred * c; + + if(!kcdb_is_identity(id)) + return KHM_ERROR_INVALID_PARAM; + + kcdb_cred_lock_write(); + if(!kcdb_cred_is_active_cred(vcred)) { + kcdb_cred_unlock_write(); + return KHM_ERROR_INVALID_PARAM; + } + + c = (kcdb_cred *) vcred; + + if(c->identity) { + kcdb_identity_release((khm_handle) c->identity); + } + kcdb_identity_hold(id); + c->identity = (kcdb_identity *) id; + + kcdb_cred_unlock_write(); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_get_type( + khm_handle vcred, + khm_int32 * type) +{ + kcdb_cred * c; + + if(!type) + return KHM_ERROR_INVALID_PARAM; + + kcdb_cred_lock_read(); + + if(!kcdb_cred_is_active_cred(vcred)) { + kcdb_cred_unlock_read(); + return KHM_ERROR_INVALID_PARAM; + } + + c = (kcdb_cred *) vcred; + + *type = c->type; + + kcdb_cred_unlock_read(); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_set_attrib( + khm_handle cred, + const wchar_t * name, + void * buffer, + khm_size cbbuf) +{ + khm_int32 attr_id = -1; + + if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id))) + return KHM_ERROR_INVALID_PARAM; + + return kcdb_cred_set_attr( + cred, + attr_id, + buffer, + cbbuf); +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_set_attr( + khm_handle vcred, + khm_int32 attr_id, + void * buffer, + khm_size cbbuf) +{ + kcdb_cred * cred; + kcdb_type * type = NULL; + kcdb_attrib * attrib = NULL; + khm_size cbdest; + khm_int32 code = KHM_ERROR_SUCCESS; + + if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + kcdb_cred_lock_write(); + + if(!kcdb_cred_is_active_cred(vcred)) { + kcdb_cred_unlock_write(); + return KHM_ERROR_INVALID_PARAM; + } + + cred = (kcdb_cred *) vcred; + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { + kcdb_cred_unlock_write(); + return KHM_ERROR_INVALID_PARAM; + } + + if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) + { + kcdb_cred_unlock_write(); + kcdb_attrib_release_info(attrib); + return KHM_ERROR_INVALID_OPERATION; + } + + if (buffer == 0) { + /* we are removing the value */ + kcdb_buf_alloc(&cred->buf, attr_id, attr_id, 0); + code = KHM_ERROR_SUCCESS; + goto _exit; + } + + if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { + kcdb_cred_unlock_write(); + kcdb_attrib_release_info(attrib); + return KHM_ERROR_INVALID_PARAM; + } + + if(!(type->isValid(buffer,cbbuf))) { + code = KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + + if((type->dup(buffer, cbbuf, NULL, &cbdest)) != KHM_ERROR_TOO_LONG) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + kcdb_buf_alloc(&cred->buf, attr_id, attr_id, cbdest); + if(!kcdb_cred_buf_exist(cred, attr_id)) { + code = KHM_ERROR_NO_RESOURCES; + goto _exit; + } + + if(KHM_FAILED(code = + type->dup(buffer, cbbuf, kcdb_cred_buf_get(cred,attr_id), &cbdest))) + { + kcdb_buf_alloc(&cred->buf, attr_id, attr_id, 0); + goto _exit; + } + + kcdb_buf_set_value_flag(&cred->buf, attr_id); + +_exit: + kcdb_cred_unlock_write(); + + if(attrib) + kcdb_attrib_release_info(attrib); + if(type) + kcdb_type_release_info(type); + + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_get_attrib( + khm_handle cred, + const wchar_t * name, + khm_int32 * attr_type, + void * buffer, + khm_size * cbbuf) +{ + khm_int32 attr_id = -1; + + if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id))) + return KHM_ERROR_NOT_FOUND; + + return kcdb_cred_get_attr( + cred, + attr_id, + attr_type, + buffer, + cbbuf); +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_get_attrib_string( + khm_handle cred, + const wchar_t * name, + wchar_t * buffer, + khm_size * cbbuf, + khm_int32 flags) +{ + khm_int32 attr_id = -1; + + if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id))) + return KHM_ERROR_NOT_FOUND; + + return kcdb_cred_get_attr_string( + cred, + attr_id, + buffer, + cbbuf, + flags); +} + +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_attr(khm_handle vcred, + khm_int32 attr_id, + khm_int32 * attr_type, + void * buffer, + khm_size * pcbbuf) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred * cred = NULL; + kcdb_attrib * attrib = NULL; + kcdb_type * type = NULL; + + if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { + return KHM_ERROR_INVALID_PARAM; + } + + if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { + kcdb_attrib_release_info(attrib); + return KHM_ERROR_UNKNOWN; + } + + if(attr_type) + *attr_type = attrib->type; + + kcdb_cred_lock_read(); + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + if(!buffer && !pcbbuf) { + /* in this case the caller is only trying to determine if the + field contains data. We assume that computed fields are + always non-null. */ + code = (kcdb_cred_val_exist(cred, attr_id) || + (attrib->flags & KCDB_ATTR_FLAG_COMPUTED))?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND; + goto _exit; + } + + if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) { + code = attrib->compute_cb( + vcred, + attr_id, + buffer, + pcbbuf); + } else if (kcdb_cred_val_exist(cred, attr_id)) { + code = type->dup( + kcdb_cred_buf_get(cred, attr_id), + kcdb_cred_buf_size(cred, attr_id), + buffer, + pcbbuf); + } else { + code = KHM_ERROR_NOT_FOUND; + } + +_exit: + kcdb_cred_unlock_read(); + if(type) + kcdb_type_release_info(type); + if(attrib) + kcdb_attrib_release_info(attrib); + + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_get_attr_string( + khm_handle vcred, + khm_int32 attr_id, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred * cred = NULL; + kcdb_attrib * attrib = NULL; + kcdb_type * type = NULL; + + if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit_nolock; + } + + if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { + code = KHM_ERROR_UNKNOWN; + goto _exit_nolock; + } + + kcdb_cred_lock_read(); + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + if(!buffer && !pcbbuf) { + /* in this case the caller is only trying to determine if the + field contains data. We assume that computed fields are + always non-null. */ + code = (kcdb_cred_val_exist(cred, attr_id) || + (attrib->flags & KCDB_ATTR_FLAG_COMPUTED))?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND; + goto _exit; + } + + if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) { + void * buf; + khm_size cbbuf; + + code = attrib->compute_cb(vcred, + attr_id, + NULL, + &cbbuf); + if(code == KHM_ERROR_TOO_LONG) { + wchar_t vbuf[KCDB_MAXCCH_NAME]; + + if (cbbuf < sizeof(vbuf)) + buf = vbuf; + else + buf = PMALLOC(cbbuf); + + code = attrib->compute_cb(vcred, + attr_id, + buf, + &cbbuf); + if(KHM_SUCCEEDED(code)) { + code = type->toString(buf, + cbbuf, + buffer, + pcbbuf, + flags); + } + + if (buf != vbuf) + PFREE(buf); + } + } else { + if(kcdb_cred_buf_exist(cred, attr_id)) { + code = type->toString( + kcdb_cred_buf_get(cred, attr_id), + kcdb_cred_buf_size(cred, attr_id), + buffer, + pcbbuf, + flags); + } else + code = KHM_ERROR_NOT_FOUND; + } + + _exit: + kcdb_cred_unlock_read(); + _exit_nolock: + if(type) + kcdb_type_release_info(type); + if(attrib) + kcdb_attrib_release_info(attrib); + + return code; +} + + +KHMEXP khm_int32 KHMAPI kcdb_cred_get_name( + khm_handle vcred, + wchar_t * buffer, + khm_size * cbbuf) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred * cred = NULL; + size_t cbsize; + + if(!cbbuf) + return KHM_ERROR_INVALID_PARAM; + + kcdb_cred_lock_read(); + + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + if(FAILED(StringCbLength(cred->name, KCDB_CRED_MAXCB_NAME, &cbsize))) { + code = KHM_ERROR_UNKNOWN; + goto _exit; + } + + cbsize += sizeof(wchar_t); + + if(!buffer || *cbbuf < cbsize) { + *cbbuf = cbsize; + code = KHM_ERROR_TOO_LONG; + goto _exit; + } + + StringCbCopy(buffer, *cbbuf, cred->name); + + *cbbuf = cbsize; + +_exit: + + kcdb_cred_unlock_read(); + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_get_identity( + khm_handle vcred, + khm_handle * identity) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred * cred; + + if(!identity) + return KHM_ERROR_INVALID_PARAM; + + kcdb_cred_lock_read(); + + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + kcdb_identity_hold((khm_handle) cred->identity); + + *identity = cred->identity; + +_exit: + kcdb_cred_unlock_read(); + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_hold(khm_handle vcred) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred * cred; + + kcdb_cred_lock_write(); + + if(!kcdb_cred_is_cred(vcred)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + cred->refcount++; + +_exit: + kcdb_cred_unlock_write(); + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_release(khm_handle vcred) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred * cred; + + kcdb_cred_lock_write(); + + if(!kcdb_cred_is_cred(vcred)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + cred->refcount--; + +_exit: + kcdb_cred_unlock_write(); + + kcdb_cred_check_and_delete(vcred); + + return code; +} + +void kcdb_cred_check_and_delete(khm_handle vcred) +{ + kcdb_cred * cred; + + kcdb_cred_lock_read(); + if(!kcdb_cred_is_cred(vcred)) { + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + if(cred->refcount) + goto _exit; + + kcdb_cred_unlock_read(); + kcdb_cred_lock_write(); + if(!kcdb_cred_is_cred(vcred)) { + /* did we lose the race? */ + goto _exit2; + } + + cred->magic = 0; /* no longer a cred */ + kcdb_identity_release(cred->identity); + + EnterCriticalSection(&cs_creds); + LDELETE(&kcdb_creds, cred); + LeaveCriticalSection(&cs_creds); + + kcdb_buf_delete(&cred->buf); + PFREE(cred->name); + PFREE(cred); + + /*TODO: notifications */ + +_exit2: + kcdb_cred_unlock_write(); + return; + +_exit: + kcdb_cred_unlock_read(); +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_delete(khm_handle vcred) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred * cred; + + kcdb_cred_lock_write(); + + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + cred->flags |= KCDB_CRED_FLAG_DELETED; + +_exit: + kcdb_cred_unlock_write(); + + kcdb_cred_check_and_delete(vcred); + + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_creds_comp_attrib(khm_handle cred1, + khm_handle cred2, + const wchar_t * name) +{ + khm_int32 attr_id; + + if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id))) + return 0; + + return kcdb_creds_comp_attr(cred1, cred2, attr_id); +} + +KHMEXP khm_int32 KHMAPI +kcdb_creds_comp_attr(khm_handle vcred1, + khm_handle vcred2, + khm_int32 attr_id) +{ + khm_int32 code = 0; + kcdb_cred * cred1; + kcdb_cred * cred2; + kcdb_attrib * attrib = NULL; + kcdb_type * type = NULL; + + if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID) + return 0; + + cred1 = (kcdb_cred *) vcred1; + cred2 = (kcdb_cred *) vcred2; + + kcdb_cred_lock_read(); + if( + !kcdb_cred_is_active_cred(vcred1) || + !kcdb_cred_is_active_cred(vcred2)) + goto _exit; + + cred1 = (kcdb_cred *) vcred1; + cred2 = (kcdb_cred *) vcred2; + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) + goto _exit; + + if(!(attrib->flags & KCDB_ATTR_FLAG_COMPUTED)) { + int nc = 0; + + if(!kcdb_cred_val_exist(cred1, attr_id)) { + code = -1; + nc = 1; + } + if(!kcdb_cred_val_exist(cred2, attr_id)) { + code += 1; + nc = 1; + } + + if(nc) + goto _exit; + } + + if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) + goto _exit; + + if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) { + khm_octet vbuf[KCDB_MAXCB_NAME * 2]; + void * buf1 = NULL; + void * buf2 = NULL; + khm_size cb1; + khm_size cb2; + + code = 0; + + if(attrib->compute_cb(vcred1, attr_id, + NULL, &cb1) != KHM_ERROR_TOO_LONG) + goto _exit_1; + + if(attrib->compute_cb(vcred2, attr_id, + NULL, &cb2) != KHM_ERROR_TOO_LONG) + goto _exit_1; + + if(cb1) { + if (cb1 < sizeof(vbuf)) + buf1 = vbuf; + else + buf1 = PMALLOC(cb1); + + if(KHM_FAILED(attrib->compute_cb(vcred1, attr_id, buf1, &cb1))) + goto _exit_1; + } + + if(cb2) { + if (cb1 + cb2 < sizeof(vbuf)) + buf2 = vbuf + cb1; + else + buf2 = PMALLOC(cb2); + + if(KHM_FAILED(attrib->compute_cb(vcred2, attr_id, buf2, &cb2))) + goto _exit_1; + } + + code = type->comp(buf1, cb1, + buf2, cb2); +_exit_1: + if(buf1 && (buf1 < (void *)vbuf || + buf1 >= (void*)(vbuf + sizeof(vbuf)))) + PFREE(buf1); + if(buf2 && (buf2 < (void *)vbuf || + buf2 >= (void *)(vbuf + sizeof(vbuf)))) + PFREE(buf2); + } else { + code = type->comp( + kcdb_cred_buf_get(cred1, attr_id), + kcdb_cred_buf_size(cred1, attr_id), + kcdb_cred_buf_get(cred2, attr_id), + kcdb_cred_buf_size(cred2, attr_id)); + } + +_exit: + kcdb_cred_unlock_read(); + if(attrib) + kcdb_attrib_release_info(attrib); + if(type) + kcdb_type_release_info(type); + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_creds_is_equal(khm_handle vcred1, + khm_handle vcred2) +{ + khm_int32 code = 0; + kcdb_cred * cred1; + kcdb_cred * cred2; + + kcdb_cred_lock_read(); + if(!kcdb_cred_is_active_cred(vcred1) || + !kcdb_cred_is_active_cred(vcred2)) { + + code = FALSE; + goto _exit; + + } + + if(vcred1 == vcred2) { + + code = TRUE; + goto _exit; + + } + + cred1 = vcred1; + cred2 = vcred2; + + if(cred1->identity == cred2->identity && + cred1->type == cred2->type && + !wcscmp(cred1->name, cred2->name)) { + + kcdb_credtype * type; + + code = TRUE; + + if (KHM_SUCCEEDED(kcdb_credtype_get_info(cred1->type, &type))) { + if (type->is_equal && + (*type->is_equal)(vcred1, vcred2, NULL)) + code = 0; + + kcdb_credtype_release_info(type); + } + } + +_exit: + kcdb_cred_unlock_read(); + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_flags(khm_handle vcred, + khm_int32 * pflags) +{ + khm_int32 f; + khm_int32 rv = KHM_ERROR_SUCCESS; + kcdb_cred * cred; + int release_lock = TRUE; + + if (pflags == NULL) + return KHM_ERROR_INVALID_PARAM; + + kcdb_cred_lock_read(); + if (!kcdb_cred_is_active_cred(vcred)) { + *pflags = 0; + rv = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = vcred; + f = cred->flags; + + /* Update flags if necessary */ + + if (!(f & KCDB_CRED_FLAG_EXPIRED) && + kcdb_cred_buf_exist(cred, KCDB_ATTR_EXPIRE)) { + + FILETIME ftc; + + GetSystemTimeAsFileTime(&ftc); + if (CompareFileTime(&ftc, ((FILETIME *) + kcdb_cred_buf_get(cred, KCDB_ATTR_EXPIRE))) + >= 0) + f |= KCDB_CRED_FLAG_EXPIRED; + } + +#if 0 + /* Commented out: if the credential has expired, then checking the + renewable time is not useful */ + if (!(f & KCDB_CRED_FLAG_INVALID)) { + if (f & KCDB_CRED_FLAG_RENEWABLE) { + if (kcdb_cred_buf_exist(cred, KCDB_ATTR_RENEW_EXPIRE)) { + FILETIME ftc; + + GetSystemTimeAsFileTime(&ftc); + if (CompareFileTime(&ftc, ((FILETIME *) + kcdb_cred_buf_get(cred, KCDB_ATTR_RENEW_EXPIRE))) >= 0) + f |= KCDB_CRED_FLAG_INVALID; + } + } else { + if (f & KCDB_CRED_FLAG_EXPIRED) + f |= KCDB_CRED_FLAG_INVALID; + } + } + + /* Commented out: this is a read operation. We shouldn't attempt + to lock for writing */ + if (f != cred->flags) { + kcdb_cred_unlock_read(); + kcdb_cred_lock_write(); + /* Did we lose a race? */ + if (kcdb_cred_is_active_cred(vcred)) + cred->flags = f; + else { + rv = KHM_ERROR_INVALID_PARAM; + f = 0; + } + kcdb_cred_unlock_write(); + release_lock = FALSE; + } +#endif + + *pflags = f; + + _exit: + if (release_lock) + kcdb_cred_unlock_read(); + + return rv; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_set_flags( + khm_handle vcred, + khm_int32 flags, + khm_int32 mask) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + kcdb_cred * cred; + + kcdb_cred_lock_write(); + if(!kcdb_cred_is_active_cred(vcred)) { + rv = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = vcred; + + flags &= ~(KCDB_CRED_FLAG_DELETED); + mask &= ~(KCDB_CRED_FLAG_DELETED); + + cred->flags = + (cred->flags & (~mask)) | + (flags & mask); + + _exit: + kcdb_cred_unlock_write(); + return rv; +} diff --git a/src/windows/identity/kcreddb/credential.h b/src/windows/identity/kcreddb/credential.h index 9cb70ab4d..49b3953c9 100644 --- a/src/windows/identity/kcreddb/credential.h +++ b/src/windows/identity/kcreddb/credential.h @@ -1,71 +1,71 @@ -/* - * 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_KCDB_CREDENTIAL_H -#define __KHIMAIRA_KCDB_CREDENTIAL_H - -/* Credentials */ - -typedef struct kcdb_cred_t { - khm_int32 magic; - khm_ui_8 id; /* serial number */ - kcdb_identity * identity; - khm_int32 type; - wchar_t * name; - - khm_int32 flags; - khm_int32 refcount; - - kcdb_buf buf; - - LDCL(struct kcdb_cred_t); -} kcdb_cred; - -#define KCDB_CRED_MAGIC 0x38fb84a6 - -extern CRITICAL_SECTION cs_creds; -extern kcdb_cred * kcdb_creds; -extern RWLOCK l_creds; -extern khm_ui_8 kcdb_cred_id; - -#define kcdb_cred_val_exist(c,a) kcdb_buf_val_exist(&(c)->buf, a) -#define kcdb_cred_buf_exist(c,a) kcdb_buf_exist(&(c)->buf, a) -#define kcdb_cred_buf_get(c,a) kcdb_buf_get(&(c)->buf, a) -#define kcdb_cred_buf_size(c,a) kcdb_buf_size(&(c)->buf, a) - -#define kcdb_cred_is_cred(c) ((c) && ((kcdb_cred *) c)->magic == KCDB_CRED_MAGIC) -#define kcdb_cred_is_active_cred(c) (kcdb_cred_is_cred(c) && !(((kcdb_cred *) c)->flags & KCDB_CRED_FLAG_DELETED)) - -#define kcdb_cred_lock_read() (LockObtainRead(&l_creds)) -#define kcdb_cred_unlock_read() (LockReleaseRead(&l_creds)) -#define kcdb_cred_lock_write() (LockObtainWrite(&l_creds)) -#define kcdb_cred_unlock_write() (LockReleaseWrite(&l_creds)) - -void kcdb_cred_init(void); -void kcdb_cred_exit(void); -void kcdb_cred_check_and_delete(khm_handle vcred); - -#endif +/* + * 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_KCDB_CREDENTIAL_H +#define __KHIMAIRA_KCDB_CREDENTIAL_H + +/* Credentials */ + +typedef struct kcdb_cred_t { + khm_int32 magic; + khm_ui_8 id; /* serial number */ + kcdb_identity * identity; + khm_int32 type; + wchar_t * name; + + khm_int32 flags; + khm_int32 refcount; + + kcdb_buf buf; + + LDCL(struct kcdb_cred_t); +} kcdb_cred; + +#define KCDB_CRED_MAGIC 0x38fb84a6 + +extern CRITICAL_SECTION cs_creds; +extern kcdb_cred * kcdb_creds; +extern RWLOCK l_creds; +extern khm_ui_8 kcdb_cred_id; + +#define kcdb_cred_val_exist(c,a) kcdb_buf_val_exist(&(c)->buf, a) +#define kcdb_cred_buf_exist(c,a) kcdb_buf_exist(&(c)->buf, a) +#define kcdb_cred_buf_get(c,a) kcdb_buf_get(&(c)->buf, a) +#define kcdb_cred_buf_size(c,a) kcdb_buf_size(&(c)->buf, a) + +#define kcdb_cred_is_cred(c) ((c) && ((kcdb_cred *) c)->magic == KCDB_CRED_MAGIC) +#define kcdb_cred_is_active_cred(c) (kcdb_cred_is_cred(c) && !(((kcdb_cred *) c)->flags & KCDB_CRED_FLAG_DELETED)) + +#define kcdb_cred_lock_read() (LockObtainRead(&l_creds)) +#define kcdb_cred_unlock_read() (LockReleaseRead(&l_creds)) +#define kcdb_cred_lock_write() (LockObtainWrite(&l_creds)) +#define kcdb_cred_unlock_write() (LockReleaseWrite(&l_creds)) + +void kcdb_cred_init(void); +void kcdb_cred_exit(void); +void kcdb_cred_check_and_delete(khm_handle vcred); + +#endif diff --git a/src/windows/identity/kcreddb/credset.c b/src/windows/identity/kcreddb/credset.c index 2d7eeeb1f..41ca19a46 100644 --- a/src/windows/identity/kcreddb/credset.c +++ b/src/windows/identity/kcreddb/credset.c @@ -1,1177 +1,1177 @@ -/* - * 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 - -CRITICAL_SECTION cs_credset; -kcdb_credset * kcdb_credsets = NULL; -kcdb_credset * kcdb_root_credset = NULL; - -void -kcdb_credset_init(void) -{ - khm_handle rc; - - InitializeCriticalSection(&cs_credset); - kcdb_credsets = NULL; - - kcdb_credset_create(&rc); - kcdb_root_credset = (kcdb_credset *) rc; - kcdb_root_credset->flags |= KCDB_CREDSET_FLAG_ROOT; -} - -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) -{ - cs->clist = PMALLOC(KCDB_CREDSET_INITIAL_SIZE * - sizeof(kcdb_credset_credref)); - ZeroMemory(cs->clist, - KCDB_CREDSET_INITIAL_SIZE * - sizeof(kcdb_credset_credref)); - cs->nc_clist = KCDB_CREDSET_INITIAL_SIZE; - cs->nclist = 0; -} - -/* called on an unreleased credset, or with credset::cs held */ -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) -{ - if(cs->nc_clist < nclist) { - kcdb_credset_credref * new_clist; - - /* nclist had better be greater than KCDB_CREDSET_INITIAL_SIZE */ - nclist = KCDB_CREDSET_INITIAL_SIZE + - (((nclist - (KCDB_CREDSET_INITIAL_SIZE + 1)) / KCDB_CREDSET_GROWTH_FACTOR) + 1) * - KCDB_CREDSET_GROWTH_FACTOR; - - new_clist = PCALLOC(nclist, sizeof(kcdb_credset_credref)); - - memcpy(new_clist, cs->clist, cs->nclist * sizeof(kcdb_credset_credref)); - - PFREE(cs->clist); - - cs->clist = new_clist; - } -} - -KHMEXP khm_int32 KHMAPI -kcdb_credset_create(khm_handle * result) -{ - kcdb_credset * cs; - - cs = PMALLOC(sizeof(kcdb_credset)); - ZeroMemory(cs, sizeof(kcdb_credset)); - - cs->magic = KCDB_CREDSET_MAGIC; - InitializeCriticalSection(&(cs->cs)); - LINIT(cs); - kcdb_credset_buf_new(cs); - cs->version = 0; - cs->seal_count = 0; - - EnterCriticalSection(&cs_credset); - LPUSH(&kcdb_credsets, cs); - LeaveCriticalSection(&cs_credset); - - *result = (khm_handle) cs; - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kcdb_credset_delete(khm_handle vcredset) -{ - kcdb_credset * cs; - int i; - - if(!kcdb_credset_is_credset(vcredset)) { - return KHM_ERROR_INVALID_PARAM; - } - - cs = (kcdb_credset *) vcredset; - - EnterCriticalSection(&cs_credset); - LDELETE(&kcdb_credsets, cs); - LeaveCriticalSection(&cs_credset); - - EnterCriticalSection(&(cs->cs)); - cs->magic = 0; - - for(i=0;inclist;i++) { - if(cs->clist[i].cred) { - kcdb_cred_release((khm_handle) cs->clist[i].cred); - } - } - kcdb_credset_buf_delete(cs); - - LeaveCriticalSection(&(cs->cs)); - DeleteCriticalSection(&(cs->cs)); - - PFREE(cs); - - return KHM_ERROR_SUCCESS; -} - -/*! \internal - -Collect credentials from cs2 to cs1 which have already been selected into -cl1 and cl2. - -- Credentials in cl2 that are not in cl1 will get added to cs1 -- Credentials in cl1 that are not in cl2 will get removed from cs1 -- Credentials in cl1 and cl2 will be updated in cs1 - -cl1 and cl2 will be modified. -*/ -khm_int32 -kcdb_credset_collect_core(kcdb_credset * cs1, - kcdb_cred ** cl1, - khm_int32 ncl1, - kcdb_credset * cs2, - kcdb_cred ** cl2, - khm_int32 ncl2, - khm_int32 * delta) -{ - int i, j; - int ldelta = 0; - khm_int32 rv; - - /* find matching creds and update them */ - for(i=0; ics)); - EnterCriticalSection(&(rcs->cs)); - - /* enumerate through the root and given credential sets and select - the ones we want */ - - if(rcs->nclist > 0) - r_sel = PMALLOC(sizeof(kcdb_cred *) * rcs->nclist); - if(cs->nclist > 0) - c_sel = PMALLOC(sizeof(kcdb_cred *) * cs->nclist); - nr_sel = 0; - nc_sel = 0; - - for(i=0; inclist; i++) { - if(rcs->clist[i].cred && - (!identity || rcs->clist[i].cred->identity == identity) && - (type==KCDB_CREDTYPE_ALL || rcs->clist[i].cred->type == type)) - { - r_sel[nr_sel++] = rcs->clist[i].cred; - } - } - - for(i=0; inclist; i++) { - if(cs->clist[i].cred && - (!identity || cs->clist[i].cred->identity == identity) && - (type==KCDB_CREDTYPE_ALL || cs->clist[i].cred->type == type)) - { - c_sel[nc_sel++] = cs->clist[i].cred; - } - } - - rcs->version++; - - code = kcdb_credset_collect_core( - rcs, - r_sel, - nr_sel, - cs, - c_sel, - nc_sel, - delta); - - LeaveCriticalSection(&(rcs->cs)); - LeaveCriticalSection(&(cs->cs)); - - if(r_sel) - PFREE(r_sel); - if(c_sel) - PFREE(c_sel); - - if (cs_dest == NULL) { - kcdb_identity_refresh_all(); - } - - 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) -{ - kcdb_credset * cs; - kcdb_credset * rcs; - khm_int32 code = KHM_ERROR_SUCCESS; - kcdb_cred ** r_sel = NULL; - kcdb_cred ** c_sel = NULL; - int nr_sel, nc_sel; - int i; - khm_int32 cs_f = 0; - khm_int32 rcs_f = 0; - - if((cs_src && !kcdb_credset_is_credset(cs_src)) || - (cs_dest && !kcdb_credset_is_credset(cs_dest)) || - (cs_src == cs_dest)) /* works because credsets use shared - handles */ - return KHM_ERROR_INVALID_PARAM; - - if(cs_src) - cs = (kcdb_credset *) cs_src; - else { - cs = kcdb_root_credset; - cs_f = KCDB_CREDCOLL_FILTER_ROOT; - } - - if(cs_dest) - rcs = (kcdb_credset *) cs_dest; - else { - rcs = kcdb_root_credset; - rcs_f = KCDB_CREDCOLL_FILTER_ROOT; - } - - if (kcdb_credset_is_sealed(rcs)) - return KHM_ERROR_INVALID_OPERATION; - - EnterCriticalSection(&(cs->cs)); - EnterCriticalSection(&(rcs->cs)); - -#ifdef DEBUG - assert(!(rcs->flags & KCDB_CREDSET_FLAG_ENUM)); - assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); -#endif - - if(rcs->nclist) - r_sel = PMALLOC(sizeof(kcdb_cred *) * rcs->nclist); - if(cs->nclist) - c_sel = PMALLOC(sizeof(kcdb_cred *) * cs->nclist); - nr_sel = 0; - nc_sel = 0; - - rcs->flags |= KCDB_CREDSET_FLAG_ENUM; - - for(i=0; inclist; i++) { - if(rcs->clist[i].cred && - (*filter)((khm_handle)rcs->clist[i].cred, - KCDB_CREDCOLL_FILTER_DEST | rcs_f, - rock)) - { - r_sel[nr_sel++] = rcs->clist[i].cred; - } - } - - rcs->flags &= ~KCDB_CREDSET_FLAG_ENUM; - cs->flags |= KCDB_CREDSET_FLAG_ENUM; - - for(i=0; inclist; i++) { - if(cs->clist[i].cred && filter((khm_handle)rcs->clist[i].cred, KCDB_CREDCOLL_FILTER_SRC | cs_f, rock)) - { - c_sel[nc_sel++] = cs->clist[i].cred; - } - } - - cs->flags &= ~KCDB_CREDSET_FLAG_ENUM; - - rcs->version++; - - code = kcdb_credset_collect_core( - rcs, - r_sel, - nr_sel, - cs, - c_sel, - nc_sel, - delta); - - LeaveCriticalSection(&(rcs->cs)); - LeaveCriticalSection(&(cs->cs)); - - if(r_sel) - PFREE(r_sel); - if(c_sel) - PFREE(c_sel); - - if (cs_dest == NULL) { - kcdb_identity_refresh_all(); - } - - return code; -} - -KHMEXP khm_int32 KHMAPI -kcdb_credset_flush(khm_handle vcredset) -{ - int i; - kcdb_credset * cs; - - if(!kcdb_credset_is_credset(vcredset)) - return KHM_ERROR_INVALID_PARAM; - - cs = (kcdb_credset *) vcredset; - - if (kcdb_credset_is_sealed(cs)) - return KHM_ERROR_INVALID_OPERATION; - - EnterCriticalSection(&(cs->cs)); - -#ifdef DEBUG - assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); -#endif - - for(i=0;inclist;i++) { - if(cs->clist[i].cred) { - kcdb_cred_release((khm_handle) cs->clist[i].cred); - } - } - cs->nclist = 0; - LeaveCriticalSection(&(cs->cs)); - - return KHM_ERROR_SUCCESS; -} - -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; - kcdb_credset * src; - int isRoot = 0; - khm_size srcSize = 0; - int i; - - if(!kcdb_credset_is_credset(destcredset)) - return KHM_ERROR_INVALID_PARAM; - - if(sourcecredset) { - if(!kcdb_credset_is_credset(sourcecredset)) - return KHM_ERROR_INVALID_PARAM; - } else { - sourcecredset = kcdb_root_credset; - } - - if (sourcecredset == kcdb_root_credset) - isRoot = 1; - - src = (kcdb_credset *) sourcecredset; - dest = (kcdb_credset *) destcredset; - - if (kcdb_credset_is_sealed(dest)) - return KHM_ERROR_INVALID_OPERATION; - - EnterCriticalSection(&(src->cs)); - EnterCriticalSection(&(dest->cs)); - -#ifdef DEBUG - assert(!(dest->flags & KCDB_CREDSET_FLAG_ENUM)); -#endif - - if(KHM_FAILED(kcdb_credset_get_size(sourcecredset, &srcSize))) { - code = KHM_ERROR_UNKNOWN; - goto _exit; - } - - kcdb_cred_lock_read(); - - for(i=0; i < (int) srcSize; i++) { - kcdb_cred * c; - - c = src->clist[i].cred; - if(kcdb_cred_is_active_cred((khm_handle) c) && - (!identity || c->identity == identity) && - (type < 0 || c->type == type)) - { - if(isRoot) { - khm_handle newcred; - - kcdb_cred_unlock_read(); - kcdb_cred_dup((khm_handle) c, &newcred); - kcdb_credset_add_cred(destcredset, newcred, -1); - kcdb_cred_release(newcred); - kcdb_cred_lock_read(); - } else { - kcdb_cred_unlock_read(); - kcdb_credset_add_cred(destcredset, (khm_handle) c, -1); - kcdb_cred_lock_read(); - } - } - } - - kcdb_cred_unlock_read(); - -_exit: - LeaveCriticalSection(&(dest->cs)); - LeaveCriticalSection(&(src->cs)); - - return code; -} - -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; - kcdb_credset * src; - int isRoot = 0; - khm_size srcSize = 0; - int i; - - if(!kcdb_credset_is_credset(destcredset)) - return KHM_ERROR_INVALID_PARAM; - - if(sourcecredset) { - if(!kcdb_credset_is_credset(sourcecredset)) - return KHM_ERROR_INVALID_PARAM; - } else { - sourcecredset = kcdb_root_credset; - isRoot = 1; - } - - src = (kcdb_credset *) sourcecredset; - dest = (kcdb_credset *) destcredset; - - if (kcdb_credset_is_sealed(dest)) - return KHM_ERROR_INVALID_OPERATION; - - EnterCriticalSection(&(src->cs)); - EnterCriticalSection(&(dest->cs)); - -#ifdef DEBUG - assert(!(dest->flags & KCDB_CREDSET_FLAG_ENUM)); -#endif - - if(KHM_FAILED(kcdb_credset_get_size(sourcecredset, &srcSize))) { - code = KHM_ERROR_UNKNOWN; - goto _exit; - } - - kcdb_cred_lock_read(); - - dest->flags |= KCDB_CREDSET_FLAG_ENUM; - - for(i=0; i < (int) srcSize; i++) { - kcdb_cred * c; - - c = src->clist[i].cred; - if(kcdb_cred_is_active_cred((khm_handle) c) && - filter(c, 0, rock)) - { - if(isRoot) { - khm_handle newcred; - - kcdb_cred_unlock_read(); - kcdb_cred_dup((khm_handle) c, &newcred); - kcdb_credset_add_cred(destcredset, newcred, -1); - kcdb_cred_release(newcred); - kcdb_cred_lock_read(); - } else { - kcdb_cred_unlock_read(); - kcdb_credset_add_cred(destcredset, (khm_handle) c, -1); - kcdb_cred_lock_read(); - } - } - } - - dest->flags &= ~KCDB_CREDSET_FLAG_ENUM; - - kcdb_cred_unlock_read(); - -_exit: - LeaveCriticalSection(&(dest->cs)); - LeaveCriticalSection(&(src->cs)); - - return code; -} - -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; - int i; - - if(vcredset != NULL && !kcdb_credset_is_credset(vcredset)) - return KHM_ERROR_INVALID_PARAM; - - if(vcredset == NULL) { - cs = kcdb_root_credset; - } else { - cs = (kcdb_credset *) vcredset; - } - - EnterCriticalSection(&cs->cs); - -#ifdef DEBUG - assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); -#endif - - cs->flags |= KCDB_CREDSET_FLAG_ENUM; - - for(i=0; inclist; i++) { - if(!kcdb_cred_is_active_cred(cs->clist[i].cred)) - continue; - - if(KHM_FAILED(f((khm_handle) cs->clist[i].cred, rock))) - break; - } - - cs->flags &= ~KCDB_CREDSET_FLAG_ENUM; - - LeaveCriticalSection(&cs->cs); - - if(inclist) - rv = KHM_ERROR_EXIT; - - return rv; -} - -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; - - if(!kcdb_credset_is_credset(vcredset)) - return KHM_ERROR_INVALID_PARAM; - - cs = (kcdb_credset *) vcredset; - - *cred = NULL; - - EnterCriticalSection(&(cs->cs)); - if(idx < 0 || idx >= cs->nclist) - code = KHM_ERROR_OUT_OF_BOUNDS; - else if(!cs->clist[idx].cred || !kcdb_cred_is_active_cred((khm_handle) cs->clist[idx].cred)) { - code = KHM_ERROR_DELETED; - if(cs->clist[idx].cred) { - kcdb_cred_release((khm_handle) cs->clist[idx].cred); - cs->clist[idx].cred = NULL; - } - } - else { - kcdb_cred_hold((khm_handle) cs->clist[idx].cred); - *cred = cs->clist[idx].cred; - } - LeaveCriticalSection(&(cs->cs)); - 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) -{ - kcdb_credset * cs; - khm_int32 rv = KHM_ERROR_SUCCESS; - int i; - - if((credset && !kcdb_credset_is_credset(credset)) || !f) - return KHM_ERROR_INVALID_PARAM; - - if(credset) - cs = (kcdb_credset *) credset; - else - cs = kcdb_root_credset; - - EnterCriticalSection(&cs->cs); - - if(idx_start < 0) - i = 0; - else - i = idx_start + 1; - -#ifdef DEBUG - assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); -#endif - - cs->flags |= KCDB_CREDSET_FLAG_ENUM; - - for(; i < cs->nclist; i++) { - if(kcdb_cred_is_active_cred(cs->clist[i].cred) && - (*f)((khm_handle) cs->clist[i].cred, 0, rock) != 0) - break; - } - - cs->flags &= ~KCDB_CREDSET_FLAG_ENUM; - - if(i < cs->nclist) { - if (cred) { - *cred = (khm_handle) cs->clist[i].cred; - kcdb_cred_hold(*cred); - } - - if(idx) { - *idx = i; - } - } else { - rv = KHM_ERROR_NOT_FOUND; - } - - LeaveCriticalSection(&cs->cs); - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kcdb_credset_find_cred(khm_handle vcredset, - khm_handle vcred_src, - khm_handle *cred_dest) { - kcdb_credset * cs; - khm_handle cred = NULL; - int idx; - - if (!kcdb_credset_is_credset(vcredset)) - return KHM_ERROR_INVALID_PARAM; - - if (!kcdb_cred_is_active_cred(vcred_src)) - return KHM_ERROR_INVALID_PARAM; - - cs = (kcdb_credset *) vcredset; - - EnterCriticalSection(&cs->cs); - for (idx = 0; idx < cs->nclist; idx++) { - if (cs->clist[idx].cred && - kcdb_creds_is_equal(vcred_src, cs->clist[idx].cred)) { - cred = cs->clist[idx].cred; - break; - } - } - - if (cred) - kcdb_cred_hold(cred); - - LeaveCriticalSection(&cs->cs); - - if (cred) { - if (cred_dest) - *cred_dest = cred; - else - kcdb_cred_release(cred); - - return KHM_ERROR_SUCCESS; - } else { - return KHM_ERROR_NOT_FOUND; - } -} - -KHMEXP khm_int32 KHMAPI -kcdb_credset_del_cred(khm_handle vcredset, - khm_int32 idx) -{ - kcdb_credset * cs; - khm_int32 code = KHM_ERROR_SUCCESS; - - if(!kcdb_credset_is_credset(vcredset)) - return KHM_ERROR_INVALID_PARAM; - - cs = (kcdb_credset *) vcredset; - - if (kcdb_credset_is_sealed(cs)) - return KHM_ERROR_INVALID_OPERATION; - - EnterCriticalSection(&(cs->cs)); - if(idx < 0 || idx >= cs->nclist) { - code = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - if(cs->clist[idx].cred) - kcdb_cred_release((khm_handle) cs->clist[idx].cred); - - if (!(cs->flags & KCDB_CREDSET_FLAG_ENUM)) { - - if(idx + 1 < cs->nclist) - memmove(&(cs->clist[idx]), - &(cs->clist[idx+1]), - sizeof(kcdb_credset_credref) * - (cs->nclist - (idx + 1))); - - cs->nclist--; - } else { - cs->clist[idx].cred = NULL; - } - -_exit: - LeaveCriticalSection(&(cs->cs)); - - return code; -} - -khm_int32 -kcdb_credset_update_cred_ref(khm_handle credset, - khm_handle cred) -{ - kcdb_credset * cs; - khm_int32 code = KHM_ERROR_SUCCESS; - int i; - - if(!kcdb_credset_is_credset(credset)) - return KHM_ERROR_INVALID_PARAM; - - cs = (kcdb_credset *) credset; - - EnterCriticalSection(&(cs->cs)); - - for(i=0; inclist; i++) { - if(cs->clist[i].cred == cred) - break; - } - - if(inclist) { - cs->clist[i].version = cs->version; - } else { - code = KHM_ERROR_NOT_FOUND; - } - - LeaveCriticalSection(&(cs->cs)); - return code; -} - -KHMEXP khm_int32 KHMAPI -kcdb_credset_del_cred_ref(khm_handle credset, - khm_handle cred) -{ - kcdb_credset * cs; - khm_int32 code = KHM_ERROR_SUCCESS; - int i; - - if(!kcdb_credset_is_credset(credset)) - return KHM_ERROR_INVALID_PARAM; - - cs = (kcdb_credset *) credset; - - if (kcdb_credset_is_sealed(cs)) - return KHM_ERROR_INVALID_OPERATION; - - EnterCriticalSection(&(cs->cs)); - - for(i=0; inclist; i++) { - if(cs->clist[i].cred == cred) - break; - } - - if(inclist) { - code = kcdb_credset_del_cred(credset, i); - } else { - code = KHM_ERROR_NOT_FOUND; - } - - LeaveCriticalSection(&(cs->cs)); - return code; -} - -KHMEXP khm_int32 KHMAPI -kcdb_credset_add_cred(khm_handle credset, - khm_handle cred, - khm_int32 idx) -{ - int new_idx; - kcdb_credset * cs; - khm_int32 code = KHM_ERROR_SUCCESS; - - if(!kcdb_credset_is_credset(credset)) - return KHM_ERROR_INVALID_PARAM; - - cs = (kcdb_credset *) credset; - - if (kcdb_credset_is_sealed(cs)) - return KHM_ERROR_INVALID_OPERATION; - - EnterCriticalSection(&(cs->cs)); - - kcdb_credset_buf_assert_size(cs, cs->nclist + 1); - - if(idx < 0 || idx > cs->nclist) - new_idx = cs->nclist; - else if(idx < cs->nclist){ -#ifdef DEBUG - assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); -#endif - memmove(&(cs->clist[idx+1]), &(cs->clist[idx]), (cs->nclist - idx)*sizeof(cs->clist[0])); - new_idx = idx; - } else - new_idx = idx; - - kcdb_cred_hold(cred); - - cs->clist[new_idx].cred = (kcdb_cred *) cred; - cs->clist[new_idx].version = cs->version; - cs->nclist++; - - LeaveCriticalSection(&(cs->cs)); - return code; -} - -KHMEXP khm_int32 KHMAPI -kcdb_credset_get_size(khm_handle credset, - khm_size * size) -{ - kcdb_credset * cs; - - *size = 0; - - /* we don't rely on this working, since we can't purge a sealed - credset, although we can measure its size. */ - kcdb_credset_purge(credset); - - if (credset == NULL) - cs = kcdb_root_credset; - else - cs = (kcdb_credset *) credset; - - EnterCriticalSection(&(cs->cs)); - /* while it may seem a bit redundant to get a lock, it ensures that - that the size that we return is consistent with the current state - of the credential set */ - *size = cs->nclist; - LeaveCriticalSection(&(cs->cs)); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kcdb_credset_purge(khm_handle credset) -{ - khm_int32 code = KHM_ERROR_SUCCESS; - kcdb_credset * cs; - int i,j; - - if(!kcdb_credset_is_credset(credset)) - return KHM_ERROR_INVALID_PARAM; - - cs = (kcdb_credset *) credset; - - if (kcdb_credset_is_sealed(cs)) - return KHM_ERROR_INVALID_OPERATION; - - EnterCriticalSection(&(cs->cs)); - - /* we can't purge a credset while an enumeration operation is in - progress. */ - if (cs->flags & KCDB_CREDSET_FLAG_ENUM) { - code = KHM_ERROR_INVALID_OPERATION; - goto _exit; - } - - for(i=0,j=0; i < cs->nclist; i++) { - if(cs->clist[i].cred) { - if(!kcdb_cred_is_active_cred((khm_handle) cs->clist[i].cred)) { - kcdb_cred_release((khm_handle) cs->clist[i].cred); - } else if(i != j) { - cs->clist[j++] = cs->clist[i]; - } else - j++; - } - } - cs->nclist = j; - - _exit: - LeaveCriticalSection(&(cs->cs)); - return code; -} - -KHMEXP khm_int32 KHMAPI -kcdb_credset_seal(khm_handle credset) { - kcdb_credset * cs; - - if (!kcdb_credset_is_credset(credset)) - return KHM_ERROR_INVALID_PARAM; - - cs = (kcdb_credset *) credset; - - EnterCriticalSection(&cs->cs); - cs->seal_count++; - LeaveCriticalSection(&cs->cs); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kcdb_credset_unseal(khm_handle credset) { - kcdb_credset * cs; - khm_int32 rv; - - if (!kcdb_credset_is_credset(credset)) - return KHM_ERROR_INVALID_PARAM; - - cs = (kcdb_credset *) credset; - - EnterCriticalSection(&cs->cs); - if (cs->seal_count > 0) { - cs->seal_count--; - rv = KHM_ERROR_SUCCESS; - } else { - rv = KHM_ERROR_INVALID_OPERATION; - } - LeaveCriticalSection(&cs->cs); - - return rv; -} - - -/* wrapper for qsort and also parameter gobbling FSM. Access to this - function is serialized via cs_credset. */ -int __cdecl -kcdb_creds_comp_wrapper(const void * a, const void * b) -{ - static void * rock = NULL; - static kcdb_cred_comp_func comp = NULL; - - if(!b) { - rock = (void *) a; - return 0; - } - - if(!a) { - comp = (kcdb_cred_comp_func) b; - return 0; - } - - return comp((khm_handle) ((kcdb_credset_credref *)a)->cred, - (khm_handle) ((kcdb_credset_credref *)b)->cred, - 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; - - if(!kcdb_credset_is_credset(credset)) - return KHM_ERROR_INVALID_PARAM; - - cs = (kcdb_credset *) credset; - - if (kcdb_credset_is_sealed(cs)) - return KHM_ERROR_INVALID_OPERATION; - - EnterCriticalSection(&(cs->cs)); - -#ifdef DEBUG - assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); -#endif - - EnterCriticalSection(&cs_credset); - - 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); - - LeaveCriticalSection(&cs_credset); - - LeaveCriticalSection(&(cs->cs)); - return code; -} - -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; - khm_int32 r = 0; - khm_int32 f1, f2; - khm_int32 t1, t2; - khm_int32 pt; - - for(i=0; inFields; i++) { - if (o->fields[i].order & KCDB_CRED_COMP_INITIAL_FIRST) { - - if (o->fields[i].attrib == KCDB_ATTR_TYPE_NAME || - o->fields[i].attrib == KCDB_ATTR_TYPE) { - - kcdb_cred_get_type(cred1, &t1); - kcdb_cred_get_type(cred2, &t2); - kcdb_identity_get_type(&pt); - - if (t1 == t2) - r = 0; - else if (t1 == pt) - r = -1; - else if (t2 == pt) - r = 1; - else - r = 0; - - } else { - - kcdb_cred_get_flags(cred1, &f1); - kcdb_cred_get_flags(cred2, &f2); - - if (((f1 ^ f2) & KCDB_CRED_FLAG_INITIAL) == 0) - r = 0; - else if (f1 & KCDB_CRED_FLAG_INITIAL) - r = -1; - else - r = 1; - - } - - } else { - r = 0; - } - - if (r == 0) - r = kcdb_creds_comp_attr(cred1,cred2,o->fields[i].attrib); - - if(r != 0) { - if(o->fields[i].order & KCDB_CRED_COMP_DECREASING) - r = -r; - break; - } - } - - return r; -} +/* + * 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 + +CRITICAL_SECTION cs_credset; +kcdb_credset * kcdb_credsets = NULL; +kcdb_credset * kcdb_root_credset = NULL; + +void +kcdb_credset_init(void) +{ + khm_handle rc; + + InitializeCriticalSection(&cs_credset); + kcdb_credsets = NULL; + + kcdb_credset_create(&rc); + kcdb_root_credset = (kcdb_credset *) rc; + kcdb_root_credset->flags |= KCDB_CREDSET_FLAG_ROOT; +} + +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) +{ + cs->clist = PMALLOC(KCDB_CREDSET_INITIAL_SIZE * + sizeof(kcdb_credset_credref)); + ZeroMemory(cs->clist, + KCDB_CREDSET_INITIAL_SIZE * + sizeof(kcdb_credset_credref)); + cs->nc_clist = KCDB_CREDSET_INITIAL_SIZE; + cs->nclist = 0; +} + +/* called on an unreleased credset, or with credset::cs held */ +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) +{ + if(cs->nc_clist < nclist) { + kcdb_credset_credref * new_clist; + + /* nclist had better be greater than KCDB_CREDSET_INITIAL_SIZE */ + nclist = KCDB_CREDSET_INITIAL_SIZE + + (((nclist - (KCDB_CREDSET_INITIAL_SIZE + 1)) / KCDB_CREDSET_GROWTH_FACTOR) + 1) * + KCDB_CREDSET_GROWTH_FACTOR; + + new_clist = PCALLOC(nclist, sizeof(kcdb_credset_credref)); + + memcpy(new_clist, cs->clist, cs->nclist * sizeof(kcdb_credset_credref)); + + PFREE(cs->clist); + + cs->clist = new_clist; + } +} + +KHMEXP khm_int32 KHMAPI +kcdb_credset_create(khm_handle * result) +{ + kcdb_credset * cs; + + cs = PMALLOC(sizeof(kcdb_credset)); + ZeroMemory(cs, sizeof(kcdb_credset)); + + cs->magic = KCDB_CREDSET_MAGIC; + InitializeCriticalSection(&(cs->cs)); + LINIT(cs); + kcdb_credset_buf_new(cs); + cs->version = 0; + cs->seal_count = 0; + + EnterCriticalSection(&cs_credset); + LPUSH(&kcdb_credsets, cs); + LeaveCriticalSection(&cs_credset); + + *result = (khm_handle) cs; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_credset_delete(khm_handle vcredset) +{ + kcdb_credset * cs; + int i; + + if(!kcdb_credset_is_credset(vcredset)) { + return KHM_ERROR_INVALID_PARAM; + } + + cs = (kcdb_credset *) vcredset; + + EnterCriticalSection(&cs_credset); + LDELETE(&kcdb_credsets, cs); + LeaveCriticalSection(&cs_credset); + + EnterCriticalSection(&(cs->cs)); + cs->magic = 0; + + for(i=0;inclist;i++) { + if(cs->clist[i].cred) { + kcdb_cred_release((khm_handle) cs->clist[i].cred); + } + } + kcdb_credset_buf_delete(cs); + + LeaveCriticalSection(&(cs->cs)); + DeleteCriticalSection(&(cs->cs)); + + PFREE(cs); + + return KHM_ERROR_SUCCESS; +} + +/*! \internal + +Collect credentials from cs2 to cs1 which have already been selected into +cl1 and cl2. + +- Credentials in cl2 that are not in cl1 will get added to cs1 +- Credentials in cl1 that are not in cl2 will get removed from cs1 +- Credentials in cl1 and cl2 will be updated in cs1 + +cl1 and cl2 will be modified. +*/ +khm_int32 +kcdb_credset_collect_core(kcdb_credset * cs1, + kcdb_cred ** cl1, + khm_int32 ncl1, + kcdb_credset * cs2, + kcdb_cred ** cl2, + khm_int32 ncl2, + khm_int32 * delta) +{ + int i, j; + int ldelta = 0; + khm_int32 rv; + + /* find matching creds and update them */ + for(i=0; ics)); + EnterCriticalSection(&(rcs->cs)); + + /* enumerate through the root and given credential sets and select + the ones we want */ + + if(rcs->nclist > 0) + r_sel = PMALLOC(sizeof(kcdb_cred *) * rcs->nclist); + if(cs->nclist > 0) + c_sel = PMALLOC(sizeof(kcdb_cred *) * cs->nclist); + nr_sel = 0; + nc_sel = 0; + + for(i=0; inclist; i++) { + if(rcs->clist[i].cred && + (!identity || rcs->clist[i].cred->identity == identity) && + (type==KCDB_CREDTYPE_ALL || rcs->clist[i].cred->type == type)) + { + r_sel[nr_sel++] = rcs->clist[i].cred; + } + } + + for(i=0; inclist; i++) { + if(cs->clist[i].cred && + (!identity || cs->clist[i].cred->identity == identity) && + (type==KCDB_CREDTYPE_ALL || cs->clist[i].cred->type == type)) + { + c_sel[nc_sel++] = cs->clist[i].cred; + } + } + + rcs->version++; + + code = kcdb_credset_collect_core( + rcs, + r_sel, + nr_sel, + cs, + c_sel, + nc_sel, + delta); + + LeaveCriticalSection(&(rcs->cs)); + LeaveCriticalSection(&(cs->cs)); + + if(r_sel) + PFREE(r_sel); + if(c_sel) + PFREE(c_sel); + + if (cs_dest == NULL) { + kcdb_identity_refresh_all(); + } + + 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) +{ + kcdb_credset * cs; + kcdb_credset * rcs; + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred ** r_sel = NULL; + kcdb_cred ** c_sel = NULL; + int nr_sel, nc_sel; + int i; + khm_int32 cs_f = 0; + khm_int32 rcs_f = 0; + + if((cs_src && !kcdb_credset_is_credset(cs_src)) || + (cs_dest && !kcdb_credset_is_credset(cs_dest)) || + (cs_src == cs_dest)) /* works because credsets use shared + handles */ + return KHM_ERROR_INVALID_PARAM; + + if(cs_src) + cs = (kcdb_credset *) cs_src; + else { + cs = kcdb_root_credset; + cs_f = KCDB_CREDCOLL_FILTER_ROOT; + } + + if(cs_dest) + rcs = (kcdb_credset *) cs_dest; + else { + rcs = kcdb_root_credset; + rcs_f = KCDB_CREDCOLL_FILTER_ROOT; + } + + if (kcdb_credset_is_sealed(rcs)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(cs->cs)); + EnterCriticalSection(&(rcs->cs)); + +#ifdef DEBUG + assert(!(rcs->flags & KCDB_CREDSET_FLAG_ENUM)); + assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); +#endif + + if(rcs->nclist) + r_sel = PMALLOC(sizeof(kcdb_cred *) * rcs->nclist); + if(cs->nclist) + c_sel = PMALLOC(sizeof(kcdb_cred *) * cs->nclist); + nr_sel = 0; + nc_sel = 0; + + rcs->flags |= KCDB_CREDSET_FLAG_ENUM; + + for(i=0; inclist; i++) { + if(rcs->clist[i].cred && + (*filter)((khm_handle)rcs->clist[i].cred, + KCDB_CREDCOLL_FILTER_DEST | rcs_f, + rock)) + { + r_sel[nr_sel++] = rcs->clist[i].cred; + } + } + + rcs->flags &= ~KCDB_CREDSET_FLAG_ENUM; + cs->flags |= KCDB_CREDSET_FLAG_ENUM; + + for(i=0; inclist; i++) { + if(cs->clist[i].cred && filter((khm_handle)rcs->clist[i].cred, KCDB_CREDCOLL_FILTER_SRC | cs_f, rock)) + { + c_sel[nc_sel++] = cs->clist[i].cred; + } + } + + cs->flags &= ~KCDB_CREDSET_FLAG_ENUM; + + rcs->version++; + + code = kcdb_credset_collect_core( + rcs, + r_sel, + nr_sel, + cs, + c_sel, + nc_sel, + delta); + + LeaveCriticalSection(&(rcs->cs)); + LeaveCriticalSection(&(cs->cs)); + + if(r_sel) + PFREE(r_sel); + if(c_sel) + PFREE(c_sel); + + if (cs_dest == NULL) { + kcdb_identity_refresh_all(); + } + + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_credset_flush(khm_handle vcredset) +{ + int i; + kcdb_credset * cs; + + if(!kcdb_credset_is_credset(vcredset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) vcredset; + + if (kcdb_credset_is_sealed(cs)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(cs->cs)); + +#ifdef DEBUG + assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); +#endif + + for(i=0;inclist;i++) { + if(cs->clist[i].cred) { + kcdb_cred_release((khm_handle) cs->clist[i].cred); + } + } + cs->nclist = 0; + LeaveCriticalSection(&(cs->cs)); + + return KHM_ERROR_SUCCESS; +} + +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; + kcdb_credset * src; + int isRoot = 0; + khm_size srcSize = 0; + int i; + + if(!kcdb_credset_is_credset(destcredset)) + return KHM_ERROR_INVALID_PARAM; + + if(sourcecredset) { + if(!kcdb_credset_is_credset(sourcecredset)) + return KHM_ERROR_INVALID_PARAM; + } else { + sourcecredset = kcdb_root_credset; + } + + if (sourcecredset == kcdb_root_credset) + isRoot = 1; + + src = (kcdb_credset *) sourcecredset; + dest = (kcdb_credset *) destcredset; + + if (kcdb_credset_is_sealed(dest)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(src->cs)); + EnterCriticalSection(&(dest->cs)); + +#ifdef DEBUG + assert(!(dest->flags & KCDB_CREDSET_FLAG_ENUM)); +#endif + + if(KHM_FAILED(kcdb_credset_get_size(sourcecredset, &srcSize))) { + code = KHM_ERROR_UNKNOWN; + goto _exit; + } + + kcdb_cred_lock_read(); + + for(i=0; i < (int) srcSize; i++) { + kcdb_cred * c; + + c = src->clist[i].cred; + if(kcdb_cred_is_active_cred((khm_handle) c) && + (!identity || c->identity == identity) && + (type < 0 || c->type == type)) + { + if(isRoot) { + khm_handle newcred; + + kcdb_cred_unlock_read(); + kcdb_cred_dup((khm_handle) c, &newcred); + kcdb_credset_add_cred(destcredset, newcred, -1); + kcdb_cred_release(newcred); + kcdb_cred_lock_read(); + } else { + kcdb_cred_unlock_read(); + kcdb_credset_add_cred(destcredset, (khm_handle) c, -1); + kcdb_cred_lock_read(); + } + } + } + + kcdb_cred_unlock_read(); + +_exit: + LeaveCriticalSection(&(dest->cs)); + LeaveCriticalSection(&(src->cs)); + + return code; +} + +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; + kcdb_credset * src; + int isRoot = 0; + khm_size srcSize = 0; + int i; + + if(!kcdb_credset_is_credset(destcredset)) + return KHM_ERROR_INVALID_PARAM; + + if(sourcecredset) { + if(!kcdb_credset_is_credset(sourcecredset)) + return KHM_ERROR_INVALID_PARAM; + } else { + sourcecredset = kcdb_root_credset; + isRoot = 1; + } + + src = (kcdb_credset *) sourcecredset; + dest = (kcdb_credset *) destcredset; + + if (kcdb_credset_is_sealed(dest)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(src->cs)); + EnterCriticalSection(&(dest->cs)); + +#ifdef DEBUG + assert(!(dest->flags & KCDB_CREDSET_FLAG_ENUM)); +#endif + + if(KHM_FAILED(kcdb_credset_get_size(sourcecredset, &srcSize))) { + code = KHM_ERROR_UNKNOWN; + goto _exit; + } + + kcdb_cred_lock_read(); + + dest->flags |= KCDB_CREDSET_FLAG_ENUM; + + for(i=0; i < (int) srcSize; i++) { + kcdb_cred * c; + + c = src->clist[i].cred; + if(kcdb_cred_is_active_cred((khm_handle) c) && + filter(c, 0, rock)) + { + if(isRoot) { + khm_handle newcred; + + kcdb_cred_unlock_read(); + kcdb_cred_dup((khm_handle) c, &newcred); + kcdb_credset_add_cred(destcredset, newcred, -1); + kcdb_cred_release(newcred); + kcdb_cred_lock_read(); + } else { + kcdb_cred_unlock_read(); + kcdb_credset_add_cred(destcredset, (khm_handle) c, -1); + kcdb_cred_lock_read(); + } + } + } + + dest->flags &= ~KCDB_CREDSET_FLAG_ENUM; + + kcdb_cred_unlock_read(); + +_exit: + LeaveCriticalSection(&(dest->cs)); + LeaveCriticalSection(&(src->cs)); + + return code; +} + +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; + int i; + + if(vcredset != NULL && !kcdb_credset_is_credset(vcredset)) + return KHM_ERROR_INVALID_PARAM; + + if(vcredset == NULL) { + cs = kcdb_root_credset; + } else { + cs = (kcdb_credset *) vcredset; + } + + EnterCriticalSection(&cs->cs); + +#ifdef DEBUG + assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); +#endif + + cs->flags |= KCDB_CREDSET_FLAG_ENUM; + + for(i=0; inclist; i++) { + if(!kcdb_cred_is_active_cred(cs->clist[i].cred)) + continue; + + if(KHM_FAILED(f((khm_handle) cs->clist[i].cred, rock))) + break; + } + + cs->flags &= ~KCDB_CREDSET_FLAG_ENUM; + + LeaveCriticalSection(&cs->cs); + + if(inclist) + rv = KHM_ERROR_EXIT; + + return rv; +} + +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; + + if(!kcdb_credset_is_credset(vcredset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) vcredset; + + *cred = NULL; + + EnterCriticalSection(&(cs->cs)); + if(idx < 0 || idx >= cs->nclist) + code = KHM_ERROR_OUT_OF_BOUNDS; + else if(!cs->clist[idx].cred || !kcdb_cred_is_active_cred((khm_handle) cs->clist[idx].cred)) { + code = KHM_ERROR_DELETED; + if(cs->clist[idx].cred) { + kcdb_cred_release((khm_handle) cs->clist[idx].cred); + cs->clist[idx].cred = NULL; + } + } + else { + kcdb_cred_hold((khm_handle) cs->clist[idx].cred); + *cred = cs->clist[idx].cred; + } + LeaveCriticalSection(&(cs->cs)); + 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) +{ + kcdb_credset * cs; + khm_int32 rv = KHM_ERROR_SUCCESS; + int i; + + if((credset && !kcdb_credset_is_credset(credset)) || !f) + return KHM_ERROR_INVALID_PARAM; + + if(credset) + cs = (kcdb_credset *) credset; + else + cs = kcdb_root_credset; + + EnterCriticalSection(&cs->cs); + + if(idx_start < 0) + i = 0; + else + i = idx_start + 1; + +#ifdef DEBUG + assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); +#endif + + cs->flags |= KCDB_CREDSET_FLAG_ENUM; + + for(; i < cs->nclist; i++) { + if(kcdb_cred_is_active_cred(cs->clist[i].cred) && + (*f)((khm_handle) cs->clist[i].cred, 0, rock) != 0) + break; + } + + cs->flags &= ~KCDB_CREDSET_FLAG_ENUM; + + if(i < cs->nclist) { + if (cred) { + *cred = (khm_handle) cs->clist[i].cred; + kcdb_cred_hold(*cred); + } + + if(idx) { + *idx = i; + } + } else { + rv = KHM_ERROR_NOT_FOUND; + } + + LeaveCriticalSection(&cs->cs); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_credset_find_cred(khm_handle vcredset, + khm_handle vcred_src, + khm_handle *cred_dest) { + kcdb_credset * cs; + khm_handle cred = NULL; + int idx; + + if (!kcdb_credset_is_credset(vcredset)) + return KHM_ERROR_INVALID_PARAM; + + if (!kcdb_cred_is_active_cred(vcred_src)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) vcredset; + + EnterCriticalSection(&cs->cs); + for (idx = 0; idx < cs->nclist; idx++) { + if (cs->clist[idx].cred && + kcdb_creds_is_equal(vcred_src, cs->clist[idx].cred)) { + cred = cs->clist[idx].cred; + break; + } + } + + if (cred) + kcdb_cred_hold(cred); + + LeaveCriticalSection(&cs->cs); + + if (cred) { + if (cred_dest) + *cred_dest = cred; + else + kcdb_cred_release(cred); + + return KHM_ERROR_SUCCESS; + } else { + return KHM_ERROR_NOT_FOUND; + } +} + +KHMEXP khm_int32 KHMAPI +kcdb_credset_del_cred(khm_handle vcredset, + khm_int32 idx) +{ + kcdb_credset * cs; + khm_int32 code = KHM_ERROR_SUCCESS; + + if(!kcdb_credset_is_credset(vcredset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) vcredset; + + if (kcdb_credset_is_sealed(cs)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(cs->cs)); + if(idx < 0 || idx >= cs->nclist) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + if(cs->clist[idx].cred) + kcdb_cred_release((khm_handle) cs->clist[idx].cred); + + if (!(cs->flags & KCDB_CREDSET_FLAG_ENUM)) { + + if(idx + 1 < cs->nclist) + memmove(&(cs->clist[idx]), + &(cs->clist[idx+1]), + sizeof(kcdb_credset_credref) * + (cs->nclist - (idx + 1))); + + cs->nclist--; + } else { + cs->clist[idx].cred = NULL; + } + +_exit: + LeaveCriticalSection(&(cs->cs)); + + return code; +} + +khm_int32 +kcdb_credset_update_cred_ref(khm_handle credset, + khm_handle cred) +{ + kcdb_credset * cs; + khm_int32 code = KHM_ERROR_SUCCESS; + int i; + + if(!kcdb_credset_is_credset(credset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) credset; + + EnterCriticalSection(&(cs->cs)); + + for(i=0; inclist; i++) { + if(cs->clist[i].cred == cred) + break; + } + + if(inclist) { + cs->clist[i].version = cs->version; + } else { + code = KHM_ERROR_NOT_FOUND; + } + + LeaveCriticalSection(&(cs->cs)); + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_credset_del_cred_ref(khm_handle credset, + khm_handle cred) +{ + kcdb_credset * cs; + khm_int32 code = KHM_ERROR_SUCCESS; + int i; + + if(!kcdb_credset_is_credset(credset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) credset; + + if (kcdb_credset_is_sealed(cs)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(cs->cs)); + + for(i=0; inclist; i++) { + if(cs->clist[i].cred == cred) + break; + } + + if(inclist) { + code = kcdb_credset_del_cred(credset, i); + } else { + code = KHM_ERROR_NOT_FOUND; + } + + LeaveCriticalSection(&(cs->cs)); + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_credset_add_cred(khm_handle credset, + khm_handle cred, + khm_int32 idx) +{ + int new_idx; + kcdb_credset * cs; + khm_int32 code = KHM_ERROR_SUCCESS; + + if(!kcdb_credset_is_credset(credset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) credset; + + if (kcdb_credset_is_sealed(cs)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(cs->cs)); + + kcdb_credset_buf_assert_size(cs, cs->nclist + 1); + + if(idx < 0 || idx > cs->nclist) + new_idx = cs->nclist; + else if(idx < cs->nclist){ +#ifdef DEBUG + assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); +#endif + memmove(&(cs->clist[idx+1]), &(cs->clist[idx]), (cs->nclist - idx)*sizeof(cs->clist[0])); + new_idx = idx; + } else + new_idx = idx; + + kcdb_cred_hold(cred); + + cs->clist[new_idx].cred = (kcdb_cred *) cred; + cs->clist[new_idx].version = cs->version; + cs->nclist++; + + LeaveCriticalSection(&(cs->cs)); + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_credset_get_size(khm_handle credset, + khm_size * size) +{ + kcdb_credset * cs; + + *size = 0; + + /* we don't rely on this working, since we can't purge a sealed + credset, although we can measure its size. */ + kcdb_credset_purge(credset); + + if (credset == NULL) + cs = kcdb_root_credset; + else + cs = (kcdb_credset *) credset; + + EnterCriticalSection(&(cs->cs)); + /* while it may seem a bit redundant to get a lock, it ensures that + that the size that we return is consistent with the current state + of the credential set */ + *size = cs->nclist; + LeaveCriticalSection(&(cs->cs)); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_credset_purge(khm_handle credset) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_credset * cs; + int i,j; + + if(!kcdb_credset_is_credset(credset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) credset; + + if (kcdb_credset_is_sealed(cs)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(cs->cs)); + + /* we can't purge a credset while an enumeration operation is in + progress. */ + if (cs->flags & KCDB_CREDSET_FLAG_ENUM) { + code = KHM_ERROR_INVALID_OPERATION; + goto _exit; + } + + for(i=0,j=0; i < cs->nclist; i++) { + if(cs->clist[i].cred) { + if(!kcdb_cred_is_active_cred((khm_handle) cs->clist[i].cred)) { + kcdb_cred_release((khm_handle) cs->clist[i].cred); + } else if(i != j) { + cs->clist[j++] = cs->clist[i]; + } else + j++; + } + } + cs->nclist = j; + + _exit: + LeaveCriticalSection(&(cs->cs)); + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_credset_seal(khm_handle credset) { + kcdb_credset * cs; + + if (!kcdb_credset_is_credset(credset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) credset; + + EnterCriticalSection(&cs->cs); + cs->seal_count++; + LeaveCriticalSection(&cs->cs); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_credset_unseal(khm_handle credset) { + kcdb_credset * cs; + khm_int32 rv; + + if (!kcdb_credset_is_credset(credset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) credset; + + EnterCriticalSection(&cs->cs); + if (cs->seal_count > 0) { + cs->seal_count--; + rv = KHM_ERROR_SUCCESS; + } else { + rv = KHM_ERROR_INVALID_OPERATION; + } + LeaveCriticalSection(&cs->cs); + + return rv; +} + + +/* wrapper for qsort and also parameter gobbling FSM. Access to this + function is serialized via cs_credset. */ +int __cdecl +kcdb_creds_comp_wrapper(const void * a, const void * b) +{ + static void * rock = NULL; + static kcdb_cred_comp_func comp = NULL; + + if(!b) { + rock = (void *) a; + return 0; + } + + if(!a) { + comp = (kcdb_cred_comp_func) b; + return 0; + } + + return comp((khm_handle) ((kcdb_credset_credref *)a)->cred, + (khm_handle) ((kcdb_credset_credref *)b)->cred, + 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; + + if(!kcdb_credset_is_credset(credset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) credset; + + if (kcdb_credset_is_sealed(cs)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(cs->cs)); + +#ifdef DEBUG + assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); +#endif + + EnterCriticalSection(&cs_credset); + + 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); + + LeaveCriticalSection(&cs_credset); + + LeaveCriticalSection(&(cs->cs)); + return code; +} + +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; + khm_int32 r = 0; + khm_int32 f1, f2; + khm_int32 t1, t2; + khm_int32 pt; + + for(i=0; inFields; i++) { + if (o->fields[i].order & KCDB_CRED_COMP_INITIAL_FIRST) { + + if (o->fields[i].attrib == KCDB_ATTR_TYPE_NAME || + o->fields[i].attrib == KCDB_ATTR_TYPE) { + + kcdb_cred_get_type(cred1, &t1); + kcdb_cred_get_type(cred2, &t2); + kcdb_identity_get_type(&pt); + + if (t1 == t2) + r = 0; + else if (t1 == pt) + r = -1; + else if (t2 == pt) + r = 1; + else + r = 0; + + } else { + + kcdb_cred_get_flags(cred1, &f1); + kcdb_cred_get_flags(cred2, &f2); + + if (((f1 ^ f2) & KCDB_CRED_FLAG_INITIAL) == 0) + r = 0; + else if (f1 & KCDB_CRED_FLAG_INITIAL) + r = -1; + else + r = 1; + + } + + } else { + r = 0; + } + + if (r == 0) + r = kcdb_creds_comp_attr(cred1,cred2,o->fields[i].attrib); + + if(r != 0) { + if(o->fields[i].order & KCDB_CRED_COMP_DECREASING) + r = -r; + break; + } + } + + return r; +} diff --git a/src/windows/identity/kcreddb/credset.h b/src/windows/identity/kcreddb/credset.h index cd216fdd2..ba8ec419e 100644 --- a/src/windows/identity/kcreddb/credset.h +++ b/src/windows/identity/kcreddb/credset.h @@ -1,75 +1,75 @@ -/* - * 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_KCDB_CREDSET_H -#define __KHIMAIRA_KCDB_CREDSET_H - -/* credset */ - -typedef struct kcdb_credset_credref_t { - khm_int32 version; - kcdb_cred * cred; -} kcdb_credset_credref; - -typedef struct kcdb_credset_t { - khm_int32 magic; - khm_int32 flags; - CRITICAL_SECTION cs; - - kcdb_credset_credref * clist; - khm_int32 nc_clist; /* total capacity */ - khm_int32 nclist; /* current load */ - - khm_int32 version; /* data version */ - - khm_int32 seal_count; /* number of seals applied to the - credset */ - - struct kcdb_credset_t * next; - struct kcdb_credset_t * prev; -} kcdb_credset; - -#define KCDB_CREDSET_MAGIC 0x63a84f8b - -#define KCDB_CREDSET_FLAG_ROOT 1 - -/* the credset is in the process of being enumerated */ -#define KCDB_CREDSET_FLAG_ENUM 2 - -#define kcdb_credset_is_credset(c) ((c) && ((kcdb_credset *)c)->magic == KCDB_CREDSET_MAGIC) - -#define kcdb_credset_is_sealed(c) ((c)->seal_count != 0) - -#define KCDB_CREDSET_INITIAL_SIZE 256 -#define KCDB_CREDSET_GROWTH_FACTOR 256 - -void kcdb_credset_init(void); -void kcdb_credset_exit(void); -khm_int32 kcdb_credset_update_cred_ref( - khm_handle credset, - khm_handle cred); - -#endif +/* + * 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_KCDB_CREDSET_H +#define __KHIMAIRA_KCDB_CREDSET_H + +/* credset */ + +typedef struct kcdb_credset_credref_t { + khm_int32 version; + kcdb_cred * cred; +} kcdb_credset_credref; + +typedef struct kcdb_credset_t { + khm_int32 magic; + khm_int32 flags; + CRITICAL_SECTION cs; + + kcdb_credset_credref * clist; + khm_int32 nc_clist; /* total capacity */ + khm_int32 nclist; /* current load */ + + khm_int32 version; /* data version */ + + khm_int32 seal_count; /* number of seals applied to the + credset */ + + struct kcdb_credset_t * next; + struct kcdb_credset_t * prev; +} kcdb_credset; + +#define KCDB_CREDSET_MAGIC 0x63a84f8b + +#define KCDB_CREDSET_FLAG_ROOT 1 + +/* the credset is in the process of being enumerated */ +#define KCDB_CREDSET_FLAG_ENUM 2 + +#define kcdb_credset_is_credset(c) ((c) && ((kcdb_credset *)c)->magic == KCDB_CREDSET_MAGIC) + +#define kcdb_credset_is_sealed(c) ((c)->seal_count != 0) + +#define KCDB_CREDSET_INITIAL_SIZE 256 +#define KCDB_CREDSET_GROWTH_FACTOR 256 + +void kcdb_credset_init(void); +void kcdb_credset_exit(void); +khm_int32 kcdb_credset_update_cred_ref( + khm_handle credset, + khm_handle cred); + +#endif diff --git a/src/windows/identity/kcreddb/credtype.c b/src/windows/identity/kcreddb/credtype.c index 89bd26b85..b88852cfc 100644 --- a/src/windows/identity/kcreddb/credtype.c +++ b/src/windows/identity/kcreddb/credtype.c @@ -1,408 +1,408 @@ -/* - * 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 - -CRITICAL_SECTION cs_credtype; -kcdb_credtype_i ** kcdb_credtype_tbl = NULL; -kcdb_credtype_i * kcdb_credtypes = NULL; - -void kcdb_credtype_init(void) -{ - InitializeCriticalSection(&cs_credtype); - kcdb_credtypes = NULL; - - kcdb_credtype_tbl = PMALLOC(sizeof(kcdb_credtype_i *) * (KCDB_CREDTYPE_MAX_ID+1)); - ZeroMemory(kcdb_credtype_tbl, sizeof(kcdb_credtype_i *) * (KCDB_CREDTYPE_MAX_ID+1)); -} - -void kcdb_credtype_exit(void) -{ - /*TODO:Free up the cred types */ - PFREE(kcdb_credtype_tbl); - DeleteCriticalSection(&cs_credtype); -} - -/* Called with cs_credtype held */ -void kcdb_credtype_check_and_delete(khm_int32 id) -{ - kcdb_credtype_i * ict; - ict = kcdb_credtype_tbl[id]; - if(!ict) - return; - - if((ict->flags & KCDB_CTI_FLAG_DELETED) && - !ict->refcount) - { - kcdb_credtype_tbl[id] = NULL; - LDELETE(&kcdb_credtypes, ict); - - PFREE(ict->ct.name); - if(ict->ct.short_desc) - PFREE(ict->ct.short_desc); - if(ict->ct.long_desc) - PFREE(ict->ct.long_desc); - if(ict->ct.sub) - kmq_delete_subscription(ict->ct.sub); - - PFREE(ict); - } -} - -KHMEXP khm_int32 KHMAPI -kcdb_credtype_register(const kcdb_credtype * type, khm_int32 * new_id) -{ - khm_int32 id; - kcdb_credtype_i * ict; - size_t cb_name; - size_t cb_short_desc; - size_t cb_long_desc; - int i; - - if(!type) - return KHM_ERROR_INVALID_PARAM; - - if(type->id >= KCDB_CREDTYPE_MAX_ID) - return KHM_ERROR_INVALID_PARAM; - - if(type->name) { - if(FAILED(StringCbLength(type->name, KCDB_MAXCB_NAME, &cb_name))) - return KHM_ERROR_TOO_LONG; - cb_name += sizeof(wchar_t); - } else - return KHM_ERROR_INVALID_PARAM; - - if(type->short_desc) { - if(FAILED(StringCbLength(type->short_desc, KCDB_MAXCB_SHORT_DESC, &cb_short_desc))) - return KHM_ERROR_TOO_LONG; - cb_short_desc += sizeof(wchar_t); - } else - cb_short_desc = 0; - - if(type->long_desc) { - if(FAILED(StringCbLength(type->long_desc, KCDB_MAXCB_LONG_DESC, &cb_long_desc))) - return KHM_ERROR_TOO_LONG; - cb_long_desc += sizeof(wchar_t); - } else - cb_long_desc = 0; - - if(type->sub == NULL) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_credtype); - - if(type->id < 0) { - if(KHM_FAILED(kcdb_credtype_get_next_free_id(&id))) { - LeaveCriticalSection(&cs_credtype); - return KHM_ERROR_NO_RESOURCES; - } - } - else - id = type->id; - - if(kcdb_credtype_tbl[id]) { - LeaveCriticalSection(&cs_credtype); - return KHM_ERROR_DUPLICATE; - } - - for(i=0;i<=KCDB_CREDTYPE_MAX_ID;i++) { - if(kcdb_credtype_tbl[i] && !wcscmp(kcdb_credtype_tbl[i]->ct.name, type->name)) { - LeaveCriticalSection(&cs_credtype); - return KHM_ERROR_DUPLICATE; - } - } - - ict = PMALLOC(sizeof(kcdb_credtype_i)); - ZeroMemory(ict, sizeof(kcdb_credtype_i)); - - ict->ct.name = PMALLOC(cb_name); - StringCbCopy(ict->ct.name, cb_name, type->name); - - if(cb_short_desc) { - ict->ct.short_desc = PMALLOC(cb_short_desc); - StringCbCopy(ict->ct.short_desc, cb_short_desc, type->short_desc); - } - - if(cb_long_desc) { - ict->ct.long_desc = PMALLOC(cb_long_desc); - StringCbCopy(ict->ct.long_desc, cb_long_desc, type->long_desc); - } - - ict->ct.id = id; - - ict->ct.icon = type->icon; - - ict->ct.sub = type->sub; - - ict->ct.is_equal = type->is_equal; - - kcdb_credtype_tbl[id] = ict; - - LPUSH(&kcdb_credtypes, ict); - - LeaveCriticalSection(&cs_credtype); - - kcdb_credtype_post_message(KCDB_OP_INSERT, &(ict->ct)); - - if (new_id) - *new_id = id; - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI kcdb_credtype_get_info( - khm_int32 id, - kcdb_credtype ** type) -{ - int found = 0; - - if(id < 0 || id > KCDB_CREDTYPE_MAX_ID) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_credtype); - if(kcdb_credtype_tbl[id] && - !(kcdb_credtype_tbl[id]->flags & KCDB_CTI_FLAG_DELETED)) - { - found = 1; - if(type) { - *type = &(kcdb_credtype_tbl[id]->ct); - kcdb_credtype_hold(kcdb_credtype_tbl[id]); - } - } else { - if(type) - *type = NULL; - } - LeaveCriticalSection(&cs_credtype); - - if(found) - return KHM_ERROR_SUCCESS; - else - return KHM_ERROR_NOT_FOUND; -} - -KHMEXP khm_int32 KHMAPI kcdb_credtype_release_info(kcdb_credtype * type) -{ - kcdb_credtype_i * ict; - - if(!type) - return KHM_ERROR_INVALID_PARAM; - - ict = (kcdb_credtype_i *) type; - return kcdb_credtype_release(ict); -} - -KHMEXP khm_int32 KHMAPI kcdb_credtype_unregister(khm_int32 id) -{ - kcdb_credtype_i * ict; - - if(id < 0 || id > KCDB_CREDTYPE_MAX_ID) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_credtype); - ict = kcdb_credtype_tbl[id]; - ict->flags |= KCDB_CTI_FLAG_DELETED; - kcdb_credtype_check_and_delete(id); - LeaveCriticalSection(&cs_credtype); - - //kcdb_credtype_post_message(KCDB_OP_DELETE, &(ict->ct)); - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_handle KHMAPI kcdb_credtype_get_sub(khm_int32 id) -{ - kcdb_credtype_i * t; - khm_handle s; - - if(id < 0 || id > KCDB_CREDTYPE_MAX_ID) - return NULL; - - EnterCriticalSection(&cs_credtype); - t = kcdb_credtype_tbl[id]; - if(t) - s = t->ct.sub; - else - s = NULL; - LeaveCriticalSection(&cs_credtype); - - return s; -} - -KHMEXP khm_int32 KHMAPI kcdb_credtype_describe( - khm_int32 id, - wchar_t * buf, - khm_size * cbbuf, - khm_int32 flags) -{ - size_t s; - size_t maxs; - wchar_t * str; - kcdb_credtype_i * t; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!cbbuf || id < 0 || id > KCDB_CREDTYPE_MAX_ID) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_credtype); - t = kcdb_credtype_tbl[id]; - if(t) { - if(flags & KCDB_TS_SHORT) { - str = (t->ct.short_desc)?t->ct.short_desc:t->ct.name; - maxs = (t->ct.short_desc)?KCDB_MAXCB_SHORT_DESC:KCDB_MAXCB_NAME; - } else { - str = (t->ct.long_desc)?t->ct.long_desc:((t->ct.short_desc)?t->ct.short_desc:t->ct.name); - maxs = (t->ct.long_desc)?KCDB_MAXCB_LONG_DESC:((t->ct.short_desc)?KCDB_MAXCB_SHORT_DESC:KCDB_MAXCB_NAME); - } - StringCbLength(str, maxs, &s); - s += sizeof(wchar_t); - if(!buf || *cbbuf < s) { - *cbbuf = s; - rv = KHM_ERROR_TOO_LONG; - } else { - StringCbCopy(buf, *cbbuf, str); - *cbbuf = s; - } - } else { - if(buf && *cbbuf > 0) - *buf = L'\0'; - *cbbuf = 0; - rv = KHM_ERROR_NOT_FOUND; - } - LeaveCriticalSection(&cs_credtype); - - return rv; -} - - -KHMEXP khm_int32 KHMAPI kcdb_credtype_get_name( - khm_int32 id, - wchar_t * buf, - khm_size * cbbuf) -{ - size_t s; - kcdb_credtype_i * t; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!cbbuf || id < 0 || id > KCDB_CREDTYPE_MAX_ID) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_credtype); - t = kcdb_credtype_tbl[id]; - if(t) { - StringCbLength(t->ct.name, KCDB_MAXCB_NAME, &s); - s += sizeof(wchar_t); - if(!buf || *cbbuf < s) { - *cbbuf = s; - rv = KHM_ERROR_TOO_LONG; - } else { - StringCbCopy(buf, *cbbuf, t->ct.name); - *cbbuf = s; - } - } else { - *cbbuf = 0; - rv = KHM_ERROR_NOT_FOUND; - } - LeaveCriticalSection(&cs_credtype); - - return rv; -} - -KHMEXP khm_int32 KHMAPI kcdb_credtype_get_id( - const wchar_t * name, - khm_int32 * id) -{ - int i; - - *id = 0; - if(!name) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_credtype); - for(i=0;i <= KCDB_CREDTYPE_MAX_ID; i++) { - if(kcdb_credtype_tbl[i] && !wcscmp(name, kcdb_credtype_tbl[i]->ct.name)) - break; - } - LeaveCriticalSection(&cs_credtype); - - if(i <= KCDB_CREDTYPE_MAX_ID) { - *id = i; - return KHM_ERROR_SUCCESS; - } else - return KHM_ERROR_NOT_FOUND; -} - -khm_int32 kcdb_credtype_get_next_free_id(khm_int32 * id) -{ - int i; - - EnterCriticalSection(&cs_credtype); - for(i=0;i <= KCDB_CREDTYPE_MAX_ID; i++) { - if(!kcdb_credtype_tbl[i]) - break; - } - LeaveCriticalSection(&cs_credtype); - - if(i <= KCDB_CREDTYPE_MAX_ID) { - *id = i; - return KHM_ERROR_SUCCESS; - } else { - *id = -1; - return KHM_ERROR_NO_RESOURCES; - } -} - -khm_int32 kcdb_credtype_hold(kcdb_credtype_i * ict) { - - if(!ict) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_credtype); - ict->refcount++; - LeaveCriticalSection(&cs_credtype); - return KHM_ERROR_SUCCESS; -} - -khm_int32 kcdb_credtype_release(kcdb_credtype_i * ict) { - - if(!ict) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_credtype); - ict->refcount--; - kcdb_credtype_check_and_delete(ict->ct.id); - LeaveCriticalSection(&cs_credtype); - return KHM_ERROR_SUCCESS; -} - -void kcdb_credtype_msg_completion(kmq_message * m) -{ - kcdb_credtype_release((kcdb_credtype_i *) m->vparam); -} - -void kcdb_credtype_post_message(khm_int32 op, kcdb_credtype * type) -{ - kcdb_credtype_hold((kcdb_credtype_i *) type); - kmq_post_message(KMSG_KCDB, KMSG_KCDB_CREDTYPE, op, (void *) type); -} +/* + * 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 + +CRITICAL_SECTION cs_credtype; +kcdb_credtype_i ** kcdb_credtype_tbl = NULL; +kcdb_credtype_i * kcdb_credtypes = NULL; + +void kcdb_credtype_init(void) +{ + InitializeCriticalSection(&cs_credtype); + kcdb_credtypes = NULL; + + kcdb_credtype_tbl = PMALLOC(sizeof(kcdb_credtype_i *) * (KCDB_CREDTYPE_MAX_ID+1)); + ZeroMemory(kcdb_credtype_tbl, sizeof(kcdb_credtype_i *) * (KCDB_CREDTYPE_MAX_ID+1)); +} + +void kcdb_credtype_exit(void) +{ + /*TODO:Free up the cred types */ + PFREE(kcdb_credtype_tbl); + DeleteCriticalSection(&cs_credtype); +} + +/* Called with cs_credtype held */ +void kcdb_credtype_check_and_delete(khm_int32 id) +{ + kcdb_credtype_i * ict; + ict = kcdb_credtype_tbl[id]; + if(!ict) + return; + + if((ict->flags & KCDB_CTI_FLAG_DELETED) && + !ict->refcount) + { + kcdb_credtype_tbl[id] = NULL; + LDELETE(&kcdb_credtypes, ict); + + PFREE(ict->ct.name); + if(ict->ct.short_desc) + PFREE(ict->ct.short_desc); + if(ict->ct.long_desc) + PFREE(ict->ct.long_desc); + if(ict->ct.sub) + kmq_delete_subscription(ict->ct.sub); + + PFREE(ict); + } +} + +KHMEXP khm_int32 KHMAPI +kcdb_credtype_register(const kcdb_credtype * type, khm_int32 * new_id) +{ + khm_int32 id; + kcdb_credtype_i * ict; + size_t cb_name; + size_t cb_short_desc; + size_t cb_long_desc; + int i; + + if(!type) + return KHM_ERROR_INVALID_PARAM; + + if(type->id >= KCDB_CREDTYPE_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + if(type->name) { + if(FAILED(StringCbLength(type->name, KCDB_MAXCB_NAME, &cb_name))) + return KHM_ERROR_TOO_LONG; + cb_name += sizeof(wchar_t); + } else + return KHM_ERROR_INVALID_PARAM; + + if(type->short_desc) { + if(FAILED(StringCbLength(type->short_desc, KCDB_MAXCB_SHORT_DESC, &cb_short_desc))) + return KHM_ERROR_TOO_LONG; + cb_short_desc += sizeof(wchar_t); + } else + cb_short_desc = 0; + + if(type->long_desc) { + if(FAILED(StringCbLength(type->long_desc, KCDB_MAXCB_LONG_DESC, &cb_long_desc))) + return KHM_ERROR_TOO_LONG; + cb_long_desc += sizeof(wchar_t); + } else + cb_long_desc = 0; + + if(type->sub == NULL) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_credtype); + + if(type->id < 0) { + if(KHM_FAILED(kcdb_credtype_get_next_free_id(&id))) { + LeaveCriticalSection(&cs_credtype); + return KHM_ERROR_NO_RESOURCES; + } + } + else + id = type->id; + + if(kcdb_credtype_tbl[id]) { + LeaveCriticalSection(&cs_credtype); + return KHM_ERROR_DUPLICATE; + } + + for(i=0;i<=KCDB_CREDTYPE_MAX_ID;i++) { + if(kcdb_credtype_tbl[i] && !wcscmp(kcdb_credtype_tbl[i]->ct.name, type->name)) { + LeaveCriticalSection(&cs_credtype); + return KHM_ERROR_DUPLICATE; + } + } + + ict = PMALLOC(sizeof(kcdb_credtype_i)); + ZeroMemory(ict, sizeof(kcdb_credtype_i)); + + ict->ct.name = PMALLOC(cb_name); + StringCbCopy(ict->ct.name, cb_name, type->name); + + if(cb_short_desc) { + ict->ct.short_desc = PMALLOC(cb_short_desc); + StringCbCopy(ict->ct.short_desc, cb_short_desc, type->short_desc); + } + + if(cb_long_desc) { + ict->ct.long_desc = PMALLOC(cb_long_desc); + StringCbCopy(ict->ct.long_desc, cb_long_desc, type->long_desc); + } + + ict->ct.id = id; + + ict->ct.icon = type->icon; + + ict->ct.sub = type->sub; + + ict->ct.is_equal = type->is_equal; + + kcdb_credtype_tbl[id] = ict; + + LPUSH(&kcdb_credtypes, ict); + + LeaveCriticalSection(&cs_credtype); + + kcdb_credtype_post_message(KCDB_OP_INSERT, &(ict->ct)); + + if (new_id) + *new_id = id; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_credtype_get_info( + khm_int32 id, + kcdb_credtype ** type) +{ + int found = 0; + + if(id < 0 || id > KCDB_CREDTYPE_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_credtype); + if(kcdb_credtype_tbl[id] && + !(kcdb_credtype_tbl[id]->flags & KCDB_CTI_FLAG_DELETED)) + { + found = 1; + if(type) { + *type = &(kcdb_credtype_tbl[id]->ct); + kcdb_credtype_hold(kcdb_credtype_tbl[id]); + } + } else { + if(type) + *type = NULL; + } + LeaveCriticalSection(&cs_credtype); + + if(found) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI kcdb_credtype_release_info(kcdb_credtype * type) +{ + kcdb_credtype_i * ict; + + if(!type) + return KHM_ERROR_INVALID_PARAM; + + ict = (kcdb_credtype_i *) type; + return kcdb_credtype_release(ict); +} + +KHMEXP khm_int32 KHMAPI kcdb_credtype_unregister(khm_int32 id) +{ + kcdb_credtype_i * ict; + + if(id < 0 || id > KCDB_CREDTYPE_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_credtype); + ict = kcdb_credtype_tbl[id]; + ict->flags |= KCDB_CTI_FLAG_DELETED; + kcdb_credtype_check_and_delete(id); + LeaveCriticalSection(&cs_credtype); + + //kcdb_credtype_post_message(KCDB_OP_DELETE, &(ict->ct)); + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_handle KHMAPI kcdb_credtype_get_sub(khm_int32 id) +{ + kcdb_credtype_i * t; + khm_handle s; + + if(id < 0 || id > KCDB_CREDTYPE_MAX_ID) + return NULL; + + EnterCriticalSection(&cs_credtype); + t = kcdb_credtype_tbl[id]; + if(t) + s = t->ct.sub; + else + s = NULL; + LeaveCriticalSection(&cs_credtype); + + return s; +} + +KHMEXP khm_int32 KHMAPI kcdb_credtype_describe( + khm_int32 id, + wchar_t * buf, + khm_size * cbbuf, + khm_int32 flags) +{ + size_t s; + size_t maxs; + wchar_t * str; + kcdb_credtype_i * t; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!cbbuf || id < 0 || id > KCDB_CREDTYPE_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_credtype); + t = kcdb_credtype_tbl[id]; + if(t) { + if(flags & KCDB_TS_SHORT) { + str = (t->ct.short_desc)?t->ct.short_desc:t->ct.name; + maxs = (t->ct.short_desc)?KCDB_MAXCB_SHORT_DESC:KCDB_MAXCB_NAME; + } else { + str = (t->ct.long_desc)?t->ct.long_desc:((t->ct.short_desc)?t->ct.short_desc:t->ct.name); + maxs = (t->ct.long_desc)?KCDB_MAXCB_LONG_DESC:((t->ct.short_desc)?KCDB_MAXCB_SHORT_DESC:KCDB_MAXCB_NAME); + } + StringCbLength(str, maxs, &s); + s += sizeof(wchar_t); + if(!buf || *cbbuf < s) { + *cbbuf = s; + rv = KHM_ERROR_TOO_LONG; + } else { + StringCbCopy(buf, *cbbuf, str); + *cbbuf = s; + } + } else { + if(buf && *cbbuf > 0) + *buf = L'\0'; + *cbbuf = 0; + rv = KHM_ERROR_NOT_FOUND; + } + LeaveCriticalSection(&cs_credtype); + + return rv; +} + + +KHMEXP khm_int32 KHMAPI kcdb_credtype_get_name( + khm_int32 id, + wchar_t * buf, + khm_size * cbbuf) +{ + size_t s; + kcdb_credtype_i * t; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!cbbuf || id < 0 || id > KCDB_CREDTYPE_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_credtype); + t = kcdb_credtype_tbl[id]; + if(t) { + StringCbLength(t->ct.name, KCDB_MAXCB_NAME, &s); + s += sizeof(wchar_t); + if(!buf || *cbbuf < s) { + *cbbuf = s; + rv = KHM_ERROR_TOO_LONG; + } else { + StringCbCopy(buf, *cbbuf, t->ct.name); + *cbbuf = s; + } + } else { + *cbbuf = 0; + rv = KHM_ERROR_NOT_FOUND; + } + LeaveCriticalSection(&cs_credtype); + + return rv; +} + +KHMEXP khm_int32 KHMAPI kcdb_credtype_get_id( + const wchar_t * name, + khm_int32 * id) +{ + int i; + + *id = 0; + if(!name) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_credtype); + for(i=0;i <= KCDB_CREDTYPE_MAX_ID; i++) { + if(kcdb_credtype_tbl[i] && !wcscmp(name, kcdb_credtype_tbl[i]->ct.name)) + break; + } + LeaveCriticalSection(&cs_credtype); + + if(i <= KCDB_CREDTYPE_MAX_ID) { + *id = i; + return KHM_ERROR_SUCCESS; + } else + return KHM_ERROR_NOT_FOUND; +} + +khm_int32 kcdb_credtype_get_next_free_id(khm_int32 * id) +{ + int i; + + EnterCriticalSection(&cs_credtype); + for(i=0;i <= KCDB_CREDTYPE_MAX_ID; i++) { + if(!kcdb_credtype_tbl[i]) + break; + } + LeaveCriticalSection(&cs_credtype); + + if(i <= KCDB_CREDTYPE_MAX_ID) { + *id = i; + return KHM_ERROR_SUCCESS; + } else { + *id = -1; + return KHM_ERROR_NO_RESOURCES; + } +} + +khm_int32 kcdb_credtype_hold(kcdb_credtype_i * ict) { + + if(!ict) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_credtype); + ict->refcount++; + LeaveCriticalSection(&cs_credtype); + return KHM_ERROR_SUCCESS; +} + +khm_int32 kcdb_credtype_release(kcdb_credtype_i * ict) { + + if(!ict) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_credtype); + ict->refcount--; + kcdb_credtype_check_and_delete(ict->ct.id); + LeaveCriticalSection(&cs_credtype); + return KHM_ERROR_SUCCESS; +} + +void kcdb_credtype_msg_completion(kmq_message * m) +{ + kcdb_credtype_release((kcdb_credtype_i *) m->vparam); +} + +void kcdb_credtype_post_message(khm_int32 op, kcdb_credtype * type) +{ + kcdb_credtype_hold((kcdb_credtype_i *) type); + kmq_post_message(KMSG_KCDB, KMSG_KCDB_CREDTYPE, op, (void *) type); +} diff --git a/src/windows/identity/kcreddb/credtype.h b/src/windows/identity/kcreddb/credtype.h index aa605d730..3bb0a7d5e 100644 --- a/src/windows/identity/kcreddb/credtype.h +++ b/src/windows/identity/kcreddb/credtype.h @@ -1,55 +1,55 @@ -/* - * 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_KCDB_CREDTYPE_H -#define __KHIMAIRA_KCDB_CREDTYPE_H - -/* credtype */ -typedef struct kcdb_credtype_i_t { - kcdb_credtype ct; - khm_int32 refcount; - khm_int32 flags; - - struct kcdb_credtype_i_t * next; - struct kcdb_credtype_i_t * prev; -} kcdb_credtype_i; - -#define KCDB_CTI_FLAG_DELETED 8 - -extern CRITICAL_SECTION cs_credtype; -extern kcdb_credtype_i * kcdb_credtypes; -extern kcdb_credtype_i ** kcdb_credtype_tbl; - -void kcdb_credtype_init(void); -void kcdb_credtype_exit(void); -void kcdb_credtype_check_and_delete(khm_int32 id); -khm_int32 kcdb_credtype_hold(kcdb_credtype_i * ict); -khm_int32 kcdb_credtype_release(kcdb_credtype_i * ict); -void kcdb_credtype_msg_completion(kmq_message * m); -void kcdb_credtype_post_message(khm_int32 op, kcdb_credtype * type); -khm_int32 kcdb_credtype_get_next_free_id(khm_int32 * id); - -#endif +/* + * 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_KCDB_CREDTYPE_H +#define __KHIMAIRA_KCDB_CREDTYPE_H + +/* credtype */ +typedef struct kcdb_credtype_i_t { + kcdb_credtype ct; + khm_int32 refcount; + khm_int32 flags; + + struct kcdb_credtype_i_t * next; + struct kcdb_credtype_i_t * prev; +} kcdb_credtype_i; + +#define KCDB_CTI_FLAG_DELETED 8 + +extern CRITICAL_SECTION cs_credtype; +extern kcdb_credtype_i * kcdb_credtypes; +extern kcdb_credtype_i ** kcdb_credtype_tbl; + +void kcdb_credtype_init(void); +void kcdb_credtype_exit(void); +void kcdb_credtype_check_and_delete(khm_int32 id); +khm_int32 kcdb_credtype_hold(kcdb_credtype_i * ict); +khm_int32 kcdb_credtype_release(kcdb_credtype_i * ict); +void kcdb_credtype_msg_completion(kmq_message * m); +void kcdb_credtype_post_message(khm_int32 op, kcdb_credtype * type); +khm_int32 kcdb_credtype_get_next_free_id(khm_int32 * id); + +#endif diff --git a/src/windows/identity/kcreddb/identity.c b/src/windows/identity/kcreddb/identity.c index 5d76384d9..e14ceec4c 100644 --- a/src/windows/identity/kcreddb/identity.c +++ b/src/windows/identity/kcreddb/identity.c @@ -1,1599 +1,1599 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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 - -static CRITICAL_SECTION cs_ident; -hashtable * kcdb_identities_namemap = NULL; -khm_int32 kcdb_n_identities = 0; -kcdb_identity * kcdb_identities = NULL; -kcdb_identity * kcdb_def_identity = NULL; -khm_handle kcdb_ident_sub = NULL; /* identity provider */ -khm_int32 kcdb_ident_cred_type = KCDB_CREDTYPE_INVALID; -/* primary credentials type */ -khm_ui_4 kcdb_ident_refresh_cycle = 0; -khm_boolean kcdb_checked_config = FALSE; -khm_boolean kcdb_checking_config = FALSE; - -KHMEXP khm_boolean KHMAPI -kcdb_identity_is_equal(khm_handle identity1, - khm_handle identity2) -{ - - return (identity1 == identity2); - -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_set_provider(khm_handle sub) -{ - EnterCriticalSection(&cs_ident); - if (sub != kcdb_ident_sub) { - if(kcdb_ident_sub != NULL) { - kmq_send_sub_msg(kcdb_ident_sub, - KMSG_IDENT, - KMSG_IDENT_EXIT, - 0, - 0); - kmq_delete_subscription(kcdb_ident_sub); - } - kcdb_ident_sub = sub; - - if (kcdb_ident_sub) - kmq_send_sub_msg(kcdb_ident_sub, - KMSG_IDENT, - KMSG_IDENT_INIT, - 0, - 0); - } - LeaveCriticalSection(&cs_ident); - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_provider(khm_handle * sub) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - - EnterCriticalSection(&cs_ident); - if(kcdb_ident_sub != NULL) - rv = KHM_ERROR_SUCCESS; - else - rv = KHM_ERROR_NOT_FOUND; - if(sub != NULL) - *sub = kcdb_ident_sub; - LeaveCriticalSection(&cs_ident); - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_set_type(khm_int32 cred_type) -{ - EnterCriticalSection(&cs_ident); - kcdb_ident_cred_type = cred_type; - LeaveCriticalSection(&cs_ident); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_type(khm_int32 * ptype) -{ - if (!ptype) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_ident); - *ptype = kcdb_ident_cred_type; - LeaveCriticalSection(&cs_ident); - - if (*ptype >= 0) - return KHM_ERROR_SUCCESS; - else - return KHM_ERROR_NOT_FOUND; -} - -/* message completion routine */ -void -kcdbint_ident_msg_completion(kmq_message * m) { - kcdb_identity_release(m->vparam); -} - -void -kcdbint_ident_add_ref(const void * key, void * vid) { - /* References in the hashtable are not refcounted */ - - // kcdb_identity_hold(vid); -} - -void -kcdbint_ident_del_ref(const void * key, void * vid) { - /* References in the hashtable are not refcounted */ - - // kcdb_identity_release(vid); -} - -void -kcdbint_ident_init(void) { - InitializeCriticalSection(&cs_ident); - kcdb_identities_namemap = hash_new_hashtable( - KCDB_IDENT_HASHTABLE_SIZE, - hash_string, - hash_string_comp, - kcdbint_ident_add_ref, - kcdbint_ident_del_ref); -} - -void -kcdbint_ident_exit(void) { - EnterCriticalSection(&cs_ident); - hash_del_hashtable(kcdb_identities_namemap); - LeaveCriticalSection(&cs_ident); - DeleteCriticalSection(&cs_ident); -} - -/* NOT called with cs_ident held */ -KHMEXP khm_boolean KHMAPI -kcdb_identity_is_valid_name(const wchar_t * name) -{ - khm_int32 rv; - - /* special case. Note since the string we are comparing with is - of a known length we don't need to check the length of name. */ - if (!wcscmp(name, L"_Schema")) - return FALSE; - - rv = kcdb_identpro_validate_name(name); - - if(rv == KHM_ERROR_NO_PROVIDER || - rv == KHM_ERROR_NOT_IMPLEMENTED) - return TRUE; - else - return KHM_SUCCEEDED(rv); -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_create(const wchar_t *name, - khm_int32 flags, - khm_handle * result) { - kcdb_identity * id = NULL; - kcdb_identity * id_tmp = NULL; - size_t namesize; - - if(!result || !name) - return KHM_ERROR_INVALID_PARAM; - - *result = NULL; - - /* is it there already? */ - EnterCriticalSection(&cs_ident); - id = hash_lookup(kcdb_identities_namemap, (void *) name); - if(id) - kcdb_identity_hold((khm_handle) id); - LeaveCriticalSection(&cs_ident); - - if(id) { - *result = (khm_handle) id; - return KHM_ERROR_SUCCESS; - } else if(!(flags & KCDB_IDENT_FLAG_CREATE)) { - return KHM_ERROR_NOT_FOUND; - } - - flags &= ~KCDB_IDENT_FLAG_CREATE; - - /* nope. create it */ - if((flags & ~KCDB_IDENT_FLAGMASK_RDWR) || - (flags & (KCDB_IDENT_FLAG_DEFAULT | - KCDB_IDENT_FLAG_SEARCHABLE | - KCDB_IDENT_FLAG_STICKY))) { - /* can't specify this flag in create */ - return KHM_ERROR_INVALID_PARAM; - } - - if(!kcdb_identity_is_valid_name(name)) { - return KHM_ERROR_INVALID_NAME; - } - - /* we expect the following will succeed since the above - test passed */ - StringCbLength(name, KCDB_IDENT_MAXCB_NAME, &namesize); - namesize += sizeof(wchar_t); - - id = PMALLOC(sizeof(kcdb_identity)); - ZeroMemory(id, sizeof(kcdb_identity)); - id->magic = KCDB_IDENT_MAGIC; - id->name = PMALLOC(namesize); - StringCbCopy(id->name, namesize, name); - - id->flags = (flags & KCDB_IDENT_FLAGMASK_RDWR); - id->flags |= KCDB_IDENT_FLAG_ACTIVE | KCDB_IDENT_FLAG_EMPTY; - LINIT(id); - - EnterCriticalSection(&cs_ident); - id_tmp = hash_lookup(kcdb_identities_namemap, (void *) id->name); - if(id_tmp) { - /* lost a race */ - kcdb_identity_hold((khm_handle) id_tmp); - *result = (khm_handle) id_tmp; - - PFREE(id->name); - PFREE(id); - - id = NULL; - } else { - khm_handle h_cfg; - - kcdb_identity_hold((khm_handle) id); - hash_add(kcdb_identities_namemap, - (void *) id->name, - (void *) id); - LPUSH(&kcdb_identities, id); - - if(KHM_SUCCEEDED(kcdb_identity_get_config((khm_handle) id, - 0, - &h_cfg))) { - /* don't need to set the KCDB_IDENT_FLAG_CONFIG flags - since kcdb_identity_get_config() sets it for us. */ - khm_int32 sticky; - - if (KHM_SUCCEEDED(khc_read_int32(h_cfg, L"Sticky", &sticky)) && - sticky) { - id->flags |= KCDB_IDENT_FLAG_STICKY; - } - - khc_close_space(h_cfg); - } - } - LeaveCriticalSection(&cs_ident); - - if(id != NULL) { - *result = (khm_handle) id; - - kcdb_identpro_notify_create((khm_handle) id); - - kcdbint_ident_post_message(KCDB_OP_INSERT, id); - } - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_delete(khm_handle vid) { - kcdb_identity * id; - khm_int32 code = KHM_ERROR_SUCCESS; - - EnterCriticalSection(&cs_ident); - if(!kcdb_is_identity(vid)) { - code = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - id = (kcdb_identity *) vid; - - if (kcdb_is_active_identity(vid)) { - - id->flags &= ~KCDB_IDENT_FLAG_ACTIVE; - - hash_del(kcdb_identities_namemap, (void *) id->name); - - LeaveCriticalSection(&cs_ident); - - kcdbint_ident_post_message(KCDB_OP_DELETE, id); - - /* Once everybody finishes dealing with the identity deletion, - we will get called again. */ - return KHM_ERROR_SUCCESS; - } else if (id->refcount == 0) { - /* If the identity is not active, it is not in the hashtable - either */ - LDELETE(&kcdb_identities, id); - - if (id->name) - PFREE(id->name); - PFREE(id); - } - /* else, we have an identity that is not active, but has - outstanding references. We have to wait until those references - are freed. Once they are released, kcdb_identity_delete() will - be called again. */ - - _exit: - LeaveCriticalSection(&cs_ident); - - return code; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_set_flags(khm_handle vid, - khm_int32 flag, - khm_int32 mask) { - kcdb_identity * id; - khm_int32 oldflags; - khm_int32 newflags; - khm_int32 delta = 0; - khm_int32 rv; - - if (mask == 0) - return KHM_ERROR_SUCCESS; - - if(!kcdb_is_active_identity(vid)) - return KHM_ERROR_INVALID_PARAM; - - id = (kcdb_identity *) vid; - - flag &= mask; - - if((mask & ~KCDB_IDENT_FLAGMASK_RDWR) || - ((flag & KCDB_IDENT_FLAG_INVALID) && (flag & KCDB_IDENT_FLAG_VALID))) - return KHM_ERROR_INVALID_PARAM; - - if((mask & KCDB_IDENT_FLAG_DEFAULT) && - (flag & KCDB_IDENT_FLAG_DEFAULT)) { - /* kcdb_identity_set_default already does checking for - redundant transitions */ - rv = kcdb_identity_set_default(vid); - - if(KHM_FAILED(rv)) - return rv; - - mask &= ~KCDB_IDENT_FLAG_DEFAULT; - flag &= ~KCDB_IDENT_FLAG_DEFAULT; - } - - EnterCriticalSection(&cs_ident); - - if(mask & KCDB_IDENT_FLAG_SEARCHABLE) { - if(!(flag & KCDB_IDENT_FLAG_SEARCHABLE)) { - if(id->flags & KCDB_IDENT_FLAG_SEARCHABLE) { - LeaveCriticalSection(&cs_ident); - rv = kcdb_identpro_set_searchable(vid, FALSE); - EnterCriticalSection(&cs_ident); - if(rv == KHM_ERROR_NO_PROVIDER || - KHM_SUCCEEDED(rv)) { - id->flags &= ~KCDB_IDENT_FLAG_SEARCHABLE; - delta |= KCDB_IDENT_FLAG_SEARCHABLE; - } - } - } else { - if(!(id->flags & KCDB_IDENT_FLAG_SEARCHABLE)) { - LeaveCriticalSection(&cs_ident); - rv = kcdb_identpro_set_searchable(vid, TRUE); - EnterCriticalSection(&cs_ident); - if(rv == KHM_ERROR_NO_PROVIDER || - KHM_SUCCEEDED(rv)) { - id->flags |= KCDB_IDENT_FLAG_SEARCHABLE; - delta |= KCDB_IDENT_FLAG_SEARCHABLE; - } - } - } - - flag &= ~KCDB_IDENT_FLAG_SEARCHABLE; - mask &= ~KCDB_IDENT_FLAG_SEARCHABLE; - } - - if (mask & KCDB_IDENT_FLAG_STICKY) { - if ((flag ^ id->flags) & KCDB_IDENT_FLAG_STICKY) { - khm_handle h_conf; - - if (KHM_SUCCEEDED(kcdb_identity_get_config(vid, - KHM_FLAG_CREATE, - &h_conf))) { - khc_write_int32(h_conf, L"Sticky", - !!(flag & KCDB_IDENT_FLAG_STICKY)); - khc_close_space(h_conf); - } - - id->flags = - ((id->flags & ~KCDB_IDENT_FLAG_STICKY) | - (flag & KCDB_IDENT_FLAG_STICKY)); - - delta |= KCDB_IDENT_FLAG_STICKY; - } - - flag &= ~KCDB_IDENT_FLAG_STICKY; - mask &= ~KCDB_IDENT_FLAG_STICKY; - } - - /* deal with every other flag */ - - oldflags = id->flags; - - id->flags = (id->flags & ~mask) | (flag & mask); - - if (flag & KCDB_IDENT_FLAG_VALID) { - id->flags &= ~(KCDB_IDENT_FLAG_INVALID | KCDB_IDENT_FLAG_UNKNOWN); - } - if (flag & KCDB_IDENT_FLAG_INVALID) { - id->flags &= ~(KCDB_IDENT_FLAG_VALID | KCDB_IDENT_FLAG_UNKNOWN); - } - - newflags = id->flags; - - LeaveCriticalSection(&cs_ident); - - delta |= newflags ^ oldflags; - - if((delta & KCDB_IDENT_FLAG_HIDDEN)) { - kcdbint_ident_post_message( - (newflags & KCDB_IDENT_FLAG_HIDDEN)?KCDB_OP_HIDE:KCDB_OP_UNHIDE, - vid); - } - - if((delta & KCDB_IDENT_FLAG_SEARCHABLE)) { - kcdbint_ident_post_message( - (newflags & KCDB_IDENT_FLAG_SEARCHABLE)?KCDB_OP_SETSEARCH:KCDB_OP_UNSETSEARCH, - vid); - } - - if(delta != 0) - kcdbint_ident_post_message(KCDB_OP_MODIFY, vid); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_flags(khm_handle vid, - khm_int32 * flags) { - kcdb_identity * id; - - *flags = 0; - - if(!kcdb_is_active_identity(vid)) - return KHM_ERROR_INVALID_PARAM; - - id = (kcdb_identity *) vid; - - EnterCriticalSection(&cs_ident); - *flags = id->flags; - LeaveCriticalSection(&cs_ident); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_name(khm_handle vid, - wchar_t * buffer, - khm_size * pcbsize) { - size_t namesize; - kcdb_identity * id; - - if(!kcdb_is_active_identity(vid) || !pcbsize) - return KHM_ERROR_INVALID_PARAM; - - id = (kcdb_identity *) vid; - - if(FAILED(StringCbLength(id->name, KCDB_IDENT_MAXCB_NAME, &namesize))) - return KHM_ERROR_UNKNOWN; - - namesize += sizeof(wchar_t); - - if(!buffer || namesize > *pcbsize) { - *pcbsize = namesize; - return KHM_ERROR_TOO_LONG; - } - - StringCbCopy(buffer, *pcbsize, id->name); - *pcbsize = namesize; - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_default(khm_handle * pvid) { - khm_handle def; - - if (pvid == NULL) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_ident); - def = kcdb_def_identity; - if (def != NULL) - kcdb_identity_hold(def); - LeaveCriticalSection(&cs_ident); - - *pvid = def; - - if (def != NULL) - return KHM_ERROR_SUCCESS; - else - return KHM_ERROR_NOT_FOUND; -} - -static khm_int32 -kcdbint_ident_set_default(khm_handle vid, - khm_boolean invoke_identpro) { - kcdb_identity * new_def; - kcdb_identity * old_def; - khm_int32 rv; - - if (vid != NULL && !kcdb_is_active_identity(vid)) - return KHM_ERROR_INVALID_PARAM; - - new_def = (kcdb_identity *)vid; - - if (new_def != NULL && (new_def->flags & KCDB_IDENT_FLAG_DEFAULT)) - return KHM_ERROR_SUCCESS; - - if ((new_def == NULL && kcdb_def_identity == NULL) || - (new_def == kcdb_def_identity)) - return KHM_ERROR_SUCCESS; - - /* first check with the identity provider if this operation - is permitted. */ - if (invoke_identpro) { - rv = kcdb_identpro_set_default(vid); - if(rv != KHM_ERROR_NO_PROVIDER && KHM_FAILED(rv)) - return rv; - } - - EnterCriticalSection(&cs_ident); - - old_def = kcdb_def_identity; - kcdb_def_identity = new_def; - - if(old_def != new_def) { - if(old_def) { - old_def->flags &= ~KCDB_IDENT_FLAG_DEFAULT; - kcdb_identity_release((khm_handle) old_def); - } - - if(new_def) { - new_def->flags |= KCDB_IDENT_FLAG_DEFAULT; - kcdb_identity_hold((khm_handle) new_def); - } - - LeaveCriticalSection(&cs_ident); - - /* if (invoke_identpro) */ - kcdbint_ident_post_message(KCDB_OP_NEW_DEFAULT, new_def); - } else { - LeaveCriticalSection(&cs_ident); - } - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_set_default(khm_handle vid) { - return kcdbint_ident_set_default(vid, TRUE); -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_set_default_int(khm_handle vid) { - return kcdbint_ident_set_default(vid, FALSE); -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_config(khm_handle vid, - khm_int32 flags, - khm_handle * result) { - khm_handle hkcdb; - khm_handle hidents = NULL; - khm_handle hident = NULL; - khm_int32 rv; - kcdb_identity * id; - - if(kcdb_is_active_identity(vid)) { - id = (kcdb_identity *) vid; - } else { - return KHM_ERROR_INVALID_PARAM; - } - - hkcdb = kcdb_get_config(); - if(hkcdb) { - rv = khc_open_space(hkcdb, L"Identity", 0, &hidents); - if(KHM_FAILED(rv)) - goto _exit; - - rv = khc_open_space(hidents, - id->name, - flags | KCONF_FLAG_NOPARSENAME, - &hident); - - if(KHM_FAILED(rv)) { - khm_int32 oldflags; - EnterCriticalSection(&cs_ident); - oldflags = id->flags; - id->flags &= ~KCDB_IDENT_FLAG_CONFIG; - LeaveCriticalSection(&cs_ident); - if (oldflags & KCDB_IDENT_FLAG_CONFIG) - kcdbint_ident_post_message(KCDB_OP_DELCONFIG, id); - goto _exit; - } - - EnterCriticalSection(&cs_ident); - id->flags |= KCDB_IDENT_FLAG_CONFIG; - LeaveCriticalSection(&cs_ident); - - *result = hident; - } else - rv = KHM_ERROR_UNKNOWN; - -_exit: - if(hidents) - khc_close_space(hidents); - if(hkcdb) - khc_close_space(hkcdb); - return rv; -} - -/*! \note cs_ident must be available. */ -void -kcdbint_ident_post_message(khm_int32 op, kcdb_identity * id) { - kcdb_identity_hold(id); - kmq_post_message(KMSG_KCDB, KMSG_KCDB_IDENT, op, (void *) id); -} - -/*! \note cs_ident must be available. */ -KHMEXP khm_int32 KHMAPI -kcdb_identity_hold(khm_handle vid) { - kcdb_identity * id; - - EnterCriticalSection(&cs_ident); - if(kcdb_is_active_identity(vid)) { - id = vid; - id->refcount++; - } else { - LeaveCriticalSection(&cs_ident); - return KHM_ERROR_INVALID_PARAM; - } - LeaveCriticalSection(&cs_ident); - return ERROR_SUCCESS; -} - -/*! \note cs_ident must be available. */ -KHMEXP khm_int32 KHMAPI -kcdb_identity_release(khm_handle vid) { - kcdb_identity * id; - khm_int32 refcount; - - EnterCriticalSection(&cs_ident); - if(kcdb_is_identity(vid)) { - id = vid; - refcount = --id->refcount; - if(refcount == 0) { - /* We only delete identities which do not have a - configuration. */ - if (id->refcount == 0 && - !(id->flags & KCDB_IDENT_FLAG_CONFIG)) - kcdb_identity_delete(vid); - } - } else { - LeaveCriticalSection(&cs_ident); - return KHM_ERROR_INVALID_PARAM; - } - LeaveCriticalSection(&cs_ident); - return ERROR_SUCCESS; -} - -struct kcdb_idref_result { - kcdb_identity * ident; - khm_int32 flags; - khm_size count; -}; - -static khm_int32 KHMAPI -kcdbint_idref_proc(khm_handle cred, void * r) { - khm_handle vid; - struct kcdb_idref_result *result; - khm_int32 flags; - - result = (struct kcdb_idref_result *) r; - - if (KHM_SUCCEEDED(kcdb_cred_get_identity(cred, &vid))) { - if (result->ident == (kcdb_identity *) vid) { - - result->count++; - kcdb_cred_get_flags(cred, &flags); - - if (flags & KCDB_CRED_FLAG_RENEWABLE) { - result->flags |= KCDB_IDENT_FLAG_CRED_RENEW; - if (flags & KCDB_CRED_FLAG_INITIAL) { - result->flags |= KCDB_IDENT_FLAG_RENEWABLE; - } - } - - if (flags & KCDB_CRED_FLAG_EXPIRED) { - result->flags |= KCDB_IDENT_FLAG_CRED_EXP; - if (flags & KCDB_CRED_FLAG_INITIAL) { - result->flags |= KCDB_IDENT_FLAG_EXPIRED; - } - } - - if (flags & KCDB_CRED_FLAG_INITIAL) { - result->flags |= KCDB_IDENT_FLAG_VALID; - } - } - - kcdb_identity_release(vid); - } - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_refresh(khm_handle vid) { - kcdb_identity * ident; - khm_int32 code = KHM_ERROR_SUCCESS; - struct kcdb_idref_result result; - - EnterCriticalSection(&cs_ident); - - if (!kcdb_is_active_identity(vid)) { - code = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - ident = (kcdb_identity *) vid; - - result.ident = ident; - result.flags = 0; - result.count = 0; - - LeaveCriticalSection(&cs_ident); - - kcdb_credset_apply(NULL, kcdbint_idref_proc, &result); - - if (result.count == 0) - result.flags |= KCDB_IDENT_FLAG_EMPTY; - - kcdb_identity_set_flags(vid, result.flags, - KCDB_IDENT_FLAGMASK_RDWR & - ~(KCDB_IDENT_FLAG_DEFAULT | - KCDB_IDENT_FLAG_SEARCHABLE | - KCDB_IDENT_FLAG_STICKY)); - - EnterCriticalSection(&cs_ident); - ident->refresh_cycle = kcdb_ident_refresh_cycle; - - _exit: - LeaveCriticalSection(&cs_ident); - - if (code == 0) - code = kcdb_identpro_update(vid); - - return code; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_refresh_all(void) { - kcdb_identity * ident; - kcdb_identity * next; - khm_int32 code = KHM_ERROR_SUCCESS; - int hit_count; - - EnterCriticalSection(&cs_ident); - - kcdb_ident_refresh_cycle++; - - /* The do-while loop is here to account for race conditions. We - release cs_ident in the for loop, so we don't actually have a - guarantee that we traversed the whole identity list at the end. - We repeat until all the identities are uptodate. */ - - do { - hit_count = 0; - - for (ident = kcdb_identities; - ident != NULL; - ident = next) { - - if (!kcdb_is_active_identity(ident) || - ident->refresh_cycle == kcdb_ident_refresh_cycle) { - next = LNEXT(ident); - continue; - } - - kcdb_identity_hold((khm_handle) ident); - - LeaveCriticalSection(&cs_ident); - - kcdb_identity_refresh((khm_handle) ident); - - EnterCriticalSection(&cs_ident); - - next = LNEXT(ident); - kcdb_identity_release((khm_handle) ident); - - hit_count++; - } - - } while (hit_count > 0); - - LeaveCriticalSection(&cs_ident); - - return code; -} - -/*****************************************/ -/* Custom property functions */ - -KHMEXP khm_int32 KHMAPI -kcdb_identity_set_attr(khm_handle vid, - khm_int32 attr_id, - void * buffer, - khm_size cbbuf) -{ - kcdb_identity * id = NULL; - kcdb_attrib * attrib = NULL; - kcdb_type * type = NULL; - khm_size slot; - khm_size cbdest; - khm_int32 code = KHM_ERROR_SUCCESS; - - EnterCriticalSection(&cs_ident); - if(!kcdb_is_active_identity(vid)) { - LeaveCriticalSection(&cs_ident); - return KHM_ERROR_INVALID_PARAM; - } - - id = (kcdb_identity *) vid; - - if(!(id->flags & KCDB_IDENT_FLAG_ATTRIBS)) { - kcdb_buf_new(&id->buf, KCDB_BUF_DEFAULT); - id->flags |= KCDB_IDENT_FLAG_ATTRIBS; - } - - if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { - LeaveCriticalSection(&cs_ident); - return KHM_ERROR_INVALID_PARAM; - } - -#if 0 - /* actually, even if an attribute is computed, we still allow - those values to be set. This is because computing values - is only for credentials. If a computed value is used as a - property in any other object, it is treated as a regular value - */ - if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) - { - LeaveCriticalSection(&cs_ident); - kcdb_attrib_release_info(attrib); - return KHM_ERROR_INVALID_OPERATION; - } -#endif - - if (buffer == NULL) { - /* we are removing a value */ - slot = kcdb_buf_slot_by_id(&id->buf, attr_id); - if (slot != KCDB_BUF_INVALID_SLOT && - kcdb_buf_exist(&id->buf, slot)) - kcdb_buf_alloc(&id->buf, slot, attr_id, 0); - code = KHM_ERROR_SUCCESS; - goto _exit; - } - - if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { - LeaveCriticalSection(&cs_ident); - kcdb_attrib_release_info(attrib); - return KHM_ERROR_INVALID_PARAM; - } - - if(!(type->isValid(buffer,cbbuf))) { - code = KHM_ERROR_TYPE_MISMATCH; - goto _exit; - } - - if((type->dup(buffer, cbbuf, NULL, &cbdest)) != KHM_ERROR_TOO_LONG) { - code = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - kcdb_buf_alloc(&id->buf, KCDB_BUF_APPEND, attr_id, cbdest); - slot = kcdb_buf_slot_by_id(&id->buf, attr_id); - if(slot == KCDB_BUF_INVALID_SLOT || !kcdb_buf_exist(&id->buf, slot)) { - code = KHM_ERROR_NO_RESOURCES; - goto _exit; - } - - if(KHM_FAILED(code = - type->dup(buffer, cbbuf, kcdb_buf_get(&id->buf, slot), &cbdest))) - { - kcdb_buf_alloc(&id->buf, slot, attr_id, 0); - goto _exit; - } - - kcdb_buf_set_value_flag(&id->buf, slot); - -_exit: - LeaveCriticalSection(&cs_ident); - - if(attrib) - kcdb_attrib_release_info(attrib); - if(type) - kcdb_type_release_info(type); - - return code; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_set_attrib(khm_handle vid, - const wchar_t * attr_name, - void * buffer, - khm_size cbbuf) -{ - khm_int32 attr_id = -1; - - if(KHM_FAILED(kcdb_attrib_get_id(attr_name, &attr_id))) - return KHM_ERROR_INVALID_PARAM; - - return kcdb_identity_set_attr( - vid, - attr_id, - buffer, - cbbuf); -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_attr(khm_handle vid, - khm_int32 attr_id, - khm_int32 * attr_type, - void * buffer, - khm_size * pcbbuf) -{ - khm_int32 code = KHM_ERROR_SUCCESS; - kcdb_identity * id = NULL; - kcdb_attrib * attrib = NULL; - kcdb_type * type = NULL; - khm_size slot; - - if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { - return KHM_ERROR_INVALID_PARAM; - } - - if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { - kcdb_attrib_release_info(attrib); - return KHM_ERROR_UNKNOWN; - } - - if(attr_type) - *attr_type = attrib->type; - - EnterCriticalSection(&cs_ident); - - if(!kcdb_is_active_identity(vid)) { - code = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - id = (kcdb_identity *) vid; - - if(!(id->flags & KCDB_IDENT_FLAG_ATTRIBS) || - (slot = kcdb_buf_slot_by_id(&id->buf, attr_id)) == KCDB_BUF_INVALID_SLOT || - !kcdb_buf_val_exist(&id->buf, slot)) - { - code = KHM_ERROR_NOT_FOUND; - goto _exit; - } - - if(!buffer && !pcbbuf) { - /* in this case the caller is only trying to determine if the field - contains data. If we get here, then the value exists. */ - code = KHM_ERROR_SUCCESS; - goto _exit; - } - -#if 0 - if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) { - /* we should never hit this case */ -#ifdef DEBUG - assert(FALSE); -#endif - code = KHM_ERROR_INVALID_OPERATION; - } else { -#endif - code = type->dup( - kcdb_buf_get(&id->buf, slot), - kcdb_buf_size(&id->buf, slot), - buffer, - pcbbuf); -#if 0 - } -#endif - -_exit: - LeaveCriticalSection(&cs_ident); - if(type) - kcdb_type_release_info(type); - if(attrib) - kcdb_attrib_release_info(attrib); - - return code; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_attrib(khm_handle vid, - const wchar_t * attr_name, - khm_int32 * attr_type, - void * buffer, - khm_size * pcbbuf) -{ - khm_int32 attr_id = -1; - - if(KHM_FAILED(kcdb_attrib_get_id(attr_name, &attr_id))) - return KHM_ERROR_NOT_FOUND; - - return kcdb_identity_get_attr(vid, - attr_id, - attr_type, - buffer, - pcbbuf); -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_attr_string(khm_handle vid, - khm_int32 attr_id, - wchar_t * buffer, - khm_size * pcbbuf, - khm_int32 flags) -{ - khm_int32 code = KHM_ERROR_SUCCESS; - kcdb_identity * id = NULL; - kcdb_attrib * attrib = NULL; - kcdb_type * type = NULL; - khm_size slot; - - if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { - return KHM_ERROR_INVALID_PARAM; - } - - if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { - kcdb_attrib_release_info(attrib); - return KHM_ERROR_UNKNOWN; - } - - EnterCriticalSection(&cs_ident); - - if(!kcdb_is_active_identity(vid)) { - code = KHM_ERROR_INVALID_PARAM; - goto _exit; - } - - id = (kcdb_identity *) vid; - - if(!(id->flags & KCDB_IDENT_FLAG_ATTRIBS) || - (slot = kcdb_buf_slot_by_id(&id->buf, attr_id)) == KCDB_BUF_INVALID_SLOT || - !kcdb_buf_val_exist(&id->buf, slot)) - { - code = KHM_ERROR_NOT_FOUND; - goto _exit; - } - - if(!buffer && !pcbbuf) { - /* in this case the caller is only trying to determine if the field - contains data. If we get here, then the value exists */ - code = KHM_ERROR_SUCCESS; - goto _exit; - } - -#if 0 - if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) { -#ifdef DEBUG - assert(FALSE); -#endif - code = KHM_ERROR_INVALID_OPERATION; - } else { -#endif - if(kcdb_buf_exist(&id->buf, slot)) { - code = type->toString( - kcdb_buf_get(&id->buf, slot), - kcdb_buf_size(&id->buf, slot), - buffer, - pcbbuf, - flags); - } else - code = KHM_ERROR_NOT_FOUND; -#if 0 - } -#endif - -_exit: - LeaveCriticalSection(&cs_ident); - if(type) - kcdb_type_release_info(type); - if(attrib) - kcdb_attrib_release_info(attrib); - - return code; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_attrib_string(khm_handle vid, - const wchar_t * attr_name, - wchar_t * buffer, - khm_size * pcbbuf, - khm_int32 flags) -{ - khm_int32 attr_id = -1; - - if(KHM_FAILED(kcdb_attrib_get_id(attr_name, &attr_id))) - return KHM_ERROR_NOT_FOUND; - - return kcdb_identity_get_attr_string( - vid, - attr_id, - buffer, - pcbbuf, - flags); -} - -/*****************************************/ -/* Identity provider interface functions */ - -/* NOT called with cs_ident held */ -KHMEXP khm_int32 KHMAPI -kcdb_identpro_validate_name(const wchar_t * name) -{ - kcdb_ident_name_xfer namex; - khm_handle sub; - khm_size cch; - khm_int32 rv = KHM_ERROR_SUCCESS; - - /* we need to verify the length and the contents of the string - 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) { - sub = kcdb_ident_sub; - } else { - sub = NULL; - rv = KHM_ERROR_NO_PROVIDER; - } - LeaveCriticalSection(&cs_ident); - - if(sub != NULL) { - ZeroMemory(&namex, sizeof(namex)); - - namex.name_src = name; - namex.result = KHM_ERROR_NOT_IMPLEMENTED; - - kmq_send_sub_msg(sub, - KMSG_IDENT, - KMSG_IDENT_VALIDATE_NAME, - 0, - (void *) &namex); - - rv = namex.result; - } - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identpro_validate_identity(khm_handle identity) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - khm_handle sub; - - if(!kcdb_is_active_identity(identity)) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_ident); - if(kcdb_ident_sub != NULL) { - sub = kcdb_ident_sub; - } else { - sub = NULL; - rv = KHM_ERROR_NO_PROVIDER; - } - LeaveCriticalSection(&cs_ident); - - if(sub != NULL) { - rv = kmq_send_sub_msg(sub, - KMSG_IDENT, - KMSG_IDENT_VALIDATE_IDENTITY, - 0, - (void *) identity); - } - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identpro_canon_name(const wchar_t * name_in, - wchar_t * name_out, - khm_size * cb_name_out) -{ - khm_handle sub; - kcdb_ident_name_xfer namex; - wchar_t name_tmp[KCDB_IDENT_MAXCCH_NAME]; - khm_int32 rv = KHM_ERROR_SUCCESS; - khm_size cch; - - if(cb_name_out == 0 || - FAILED(StringCchLength(name_in, KCDB_IDENT_MAXCCH_NAME, &cch))) - return KHM_ERROR_INVALID_NAME; - - EnterCriticalSection(&cs_ident); - if(kcdb_ident_sub != NULL) { - sub = kcdb_ident_sub; - } else { - sub = NULL; - rv = KHM_ERROR_NO_PROVIDER; - } - LeaveCriticalSection(&cs_ident); - - if(sub != NULL) { - ZeroMemory(&namex, sizeof(namex)); - ZeroMemory(name_tmp, sizeof(name_tmp)); - - namex.name_src = name_in; - namex.name_dest = name_tmp; - namex.cb_name_dest = sizeof(name_tmp); - namex.result = KHM_ERROR_NOT_IMPLEMENTED; - - rv = kmq_send_sub_msg(sub, - KMSG_IDENT, - KMSG_IDENT_CANON_NAME, - 0, - (void *) &namex); - - if(KHM_SUCCEEDED(namex.result)) { - const wchar_t * name_result; - khm_size cb; - - if(name_in[0] != 0 && name_tmp[0] == 0) - name_result = name_tmp; - else - name_result = name_in; - - if(FAILED(StringCbLength(name_result, KCDB_IDENT_MAXCB_NAME, &cb))) - rv = KHM_ERROR_UNKNOWN; - else { - cb += sizeof(wchar_t); - if(name_out == 0 || *cb_name_out < cb) { - rv = KHM_ERROR_TOO_LONG; - *cb_name_out = cb; - } else { - StringCbCopy(name_out, *cb_name_out, name_result); - *cb_name_out = cb; - rv = KHM_ERROR_SUCCESS; - } - } - } - } - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identpro_compare_name(const wchar_t * name1, - const wchar_t * name2) -{ - khm_handle sub; - kcdb_ident_name_xfer namex; - khm_int32 rv = 0; - - /* Generally in kcdb_identpro_* functions we don't emulate - any behavior if the provider is not available, but lacking - a way to make this known, we emulate here */ - rv = wcscmp(name1, name2); - - EnterCriticalSection(&cs_ident); - if(kcdb_ident_sub != NULL) { - sub = kcdb_ident_sub; - } else { - sub = NULL; - } - LeaveCriticalSection(&cs_ident); - - if(sub != NULL) { - ZeroMemory(&namex, sizeof(namex)); - namex.name_src = name1; - namex.name_alt = name2; - namex.result = rv; - - kmq_send_sub_msg(sub, - KMSG_IDENT, - KMSG_IDENT_COMPARE_NAME, - 0, - (void *) &namex); - - rv = namex.result; - } - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identpro_set_default(khm_handle identity) -{ - khm_handle sub; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if((identity != NULL) && - !kcdb_is_active_identity(identity)) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_ident); - if(kcdb_ident_sub != NULL) { - sub = kcdb_ident_sub; - } else { - sub = NULL; - rv = KHM_ERROR_NO_PROVIDER; - } - LeaveCriticalSection(&cs_ident); - - if(sub != NULL) { - rv = kmq_send_sub_msg(sub, - KMSG_IDENT, - KMSG_IDENT_SET_DEFAULT, - (identity != NULL), - (void *) identity); - } - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identpro_set_searchable(khm_handle identity, - khm_boolean searchable) -{ - khm_handle sub; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!kcdb_is_active_identity(identity)) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_ident); - if(kcdb_ident_sub != NULL) { - sub = kcdb_ident_sub; - } else { - sub = NULL; - rv = KHM_ERROR_NO_PROVIDER; - } - LeaveCriticalSection(&cs_ident); - - if(sub != NULL) { - rv = kmq_send_sub_msg( - sub, - KMSG_IDENT, - KMSG_IDENT_SET_SEARCHABLE, - searchable, - (void *) identity); - } - - return rv; -} - - -KHMEXP khm_int32 KHMAPI -kcdb_identpro_update(khm_handle identity) -{ - khm_handle sub; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!kcdb_is_active_identity(identity)) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_ident); - if(kcdb_ident_sub != NULL) { - sub = kcdb_ident_sub; - } else { - sub = NULL; - rv = KHM_ERROR_NO_PROVIDER; - } - LeaveCriticalSection(&cs_ident); - - if(sub != NULL) { - rv = kmq_send_sub_msg(sub, - KMSG_IDENT, - KMSG_IDENT_UPDATE, - 0, - (void *) identity); - } - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identpro_notify_create(khm_handle identity) -{ - khm_handle sub; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!kcdb_is_active_identity(identity)) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_ident); - if(kcdb_ident_sub != NULL) { - sub = kcdb_ident_sub; - } else { - sub = NULL; - rv = KHM_ERROR_NO_PROVIDER; - } - LeaveCriticalSection(&cs_ident); - - if(sub != NULL) { - rv = kmq_send_sub_msg( - sub, - KMSG_IDENT, - KMSG_IDENT_NOTIFY_CREATE, - 0, - (void *) identity); - } - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identpro_get_ui_cb(void * rock) -{ - khm_handle sub; - khm_int32 rv = KHM_ERROR_SUCCESS; - - EnterCriticalSection(&cs_ident); - if(kcdb_ident_sub != NULL) { - sub = kcdb_ident_sub; - } else { - sub = NULL; - rv = KHM_ERROR_NO_PROVIDER; - } - LeaveCriticalSection(&cs_ident); - - if(sub != NULL) { - rv = kmq_send_sub_msg( - sub, - KMSG_IDENT, - KMSG_IDENT_GET_UI_CALLBACK, - 0, - rock); - } - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kcdb_identity_enum(khm_int32 and_flags, - khm_int32 eq_flags, - wchar_t * name_buf, - khm_size * pcb_buf, - khm_size * pn_idents) -{ - kcdb_identity * id; - khm_int32 rv = KHM_ERROR_SUCCESS; - khm_size cb_req = 0; - khm_size n_idents = 0; - size_t cb_curr; - size_t cch_curr; - size_t cch_left; - HRESULT hr; - - if ((name_buf == NULL && pcb_buf == NULL && pn_idents == NULL) || - (name_buf != NULL && pcb_buf == NULL)) - return KHM_ERROR_INVALID_PARAM; - - eq_flags &= and_flags; - - EnterCriticalSection(&cs_ident); - - if (!kcdb_checked_config) { - khm_handle h_kcdb = NULL; - khm_handle h_idents = NULL; - khm_handle h_ident = NULL; - - kcdb_checked_config = TRUE; - kcdb_checking_config = TRUE; - - h_kcdb = kcdb_get_config(); - if (!h_kcdb) - goto _config_check_cleanup; - if(KHM_FAILED(khc_open_space(h_kcdb, L"Identity", 0, &h_idents))) - goto _config_check_cleanup; - - while(KHM_SUCCEEDED(khc_enum_subspaces(h_idents, - h_ident, - &h_ident))) { - - wchar_t wname[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - khm_handle t_id; - - cb = sizeof(wname); - if (KHM_FAILED(khc_get_config_space_name(h_ident, - wname, - &cb))) - continue; - - LeaveCriticalSection(&cs_ident); - - if (KHM_SUCCEEDED(kcdb_identity_create(wname, - KCDB_IDENT_FLAG_CREATE, - &t_id))) - kcdb_identity_release(t_id); - - EnterCriticalSection(&cs_ident); - } - - _config_check_cleanup: - if (h_kcdb) - khc_close_space(h_kcdb); - if (h_idents) - khc_close_space(h_idents); - - kcdb_checking_config = FALSE; - } - - for ( id = kcdb_identities; - id != NULL; - id = LNEXT(id) ) { - if (((id->flags & KCDB_IDENT_FLAG_ACTIVE) == - KCDB_IDENT_FLAG_ACTIVE) && - ((id->flags & and_flags) == eq_flags)) { - n_idents ++; - hr = StringCbLength(id->name, KCDB_IDENT_MAXCB_NAME, &cb_curr); -#ifdef DEBUG - assert(SUCCEEDED(hr)); -#endif - cb_req += cb_curr + sizeof(wchar_t); - } - } - - cb_req += sizeof(wchar_t); - - if (pn_idents != NULL) - *pn_idents = n_idents; - - if (pcb_buf != NULL && (name_buf == NULL || *pcb_buf < cb_req)) { - *pcb_buf = cb_req; - - rv = KHM_ERROR_TOO_LONG; - } else if(name_buf != NULL) { - cch_left = (*pcb_buf) / sizeof(wchar_t); - - for (id = kcdb_identities; - id != NULL; - id = LNEXT(id)) { - if (((id->flags & KCDB_IDENT_FLAG_ACTIVE) == - KCDB_IDENT_FLAG_ACTIVE) && - ((id->flags & and_flags) == eq_flags)) { - StringCchLength(id->name, KCDB_IDENT_MAXCCH_NAME, - &cch_curr); - cch_curr++; - StringCchCopy(name_buf, cch_left, id->name); - cch_left -= cch_curr; - name_buf += cch_curr; - } - } - - *name_buf = L'\0'; - *pcb_buf = cb_req; - } - - LeaveCriticalSection(&cs_ident); - - return rv; -} +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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 + +static CRITICAL_SECTION cs_ident; +hashtable * kcdb_identities_namemap = NULL; +khm_int32 kcdb_n_identities = 0; +kcdb_identity * kcdb_identities = NULL; +kcdb_identity * kcdb_def_identity = NULL; +khm_handle kcdb_ident_sub = NULL; /* identity provider */ +khm_int32 kcdb_ident_cred_type = KCDB_CREDTYPE_INVALID; +/* primary credentials type */ +khm_ui_4 kcdb_ident_refresh_cycle = 0; +khm_boolean kcdb_checked_config = FALSE; +khm_boolean kcdb_checking_config = FALSE; + +KHMEXP khm_boolean KHMAPI +kcdb_identity_is_equal(khm_handle identity1, + khm_handle identity2) +{ + + return (identity1 == identity2); + +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_provider(khm_handle sub) +{ + EnterCriticalSection(&cs_ident); + if (sub != kcdb_ident_sub) { + if(kcdb_ident_sub != NULL) { + kmq_send_sub_msg(kcdb_ident_sub, + KMSG_IDENT, + KMSG_IDENT_EXIT, + 0, + 0); + kmq_delete_subscription(kcdb_ident_sub); + } + kcdb_ident_sub = sub; + + if (kcdb_ident_sub) + kmq_send_sub_msg(kcdb_ident_sub, + KMSG_IDENT, + KMSG_IDENT_INIT, + 0, + 0); + } + LeaveCriticalSection(&cs_ident); + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_provider(khm_handle * sub) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) + rv = KHM_ERROR_SUCCESS; + else + rv = KHM_ERROR_NOT_FOUND; + if(sub != NULL) + *sub = kcdb_ident_sub; + LeaveCriticalSection(&cs_ident); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_type(khm_int32 cred_type) +{ + EnterCriticalSection(&cs_ident); + kcdb_ident_cred_type = cred_type; + LeaveCriticalSection(&cs_ident); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_type(khm_int32 * ptype) +{ + if (!ptype) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_ident); + *ptype = kcdb_ident_cred_type; + LeaveCriticalSection(&cs_ident); + + if (*ptype >= 0) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +/* message completion routine */ +void +kcdbint_ident_msg_completion(kmq_message * m) { + kcdb_identity_release(m->vparam); +} + +void +kcdbint_ident_add_ref(const void * key, void * vid) { + /* References in the hashtable are not refcounted */ + + // kcdb_identity_hold(vid); +} + +void +kcdbint_ident_del_ref(const void * key, void * vid) { + /* References in the hashtable are not refcounted */ + + // kcdb_identity_release(vid); +} + +void +kcdbint_ident_init(void) { + InitializeCriticalSection(&cs_ident); + kcdb_identities_namemap = hash_new_hashtable( + KCDB_IDENT_HASHTABLE_SIZE, + hash_string, + hash_string_comp, + kcdbint_ident_add_ref, + kcdbint_ident_del_ref); +} + +void +kcdbint_ident_exit(void) { + EnterCriticalSection(&cs_ident); + hash_del_hashtable(kcdb_identities_namemap); + LeaveCriticalSection(&cs_ident); + DeleteCriticalSection(&cs_ident); +} + +/* NOT called with cs_ident held */ +KHMEXP khm_boolean KHMAPI +kcdb_identity_is_valid_name(const wchar_t * name) +{ + khm_int32 rv; + + /* special case. Note since the string we are comparing with is + of a known length we don't need to check the length of name. */ + if (!wcscmp(name, L"_Schema")) + return FALSE; + + rv = kcdb_identpro_validate_name(name); + + if(rv == KHM_ERROR_NO_PROVIDER || + rv == KHM_ERROR_NOT_IMPLEMENTED) + return TRUE; + else + return KHM_SUCCEEDED(rv); +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_create(const wchar_t *name, + khm_int32 flags, + khm_handle * result) { + kcdb_identity * id = NULL; + kcdb_identity * id_tmp = NULL; + size_t namesize; + + if(!result || !name) + return KHM_ERROR_INVALID_PARAM; + + *result = NULL; + + /* is it there already? */ + EnterCriticalSection(&cs_ident); + id = hash_lookup(kcdb_identities_namemap, (void *) name); + if(id) + kcdb_identity_hold((khm_handle) id); + LeaveCriticalSection(&cs_ident); + + if(id) { + *result = (khm_handle) id; + return KHM_ERROR_SUCCESS; + } else if(!(flags & KCDB_IDENT_FLAG_CREATE)) { + return KHM_ERROR_NOT_FOUND; + } + + flags &= ~KCDB_IDENT_FLAG_CREATE; + + /* nope. create it */ + if((flags & ~KCDB_IDENT_FLAGMASK_RDWR) || + (flags & (KCDB_IDENT_FLAG_DEFAULT | + KCDB_IDENT_FLAG_SEARCHABLE | + KCDB_IDENT_FLAG_STICKY))) { + /* can't specify this flag in create */ + return KHM_ERROR_INVALID_PARAM; + } + + if(!kcdb_identity_is_valid_name(name)) { + return KHM_ERROR_INVALID_NAME; + } + + /* we expect the following will succeed since the above + test passed */ + StringCbLength(name, KCDB_IDENT_MAXCB_NAME, &namesize); + namesize += sizeof(wchar_t); + + id = PMALLOC(sizeof(kcdb_identity)); + ZeroMemory(id, sizeof(kcdb_identity)); + id->magic = KCDB_IDENT_MAGIC; + id->name = PMALLOC(namesize); + StringCbCopy(id->name, namesize, name); + + id->flags = (flags & KCDB_IDENT_FLAGMASK_RDWR); + id->flags |= KCDB_IDENT_FLAG_ACTIVE | KCDB_IDENT_FLAG_EMPTY; + LINIT(id); + + EnterCriticalSection(&cs_ident); + id_tmp = hash_lookup(kcdb_identities_namemap, (void *) id->name); + if(id_tmp) { + /* lost a race */ + kcdb_identity_hold((khm_handle) id_tmp); + *result = (khm_handle) id_tmp; + + PFREE(id->name); + PFREE(id); + + id = NULL; + } else { + khm_handle h_cfg; + + kcdb_identity_hold((khm_handle) id); + hash_add(kcdb_identities_namemap, + (void *) id->name, + (void *) id); + LPUSH(&kcdb_identities, id); + + if(KHM_SUCCEEDED(kcdb_identity_get_config((khm_handle) id, + 0, + &h_cfg))) { + /* don't need to set the KCDB_IDENT_FLAG_CONFIG flags + since kcdb_identity_get_config() sets it for us. */ + khm_int32 sticky; + + if (KHM_SUCCEEDED(khc_read_int32(h_cfg, L"Sticky", &sticky)) && + sticky) { + id->flags |= KCDB_IDENT_FLAG_STICKY; + } + + khc_close_space(h_cfg); + } + } + LeaveCriticalSection(&cs_ident); + + if(id != NULL) { + *result = (khm_handle) id; + + kcdb_identpro_notify_create((khm_handle) id); + + kcdbint_ident_post_message(KCDB_OP_INSERT, id); + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_delete(khm_handle vid) { + kcdb_identity * id; + khm_int32 code = KHM_ERROR_SUCCESS; + + EnterCriticalSection(&cs_ident); + if(!kcdb_is_identity(vid)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + id = (kcdb_identity *) vid; + + if (kcdb_is_active_identity(vid)) { + + id->flags &= ~KCDB_IDENT_FLAG_ACTIVE; + + hash_del(kcdb_identities_namemap, (void *) id->name); + + LeaveCriticalSection(&cs_ident); + + kcdbint_ident_post_message(KCDB_OP_DELETE, id); + + /* Once everybody finishes dealing with the identity deletion, + we will get called again. */ + return KHM_ERROR_SUCCESS; + } else if (id->refcount == 0) { + /* If the identity is not active, it is not in the hashtable + either */ + LDELETE(&kcdb_identities, id); + + if (id->name) + PFREE(id->name); + PFREE(id); + } + /* else, we have an identity that is not active, but has + outstanding references. We have to wait until those references + are freed. Once they are released, kcdb_identity_delete() will + be called again. */ + + _exit: + LeaveCriticalSection(&cs_ident); + + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_flags(khm_handle vid, + khm_int32 flag, + khm_int32 mask) { + kcdb_identity * id; + khm_int32 oldflags; + khm_int32 newflags; + khm_int32 delta = 0; + khm_int32 rv; + + if (mask == 0) + return KHM_ERROR_SUCCESS; + + if(!kcdb_is_active_identity(vid)) + return KHM_ERROR_INVALID_PARAM; + + id = (kcdb_identity *) vid; + + flag &= mask; + + if((mask & ~KCDB_IDENT_FLAGMASK_RDWR) || + ((flag & KCDB_IDENT_FLAG_INVALID) && (flag & KCDB_IDENT_FLAG_VALID))) + return KHM_ERROR_INVALID_PARAM; + + if((mask & KCDB_IDENT_FLAG_DEFAULT) && + (flag & KCDB_IDENT_FLAG_DEFAULT)) { + /* kcdb_identity_set_default already does checking for + redundant transitions */ + rv = kcdb_identity_set_default(vid); + + if(KHM_FAILED(rv)) + return rv; + + mask &= ~KCDB_IDENT_FLAG_DEFAULT; + flag &= ~KCDB_IDENT_FLAG_DEFAULT; + } + + EnterCriticalSection(&cs_ident); + + if(mask & KCDB_IDENT_FLAG_SEARCHABLE) { + if(!(flag & KCDB_IDENT_FLAG_SEARCHABLE)) { + if(id->flags & KCDB_IDENT_FLAG_SEARCHABLE) { + LeaveCriticalSection(&cs_ident); + rv = kcdb_identpro_set_searchable(vid, FALSE); + EnterCriticalSection(&cs_ident); + if(rv == KHM_ERROR_NO_PROVIDER || + KHM_SUCCEEDED(rv)) { + id->flags &= ~KCDB_IDENT_FLAG_SEARCHABLE; + delta |= KCDB_IDENT_FLAG_SEARCHABLE; + } + } + } else { + if(!(id->flags & KCDB_IDENT_FLAG_SEARCHABLE)) { + LeaveCriticalSection(&cs_ident); + rv = kcdb_identpro_set_searchable(vid, TRUE); + EnterCriticalSection(&cs_ident); + if(rv == KHM_ERROR_NO_PROVIDER || + KHM_SUCCEEDED(rv)) { + id->flags |= KCDB_IDENT_FLAG_SEARCHABLE; + delta |= KCDB_IDENT_FLAG_SEARCHABLE; + } + } + } + + flag &= ~KCDB_IDENT_FLAG_SEARCHABLE; + mask &= ~KCDB_IDENT_FLAG_SEARCHABLE; + } + + if (mask & KCDB_IDENT_FLAG_STICKY) { + if ((flag ^ id->flags) & KCDB_IDENT_FLAG_STICKY) { + khm_handle h_conf; + + if (KHM_SUCCEEDED(kcdb_identity_get_config(vid, + KHM_FLAG_CREATE, + &h_conf))) { + khc_write_int32(h_conf, L"Sticky", + !!(flag & KCDB_IDENT_FLAG_STICKY)); + khc_close_space(h_conf); + } + + id->flags = + ((id->flags & ~KCDB_IDENT_FLAG_STICKY) | + (flag & KCDB_IDENT_FLAG_STICKY)); + + delta |= KCDB_IDENT_FLAG_STICKY; + } + + flag &= ~KCDB_IDENT_FLAG_STICKY; + mask &= ~KCDB_IDENT_FLAG_STICKY; + } + + /* deal with every other flag */ + + oldflags = id->flags; + + id->flags = (id->flags & ~mask) | (flag & mask); + + if (flag & KCDB_IDENT_FLAG_VALID) { + id->flags &= ~(KCDB_IDENT_FLAG_INVALID | KCDB_IDENT_FLAG_UNKNOWN); + } + if (flag & KCDB_IDENT_FLAG_INVALID) { + id->flags &= ~(KCDB_IDENT_FLAG_VALID | KCDB_IDENT_FLAG_UNKNOWN); + } + + newflags = id->flags; + + LeaveCriticalSection(&cs_ident); + + delta |= newflags ^ oldflags; + + if((delta & KCDB_IDENT_FLAG_HIDDEN)) { + kcdbint_ident_post_message( + (newflags & KCDB_IDENT_FLAG_HIDDEN)?KCDB_OP_HIDE:KCDB_OP_UNHIDE, + vid); + } + + if((delta & KCDB_IDENT_FLAG_SEARCHABLE)) { + kcdbint_ident_post_message( + (newflags & KCDB_IDENT_FLAG_SEARCHABLE)?KCDB_OP_SETSEARCH:KCDB_OP_UNSETSEARCH, + vid); + } + + if(delta != 0) + kcdbint_ident_post_message(KCDB_OP_MODIFY, vid); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_flags(khm_handle vid, + khm_int32 * flags) { + kcdb_identity * id; + + *flags = 0; + + if(!kcdb_is_active_identity(vid)) + return KHM_ERROR_INVALID_PARAM; + + id = (kcdb_identity *) vid; + + EnterCriticalSection(&cs_ident); + *flags = id->flags; + LeaveCriticalSection(&cs_ident); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_name(khm_handle vid, + wchar_t * buffer, + khm_size * pcbsize) { + size_t namesize; + kcdb_identity * id; + + if(!kcdb_is_active_identity(vid) || !pcbsize) + return KHM_ERROR_INVALID_PARAM; + + id = (kcdb_identity *) vid; + + if(FAILED(StringCbLength(id->name, KCDB_IDENT_MAXCB_NAME, &namesize))) + return KHM_ERROR_UNKNOWN; + + namesize += sizeof(wchar_t); + + if(!buffer || namesize > *pcbsize) { + *pcbsize = namesize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buffer, *pcbsize, id->name); + *pcbsize = namesize; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_default(khm_handle * pvid) { + khm_handle def; + + if (pvid == NULL) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_ident); + def = kcdb_def_identity; + if (def != NULL) + kcdb_identity_hold(def); + LeaveCriticalSection(&cs_ident); + + *pvid = def; + + if (def != NULL) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +static khm_int32 +kcdbint_ident_set_default(khm_handle vid, + khm_boolean invoke_identpro) { + kcdb_identity * new_def; + kcdb_identity * old_def; + khm_int32 rv; + + if (vid != NULL && !kcdb_is_active_identity(vid)) + return KHM_ERROR_INVALID_PARAM; + + new_def = (kcdb_identity *)vid; + + if (new_def != NULL && (new_def->flags & KCDB_IDENT_FLAG_DEFAULT)) + return KHM_ERROR_SUCCESS; + + if ((new_def == NULL && kcdb_def_identity == NULL) || + (new_def == kcdb_def_identity)) + return KHM_ERROR_SUCCESS; + + /* first check with the identity provider if this operation + is permitted. */ + if (invoke_identpro) { + rv = kcdb_identpro_set_default(vid); + if(rv != KHM_ERROR_NO_PROVIDER && KHM_FAILED(rv)) + return rv; + } + + EnterCriticalSection(&cs_ident); + + old_def = kcdb_def_identity; + kcdb_def_identity = new_def; + + if(old_def != new_def) { + if(old_def) { + old_def->flags &= ~KCDB_IDENT_FLAG_DEFAULT; + kcdb_identity_release((khm_handle) old_def); + } + + if(new_def) { + new_def->flags |= KCDB_IDENT_FLAG_DEFAULT; + kcdb_identity_hold((khm_handle) new_def); + } + + LeaveCriticalSection(&cs_ident); + + /* if (invoke_identpro) */ + kcdbint_ident_post_message(KCDB_OP_NEW_DEFAULT, new_def); + } else { + LeaveCriticalSection(&cs_ident); + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_default(khm_handle vid) { + return kcdbint_ident_set_default(vid, TRUE); +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_default_int(khm_handle vid) { + return kcdbint_ident_set_default(vid, FALSE); +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_config(khm_handle vid, + khm_int32 flags, + khm_handle * result) { + khm_handle hkcdb; + khm_handle hidents = NULL; + khm_handle hident = NULL; + khm_int32 rv; + kcdb_identity * id; + + if(kcdb_is_active_identity(vid)) { + id = (kcdb_identity *) vid; + } else { + return KHM_ERROR_INVALID_PARAM; + } + + hkcdb = kcdb_get_config(); + if(hkcdb) { + rv = khc_open_space(hkcdb, L"Identity", 0, &hidents); + if(KHM_FAILED(rv)) + goto _exit; + + rv = khc_open_space(hidents, + id->name, + flags | KCONF_FLAG_NOPARSENAME, + &hident); + + if(KHM_FAILED(rv)) { + khm_int32 oldflags; + EnterCriticalSection(&cs_ident); + oldflags = id->flags; + id->flags &= ~KCDB_IDENT_FLAG_CONFIG; + LeaveCriticalSection(&cs_ident); + if (oldflags & KCDB_IDENT_FLAG_CONFIG) + kcdbint_ident_post_message(KCDB_OP_DELCONFIG, id); + goto _exit; + } + + EnterCriticalSection(&cs_ident); + id->flags |= KCDB_IDENT_FLAG_CONFIG; + LeaveCriticalSection(&cs_ident); + + *result = hident; + } else + rv = KHM_ERROR_UNKNOWN; + +_exit: + if(hidents) + khc_close_space(hidents); + if(hkcdb) + khc_close_space(hkcdb); + return rv; +} + +/*! \note cs_ident must be available. */ +void +kcdbint_ident_post_message(khm_int32 op, kcdb_identity * id) { + kcdb_identity_hold(id); + kmq_post_message(KMSG_KCDB, KMSG_KCDB_IDENT, op, (void *) id); +} + +/*! \note cs_ident must be available. */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_hold(khm_handle vid) { + kcdb_identity * id; + + EnterCriticalSection(&cs_ident); + if(kcdb_is_active_identity(vid)) { + id = vid; + id->refcount++; + } else { + LeaveCriticalSection(&cs_ident); + return KHM_ERROR_INVALID_PARAM; + } + LeaveCriticalSection(&cs_ident); + return ERROR_SUCCESS; +} + +/*! \note cs_ident must be available. */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_release(khm_handle vid) { + kcdb_identity * id; + khm_int32 refcount; + + EnterCriticalSection(&cs_ident); + if(kcdb_is_identity(vid)) { + id = vid; + refcount = --id->refcount; + if(refcount == 0) { + /* We only delete identities which do not have a + configuration. */ + if (id->refcount == 0 && + !(id->flags & KCDB_IDENT_FLAG_CONFIG)) + kcdb_identity_delete(vid); + } + } else { + LeaveCriticalSection(&cs_ident); + return KHM_ERROR_INVALID_PARAM; + } + LeaveCriticalSection(&cs_ident); + return ERROR_SUCCESS; +} + +struct kcdb_idref_result { + kcdb_identity * ident; + khm_int32 flags; + khm_size count; +}; + +static khm_int32 KHMAPI +kcdbint_idref_proc(khm_handle cred, void * r) { + khm_handle vid; + struct kcdb_idref_result *result; + khm_int32 flags; + + result = (struct kcdb_idref_result *) r; + + if (KHM_SUCCEEDED(kcdb_cred_get_identity(cred, &vid))) { + if (result->ident == (kcdb_identity *) vid) { + + result->count++; + kcdb_cred_get_flags(cred, &flags); + + if (flags & KCDB_CRED_FLAG_RENEWABLE) { + result->flags |= KCDB_IDENT_FLAG_CRED_RENEW; + if (flags & KCDB_CRED_FLAG_INITIAL) { + result->flags |= KCDB_IDENT_FLAG_RENEWABLE; + } + } + + if (flags & KCDB_CRED_FLAG_EXPIRED) { + result->flags |= KCDB_IDENT_FLAG_CRED_EXP; + if (flags & KCDB_CRED_FLAG_INITIAL) { + result->flags |= KCDB_IDENT_FLAG_EXPIRED; + } + } + + if (flags & KCDB_CRED_FLAG_INITIAL) { + result->flags |= KCDB_IDENT_FLAG_VALID; + } + } + + kcdb_identity_release(vid); + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_refresh(khm_handle vid) { + kcdb_identity * ident; + khm_int32 code = KHM_ERROR_SUCCESS; + struct kcdb_idref_result result; + + EnterCriticalSection(&cs_ident); + + if (!kcdb_is_active_identity(vid)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + ident = (kcdb_identity *) vid; + + result.ident = ident; + result.flags = 0; + result.count = 0; + + LeaveCriticalSection(&cs_ident); + + kcdb_credset_apply(NULL, kcdbint_idref_proc, &result); + + if (result.count == 0) + result.flags |= KCDB_IDENT_FLAG_EMPTY; + + kcdb_identity_set_flags(vid, result.flags, + KCDB_IDENT_FLAGMASK_RDWR & + ~(KCDB_IDENT_FLAG_DEFAULT | + KCDB_IDENT_FLAG_SEARCHABLE | + KCDB_IDENT_FLAG_STICKY)); + + EnterCriticalSection(&cs_ident); + ident->refresh_cycle = kcdb_ident_refresh_cycle; + + _exit: + LeaveCriticalSection(&cs_ident); + + if (code == 0) + code = kcdb_identpro_update(vid); + + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_refresh_all(void) { + kcdb_identity * ident; + kcdb_identity * next; + khm_int32 code = KHM_ERROR_SUCCESS; + int hit_count; + + EnterCriticalSection(&cs_ident); + + kcdb_ident_refresh_cycle++; + + /* The do-while loop is here to account for race conditions. We + release cs_ident in the for loop, so we don't actually have a + guarantee that we traversed the whole identity list at the end. + We repeat until all the identities are uptodate. */ + + do { + hit_count = 0; + + for (ident = kcdb_identities; + ident != NULL; + ident = next) { + + if (!kcdb_is_active_identity(ident) || + ident->refresh_cycle == kcdb_ident_refresh_cycle) { + next = LNEXT(ident); + continue; + } + + kcdb_identity_hold((khm_handle) ident); + + LeaveCriticalSection(&cs_ident); + + kcdb_identity_refresh((khm_handle) ident); + + EnterCriticalSection(&cs_ident); + + next = LNEXT(ident); + kcdb_identity_release((khm_handle) ident); + + hit_count++; + } + + } while (hit_count > 0); + + LeaveCriticalSection(&cs_ident); + + return code; +} + +/*****************************************/ +/* Custom property functions */ + +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_attr(khm_handle vid, + khm_int32 attr_id, + void * buffer, + khm_size cbbuf) +{ + kcdb_identity * id = NULL; + kcdb_attrib * attrib = NULL; + kcdb_type * type = NULL; + khm_size slot; + khm_size cbdest; + khm_int32 code = KHM_ERROR_SUCCESS; + + EnterCriticalSection(&cs_ident); + if(!kcdb_is_active_identity(vid)) { + LeaveCriticalSection(&cs_ident); + return KHM_ERROR_INVALID_PARAM; + } + + id = (kcdb_identity *) vid; + + if(!(id->flags & KCDB_IDENT_FLAG_ATTRIBS)) { + kcdb_buf_new(&id->buf, KCDB_BUF_DEFAULT); + id->flags |= KCDB_IDENT_FLAG_ATTRIBS; + } + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { + LeaveCriticalSection(&cs_ident); + return KHM_ERROR_INVALID_PARAM; + } + +#if 0 + /* actually, even if an attribute is computed, we still allow + those values to be set. This is because computing values + is only for credentials. If a computed value is used as a + property in any other object, it is treated as a regular value + */ + if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) + { + LeaveCriticalSection(&cs_ident); + kcdb_attrib_release_info(attrib); + return KHM_ERROR_INVALID_OPERATION; + } +#endif + + if (buffer == NULL) { + /* we are removing a value */ + slot = kcdb_buf_slot_by_id(&id->buf, attr_id); + if (slot != KCDB_BUF_INVALID_SLOT && + kcdb_buf_exist(&id->buf, slot)) + kcdb_buf_alloc(&id->buf, slot, attr_id, 0); + code = KHM_ERROR_SUCCESS; + goto _exit; + } + + if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { + LeaveCriticalSection(&cs_ident); + kcdb_attrib_release_info(attrib); + return KHM_ERROR_INVALID_PARAM; + } + + if(!(type->isValid(buffer,cbbuf))) { + code = KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + + if((type->dup(buffer, cbbuf, NULL, &cbdest)) != KHM_ERROR_TOO_LONG) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + kcdb_buf_alloc(&id->buf, KCDB_BUF_APPEND, attr_id, cbdest); + slot = kcdb_buf_slot_by_id(&id->buf, attr_id); + if(slot == KCDB_BUF_INVALID_SLOT || !kcdb_buf_exist(&id->buf, slot)) { + code = KHM_ERROR_NO_RESOURCES; + goto _exit; + } + + if(KHM_FAILED(code = + type->dup(buffer, cbbuf, kcdb_buf_get(&id->buf, slot), &cbdest))) + { + kcdb_buf_alloc(&id->buf, slot, attr_id, 0); + goto _exit; + } + + kcdb_buf_set_value_flag(&id->buf, slot); + +_exit: + LeaveCriticalSection(&cs_ident); + + if(attrib) + kcdb_attrib_release_info(attrib); + if(type) + kcdb_type_release_info(type); + + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_attrib(khm_handle vid, + const wchar_t * attr_name, + void * buffer, + khm_size cbbuf) +{ + khm_int32 attr_id = -1; + + if(KHM_FAILED(kcdb_attrib_get_id(attr_name, &attr_id))) + return KHM_ERROR_INVALID_PARAM; + + return kcdb_identity_set_attr( + vid, + attr_id, + buffer, + cbbuf); +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_attr(khm_handle vid, + khm_int32 attr_id, + khm_int32 * attr_type, + void * buffer, + khm_size * pcbbuf) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_identity * id = NULL; + kcdb_attrib * attrib = NULL; + kcdb_type * type = NULL; + khm_size slot; + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { + return KHM_ERROR_INVALID_PARAM; + } + + if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { + kcdb_attrib_release_info(attrib); + return KHM_ERROR_UNKNOWN; + } + + if(attr_type) + *attr_type = attrib->type; + + EnterCriticalSection(&cs_ident); + + if(!kcdb_is_active_identity(vid)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + id = (kcdb_identity *) vid; + + if(!(id->flags & KCDB_IDENT_FLAG_ATTRIBS) || + (slot = kcdb_buf_slot_by_id(&id->buf, attr_id)) == KCDB_BUF_INVALID_SLOT || + !kcdb_buf_val_exist(&id->buf, slot)) + { + code = KHM_ERROR_NOT_FOUND; + goto _exit; + } + + if(!buffer && !pcbbuf) { + /* in this case the caller is only trying to determine if the field + contains data. If we get here, then the value exists. */ + code = KHM_ERROR_SUCCESS; + goto _exit; + } + +#if 0 + if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) { + /* we should never hit this case */ +#ifdef DEBUG + assert(FALSE); +#endif + code = KHM_ERROR_INVALID_OPERATION; + } else { +#endif + code = type->dup( + kcdb_buf_get(&id->buf, slot), + kcdb_buf_size(&id->buf, slot), + buffer, + pcbbuf); +#if 0 + } +#endif + +_exit: + LeaveCriticalSection(&cs_ident); + if(type) + kcdb_type_release_info(type); + if(attrib) + kcdb_attrib_release_info(attrib); + + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_attrib(khm_handle vid, + const wchar_t * attr_name, + khm_int32 * attr_type, + void * buffer, + khm_size * pcbbuf) +{ + khm_int32 attr_id = -1; + + if(KHM_FAILED(kcdb_attrib_get_id(attr_name, &attr_id))) + return KHM_ERROR_NOT_FOUND; + + return kcdb_identity_get_attr(vid, + attr_id, + attr_type, + buffer, + pcbbuf); +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_attr_string(khm_handle vid, + khm_int32 attr_id, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_identity * id = NULL; + kcdb_attrib * attrib = NULL; + kcdb_type * type = NULL; + khm_size slot; + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { + return KHM_ERROR_INVALID_PARAM; + } + + if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { + kcdb_attrib_release_info(attrib); + return KHM_ERROR_UNKNOWN; + } + + EnterCriticalSection(&cs_ident); + + if(!kcdb_is_active_identity(vid)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + id = (kcdb_identity *) vid; + + if(!(id->flags & KCDB_IDENT_FLAG_ATTRIBS) || + (slot = kcdb_buf_slot_by_id(&id->buf, attr_id)) == KCDB_BUF_INVALID_SLOT || + !kcdb_buf_val_exist(&id->buf, slot)) + { + code = KHM_ERROR_NOT_FOUND; + goto _exit; + } + + if(!buffer && !pcbbuf) { + /* in this case the caller is only trying to determine if the field + contains data. If we get here, then the value exists */ + code = KHM_ERROR_SUCCESS; + goto _exit; + } + +#if 0 + if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) { +#ifdef DEBUG + assert(FALSE); +#endif + code = KHM_ERROR_INVALID_OPERATION; + } else { +#endif + if(kcdb_buf_exist(&id->buf, slot)) { + code = type->toString( + kcdb_buf_get(&id->buf, slot), + kcdb_buf_size(&id->buf, slot), + buffer, + pcbbuf, + flags); + } else + code = KHM_ERROR_NOT_FOUND; +#if 0 + } +#endif + +_exit: + LeaveCriticalSection(&cs_ident); + if(type) + kcdb_type_release_info(type); + if(attrib) + kcdb_attrib_release_info(attrib); + + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_attrib_string(khm_handle vid, + const wchar_t * attr_name, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags) +{ + khm_int32 attr_id = -1; + + if(KHM_FAILED(kcdb_attrib_get_id(attr_name, &attr_id))) + return KHM_ERROR_NOT_FOUND; + + return kcdb_identity_get_attr_string( + vid, + attr_id, + buffer, + pcbbuf, + flags); +} + +/*****************************************/ +/* Identity provider interface functions */ + +/* NOT called with cs_ident held */ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_validate_name(const wchar_t * name) +{ + kcdb_ident_name_xfer namex; + khm_handle sub; + khm_size cch; + khm_int32 rv = KHM_ERROR_SUCCESS; + + /* we need to verify the length and the contents of the string + 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) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + rv = KHM_ERROR_NO_PROVIDER; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + ZeroMemory(&namex, sizeof(namex)); + + namex.name_src = name; + namex.result = KHM_ERROR_NOT_IMPLEMENTED; + + kmq_send_sub_msg(sub, + KMSG_IDENT, + KMSG_IDENT_VALIDATE_NAME, + 0, + (void *) &namex); + + rv = namex.result; + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identpro_validate_identity(khm_handle identity) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_handle sub; + + if(!kcdb_is_active_identity(identity)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + rv = KHM_ERROR_NO_PROVIDER; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + rv = kmq_send_sub_msg(sub, + KMSG_IDENT, + KMSG_IDENT_VALIDATE_IDENTITY, + 0, + (void *) identity); + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identpro_canon_name(const wchar_t * name_in, + wchar_t * name_out, + khm_size * cb_name_out) +{ + khm_handle sub; + kcdb_ident_name_xfer namex; + wchar_t name_tmp[KCDB_IDENT_MAXCCH_NAME]; + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_size cch; + + if(cb_name_out == 0 || + FAILED(StringCchLength(name_in, KCDB_IDENT_MAXCCH_NAME, &cch))) + return KHM_ERROR_INVALID_NAME; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + rv = KHM_ERROR_NO_PROVIDER; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + ZeroMemory(&namex, sizeof(namex)); + ZeroMemory(name_tmp, sizeof(name_tmp)); + + namex.name_src = name_in; + namex.name_dest = name_tmp; + namex.cb_name_dest = sizeof(name_tmp); + namex.result = KHM_ERROR_NOT_IMPLEMENTED; + + rv = kmq_send_sub_msg(sub, + KMSG_IDENT, + KMSG_IDENT_CANON_NAME, + 0, + (void *) &namex); + + if(KHM_SUCCEEDED(namex.result)) { + const wchar_t * name_result; + khm_size cb; + + if(name_in[0] != 0 && name_tmp[0] == 0) + name_result = name_tmp; + else + name_result = name_in; + + if(FAILED(StringCbLength(name_result, KCDB_IDENT_MAXCB_NAME, &cb))) + rv = KHM_ERROR_UNKNOWN; + else { + cb += sizeof(wchar_t); + if(name_out == 0 || *cb_name_out < cb) { + rv = KHM_ERROR_TOO_LONG; + *cb_name_out = cb; + } else { + StringCbCopy(name_out, *cb_name_out, name_result); + *cb_name_out = cb; + rv = KHM_ERROR_SUCCESS; + } + } + } + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identpro_compare_name(const wchar_t * name1, + const wchar_t * name2) +{ + khm_handle sub; + kcdb_ident_name_xfer namex; + khm_int32 rv = 0; + + /* Generally in kcdb_identpro_* functions we don't emulate + any behavior if the provider is not available, but lacking + a way to make this known, we emulate here */ + rv = wcscmp(name1, name2); + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + ZeroMemory(&namex, sizeof(namex)); + namex.name_src = name1; + namex.name_alt = name2; + namex.result = rv; + + kmq_send_sub_msg(sub, + KMSG_IDENT, + KMSG_IDENT_COMPARE_NAME, + 0, + (void *) &namex); + + rv = namex.result; + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identpro_set_default(khm_handle identity) +{ + khm_handle sub; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if((identity != NULL) && + !kcdb_is_active_identity(identity)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + rv = KHM_ERROR_NO_PROVIDER; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + rv = kmq_send_sub_msg(sub, + KMSG_IDENT, + KMSG_IDENT_SET_DEFAULT, + (identity != NULL), + (void *) identity); + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identpro_set_searchable(khm_handle identity, + khm_boolean searchable) +{ + khm_handle sub; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!kcdb_is_active_identity(identity)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + rv = KHM_ERROR_NO_PROVIDER; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + rv = kmq_send_sub_msg( + sub, + KMSG_IDENT, + KMSG_IDENT_SET_SEARCHABLE, + searchable, + (void *) identity); + } + + return rv; +} + + +KHMEXP khm_int32 KHMAPI +kcdb_identpro_update(khm_handle identity) +{ + khm_handle sub; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!kcdb_is_active_identity(identity)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + rv = KHM_ERROR_NO_PROVIDER; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + rv = kmq_send_sub_msg(sub, + KMSG_IDENT, + KMSG_IDENT_UPDATE, + 0, + (void *) identity); + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identpro_notify_create(khm_handle identity) +{ + khm_handle sub; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!kcdb_is_active_identity(identity)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + rv = KHM_ERROR_NO_PROVIDER; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + rv = kmq_send_sub_msg( + sub, + KMSG_IDENT, + KMSG_IDENT_NOTIFY_CREATE, + 0, + (void *) identity); + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identpro_get_ui_cb(void * rock) +{ + khm_handle sub; + khm_int32 rv = KHM_ERROR_SUCCESS; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + rv = KHM_ERROR_NO_PROVIDER; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + rv = kmq_send_sub_msg( + sub, + KMSG_IDENT, + KMSG_IDENT_GET_UI_CALLBACK, + 0, + rock); + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_enum(khm_int32 and_flags, + khm_int32 eq_flags, + wchar_t * name_buf, + khm_size * pcb_buf, + khm_size * pn_idents) +{ + kcdb_identity * id; + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_size cb_req = 0; + khm_size n_idents = 0; + size_t cb_curr; + size_t cch_curr; + size_t cch_left; + HRESULT hr; + + if ((name_buf == NULL && pcb_buf == NULL && pn_idents == NULL) || + (name_buf != NULL && pcb_buf == NULL)) + return KHM_ERROR_INVALID_PARAM; + + eq_flags &= and_flags; + + EnterCriticalSection(&cs_ident); + + if (!kcdb_checked_config) { + khm_handle h_kcdb = NULL; + khm_handle h_idents = NULL; + khm_handle h_ident = NULL; + + kcdb_checked_config = TRUE; + kcdb_checking_config = TRUE; + + h_kcdb = kcdb_get_config(); + if (!h_kcdb) + goto _config_check_cleanup; + if(KHM_FAILED(khc_open_space(h_kcdb, L"Identity", 0, &h_idents))) + goto _config_check_cleanup; + + while(KHM_SUCCEEDED(khc_enum_subspaces(h_idents, + h_ident, + &h_ident))) { + + wchar_t wname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khm_handle t_id; + + cb = sizeof(wname); + if (KHM_FAILED(khc_get_config_space_name(h_ident, + wname, + &cb))) + continue; + + LeaveCriticalSection(&cs_ident); + + if (KHM_SUCCEEDED(kcdb_identity_create(wname, + KCDB_IDENT_FLAG_CREATE, + &t_id))) + kcdb_identity_release(t_id); + + EnterCriticalSection(&cs_ident); + } + + _config_check_cleanup: + if (h_kcdb) + khc_close_space(h_kcdb); + if (h_idents) + khc_close_space(h_idents); + + kcdb_checking_config = FALSE; + } + + for ( id = kcdb_identities; + id != NULL; + id = LNEXT(id) ) { + if (((id->flags & KCDB_IDENT_FLAG_ACTIVE) == + KCDB_IDENT_FLAG_ACTIVE) && + ((id->flags & and_flags) == eq_flags)) { + n_idents ++; + hr = StringCbLength(id->name, KCDB_IDENT_MAXCB_NAME, &cb_curr); +#ifdef DEBUG + assert(SUCCEEDED(hr)); +#endif + cb_req += cb_curr + sizeof(wchar_t); + } + } + + cb_req += sizeof(wchar_t); + + if (pn_idents != NULL) + *pn_idents = n_idents; + + if (pcb_buf != NULL && (name_buf == NULL || *pcb_buf < cb_req)) { + *pcb_buf = cb_req; + + rv = KHM_ERROR_TOO_LONG; + } else if(name_buf != NULL) { + cch_left = (*pcb_buf) / sizeof(wchar_t); + + for (id = kcdb_identities; + id != NULL; + id = LNEXT(id)) { + if (((id->flags & KCDB_IDENT_FLAG_ACTIVE) == + KCDB_IDENT_FLAG_ACTIVE) && + ((id->flags & and_flags) == eq_flags)) { + StringCchLength(id->name, KCDB_IDENT_MAXCCH_NAME, + &cch_curr); + cch_curr++; + StringCchCopy(name_buf, cch_left, id->name); + cch_left -= cch_curr; + name_buf += cch_curr; + } + } + + *name_buf = L'\0'; + *pcb_buf = cb_req; + } + + LeaveCriticalSection(&cs_ident); + + return rv; +} diff --git a/src/windows/identity/kcreddb/identity.h b/src/windows/identity/kcreddb/identity.h index be0205d96..ba55a201b 100644 --- a/src/windows/identity/kcreddb/identity.h +++ b/src/windows/identity/kcreddb/identity.h @@ -1,60 +1,60 @@ -/* - * 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_KCDB_IDENTITY_H -#define __KHIMAIRA_KCDB_IDENTITY_H - -/* Identity */ - -#define KCDB_IDENT_HASHTABLE_SIZE 31 - -typedef struct kcdb_identity_t { - khm_int32 magic; - wchar_t * name; - khm_int32 flags; - khm_int32 refcount; - kcdb_buf buf; - khm_ui_4 refresh_cycle; - LDCL(struct kcdb_identity_t); -} kcdb_identity; - -#define KCDB_IDENT_MAGIC 0x31938d4f - -extern hashtable * kcdb_identities_namemap; -extern khm_int32 kcdb_n_identities; -extern kcdb_identity * kcdb_identities; /* all identities */ -extern kcdb_identity * kcdb_def_identity; /* default identity */ -extern khm_ui_4 kcdb_ident_refresh_cycle; - -void kcdbint_ident_init(void); -void kcdbint_ident_exit(void); -void kcdbint_ident_msg_completion(kmq_message * m); -void kcdbint_ident_post_message(khm_int32 op, kcdb_identity * id); - -#define kcdb_is_identity(id) ((id) && ((kcdb_identity *)(id))->magic == KCDB_IDENT_MAGIC) -#define kcdb_is_active_identity(id) (kcdb_is_identity(id) && (((kcdb_identity *)(id))->flags & KCDB_IDENT_FLAG_ACTIVE)) - -#endif +/* + * 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_KCDB_IDENTITY_H +#define __KHIMAIRA_KCDB_IDENTITY_H + +/* Identity */ + +#define KCDB_IDENT_HASHTABLE_SIZE 31 + +typedef struct kcdb_identity_t { + khm_int32 magic; + wchar_t * name; + khm_int32 flags; + khm_int32 refcount; + kcdb_buf buf; + khm_ui_4 refresh_cycle; + LDCL(struct kcdb_identity_t); +} kcdb_identity; + +#define KCDB_IDENT_MAGIC 0x31938d4f + +extern hashtable * kcdb_identities_namemap; +extern khm_int32 kcdb_n_identities; +extern kcdb_identity * kcdb_identities; /* all identities */ +extern kcdb_identity * kcdb_def_identity; /* default identity */ +extern khm_ui_4 kcdb_ident_refresh_cycle; + +void kcdbint_ident_init(void); +void kcdbint_ident_exit(void); +void kcdbint_ident_msg_completion(kmq_message * m); +void kcdbint_ident_post_message(khm_int32 op, kcdb_identity * id); + +#define kcdb_is_identity(id) ((id) && ((kcdb_identity *)(id))->magic == KCDB_IDENT_MAGIC) +#define kcdb_is_active_identity(id) (kcdb_is_identity(id) && (((kcdb_identity *)(id))->flags & KCDB_IDENT_FLAG_ACTIVE)) + +#endif diff --git a/src/windows/identity/kcreddb/init.c b/src/windows/identity/kcreddb/init.c index 13ef4da55..cea97a8c7 100644 --- a/src/windows/identity/kcreddb/init.c +++ b/src/windows/identity/kcreddb/init.c @@ -1,91 +1,91 @@ -/* - * 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 - -/* set to TRUE when the configuration is loaded */ -static int kcdb_config_loaded = 0; - -/* global state cs */ -static CRITICAL_SECTION cs_kcdb_global; - -/* forward dcl */ -void KHMAPI kcdb_msg_completion(kmq_message * m); - -void kcdb_init(void) { - /* setup the critical sections */ - InitializeCriticalSection(&cs_kcdb_global); - - kmq_set_completion_handler(KMSG_KCDB, kcdb_msg_completion); - - kcdb_credtype_init(); - kcdbint_ident_init(); - kcdb_credset_init(); - kcdb_cred_init(); - kcdb_type_init(); - kcdb_attrib_init(); -} - -void kcdb_exit(void) { - - kcdb_attrib_exit(); - kcdb_type_exit(); - kcdb_cred_exit(); - kcdb_credset_exit(); - kcdbint_ident_exit(); - kcdb_credtype_exit(); - - kmq_set_completion_handler(KMSG_KCDB, NULL); - - DeleteCriticalSection(&cs_kcdb_global); -} - -khm_handle kcdb_get_config(void) { - khm_handle space = NULL; - - EnterCriticalSection(&cs_kcdb_global); - if(!kcdb_config_loaded) { - khc_load_schema(NULL, schema_kcdbconfig); - kcdb_config_loaded = 1; - } - khc_open_space(NULL, L"KCDB", 0, &space); - LeaveCriticalSection(&cs_kcdb_global); - - return space; -} - -void KHMAPI kcdb_msg_completion(kmq_message * m) { - if(!m) - return; - if(m->subtype == KMSG_KCDB_IDENT) - kcdbint_ident_msg_completion(m); - else if(m->subtype == KMSG_KCDB_ATTRIB) - kcdb_attrib_msg_completion(m); - else if(m->subtype == KMSG_KCDB_TYPE) - kcdb_type_msg_completion(m); - else if(m->subtype == KMSG_KCDB_CREDTYPE) - kcdb_credtype_msg_completion(m); -} +/* + * 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 + +/* set to TRUE when the configuration is loaded */ +static int kcdb_config_loaded = 0; + +/* global state cs */ +static CRITICAL_SECTION cs_kcdb_global; + +/* forward dcl */ +void KHMAPI kcdb_msg_completion(kmq_message * m); + +void kcdb_init(void) { + /* setup the critical sections */ + InitializeCriticalSection(&cs_kcdb_global); + + kmq_set_completion_handler(KMSG_KCDB, kcdb_msg_completion); + + kcdb_credtype_init(); + kcdbint_ident_init(); + kcdb_credset_init(); + kcdb_cred_init(); + kcdb_type_init(); + kcdb_attrib_init(); +} + +void kcdb_exit(void) { + + kcdb_attrib_exit(); + kcdb_type_exit(); + kcdb_cred_exit(); + kcdb_credset_exit(); + kcdbint_ident_exit(); + kcdb_credtype_exit(); + + kmq_set_completion_handler(KMSG_KCDB, NULL); + + DeleteCriticalSection(&cs_kcdb_global); +} + +khm_handle kcdb_get_config(void) { + khm_handle space = NULL; + + EnterCriticalSection(&cs_kcdb_global); + if(!kcdb_config_loaded) { + khc_load_schema(NULL, schema_kcdbconfig); + kcdb_config_loaded = 1; + } + khc_open_space(NULL, L"KCDB", 0, &space); + LeaveCriticalSection(&cs_kcdb_global); + + return space; +} + +void KHMAPI kcdb_msg_completion(kmq_message * m) { + if(!m) + return; + if(m->subtype == KMSG_KCDB_IDENT) + kcdbint_ident_msg_completion(m); + else if(m->subtype == KMSG_KCDB_ATTRIB) + kcdb_attrib_msg_completion(m); + else if(m->subtype == KMSG_KCDB_TYPE) + kcdb_type_msg_completion(m); + else if(m->subtype == KMSG_KCDB_CREDTYPE) + kcdb_credtype_msg_completion(m); +} diff --git a/src/windows/identity/kcreddb/kcreddb.h b/src/windows/identity/kcreddb/kcreddb.h index 4b15a245f..9d54105c4 100644 --- a/src/windows/identity/kcreddb/kcreddb.h +++ b/src/windows/identity/kcreddb/kcreddb.h @@ -1,3329 +1,3329 @@ -/* - * 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_KCREDDB_H__ -#define __KHIMAIRA_KCREDDB_H__ - -#include -#include - - -/*! \defgroup kcdb NetIDMgr Credentials Database */ -/*@{*/ - -/*! \brief Maximum length in characters of short description - - The length includes the terminating \a NULL character. - */ -#define KCDB_MAXCCH_SHORT_DESC 256 - -/*! \brief Maximum length in bytes of short description - - The length includes the terminating \a NULL character. - */ -#define KCDB_MAXCB_SHORT_DESC (sizeof(wchar_t) * KCDB_MAXCCH_SHORT_DESC) - -/*! \brief Maximum length in characters of long description - - The length includes the terminating \a NULL character. - */ -#define KCDB_MAXCCH_LONG_DESC 8192 - -/*! \brief Maximum length in characters of long description - - The length includes the terminating \a NULL character. - */ -#define KCDB_MAXCB_LONG_DESC (sizeof(wchar_t) * KCDB_MAXCCH_LONG_DESC) - -/*! \brief Maximum length in characters of name - - The length includes the terminating \a NULL character. - */ -#define KCDB_MAXCCH_NAME 256 - -/*! \brief Maximum length in bytes of short description - - The length includes the terminating \a NULL character. - */ -#define KCDB_MAXCB_NAME (sizeof(wchar_t) * KCDB_MAXCCH_NAME) - -/*! \brief Automatically determine the number of bytes required - - Can be used in most places where a count of bytes is required. - For many objects, the number of bytes that are required can be - determined through context and may be ommited. In such cases you - can use the \a KCDB_CBSIZE_AUTO value to specify that the function - is to determine the size automatically. - - \note Not all functions that take a count of bytes support the \a - KCDB_CBSIZE_AUTO value. -*/ -#define KCDB_CBSIZE_AUTO (-1) - -/*! -\defgroup kcdb_ident Identities - -Functions, macros etc. for manipulating identities. -*/ - -/*@{*/ - -/*! \brief The maximum number of characters (including terminator) that can - be specified as an identity name */ -#define KCDB_IDENT_MAXCCH_NAME 256 - -/*! \brief The maximum number of bytes that can be specified as an identity - 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 */ -/*@{*/ - -/*! \brief Create the identity if it doesn't already exist. - \note Only to be used with kcdb_identity_create() */ -#define KCDB_IDENT_FLAG_CREATE 0x10000000L - -/*! \brief Has configuration information - - Indicates that the identity has persistent configuration - information associated with it. - */ -#define KCDB_IDENT_FLAG_CONFIG 0x00800000L - -/*! \brief Marks the identity as active. - - An active identity is one that is in active use within NetIDMgr. - - \note This flag is readonly and cannot be specified when creating - or modifying an identity. Once an identity is deleted, it will - no longer have this flag. */ -#define KCDB_IDENT_FLAG_ACTIVE 0x02000000L - - -/*! \brief The identity has custom attributes assigned - */ -#define KCDB_IDENT_FLAG_ATTRIBS 0x08000000L - -/*! \brief This is the default identity. - - At most one identity will have this flag set at any given time. - To set or reset the flag, use kcdb_identity_set_default() */ -#define KCDB_IDENT_FLAG_DEFAULT 0x00000001L - -/*! \brief This identity can be searched. - - The meaning of this flag is left to be interpreted by individual - plugins. */ -#define KCDB_IDENT_FLAG_SEARCHABLE 0x00000002L - -/*! \brief Hidden identity. - - The identity will not show up in the identity list window. Once - the hidden is switched off, the identity (and all associated - credentials) will re-appear in the window */ -#define KCDB_IDENT_FLAG_HIDDEN 0x00000004L - -/*! \brief Invalid identity - - For one reason or another, this identity is invalid. This flag - can be set by an identity provider to indicate that this identity - does not correspond to an actual identity because an external - entity (such as a KDC) has denied it's existence. - - The absence of this flag does not imply that the identity is - valid. The ::KCDB_IDENT_FLAG_VALID bit must be set for that to be - the case. If neither flag is set, then the status of the identity - is not known. -*/ -#define KCDB_IDENT_FLAG_INVALID 0x00000008L - -/*! \brief Valid identity - - The identity has been validated through an external entity, or - it's validity implied through the existence of credentials for the - identity. - - The absence of this flag does not imply that the identity is - invalid. The ::KCDB_IDENT_FLAG_INVALID bit must be set for that - to be the case. If neither flag is set, then the status of the - identity is not known. - */ -#define KCDB_IDENT_FLAG_VALID 0x00000010L - -/*! \brief Expired identity - - This identity has expired and can not be actively used to obtain - credentials. This determination is made based on the input of - some external entity. This flag may only be set by an identity - provider. -*/ -#define KCDB_IDENT_FLAG_EXPIRED 0x00000020L - -/*! \brief Empty identity - - The identity does not have actual credentials associated with it. - */ -#define KCDB_IDENT_FLAG_EMPTY 0x00000040L - -/*! \brief Renewable identity - - The initial credentials associated with this identity are - renewable. Thus making the whole identity renewable. - */ -#define KCDB_IDENT_FLAG_RENEWABLE 0x00000080L - -/*! \brief Required user interaction - - The identity is in a state which requires user interaction to - activate. Currently, the identity may not be in a state where it - can be used to obtain credentials. - - A typical example of this is when the primary password for an - identity has expired. - */ -#define KCDB_IDENT_FLAG_INTERACT 0x00000100L - -/*! \brief Has expired credentials - - The identity has expired credentials associated with it. - */ -#define KCDB_IDENT_FLAG_CRED_EXP 0x00000200L - -/*! \brief Has renewable credentials - - The identity has renewable credentials associated with it. If the - initial credentials of the identity are renewable, then identity - is renewable. Hence the ::KCDB_IDENT_FLAG_RENEWABLE should also - be set. - */ -#define KCDB_IDENT_FLAG_CRED_RENEW 0x00000400L - -/*! \brief Sticky identity - - Sticky identities are identities that are always visible in the - credentials display even if no credentials are associated with it. - */ -#define KCDB_IDENT_FLAG_STICKY 0x00000800L - -/*! \brief Unknown state - - The validity of the identity cannot be determined. This usually - means that an authority could not be contacted. This flag is to - be treated as transient. If ::KCDB_IDENT_FLAG_INVALID or - ::KCDB_IDENT_FLAG_VALID is set for the identity, this flag is to - be ignored. - */ -#define KCDB_IDENT_FLAG_UNKNOWN 0x00001000L - -/*! \brief Read/write flags mask. - - A bitmask that correspond to all the read/write flags in the mask. -*/ -#define KCDB_IDENT_FLAGMASK_RDWR 0x00001fffL - -/*@}*/ - -/*! \name Identity Provider Data Structures -@{*/ - -/*! \brief Name transfer structure - - Used when the KCDB is communicating with the identity provider to - exchange string names of identities. See individual ::KMSG_IDENT - message subtypes for the usage of this structure. - */ -typedef struct tag_kcdb_ident_name_xfer { - const wchar_t * name_src; /*!< An identity name. Does not - exceed KCDB_IDENT_MAXCCH_NAME - characters including terminating - NULL. */ - const wchar_t * name_alt; /*!< An identity name. Does not - exceed KCDB_IDENT_MAXCCH_NAME - characters including terminating - NULL. */ - wchar_t * name_dest; /*!< Pointer to a buffer that is to - receive a response string. The - size of the buffer in bytes is - specified in \a cb_name_dest. */ - khm_size cb_name_dest; /*!< Size of buffer pointed to by \a - name_dest in bytes. */ - khm_int32 result; /*!< Receives a result value, which is - usually an error code defined in - kherror.h, though it is not - always. */ -} kcdb_ident_name_xfer; - -typedef struct tag_kcdb_ident_info { - khm_handle identity; - khm_int32 fields; - - FILETIME expiration; -} kcdb_ident_info; - -/*@}*/ - -/*! \name Identity provider interface functions - - These functions encapsulate safe calls to the current identity - provider. While these functions are exported, applications should - not call these functions directly. They are provided for use by - the NetIDMgr core application. -@{*/ - -/*! \brief Validate an identity name - - The name that is provided will be passed through sets of - validations. One set, which doesn't depend on the identity - provider checks whether the length of the identity name and - whether there are any invalid characters in the identity name. If - the name passes those tests, then the name is passed down to the - identity provider's name validation handler. - - \retval KHM_ERROR_SUCCESS The name is valid - \retval KHM_ERROR_TOO_LONG Too many characters in name - \retval KHM_ERROR_INVALID_NAME There were invalid characters in the name. - \retval KHM_ERROR_NO_PROVIDER There is no identity provider; - however the name passed the length and character tests. - \retval KHM_ERROR_NOT_IMPLEMENTED The identity provider doesn't - implement a name validation handler; however the name passed - the length and character tests. - - \see ::KMSG_IDENT_VALIDATE_NAME - */ -KHMEXP khm_int32 KHMAPI -kcdb_identpro_validate_name(const wchar_t * name); - -/*! \brief Validate an identity - - The identity itself needs to be validated. This may involve - communicating with an external entity. - - \see ::KMSG_IDENT_VALIDATE_IDENTITY - */ -KHMEXP khm_int32 KHMAPI -kcdb_identpro_validate_identity(khm_handle identity); - -/*! \brief Canonicalize the name - - - \see ::KMSG_IDENT_CANON_NAME -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identpro_canon_name(const wchar_t * name_in, - wchar_t * name_out, - khm_size * cb_name_out); - -/*! \brief Compare two identity names - - \see ::KMSG_IDENT_COMPARE_NAME -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identpro_compare_name(const wchar_t * name1, - const wchar_t * name2); - -/*! \brief Set the specified identity as the default - - \see ::KMSG_IDENT_SET_DEFAULT -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identpro_set_default(khm_handle identity); - -/*! \brief Set the specified identity as searchable - - \see ::KMSG_IDENT_SET_SEARCHABLE -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identpro_set_searchable(khm_handle identity, - khm_boolean searchable); - -/*! \brief Update the specified identity - - \see ::KMSG_IDENT_UPDATE -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identpro_update(khm_handle identity); - -/*! \brief Obtain the UI callback - - \a rock is actually a pointer to a ::khui_ident_new_creds_cb which - is to receive the callback. - - \see ::KMSG_IDENT_GET_UI_CALLBACK - */ -KHMEXP khm_int32 KHMAPI -kcdb_identpro_get_ui_cb(void * rock); - -/*! \brief Notify an identity provider of the creation of a new identity - - \see ::KMSG_IDENT_NOTIFY_CREATE -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identpro_notify_create(khm_handle identity); - -/*@}*/ - -/*! \brief Check if the given name is a valid identity name - - \return TRUE or FALSE to the question, is this valid? -*/ -KHMEXP khm_boolean KHMAPI -kcdb_identity_is_valid_name(const wchar_t * name); - -/*! \brief Create or open an identity. - - If the KCDB_IDENT_FLAG_CREATE flag is specified in the flags - parameter a new identity will be created if one does not already - exist with the given name. If an identity by that name already - exists, then the existing identity will be opened. The result - parameter will receive a held reference to the opened identity. - Use kcdb_identity_release() to release the handle. - - \param[in] name Name of identity to create - \param[in] flags If KCDB_IDENT_FLAG_CREATE is specified, then the - identity will be created if it doesn't already exist. - Additional flags can be set here which will be assigned to the - identity if it is created. Additional flags have no effect if - an existing identity is opened. - \param[out] result If the call is successful, this receives a held - reference to the identity. The caller should call - kcdb_identity_release() to release the identity once it is no - longer needed. - */ -KHMEXP khm_int32 KHMAPI -kcdb_identity_create(const wchar_t *name, - khm_int32 flags, - khm_handle * result); - -/*! \brief Mark an identity for deletion. - - The identity will be marked for deletion. The - KCDB_IDENT_FLAG_ACTIVE will no longer be present for this - identity. Once all references to the identity are released, it - will be removed from memory. All associated credentials will also - be removed. */ -KHMEXP khm_int32 KHMAPI -kcdb_identity_delete(khm_handle id); - -/*! \brief Set or unset the specified flags in the specified identity. - - Only flags that are in KCDB_IDENT_FLAGMASK_RDWR can be specifed in - the \a flags parameter or the \a mask parameter. The flags set in - the \a mask parameter of the identity will be set to the - corresponding values in the \a flags parameter. - - If ::KCDB_IDENT_FLAG_INVALID is set using this function, then the - ::KCDB_IDENT_FLAG_VALID will be automatically reset, and vice - versa. Resetting either bit does not undo this change, and will - leave the identity's validity unspecified. Setting either of - ::KCDB_IDENT_FLAG_INVALID or ::KCDB_IDENT_FLAG_VALID will - automatically reset ::KCDB_IDENT_FLAG_UNKNOWN. - - Note that setting or resetting certain flags have other semantic - side-effects: - - - ::KCDB_IDENT_FLAG_DEFAULT : Setting this is equivalent to - calling kcdb_identity_set_default() with \a id. Resetting this - is equivalent to calling kcdb_identity_set_default() with NULL. - - - ::KCDB_IDENT_FLAG_SEARCHABLE : Setting this will result in the - identity provider getting notified of the change. If the - identity provider indicates that searchable flag should not be - set or reset on the identity, then kcdb_identity_set_flags() - will return an error. - - \note kcdb_identity_set_flags() is not atomic. Even if the - function returns a failure code, some flags in the identity may - have been set. When calling kcdb_identity_set_flags() always - check the flags in the identity using kcdb_identity_get_flags() to - check which flags have been set and which have failed. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identity_set_flags(khm_handle id, - khm_int32 flags, - khm_int32 mask); - -/*! \brief Return all the flags for the identity - - The returned flags may include internal flags. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_flags(khm_handle id, - khm_int32 * flags); - -/*! \brief Return the name of the identity - - \param[out] buffer Buffer to copy the identity name into. The - maximum size of an identity name is \a KCDB_IDENT_MAXCB_NAME. - If \a buffer is \a NULL, then the required size of the buffer - is returned in \a pcbsize. - - \param[in,out] pcbsize Size of buffer in bytes. */ -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_name(khm_handle id, - wchar_t * buffer, - khm_size * pcbsize); - -/*! \brief Set the specified identity as the default. - - Specifying NULL effectively makes none of the identities the - default. - - \see kcdb_identity_set_flags() -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identity_set_default(khm_handle id); - -/*! \brief Mark the specified identity as the default. - - This API is reserved for use by identity providers as a means of - specifying which identity is default. The difference between - kcdb_identity_set_default() and kcdb_identity_set_default_int() is - in semantics. - - - kcdb_identity_set_default() is used to request the KCDB to - designate the specified identity as the default. When - processing the request, the KCDB invokes the identity provider - to do the necessary work to make the identity the default. - - - kcdb_identity_set_default_int() is used by the identity provider - to notify the KCDB that the specified identity is the default. - This does not result in the invocation of any other semantics to - make the identity the default other than releasing the previous - defualt identity and making the specified one the default. - */ -KHMEXP khm_int32 KHMAPI -kcdb_identity_set_default_int(khm_handle id); - -/*! \brief Get the default identity - - Obtain a held handle to the default identity if there is one. The - handle must be freed using kcdb_identity_release(). - - If there is no default identity, then the handle pointed to by \a - pvid is set to \a NULL and the function returns - KHM_ERROR_NOT_FOUND. */ -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_default(khm_handle * pvid); - -/*! \brief Get the configuration space for the identity. - - If the configuration space for the identity does not exist and the - flags parameter does not specify ::KHM_FLAG_CREATE, then the - function will return a failure code as specified in - ::khc_open_space(). Depending on whether or not a configuration - space was found, the ::KCDB_IDENT_FLAG_CONFIG flag will be set or - reset for the identity. - - \param[in] id Identity for which the configuraiton space is requested - - \param[in] flags Flags used when calling khc_open_space(). If \a - flags specifies KHM_FLAG_CREATE, then the configuration space - is created. - - \param[out] result The resulting handle. If the call is - successful, this receives a handle to the configuration space. - Use khc_close_space() to close the handle. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_config(khm_handle id, - khm_int32 flags, - khm_handle * result); - -/*! \brief Hold a reference to an identity. - - A reference to an identity (a handle) is only valid while it is - held. \note Once the handle is released, it can not be - revalidated by calling kcdb_identity_hold(). Doing so would lead - to unpredictable consequences. */ -KHMEXP khm_int32 KHMAPI -kcdb_identity_hold(khm_handle id); - -/*! \brief Release a reference to an identity. - \see kcdb_identity_hold() */ -KHMEXP khm_int32 KHMAPI -kcdb_identity_release(khm_handle id); - -/*! \brief Set the identity provider subscription - - If there was a previous subscription, that subscription will be - automatically deleted. - - \param[in] sub New identity provider subscription -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identity_set_provider(khm_handle sub); - -/*! \brief Set the primary credentials type - - The primary credentials type is designated by the identity - provider. As such, this function should only be called by an - identity provider. - */ -KHMEXP khm_int32 KHMAPI -kcdb_identity_set_type(khm_int32 cred_type); - -/*! \brief Retrieve the identity provider subscription - - \param[out] sub Receives the current identity provider - subscription. Set to NULL if only the existence of an - identity provider needs to be checked. - - \retval KHM_ERROR_SUCCESS An identity provider exists. If \a sub - was not NULL, the subscription has been copied there. - - \retval KHM_ERROR_NOT_FOUND There is currently no registered - identity provider. If \a sub was not NULL, the handle it - points to has been set to NULL. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_provider(khm_handle * sub); - -/*! \brief Retrieve the identity provider credentials type - - This is the credentials type that the identity provider has - designated as the primary credentials type. - */ -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_type(khm_int32 * ptype); - -/*! \brief Returns TRUE if the two identities are equal - - Also returns TRUE if both identities are NULL. - */ -KHMEXP khm_boolean KHMAPI -kcdb_identity_is_equal(khm_handle identity1, - khm_handle identity2); - -/*! \brief Set an attribute in an identity by attribute id - - \param[in] buffer A pointer to a buffer containing the data to - assign to the attribute. Setting \a buffer to NULL has the - effect of removing any data that is already assigned to the - attribute. If \a buffer is non-NULL, then \a cbbuf should - specify the number of bytes in \a buffer. - - \param[in] cbbuf Number of bytes of data in \a buffer. The - individual data type handlers may copy in less than this many - bytes in to the credential. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identity_set_attr(khm_handle identity, - khm_int32 attr_id, - void * buffer, - khm_size cbbuf); - -/*! \brief Set an attribute in an identity by name - - The attribute name has to be a KCDB registered attribute or - property. - - \param[in] cbbuf Number of bytes of data in \a buffer. The - individual data type handlers may copy in less than this many - bytes in to the credential. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identity_set_attrib(khm_handle identity, - const wchar_t * attr_name, - void * buffer, - khm_size cbbuf); - -/*! \brief Get an attribute from an identity by attribute id. - - \param[in] buffer The buffer that is to receive the attribute - value. Set this to NULL if only the required buffer size is - to be returned. - - \param[in,out] cbbuf The number of bytes available in \a buffer. - If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and - sets this to the required buffer size. - - \param[out] attr_type Receives the data type of the attribute. - Set this to NULL if the type is not required. - - \note Set both \a buffer and \a cbbuf to NULL if only the - existence of the attribute is to be checked. If the attribute - exists in this identity then the function will return - KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_attr(khm_handle identity, - khm_int32 attr_id, - khm_int32 * attr_type, - void * buffer, - khm_size * pcbbuf); - -/*! \brief Get an attribute from an identity by name. - - \param[in] buffer The buffer that is to receive the attribute - value. Set this to NULL if only the required buffer size is - to be returned. - - \param[in,out] cbbuf The number of bytes available in \a buffer. - If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and - sets this to the required buffer size. - - \note Set both \a buffer and \a cbbuf to NULL if only the - existence of the attribute is to be checked. If the attribute - exists in this identity then the function will return - KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_attrib(khm_handle identity, - const wchar_t * attr_name, - khm_int32 * attr_type, - void * buffer, - khm_size * pcbbuf); - -/*! \brief Get the string representation of an identity attribute. - - A shortcut function which generates the string representation of - an identity attribute directly. - - \param[in] identity A handle to an identity - - \param[in] attr_id The attribute to retrieve - - \param[out] buffer A pointer to a string buffer which receives the - string form of the attribute. Set this to NULL if you only - want to determine the size of the required buffer. - - \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, - holds the size of the buffer pointed to by \a buffer, and on - exit, receives the actual number of bytes that were copied. - - \param[in] flags Flags for the string conversion. Can be set to - one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is - KCDB_TS_LONG. - - \retval KHM_ERROR_SUCCESS Success - \retval KHM_ERROR_NOT_FOUND The given attribute was either invalid - or was not defined for this identity - \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid - \retval KHM_ERROR_TOO_LONG Either \a buffer was NULL or the - supplied buffer was insufficient -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_attr_string(khm_handle identity, - khm_int32 attr_id, - wchar_t * buffer, - khm_size * pcbbuf, - khm_int32 flags); - -/*! \brief Get the string representation of an identity attribute by name. - - A shortcut function which generates the string representation of - an identity attribute directly. - - \param[in] identity A handle to an identity - - \param[in] attrib The name of the attribute to retrieve - - \param[out] buffer A pointer to a string buffer which receives the - string form of the attribute. Set this to NULL if you only - want to determine the size of the required buffer. - - \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, - holds the size of the buffer pointed to by \a buffer, and on - exit, receives the actual number of bytes that were copied. - - \param[in] flags Flags for the string conversion. Can be set to - one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is - KCDB_TS_LONG. - - \see kcdb_identity_get_attr_string() -*/ -KHMEXP khm_int32 KHMAPI -kcdb_identity_get_attrib_string(khm_handle identity, - const wchar_t * attr_name, - wchar_t * buffer, - khm_size * pcbbuf, - khm_int32 flags); - -/*! \brief Enumerate identities - - Enumerates all the active identities that match the criteria - specified using \a and_flags and \a eq_flags. The condition is - applied to all active identities as follows: - - \code - (identity->flags & and_flags) == (eq_flags & and_flags) - \endcode - - Essentially, if a flag is set in \a and_flags, then that flag in - the identity should equal the setting in \a eq_flags. - - \param[in] and_flags See above - - \param[in] eq_flags See above - - \param[out] name_buf Buffer to receive the list of identity names. - Can be NULL if only the required size of the buffer or the - number of matching identities is required. The list is - returned as a multi string. - - \param[in,out] pcb_buf Number of bytes in buffer pointed to by \a - name_buf on entry. On exit, will receive the number of bytes - copied. Can be NULL only if \a name_buf is also NULL. If \a - name_buf is NULL or if \a pcb_buf indicates that the buffer is - insufficient, this will receive the number of bytes required - and the return value of the function will be - KHM_ERROR_TOO_LONG - - \param[out] pn_idents Receives the number of identities that match - the given criteria. - - \retval KHM_ERROR_SUCCESS If \a name_buf was valid, the buffer now - contains a multi string of identities that matched. If \a - pn_idents was valid, it contains the number of identities - matched. - - \retval KHM_ERROR_TOO_LONG No buffer was supplied or the supplied - buffer was insufficient. If \a pn_idents was valid, it - contains the number of identities. - - \retval KHM_ERROR_INVALID_PARAM None of the parameters \a name_buf, - \a pcb_buf and \a pn_idents were supplied, or \a pcb_buf was - NULL when \a name_buf was not. - - \note Calling this function to obtain the required size of the - buffer and then calling it with a that sized buffer is not - guaranteed to work since the list of identities may change - between the two calls. - */ -KHMEXP khm_int32 KHMAPI -kcdb_identity_enum(khm_int32 and_flags, - khm_int32 eq_flags, - wchar_t * name_buf, - khm_size * pcb_buf, - khm_size * pn_idents); - -/*! \brief Refresh identity attributes based on root credential set - - Several flags in an identity are dependent on the credentials that - are associated with it in the root credential set. In addition, - other flags in an identity depend on external factors that need to - be verfied once in a while. This API goes through the root - credential set as well as consulting the identity provider to - update an identity. - - \see kcdb_identity_refresh() - */ -KHMEXP khm_int32 KHMAPI -kcdb_identity_refresh(khm_handle vid); - -/*! \brief Refresh all identities - - Equivalent to calling kcdb_identity_refresh() for all active - identities. - - \see kcdb_identityt_refresh() - */ -KHMEXP khm_int32 KHMAPI -kcdb_identity_refresh_all(void); - -/* KSMG_KCDB_IDENT notifications are structured as follows: - type=KMSG_KCDB - subtype=KMSG_KCDB_IDENT - uparam=one of KCDB_OP_* - blob=handle to identity in question */ - -/*@}*/ - - -/*********************************************************************/ - - -/*! -\defgroup kcdb_creds Credential sets and individual credentials - -@{ -*/ - - -/*! \brief Credentials process function - - This function is called for each credential in a credential set - when supplied to kcdb_credset_apply(). It should return - KHM_ERROR_SUCCESS to continue the operation, or any other value to - terminate the processing. - - \see kcdb_credset_apply() -*/ -typedef khm_int32 -(KHMAPI *kcdb_cred_apply_func)(khm_handle cred, - void * rock); - -/*! \brief Credentials filter function. - - Should return non-zero if the credential passed as \a cred is to - be "accepted". The precise consequence of a non-zero return value - is determined by the individual function that this call back is - passed into. - - This function should not call any other function which may modify - \a cred. - - \see kcdb_credset_collect_filtered() - \see kcdb_credset_extract_filtered() -*/ -typedef khm_int32 -(KHMAPI *kcdb_cred_filter_func)(khm_handle cred, - khm_int32 flags, - void * rock); - -/*! \brief Credentials compare function. - - Asserts a weak ordering on the credentials that are passed in as - \a cred1 and \a cred2. It should return: - - - a negative value if \a cred1 < \a cred2 - - zero if \a cred1 == \a cred2 - - a postive value if \a cred1 > \a cred2 - \see kcdb_credset_sort() - \see ::kcdb_credtype -*/ -typedef khm_int32 -(KHMAPI *kcdb_cred_comp_func)(khm_handle cred1, - khm_handle cred2, - void * rock); - -/*! \defgroup kcdb_credset Credential sets */ -/*@{*/ - -/*! \brief Create a credential set. - - Credential sets are temporary containers for credentials. These - can be used by plug-ins to store credentials while they are being - enumerated from an external source. Once all the credentials have - been collected into the credential set, the plug-in may call - kcdb_credset_collect() to collect the credentials into the root - credential store. - - The user interface will only display credentials that are in the - root credential store. No notifications are generated for changes - to a non-root credential set. - - Use kcdb_credset_delete() to delete the credential set once it is - created. - - \see kcdb_credset_delete() - \see kcdb_credset_collect() -*/ -KHMEXP khm_int32 KHMAPI -kcdb_credset_create(khm_handle * result); - -/** \brief Delete a credential set - - \see kcdb_credset_create() -*/ -KHMEXP khm_int32 KHMAPI -kcdb_credset_delete(khm_handle credset); - -/** \brief Collect credentials from a credential set to another credential set. - - Collecting a subset of credentials from credential set \a cs_src - into credential set \a cs_dest involves the following steps: - - - Select all credentials from \a cs_src that matches the \a - identity and \a type specified in the function call and add them - to the \a cs_dest credential set if they are not there already. - Note that if neither credential set is not the root credential - store, then the credentials will be added by reference, while if - it is the root credential store, the credentials will be - duplicated, and the copies will be added to \a cs_dest. - - - If a selected credential in \a cs_src already exists in \a - cs_dest, then update the credential in \a cs_dest with the - credential fields in \a cs_src. In other words, once a - credential is found to exist in both \a cs_src and \a cs_dest, - all the non-null fields from the credential in \a cs_src will be - copied to the credential in \a cs_dest. Fields which are null - (undefined) in \a cs_src and are non-null in \a cs_dest will be - left unmodified in \a cs_dest. - - One notable exception is the credentials' flags. All flags in - \a cs_src which are not included in - ::KCDB_CRED_FLAGMASK_ADDITIVE will be copied to the - corresponding bits in the flags of \a cs_dest. However, flags - that are included in ::KCDB_CRED_FLAGMASK_ADDITIVE will be added - to the corresponding bits in \a cs_dest. - - (See notes below) - - - Remove all credentials from \a cs_dest that match the \a - identity and \a type that do not appear in \a cs_src. (see notes - below) - - For performance reasons, plugins should use kcdb_credset_collect() - to update the root credentials store instead of adding and - removing individual credentials from the root store. - - Only credentials that are associated with active identities are - affected by kcdb_credset_collect(). - - \param[in] cs_dest A handle to the destination credential set. If - this is \a NULL, then it is assumed to refer to the root - credential store. - - \param[in] cs_src A handle to the source credential set. If this - is NULL, then it is assumed to refer to the root credential - store. - - \param[in] identity A handle to an identity. Setting this to NULL - collects all identities in the credential set. - - \param[in] type A credentials type. Setting this to - KCDB_CREDTYPE_ALL collects all credential types in the set. - - \param[out] delta A bit mask that indicates the modifications that - were made to \a cs_dest as a result of the collect operation. - This is a combination of KCDB_DELTA_* values. This parameter - can be \a NULL if the value is not required. - - \warning If \a identity and \a type is set to a wildcard, all - credentials in the root store that are not in this credentials - set will be deleted. - - \note Two credentials \a A and \a B are considered equal if: - - They refer to the same identity - - Both have the same credential type - - Both have the same name - - \note This is the only supported way of modifying the root - credential store. - - \note \a cs_src and \a cs_dest can not refer to the same - credentials set. - - \note The destination credential set cannot be sealed. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_credset_collect(khm_handle cs_dest, - khm_handle cs_src, - khm_handle identity, - khm_int32 type, - khm_int32 * delta); - -/*! \brief Credentials were added - \see kcdb_credset_collect() */ -#define KCDB_DELTA_ADD 1 - -/*! \brief Credentials were deleted - \see kcdb_credset_collect() */ -#define KCDB_DELTA_DEL 2 - -/*! \brief Credentials were modified - \see kcdb_credset_collect() */ -#define KCDB_DELTA_MODIFY 4 - -/*! \brief Indicates that the credential to be filtered is from the root store. - - \see kcdb_credset_collect_filtered() -*/ -#define KCDB_CREDCOLL_FILTER_ROOT 1 - -/*! \brief Indicates that the credential to be filtered is from the source - credential set - - \see kcdb_credset_collect_filtered() */ -#define KCDB_CREDCOLL_FILTER_SRC 2 - -/*! \brief Indicates that the credential to be filtered is from the destination - credential set - - \see kcdb_credset_collect_filtered() */ -#define KCDB_CREDCOLL_FILTER_DEST 4 - -/*! \brief Collect credentials from one credential set to another using a filter. - - Similar to kcdb_credset_collect() except instead of selecting - credentials by matching against an identity and/or type, a filter - function is called. If the filter function returns non-zero for a - credential, that credential is selected. - - Credentials in the source and destination credential sets are - passed into the filter function. Depending on whether the - credential is in the source credential set or destination - credential set, the \a flag parameter may have either \a - KCDB_CREDCOLL_FILTER_SRC or \a KCDB_CREDCOLL_FILTER_DEST bits set. - Also, if either one of the credential sets is the root credential - store, then additionally \a KCDB_CREDCOLL_FILTER_ROOT would also - be set. - - See the kcdb_credset_collect() documentation for explanations of - the \a cs_src, \a cs_dest and \a delta parameters which perform - identical functions. - - \param[in] filter The filter of type ::kcdb_cred_filter_func - \param[in] rock A custom argument to be passed to the filter function. - - \see kcdb_credset_collect() -*/ -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); - -/*! \brief Flush all credentials from a credential set - - Deletes all the crednetials from the credential set. - - \param[in] credset A handle to a credential set. Cannot be NULL. - - \note The credential set cannot be sealed -*/ -KHMEXP khm_int32 KHMAPI -kcdb_credset_flush(khm_handle credset); - -/*! \brief Extract credentials from one credential set to another - - Credentials from the source credential set are selected based on - the \a identity and \a type arguements. If a credential is - matched, then it is added to the \a destcredset. - - If the \a sourcecredset is the root credential set, the added - credentials are copies of the actual credentials in the root - credential set. Otherwise the credentials are references to the - original credentials in the \a sourcecredset . - - \param[in] destcredset Destination credential set. Must be valid. - - \param[in] sourcecredset The source credential set. If set to - NULL, extracts from the root credential set. - - \param[in] identity The identity to match in the source credential - 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_CREDTYPE_INVALID, matches all types. - - \note This function does not check for duplicate credentials. - - \note The destination credential set cannot be sealed. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_credset_extract(khm_handle destcredset, - khm_handle sourcecredset, - khm_handle identity, - khm_int32 type); - -/*! \brief Extract credentials from one credential set to another using a filter. - - Similar to kcdb_credset_extract() except a filter function is used - to determine which credentials should be selected. - - \param[in] rock A custom argument to be passed in to the filter function. - - \note The destination credential set cannot be sealed. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_credset_extract_filtered(khm_handle destcredset, - khm_handle sourcecredset, - kcdb_cred_filter_func filter, - void * rock); - -/*! \brief Retrieve a held reference to a credential in a credential set based on index. - - \param[in] idx The index of the credential to retrieve. This is a - zero based index which goes from 0 ... (size of credset - 1). - - \param[out] cred The held reference to a credential. Call - kcdb_cred_release() to release the credential. - - \retval KHM_ERROR_SUCCESS Success. \a cred has a held reference to the credential. - \retval KHM_ERROR_OUT_OF_BOUNDS The index specified in \a idx is out of bounds. - \retval KHM_ERROR_DELETED The credential at index \a idx has been marked as deleted. - - \see kcdb_cred_release() -*/ -KHMEXP khm_int32 KHMAPI -kcdb_credset_get_cred(khm_handle credset, - khm_int32 idx, - khm_handle * cred); - -/*! \brief Search a credential set for a specific credential - - The credential set indicated by \a credset is searched for a - credential that satisfies the predicate function \a f. Each - credential starting at \a idx_start is passed into the predicate - function until it returns a non-zero value. At this point, that - credential is passed in to the \a cred parameter, and the index of - the credential is passed into the \a idx parameter. - - \param[in] credset The credential set to search on. Specify NULL - if you want to search teh root credential set. - - \param[in] idx_start The index at which to start the search after. - The first credential passed to the predicate function will be - at \a idx_start + 1. Specify -1 to start from the beginning - of the credential set. - - \param[in] f The predicate function. The \a flags parameter of - the predicate function will always receive 0. - - \param[in] rock An opaque parameter to be passed to the predicate - function \a f. - - \param[out] cred A held reference to the credential that satisfied - the predicate function or NULL if no such credential was - found. Note that if a valid credential is returned, the - calling function must release the credential using - kcdb_cred_release(). - - \param[out] idx The index of the credential passed in \a cred. - Specify NULL if the index is not required. - - \retval KHM_ERROR_SUCCESS A credential that satisfied the - predicate function was found and was assigned to \a cred. - - \retval KHM_ERROR_NOT_FOUND No credential was found that matched - the predicate function. - - \note When querying credential sets that are shared between - threads, it is possible that another thread modifies the - credential set between successive calls to - kcdb_credset_find_filtered(). Therefore a continued sequences of - searches are not guaranteed to exhastively cover the - credential set nor to not return duplicate matches. Duplicate - matches are possible if the order of the credentials in the - set was changed. -*/ -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); - -/*! \brief Find matching credential - - Searches a credential set for a credential that matches the - specified credential. For a credential to be a match, it must - have the same identity, credential type and name. - - \param[in] credset Credential set to search - - \param[in] cred_src Credetial to search on - - \param[out] cred_dest receieves the matching credential if the - search is successful. If a handle is returend, the - kcdb_cred_release() must be used to release the handle. If - the matching credential is not required, you can pass in NULL. - - \retval KHM_ERROR_SUCCESS The search was successful. A credential - was assigned to \a cred_dest - - \retval KHM_ERROR_NOT_FOUND A matching credential was not found. - */ -KHMEXP khm_int32 KHMAPI -kcdb_credset_find_cred(khm_handle credset, - khm_handle cred_src, - khm_handle *cred_dest); - - -/*! \brief Delete a credential from a credential set. - - The credential at index \a idx will be deleted. All the - credentials that are at indices \a idx + 1 and above will be moved - down to fill the gap and the size of the credential set will - decrease by one. - - Use kcdb_credset_del_cred_ref() to delete a credential by - reference. Using kcdb_credset_del_cred() is faster than - kcdb_credset_del_cred_ref(). - - If you call kcdb_credset_del_cred() or kcdb_credset_del_cred_ref() - from within kcdb_credset_apply(), the credential will only be - marked as deleted. They will not be removed. This means that the - size of the credential set will not decrease. To purge the - deleted credentials from the set, call kcdb_credset_purge() after - kcdb_credset_apply() completes. - - \note The credential set cannot be sealed. - - \see kcdb_credset_del_cred_ref() -*/ -KHMEXP khm_int32 KHMAPI -kcdb_credset_del_cred(khm_handle credset, - khm_int32 idx); - -/*! \brief Delete a credential from a credential set by reference. - - See kcdb_credset_del_cred() for description of what happens when a - credential is deleted from a credential set. - - \note The credential set cannot be sealed. - - \see kcdb_credset_del_cred() -*/ -KHMEXP khm_int32 KHMAPI -kcdb_credset_del_cred_ref(khm_handle credset, - khm_handle cred); - -/*! \brief Add a credential to a credential set. - - The credential is added by reference. In other words, no copy of - the credential is made. - - \param[in] idx Index of the new credential. This must be a value - in the range 0..(previous size of credential set) or -1. If - -1 is specifed, then the credential is appended at the end of - the set. - - \note The credential set cannot be sealed. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_credset_add_cred(khm_handle credset, - khm_handle cred, - khm_int32 idx); - -/*! \brief Get the number of credentials in a credential set. - - Credentials in a credential set may be volatile. When - kcdb_credeset_get_size() is called, the credential set is - compacted to only include credentials that are active at the time. - However, when you are iterating through the credential set, it - might be the case that some credentials would get marked as - deleted. These credentials will remain in the credential set - until the credential set is discarded or another call to - kcdb_credset_get_size() or kdcb_credset_purge() is made. - - If the credential set is sealed, then it will not be compacted and - will include deleted credentials as well. - - \see kcdb_credset_purge() - \see kcdb_credset_get_cred() -*/ -KHMEXP khm_int32 KHMAPI -kcdb_credset_get_size(khm_handle credset, - khm_size * size); - -/*! \brief Removes credentials that have been marked as deleted from a credential set. - - See description of \a kcdb_credset_purge() for a description of - what happens when credntials that are contained in a credential - set are deleted by an external entity. - - \note The credential set cannot be sealed. - - \see kcdb_credset_get_size() - \see kcdb_credset_get_cred() -*/ -KHMEXP khm_int32 KHMAPI -kcdb_credset_purge(khm_handle credset); - -/*! \brief Applies a function to all the credentials in a credentials set - - The given function is called for each credential in a credential - set. With each iteration, the function is called with a handle to - the credential and the user defined parameter \a rock. If the - function returns anything other than KHM_ERROR_SUCCESS, the - processing stops. - - \param[in] credset The credential set to apply the function to, or - NULL if you want to apply this to the root credential set. - - \param[in] f Function to call for each credential - - \param[in] rock An opaque parameter which is to be passed to 'f' - as the second argument. - - \retval KHM_ERROR_SUCCESS All the credentials were processed. - - \retval KHM_ERROR_EXIT The supplied function signalled the - processing to be aborted. - - \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_credset_apply(khm_handle credset, - kcdb_cred_apply_func f, - void * rock); - -/*! \brief Sort the contents of a credential set. - - \param[in] rock A custom argument to be passed in to the \a comp function. - - \note The credential set cannot be sealed. - - \see kcdb_cred_comp_generic() -*/ -KHMEXP khm_int32 KHMAPI -kcdb_credset_sort(khm_handle credset, - kcdb_cred_comp_func comp, - void * rock); - -/*! \brief Seal a credential set - - Sealing a credential set makes it read-only. To unseal a - credential set, call kcdb_credset_unseal(). - - Sealing is an additive operation. kcdb_credset_seal() can be - called muliple times. However, for every call to - kcdb_credset_seal() a call to kcdb_credset_unseal() must be made - to undo the seal. The credential set will become unsealed when - all the seals are released. - - Once sealed, the credential set will not allow any operation that - might change its contents. However, a selaed credential set can - still be delted. - - \see kcdb_credset_unseal() - */ -KHMEXP khm_int32 KHMAPI -kcdb_credset_seal(khm_handle credset); - -/*! \brief Unseal a credential set - - Undoes what kcdb_credset_seal() did. This does not guarantee that - the credential set is unsealed since there may be other seals. - - \see kcdb_credset_seal() - */ -KHMEXP khm_int32 KHMAPI -kcdb_credset_unseal(khm_handle credset); - -/*! \brief Defines a sort criterion for kcdb_cred_comp_generic() - - \see kcdb_cred_comp_generic() -*/ -typedef struct tag_kcdb_cred_comp_field { - khm_int32 attrib; /*!< a valid attribute ID */ - khm_int32 order; /*!< one of KCDB_CRED_COMP_INCREASING or - KCDB_CRED_COMP_DECREASING. Optionally, - KCDB_CRED_COMP_INITIAL_FIRST may be combined - with either. */ -} kcdb_cred_comp_field; - -/*! \brief Defines the sort order for a field in ::kcdb_cred_comp_field - - Sorts lexicographically ascending by string representation of field. -*/ -#define KCDB_CRED_COMP_INCREASING 0 - -/*! \brief Defines the sort order for a field in ::kcdb_cred_comp_field - - Sorts lexicographically descending by string representation of - field. - */ -#define KCDB_CRED_COMP_DECREASING 1 - -/*! \brief Defines the sort order for a field in ::kcdb_cred_comp_field - - Any credentials which have the ::KCDB_CRED_FLAG_INITIAL will be - grouped above any that don't. - - If that does not apply, then credentials from the primary - credentials type will be sorted before others. -*/ -#define KCDB_CRED_COMP_INITIAL_FIRST 2 - -/*! \brief Defines the sort criteria for kcdb_cred_comp_generic() - - \see kcdb_cred_comp_generic() -*/ -typedef struct tag_kcdb_cred_comp_order { - khm_int32 nFields; - kcdb_cred_comp_field * fields; -} kcdb_cred_comp_order; - -/*! \brief A generic compare function for comparing credentials. - - This function can be passed as a parameter to kcdb_credset_sort(). - - The \a rock parameter to this function should be a pointer to a - ::kcdb_cred_comp_order object. The \a fields member of the - ::kcdb_cred_comp_order object should point to an array of - ::kcdb_cred_comp_field objects, each of which specifies the sort - order in decreasing order of priority. The number of - ::kcdb_cred_comp_field objects in the array should correspond to - the \a nFields member in the ::kcdb_cred_comp_order object. - - The array of ::kcdb_cred_comp_field objects define the sort - criteria, in order. The \a attrib member should be a valid - attribute ID, while the \a order member determines whether the - sort order is increasing or decreasing. The exact meaning or - increasing or decreasing depends on the data type of the - attribute. - - \param[in] rock a pointer to a ::kcdb_cred_comp_order object -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_comp_generic(khm_handle cred1, - khm_handle cred2, - void * rock); - -/*@}*/ - -/*! \defgroup kcdb_cred Credentials */ -/*@{*/ - -/*! \brief Maximum number of characters in a credential name */ -#define KCDB_CRED_MAXCCH_NAME 256 - -/*! \brief Maximum number of bytes in a credential name */ -#define KCDB_CRED_MAXCB_NAME (sizeof(wchar_t) * KCDB_CRED_MAXCCH_NAME) - -/*! \brief Marked as deleted */ -#define KCDB_CRED_FLAG_DELETED 0x00000008 - -/*! \brief Renewable */ -#define KCDB_CRED_FLAG_RENEWABLE 0x00000010 - -/*! \brief Initial - - Initial credentials form the basis of an identity. Some - properties of an initial credential, such as being renewable, are - directly inherited by the identity. An identity is also - automatically considered valid if it contains a valid initial - credential. - */ -#define KCDB_CRED_FLAG_INITIAL 0x00000020 - -/*! \brief Expired - - The credential's lifetime has ended. - */ -#define KCDB_CRED_FLAG_EXPIRED 0x00000040 - -/*! \brief Invalid - - The credential can no longer serve its intended function. This - may be because it is expired and is not renewable, or its - renewable time period has also expired, or for some other reason. - */ -#define KCDB_CRED_FLAG_INVALID 0x00000080 - -/*! \brief Credential is selected - - Indicates that the credential is selected. Note that using this - flag may be subject to race conditions. - */ -#define KCDB_CRED_FLAG_SELECTED 0x00000100 - -/*! \brief Bitmask indicating all known credential flags - */ -#define KCDB_CRED_FLAGMASK_ALL 0x0000ffff - -/*! \brief External flags - - These are flags that are provided by the credentials providers. - The other flags are internal to KCDB and should not be modified. - */ -#define KCDB_CRED_FLAGMASK_EXT (KCDB_CRED_FLAG_INITIAL | KCDB_CRED_FLAG_EXPIRED | KCDB_CRED_FLAG_INVALID | KCDB_CRED_FLAG_RENEWABLE) - -/*! \brief Bitmask indicating dditive flags - - Additive flags are special flags which are added to exiting - credentials based on new credentials when doing a collect - operation. See details on kcdb_credset_collect() - - \see kcdb_credset_collect() -*/ -#define KCDB_CRED_FLAGMASK_ADDITIVE KCDB_CRED_FLAG_SELECTED - -/*! \brief Generic credentials request - - This data structure is used as the format for a generic - credentials reqeust for a ::KMSG_KCDB_REQUEST message. A plugin - typically publishes this message so that a credentials provider - may handle it and in response, obtain the specified credential. - - While the \a identity, \a type and \a name members of the - structure are all optional, typically one would specify all three - or at least two for a credential provider to be able to provide - the credential unambigously. - - Credential providers do not need to respond to ::KMSG_KCDB_REQUEST - messages. However, if they do, they should make sure that they - are the only credential provider that is responding by setting the - \a semaphore member to a non-zero value. The \a semaphore is set - to zero when a request is initially sent out. When incrementing - the semaphore, the plugin should use a thread safe mechanism to - ensure that there are no race conditions that would allow more - than one provider to respond to the message. - */ -typedef struct tag_kcdb_cred_request { - khm_handle identity; /*!< Identity of the credential. Set - to NULL if not specified. */ - khm_int32 type; /*!< Type of the credential. Set to - KCDB_CREDTYPE_INVALID if not - specified. */ - wchar_t * name; /*!< Name of the credential. Set to - NULL if not specified. */ - - khm_handle dest_credset; /*!< If non-NULL, instructs whoever is - handling the request that the - credential thus obtained be placed - in this credential set in addition - to whereever it may place newly - acquired credentials. Note that - while this can be NULL if the new - credential does not need to be - placed in a credential set, it can - not equal the root credential - set. */ - - void * vparam; /*!< An unspecified - parameter. Specific credential types - may specify how this field is to be - used. */ - - long semaphore; /*!< Incremented by one when this - request is answered. Only one - credential provider is allowed to - answer a ::KMSG_KCDB_REQUEST - message. Initially, when the - message is sent out, this member - should be set to zero. */ -} kcdb_cred_request; - -/*! \brief Create a new credential - - \param[in] name Name of credential. \a name cannot be NULL and cannot - exceed \a KCDB_CRED_MAXCCH_NAME unicode characters including the - \a NULL terminator. - \param[in] identity A reference to an identity. - \param[in] cred_type A credentials type identifier for the credential. - \param[out] result Gets a held reference to the newly created credential. - Call kcdb_cred_release() or kcdb_cred_delete() to release the - reference. - \see kcdb_cred_release() -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_create(const wchar_t * name, - khm_handle identity, - khm_int32 cred_type, - khm_handle * result); - -/*! \brief Duplicate an existing credential. - - \param[out] newcred A held reference to the new credential if the call - succeeds. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_dup(khm_handle cred, - khm_handle * newcred); - -/*! \brief Updates one credential using field values from another - - All fields that exist in \a vsrc will get copied to \a vdest and will - overwrite any values that are already there in \a vdest. However any - values that exist in \a vdest taht do not exist in \a vsrc will not be - modified. - - \retval KHM_ERROR_SUCCESS vdest was successfully updated - \retval KHM_ERROR_EQUIVALENT all fields in vsrc were present and equivalent in vdest -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_update(khm_handle vdest, - khm_handle vsrc); - -/*! \brief Set an attribute in a credential by name - - - - \param[in] cbbuf Number of bytes of data in \a buffer. The - individual data type handlers may copy in less than this many - bytes in to the credential. For some data types where the - size of the buffer is fixed or can be determined from its - contents, you can specify ::KCDB_CBSIZE_AUTO for this - parameter. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_set_attrib(khm_handle cred, - const wchar_t * name, - void * buffer, - khm_size cbbuf); - -/*! \brief Set an attribute in a credential by attribute id - - \param[in] buffer A pointer to a buffer containing the data to - assign to the attribute. Setting this to NULL has the effect - of removing any data that is already assigned to the - attribute. If \a buffer is non-NULL, then \a cbbuf should - specify the number of bytes in \a buffer. - - \param[in] cbbuf Number of bytes of data in \a buffer. The - individual data type handlers may copy in less than this many - bytes in to the credential. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_set_attr(khm_handle cred, - khm_int32 attr_id, - void * buffer, - khm_size cbbuf); - -/*! \brief Get an attribute from a credential by name. - - \param[in] buffer The buffer that is to receive the attribute - value. Set this to NULL if only the required buffer size is - to be returned. - - \param[in,out] cbbuf The number of bytes available in \a buffer. - If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and - sets this to the required buffer size. - - \note Set both \a buffer and \a cbbuf to NULL if only the - existence of the attribute is to be checked. If the attribute - exists in this credential then the function will return - KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_get_attrib(khm_handle cred, - const wchar_t * name, - khm_int32 * attr_type, - void * buffer, - khm_size * cbbuf); - -/*! \brief Get an attribute from a credential by attribute id. - - \param[in] buffer The buffer that is to receive the attribute - value. Set this to NULL if only the required buffer size is - to be returned. - - \param[in,out] cbbuf The number of bytes available in \a buffer. - If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and - sets this to the required buffer size. - - \param[out] attr_type Receives the data type of the attribute. - Set this to NULL if the type is not required. - - \note Set both \a buffer and \a cbbuf to NULL if only the - existence of the attribute is to be checked. If the attribute - exists in this credential then the function will return - KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_get_attr(khm_handle cred, - khm_int32 attr_id, - khm_int32 * attr_type, - void * buffer, - khm_size * cbbuf); - -/*! \brief Get the name of a credential. - - \param[in] buffer The buffer that is to receive the credential - name. Set this to NULL if only the required buffer size is to - be returned. - - \param[in,out] cbbuf The number of bytes available in \a buffer. - If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and - sets this to the required buffer size. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_get_name(khm_handle cred, - wchar_t * buffer, - khm_size * cbbuf); - -/*! \brief Get the string representation of a credential attribute. - - A shortcut function which generates the string representation of a - credential attribute directly. - - \param[in] vcred A handle to a credential - - \param[in] attr_id The attribute to retrieve - - \param[out] buffer A pointer to a string buffer which receives the - string form of the attribute. Set this to NULL if you only - want to determine the size of the required buffer. - - \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, - holds the size of the buffer pointed to by \a buffer, and on - exit, receives the actual number of bytes that were copied. - - \param[in] flags Flags for the string conversion. Can be set to - one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is - KCDB_TS_LONG. - - \retval KHM_ERROR_SUCCESS Success - \retval KHM_ERROR_NOT_FOUND The given attribute was either invalid - or was not defined for this credential - \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid - \retval KHM_ERROR_TOO_LONG Either \a buffer was NULL or the - supplied buffer was insufficient -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_get_attr_string(khm_handle vcred, - khm_int32 attr_id, - wchar_t * buffer, - khm_size * pcbbuf, - khm_int32 flags); - -/*! \brief Get the string representation of a credential attribute by name. - - A shortcut function which generates the string representation of a - credential attribute directly. - - \param[in] vcred A handle to a credential - - \param[in] attrib The name of the attribute to retrieve - - \param[out] buffer A pointer to a string buffer which receives the - string form of the attribute. Set this to NULL if you only - want to determine the size of the required buffer. - - \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, - holds the size of the buffer pointed to by \a buffer, and on - exit, receives the actual number of bytes that were copied. - - \param[in] flags Flags for the string conversion. Can be set to - one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is - KCDB_TS_LONG. - - \see kcdb_cred_get_attr_string() -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_get_attrib_string(khm_handle cred, - const wchar_t * name, - wchar_t * buffer, - khm_size * cbbuf, - khm_int32 flags) ; - - -/*! \brief Get a held reference to the identity associated with a credential - - Use kcdb_identity_release() to release the reference that is - returned. - - \see kcdb_identity_relase() -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_get_identity(khm_handle cred, - khm_handle * identity); - -/*! \brief Set the identity of a credential - - While it is ill-advised to change the identity of a credential - that has been placed in one or more credential sets, there can be - legitimate reasons for doing so. Only change the identity of a - credential that is not placed in a credential set or placed in a - credential set that is only used by a single entity. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_set_identity(khm_handle vcred, - khm_handle id); - -/*! \brief Get the serial number for the credential. - - Each credential gets assigned a serial number at the time it is - created. This will stay with the credential for its lifetime. - - \param[out] pserial Receives the serial number. Cannot be NULL. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_get_serial(khm_handle cred, - khm_ui_8 * pserial); - -/*! \brief Get the type of the credential. - - The returned type is a credential type. Doh. - - \param[out] type Receives the type. Cannot be NULL. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_get_type(khm_handle cred, - khm_int32 * type); - -/*! \brief Retrieve flags from a credential - - The flags returned will be place in the location pointed to by \a - flags. Note that the specified credential must be an active - credential for the operation to succeed. This means the - ::KCDB_CRED_FLAG_DELETED will never be retured by this function. - */ -KHMEXP khm_int32 KHMAPI -kcdb_cred_get_flags(khm_handle cred, - khm_int32 * flags); - -/*! \brief Set the flags of a credential - - The flags specified in the \a mask parameter will be set to the - values specified in the \a flags parameter. The flags that are - not included in \a mask will not be modified. - - This function can not be used to set the ::KCDB_CRED_FLAG_DELETED - flag. If this bit is specified in either \a flags or \a mask, it - will be ignored. - - \see ::KCDB_CRED_FLAGMASK_ALL - */ -KHMEXP khm_int32 KHMAPI -kcdb_cred_set_flags(khm_handle cred, - khm_int32 flags, - khm_int32 mask); - -/*! \brief Hold a reference to a credential. - - Use kcdb_cred_release() to release the reference. - - \see kcdb_cred_release() -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_hold(khm_handle cred); - -/*! \brief Release a held reference to a credential. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_release(khm_handle cred); - -/*! \brief Delete a credential. - - The credential will be marked for deletion and will continue to - exist until all held references are released. If the credential - is bound to a credential set or the root credential store, it will - be removed from the respective container. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_cred_delete(khm_handle cred); - -/*! \brief Compare an attribute of two credentials by name. - - \return The return value is dependent on the type of the attribute - and indicate a weak ordering of the attribute values of the two - credentials. If one or both credentials do not contain the - attribute, the return value is 0, which signifies that no ordering - can be determined. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_creds_comp_attrib(khm_handle cred1, - khm_handle cred2, - const wchar_t * name); - -/*! \brief Compare an attribute of two credentials by attribute id. - - \return The return value is dependent on the type of the attribute - and indicate a weak ordering of the attribute values of the two - credentials. If one or both credentials do not contain the - attribute, the return value is 0, which signifies that no ordering - can be determined. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_creds_comp_attr(khm_handle cred1, - khm_handle cred2, - khm_int32 attr_id); - -/*! \brief Compare two credentials for equivalence - - \return Non-zero if the two credentials are equal. Zero otherwise. - \note Two credentials are considered equal if all the following hold: - - Both refer to the same identity. - - Both have the same name. - - Both have the same type. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_creds_is_equal(khm_handle cred1, - khm_handle cred2); - -/*@}*/ -/*@}*/ - -/********************************************************************/ - -/*! \defgroup kcdb_type Credential attribute types - -@{*/ - -/*! \brief Convert a field to a string - - Provides a string representation of a field in a credential. The - data buffer can be assumed to be valid. - - On entry, \a s_buf can be NULL if only the required size of the - buffer is to be returned. \a pcb_s_buf should be non-NULL and - should point to a valid variable of type ::khm_size that will, on - entry, contain the size of the buffer pointed to by \a s_buf if \a - s_buf is not \a NULL, and on exit will contain the number of bytes - consumed in \a s_buf, or the required size of the buffer if \a - s_buf was NULL or the size of the buffer was insufficient. - - The implementation should verify the parameters that are passed in - to the function. - - The data pointed to by \a data should not be modified in any way. - - \param[in] data Valid pointer to a block of data - - \param[in] cb_data Number of bytes in data block pointed to by \a - data - - \param[out] s_buf Buffer to receive the string representation of - data. If the data type flags has KCDB_TYPE_FLAG_CB_AUTO, then - this parameter could be set to KCDB_CBSIZE_AUTO. In this - case, the function should compute the size of the input buffer - assuming that the input buffer is valid. - - \param[in,out] pcb_s_buf On entry, contains the size of the buffer - pointed to by \a s_buf, and on exit, contains the number of - bytes used by the string representation of the data including - the NULL terminator - - \param[in] flags Flags for formatting the string - - \retval KHM_ERROR_SUCCESS The string representation of the data - field was successfully copied to \a s_buf and the size of the - buffer used was copied to \a pcb_s_buf. - - \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid - - \retval KHM_ERROR_TOO_LONG Either \a s_buf was \a NULL or the size - indicated by \a pcb_s_buf was too small to contain the string - representation of the value. The required size of the buffer - is in \a pcb_s_buf. - - \note This documents the expected behavior of this prototype function - - \see ::kcdb_type - */ -typedef khm_int32 -(KHMAPI *kcdb_dtf_toString)(const void * data, - khm_size cb_data, - wchar_t * s_buf, - khm_size * pcb_s_buf, - khm_int32 flags); - -/*! \brief Verifies whetehr the given buffer contains valid data - - The function should examine the buffer and the size of the buffer - and determine whether or not the buffer contains valid data for - this data type. - - The data field pointed to by \a data should not be modified in any - way. - - \param[in] data A pointer to a data buffer - - \param[in] cb_data The number of bytes in the data buffer. If the - data type flags has KCDB_TYPE_FLAG_CB_AUTO, then this - parameter could be set to KCDB_CBSIZE_AUTO. In this case, the - function should compute the size of the input buffer assuming - that the input buffer is valid. - - \return TRUE if the data is valid, FALSE otherwise. - - \note This documents the expected behavior of this prototype function - - \see ::kcdb_type -*/ -typedef khm_boolean -(KHMAPI *kcdb_dtf_isValid)(const void * data, - khm_size cb_data); - -/*! \brief Compare two fields - - Compare the two data fields and return a value indicating their - relative ordering. The return value follows the same - specification as strcmp(). - - Both data buffers that are passed in can be assumed to be valid. - - None of the data buffers should be modified in any way. - - \param[in] data_l Valid pointer to first data buffer - - \param[in] cb_data_l Number of bytes in \a data_l. If the data - type flags has KCDB_TYPE_FLAG_CB_AUTO, then this parameter - could be set to KCDB_CBSIZE_AUTO. In this case, the function - should compute the size of the input buffer assuming that the - input buffer is valid. - - \param[in] data_r Valid pointer to second data buffer - - \param[in] cb_data_r Number of bytes in \a data_r. If the data - type flags has KCDB_TYPE_FLAG_CB_AUTO, then this parameter - could be set to KCDB_CBSIZE_AUTO. In this case, the function - should compute the size of the input buffer assuming that the - input buffer is valid. - - \return The return value should be - - Less than zero if \a data_l < \a data_r - - Equal to zero if \a data_l == \a data_r or if this data type can not be compared - - Greater than zero if \a data_l > \a data_r - - \note This documents the expected behavior of this prototype function - - \see ::kcdb_type -*/ -typedef khm_int32 -(KHMAPI *kcdb_dtf_comp)(const void * data_l, - khm_size cb_data_l, - const void * data_r, - khm_size cb_data_r); - -/*! \brief Duplicate a data field - - Duplicates a data field. The buffer pointed to by \a data_src - contains a valid field. The function should copy the field with - appropriate adjustments to \a data_dst. - - The \a data_dst parameter can be NULL if only the required size of - the buffer is needed. In this case, teh function should set \a - pcb_data_dst to the number of bytes required and then return - KHM_ERROR_TOO_LONG. - - \param[in] data_src Pointer to a valid data buffer - - \param[in] cb_data_src Number of bytes in \a data_src. If the data - type flags has KCDB_TYPE_FLAG_CB_AUTO, then this parameter - could be set to KCDB_CBSIZE_AUTO. In this case, the function - should compute the size of the input buffer assuming that the - input buffer is valid. - - \param[out] data_dst Poitner to destination buffer. Could be NULL - if only the required size of the destination buffer is to be - returned. - - \param[in,out] pcb_data_dst On entry specifies the number of bytes - in \a data_dst, and on exit should contain the number of bytes - copied. - - \retval KHM_ERROR_SUCCESS The data was successfully copied. The - number of bytes copied is in \a pcb_data_dst - - \retval KHM_ERROR_INVALID_PARAM One or more parameters is incorrect. - - \retval KHM_ERROR_TOO_LONG Either \a data_dst was NULL or the size - of the buffer was insufficient. The required size is in \a - pcb_data_dst - - \note This documents the expected behavior of this prototype function - - \see ::kcdb_type - */ -typedef khm_int32 -(KHMAPI *kcdb_dtf_dup)(const void * data_src, - khm_size cb_data_src, - void * data_dst, - khm_size * pcb_data_dst); - -/*! \brief A data type descriptor. - - Handles basic operation for a specific data type. - - \see \ref cred_data_types -*/ -typedef struct tag_kcdb_type { - wchar_t * name; - khm_int32 id; - khm_int32 flags; - - khm_size cb_min; - khm_size cb_max; - - kcdb_dtf_toString toString; - /*!< Provides a string representation for a value. */ - - kcdb_dtf_isValid isValid; - /*!< Returns true of the value is valid for this data type */ - - kcdb_dtf_comp comp; - /*!< Compare two values and return \a strcmp style return value */ - - kcdb_dtf_dup dup; - /*!< Duplicate a value into a secondary buffer */ -} kcdb_type; - -/*! \name Flags for kcdb_type::toString -@{*/ -/*! \brief Specify that the short form of the string representation should be returned. - - Flags for #kcdb_type::toString. The flag specifies how long the - string representation should be. The specific length of a short - or long description is not restricted and it is up to the - implementation to choose how to interpret the flags. - - Usually, KCDB_TS_SHORT is specified when the amount of space that - is available to display the string is very restricted. It may be - the case that the string is truncated to facilitate displaying in - a constrainted space. -*/ -#define KCDB_TS_SHORT 1 - -/*! \brief Specify that the long form of the string representation should be returned - - Flags for #kcdb_type::toString. The flag specifies how long the - string representation should be. The specific length of a short - or long description is not restricted and it is up to the - implementation to choose how to interpret the flags. - -*/ -#define KCDB_TS_LONG 0 -/*@}*/ - -/*! \brief The maximum number of bytes allowed for a value of any type */ -#define KCDB_TYPE_MAXCB 16384 - -/*! \name Flags for kcdb_type -@{*/ - -/*! \brief The type supports KCDB_CBSIZE_AUTO. - - Used for types where the size of the object can be determined - through context or by the object content. Such as for objects - that have a fixed size or unicode strings that have a terminator. - - This implies that ALL the object manipulation callbacks that are - defined in this type definition support the KCDB_CBSIZE_AUTO - value. -*/ -#define KCDB_TYPE_FLAG_CB_AUTO 16 - -/*! \brief The \a cb_min member is valid. - - The \a cb_min member defines the minimum number of bytes that an - object of this type will consume. - - \note If this flag is used in conjunction with \a - KCDB_TYPE_FLAG_CB_MAX then, \a cb_min must be less than or equal - to \a cb_max. -*/ -#define KCDB_TYPE_FLAG_CB_MIN 128 - -/*! \brief The \a cb_max member is valid. - - The \a cb_max member defines the maximum number of bytes that an - object of this type will consume. - - \note If this flag is used in conjunction with \a - KCDB_TYPE_FLAG_CB_MIN then, \a cb_min must be less than or - equal to \a cb_max. */ -#define KCDB_TYPE_FLAG_CB_MAX 256 - -/*! \brief Denotes that objects of this type have a fixed size. - - If this flags is specified, then the type definition must also - specify cb_min and cb_max, which must both be the same value. - - \note Implies \a KCDB_TYPE_FLAG_CB_AUTO, \a KCDB_TYPE_FLAG_CB_MIN - and \a KCDB_TYPE_FLAG_CB_MAX. Pay special attention to the - implication of \a KCDB_TYPE_FLAG_AUTO. -*/ -#define KCDB_TYPE_FLAG_CB_FIXED (KCDB_TYPE_FLAG_CB_AUTO|KCDB_TYPE_FLAG_CB_MIN|KCDB_TYPE_FLAG_CB_MAX) - -/*@}*/ - -KHMEXP khm_int32 KHMAPI -kcdb_type_get_id(const wchar_t *name, khm_int32 * id); - -/*! \brief Return the type descriptor for a given type id - - \param[out] info Receives a held reference to a type descriptor. - Use kcdb_type_release_info() to release the handle. If the \a - 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, - khm_size * cbbuf); - -/*! \brief Register a credentials attribute type - - The credentials type record pointed to by \a type defines a new - credential attribute type. The \a id member of \a type may be set - to KCDB_TYPE_INVALID to indicate that an attribute ID is to be - generated automatically. - - \param[in] type The type descriptor - \param[out] new_id Receives the identifier for the credential attribute type. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_type_register(const kcdb_type * type, - khm_int32 * new_id); - -/*! \brief Unregister a credential attribute type - - Removes the registration for the specified credentials attribute - type. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_type_unregister(khm_int32 id); - -KHMEXP khm_int32 KHMAPI -kcdb_type_get_next_free(khm_int32 * id); - -/*! \name Conversion functions -@{*/ -/*! \brief Convert a time_t value to FILETIME -*/ -KHMEXP void KHMAPI -TimetToFileTime( time_t t, LPFILETIME pft ); - -/*! \brief Convert a time_t interval to a FILETIME interval -*/ -KHMEXP void KHMAPI -TimetToFileTimeInterval(time_t t, LPFILETIME pft); - -/*! \brief Convert a FILETIME interval to seconds -*/ -KHMEXP long KHMAPI -FtIntervalToSeconds(LPFILETIME pft); - -/*! \brief Convert a FILETIME interval to milliseconds -*/ -KHMEXP long KHMAPI -FtIntervalToMilliseconds(LPFILETIME pft); - -/*! \brief Compare two FILETIME values - - The return value is similar to the return value of strcmp(), based - on the comparison of the two FILETIME values. - */ -KHMEXP long KHMAPI -FtCompare(LPFILETIME pft1, LPFILETIME pft2); - -/*! \brief Convert a FILETIME to a 64 bit int -*/ -KHMEXP khm_int64 KHMAPI FtToInt(LPFILETIME pft); - -/*! \brief Convert a 64 bit int to a FILETIME -*/ -KHMEXP FILETIME KHMAPI IntToFt(khm_int64 i); - -/*! \brief Calculate the difference between two FILETIMEs - - Returns the value of ft1 - ft2 - */ -KHMEXP FILETIME KHMAPI FtSub(LPFILETIME ft1, LPFILETIME ft2); - -/*! \brief Calculate the sum of two FILETIMEs - - Return the value of ft1 + ft2 - */ -KHMEXP FILETIME KHMAPI FtAdd(LPFILETIME ft1, LPFILETIME ft2); - -/*! \brief Convert a FILETIME inverval to a string -*/ -KHMEXP khm_int32 KHMAPI -FtIntervalToString(LPFILETIME data, - wchar_t * buffer, - khm_size * cb_buf); - -/*! \brief Parse a string representing an interval into a FILETIME interval - - The string is a localized string which should look like the - following: - - \code - [number unit] [number unit]... - \endcode - - where \a number is an integer while \a unit is a localized - (possibly abbreviated) unit specification. The value of the - described interval is calculated as the sum of each \a number in - \a units. For example : - - \code - 1 hour 36 minutes - \endcode - - would result in an interval specification that's equivalent to 1 - hour and 36 minutes. Of course there is no restriction on the - order in which the \a number \a unit specifications are given and - the same unit may be repeated multiple times. - - \retval KHM_ERROR_INVALID_PARAM The given string was invalid or had - a token that could not be parsed. It can also mean that \a - pft was NULL or \a str was NULL. - - \retval KHM_ERROR_SUCCESS The string was successfully parsed and - the result was placed in \a pft. -*/ -KHMEXP khm_int32 KHMAPI -IntervalStringToFt(FILETIME * pft, wchar_t * str); - -/*! \brief Return number of milliseconds till next representation change - - Returns the number of milliseconds that must elapse away from the - interval specified in pft \a for the representation of pft to change - from whatever it is right now. - - Returns 0 if the representation is not expected to change. -*/ -KHMEXP long KHMAPI -FtIntervalMsToRepChange(LPFILETIME pft); - -/*! \brief Convert a safe ANSI string to a Unicode string - - The resulting string is guaranteed to be NULL terminated and - within the size limit set by \a cbwstr. - - If the whole string cannot be converted, \a wstr is set to an - empty string. - - \return the number of characters converted. This is always either - the length of the string \a astr or 0. -*/ -KHMEXP int KHMAPI -AnsiStrToUnicode( wchar_t * wstr, size_t cbwstr, const char * astr); - -/*! \brief Convert a Unicode string to ANSI - - The resulting string is guaranteed to be NULL terminated and - within the size limit set by \a cbdest. - - \return the number of characters converted. This is always either - the length of the string \a src or 0. -*/ -KHMEXP int KHMAPI -UnicodeStrToAnsi( char * dest, size_t cbdest, const wchar_t * src); -/*@}*/ - -/*! \name Standard type identifiers and names -@{*/ - -/*! Maximum identifier number */ -#define KCDB_TYPE_MAX_ID 255 - -/*! \brief Invalid type - - Used by functions that return a type identifier to indicate that - the returned type identifier is invalid. Also used to indicate - that a type identifier is not available */ -#define KCDB_TYPE_INVALID (-1) - -/*! \brief All types - - Used by filters to indicate that all types are allowed. -*/ -#define KCDB_TYPE_ALL KCDB_TYPE_INVALID - -/*! \brief Void - - No data. This is not an actual data type. - */ -#define KCDB_TYPE_VOID 0 - -/*! \brief String - - NULL terminated Unicode string. The byte count for a string - attribute always includes the terminating NULL. - */ -#define KCDB_TYPE_STRING 1 - -/*! \brief Data - - A date/time represented in FILETIME format. - */ -#define KCDB_TYPE_DATE 2 - -/*! \brief Interval - - An interval of time represented as the difference between two - FILETIME values. - */ -#define KCDB_TYPE_INTERVAL 3 - -/*! \brief 32-bit integer - - A 32-bit signed integer. - */ -#define KCDB_TYPE_INT32 4 - -/*! \brief 64-bit integer - - A 64-bit integer. - */ -#define KCDB_TYPE_INT64 5 - -/*! \brief Raw data - - A raw data buffer. - */ -#define KCDB_TYPE_DATA 6 - -#define KCDB_TYPENAME_VOID L"Void" -#define KCDB_TYPENAME_STRING L"String" -#define KCDB_TYPENAME_DATE L"Date" -#define KCDB_TYPENAME_INTERVAL L"Interval" -#define KCDB_TYPENAME_INT32 L"Int32" -#define KCDB_TYPENAME_INT64 L"Int64" -#define KCDB_TYPENAME_DATA L"Data" -/*@}*/ -/*@}*/ - -/********************************************************************/ - -/*! \defgroup kcdb_credattr Credential attributes */ -/*@{*/ - -/*! \brief Prototype callback function for computed data types. - - If the flags for a particular attribute specifies that the value - is computed, then a callback function should be specified. The - callback function will be called with a handle to a credential - along with the attribute ID for the requested attribute. The - function should place the computed value in \a buffer. The size - of the buffer in bytes is specifed in \a cbsize. However, if \a - buffer is \a NULL, then the required buffer size should be placed - in \a cbsize. - */ -typedef khm_int32 -(KHMAPI *kcdb_attrib_compute_cb)(khm_handle cred, - khm_int32 id, - void * buffer, - khm_size * cbsize); - -/*! \brief Credential attribute descriptor - - \see kcdb_attrib_register() -*/ -typedef struct tag_kcdb_attrib { - wchar_t * name; /*!< Name. (Not localized, - required) */ - khm_int32 id; /*!< Identifier. When registering, - this can be set to - ::KCDB_ATTR_INVALID if a unique - identifier is to be generated. */ - khm_int32 alt_id; /*!< Alternate identifier. If the \a - flags specify - ::KCDB_ATTR_FLAG_ALTVIEW, then this - field should specify the identifier - of the canonical attribute from - which this attribute is derived. */ - khm_int32 flags; /*!< Flags. Combination of \ref - kcdb_credattr_flags "attribute - flags" */ - - khm_int32 type; /*!< Type of the attribute. Must be valid. */ - - wchar_t * short_desc; /*!< Short description. (Localized, - optional) */ - - wchar_t * long_desc; /*!< Long description. (Localized, - optional) */ - - kcdb_attrib_compute_cb compute_cb; - /*!< Callback. Required if \a flags - specify ::KCDB_ATTR_FLAG_COMPUTED. */ - - khm_size compute_min_cbsize; - /*!< Minimum number of bytes required - to store this attribute. Required - if ::KCDB_ATTR_FLAG_COMPUTED is - specified.*/ - khm_size compute_max_cbsize; - /*!< Maximum number of bytes required - to store this attribute. Required - if ::KCDB_ATTR_FLAG_COMPUTED is - specified.*/ -} kcdb_attrib; - -/*! \brief Retrieve the ID of a named attribute */ -KHMEXP khm_int32 KHMAPI -kcdb_attrib_get_id(const wchar_t *name, - khm_int32 * id); - -/*! \brief Register an attribute - - \param[out] new_id Receives the ID of the newly registered - attribute. If the \a id member of the ::kcdb_attrib object is - set to KCDB_ATTR_INVALID, then a unique ID is generated. */ -KHMEXP khm_int32 KHMAPI -kcdb_attrib_register(const kcdb_attrib * attrib, - khm_int32 * new_id); - -/*! \brief Retrieve the attribute descriptor for an attribute - - The descriptor that is returned must be released through a call to - kcdb_attrib_release_info() - - If only the validity of the attribute identifier needs to be - checked, you can pass in NULL for \a attrib. In this case, if the - identifier is valid, then the funciton will return - KHM_ERROR_SUCCESS, otherwise it will return KHM_ERROR_NOT_FOUND. - - \see kcdb_attrib_release_info() - */ -KHMEXP khm_int32 KHMAPI -kcdb_attrib_get_info(khm_int32 id, - kcdb_attrib ** attrib); - -/*! \brief Release an attribute descriptor - - \see kcdb_attrib_get_info() - */ -KHMEXP khm_int32 KHMAPI -kcdb_attrib_release_info(kcdb_attrib * attrib); - -/*! \brief Unregister an attribute - - Once an attribute ID has been unregistered, it may be reclaimed by - a subsequent call to kcdb_attrib_register(). -*/ -KHMEXP khm_int32 KHMAPI -kcdb_attrib_unregister(khm_int32 id); - -/*! \brief Retrieve the description of an attribute - - \param[in] flags Specify \a KCDB_TS_SHORT to retrieve the short description. */ -KHMEXP khm_int32 KHMAPI -kcdb_attrib_describe(khm_int32 id, - wchar_t * buffer, - khm_size * cbsize, - khm_int32 flags); - -/*! \brief Count attributes - - Counts the number of attributes that match the given criteria. - The criteria is specified against the flags of the attribute. An - attribute is a match if its flags satisfy the condition below: - - \code - (attrib.flags & and_flags) == (eq_flags & and_flags) - \endcode - - The number of attributes that match are returned in \a pcount. - */ -KHMEXP khm_int32 KHMAPI -kcdb_attrib_get_count(khm_int32 and_flags, - khm_int32 eq_flags, - khm_size * pcount); - -/*! \brief List attribute identifiers - - Lists the identifiers of the attributes that match the given - criteria. The criteria is specified against the flags of the - attribute. An attribute is a match if the following condition is - satisfied: - - \code - (attrib.flags & and_flags) == (eq_flags & and_flags) - \endcode - - The list of attributes found are copied to the \a khm_int32 array - specified in \a plist. The number of elements available in the - buffer \a plist is specified in \a pcsize. On exit, \a pcsize - will hold the actual number of attribute identifiers copied to the - array. - - \param[in] and_flags See above - \param[in] eq_flags See above - \param[in] plist A khm_int32 array - \param[in,out] pcsize On entry, holds the number of elements - available in the array pointed to by \a plist. On exit, holds - the number of elements copied to the array. - - \retval KHM_ERROR_SUCCESS The list of attribute identifiers have - been copied. - \retval KHM_ERROR_TOO_LONG The list was too long to fit in the - supplied buffer. As many elements as possible have been - copied to the \a plist array and the required number of - elements has been written to \a pcsize. - - \note The \a pcsize parameter specifies the number of khm_int32 - elements in the array and not the number of bytes in the - array. This is different from the usual size parameters used - in the NetIDMgr API. - */ -KHMEXP khm_int32 KHMAPI -kcdb_attrib_get_ids(khm_int32 and_flags, - khm_int32 eq_flags, - khm_int32 * plist, - khm_size * pcsize); - -/*! \defgroup kcdb_credattr_flags Attribute flags */ -/*@{*/ -/*! \brief The attribute is required */ -#define KCDB_ATTR_FLAG_REQUIRED 0x00000008 - -/*! \brief The attribute is computed. - - If this flag is set, the \a compute_cb, \a compute_min_cbsize and - \a compute_max_cbsize members of the ::kcdb_attrib attribute - descriptor must be assigned valid values. -*/ -#define KCDB_ATTR_FLAG_COMPUTED 0x00000010 - -/*! \brief System attribute. - - This cannot be specified for a custom attribute. Implies that the - value of the attribute is given by the credentials database - itself. -*/ -#define KCDB_ATTR_FLAG_SYSTEM 0x00000020 - -/*! \brief Hidden - - The attribute is not meant to be displayed to the user. Setting - this flag prevents this attribute from being listed in the list of - available data fields in the UI. -*/ -#define KCDB_ATTR_FLAG_HIDDEN 0x00000040 - -/*! \brief Property - - The attribute is a property. The main difference between regular - attributes and properties are that properties are not allocated - off the credentials record. Hence, a property can not be used as - a credentials field. Other objects such as identities can hold - property sets. A property set can hold both regular attributes as - well as properties. -*/ -#define KCDB_ATTR_FLAG_PROPERTY 0x00000080 - -/*! \brief Volatile - - A volatile property is one whose value changes often, such as - ::KCDB_ATTR_TIMELEFT. Some controls will make use of additional - logic to deal with such values, or not display them at all. - */ -#define KCDB_ATTR_FLAG_VOLATILE 0x00000100 - -/*! \brief Alternate view - - The attribute is actually an alternate representation of another - attribute. The Canonical attribute name is specified in \a - alt_id. - - Sometimes a certain attribute may need to be represented in - different ways. You can register multiple attributes for each - view. However, you should also provide a canonical attribute for - whenever the canonical set of attributes of the credential is - 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 */ -/*@{*/ - -/*! \name Attribute related constants */ -/*@{*/ -/*! \brief Maximum valid attribute ID */ -#define KCDB_ATTR_MAX_ID 255 - -/*! \brief Minimum valid property ID */ -#define KCDB_ATTR_MIN_PROP_ID 4096 - -/*! \brief Maximum number of properties */ -#define KCDB_ATTR_MAX_PROPS 128 - -/*! \brief Maximum valid property ID */ -#define KCDB_ATTR_MAX_PROP_ID (KCDB_ATTR_MIN_PROP_ID + KCDB_ATTR_MAX_PROPS - 1) - -/*! \brief Invalid ID */ -#define KCDB_ATTR_INVALID (-1) - -/*! \brief First custom attribute ID */ -#define KCDB_ATTRID_USER 20 - -/*@}*/ - -/*!\name Attribute identifiers */ -/*@{*/ -/*! \brief Name of the credential - - - \b Type: STRING - - \b Flags: REQUIRED, COMPUTED, SYSTEM - */ -#define KCDB_ATTR_NAME 0 - -/*! \brief The identity handle for the credential - - - \b Type: INT64 - - \b Flags: REQUIRED, COMPUTED, SYSTEM, HIDDEN - - \note The handle returned in by specifying this attribute to - kcdb_cred_get_attr() or kcdb_cred_get_attrib() is not held. - While the identity is implicitly held for the duration that - the credential is held, it is not recommended to obtain a - handle to the identity using this method. Use - kcdb_cred_get_identity() instead. -*/ -#define KCDB_ATTR_ID 1 - -/*! \brief The name of the identity - - - \b Type: STRING - - \b Flags: REQUIRED, COMPUTED, SYSTEM - */ -#define KCDB_ATTR_ID_NAME 2 - -/*! \brief The type of the credential - - - \b Type: INT32 - - \b Flags: REQUIRED, COMPUTED, SYSTEM, HIDDEN -*/ -#define KCDB_ATTR_TYPE 3 - -/*! \brief Type name for the credential - - - \b Type: STRING - - \b Flags: REQUIRED, COMPUTED, SYSTEM -*/ -#define KCDB_ATTR_TYPE_NAME 4 - -/*! \brief Name of the parent credential - - - \b Type: STRING - - \b Flags: SYSTEM -*/ -#define KCDB_ATTR_PARENT_NAME 5 - -/*! \brief Issed on - - - \b Type: DATE - - \b Flags: SYSTEM -*/ -#define KCDB_ATTR_ISSUE 6 - -/*! \brief Expires on - - - \b Type: DATE - - \b Flags: SYSTEM -*/ -#define KCDB_ATTR_EXPIRE 7 - -/*! \brief Renewable period expires on - - - \b Type: DATE - - \b Flags: SYSTEM -*/ -#define KCDB_ATTR_RENEW_EXPIRE 8 - -/*! \brief Time left till expiration - - - \b Type: INTERVAL - - \b Flags: SYSTEM, COMPUTED, VOLATILE -*/ -#define KCDB_ATTR_TIMELEFT 9 - -#define KCDB_ATTR_RENEW_TIMELEFT 10 - -/*! \brief Location of the credential - - - \b Type: STRING - - \b Flags: SYSTEM -*/ -#define KCDB_ATTR_LOCATION 11 - -/*! \brief Lifetime of the credential - - - \b Type: INTERVAL - - \b Flags: SYSTEM -*/ -#define KCDB_ATTR_LIFETIME 12 - -#define KCDB_ATTR_RENEW_LIFETIME 13 - -/*! \brief Flags for the credential - - - \b Type: INT32 - - \b Flags: REQUIRED, COMPUTED, SYSTEM, HIDDEN - */ -#define KCDB_ATTR_FLAGS 14 - -/*@}*/ - -/*!\name Attribute names */ -/*@{ */ - -#define KCDB_ATTRNAME_NAME L"Name" -#define KCDB_ATTRNAME_ID L"Identity" -#define KCDB_ATTRNAME_ID_NAME L"IdentityName" -#define KCDB_ATTRNAME_TYPE L"TypeId" -#define KCDB_ATTRNAME_TYPE_NAME L"TypeName" -#define KCDB_ATTRNAME_FLAGS L"Flags" - -#define KCDB_ATTRNAME_PARENT_NAME L"Parent" -#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" -#define KCDB_ATTRNAME_RENEW_TIMELEFT L"RenewTimeLeft" -#define KCDB_ATTRNAME_LOCATION L"Location" -#define KCDB_ATTRNAME_LIFETIME L"Lifetime" -#define KCDB_ATTRNAME_RENEW_LIFETIME L"RenewLifetime" - -/*@}*/ - -/*@}*/ - -/*@}*/ - -/*****************************************************************************/ - -/*! \defgroup kcdb_credtype Credential types */ -/*@{*/ - -/*! \brief Credential type descriptor */ -typedef struct tag_kcdb_credtype { - wchar_t * name; /*!< name (less than KCDB_MAXCB_NAME bytes) */ - khm_int32 id; - wchar_t * short_desc; /*!< short localized description (less - than KCDB_MAXCB_SHORT_DESC bytes) */ - wchar_t * long_desc; /*!< long localized descriptionn (less - than KCDB_MAXCB_LONG_DESC bytes) */ - khm_handle sub; /*!< Subscription for credentials type - hander. This should be a valid - subscription constructed through a - call to kmq_create_subscription() - and must handle KMSG_CRED messages - that are marked as being sent to - type specific subscriptions. - - The subscription will be - automatically deleted with a call to - kmq_delete_subscription() when the - credentials type is unregistered.*/ - - kcdb_cred_comp_func is_equal; /*!< Used as an additional clause - when comparing two credentials for - equality. The function this is - actually a comparison function, it - should return zero if the two - credentials are equal and non-zero - if they are not. The addtional \a - rock parameter is always zero. - - It can be assumed that the identity, - name and credentials type have - already been found to be equal among - the credentials and the credential - type is the type that is being - registered.*/ - -#ifdef _WIN32 - HICON icon; -#endif -} kcdb_credtype; - -/*! \brief Maximum value of a credential type identifier - - Credential type identifiers are assigned serially unless the - process registering the credential type sets a specific identity. - The maximum identifier number places a hard limit to the number of - credential types that can be registered at one time, which is - KCDB_CREDTYPE_MAX_ID + 1. - */ -#define KCDB_CREDTYPE_MAX_ID 31 - -/*! \brief Specify all credential types - - This value is used by functions which filter credentials based on - credential types. Specifying this value tells the filter to - accept all credential types. - */ -#define KCDB_CREDTYPE_ALL (-1) - -/*! \brief Automatically determine a credential type identifier - - Used with kcdb_credtype_register() to specify that the credential - type identifier should be automatically determined to avoid - collisions. - */ -#define KCDB_CREDTYPE_AUTO (-2) - -/*! \brief An invalid credential type - - Even though any non positive credential type ID is invalid - anywhere where a specific credential type ID is required, this - value is provided for explicit indication that the credential type - is invalid. Also it makes code more readable to have a constant - that shouts out INVALID. - -*/ -#define KCDB_CREDTYPE_INVALID (-3) - -/*! \brief Macro predicate for testing whether a credtype is valid - - Returns TRUE if the given credtype is valid. This is a safe - macro. -*/ -#define KCDB_CREDTYPE_IS_VALID(t) ((t) >= 0) - -/*! \brief Register a credentials type. - - The information given in the \a type parameter is used to register - a new credential type. Note that the \a name member of the \a - type should be unique among all credential types. - - You can specify ::KCDB_CREDTYPE_AUTO as the \a id member of \a - type to let kcdb_credtype_register() determine a suitable - credential type identifier. You can subsequently call - kcdb_credtype_get_id() to retrieve the generated id or pass a - valid pointer to a khm_int32 type variable as \a new_id. - - \param[in] type Credential type descriptor - - \param[out] new_id The credential type identifier that this type - was registered as. - - \retval KHM_ERROR_SUCCESS The credential type was successfully registered. - - \retval KHM_ERROR_INVALID_PARAM One or more of the parameters were invalid - - \retval KHM_ERROR_TOO_LONG One or more of the string fields in \a - type exceeded the character limit for that field. - - \retval KHM_ERROR_NO_RESOURCES When autogenerating credential type - identifiers, this value indicates that the maximum number of - credential types have been registered. No more registrations - can be accepted unless some credentials type is unregisred. - - \retval KHM_ERROR_DUPLICATE The \a name or \a id that was - specified is already in use. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_credtype_register(const kcdb_credtype * type, - khm_int32 * new_id); - -/*! \brief Return a held reference to a \a kcdb_credtype object describing the credential type. - - The reference points to a static internal object of type \a - kcdb_credtype. Use the kcdb_credtype_release_info() function to - release the reference. - - Also, the structure passed in as the \a type argument to - kcdb_credtype_register() is not valid as a credential type - descriptor. Use kcdb_credtype_get_info() to obtain the actual - credential type descriptor. - - \param[in] id Credentials type identifier. - - \param[out] type Receives the credentials descriptor handle. If - \a type is NULL, then no handle is returned. However, the - function will still return \a KHM_ERROR_SUCCESS if the \a id - parameter passed in is a valid credentials type identifier. - - \see kcdb_credtype_release_info() - \see kcdb_credtype_register() -*/ -KHMEXP khm_int32 KHMAPI -kcdb_credtype_get_info(khm_int32 id, - kcdb_credtype ** type); - -/*! \brief Release a reference to a \a kcdb_credtype object - - Undoes the hold obtained on a \a kcdb_credtype object from a - previous call to kcdb_credtype_get_info(). - - \see kcdb_credtype_get_info() - */ -KHMEXP khm_int32 KHMAPI -kcdb_credtype_release_info(kcdb_credtype * type); - -/*! \brief Unregister a credentials type - - Undoes the registration performed by kcdb_credtype_register(). - - This should only be done when the credentials provider is being - unloaded. - */ -KHMEXP khm_int32 KHMAPI -kcdb_credtype_unregister(khm_int32 id); - -/*! \brief Retrieve the name of a credentials type - - Given a credentials type identifier, retrieves the name. The name - is not localized and serves as a persistent identifier of the - credentials type. - - \param[out] buf The buffer to receive the name. Could be \a NULL - if only the length of the buffer is required. - - \param[in,out] cbbuf On entry, specifies the size of the buffer - pointed to by \a buf if \a buf is not NULL. On exit, contains - the number of bytes copied to \a buf or the required size of - the buffer. - - \retval KHM_ERROR_SUCCESS The call succeeded. - - \retval KHM_ERROR_TOO_LONG Either \a buf was NULL or the supplied - buffer was not large enough. The required size is in \a cbbuf. - - \retval KHM_ERROR_INVALID_PARAM Invalid parameter. - */ -KHMEXP khm_int32 KHMAPI -kcdb_credtype_get_name(khm_int32 id, - wchar_t * buf, - khm_size * cbbuf); - -/*! \brief Retrieve the type specific subscription for a type - - Given a credentials type, this function returns the credentials - type specific subcription. It may return NULL if the subscription - is not available. - */ -KHMEXP khm_handle KHMAPI -kcdb_credtype_get_sub(khm_int32 id); - -/*! \brief Get the description of a credentials type - - Unlike the name of a credential type, the description is localized. - - \param[in] id Credentials type identifier - - \param[out] buf Receives the description. Can bet set to NULL if - only the size of the buffer is required. - - \param[in,out] cbbuf On entry, specifies the size of the buffer - pointed to by \a buf. On exit, specifies the required size of - the buffer or the number of bytes copied, depending on whether - the call succeeded or not. - - \param[in] flags Specify ::KCDB_TS_SHORT if the short version of - the description is desired if there is more than one. - - \retval KHM_ERROR_SUCCESS The call succeeded - \retval KHM_ERROR_TOO_LONG Either \a buf was NULL or the supplied buffer was insufficient. The required size is specified in \a cbbuf. - \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid. - */ -KHMEXP khm_int32 KHMAPI -kcdb_credtype_describe(khm_int32 id, - wchar_t * buf, - khm_size * cbbuf, - khm_int32 flags); - -/*! \brief Look up the identifier of a credentials type by name - - Given a name, looks up the identifier. - - \param[in] name Name of the credentials type - \param[out] id Receives the identifier if the call succeeds - - */ -KHMEXP khm_int32 KHMAPI -kcdb_credtype_get_id(const wchar_t * name, - khm_int32 * id); - -/*@}*/ - -/*********************************************************************/ - -/*! \defgroup kcdb_buf Generic access to buffer - - Currently, credentials and identities both hold record data types. - This set of API's allow an application to access fields in the - records using a single interface. Note that credentials only - accept regular attributes while identities can hold both - attributes and properties. - - Handles to credentials and identities are implicitly also handles - to records. Thus they can be directly used as such. -*/ -/*@{*/ - -/*! \brief Get an attribute from a record by attribute id. - - \param[in] buffer The buffer that is to receive the attribute - value. Set this to NULL if only the required buffer size is - to be returned. - - \param[in,out] cbbuf The number of bytes available in \a buffer. - If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and - sets this to the required buffer size. - - \param[out] attr_type Receives the data type of the attribute. - Set this to NULL if the type is not required. - - \note Set both \a buffer and \a cbbuf to NULL if only the - existence of the attribute is to be checked. If the attribute - exists in this record then the function will return - KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_buf_get_attr(khm_handle record, - khm_int32 attr_id, - khm_int32 * attr_type, - void * buffer, - khm_size * pcb_buf); - -/*! \brief Get an attribute from a record by name. - - \param[in] buffer The buffer that is to receive the attribute - value. Set this to NULL if only the required buffer size is - to be returned. - - \param[in,out] cbbuf The number of bytes available in \a buffer. - If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and - sets this to the required buffer size. - - \note Set both \a buffer and \a cbbuf to NULL if only the - existence of the attribute is to be checked. If the attribute - exists in this record then the function will return - KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_buf_get_attrib(khm_handle record, - const wchar_t * attr_name, - khm_int32 * attr_type, - void * buffer, - khm_size * pcb_buf); - -/*! \brief Get the string representation of a record attribute. - - A shortcut function which generates the string representation of a - record attribute directly. - - \param[in] record A handle to a record - - \param[in] attr_id The attribute to retrieve - - \param[out] buffer A pointer to a string buffer which receives the - string form of the attribute. Set this to NULL if you only - want to determine the size of the required buffer. - - \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, - holds the size of the buffer pointed to by \a buffer, and on - exit, receives the actual number of bytes that were copied. - - \param[in] flags Flags for the string conversion. Can be set to - one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is - KCDB_TS_LONG. - - \retval KHM_ERROR_SUCCESS Success - \retval KHM_ERROR_NOT_FOUND The given attribute was either invalid - or was not defined for this record - \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid - \retval KHM_ERROR_TOO_LONG Either \a buffer was NULL or the - supplied buffer was insufficient -*/ -KHMEXP khm_int32 KHMAPI -kcdb_buf_get_attr_string(khm_handle record, - khm_int32 attr_id, - wchar_t * buffer, - khm_size * pcbbuf, - khm_int32 flags); - -/*! \brief Get the string representation of a record attribute by name. - - A shortcut function which generates the string representation of a - record attribute directly. - - \param[in] record A handle to a record - - \param[in] attrib The name of the attribute to retrieve - - \param[out] buffer A pointer to a string buffer which receives the - string form of the attribute. Set this to NULL if you only - want to determine the size of the required buffer. - - \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, - holds the size of the buffer pointed to by \a buffer, and on - exit, receives the actual number of bytes that were copied. - - \param[in] flags Flags for the string conversion. Can be set to - one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is - KCDB_TS_LONG. - - \see kcdb_cred_get_attr_string() -*/ -KHMEXP khm_int32 KHMAPI -kcdb_buf_get_attrib_string(khm_handle record, - const wchar_t * attr_name, - wchar_t * buffer, - khm_size * pcbbuf, - khm_int32 flags); - -/*! \brief Set an attribute in a record by attribute id - - \param[in] cbbuf Number of bytes of data in \a buffer. The - individual data type handlers may copy in less than this many - bytes in to the record. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_buf_set_attr(khm_handle record, - khm_int32 attr_id, - void * buffer, - khm_size cbbuf); - -/*! \brief Set an attribute in a record by name - - \param[in] cbbuf Number of bytes of data in \a buffer. The - individual data type handlers may copy in less than this many - bytes in to the record. -*/ -KHMEXP khm_int32 KHMAPI -kcdb_buf_set_attrib(khm_handle record, - const wchar_t * attr_name, - void * buffer, - khm_size cbbuf); - -KHMEXP khm_int32 KHMAPI -kcdb_buf_hold(khm_handle record); - -KHMEXP khm_int32 KHMAPI -kcdb_buf_release(khm_handle record); - -/*@}*/ - -/********************************************************************/ - -/* Notification operation constants */ - -#define KCDB_OP_INSERT 1 -#define KCDB_OP_DELETE 2 -#define KCDB_OP_MODIFY 3 -#define KCDB_OP_ACTIVATE 4 -#define KCDB_OP_DEACTIVATE 5 -#define KCDB_OP_HIDE 6 -#define KCDB_OP_UNHIDE 7 -#define KCDB_OP_SETSEARCH 8 -#define KCDB_OP_UNSETSEARCH 9 -#define KCDB_OP_NEW_DEFAULT 10 -#define KCDB_OP_DELCONFIG 11 - -/*@}*/ - -#endif +/* + * 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_KCREDDB_H__ +#define __KHIMAIRA_KCREDDB_H__ + +#include +#include + + +/*! \defgroup kcdb NetIDMgr Credentials Database */ +/*@{*/ + +/*! \brief Maximum length in characters of short description + + The length includes the terminating \a NULL character. + */ +#define KCDB_MAXCCH_SHORT_DESC 256 + +/*! \brief Maximum length in bytes of short description + + The length includes the terminating \a NULL character. + */ +#define KCDB_MAXCB_SHORT_DESC (sizeof(wchar_t) * KCDB_MAXCCH_SHORT_DESC) + +/*! \brief Maximum length in characters of long description + + The length includes the terminating \a NULL character. + */ +#define KCDB_MAXCCH_LONG_DESC 8192 + +/*! \brief Maximum length in characters of long description + + The length includes the terminating \a NULL character. + */ +#define KCDB_MAXCB_LONG_DESC (sizeof(wchar_t) * KCDB_MAXCCH_LONG_DESC) + +/*! \brief Maximum length in characters of name + + The length includes the terminating \a NULL character. + */ +#define KCDB_MAXCCH_NAME 256 + +/*! \brief Maximum length in bytes of short description + + The length includes the terminating \a NULL character. + */ +#define KCDB_MAXCB_NAME (sizeof(wchar_t) * KCDB_MAXCCH_NAME) + +/*! \brief Automatically determine the number of bytes required + + Can be used in most places where a count of bytes is required. + For many objects, the number of bytes that are required can be + determined through context and may be ommited. In such cases you + can use the \a KCDB_CBSIZE_AUTO value to specify that the function + is to determine the size automatically. + + \note Not all functions that take a count of bytes support the \a + KCDB_CBSIZE_AUTO value. +*/ +#define KCDB_CBSIZE_AUTO (-1) + +/*! +\defgroup kcdb_ident Identities + +Functions, macros etc. for manipulating identities. +*/ + +/*@{*/ + +/*! \brief The maximum number of characters (including terminator) that can + be specified as an identity name */ +#define KCDB_IDENT_MAXCCH_NAME 256 + +/*! \brief The maximum number of bytes that can be specified as an identity + 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 */ +/*@{*/ + +/*! \brief Create the identity if it doesn't already exist. + \note Only to be used with kcdb_identity_create() */ +#define KCDB_IDENT_FLAG_CREATE 0x10000000L + +/*! \brief Has configuration information + + Indicates that the identity has persistent configuration + information associated with it. + */ +#define KCDB_IDENT_FLAG_CONFIG 0x00800000L + +/*! \brief Marks the identity as active. + + An active identity is one that is in active use within NetIDMgr. + + \note This flag is readonly and cannot be specified when creating + or modifying an identity. Once an identity is deleted, it will + no longer have this flag. */ +#define KCDB_IDENT_FLAG_ACTIVE 0x02000000L + + +/*! \brief The identity has custom attributes assigned + */ +#define KCDB_IDENT_FLAG_ATTRIBS 0x08000000L + +/*! \brief This is the default identity. + + At most one identity will have this flag set at any given time. + To set or reset the flag, use kcdb_identity_set_default() */ +#define KCDB_IDENT_FLAG_DEFAULT 0x00000001L + +/*! \brief This identity can be searched. + + The meaning of this flag is left to be interpreted by individual + plugins. */ +#define KCDB_IDENT_FLAG_SEARCHABLE 0x00000002L + +/*! \brief Hidden identity. + + The identity will not show up in the identity list window. Once + the hidden is switched off, the identity (and all associated + credentials) will re-appear in the window */ +#define KCDB_IDENT_FLAG_HIDDEN 0x00000004L + +/*! \brief Invalid identity + + For one reason or another, this identity is invalid. This flag + can be set by an identity provider to indicate that this identity + does not correspond to an actual identity because an external + entity (such as a KDC) has denied it's existence. + + The absence of this flag does not imply that the identity is + valid. The ::KCDB_IDENT_FLAG_VALID bit must be set for that to be + the case. If neither flag is set, then the status of the identity + is not known. +*/ +#define KCDB_IDENT_FLAG_INVALID 0x00000008L + +/*! \brief Valid identity + + The identity has been validated through an external entity, or + it's validity implied through the existence of credentials for the + identity. + + The absence of this flag does not imply that the identity is + invalid. The ::KCDB_IDENT_FLAG_INVALID bit must be set for that + to be the case. If neither flag is set, then the status of the + identity is not known. + */ +#define KCDB_IDENT_FLAG_VALID 0x00000010L + +/*! \brief Expired identity + + This identity has expired and can not be actively used to obtain + credentials. This determination is made based on the input of + some external entity. This flag may only be set by an identity + provider. +*/ +#define KCDB_IDENT_FLAG_EXPIRED 0x00000020L + +/*! \brief Empty identity + + The identity does not have actual credentials associated with it. + */ +#define KCDB_IDENT_FLAG_EMPTY 0x00000040L + +/*! \brief Renewable identity + + The initial credentials associated with this identity are + renewable. Thus making the whole identity renewable. + */ +#define KCDB_IDENT_FLAG_RENEWABLE 0x00000080L + +/*! \brief Required user interaction + + The identity is in a state which requires user interaction to + activate. Currently, the identity may not be in a state where it + can be used to obtain credentials. + + A typical example of this is when the primary password for an + identity has expired. + */ +#define KCDB_IDENT_FLAG_INTERACT 0x00000100L + +/*! \brief Has expired credentials + + The identity has expired credentials associated with it. + */ +#define KCDB_IDENT_FLAG_CRED_EXP 0x00000200L + +/*! \brief Has renewable credentials + + The identity has renewable credentials associated with it. If the + initial credentials of the identity are renewable, then identity + is renewable. Hence the ::KCDB_IDENT_FLAG_RENEWABLE should also + be set. + */ +#define KCDB_IDENT_FLAG_CRED_RENEW 0x00000400L + +/*! \brief Sticky identity + + Sticky identities are identities that are always visible in the + credentials display even if no credentials are associated with it. + */ +#define KCDB_IDENT_FLAG_STICKY 0x00000800L + +/*! \brief Unknown state + + The validity of the identity cannot be determined. This usually + means that an authority could not be contacted. This flag is to + be treated as transient. If ::KCDB_IDENT_FLAG_INVALID or + ::KCDB_IDENT_FLAG_VALID is set for the identity, this flag is to + be ignored. + */ +#define KCDB_IDENT_FLAG_UNKNOWN 0x00001000L + +/*! \brief Read/write flags mask. + + A bitmask that correspond to all the read/write flags in the mask. +*/ +#define KCDB_IDENT_FLAGMASK_RDWR 0x00001fffL + +/*@}*/ + +/*! \name Identity Provider Data Structures +@{*/ + +/*! \brief Name transfer structure + + Used when the KCDB is communicating with the identity provider to + exchange string names of identities. See individual ::KMSG_IDENT + message subtypes for the usage of this structure. + */ +typedef struct tag_kcdb_ident_name_xfer { + const wchar_t * name_src; /*!< An identity name. Does not + exceed KCDB_IDENT_MAXCCH_NAME + characters including terminating + NULL. */ + const wchar_t * name_alt; /*!< An identity name. Does not + exceed KCDB_IDENT_MAXCCH_NAME + characters including terminating + NULL. */ + wchar_t * name_dest; /*!< Pointer to a buffer that is to + receive a response string. The + size of the buffer in bytes is + specified in \a cb_name_dest. */ + khm_size cb_name_dest; /*!< Size of buffer pointed to by \a + name_dest in bytes. */ + khm_int32 result; /*!< Receives a result value, which is + usually an error code defined in + kherror.h, though it is not + always. */ +} kcdb_ident_name_xfer; + +typedef struct tag_kcdb_ident_info { + khm_handle identity; + khm_int32 fields; + + FILETIME expiration; +} kcdb_ident_info; + +/*@}*/ + +/*! \name Identity provider interface functions + + These functions encapsulate safe calls to the current identity + provider. While these functions are exported, applications should + not call these functions directly. They are provided for use by + the NetIDMgr core application. +@{*/ + +/*! \brief Validate an identity name + + The name that is provided will be passed through sets of + validations. One set, which doesn't depend on the identity + provider checks whether the length of the identity name and + whether there are any invalid characters in the identity name. If + the name passes those tests, then the name is passed down to the + identity provider's name validation handler. + + \retval KHM_ERROR_SUCCESS The name is valid + \retval KHM_ERROR_TOO_LONG Too many characters in name + \retval KHM_ERROR_INVALID_NAME There were invalid characters in the name. + \retval KHM_ERROR_NO_PROVIDER There is no identity provider; + however the name passed the length and character tests. + \retval KHM_ERROR_NOT_IMPLEMENTED The identity provider doesn't + implement a name validation handler; however the name passed + the length and character tests. + + \see ::KMSG_IDENT_VALIDATE_NAME + */ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_validate_name(const wchar_t * name); + +/*! \brief Validate an identity + + The identity itself needs to be validated. This may involve + communicating with an external entity. + + \see ::KMSG_IDENT_VALIDATE_IDENTITY + */ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_validate_identity(khm_handle identity); + +/*! \brief Canonicalize the name + + + \see ::KMSG_IDENT_CANON_NAME +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_canon_name(const wchar_t * name_in, + wchar_t * name_out, + khm_size * cb_name_out); + +/*! \brief Compare two identity names + + \see ::KMSG_IDENT_COMPARE_NAME +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_compare_name(const wchar_t * name1, + const wchar_t * name2); + +/*! \brief Set the specified identity as the default + + \see ::KMSG_IDENT_SET_DEFAULT +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_set_default(khm_handle identity); + +/*! \brief Set the specified identity as searchable + + \see ::KMSG_IDENT_SET_SEARCHABLE +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_set_searchable(khm_handle identity, + khm_boolean searchable); + +/*! \brief Update the specified identity + + \see ::KMSG_IDENT_UPDATE +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_update(khm_handle identity); + +/*! \brief Obtain the UI callback + + \a rock is actually a pointer to a ::khui_ident_new_creds_cb which + is to receive the callback. + + \see ::KMSG_IDENT_GET_UI_CALLBACK + */ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_get_ui_cb(void * rock); + +/*! \brief Notify an identity provider of the creation of a new identity + + \see ::KMSG_IDENT_NOTIFY_CREATE +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_notify_create(khm_handle identity); + +/*@}*/ + +/*! \brief Check if the given name is a valid identity name + + \return TRUE or FALSE to the question, is this valid? +*/ +KHMEXP khm_boolean KHMAPI +kcdb_identity_is_valid_name(const wchar_t * name); + +/*! \brief Create or open an identity. + + If the KCDB_IDENT_FLAG_CREATE flag is specified in the flags + parameter a new identity will be created if one does not already + exist with the given name. If an identity by that name already + exists, then the existing identity will be opened. The result + parameter will receive a held reference to the opened identity. + Use kcdb_identity_release() to release the handle. + + \param[in] name Name of identity to create + \param[in] flags If KCDB_IDENT_FLAG_CREATE is specified, then the + identity will be created if it doesn't already exist. + Additional flags can be set here which will be assigned to the + identity if it is created. Additional flags have no effect if + an existing identity is opened. + \param[out] result If the call is successful, this receives a held + reference to the identity. The caller should call + kcdb_identity_release() to release the identity once it is no + longer needed. + */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_create(const wchar_t *name, + khm_int32 flags, + khm_handle * result); + +/*! \brief Mark an identity for deletion. + + The identity will be marked for deletion. The + KCDB_IDENT_FLAG_ACTIVE will no longer be present for this + identity. Once all references to the identity are released, it + will be removed from memory. All associated credentials will also + be removed. */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_delete(khm_handle id); + +/*! \brief Set or unset the specified flags in the specified identity. + + Only flags that are in KCDB_IDENT_FLAGMASK_RDWR can be specifed in + the \a flags parameter or the \a mask parameter. The flags set in + the \a mask parameter of the identity will be set to the + corresponding values in the \a flags parameter. + + If ::KCDB_IDENT_FLAG_INVALID is set using this function, then the + ::KCDB_IDENT_FLAG_VALID will be automatically reset, and vice + versa. Resetting either bit does not undo this change, and will + leave the identity's validity unspecified. Setting either of + ::KCDB_IDENT_FLAG_INVALID or ::KCDB_IDENT_FLAG_VALID will + automatically reset ::KCDB_IDENT_FLAG_UNKNOWN. + + Note that setting or resetting certain flags have other semantic + side-effects: + + - ::KCDB_IDENT_FLAG_DEFAULT : Setting this is equivalent to + calling kcdb_identity_set_default() with \a id. Resetting this + is equivalent to calling kcdb_identity_set_default() with NULL. + + - ::KCDB_IDENT_FLAG_SEARCHABLE : Setting this will result in the + identity provider getting notified of the change. If the + identity provider indicates that searchable flag should not be + set or reset on the identity, then kcdb_identity_set_flags() + will return an error. + + \note kcdb_identity_set_flags() is not atomic. Even if the + function returns a failure code, some flags in the identity may + have been set. When calling kcdb_identity_set_flags() always + check the flags in the identity using kcdb_identity_get_flags() to + check which flags have been set and which have failed. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_flags(khm_handle id, + khm_int32 flags, + khm_int32 mask); + +/*! \brief Return all the flags for the identity + + The returned flags may include internal flags. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_flags(khm_handle id, + khm_int32 * flags); + +/*! \brief Return the name of the identity + + \param[out] buffer Buffer to copy the identity name into. The + maximum size of an identity name is \a KCDB_IDENT_MAXCB_NAME. + If \a buffer is \a NULL, then the required size of the buffer + is returned in \a pcbsize. + + \param[in,out] pcbsize Size of buffer in bytes. */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_name(khm_handle id, + wchar_t * buffer, + khm_size * pcbsize); + +/*! \brief Set the specified identity as the default. + + Specifying NULL effectively makes none of the identities the + default. + + \see kcdb_identity_set_flags() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_default(khm_handle id); + +/*! \brief Mark the specified identity as the default. + + This API is reserved for use by identity providers as a means of + specifying which identity is default. The difference between + kcdb_identity_set_default() and kcdb_identity_set_default_int() is + in semantics. + + - kcdb_identity_set_default() is used to request the KCDB to + designate the specified identity as the default. When + processing the request, the KCDB invokes the identity provider + to do the necessary work to make the identity the default. + + - kcdb_identity_set_default_int() is used by the identity provider + to notify the KCDB that the specified identity is the default. + This does not result in the invocation of any other semantics to + make the identity the default other than releasing the previous + defualt identity and making the specified one the default. + */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_default_int(khm_handle id); + +/*! \brief Get the default identity + + Obtain a held handle to the default identity if there is one. The + handle must be freed using kcdb_identity_release(). + + If there is no default identity, then the handle pointed to by \a + pvid is set to \a NULL and the function returns + KHM_ERROR_NOT_FOUND. */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_default(khm_handle * pvid); + +/*! \brief Get the configuration space for the identity. + + If the configuration space for the identity does not exist and the + flags parameter does not specify ::KHM_FLAG_CREATE, then the + function will return a failure code as specified in + ::khc_open_space(). Depending on whether or not a configuration + space was found, the ::KCDB_IDENT_FLAG_CONFIG flag will be set or + reset for the identity. + + \param[in] id Identity for which the configuraiton space is requested + + \param[in] flags Flags used when calling khc_open_space(). If \a + flags specifies KHM_FLAG_CREATE, then the configuration space + is created. + + \param[out] result The resulting handle. If the call is + successful, this receives a handle to the configuration space. + Use khc_close_space() to close the handle. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_config(khm_handle id, + khm_int32 flags, + khm_handle * result); + +/*! \brief Hold a reference to an identity. + + A reference to an identity (a handle) is only valid while it is + held. \note Once the handle is released, it can not be + revalidated by calling kcdb_identity_hold(). Doing so would lead + to unpredictable consequences. */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_hold(khm_handle id); + +/*! \brief Release a reference to an identity. + \see kcdb_identity_hold() */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_release(khm_handle id); + +/*! \brief Set the identity provider subscription + + If there was a previous subscription, that subscription will be + automatically deleted. + + \param[in] sub New identity provider subscription +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_provider(khm_handle sub); + +/*! \brief Set the primary credentials type + + The primary credentials type is designated by the identity + provider. As such, this function should only be called by an + identity provider. + */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_type(khm_int32 cred_type); + +/*! \brief Retrieve the identity provider subscription + + \param[out] sub Receives the current identity provider + subscription. Set to NULL if only the existence of an + identity provider needs to be checked. + + \retval KHM_ERROR_SUCCESS An identity provider exists. If \a sub + was not NULL, the subscription has been copied there. + + \retval KHM_ERROR_NOT_FOUND There is currently no registered + identity provider. If \a sub was not NULL, the handle it + points to has been set to NULL. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_provider(khm_handle * sub); + +/*! \brief Retrieve the identity provider credentials type + + This is the credentials type that the identity provider has + designated as the primary credentials type. + */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_type(khm_int32 * ptype); + +/*! \brief Returns TRUE if the two identities are equal + + Also returns TRUE if both identities are NULL. + */ +KHMEXP khm_boolean KHMAPI +kcdb_identity_is_equal(khm_handle identity1, + khm_handle identity2); + +/*! \brief Set an attribute in an identity by attribute id + + \param[in] buffer A pointer to a buffer containing the data to + assign to the attribute. Setting \a buffer to NULL has the + effect of removing any data that is already assigned to the + attribute. If \a buffer is non-NULL, then \a cbbuf should + specify the number of bytes in \a buffer. + + \param[in] cbbuf Number of bytes of data in \a buffer. The + individual data type handlers may copy in less than this many + bytes in to the credential. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_attr(khm_handle identity, + khm_int32 attr_id, + void * buffer, + khm_size cbbuf); + +/*! \brief Set an attribute in an identity by name + + The attribute name has to be a KCDB registered attribute or + property. + + \param[in] cbbuf Number of bytes of data in \a buffer. The + individual data type handlers may copy in less than this many + bytes in to the credential. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_attrib(khm_handle identity, + const wchar_t * attr_name, + void * buffer, + khm_size cbbuf); + +/*! \brief Get an attribute from an identity by attribute id. + + \param[in] buffer The buffer that is to receive the attribute + value. Set this to NULL if only the required buffer size is + to be returned. + + \param[in,out] cbbuf The number of bytes available in \a buffer. + If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and + sets this to the required buffer size. + + \param[out] attr_type Receives the data type of the attribute. + Set this to NULL if the type is not required. + + \note Set both \a buffer and \a cbbuf to NULL if only the + existence of the attribute is to be checked. If the attribute + exists in this identity then the function will return + KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_attr(khm_handle identity, + khm_int32 attr_id, + khm_int32 * attr_type, + void * buffer, + khm_size * pcbbuf); + +/*! \brief Get an attribute from an identity by name. + + \param[in] buffer The buffer that is to receive the attribute + value. Set this to NULL if only the required buffer size is + to be returned. + + \param[in,out] cbbuf The number of bytes available in \a buffer. + If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and + sets this to the required buffer size. + + \note Set both \a buffer and \a cbbuf to NULL if only the + existence of the attribute is to be checked. If the attribute + exists in this identity then the function will return + KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_attrib(khm_handle identity, + const wchar_t * attr_name, + khm_int32 * attr_type, + void * buffer, + khm_size * pcbbuf); + +/*! \brief Get the string representation of an identity attribute. + + A shortcut function which generates the string representation of + an identity attribute directly. + + \param[in] identity A handle to an identity + + \param[in] attr_id The attribute to retrieve + + \param[out] buffer A pointer to a string buffer which receives the + string form of the attribute. Set this to NULL if you only + want to determine the size of the required buffer. + + \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, + holds the size of the buffer pointed to by \a buffer, and on + exit, receives the actual number of bytes that were copied. + + \param[in] flags Flags for the string conversion. Can be set to + one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is + KCDB_TS_LONG. + + \retval KHM_ERROR_SUCCESS Success + \retval KHM_ERROR_NOT_FOUND The given attribute was either invalid + or was not defined for this identity + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + \retval KHM_ERROR_TOO_LONG Either \a buffer was NULL or the + supplied buffer was insufficient +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_attr_string(khm_handle identity, + khm_int32 attr_id, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags); + +/*! \brief Get the string representation of an identity attribute by name. + + A shortcut function which generates the string representation of + an identity attribute directly. + + \param[in] identity A handle to an identity + + \param[in] attrib The name of the attribute to retrieve + + \param[out] buffer A pointer to a string buffer which receives the + string form of the attribute. Set this to NULL if you only + want to determine the size of the required buffer. + + \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, + holds the size of the buffer pointed to by \a buffer, and on + exit, receives the actual number of bytes that were copied. + + \param[in] flags Flags for the string conversion. Can be set to + one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is + KCDB_TS_LONG. + + \see kcdb_identity_get_attr_string() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_attrib_string(khm_handle identity, + const wchar_t * attr_name, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags); + +/*! \brief Enumerate identities + + Enumerates all the active identities that match the criteria + specified using \a and_flags and \a eq_flags. The condition is + applied to all active identities as follows: + + \code + (identity->flags & and_flags) == (eq_flags & and_flags) + \endcode + + Essentially, if a flag is set in \a and_flags, then that flag in + the identity should equal the setting in \a eq_flags. + + \param[in] and_flags See above + + \param[in] eq_flags See above + + \param[out] name_buf Buffer to receive the list of identity names. + Can be NULL if only the required size of the buffer or the + number of matching identities is required. The list is + returned as a multi string. + + \param[in,out] pcb_buf Number of bytes in buffer pointed to by \a + name_buf on entry. On exit, will receive the number of bytes + copied. Can be NULL only if \a name_buf is also NULL. If \a + name_buf is NULL or if \a pcb_buf indicates that the buffer is + insufficient, this will receive the number of bytes required + and the return value of the function will be + KHM_ERROR_TOO_LONG + + \param[out] pn_idents Receives the number of identities that match + the given criteria. + + \retval KHM_ERROR_SUCCESS If \a name_buf was valid, the buffer now + contains a multi string of identities that matched. If \a + pn_idents was valid, it contains the number of identities + matched. + + \retval KHM_ERROR_TOO_LONG No buffer was supplied or the supplied + buffer was insufficient. If \a pn_idents was valid, it + contains the number of identities. + + \retval KHM_ERROR_INVALID_PARAM None of the parameters \a name_buf, + \a pcb_buf and \a pn_idents were supplied, or \a pcb_buf was + NULL when \a name_buf was not. + + \note Calling this function to obtain the required size of the + buffer and then calling it with a that sized buffer is not + guaranteed to work since the list of identities may change + between the two calls. + */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_enum(khm_int32 and_flags, + khm_int32 eq_flags, + wchar_t * name_buf, + khm_size * pcb_buf, + khm_size * pn_idents); + +/*! \brief Refresh identity attributes based on root credential set + + Several flags in an identity are dependent on the credentials that + are associated with it in the root credential set. In addition, + other flags in an identity depend on external factors that need to + be verfied once in a while. This API goes through the root + credential set as well as consulting the identity provider to + update an identity. + + \see kcdb_identity_refresh() + */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_refresh(khm_handle vid); + +/*! \brief Refresh all identities + + Equivalent to calling kcdb_identity_refresh() for all active + identities. + + \see kcdb_identityt_refresh() + */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_refresh_all(void); + +/* KSMG_KCDB_IDENT notifications are structured as follows: + type=KMSG_KCDB + subtype=KMSG_KCDB_IDENT + uparam=one of KCDB_OP_* + blob=handle to identity in question */ + +/*@}*/ + + +/*********************************************************************/ + + +/*! +\defgroup kcdb_creds Credential sets and individual credentials + +@{ +*/ + + +/*! \brief Credentials process function + + This function is called for each credential in a credential set + when supplied to kcdb_credset_apply(). It should return + KHM_ERROR_SUCCESS to continue the operation, or any other value to + terminate the processing. + + \see kcdb_credset_apply() +*/ +typedef khm_int32 +(KHMAPI *kcdb_cred_apply_func)(khm_handle cred, + void * rock); + +/*! \brief Credentials filter function. + + Should return non-zero if the credential passed as \a cred is to + be "accepted". The precise consequence of a non-zero return value + is determined by the individual function that this call back is + passed into. + + This function should not call any other function which may modify + \a cred. + + \see kcdb_credset_collect_filtered() + \see kcdb_credset_extract_filtered() +*/ +typedef khm_int32 +(KHMAPI *kcdb_cred_filter_func)(khm_handle cred, + khm_int32 flags, + void * rock); + +/*! \brief Credentials compare function. + + Asserts a weak ordering on the credentials that are passed in as + \a cred1 and \a cred2. It should return: + + - a negative value if \a cred1 < \a cred2 + - zero if \a cred1 == \a cred2 + - a postive value if \a cred1 > \a cred2 + \see kcdb_credset_sort() + \see ::kcdb_credtype +*/ +typedef khm_int32 +(KHMAPI *kcdb_cred_comp_func)(khm_handle cred1, + khm_handle cred2, + void * rock); + +/*! \defgroup kcdb_credset Credential sets */ +/*@{*/ + +/*! \brief Create a credential set. + + Credential sets are temporary containers for credentials. These + can be used by plug-ins to store credentials while they are being + enumerated from an external source. Once all the credentials have + been collected into the credential set, the plug-in may call + kcdb_credset_collect() to collect the credentials into the root + credential store. + + The user interface will only display credentials that are in the + root credential store. No notifications are generated for changes + to a non-root credential set. + + Use kcdb_credset_delete() to delete the credential set once it is + created. + + \see kcdb_credset_delete() + \see kcdb_credset_collect() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_create(khm_handle * result); + +/** \brief Delete a credential set + + \see kcdb_credset_create() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_delete(khm_handle credset); + +/** \brief Collect credentials from a credential set to another credential set. + + Collecting a subset of credentials from credential set \a cs_src + into credential set \a cs_dest involves the following steps: + + - Select all credentials from \a cs_src that matches the \a + identity and \a type specified in the function call and add them + to the \a cs_dest credential set if they are not there already. + Note that if neither credential set is not the root credential + store, then the credentials will be added by reference, while if + it is the root credential store, the credentials will be + duplicated, and the copies will be added to \a cs_dest. + + - If a selected credential in \a cs_src already exists in \a + cs_dest, then update the credential in \a cs_dest with the + credential fields in \a cs_src. In other words, once a + credential is found to exist in both \a cs_src and \a cs_dest, + all the non-null fields from the credential in \a cs_src will be + copied to the credential in \a cs_dest. Fields which are null + (undefined) in \a cs_src and are non-null in \a cs_dest will be + left unmodified in \a cs_dest. + + One notable exception is the credentials' flags. All flags in + \a cs_src which are not included in + ::KCDB_CRED_FLAGMASK_ADDITIVE will be copied to the + corresponding bits in the flags of \a cs_dest. However, flags + that are included in ::KCDB_CRED_FLAGMASK_ADDITIVE will be added + to the corresponding bits in \a cs_dest. + + (See notes below) + + - Remove all credentials from \a cs_dest that match the \a + identity and \a type that do not appear in \a cs_src. (see notes + below) + + For performance reasons, plugins should use kcdb_credset_collect() + to update the root credentials store instead of adding and + removing individual credentials from the root store. + + Only credentials that are associated with active identities are + affected by kcdb_credset_collect(). + + \param[in] cs_dest A handle to the destination credential set. If + this is \a NULL, then it is assumed to refer to the root + credential store. + + \param[in] cs_src A handle to the source credential set. If this + is NULL, then it is assumed to refer to the root credential + store. + + \param[in] identity A handle to an identity. Setting this to NULL + collects all identities in the credential set. + + \param[in] type A credentials type. Setting this to + KCDB_CREDTYPE_ALL collects all credential types in the set. + + \param[out] delta A bit mask that indicates the modifications that + were made to \a cs_dest as a result of the collect operation. + This is a combination of KCDB_DELTA_* values. This parameter + can be \a NULL if the value is not required. + + \warning If \a identity and \a type is set to a wildcard, all + credentials in the root store that are not in this credentials + set will be deleted. + + \note Two credentials \a A and \a B are considered equal if: + - They refer to the same identity + - Both have the same credential type + - Both have the same name + + \note This is the only supported way of modifying the root + credential store. + + \note \a cs_src and \a cs_dest can not refer to the same + credentials set. + + \note The destination credential set cannot be sealed. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_collect(khm_handle cs_dest, + khm_handle cs_src, + khm_handle identity, + khm_int32 type, + khm_int32 * delta); + +/*! \brief Credentials were added + \see kcdb_credset_collect() */ +#define KCDB_DELTA_ADD 1 + +/*! \brief Credentials were deleted + \see kcdb_credset_collect() */ +#define KCDB_DELTA_DEL 2 + +/*! \brief Credentials were modified + \see kcdb_credset_collect() */ +#define KCDB_DELTA_MODIFY 4 + +/*! \brief Indicates that the credential to be filtered is from the root store. + + \see kcdb_credset_collect_filtered() +*/ +#define KCDB_CREDCOLL_FILTER_ROOT 1 + +/*! \brief Indicates that the credential to be filtered is from the source + credential set + + \see kcdb_credset_collect_filtered() */ +#define KCDB_CREDCOLL_FILTER_SRC 2 + +/*! \brief Indicates that the credential to be filtered is from the destination + credential set + + \see kcdb_credset_collect_filtered() */ +#define KCDB_CREDCOLL_FILTER_DEST 4 + +/*! \brief Collect credentials from one credential set to another using a filter. + + Similar to kcdb_credset_collect() except instead of selecting + credentials by matching against an identity and/or type, a filter + function is called. If the filter function returns non-zero for a + credential, that credential is selected. + + Credentials in the source and destination credential sets are + passed into the filter function. Depending on whether the + credential is in the source credential set or destination + credential set, the \a flag parameter may have either \a + KCDB_CREDCOLL_FILTER_SRC or \a KCDB_CREDCOLL_FILTER_DEST bits set. + Also, if either one of the credential sets is the root credential + store, then additionally \a KCDB_CREDCOLL_FILTER_ROOT would also + be set. + + See the kcdb_credset_collect() documentation for explanations of + the \a cs_src, \a cs_dest and \a delta parameters which perform + identical functions. + + \param[in] filter The filter of type ::kcdb_cred_filter_func + \param[in] rock A custom argument to be passed to the filter function. + + \see kcdb_credset_collect() +*/ +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); + +/*! \brief Flush all credentials from a credential set + + Deletes all the crednetials from the credential set. + + \param[in] credset A handle to a credential set. Cannot be NULL. + + \note The credential set cannot be sealed +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_flush(khm_handle credset); + +/*! \brief Extract credentials from one credential set to another + + Credentials from the source credential set are selected based on + the \a identity and \a type arguements. If a credential is + matched, then it is added to the \a destcredset. + + If the \a sourcecredset is the root credential set, the added + credentials are copies of the actual credentials in the root + credential set. Otherwise the credentials are references to the + original credentials in the \a sourcecredset . + + \param[in] destcredset Destination credential set. Must be valid. + + \param[in] sourcecredset The source credential set. If set to + NULL, extracts from the root credential set. + + \param[in] identity The identity to match in the source credential + 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_CREDTYPE_INVALID, matches all types. + + \note This function does not check for duplicate credentials. + + \note The destination credential set cannot be sealed. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_extract(khm_handle destcredset, + khm_handle sourcecredset, + khm_handle identity, + khm_int32 type); + +/*! \brief Extract credentials from one credential set to another using a filter. + + Similar to kcdb_credset_extract() except a filter function is used + to determine which credentials should be selected. + + \param[in] rock A custom argument to be passed in to the filter function. + + \note The destination credential set cannot be sealed. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_extract_filtered(khm_handle destcredset, + khm_handle sourcecredset, + kcdb_cred_filter_func filter, + void * rock); + +/*! \brief Retrieve a held reference to a credential in a credential set based on index. + + \param[in] idx The index of the credential to retrieve. This is a + zero based index which goes from 0 ... (size of credset - 1). + + \param[out] cred The held reference to a credential. Call + kcdb_cred_release() to release the credential. + + \retval KHM_ERROR_SUCCESS Success. \a cred has a held reference to the credential. + \retval KHM_ERROR_OUT_OF_BOUNDS The index specified in \a idx is out of bounds. + \retval KHM_ERROR_DELETED The credential at index \a idx has been marked as deleted. + + \see kcdb_cred_release() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_get_cred(khm_handle credset, + khm_int32 idx, + khm_handle * cred); + +/*! \brief Search a credential set for a specific credential + + The credential set indicated by \a credset is searched for a + credential that satisfies the predicate function \a f. Each + credential starting at \a idx_start is passed into the predicate + function until it returns a non-zero value. At this point, that + credential is passed in to the \a cred parameter, and the index of + the credential is passed into the \a idx parameter. + + \param[in] credset The credential set to search on. Specify NULL + if you want to search teh root credential set. + + \param[in] idx_start The index at which to start the search after. + The first credential passed to the predicate function will be + at \a idx_start + 1. Specify -1 to start from the beginning + of the credential set. + + \param[in] f The predicate function. The \a flags parameter of + the predicate function will always receive 0. + + \param[in] rock An opaque parameter to be passed to the predicate + function \a f. + + \param[out] cred A held reference to the credential that satisfied + the predicate function or NULL if no such credential was + found. Note that if a valid credential is returned, the + calling function must release the credential using + kcdb_cred_release(). + + \param[out] idx The index of the credential passed in \a cred. + Specify NULL if the index is not required. + + \retval KHM_ERROR_SUCCESS A credential that satisfied the + predicate function was found and was assigned to \a cred. + + \retval KHM_ERROR_NOT_FOUND No credential was found that matched + the predicate function. + + \note When querying credential sets that are shared between + threads, it is possible that another thread modifies the + credential set between successive calls to + kcdb_credset_find_filtered(). Therefore a continued sequences of + searches are not guaranteed to exhastively cover the + credential set nor to not return duplicate matches. Duplicate + matches are possible if the order of the credentials in the + set was changed. +*/ +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); + +/*! \brief Find matching credential + + Searches a credential set for a credential that matches the + specified credential. For a credential to be a match, it must + have the same identity, credential type and name. + + \param[in] credset Credential set to search + + \param[in] cred_src Credetial to search on + + \param[out] cred_dest receieves the matching credential if the + search is successful. If a handle is returend, the + kcdb_cred_release() must be used to release the handle. If + the matching credential is not required, you can pass in NULL. + + \retval KHM_ERROR_SUCCESS The search was successful. A credential + was assigned to \a cred_dest + + \retval KHM_ERROR_NOT_FOUND A matching credential was not found. + */ +KHMEXP khm_int32 KHMAPI +kcdb_credset_find_cred(khm_handle credset, + khm_handle cred_src, + khm_handle *cred_dest); + + +/*! \brief Delete a credential from a credential set. + + The credential at index \a idx will be deleted. All the + credentials that are at indices \a idx + 1 and above will be moved + down to fill the gap and the size of the credential set will + decrease by one. + + Use kcdb_credset_del_cred_ref() to delete a credential by + reference. Using kcdb_credset_del_cred() is faster than + kcdb_credset_del_cred_ref(). + + If you call kcdb_credset_del_cred() or kcdb_credset_del_cred_ref() + from within kcdb_credset_apply(), the credential will only be + marked as deleted. They will not be removed. This means that the + size of the credential set will not decrease. To purge the + deleted credentials from the set, call kcdb_credset_purge() after + kcdb_credset_apply() completes. + + \note The credential set cannot be sealed. + + \see kcdb_credset_del_cred_ref() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_del_cred(khm_handle credset, + khm_int32 idx); + +/*! \brief Delete a credential from a credential set by reference. + + See kcdb_credset_del_cred() for description of what happens when a + credential is deleted from a credential set. + + \note The credential set cannot be sealed. + + \see kcdb_credset_del_cred() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_del_cred_ref(khm_handle credset, + khm_handle cred); + +/*! \brief Add a credential to a credential set. + + The credential is added by reference. In other words, no copy of + the credential is made. + + \param[in] idx Index of the new credential. This must be a value + in the range 0..(previous size of credential set) or -1. If + -1 is specifed, then the credential is appended at the end of + the set. + + \note The credential set cannot be sealed. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_add_cred(khm_handle credset, + khm_handle cred, + khm_int32 idx); + +/*! \brief Get the number of credentials in a credential set. + + Credentials in a credential set may be volatile. When + kcdb_credeset_get_size() is called, the credential set is + compacted to only include credentials that are active at the time. + However, when you are iterating through the credential set, it + might be the case that some credentials would get marked as + deleted. These credentials will remain in the credential set + until the credential set is discarded or another call to + kcdb_credset_get_size() or kdcb_credset_purge() is made. + + If the credential set is sealed, then it will not be compacted and + will include deleted credentials as well. + + \see kcdb_credset_purge() + \see kcdb_credset_get_cred() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_get_size(khm_handle credset, + khm_size * size); + +/*! \brief Removes credentials that have been marked as deleted from a credential set. + + See description of \a kcdb_credset_purge() for a description of + what happens when credntials that are contained in a credential + set are deleted by an external entity. + + \note The credential set cannot be sealed. + + \see kcdb_credset_get_size() + \see kcdb_credset_get_cred() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_purge(khm_handle credset); + +/*! \brief Applies a function to all the credentials in a credentials set + + The given function is called for each credential in a credential + set. With each iteration, the function is called with a handle to + the credential and the user defined parameter \a rock. If the + function returns anything other than KHM_ERROR_SUCCESS, the + processing stops. + + \param[in] credset The credential set to apply the function to, or + NULL if you want to apply this to the root credential set. + + \param[in] f Function to call for each credential + + \param[in] rock An opaque parameter which is to be passed to 'f' + as the second argument. + + \retval KHM_ERROR_SUCCESS All the credentials were processed. + + \retval KHM_ERROR_EXIT The supplied function signalled the + processing to be aborted. + + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_apply(khm_handle credset, + kcdb_cred_apply_func f, + void * rock); + +/*! \brief Sort the contents of a credential set. + + \param[in] rock A custom argument to be passed in to the \a comp function. + + \note The credential set cannot be sealed. + + \see kcdb_cred_comp_generic() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_sort(khm_handle credset, + kcdb_cred_comp_func comp, + void * rock); + +/*! \brief Seal a credential set + + Sealing a credential set makes it read-only. To unseal a + credential set, call kcdb_credset_unseal(). + + Sealing is an additive operation. kcdb_credset_seal() can be + called muliple times. However, for every call to + kcdb_credset_seal() a call to kcdb_credset_unseal() must be made + to undo the seal. The credential set will become unsealed when + all the seals are released. + + Once sealed, the credential set will not allow any operation that + might change its contents. However, a selaed credential set can + still be delted. + + \see kcdb_credset_unseal() + */ +KHMEXP khm_int32 KHMAPI +kcdb_credset_seal(khm_handle credset); + +/*! \brief Unseal a credential set + + Undoes what kcdb_credset_seal() did. This does not guarantee that + the credential set is unsealed since there may be other seals. + + \see kcdb_credset_seal() + */ +KHMEXP khm_int32 KHMAPI +kcdb_credset_unseal(khm_handle credset); + +/*! \brief Defines a sort criterion for kcdb_cred_comp_generic() + + \see kcdb_cred_comp_generic() +*/ +typedef struct tag_kcdb_cred_comp_field { + khm_int32 attrib; /*!< a valid attribute ID */ + khm_int32 order; /*!< one of KCDB_CRED_COMP_INCREASING or + KCDB_CRED_COMP_DECREASING. Optionally, + KCDB_CRED_COMP_INITIAL_FIRST may be combined + with either. */ +} kcdb_cred_comp_field; + +/*! \brief Defines the sort order for a field in ::kcdb_cred_comp_field + + Sorts lexicographically ascending by string representation of field. +*/ +#define KCDB_CRED_COMP_INCREASING 0 + +/*! \brief Defines the sort order for a field in ::kcdb_cred_comp_field + + Sorts lexicographically descending by string representation of + field. + */ +#define KCDB_CRED_COMP_DECREASING 1 + +/*! \brief Defines the sort order for a field in ::kcdb_cred_comp_field + + Any credentials which have the ::KCDB_CRED_FLAG_INITIAL will be + grouped above any that don't. + + If that does not apply, then credentials from the primary + credentials type will be sorted before others. +*/ +#define KCDB_CRED_COMP_INITIAL_FIRST 2 + +/*! \brief Defines the sort criteria for kcdb_cred_comp_generic() + + \see kcdb_cred_comp_generic() +*/ +typedef struct tag_kcdb_cred_comp_order { + khm_int32 nFields; + kcdb_cred_comp_field * fields; +} kcdb_cred_comp_order; + +/*! \brief A generic compare function for comparing credentials. + + This function can be passed as a parameter to kcdb_credset_sort(). + + The \a rock parameter to this function should be a pointer to a + ::kcdb_cred_comp_order object. The \a fields member of the + ::kcdb_cred_comp_order object should point to an array of + ::kcdb_cred_comp_field objects, each of which specifies the sort + order in decreasing order of priority. The number of + ::kcdb_cred_comp_field objects in the array should correspond to + the \a nFields member in the ::kcdb_cred_comp_order object. + + The array of ::kcdb_cred_comp_field objects define the sort + criteria, in order. The \a attrib member should be a valid + attribute ID, while the \a order member determines whether the + sort order is increasing or decreasing. The exact meaning or + increasing or decreasing depends on the data type of the + attribute. + + \param[in] rock a pointer to a ::kcdb_cred_comp_order object +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_comp_generic(khm_handle cred1, + khm_handle cred2, + void * rock); + +/*@}*/ + +/*! \defgroup kcdb_cred Credentials */ +/*@{*/ + +/*! \brief Maximum number of characters in a credential name */ +#define KCDB_CRED_MAXCCH_NAME 256 + +/*! \brief Maximum number of bytes in a credential name */ +#define KCDB_CRED_MAXCB_NAME (sizeof(wchar_t) * KCDB_CRED_MAXCCH_NAME) + +/*! \brief Marked as deleted */ +#define KCDB_CRED_FLAG_DELETED 0x00000008 + +/*! \brief Renewable */ +#define KCDB_CRED_FLAG_RENEWABLE 0x00000010 + +/*! \brief Initial + + Initial credentials form the basis of an identity. Some + properties of an initial credential, such as being renewable, are + directly inherited by the identity. An identity is also + automatically considered valid if it contains a valid initial + credential. + */ +#define KCDB_CRED_FLAG_INITIAL 0x00000020 + +/*! \brief Expired + + The credential's lifetime has ended. + */ +#define KCDB_CRED_FLAG_EXPIRED 0x00000040 + +/*! \brief Invalid + + The credential can no longer serve its intended function. This + may be because it is expired and is not renewable, or its + renewable time period has also expired, or for some other reason. + */ +#define KCDB_CRED_FLAG_INVALID 0x00000080 + +/*! \brief Credential is selected + + Indicates that the credential is selected. Note that using this + flag may be subject to race conditions. + */ +#define KCDB_CRED_FLAG_SELECTED 0x00000100 + +/*! \brief Bitmask indicating all known credential flags + */ +#define KCDB_CRED_FLAGMASK_ALL 0x0000ffff + +/*! \brief External flags + + These are flags that are provided by the credentials providers. + The other flags are internal to KCDB and should not be modified. + */ +#define KCDB_CRED_FLAGMASK_EXT (KCDB_CRED_FLAG_INITIAL | KCDB_CRED_FLAG_EXPIRED | KCDB_CRED_FLAG_INVALID | KCDB_CRED_FLAG_RENEWABLE) + +/*! \brief Bitmask indicating dditive flags + + Additive flags are special flags which are added to exiting + credentials based on new credentials when doing a collect + operation. See details on kcdb_credset_collect() + + \see kcdb_credset_collect() +*/ +#define KCDB_CRED_FLAGMASK_ADDITIVE KCDB_CRED_FLAG_SELECTED + +/*! \brief Generic credentials request + + This data structure is used as the format for a generic + credentials reqeust for a ::KMSG_KCDB_REQUEST message. A plugin + typically publishes this message so that a credentials provider + may handle it and in response, obtain the specified credential. + + While the \a identity, \a type and \a name members of the + structure are all optional, typically one would specify all three + or at least two for a credential provider to be able to provide + the credential unambigously. + + Credential providers do not need to respond to ::KMSG_KCDB_REQUEST + messages. However, if they do, they should make sure that they + are the only credential provider that is responding by setting the + \a semaphore member to a non-zero value. The \a semaphore is set + to zero when a request is initially sent out. When incrementing + the semaphore, the plugin should use a thread safe mechanism to + ensure that there are no race conditions that would allow more + than one provider to respond to the message. + */ +typedef struct tag_kcdb_cred_request { + khm_handle identity; /*!< Identity of the credential. Set + to NULL if not specified. */ + khm_int32 type; /*!< Type of the credential. Set to + KCDB_CREDTYPE_INVALID if not + specified. */ + wchar_t * name; /*!< Name of the credential. Set to + NULL if not specified. */ + + khm_handle dest_credset; /*!< If non-NULL, instructs whoever is + handling the request that the + credential thus obtained be placed + in this credential set in addition + to whereever it may place newly + acquired credentials. Note that + while this can be NULL if the new + credential does not need to be + placed in a credential set, it can + not equal the root credential + set. */ + + void * vparam; /*!< An unspecified + parameter. Specific credential types + may specify how this field is to be + used. */ + + long semaphore; /*!< Incremented by one when this + request is answered. Only one + credential provider is allowed to + answer a ::KMSG_KCDB_REQUEST + message. Initially, when the + message is sent out, this member + should be set to zero. */ +} kcdb_cred_request; + +/*! \brief Create a new credential + + \param[in] name Name of credential. \a name cannot be NULL and cannot + exceed \a KCDB_CRED_MAXCCH_NAME unicode characters including the + \a NULL terminator. + \param[in] identity A reference to an identity. + \param[in] cred_type A credentials type identifier for the credential. + \param[out] result Gets a held reference to the newly created credential. + Call kcdb_cred_release() or kcdb_cred_delete() to release the + reference. + \see kcdb_cred_release() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_create(const wchar_t * name, + khm_handle identity, + khm_int32 cred_type, + khm_handle * result); + +/*! \brief Duplicate an existing credential. + + \param[out] newcred A held reference to the new credential if the call + succeeds. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_dup(khm_handle cred, + khm_handle * newcred); + +/*! \brief Updates one credential using field values from another + + All fields that exist in \a vsrc will get copied to \a vdest and will + overwrite any values that are already there in \a vdest. However any + values that exist in \a vdest taht do not exist in \a vsrc will not be + modified. + + \retval KHM_ERROR_SUCCESS vdest was successfully updated + \retval KHM_ERROR_EQUIVALENT all fields in vsrc were present and equivalent in vdest +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_update(khm_handle vdest, + khm_handle vsrc); + +/*! \brief Set an attribute in a credential by name + + + + \param[in] cbbuf Number of bytes of data in \a buffer. The + individual data type handlers may copy in less than this many + bytes in to the credential. For some data types where the + size of the buffer is fixed or can be determined from its + contents, you can specify ::KCDB_CBSIZE_AUTO for this + parameter. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_set_attrib(khm_handle cred, + const wchar_t * name, + void * buffer, + khm_size cbbuf); + +/*! \brief Set an attribute in a credential by attribute id + + \param[in] buffer A pointer to a buffer containing the data to + assign to the attribute. Setting this to NULL has the effect + of removing any data that is already assigned to the + attribute. If \a buffer is non-NULL, then \a cbbuf should + specify the number of bytes in \a buffer. + + \param[in] cbbuf Number of bytes of data in \a buffer. The + individual data type handlers may copy in less than this many + bytes in to the credential. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_set_attr(khm_handle cred, + khm_int32 attr_id, + void * buffer, + khm_size cbbuf); + +/*! \brief Get an attribute from a credential by name. + + \param[in] buffer The buffer that is to receive the attribute + value. Set this to NULL if only the required buffer size is + to be returned. + + \param[in,out] cbbuf The number of bytes available in \a buffer. + If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and + sets this to the required buffer size. + + \note Set both \a buffer and \a cbbuf to NULL if only the + existence of the attribute is to be checked. If the attribute + exists in this credential then the function will return + KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_attrib(khm_handle cred, + const wchar_t * name, + khm_int32 * attr_type, + void * buffer, + khm_size * cbbuf); + +/*! \brief Get an attribute from a credential by attribute id. + + \param[in] buffer The buffer that is to receive the attribute + value. Set this to NULL if only the required buffer size is + to be returned. + + \param[in,out] cbbuf The number of bytes available in \a buffer. + If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and + sets this to the required buffer size. + + \param[out] attr_type Receives the data type of the attribute. + Set this to NULL if the type is not required. + + \note Set both \a buffer and \a cbbuf to NULL if only the + existence of the attribute is to be checked. If the attribute + exists in this credential then the function will return + KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_attr(khm_handle cred, + khm_int32 attr_id, + khm_int32 * attr_type, + void * buffer, + khm_size * cbbuf); + +/*! \brief Get the name of a credential. + + \param[in] buffer The buffer that is to receive the credential + name. Set this to NULL if only the required buffer size is to + be returned. + + \param[in,out] cbbuf The number of bytes available in \a buffer. + If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and + sets this to the required buffer size. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_name(khm_handle cred, + wchar_t * buffer, + khm_size * cbbuf); + +/*! \brief Get the string representation of a credential attribute. + + A shortcut function which generates the string representation of a + credential attribute directly. + + \param[in] vcred A handle to a credential + + \param[in] attr_id The attribute to retrieve + + \param[out] buffer A pointer to a string buffer which receives the + string form of the attribute. Set this to NULL if you only + want to determine the size of the required buffer. + + \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, + holds the size of the buffer pointed to by \a buffer, and on + exit, receives the actual number of bytes that were copied. + + \param[in] flags Flags for the string conversion. Can be set to + one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is + KCDB_TS_LONG. + + \retval KHM_ERROR_SUCCESS Success + \retval KHM_ERROR_NOT_FOUND The given attribute was either invalid + or was not defined for this credential + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + \retval KHM_ERROR_TOO_LONG Either \a buffer was NULL or the + supplied buffer was insufficient +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_attr_string(khm_handle vcred, + khm_int32 attr_id, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags); + +/*! \brief Get the string representation of a credential attribute by name. + + A shortcut function which generates the string representation of a + credential attribute directly. + + \param[in] vcred A handle to a credential + + \param[in] attrib The name of the attribute to retrieve + + \param[out] buffer A pointer to a string buffer which receives the + string form of the attribute. Set this to NULL if you only + want to determine the size of the required buffer. + + \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, + holds the size of the buffer pointed to by \a buffer, and on + exit, receives the actual number of bytes that were copied. + + \param[in] flags Flags for the string conversion. Can be set to + one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is + KCDB_TS_LONG. + + \see kcdb_cred_get_attr_string() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_attrib_string(khm_handle cred, + const wchar_t * name, + wchar_t * buffer, + khm_size * cbbuf, + khm_int32 flags) ; + + +/*! \brief Get a held reference to the identity associated with a credential + + Use kcdb_identity_release() to release the reference that is + returned. + + \see kcdb_identity_relase() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_identity(khm_handle cred, + khm_handle * identity); + +/*! \brief Set the identity of a credential + + While it is ill-advised to change the identity of a credential + that has been placed in one or more credential sets, there can be + legitimate reasons for doing so. Only change the identity of a + credential that is not placed in a credential set or placed in a + credential set that is only used by a single entity. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_set_identity(khm_handle vcred, + khm_handle id); + +/*! \brief Get the serial number for the credential. + + Each credential gets assigned a serial number at the time it is + created. This will stay with the credential for its lifetime. + + \param[out] pserial Receives the serial number. Cannot be NULL. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_serial(khm_handle cred, + khm_ui_8 * pserial); + +/*! \brief Get the type of the credential. + + The returned type is a credential type. Doh. + + \param[out] type Receives the type. Cannot be NULL. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_type(khm_handle cred, + khm_int32 * type); + +/*! \brief Retrieve flags from a credential + + The flags returned will be place in the location pointed to by \a + flags. Note that the specified credential must be an active + credential for the operation to succeed. This means the + ::KCDB_CRED_FLAG_DELETED will never be retured by this function. + */ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_flags(khm_handle cred, + khm_int32 * flags); + +/*! \brief Set the flags of a credential + + The flags specified in the \a mask parameter will be set to the + values specified in the \a flags parameter. The flags that are + not included in \a mask will not be modified. + + This function can not be used to set the ::KCDB_CRED_FLAG_DELETED + flag. If this bit is specified in either \a flags or \a mask, it + will be ignored. + + \see ::KCDB_CRED_FLAGMASK_ALL + */ +KHMEXP khm_int32 KHMAPI +kcdb_cred_set_flags(khm_handle cred, + khm_int32 flags, + khm_int32 mask); + +/*! \brief Hold a reference to a credential. + + Use kcdb_cred_release() to release the reference. + + \see kcdb_cred_release() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_hold(khm_handle cred); + +/*! \brief Release a held reference to a credential. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_release(khm_handle cred); + +/*! \brief Delete a credential. + + The credential will be marked for deletion and will continue to + exist until all held references are released. If the credential + is bound to a credential set or the root credential store, it will + be removed from the respective container. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_delete(khm_handle cred); + +/*! \brief Compare an attribute of two credentials by name. + + \return The return value is dependent on the type of the attribute + and indicate a weak ordering of the attribute values of the two + credentials. If one or both credentials do not contain the + attribute, the return value is 0, which signifies that no ordering + can be determined. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_creds_comp_attrib(khm_handle cred1, + khm_handle cred2, + const wchar_t * name); + +/*! \brief Compare an attribute of two credentials by attribute id. + + \return The return value is dependent on the type of the attribute + and indicate a weak ordering of the attribute values of the two + credentials. If one or both credentials do not contain the + attribute, the return value is 0, which signifies that no ordering + can be determined. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_creds_comp_attr(khm_handle cred1, + khm_handle cred2, + khm_int32 attr_id); + +/*! \brief Compare two credentials for equivalence + + \return Non-zero if the two credentials are equal. Zero otherwise. + \note Two credentials are considered equal if all the following hold: + - Both refer to the same identity. + - Both have the same name. + - Both have the same type. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_creds_is_equal(khm_handle cred1, + khm_handle cred2); + +/*@}*/ +/*@}*/ + +/********************************************************************/ + +/*! \defgroup kcdb_type Credential attribute types + +@{*/ + +/*! \brief Convert a field to a string + + Provides a string representation of a field in a credential. The + data buffer can be assumed to be valid. + + On entry, \a s_buf can be NULL if only the required size of the + buffer is to be returned. \a pcb_s_buf should be non-NULL and + should point to a valid variable of type ::khm_size that will, on + entry, contain the size of the buffer pointed to by \a s_buf if \a + s_buf is not \a NULL, and on exit will contain the number of bytes + consumed in \a s_buf, or the required size of the buffer if \a + s_buf was NULL or the size of the buffer was insufficient. + + The implementation should verify the parameters that are passed in + to the function. + + The data pointed to by \a data should not be modified in any way. + + \param[in] data Valid pointer to a block of data + + \param[in] cb_data Number of bytes in data block pointed to by \a + data + + \param[out] s_buf Buffer to receive the string representation of + data. If the data type flags has KCDB_TYPE_FLAG_CB_AUTO, then + this parameter could be set to KCDB_CBSIZE_AUTO. In this + case, the function should compute the size of the input buffer + assuming that the input buffer is valid. + + \param[in,out] pcb_s_buf On entry, contains the size of the buffer + pointed to by \a s_buf, and on exit, contains the number of + bytes used by the string representation of the data including + the NULL terminator + + \param[in] flags Flags for formatting the string + + \retval KHM_ERROR_SUCCESS The string representation of the data + field was successfully copied to \a s_buf and the size of the + buffer used was copied to \a pcb_s_buf. + + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + + \retval KHM_ERROR_TOO_LONG Either \a s_buf was \a NULL or the size + indicated by \a pcb_s_buf was too small to contain the string + representation of the value. The required size of the buffer + is in \a pcb_s_buf. + + \note This documents the expected behavior of this prototype function + + \see ::kcdb_type + */ +typedef khm_int32 +(KHMAPI *kcdb_dtf_toString)(const void * data, + khm_size cb_data, + wchar_t * s_buf, + khm_size * pcb_s_buf, + khm_int32 flags); + +/*! \brief Verifies whetehr the given buffer contains valid data + + The function should examine the buffer and the size of the buffer + and determine whether or not the buffer contains valid data for + this data type. + + The data field pointed to by \a data should not be modified in any + way. + + \param[in] data A pointer to a data buffer + + \param[in] cb_data The number of bytes in the data buffer. If the + data type flags has KCDB_TYPE_FLAG_CB_AUTO, then this + parameter could be set to KCDB_CBSIZE_AUTO. In this case, the + function should compute the size of the input buffer assuming + that the input buffer is valid. + + \return TRUE if the data is valid, FALSE otherwise. + + \note This documents the expected behavior of this prototype function + + \see ::kcdb_type +*/ +typedef khm_boolean +(KHMAPI *kcdb_dtf_isValid)(const void * data, + khm_size cb_data); + +/*! \brief Compare two fields + + Compare the two data fields and return a value indicating their + relative ordering. The return value follows the same + specification as strcmp(). + + Both data buffers that are passed in can be assumed to be valid. + + None of the data buffers should be modified in any way. + + \param[in] data_l Valid pointer to first data buffer + + \param[in] cb_data_l Number of bytes in \a data_l. If the data + type flags has KCDB_TYPE_FLAG_CB_AUTO, then this parameter + could be set to KCDB_CBSIZE_AUTO. In this case, the function + should compute the size of the input buffer assuming that the + input buffer is valid. + + \param[in] data_r Valid pointer to second data buffer + + \param[in] cb_data_r Number of bytes in \a data_r. If the data + type flags has KCDB_TYPE_FLAG_CB_AUTO, then this parameter + could be set to KCDB_CBSIZE_AUTO. In this case, the function + should compute the size of the input buffer assuming that the + input buffer is valid. + + \return The return value should be + - Less than zero if \a data_l < \a data_r + - Equal to zero if \a data_l == \a data_r or if this data type can not be compared + - Greater than zero if \a data_l > \a data_r + + \note This documents the expected behavior of this prototype function + + \see ::kcdb_type +*/ +typedef khm_int32 +(KHMAPI *kcdb_dtf_comp)(const void * data_l, + khm_size cb_data_l, + const void * data_r, + khm_size cb_data_r); + +/*! \brief Duplicate a data field + + Duplicates a data field. The buffer pointed to by \a data_src + contains a valid field. The function should copy the field with + appropriate adjustments to \a data_dst. + + The \a data_dst parameter can be NULL if only the required size of + the buffer is needed. In this case, teh function should set \a + pcb_data_dst to the number of bytes required and then return + KHM_ERROR_TOO_LONG. + + \param[in] data_src Pointer to a valid data buffer + + \param[in] cb_data_src Number of bytes in \a data_src. If the data + type flags has KCDB_TYPE_FLAG_CB_AUTO, then this parameter + could be set to KCDB_CBSIZE_AUTO. In this case, the function + should compute the size of the input buffer assuming that the + input buffer is valid. + + \param[out] data_dst Poitner to destination buffer. Could be NULL + if only the required size of the destination buffer is to be + returned. + + \param[in,out] pcb_data_dst On entry specifies the number of bytes + in \a data_dst, and on exit should contain the number of bytes + copied. + + \retval KHM_ERROR_SUCCESS The data was successfully copied. The + number of bytes copied is in \a pcb_data_dst + + \retval KHM_ERROR_INVALID_PARAM One or more parameters is incorrect. + + \retval KHM_ERROR_TOO_LONG Either \a data_dst was NULL or the size + of the buffer was insufficient. The required size is in \a + pcb_data_dst + + \note This documents the expected behavior of this prototype function + + \see ::kcdb_type + */ +typedef khm_int32 +(KHMAPI *kcdb_dtf_dup)(const void * data_src, + khm_size cb_data_src, + void * data_dst, + khm_size * pcb_data_dst); + +/*! \brief A data type descriptor. + + Handles basic operation for a specific data type. + + \see \ref cred_data_types +*/ +typedef struct tag_kcdb_type { + wchar_t * name; + khm_int32 id; + khm_int32 flags; + + khm_size cb_min; + khm_size cb_max; + + kcdb_dtf_toString toString; + /*!< Provides a string representation for a value. */ + + kcdb_dtf_isValid isValid; + /*!< Returns true of the value is valid for this data type */ + + kcdb_dtf_comp comp; + /*!< Compare two values and return \a strcmp style return value */ + + kcdb_dtf_dup dup; + /*!< Duplicate a value into a secondary buffer */ +} kcdb_type; + +/*! \name Flags for kcdb_type::toString +@{*/ +/*! \brief Specify that the short form of the string representation should be returned. + + Flags for #kcdb_type::toString. The flag specifies how long the + string representation should be. The specific length of a short + or long description is not restricted and it is up to the + implementation to choose how to interpret the flags. + + Usually, KCDB_TS_SHORT is specified when the amount of space that + is available to display the string is very restricted. It may be + the case that the string is truncated to facilitate displaying in + a constrainted space. +*/ +#define KCDB_TS_SHORT 1 + +/*! \brief Specify that the long form of the string representation should be returned + + Flags for #kcdb_type::toString. The flag specifies how long the + string representation should be. The specific length of a short + or long description is not restricted and it is up to the + implementation to choose how to interpret the flags. + +*/ +#define KCDB_TS_LONG 0 +/*@}*/ + +/*! \brief The maximum number of bytes allowed for a value of any type */ +#define KCDB_TYPE_MAXCB 16384 + +/*! \name Flags for kcdb_type +@{*/ + +/*! \brief The type supports KCDB_CBSIZE_AUTO. + + Used for types where the size of the object can be determined + through context or by the object content. Such as for objects + that have a fixed size or unicode strings that have a terminator. + + This implies that ALL the object manipulation callbacks that are + defined in this type definition support the KCDB_CBSIZE_AUTO + value. +*/ +#define KCDB_TYPE_FLAG_CB_AUTO 16 + +/*! \brief The \a cb_min member is valid. + + The \a cb_min member defines the minimum number of bytes that an + object of this type will consume. + + \note If this flag is used in conjunction with \a + KCDB_TYPE_FLAG_CB_MAX then, \a cb_min must be less than or equal + to \a cb_max. +*/ +#define KCDB_TYPE_FLAG_CB_MIN 128 + +/*! \brief The \a cb_max member is valid. + + The \a cb_max member defines the maximum number of bytes that an + object of this type will consume. + + \note If this flag is used in conjunction with \a + KCDB_TYPE_FLAG_CB_MIN then, \a cb_min must be less than or + equal to \a cb_max. */ +#define KCDB_TYPE_FLAG_CB_MAX 256 + +/*! \brief Denotes that objects of this type have a fixed size. + + If this flags is specified, then the type definition must also + specify cb_min and cb_max, which must both be the same value. + + \note Implies \a KCDB_TYPE_FLAG_CB_AUTO, \a KCDB_TYPE_FLAG_CB_MIN + and \a KCDB_TYPE_FLAG_CB_MAX. Pay special attention to the + implication of \a KCDB_TYPE_FLAG_AUTO. +*/ +#define KCDB_TYPE_FLAG_CB_FIXED (KCDB_TYPE_FLAG_CB_AUTO|KCDB_TYPE_FLAG_CB_MIN|KCDB_TYPE_FLAG_CB_MAX) + +/*@}*/ + +KHMEXP khm_int32 KHMAPI +kcdb_type_get_id(const wchar_t *name, khm_int32 * id); + +/*! \brief Return the type descriptor for a given type id + + \param[out] info Receives a held reference to a type descriptor. + Use kcdb_type_release_info() to release the handle. If the \a + 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, + khm_size * cbbuf); + +/*! \brief Register a credentials attribute type + + The credentials type record pointed to by \a type defines a new + credential attribute type. The \a id member of \a type may be set + to KCDB_TYPE_INVALID to indicate that an attribute ID is to be + generated automatically. + + \param[in] type The type descriptor + \param[out] new_id Receives the identifier for the credential attribute type. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_type_register(const kcdb_type * type, + khm_int32 * new_id); + +/*! \brief Unregister a credential attribute type + + Removes the registration for the specified credentials attribute + type. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_type_unregister(khm_int32 id); + +KHMEXP khm_int32 KHMAPI +kcdb_type_get_next_free(khm_int32 * id); + +/*! \name Conversion functions +@{*/ +/*! \brief Convert a time_t value to FILETIME +*/ +KHMEXP void KHMAPI +TimetToFileTime( time_t t, LPFILETIME pft ); + +/*! \brief Convert a time_t interval to a FILETIME interval +*/ +KHMEXP void KHMAPI +TimetToFileTimeInterval(time_t t, LPFILETIME pft); + +/*! \brief Convert a FILETIME interval to seconds +*/ +KHMEXP long KHMAPI +FtIntervalToSeconds(LPFILETIME pft); + +/*! \brief Convert a FILETIME interval to milliseconds +*/ +KHMEXP long KHMAPI +FtIntervalToMilliseconds(LPFILETIME pft); + +/*! \brief Compare two FILETIME values + + The return value is similar to the return value of strcmp(), based + on the comparison of the two FILETIME values. + */ +KHMEXP long KHMAPI +FtCompare(LPFILETIME pft1, LPFILETIME pft2); + +/*! \brief Convert a FILETIME to a 64 bit int +*/ +KHMEXP khm_int64 KHMAPI FtToInt(LPFILETIME pft); + +/*! \brief Convert a 64 bit int to a FILETIME +*/ +KHMEXP FILETIME KHMAPI IntToFt(khm_int64 i); + +/*! \brief Calculate the difference between two FILETIMEs + + Returns the value of ft1 - ft2 + */ +KHMEXP FILETIME KHMAPI FtSub(LPFILETIME ft1, LPFILETIME ft2); + +/*! \brief Calculate the sum of two FILETIMEs + + Return the value of ft1 + ft2 + */ +KHMEXP FILETIME KHMAPI FtAdd(LPFILETIME ft1, LPFILETIME ft2); + +/*! \brief Convert a FILETIME inverval to a string +*/ +KHMEXP khm_int32 KHMAPI +FtIntervalToString(LPFILETIME data, + wchar_t * buffer, + khm_size * cb_buf); + +/*! \brief Parse a string representing an interval into a FILETIME interval + + The string is a localized string which should look like the + following: + + \code + [number unit] [number unit]... + \endcode + + where \a number is an integer while \a unit is a localized + (possibly abbreviated) unit specification. The value of the + described interval is calculated as the sum of each \a number in + \a units. For example : + + \code + 1 hour 36 minutes + \endcode + + would result in an interval specification that's equivalent to 1 + hour and 36 minutes. Of course there is no restriction on the + order in which the \a number \a unit specifications are given and + the same unit may be repeated multiple times. + + \retval KHM_ERROR_INVALID_PARAM The given string was invalid or had + a token that could not be parsed. It can also mean that \a + pft was NULL or \a str was NULL. + + \retval KHM_ERROR_SUCCESS The string was successfully parsed and + the result was placed in \a pft. +*/ +KHMEXP khm_int32 KHMAPI +IntervalStringToFt(FILETIME * pft, wchar_t * str); + +/*! \brief Return number of milliseconds till next representation change + + Returns the number of milliseconds that must elapse away from the + interval specified in pft \a for the representation of pft to change + from whatever it is right now. + + Returns 0 if the representation is not expected to change. +*/ +KHMEXP long KHMAPI +FtIntervalMsToRepChange(LPFILETIME pft); + +/*! \brief Convert a safe ANSI string to a Unicode string + + The resulting string is guaranteed to be NULL terminated and + within the size limit set by \a cbwstr. + + If the whole string cannot be converted, \a wstr is set to an + empty string. + + \return the number of characters converted. This is always either + the length of the string \a astr or 0. +*/ +KHMEXP int KHMAPI +AnsiStrToUnicode( wchar_t * wstr, size_t cbwstr, const char * astr); + +/*! \brief Convert a Unicode string to ANSI + + The resulting string is guaranteed to be NULL terminated and + within the size limit set by \a cbdest. + + \return the number of characters converted. This is always either + the length of the string \a src or 0. +*/ +KHMEXP int KHMAPI +UnicodeStrToAnsi( char * dest, size_t cbdest, const wchar_t * src); +/*@}*/ + +/*! \name Standard type identifiers and names +@{*/ + +/*! Maximum identifier number */ +#define KCDB_TYPE_MAX_ID 255 + +/*! \brief Invalid type + + Used by functions that return a type identifier to indicate that + the returned type identifier is invalid. Also used to indicate + that a type identifier is not available */ +#define KCDB_TYPE_INVALID (-1) + +/*! \brief All types + + Used by filters to indicate that all types are allowed. +*/ +#define KCDB_TYPE_ALL KCDB_TYPE_INVALID + +/*! \brief Void + + No data. This is not an actual data type. + */ +#define KCDB_TYPE_VOID 0 + +/*! \brief String + + NULL terminated Unicode string. The byte count for a string + attribute always includes the terminating NULL. + */ +#define KCDB_TYPE_STRING 1 + +/*! \brief Data + + A date/time represented in FILETIME format. + */ +#define KCDB_TYPE_DATE 2 + +/*! \brief Interval + + An interval of time represented as the difference between two + FILETIME values. + */ +#define KCDB_TYPE_INTERVAL 3 + +/*! \brief 32-bit integer + + A 32-bit signed integer. + */ +#define KCDB_TYPE_INT32 4 + +/*! \brief 64-bit integer + + A 64-bit integer. + */ +#define KCDB_TYPE_INT64 5 + +/*! \brief Raw data + + A raw data buffer. + */ +#define KCDB_TYPE_DATA 6 + +#define KCDB_TYPENAME_VOID L"Void" +#define KCDB_TYPENAME_STRING L"String" +#define KCDB_TYPENAME_DATE L"Date" +#define KCDB_TYPENAME_INTERVAL L"Interval" +#define KCDB_TYPENAME_INT32 L"Int32" +#define KCDB_TYPENAME_INT64 L"Int64" +#define KCDB_TYPENAME_DATA L"Data" +/*@}*/ +/*@}*/ + +/********************************************************************/ + +/*! \defgroup kcdb_credattr Credential attributes */ +/*@{*/ + +/*! \brief Prototype callback function for computed data types. + + If the flags for a particular attribute specifies that the value + is computed, then a callback function should be specified. The + callback function will be called with a handle to a credential + along with the attribute ID for the requested attribute. The + function should place the computed value in \a buffer. The size + of the buffer in bytes is specifed in \a cbsize. However, if \a + buffer is \a NULL, then the required buffer size should be placed + in \a cbsize. + */ +typedef khm_int32 +(KHMAPI *kcdb_attrib_compute_cb)(khm_handle cred, + khm_int32 id, + void * buffer, + khm_size * cbsize); + +/*! \brief Credential attribute descriptor + + \see kcdb_attrib_register() +*/ +typedef struct tag_kcdb_attrib { + wchar_t * name; /*!< Name. (Not localized, + required) */ + khm_int32 id; /*!< Identifier. When registering, + this can be set to + ::KCDB_ATTR_INVALID if a unique + identifier is to be generated. */ + khm_int32 alt_id; /*!< Alternate identifier. If the \a + flags specify + ::KCDB_ATTR_FLAG_ALTVIEW, then this + field should specify the identifier + of the canonical attribute from + which this attribute is derived. */ + khm_int32 flags; /*!< Flags. Combination of \ref + kcdb_credattr_flags "attribute + flags" */ + + khm_int32 type; /*!< Type of the attribute. Must be valid. */ + + wchar_t * short_desc; /*!< Short description. (Localized, + optional) */ + + wchar_t * long_desc; /*!< Long description. (Localized, + optional) */ + + kcdb_attrib_compute_cb compute_cb; + /*!< Callback. Required if \a flags + specify ::KCDB_ATTR_FLAG_COMPUTED. */ + + khm_size compute_min_cbsize; + /*!< Minimum number of bytes required + to store this attribute. Required + if ::KCDB_ATTR_FLAG_COMPUTED is + specified.*/ + khm_size compute_max_cbsize; + /*!< Maximum number of bytes required + to store this attribute. Required + if ::KCDB_ATTR_FLAG_COMPUTED is + specified.*/ +} kcdb_attrib; + +/*! \brief Retrieve the ID of a named attribute */ +KHMEXP khm_int32 KHMAPI +kcdb_attrib_get_id(const wchar_t *name, + khm_int32 * id); + +/*! \brief Register an attribute + + \param[out] new_id Receives the ID of the newly registered + attribute. If the \a id member of the ::kcdb_attrib object is + set to KCDB_ATTR_INVALID, then a unique ID is generated. */ +KHMEXP khm_int32 KHMAPI +kcdb_attrib_register(const kcdb_attrib * attrib, + khm_int32 * new_id); + +/*! \brief Retrieve the attribute descriptor for an attribute + + The descriptor that is returned must be released through a call to + kcdb_attrib_release_info() + + If only the validity of the attribute identifier needs to be + checked, you can pass in NULL for \a attrib. In this case, if the + identifier is valid, then the funciton will return + KHM_ERROR_SUCCESS, otherwise it will return KHM_ERROR_NOT_FOUND. + + \see kcdb_attrib_release_info() + */ +KHMEXP khm_int32 KHMAPI +kcdb_attrib_get_info(khm_int32 id, + kcdb_attrib ** attrib); + +/*! \brief Release an attribute descriptor + + \see kcdb_attrib_get_info() + */ +KHMEXP khm_int32 KHMAPI +kcdb_attrib_release_info(kcdb_attrib * attrib); + +/*! \brief Unregister an attribute + + Once an attribute ID has been unregistered, it may be reclaimed by + a subsequent call to kcdb_attrib_register(). +*/ +KHMEXP khm_int32 KHMAPI +kcdb_attrib_unregister(khm_int32 id); + +/*! \brief Retrieve the description of an attribute + + \param[in] flags Specify \a KCDB_TS_SHORT to retrieve the short description. */ +KHMEXP khm_int32 KHMAPI +kcdb_attrib_describe(khm_int32 id, + wchar_t * buffer, + khm_size * cbsize, + khm_int32 flags); + +/*! \brief Count attributes + + Counts the number of attributes that match the given criteria. + The criteria is specified against the flags of the attribute. An + attribute is a match if its flags satisfy the condition below: + + \code + (attrib.flags & and_flags) == (eq_flags & and_flags) + \endcode + + The number of attributes that match are returned in \a pcount. + */ +KHMEXP khm_int32 KHMAPI +kcdb_attrib_get_count(khm_int32 and_flags, + khm_int32 eq_flags, + khm_size * pcount); + +/*! \brief List attribute identifiers + + Lists the identifiers of the attributes that match the given + criteria. The criteria is specified against the flags of the + attribute. An attribute is a match if the following condition is + satisfied: + + \code + (attrib.flags & and_flags) == (eq_flags & and_flags) + \endcode + + The list of attributes found are copied to the \a khm_int32 array + specified in \a plist. The number of elements available in the + buffer \a plist is specified in \a pcsize. On exit, \a pcsize + will hold the actual number of attribute identifiers copied to the + array. + + \param[in] and_flags See above + \param[in] eq_flags See above + \param[in] plist A khm_int32 array + \param[in,out] pcsize On entry, holds the number of elements + available in the array pointed to by \a plist. On exit, holds + the number of elements copied to the array. + + \retval KHM_ERROR_SUCCESS The list of attribute identifiers have + been copied. + \retval KHM_ERROR_TOO_LONG The list was too long to fit in the + supplied buffer. As many elements as possible have been + copied to the \a plist array and the required number of + elements has been written to \a pcsize. + + \note The \a pcsize parameter specifies the number of khm_int32 + elements in the array and not the number of bytes in the + array. This is different from the usual size parameters used + in the NetIDMgr API. + */ +KHMEXP khm_int32 KHMAPI +kcdb_attrib_get_ids(khm_int32 and_flags, + khm_int32 eq_flags, + khm_int32 * plist, + khm_size * pcsize); + +/*! \defgroup kcdb_credattr_flags Attribute flags */ +/*@{*/ +/*! \brief The attribute is required */ +#define KCDB_ATTR_FLAG_REQUIRED 0x00000008 + +/*! \brief The attribute is computed. + + If this flag is set, the \a compute_cb, \a compute_min_cbsize and + \a compute_max_cbsize members of the ::kcdb_attrib attribute + descriptor must be assigned valid values. +*/ +#define KCDB_ATTR_FLAG_COMPUTED 0x00000010 + +/*! \brief System attribute. + + This cannot be specified for a custom attribute. Implies that the + value of the attribute is given by the credentials database + itself. +*/ +#define KCDB_ATTR_FLAG_SYSTEM 0x00000020 + +/*! \brief Hidden + + The attribute is not meant to be displayed to the user. Setting + this flag prevents this attribute from being listed in the list of + available data fields in the UI. +*/ +#define KCDB_ATTR_FLAG_HIDDEN 0x00000040 + +/*! \brief Property + + The attribute is a property. The main difference between regular + attributes and properties are that properties are not allocated + off the credentials record. Hence, a property can not be used as + a credentials field. Other objects such as identities can hold + property sets. A property set can hold both regular attributes as + well as properties. +*/ +#define KCDB_ATTR_FLAG_PROPERTY 0x00000080 + +/*! \brief Volatile + + A volatile property is one whose value changes often, such as + ::KCDB_ATTR_TIMELEFT. Some controls will make use of additional + logic to deal with such values, or not display them at all. + */ +#define KCDB_ATTR_FLAG_VOLATILE 0x00000100 + +/*! \brief Alternate view + + The attribute is actually an alternate representation of another + attribute. The Canonical attribute name is specified in \a + alt_id. + + Sometimes a certain attribute may need to be represented in + different ways. You can register multiple attributes for each + view. However, you should also provide a canonical attribute for + whenever the canonical set of attributes of the credential is + 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 */ +/*@{*/ + +/*! \name Attribute related constants */ +/*@{*/ +/*! \brief Maximum valid attribute ID */ +#define KCDB_ATTR_MAX_ID 255 + +/*! \brief Minimum valid property ID */ +#define KCDB_ATTR_MIN_PROP_ID 4096 + +/*! \brief Maximum number of properties */ +#define KCDB_ATTR_MAX_PROPS 128 + +/*! \brief Maximum valid property ID */ +#define KCDB_ATTR_MAX_PROP_ID (KCDB_ATTR_MIN_PROP_ID + KCDB_ATTR_MAX_PROPS - 1) + +/*! \brief Invalid ID */ +#define KCDB_ATTR_INVALID (-1) + +/*! \brief First custom attribute ID */ +#define KCDB_ATTRID_USER 20 + +/*@}*/ + +/*!\name Attribute identifiers */ +/*@{*/ +/*! \brief Name of the credential + + - \b Type: STRING + - \b Flags: REQUIRED, COMPUTED, SYSTEM + */ +#define KCDB_ATTR_NAME 0 + +/*! \brief The identity handle for the credential + + - \b Type: INT64 + - \b Flags: REQUIRED, COMPUTED, SYSTEM, HIDDEN + + \note The handle returned in by specifying this attribute to + kcdb_cred_get_attr() or kcdb_cred_get_attrib() is not held. + While the identity is implicitly held for the duration that + the credential is held, it is not recommended to obtain a + handle to the identity using this method. Use + kcdb_cred_get_identity() instead. +*/ +#define KCDB_ATTR_ID 1 + +/*! \brief The name of the identity + + - \b Type: STRING + - \b Flags: REQUIRED, COMPUTED, SYSTEM + */ +#define KCDB_ATTR_ID_NAME 2 + +/*! \brief The type of the credential + + - \b Type: INT32 + - \b Flags: REQUIRED, COMPUTED, SYSTEM, HIDDEN +*/ +#define KCDB_ATTR_TYPE 3 + +/*! \brief Type name for the credential + + - \b Type: STRING + - \b Flags: REQUIRED, COMPUTED, SYSTEM +*/ +#define KCDB_ATTR_TYPE_NAME 4 + +/*! \brief Name of the parent credential + + - \b Type: STRING + - \b Flags: SYSTEM +*/ +#define KCDB_ATTR_PARENT_NAME 5 + +/*! \brief Issed on + + - \b Type: DATE + - \b Flags: SYSTEM +*/ +#define KCDB_ATTR_ISSUE 6 + +/*! \brief Expires on + + - \b Type: DATE + - \b Flags: SYSTEM +*/ +#define KCDB_ATTR_EXPIRE 7 + +/*! \brief Renewable period expires on + + - \b Type: DATE + - \b Flags: SYSTEM +*/ +#define KCDB_ATTR_RENEW_EXPIRE 8 + +/*! \brief Time left till expiration + + - \b Type: INTERVAL + - \b Flags: SYSTEM, COMPUTED, VOLATILE +*/ +#define KCDB_ATTR_TIMELEFT 9 + +#define KCDB_ATTR_RENEW_TIMELEFT 10 + +/*! \brief Location of the credential + + - \b Type: STRING + - \b Flags: SYSTEM +*/ +#define KCDB_ATTR_LOCATION 11 + +/*! \brief Lifetime of the credential + + - \b Type: INTERVAL + - \b Flags: SYSTEM +*/ +#define KCDB_ATTR_LIFETIME 12 + +#define KCDB_ATTR_RENEW_LIFETIME 13 + +/*! \brief Flags for the credential + + - \b Type: INT32 + - \b Flags: REQUIRED, COMPUTED, SYSTEM, HIDDEN + */ +#define KCDB_ATTR_FLAGS 14 + +/*@}*/ + +/*!\name Attribute names */ +/*@{ */ + +#define KCDB_ATTRNAME_NAME L"Name" +#define KCDB_ATTRNAME_ID L"Identity" +#define KCDB_ATTRNAME_ID_NAME L"IdentityName" +#define KCDB_ATTRNAME_TYPE L"TypeId" +#define KCDB_ATTRNAME_TYPE_NAME L"TypeName" +#define KCDB_ATTRNAME_FLAGS L"Flags" + +#define KCDB_ATTRNAME_PARENT_NAME L"Parent" +#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" +#define KCDB_ATTRNAME_RENEW_TIMELEFT L"RenewTimeLeft" +#define KCDB_ATTRNAME_LOCATION L"Location" +#define KCDB_ATTRNAME_LIFETIME L"Lifetime" +#define KCDB_ATTRNAME_RENEW_LIFETIME L"RenewLifetime" + +/*@}*/ + +/*@}*/ + +/*@}*/ + +/*****************************************************************************/ + +/*! \defgroup kcdb_credtype Credential types */ +/*@{*/ + +/*! \brief Credential type descriptor */ +typedef struct tag_kcdb_credtype { + wchar_t * name; /*!< name (less than KCDB_MAXCB_NAME bytes) */ + khm_int32 id; + wchar_t * short_desc; /*!< short localized description (less + than KCDB_MAXCB_SHORT_DESC bytes) */ + wchar_t * long_desc; /*!< long localized descriptionn (less + than KCDB_MAXCB_LONG_DESC bytes) */ + khm_handle sub; /*!< Subscription for credentials type + hander. This should be a valid + subscription constructed through a + call to kmq_create_subscription() + and must handle KMSG_CRED messages + that are marked as being sent to + type specific subscriptions. + + The subscription will be + automatically deleted with a call to + kmq_delete_subscription() when the + credentials type is unregistered.*/ + + kcdb_cred_comp_func is_equal; /*!< Used as an additional clause + when comparing two credentials for + equality. The function this is + actually a comparison function, it + should return zero if the two + credentials are equal and non-zero + if they are not. The addtional \a + rock parameter is always zero. + + It can be assumed that the identity, + name and credentials type have + already been found to be equal among + the credentials and the credential + type is the type that is being + registered.*/ + +#ifdef _WIN32 + HICON icon; +#endif +} kcdb_credtype; + +/*! \brief Maximum value of a credential type identifier + + Credential type identifiers are assigned serially unless the + process registering the credential type sets a specific identity. + The maximum identifier number places a hard limit to the number of + credential types that can be registered at one time, which is + KCDB_CREDTYPE_MAX_ID + 1. + */ +#define KCDB_CREDTYPE_MAX_ID 31 + +/*! \brief Specify all credential types + + This value is used by functions which filter credentials based on + credential types. Specifying this value tells the filter to + accept all credential types. + */ +#define KCDB_CREDTYPE_ALL (-1) + +/*! \brief Automatically determine a credential type identifier + + Used with kcdb_credtype_register() to specify that the credential + type identifier should be automatically determined to avoid + collisions. + */ +#define KCDB_CREDTYPE_AUTO (-2) + +/*! \brief An invalid credential type + + Even though any non positive credential type ID is invalid + anywhere where a specific credential type ID is required, this + value is provided for explicit indication that the credential type + is invalid. Also it makes code more readable to have a constant + that shouts out INVALID. + +*/ +#define KCDB_CREDTYPE_INVALID (-3) + +/*! \brief Macro predicate for testing whether a credtype is valid + + Returns TRUE if the given credtype is valid. This is a safe + macro. +*/ +#define KCDB_CREDTYPE_IS_VALID(t) ((t) >= 0) + +/*! \brief Register a credentials type. + + The information given in the \a type parameter is used to register + a new credential type. Note that the \a name member of the \a + type should be unique among all credential types. + + You can specify ::KCDB_CREDTYPE_AUTO as the \a id member of \a + type to let kcdb_credtype_register() determine a suitable + credential type identifier. You can subsequently call + kcdb_credtype_get_id() to retrieve the generated id or pass a + valid pointer to a khm_int32 type variable as \a new_id. + + \param[in] type Credential type descriptor + + \param[out] new_id The credential type identifier that this type + was registered as. + + \retval KHM_ERROR_SUCCESS The credential type was successfully registered. + + \retval KHM_ERROR_INVALID_PARAM One or more of the parameters were invalid + + \retval KHM_ERROR_TOO_LONG One or more of the string fields in \a + type exceeded the character limit for that field. + + \retval KHM_ERROR_NO_RESOURCES When autogenerating credential type + identifiers, this value indicates that the maximum number of + credential types have been registered. No more registrations + can be accepted unless some credentials type is unregisred. + + \retval KHM_ERROR_DUPLICATE The \a name or \a id that was + specified is already in use. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credtype_register(const kcdb_credtype * type, + khm_int32 * new_id); + +/*! \brief Return a held reference to a \a kcdb_credtype object describing the credential type. + + The reference points to a static internal object of type \a + kcdb_credtype. Use the kcdb_credtype_release_info() function to + release the reference. + + Also, the structure passed in as the \a type argument to + kcdb_credtype_register() is not valid as a credential type + descriptor. Use kcdb_credtype_get_info() to obtain the actual + credential type descriptor. + + \param[in] id Credentials type identifier. + + \param[out] type Receives the credentials descriptor handle. If + \a type is NULL, then no handle is returned. However, the + function will still return \a KHM_ERROR_SUCCESS if the \a id + parameter passed in is a valid credentials type identifier. + + \see kcdb_credtype_release_info() + \see kcdb_credtype_register() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credtype_get_info(khm_int32 id, + kcdb_credtype ** type); + +/*! \brief Release a reference to a \a kcdb_credtype object + + Undoes the hold obtained on a \a kcdb_credtype object from a + previous call to kcdb_credtype_get_info(). + + \see kcdb_credtype_get_info() + */ +KHMEXP khm_int32 KHMAPI +kcdb_credtype_release_info(kcdb_credtype * type); + +/*! \brief Unregister a credentials type + + Undoes the registration performed by kcdb_credtype_register(). + + This should only be done when the credentials provider is being + unloaded. + */ +KHMEXP khm_int32 KHMAPI +kcdb_credtype_unregister(khm_int32 id); + +/*! \brief Retrieve the name of a credentials type + + Given a credentials type identifier, retrieves the name. The name + is not localized and serves as a persistent identifier of the + credentials type. + + \param[out] buf The buffer to receive the name. Could be \a NULL + if only the length of the buffer is required. + + \param[in,out] cbbuf On entry, specifies the size of the buffer + pointed to by \a buf if \a buf is not NULL. On exit, contains + the number of bytes copied to \a buf or the required size of + the buffer. + + \retval KHM_ERROR_SUCCESS The call succeeded. + + \retval KHM_ERROR_TOO_LONG Either \a buf was NULL or the supplied + buffer was not large enough. The required size is in \a cbbuf. + + \retval KHM_ERROR_INVALID_PARAM Invalid parameter. + */ +KHMEXP khm_int32 KHMAPI +kcdb_credtype_get_name(khm_int32 id, + wchar_t * buf, + khm_size * cbbuf); + +/*! \brief Retrieve the type specific subscription for a type + + Given a credentials type, this function returns the credentials + type specific subcription. It may return NULL if the subscription + is not available. + */ +KHMEXP khm_handle KHMAPI +kcdb_credtype_get_sub(khm_int32 id); + +/*! \brief Get the description of a credentials type + + Unlike the name of a credential type, the description is localized. + + \param[in] id Credentials type identifier + + \param[out] buf Receives the description. Can bet set to NULL if + only the size of the buffer is required. + + \param[in,out] cbbuf On entry, specifies the size of the buffer + pointed to by \a buf. On exit, specifies the required size of + the buffer or the number of bytes copied, depending on whether + the call succeeded or not. + + \param[in] flags Specify ::KCDB_TS_SHORT if the short version of + the description is desired if there is more than one. + + \retval KHM_ERROR_SUCCESS The call succeeded + \retval KHM_ERROR_TOO_LONG Either \a buf was NULL or the supplied buffer was insufficient. The required size is specified in \a cbbuf. + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid. + */ +KHMEXP khm_int32 KHMAPI +kcdb_credtype_describe(khm_int32 id, + wchar_t * buf, + khm_size * cbbuf, + khm_int32 flags); + +/*! \brief Look up the identifier of a credentials type by name + + Given a name, looks up the identifier. + + \param[in] name Name of the credentials type + \param[out] id Receives the identifier if the call succeeds + + */ +KHMEXP khm_int32 KHMAPI +kcdb_credtype_get_id(const wchar_t * name, + khm_int32 * id); + +/*@}*/ + +/*********************************************************************/ + +/*! \defgroup kcdb_buf Generic access to buffer + + Currently, credentials and identities both hold record data types. + This set of API's allow an application to access fields in the + records using a single interface. Note that credentials only + accept regular attributes while identities can hold both + attributes and properties. + + Handles to credentials and identities are implicitly also handles + to records. Thus they can be directly used as such. +*/ +/*@{*/ + +/*! \brief Get an attribute from a record by attribute id. + + \param[in] buffer The buffer that is to receive the attribute + value. Set this to NULL if only the required buffer size is + to be returned. + + \param[in,out] cbbuf The number of bytes available in \a buffer. + If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and + sets this to the required buffer size. + + \param[out] attr_type Receives the data type of the attribute. + Set this to NULL if the type is not required. + + \note Set both \a buffer and \a cbbuf to NULL if only the + existence of the attribute is to be checked. If the attribute + exists in this record then the function will return + KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_buf_get_attr(khm_handle record, + khm_int32 attr_id, + khm_int32 * attr_type, + void * buffer, + khm_size * pcb_buf); + +/*! \brief Get an attribute from a record by name. + + \param[in] buffer The buffer that is to receive the attribute + value. Set this to NULL if only the required buffer size is + to be returned. + + \param[in,out] cbbuf The number of bytes available in \a buffer. + If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and + sets this to the required buffer size. + + \note Set both \a buffer and \a cbbuf to NULL if only the + existence of the attribute is to be checked. If the attribute + exists in this record then the function will return + KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_buf_get_attrib(khm_handle record, + const wchar_t * attr_name, + khm_int32 * attr_type, + void * buffer, + khm_size * pcb_buf); + +/*! \brief Get the string representation of a record attribute. + + A shortcut function which generates the string representation of a + record attribute directly. + + \param[in] record A handle to a record + + \param[in] attr_id The attribute to retrieve + + \param[out] buffer A pointer to a string buffer which receives the + string form of the attribute. Set this to NULL if you only + want to determine the size of the required buffer. + + \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, + holds the size of the buffer pointed to by \a buffer, and on + exit, receives the actual number of bytes that were copied. + + \param[in] flags Flags for the string conversion. Can be set to + one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is + KCDB_TS_LONG. + + \retval KHM_ERROR_SUCCESS Success + \retval KHM_ERROR_NOT_FOUND The given attribute was either invalid + or was not defined for this record + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + \retval KHM_ERROR_TOO_LONG Either \a buffer was NULL or the + supplied buffer was insufficient +*/ +KHMEXP khm_int32 KHMAPI +kcdb_buf_get_attr_string(khm_handle record, + khm_int32 attr_id, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags); + +/*! \brief Get the string representation of a record attribute by name. + + A shortcut function which generates the string representation of a + record attribute directly. + + \param[in] record A handle to a record + + \param[in] attrib The name of the attribute to retrieve + + \param[out] buffer A pointer to a string buffer which receives the + string form of the attribute. Set this to NULL if you only + want to determine the size of the required buffer. + + \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, + holds the size of the buffer pointed to by \a buffer, and on + exit, receives the actual number of bytes that were copied. + + \param[in] flags Flags for the string conversion. Can be set to + one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is + KCDB_TS_LONG. + + \see kcdb_cred_get_attr_string() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_buf_get_attrib_string(khm_handle record, + const wchar_t * attr_name, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags); + +/*! \brief Set an attribute in a record by attribute id + + \param[in] cbbuf Number of bytes of data in \a buffer. The + individual data type handlers may copy in less than this many + bytes in to the record. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_buf_set_attr(khm_handle record, + khm_int32 attr_id, + void * buffer, + khm_size cbbuf); + +/*! \brief Set an attribute in a record by name + + \param[in] cbbuf Number of bytes of data in \a buffer. The + individual data type handlers may copy in less than this many + bytes in to the record. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_buf_set_attrib(khm_handle record, + const wchar_t * attr_name, + void * buffer, + khm_size cbbuf); + +KHMEXP khm_int32 KHMAPI +kcdb_buf_hold(khm_handle record); + +KHMEXP khm_int32 KHMAPI +kcdb_buf_release(khm_handle record); + +/*@}*/ + +/********************************************************************/ + +/* Notification operation constants */ + +#define KCDB_OP_INSERT 1 +#define KCDB_OP_DELETE 2 +#define KCDB_OP_MODIFY 3 +#define KCDB_OP_ACTIVATE 4 +#define KCDB_OP_DEACTIVATE 5 +#define KCDB_OP_HIDE 6 +#define KCDB_OP_UNHIDE 7 +#define KCDB_OP_SETSEARCH 8 +#define KCDB_OP_UNSETSEARCH 9 +#define KCDB_OP_NEW_DEFAULT 10 +#define KCDB_OP_DELCONFIG 11 + +/*@}*/ + +#endif diff --git a/src/windows/identity/kcreddb/kcreddbinternal.h b/src/windows/identity/kcreddb/kcreddbinternal.h index f7bf4e7bd..2b80d1832 100644 --- a/src/windows/identity/kcreddb/kcreddbinternal.h +++ b/src/windows/identity/kcreddb/kcreddbinternal.h @@ -1,61 +1,61 @@ -/* - * 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_KCREDDBINTERNAL_H__ -#define __KHIMAIRA_KCREDDBINTERNAL_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "buf.h" -#include "identity.h" -#include "attrib.h" -#include "type.h" -#include "credential.h" -#include "credset.h" -#include "credtype.h" - -/* globals */ - -extern HINSTANCE hinst_kcreddb; - -kconf_schema schema_kcdbconfig[]; - -void kcdb_init(void); -void kcdb_exit(void); -khm_handle kcdb_get_config(void); - - -#endif +/* + * 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_KCREDDBINTERNAL_H__ +#define __KHIMAIRA_KCREDDBINTERNAL_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "buf.h" +#include "identity.h" +#include "attrib.h" +#include "type.h" +#include "credential.h" +#include "credset.h" +#include "credtype.h" + +/* globals */ + +extern HINSTANCE hinst_kcreddb; + +kconf_schema schema_kcdbconfig[]; + +void kcdb_init(void); +void kcdb_exit(void); +khm_handle kcdb_get_config(void); + + +#endif diff --git a/src/windows/identity/kcreddb/kcreddbmain.c b/src/windows/identity/kcreddb/kcreddbmain.c index 8f8a01b06..7702368ce 100644 --- a/src/windows/identity/kcreddb/kcreddbmain.c +++ b/src/windows/identity/kcreddb/kcreddbmain.c @@ -1,40 +1,40 @@ -/* - * 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 - -HINSTANCE hinst_kcreddb; - -void -kcdb_process_attach(HINSTANCE hinstDLL) { - hinst_kcreddb = hinstDLL; - kcdb_init(); -} - -void -kcdb_process_detach(void) { - kcdb_exit(); -} +/* + * 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 + +HINSTANCE hinst_kcreddb; + +void +kcdb_process_attach(HINSTANCE hinstDLL) { + hinst_kcreddb = hinstDLL; + kcdb_init(); +} + +void +kcdb_process_detach(void) { + kcdb_exit(); +} diff --git a/src/windows/identity/kcreddb/langres.h b/src/windows/identity/kcreddb/langres.h index 417b214e0..1c3258b3d 100644 --- a/src/windows/identity/kcreddb/langres.h +++ b/src/windows/identity/kcreddb/langres.h @@ -1,48 +1,48 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by D:\work\pismere\athena\auth\krb5\src\windows\identity\kcreddb\lang\en_us\kcredres.rc -// -#define IDS_CREDDB 101 -#define IDS_NAME 102 -#define IDS_IDENTITY 103 -#define IDS_ISSUED 104 -#define IDS_EXPIRES 105 -#define IDS_TIMELEFT 106 -#define IDS_LOCATION 107 -#define IDS_PARENT 108 -#define IDS_TYPE 109 -#define IDS_IVL_EXPIRED 110 -#define IDS_IVL_D_H 111 -#define IDS_IVL_H_M 112 -#define IDS_IVL_M_S 113 -#define IDS_IVL_S 114 -#define IDS_IVL_UNKNOWN 115 -#define IDS_LIFETIME 116 -#define IDS_IVL_1D 117 -#define IDS_IVL_1H 118 -#define IDS_IVL_1M 119 -#define IDS_IVL_1S 120 -#define IDS_IVL_D 121 -#define IDS_IVL_H 122 -#define IDS_IVL_M 123 -#define IDS_IVL_S_SPEC 124 -#define IDS_IVL_M_SPEC 125 -#define IDS_IVL_H_SPEC 126 -#define IDS_IVL_D_SPEC 127 -#define IDS_IVl_W_SPEC 128 -#define IDS_IVL_W_SPEC 128 -#define IDS_FLAGS 129 -#define IDS_RENEW_TIMELEFT 130 -#define IDS_RENEW_EXPIRES 131 -#define IDS_RENEW_LIFETIME 132 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by D:\work\pismere\athena\auth\krb5\src\windows\identity\kcreddb\lang\en_us\kcredres.rc +// +#define IDS_CREDDB 101 +#define IDS_NAME 102 +#define IDS_IDENTITY 103 +#define IDS_ISSUED 104 +#define IDS_EXPIRES 105 +#define IDS_TIMELEFT 106 +#define IDS_LOCATION 107 +#define IDS_PARENT 108 +#define IDS_TYPE 109 +#define IDS_IVL_EXPIRED 110 +#define IDS_IVL_D_H 111 +#define IDS_IVL_H_M 112 +#define IDS_IVL_M_S 113 +#define IDS_IVL_S 114 +#define IDS_IVL_UNKNOWN 115 +#define IDS_LIFETIME 116 +#define IDS_IVL_1D 117 +#define IDS_IVL_1H 118 +#define IDS_IVL_1M 119 +#define IDS_IVL_1S 120 +#define IDS_IVL_D 121 +#define IDS_IVL_H 122 +#define IDS_IVL_M 123 +#define IDS_IVL_S_SPEC 124 +#define IDS_IVL_M_SPEC 125 +#define IDS_IVL_H_SPEC 126 +#define IDS_IVL_D_SPEC 127 +#define IDS_IVl_W_SPEC 128 +#define IDS_IVL_W_SPEC 128 +#define IDS_FLAGS 129 +#define IDS_RENEW_TIMELEFT 130 +#define IDS_RENEW_EXPIRES 131 +#define IDS_RENEW_LIFETIME 132 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/windows/identity/kcreddb/resource.h b/src/windows/identity/kcreddb/resource.h index dfb47e0d4..bc587b278 100644 --- a/src/windows/identity/kcreddb/resource.h +++ b/src/windows/identity/kcreddb/resource.h @@ -1,27 +1,27 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by kcreddb.rc -// -#define IDS_PROJNAME 100 -#define IDR_WMDMLOGGER 101 -#define IDS_LOG_SEV_INFO 201 -#define IDS_LOG_SEV_WARN 202 -#define IDS_LOG_SEV_ERROR 203 -#define IDS_LOG_DATETIME 204 -#define IDS_LOG_SRCNAME 205 -#define IDS_DEF_LOGFILE 301 -#define IDS_DEF_MAXSIZE 302 -#define IDS_DEF_SHRINKTOSIZE 303 -#define IDS_DEF_LOGENABLED 304 -#define IDS_MUTEX_TIMEOUT 401 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 201 -#define _APS_NEXT_COMMAND_VALUE 32768 -#define _APS_NEXT_CONTROL_VALUE 201 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by kcreddb.rc +// +#define IDS_PROJNAME 100 +#define IDR_WMDMLOGGER 101 +#define IDS_LOG_SEV_INFO 201 +#define IDS_LOG_SEV_WARN 202 +#define IDS_LOG_SEV_ERROR 203 +#define IDS_LOG_DATETIME 204 +#define IDS_LOG_SRCNAME 205 +#define IDS_DEF_LOGFILE 301 +#define IDS_DEF_MAXSIZE 302 +#define IDS_DEF_SHRINKTOSIZE 303 +#define IDS_DEF_LOGENABLED 304 +#define IDS_MUTEX_TIMEOUT 401 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 201 +#define _APS_NEXT_COMMAND_VALUE 32768 +#define _APS_NEXT_CONTROL_VALUE 201 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/windows/identity/kcreddb/type.c b/src/windows/identity/kcreddb/type.c index 48630b5fd..e4fd2df2c 100644 --- a/src/windows/identity/kcreddb/type.c +++ b/src/windows/identity/kcreddb/type.c @@ -1,1386 +1,1386 @@ -/* - * 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 - -CRITICAL_SECTION cs_type; -hashtable * kcdb_type_namemap; -kcdb_type_i ** kcdb_type_tbl; -kcdb_type_i * kcdb_types = NULL; - -/* Void */ - -#define GENERIC_VOID_STR L"(Void)" - -khm_int32 KHMAPI kcdb_type_void_toString( - const void * d, - khm_size cbd, - wchar_t * buffer, - khm_size * cb_buf, - khm_int32 flags) -{ - size_t cbsize; - - if(!cb_buf) - return KHM_ERROR_INVALID_PARAM; - - cbsize = sizeof(GENERIC_VOID_STR); - - if(!buffer || *cb_buf < cbsize) { - *cb_buf = cbsize; - return KHM_ERROR_TOO_LONG; - } - - StringCbCopy(buffer, *cb_buf, GENERIC_VOID_STR); - - *cb_buf = cbsize; - - return KHM_ERROR_SUCCESS; -} - -khm_boolean KHMAPI kcdb_type_void_isValid( - const void * d, - khm_size cbd) -{ - /* void is always valid, even if d is NULL */ - return TRUE; -} - -khm_int32 KHMAPI kcdb_type_void_comp( - const void * d1, - khm_size cbd1, - const void * d2, - khm_size cbd2) -{ - /* voids can not be compared */ - return 0; -} - -khm_int32 KHMAPI kcdb_type_void_dup( - const void * d_src, - khm_size cbd_src, - void * d_dst, - khm_size * cbd_dst) -{ - if(!cbd_dst) - return KHM_ERROR_INVALID_PARAM; - - *cbd_dst = 0; - - /* copying a void doesn't do much */ - return KHM_ERROR_SUCCESS; -} - - -/* String */ -khm_int32 KHMAPI kcdb_type_string_toString( - const void * d, - khm_size cbd, - wchar_t * buffer, - khm_size * cb_buf, - khm_int32 flags) -{ - size_t cbsize; - wchar_t * sd; - - if(!cb_buf) - return KHM_ERROR_INVALID_PARAM; - - sd = (wchar_t *) d; - - if(FAILED(StringCbLength(sd, KCDB_TYPE_MAXCB, &cbsize))) - return KHM_ERROR_INVALID_PARAM; - - cbsize += sizeof(wchar_t); - - if(!buffer || *cb_buf < cbsize) { - *cb_buf = cbsize; - return KHM_ERROR_TOO_LONG; - } - - StringCbCopy(buffer, *cb_buf, sd); - - *cb_buf = cbsize; - - return KHM_ERROR_SUCCESS; -} - -khm_boolean KHMAPI kcdb_type_string_isValid( - const void * d, - khm_size cbd) -{ - size_t cbsize; - - if(cbd == KCDB_CBSIZE_AUTO) - cbd = KCDB_TYPE_MAXCB; - - if(FAILED(StringCbLength((wchar_t *) d, cbd, &cbsize))) - return FALSE; - else - return TRUE; -} - -khm_int32 KHMAPI kcdb_type_string_comp( - const void * d1, - khm_size cbd1, - const void * d2, - khm_size cbd2) -{ - return wcscmp((const wchar_t *) d1, (const wchar_t *) d2); -} - -khm_int32 KHMAPI kcdb_type_string_dup( - const void * d_src, - khm_size cbd_src, - void * d_dst, - khm_size * cbd_dst) -{ - size_t cbsize; - - if(!cbd_dst) - return KHM_ERROR_INVALID_PARAM; - - if(cbd_src == KCDB_CBSIZE_AUTO) { - cbd_src = KCDB_TYPE_MAXCB; - } - - if(FAILED(StringCbLength((const wchar_t *) d_src, cbd_src, &cbsize))) { - return KHM_ERROR_UNKNOWN; - } - - cbsize += sizeof(wchar_t); - - if(!d_dst || *cbd_dst < cbsize) { - *cbd_dst = cbsize; - return KHM_ERROR_TOO_LONG; - } - - StringCbCopy((wchar_t *) d_dst, *cbd_dst, (const wchar_t *) d_src); - *cbd_dst = cbsize; - - return KHM_ERROR_SUCCESS; -} - -/* Date and time */ - - -khm_int32 KHMAPI kcdb_type_date_toString( - const void * d, - khm_size cbd, - wchar_t * buffer, - khm_size * cb_buf, - khm_int32 flags) -{ - size_t cbsize; - size_t cchsize; - wchar_t * bufend; - SYSTEMTIME st_now; - SYSTEMTIME st_d; - SYSTEMTIME st_dl; - FILETIME *ft; - int today = 0; - - if(!cb_buf) - return KHM_ERROR_INVALID_PARAM; - - ft = (FILETIME *) d; - - GetLocalTime(&st_now); - FileTimeToSystemTime(ft, &st_d); - SystemTimeToTzSpecificLocalTime(NULL, &st_d, &st_dl); - if (st_now.wYear == st_dl.wYear && - st_now.wMonth == st_dl.wMonth && - st_now.wDay == st_dl.wDay) - today = 1; - - if(today && (flags & KCDB_TS_SHORT)) { - cbsize = 0; - } else { - cbsize = GetDateFormat( - LOCALE_USER_DEFAULT, - DATE_SHORTDATE, - &st_dl, - NULL, - NULL, - 0) * sizeof(wchar_t); - } - - cbsize += GetTimeFormat( - LOCALE_USER_DEFAULT, - 0, - &st_dl, - NULL, - NULL, - 0) * sizeof(wchar_t); - - if(!buffer || *cb_buf < cbsize) { - *cb_buf = cbsize; - return KHM_ERROR_TOO_LONG; - } - - cchsize = cbsize / sizeof(wchar_t); - - if(!today || !(flags & KCDB_TS_SHORT)) { - size_t cch_buf_len; - - GetDateFormat( - LOCALE_USER_DEFAULT, - DATE_SHORTDATE, - &st_dl, - NULL, - buffer, - (int) cchsize); - - StringCchCat(buffer, cchsize, L" "); - - StringCchLength(buffer, cchsize, &cch_buf_len); - - bufend = buffer + cch_buf_len; - cchsize -= cch_buf_len; - } else { - bufend = buffer; - } - - GetTimeFormat( - LOCALE_USER_DEFAULT, - 0, - &st_dl, - NULL, - bufend, - (int) cchsize); - - *cb_buf = cbsize; - - return KHM_ERROR_SUCCESS; -} - -khm_boolean KHMAPI kcdb_type_date_isValid( - const void * d, - khm_size cbd) -{ - return (d && (cbd == KCDB_CBSIZE_AUTO || cbd == sizeof(FILETIME))); -} - -khm_int32 KHMAPI kcdb_type_date_comp( - const void * d1, - khm_size cbd1, - const void * d2, - khm_size cbd2) -{ - return (khm_int32) CompareFileTime((CONST FILETIME *) d1, (CONST FILETIME *) d2); -} - -khm_int32 KHMAPI kcdb_type_date_dup( - const void * d_src, - khm_size cbd_src, - void * d_dst, - khm_size * cbd_dst) -{ - if(d_dst && *cbd_dst >= sizeof(FILETIME)) { - *cbd_dst = sizeof(FILETIME); - *((FILETIME *) d_dst) = *((FILETIME *) d_src); - return KHM_ERROR_SUCCESS; - } else { - *cbd_dst = sizeof(FILETIME); - return KHM_ERROR_TOO_LONG; - } -} - -/* Interval */ - -/* returns the number of milliseconds that must elapse away from the - interval specified in pft for the representation of pft to change - from whatever it is right now */ -KHMEXP long KHMAPI -FtIntervalMsToRepChange(LPFILETIME pft) -{ - __int64 ms,s,m,h,d; - __int64 ift; - long l; - - ift = FtToInt(pft); - ms = ift / 10000i64; - - if(ms < 0 || ift == _I64_MAX) - return -1; - - s = ms / 1000i64; - m = s / 60; - h = s / 3600; - d = s / (3600*24); - - if (d > 0) { - /* rep change at next hour change */ - l = (long) (ms % (3600*1000i64)); - } else if (h > 0) { - /* rep change at next minute change */ - l = (long) (ms % (60*1000i64)); - } else if (m > 5) { - /* rep change at next minute change */ - l = (long) (ms % (60*1000i64)); - } else { - /* rep change at next second change */ - l = (long) (ms % 1000); - } - - return l; -} - -KHMEXP khm_int32 KHMAPI -FtIntervalToString(LPFILETIME data, wchar_t * buffer, khm_size * cb_buf) -{ - size_t cbsize; - __int64 s,m,h,d; - __int64 ift; - wchar_t ibuf[256]; - wchar_t fbuf[256]; - wchar_t * t; - - if(!cb_buf) - return KHM_ERROR_INVALID_PARAM; - - ift = FtToInt(data); - s = ift / 10000000i64; - - m = s / 60; - h = s / 3600; - 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) { - h = (s - (d * 3600 * 24)) / 3600; - if(d == 1) { - LoadString(hinst_kcreddb, IDS_IVL_1D, ibuf, ARRAYLENGTH(ibuf)); - } else { - LoadString(hinst_kcreddb, IDS_IVL_D, fbuf, ARRAYLENGTH(fbuf)); - StringCbPrintf(ibuf, sizeof(ibuf), fbuf, d); - } - if(h > 0) { - StringCbCat(ibuf, sizeof(ibuf), L" "); - t = ibuf + wcslen(ibuf); - if(h == 1) - { - LoadString(hinst_kcreddb, IDS_IVL_1H, t, - (int) (ARRAYLENGTH(ibuf) - wcslen(ibuf))); - } else { - LoadString(hinst_kcreddb, IDS_IVL_H, fbuf, - (int) ARRAYLENGTH(fbuf)); - StringCbPrintf(t, sizeof(ibuf) - wcslen(ibuf)*sizeof(wchar_t), fbuf, h); - } - } - } else if(h > 0 || m > 5) { - m = (s - (h * 3600)) / 60; - if(h == 1) { - LoadString(hinst_kcreddb, IDS_IVL_1H, ibuf, ARRAYLENGTH(ibuf)); - } else if (h > 1) { - LoadString(hinst_kcreddb, IDS_IVL_H, fbuf, ARRAYLENGTH(fbuf)); - StringCbPrintf(ibuf, sizeof(ibuf), fbuf, h); - } else { - *ibuf = L'\0'; - } - - if(m > 0 || h == 0) { - if (h >= 1) - StringCbCat(ibuf, sizeof(ibuf), L" "); - - t = ibuf + wcslen(ibuf); - if(m == 1) - { - LoadString(hinst_kcreddb, IDS_IVL_1M, t, - (int) (ARRAYLENGTH(ibuf) - wcslen(ibuf))); - } else { - LoadString(hinst_kcreddb, IDS_IVL_M, fbuf, - (int) ARRAYLENGTH(fbuf)); - StringCbPrintf(t, sizeof(ibuf) - wcslen(ibuf)*sizeof(wchar_t), fbuf, m); - } - } - } else if(m > 0) { - s -= m * 60; - if(m == 1) { - LoadString(hinst_kcreddb, IDS_IVL_1M, ibuf, ARRAYLENGTH(ibuf)); - } else { - LoadString(hinst_kcreddb, IDS_IVL_M, fbuf, ARRAYLENGTH(fbuf)); - StringCbPrintf(ibuf, sizeof(ibuf), fbuf, m); - } - if(s > 0) { - StringCbCat(ibuf, sizeof(ibuf), L" "); - t = ibuf + wcslen(ibuf); - if(s == 1) - { - LoadString(hinst_kcreddb, IDS_IVL_1S, t, - (int) (ARRAYLENGTH(ibuf) - wcslen(ibuf))); - } else { - LoadString(hinst_kcreddb, IDS_IVL_S, fbuf, - (int) ARRAYLENGTH(fbuf)); - StringCbPrintf(t, sizeof(ibuf) - wcslen(ibuf)*sizeof(wchar_t), fbuf, s); - } - } - } else { - if(s == 1) { - LoadString(hinst_kcreddb, IDS_IVL_1S, ibuf, ARRAYLENGTH(ibuf)); - } else { - LoadString(hinst_kcreddb, IDS_IVL_S, fbuf, sizeof(fbuf)/sizeof(wchar_t)); - StringCbPrintf(ibuf, sizeof(ibuf), fbuf, s); - } - } - - StringCbLength(ibuf, sizeof(ibuf), &cbsize); - cbsize += sizeof(wchar_t); - - if(!buffer || *cb_buf < cbsize) { - *cb_buf = cbsize; - return KHM_ERROR_TOO_LONG; - } - - StringCbCopy(buffer, *cb_buf, ibuf); - *cb_buf = cbsize; - - return KHM_ERROR_SUCCESS; -} - -khm_int32 KHMAPI -kcdb_type_interval_toString(const void * data, - khm_size cbd, - wchar_t * buffer, - khm_size * cb_buf, - khm_int32 flags) -{ - return FtIntervalToString((LPFILETIME) data, buffer, cb_buf); -} - -khm_boolean KHMAPI kcdb_type_interval_isValid( - const void * d, - khm_size cbd) -{ - return (d && (cbd == sizeof(FILETIME) || cbd == KCDB_CBSIZE_AUTO)); -} - -khm_int32 KHMAPI kcdb_type_interval_comp( - const void * d1, - khm_size cbd1, - const void * d2, - khm_size cbd2) -{ - __int64 i1, i2; - - i1 = FtToInt((FILETIME *) d1); - i2 = FtToInt((FILETIME *) d2); - - if(i1 < i2) - return -1; - else if(i1 > i2) - return 1; - else - return 0; -} - -khm_int32 KHMAPI kcdb_type_interval_dup( - const void * d_src, - khm_size cbd_src, - void * d_dst, - khm_size * cbd_dst) -{ - if(d_dst && *cbd_dst >= sizeof(FILETIME)) { - *cbd_dst = sizeof(FILETIME); - *((FILETIME *) d_dst) = *((FILETIME *) d_src); - return KHM_ERROR_SUCCESS; - } else { - *cbd_dst = sizeof(FILETIME); - return KHM_ERROR_TOO_LONG; - } -} - -/* Int32 */ - -khm_int32 KHMAPI kcdb_type_int32_toString( - const void * d, - khm_size cbd, - wchar_t * buffer, - khm_size * cb_buf, - khm_int32 flags) -{ - size_t cbsize; - wchar_t ibuf[12]; - - if(!cb_buf) - return KHM_ERROR_INVALID_PARAM; - - StringCbPrintf(ibuf, sizeof(ibuf), L"%d", *((khm_int32 *) d)); - StringCbLength(ibuf, sizeof(ibuf), &cbsize); - cbsize += sizeof(wchar_t); - - if(!buffer || *cb_buf < cbsize) { - *cb_buf = cbsize; - return KHM_ERROR_TOO_LONG; - } - - StringCbCopy((wchar_t *) buffer, *cb_buf, ibuf); - *cb_buf = cbsize; - - return KHM_ERROR_SUCCESS; -} - -khm_boolean KHMAPI kcdb_type_int32_isValid( - const void * d, - khm_size cbd) -{ - return (d && (cbd == KCDB_CBSIZE_AUTO || cbd == sizeof(khm_int32))); -} - -khm_int32 KHMAPI kcdb_type_int32_comp( - const void * d1, - khm_size cbd1, - const void * d2, - khm_size cbd2) -{ - return *((khm_int32 *) d1) - *((khm_int32 *) d2); -} - -khm_int32 KHMAPI kcdb_type_int32_dup( - const void * d_src, - khm_size cbd_src, - void * d_dst, - khm_size * cbd_dst) -{ - if(d_dst && (*cbd_dst >= sizeof(khm_int32))) { - *cbd_dst = sizeof(khm_int32); - *((khm_int32 *) d_dst) = *((khm_int32 *) d_src); - return KHM_ERROR_SUCCESS; - } else { - *cbd_dst = sizeof(khm_int32); - return KHM_ERROR_TOO_LONG; - } -} - -/* Int64 */ - -khm_int32 KHMAPI kcdb_type_int64_toString( - const void * d, - khm_size cbd, - wchar_t * buffer, - khm_size * cb_buf, - khm_int32 flags) -{ - size_t cbsize; - wchar_t ibuf[22]; - - if(!cb_buf) - return KHM_ERROR_INVALID_PARAM; - - StringCbPrintf(ibuf, sizeof(ibuf), L"%I64d", *((__int64 *) d)); - StringCbLength(ibuf, sizeof(ibuf), &cbsize); - cbsize += sizeof(wchar_t); - - if(!buffer || *cb_buf < cbsize) { - *cb_buf = cbsize; - return KHM_ERROR_TOO_LONG; - } - - StringCbCopy((wchar_t *) buffer, *cb_buf, ibuf); - *cb_buf = cbsize; - - return KHM_ERROR_SUCCESS; -} - -khm_boolean KHMAPI kcdb_type_int64_isValid( - const void * d, - khm_size cbd) -{ - return (d && (cbd == KCDB_CBSIZE_AUTO || cbd == sizeof(__int64))); -} - -khm_int32 KHMAPI kcdb_type_int64_comp( - const void * d1, - khm_size cbd1, - const void * d2, - khm_size cbd2) -{ - __int64 r = *((__int64 *) d1) - *((__int64 *) d2); - return (r==0i64)?0:((r>0i64)?1:-1); -} - -khm_int32 KHMAPI kcdb_type_int64_dup( - const void * d_src, - khm_size cbd_src, - void * d_dst, - khm_size * cbd_dst) -{ - if(d_dst && (*cbd_dst >= sizeof(__int64))) { - *cbd_dst = sizeof(__int64); - *((__int64 *) d_dst) = *((__int64 *) d_src); - return KHM_ERROR_SUCCESS; - } else { - *cbd_dst = sizeof(__int64); - return KHM_ERROR_TOO_LONG; - } -} - -/* Data */ -#define GENERIC_DATA_STR L"(Data)" - -khm_int32 KHMAPI kcdb_type_data_toString( - const void * d, - khm_size cbd, - wchar_t * buffer, - khm_size * cb_buf, - khm_int32 flags) -{ - size_t cbsize; - - if(!cb_buf) - return KHM_ERROR_INVALID_PARAM; - - cbsize = sizeof(GENERIC_DATA_STR); - - if(!buffer || *cb_buf < cbsize) { - *cb_buf = cbsize; - return KHM_ERROR_TOO_LONG; - } - - StringCbCopy(buffer, *cb_buf, GENERIC_DATA_STR); - - *cb_buf = cbsize; - - return KHM_ERROR_SUCCESS; -} - -khm_boolean KHMAPI kcdb_type_data_isValid( - const void * d, - khm_size cbd) -{ - /* data is always valid */ - if (cbd != 0 && d == NULL) - return FALSE; - else - return TRUE; -} - -khm_int32 KHMAPI kcdb_type_data_comp( - const void * d1, - khm_size cbd1, - const void * d2, - khm_size cbd2) -{ - khm_size pref; - khm_int32 rv = 0; - - pref = min(cbd1, cbd2); - - if (pref == 0) - return (cbd1 < cbd2)? -1 : ((cbd1 > cbd2)? 1 : 0); - - rv = memcmp(d1, d2, pref); - - if (rv == 0) { - return (cbd1 < cbd2)? -1 : ((cbd1 > cbd2)? 1 : 0); - } else { - return rv; - } -} - -khm_int32 KHMAPI kcdb_type_data_dup( - const void * d_src, - khm_size cbd_src, - void * d_dst, - khm_size * cbd_dst) -{ - if(!cbd_dst || cbd_src == KCDB_CBSIZE_AUTO) - return KHM_ERROR_INVALID_PARAM; - - if(!d_dst || *cbd_dst < cbd_src) { - *cbd_dst = cbd_src; - return KHM_ERROR_TOO_LONG; - } else { - *cbd_dst = cbd_src; - memcpy(d_dst, d_src, cbd_src); - return KHM_ERROR_SUCCESS; - } -} - - -void kcdb_type_msg_completion(kmq_message * m) -{ - kcdb_type_release((kcdb_type_i *) m->vparam); -} - -void kcdb_type_post_message(khm_int32 op, kcdb_type_i * t) -{ - kcdb_type_hold(t); - kmq_post_message(KMSG_KCDB, KMSG_KCDB_TYPE, op, (void *) t); -} - -void kcdb_type_init(void) -{ - kcdb_type type; - - InitializeCriticalSection(&cs_type); - kcdb_type_namemap = hash_new_hashtable( - KCDB_TYPE_HASH_SIZE, - hash_string, - hash_string_comp, - kcdb_type_add_ref, - kcdb_type_del_ref); - kcdb_type_tbl = PMALLOC(sizeof(kcdb_type_i *) * (KCDB_TYPE_MAX_ID + 1)); - ZeroMemory(kcdb_type_tbl, sizeof(kcdb_type_i *) * (KCDB_TYPE_MAX_ID + 1)); - kcdb_types = NULL; - - /*TODO: register standard data types */ - - ZeroMemory(&type, sizeof(type)); - type.comp = kcdb_type_void_comp; - type.dup = kcdb_type_void_dup; - type.isValid = kcdb_type_void_isValid; - type.toString = kcdb_type_void_toString; - type.name = KCDB_TYPENAME_VOID; - type.id = KCDB_TYPE_VOID; - - kcdb_type_register(&type, NULL); - - ZeroMemory(&type, sizeof(type)); - type.comp = kcdb_type_string_comp; - type.dup = kcdb_type_string_dup; - type.isValid = kcdb_type_string_isValid; - type.toString = kcdb_type_string_toString; - type.name = KCDB_TYPENAME_STRING; - type.id = KCDB_TYPE_STRING; - type.flags = KCDB_TYPE_FLAG_CB_AUTO; - - kcdb_type_register(&type, NULL); - - ZeroMemory(&type, sizeof(type)); - type.comp = kcdb_type_date_comp; - type.dup = kcdb_type_date_dup; - type.isValid = kcdb_type_date_isValid; - type.toString = kcdb_type_date_toString; - type.name = KCDB_TYPENAME_DATE; - type.id = KCDB_TYPE_DATE; - type.cb_max = sizeof(FILETIME); - type.cb_min = sizeof(FILETIME); - type.flags = KCDB_TYPE_FLAG_CB_FIXED; - - kcdb_type_register(&type, NULL); - - ZeroMemory(&type, sizeof(type)); - type.comp = kcdb_type_interval_comp; - type.dup = kcdb_type_interval_dup; - type.isValid = kcdb_type_interval_isValid; - type.toString = kcdb_type_interval_toString; - type.name = KCDB_TYPENAME_INTERVAL; - type.id = KCDB_TYPE_INTERVAL; - type.cb_max = sizeof(FILETIME); - type.cb_min = sizeof(FILETIME); - type.flags = KCDB_TYPE_FLAG_CB_FIXED; - - kcdb_type_register(&type, NULL); - - ZeroMemory(&type, sizeof(type)); - type.comp = kcdb_type_int32_comp; - type.dup = kcdb_type_int32_dup; - type.isValid = kcdb_type_int32_isValid; - type.toString = kcdb_type_int32_toString; - type.name = KCDB_TYPENAME_INT32; - type.id = KCDB_TYPE_INT32; - type.cb_max = sizeof(khm_int32); - type.cb_min = sizeof(khm_int32); - type.flags = KCDB_TYPE_FLAG_CB_FIXED; - - kcdb_type_register(&type, NULL); - - ZeroMemory(&type, sizeof(type)); - type.comp = kcdb_type_int64_comp; - type.dup = kcdb_type_int64_dup; - type.isValid = kcdb_type_int64_isValid; - type.toString = kcdb_type_int64_toString; - type.name = KCDB_TYPENAME_INT64; - type.id = KCDB_TYPE_INT64; - type.cb_max = sizeof(__int64); - type.cb_min = sizeof(__int64); - type.flags = KCDB_TYPE_FLAG_CB_FIXED; - - kcdb_type_register(&type, NULL); - - ZeroMemory(&type, sizeof(type)); - type.comp = kcdb_type_data_comp; - type.dup = kcdb_type_data_dup; - type.isValid = kcdb_type_data_isValid; - type.toString = kcdb_type_data_toString; - type.name = KCDB_TYPENAME_DATA; - type.id = KCDB_TYPE_DATA; - - kcdb_type_register(&type, NULL); -} - -void kcdb_type_add_ref(const void *key, void *vt) -{ - kcdb_type_hold((kcdb_type_i *) vt); -} - -void kcdb_type_del_ref(const void *key, void *vt) -{ - kcdb_type_release((kcdb_type_i *) vt); -} - -khm_int32 kcdb_type_hold(kcdb_type_i * t) -{ - if(!t) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_type); - t->refcount++; - LeaveCriticalSection(&cs_type); - - return KHM_ERROR_SUCCESS; -} - -khm_int32 kcdb_type_release(kcdb_type_i * t) -{ - if(!t) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_type); - t->refcount--; - kcdb_type_check_and_delete(t->type.id); - LeaveCriticalSection(&cs_type); - - return KHM_ERROR_SUCCESS; -} - -void kcdb_type_exit(void) -{ - EnterCriticalSection(&cs_type); - PFREE(kcdb_type_tbl); - /*TODO: free up the individual types */ - LeaveCriticalSection(&cs_type); - DeleteCriticalSection(&cs_type); -} - -void kcdb_type_check_and_delete(khm_int32 id) -{ - kcdb_type_i * t; - - if(id < 0 || id > KCDB_TYPE_MAX_ID) - return; - - EnterCriticalSection(&cs_type); - t = kcdb_type_tbl[id]; - if(t && !t->refcount) { - kcdb_type_tbl[id] = NULL; - LDELETE(&kcdb_types, t); - /* must already be out of the hash-table, otherwise refcount should not - be zero */ - PFREE(t->type.name); - PFREE(t); - } - LeaveCriticalSection(&cs_type); -} - -KHMEXP khm_int32 KHMAPI kcdb_type_get_id(const wchar_t *name, khm_int32 * id) -{ - kcdb_type_i * t; - size_t cbsize; - - if(FAILED(StringCbLength(name, KCDB_MAXCB_NAME, &cbsize))) { - /* also fails of name is NULL */ - return KHM_ERROR_INVALID_PARAM; - } - - EnterCriticalSection(&cs_type); - t = hash_lookup(kcdb_type_namemap, (void*) name); - LeaveCriticalSection(&cs_type); - - if(!t) { - *id = KCDB_TYPE_INVALID; - return KHM_ERROR_NOT_FOUND; - } else { - *id = t->type.id; - return KHM_ERROR_SUCCESS; - } -} - -KHMEXP khm_int32 KHMAPI kcdb_type_get_info(khm_int32 id, kcdb_type ** info) -{ - kcdb_type_i * t; - - if(id < 0 || id > KCDB_TYPE_MAX_ID) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_type); - t = kcdb_type_tbl[id]; - - if (t) - kcdb_type_hold(t); - LeaveCriticalSection(&cs_type); - - if(info) - *info = (kcdb_type *) t; - else if (t) - kcdb_type_release(t); - - return (t)? KHM_ERROR_SUCCESS : KHM_ERROR_NOT_FOUND; -} - -KHMEXP khm_int32 KHMAPI kcdb_type_release_info(kcdb_type * info) -{ - return kcdb_type_release((kcdb_type_i *) info); -} - -KHMEXP khm_int32 KHMAPI kcdb_type_get_name(khm_int32 id, wchar_t * buffer, khm_size * cbbuf) -{ - size_t cbsize; - kcdb_type_i * t; - - if(id < 0 || id > KCDB_TYPE_MAX_ID || !cbbuf) - return KHM_ERROR_INVALID_PARAM; - - t = kcdb_type_tbl[id]; - - if(!t) - return KHM_ERROR_NOT_FOUND; - - if(FAILED(StringCbLength(t->type.name, KCDB_MAXCB_NAME, &cbsize))) - return KHM_ERROR_UNKNOWN; - - cbsize += sizeof(wchar_t); - - if(!buffer || *cbbuf < cbsize) { - *cbbuf = cbsize; - return KHM_ERROR_TOO_LONG; - } - - StringCbCopy(buffer, *cbbuf, t->type.name); - *cbbuf = cbsize; - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI kcdb_type_register(const kcdb_type * type, khm_int32 * new_id) -{ - kcdb_type_i *t; - size_t cbsize; - khm_int32 type_id; - - if(!type || - !type->comp || - !type->dup || - !type->isValid || - !type->toString || - !type->name) - return KHM_ERROR_INVALID_PARAM; - - if((type->flags & KCDB_TYPE_FLAG_CB_MIN) && - (type->cb_min < 0 || type->cb_min > KCDB_TYPE_MAXCB)) - { - return KHM_ERROR_INVALID_PARAM; - } - - if((type->flags & KCDB_TYPE_FLAG_CB_MAX) && - (type->cb_max < 0 || type->cb_max > KCDB_TYPE_MAXCB)) - { - return KHM_ERROR_INVALID_PARAM; - } - - if((type->flags & KCDB_TYPE_FLAG_CB_MIN) && - (type->flags & KCDB_TYPE_FLAG_CB_MAX) && - (type->cb_max < type->cb_min)) - { - return KHM_ERROR_INVALID_PARAM; - } - - if(FAILED(StringCbLength(type->name, KCDB_MAXCB_NAME, &cbsize))) - return KHM_ERROR_TOO_LONG; - - cbsize += sizeof(wchar_t); - - EnterCriticalSection(&cs_type); - if(type->id == KCDB_TYPE_INVALID) { - kcdb_type_get_next_free(&type_id); - } else if(type->id < 0 || type->id > KCDB_TYPE_MAX_ID) { - LeaveCriticalSection(&cs_type); - return KHM_ERROR_INVALID_PARAM; - } else if(kcdb_type_tbl[type->id]) { - LeaveCriticalSection(&cs_type); - return KHM_ERROR_DUPLICATE; - } else { - type_id = type->id; - } - - if(type_id == KCDB_TYPE_INVALID) { - LeaveCriticalSection(&cs_type); - return KHM_ERROR_NO_RESOURCES; - } - - t = PMALLOC(sizeof(kcdb_type_i)); - ZeroMemory(t, sizeof(kcdb_type_i)); - - t->type.name = PMALLOC(cbsize); - StringCbCopy(t->type.name, cbsize, type->name); - - t->type.comp = type->comp; - t->type.dup = type->dup; - t->type.flags = type->flags; - t->type.id = type_id; - t->type.isValid = type->isValid; - t->type.toString = type->toString; - - LINIT(t); - - kcdb_type_tbl[type_id] = t; - LPUSH(&kcdb_types, t); - - hash_add(kcdb_type_namemap, (void *) t->type.name, (void *) t); - - LeaveCriticalSection(&cs_type); - - if(new_id) - *new_id = type_id; - - kcdb_type_post_message(KCDB_OP_INSERT, t); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI kcdb_type_unregister(khm_int32 id) -{ - kcdb_type_i * t; - - if(id < 0 || id > KCDB_TYPE_MAX_ID) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_type); - t = kcdb_type_tbl[id]; - if(t) { - kcdb_type_post_message(KCDB_OP_DELETE, t); - /* we are going to remove t from the hash table. If no one is holding - a reference to it, then we can free it (actually, the del_ref code - will take care of that anyway). If there is a hold, then it will - get freed when they release it. - - Actually, the post_message call above pretty much guarantees that - the type has a hold on it.*/ - t->type.flags |= KCDB_TYPE_FLAG_DELETED; - hash_del(kcdb_type_namemap, t->type.name); - } - LeaveCriticalSection(&cs_type); - - if(t) - return KHM_ERROR_SUCCESS; - else - return KHM_ERROR_NOT_FOUND; -} - -KHMEXP khm_int32 KHMAPI kcdb_type_get_next_free(khm_int32 * id) -{ - int i; - - if(!id) - return KHM_ERROR_INVALID_PARAM; - - /* do a linear search because this function only gets called a few times */ - EnterCriticalSection(&cs_type); - for(i=0; i <= KCDB_TYPE_MAX_ID; i++) { - if(!kcdb_type_tbl[i]) - break; - } - LeaveCriticalSection(&cs_type); - - if(i <= KCDB_TYPE_MAX_ID) { - *id = i; - return KHM_ERROR_SUCCESS; - } else { - *id = KCDB_TYPE_INVALID; - return KHM_ERROR_NO_RESOURCES; - } -} - -/* Conversion functions */ - -KHMEXP void KHMAPI TimetToFileTime( time_t t, LPFILETIME pft ) -{ - LONGLONG ll; - - if ( sizeof(time_t) == 4 ) - ll = Int32x32To64(t, 10000000) + 116444736000000000i64; - else { - ll = t * 10000000i64 + 116444736000000000i64; - } - pft->dwLowDateTime = (DWORD) ll; - pft->dwHighDateTime = (DWORD) (ll >> 32); -} - -KHMEXP void KHMAPI TimetToFileTimeInterval(time_t t, LPFILETIME pft) -{ - LONGLONG ll; - - if ( sizeof(time_t) == 4 ) - ll = Int32x32To64(t, 10000000); - else { - ll = t * 10000000i64; - } - pft->dwLowDateTime = (DWORD) ll; - pft->dwHighDateTime = (DWORD) (ll >> 32); -} - -KHMEXP long KHMAPI FtIntervalToSeconds(LPFILETIME pft) -{ - __int64 i = FtToInt(pft); - return (long) (i / 10000000i64); -} - -KHMEXP long KHMAPI FtIntervalToMilliseconds(LPFILETIME pft) -{ - __int64 i = FtToInt(pft); - return (long) (i / 10000i64); -} - -KHMEXP khm_int64 KHMAPI FtToInt(LPFILETIME pft) { - LARGE_INTEGER ll; - ll.LowPart = pft->dwLowDateTime; - ll.HighPart = pft->dwHighDateTime; - return ll.QuadPart; -} - -KHMEXP FILETIME KHMAPI IntToFt(khm_int64 i) { - LARGE_INTEGER ll; - FILETIME ft; - - ll.QuadPart = i; - ft.dwLowDateTime = ll.LowPart; - ft.dwHighDateTime = ll.HighPart; - - return ft; -} - -KHMEXP FILETIME KHMAPI FtSub(LPFILETIME ft1, LPFILETIME ft2) { - FILETIME d; - LARGE_INTEGER l1, l2; - - l1.LowPart = ft1->dwLowDateTime; - l1.HighPart = ft1->dwHighDateTime; - l2.LowPart = ft2->dwLowDateTime; - l2.HighPart = ft2->dwHighDateTime; - - l1.QuadPart -= l2.QuadPart; - - d.dwLowDateTime = l1.LowPart; - d.dwHighDateTime = l1.HighPart; - - return d; -} - -KHMEXP FILETIME KHMAPI FtAdd(LPFILETIME ft1, LPFILETIME ft2) { - FILETIME d; - LARGE_INTEGER l1, l2; - - l1.LowPart = ft1->dwLowDateTime; - l1.HighPart = ft1->dwHighDateTime; - l2.LowPart = ft2->dwLowDateTime; - l2.HighPart = ft2->dwHighDateTime; - - l1.QuadPart += l2.QuadPart; - - d.dwLowDateTime = l1.LowPart; - d.dwHighDateTime = l1.HighPart; - - return d; -} - -KHMEXP int KHMAPI AnsiStrToUnicode( wchar_t * wstr, size_t cbwstr, const char * astr) -{ - size_t nc; - - if(cbwstr == 0) - return 0; - - nc = strlen(astr); - if(nc == MultiByteToWideChar( - CP_ACP, - 0, - astr, - (int) nc, - wstr, - (int)(cbwstr / sizeof(wchar_t) - 1))) { - wstr[nc] = L'\0'; - } else { - wstr[0] = L'\0'; - nc = 0; - } - - return (int) nc; -} - -KHMEXP int KHMAPI UnicodeStrToAnsi( char * dest, size_t cbdest, const wchar_t * src) -{ - size_t nc; - - if(cbdest == 0) - return 0; - - dest[0] = 0; - - if(FAILED(StringCchLength(src, cbdest, &nc)) || nc*sizeof(char) >= cbdest) - // note that cbdest counts the terminating NULL, while nc doesn't - return 0; - - nc = WideCharToMultiByte( - CP_ACP, - WC_NO_BEST_FIT_CHARS, - src, - (int) nc, - dest, - (int) cbdest, - NULL, - NULL); - - dest[nc] = 0; - - return (int) nc; -} - -#define MAX_IVL_SPECLIST_LEN 256 -#define MAX_IVL_UNITS 5 - -enum _ivl_indices { - IVL_SECONDS = 0, - IVL_MINUTES, - IVL_HOURS, - IVL_DAYS, - IVL_WEEKS -}; - -typedef struct ivspec_t { - wchar_t str[MAX_IVL_SPECLIST_LEN]; - __int64 mul; -} ivspec; - -static ivspec ivspecs[MAX_IVL_UNITS]; -static BOOL ivspecs_loaded = FALSE; - -int _iv_is_in_spec(wchar_t *s, int n, wchar_t * spec) -{ - /* spec strigns are comma separated */ - wchar_t *b, *e; - - b = spec; - while(*b) { - e = wcschr(b, L','); - if(!e) - e = b + wcslen(b); - - if((e - b) == n && !_wcsnicmp(b, s, n)) { - return TRUE; - } - - if(*e) - b = e+1; - else - break; - } - - return FALSE; -} - -KHMEXP khm_int32 KHMAPI IntervalStringToFt(FILETIME * pft, wchar_t * str) -{ - size_t cb; - wchar_t * b; - __int64 t; - - *pft = IntToFt(0); - - /* ideally we should synchronize this, but it doesn't hurt if two - threads do this at the same time, because we only set the ivspecs_loaded - flag when we are done */ - if(!ivspecs_loaded) { - LoadString(hinst_kcreddb, IDS_IVL_S_SPEC, ivspecs[IVL_SECONDS].str, MAX_IVL_SPECLIST_LEN); - ivspecs[IVL_SECONDS].mul = 10000000i64; - LoadString(hinst_kcreddb, IDS_IVL_M_SPEC, ivspecs[IVL_MINUTES].str, MAX_IVL_SPECLIST_LEN); - ivspecs[IVL_MINUTES].mul = ivspecs[IVL_SECONDS].mul * 60; - LoadString(hinst_kcreddb, IDS_IVL_H_SPEC, ivspecs[2].str, MAX_IVL_SPECLIST_LEN); - ivspecs[IVL_HOURS].mul = ivspecs[IVL_MINUTES].mul * 60; - LoadString(hinst_kcreddb, IDS_IVL_D_SPEC, ivspecs[3].str, MAX_IVL_SPECLIST_LEN); - ivspecs[IVL_DAYS].mul = ivspecs[IVL_HOURS].mul * 24; - LoadString(hinst_kcreddb, IDS_IVL_W_SPEC, ivspecs[4].str, MAX_IVL_SPECLIST_LEN); - ivspecs[IVL_WEEKS].mul = ivspecs[IVL_DAYS].mul * 7; - - ivspecs_loaded = TRUE; - } - - if(!str || FAILED(StringCbLength(str, MAX_IVL_SPECLIST_LEN, &cb))) - return KHM_ERROR_INVALID_PARAM; - - b = str; - t = 0; - while(*b) { - __int64 f = 1; - wchar_t *e; - int i; - - while(*b && iswspace(*b)) - b++; - - if(*b && iswdigit(*b)) { - f = _wtoi64(b); - - while(*b && iswdigit(*b)) - b++; - } - - while(*b && iswspace(*b)) - b++; - - if(!*b) /* no unit specified */ - return KHM_ERROR_INVALID_PARAM; - - e = b; - - while(*e && !iswspace(*e)) - e++; - - for(i=0; i < MAX_IVL_UNITS; i++) { - if(_iv_is_in_spec(b, (int)(e-b), ivspecs[i].str)) - break; - } - - if(i==MAX_IVL_UNITS) - return KHM_ERROR_INVALID_PARAM; - - t += f * ivspecs[i].mul; - - b = e; - } - - *pft = IntToFt(t); - - return KHM_ERROR_SUCCESS; -} +/* + * 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 + +CRITICAL_SECTION cs_type; +hashtable * kcdb_type_namemap; +kcdb_type_i ** kcdb_type_tbl; +kcdb_type_i * kcdb_types = NULL; + +/* Void */ + +#define GENERIC_VOID_STR L"(Void)" + +khm_int32 KHMAPI kcdb_type_void_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags) +{ + size_t cbsize; + + if(!cb_buf) + return KHM_ERROR_INVALID_PARAM; + + cbsize = sizeof(GENERIC_VOID_STR); + + if(!buffer || *cb_buf < cbsize) { + *cb_buf = cbsize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buffer, *cb_buf, GENERIC_VOID_STR); + + *cb_buf = cbsize; + + return KHM_ERROR_SUCCESS; +} + +khm_boolean KHMAPI kcdb_type_void_isValid( + const void * d, + khm_size cbd) +{ + /* void is always valid, even if d is NULL */ + return TRUE; +} + +khm_int32 KHMAPI kcdb_type_void_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2) +{ + /* voids can not be compared */ + return 0; +} + +khm_int32 KHMAPI kcdb_type_void_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst) +{ + if(!cbd_dst) + return KHM_ERROR_INVALID_PARAM; + + *cbd_dst = 0; + + /* copying a void doesn't do much */ + return KHM_ERROR_SUCCESS; +} + + +/* String */ +khm_int32 KHMAPI kcdb_type_string_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags) +{ + size_t cbsize; + wchar_t * sd; + + if(!cb_buf) + return KHM_ERROR_INVALID_PARAM; + + sd = (wchar_t *) d; + + if(FAILED(StringCbLength(sd, KCDB_TYPE_MAXCB, &cbsize))) + return KHM_ERROR_INVALID_PARAM; + + cbsize += sizeof(wchar_t); + + if(!buffer || *cb_buf < cbsize) { + *cb_buf = cbsize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buffer, *cb_buf, sd); + + *cb_buf = cbsize; + + return KHM_ERROR_SUCCESS; +} + +khm_boolean KHMAPI kcdb_type_string_isValid( + const void * d, + khm_size cbd) +{ + size_t cbsize; + + if(cbd == KCDB_CBSIZE_AUTO) + cbd = KCDB_TYPE_MAXCB; + + if(FAILED(StringCbLength((wchar_t *) d, cbd, &cbsize))) + return FALSE; + else + return TRUE; +} + +khm_int32 KHMAPI kcdb_type_string_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2) +{ + return wcscmp((const wchar_t *) d1, (const wchar_t *) d2); +} + +khm_int32 KHMAPI kcdb_type_string_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst) +{ + size_t cbsize; + + if(!cbd_dst) + return KHM_ERROR_INVALID_PARAM; + + if(cbd_src == KCDB_CBSIZE_AUTO) { + cbd_src = KCDB_TYPE_MAXCB; + } + + if(FAILED(StringCbLength((const wchar_t *) d_src, cbd_src, &cbsize))) { + return KHM_ERROR_UNKNOWN; + } + + cbsize += sizeof(wchar_t); + + if(!d_dst || *cbd_dst < cbsize) { + *cbd_dst = cbsize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy((wchar_t *) d_dst, *cbd_dst, (const wchar_t *) d_src); + *cbd_dst = cbsize; + + return KHM_ERROR_SUCCESS; +} + +/* Date and time */ + + +khm_int32 KHMAPI kcdb_type_date_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags) +{ + size_t cbsize; + size_t cchsize; + wchar_t * bufend; + SYSTEMTIME st_now; + SYSTEMTIME st_d; + SYSTEMTIME st_dl; + FILETIME *ft; + int today = 0; + + if(!cb_buf) + return KHM_ERROR_INVALID_PARAM; + + ft = (FILETIME *) d; + + GetLocalTime(&st_now); + FileTimeToSystemTime(ft, &st_d); + SystemTimeToTzSpecificLocalTime(NULL, &st_d, &st_dl); + if (st_now.wYear == st_dl.wYear && + st_now.wMonth == st_dl.wMonth && + st_now.wDay == st_dl.wDay) + today = 1; + + if(today && (flags & KCDB_TS_SHORT)) { + cbsize = 0; + } else { + cbsize = GetDateFormat( + LOCALE_USER_DEFAULT, + DATE_SHORTDATE, + &st_dl, + NULL, + NULL, + 0) * sizeof(wchar_t); + } + + cbsize += GetTimeFormat( + LOCALE_USER_DEFAULT, + 0, + &st_dl, + NULL, + NULL, + 0) * sizeof(wchar_t); + + if(!buffer || *cb_buf < cbsize) { + *cb_buf = cbsize; + return KHM_ERROR_TOO_LONG; + } + + cchsize = cbsize / sizeof(wchar_t); + + if(!today || !(flags & KCDB_TS_SHORT)) { + size_t cch_buf_len; + + GetDateFormat( + LOCALE_USER_DEFAULT, + DATE_SHORTDATE, + &st_dl, + NULL, + buffer, + (int) cchsize); + + StringCchCat(buffer, cchsize, L" "); + + StringCchLength(buffer, cchsize, &cch_buf_len); + + bufend = buffer + cch_buf_len; + cchsize -= cch_buf_len; + } else { + bufend = buffer; + } + + GetTimeFormat( + LOCALE_USER_DEFAULT, + 0, + &st_dl, + NULL, + bufend, + (int) cchsize); + + *cb_buf = cbsize; + + return KHM_ERROR_SUCCESS; +} + +khm_boolean KHMAPI kcdb_type_date_isValid( + const void * d, + khm_size cbd) +{ + return (d && (cbd == KCDB_CBSIZE_AUTO || cbd == sizeof(FILETIME))); +} + +khm_int32 KHMAPI kcdb_type_date_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2) +{ + return (khm_int32) CompareFileTime((CONST FILETIME *) d1, (CONST FILETIME *) d2); +} + +khm_int32 KHMAPI kcdb_type_date_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst) +{ + if(d_dst && *cbd_dst >= sizeof(FILETIME)) { + *cbd_dst = sizeof(FILETIME); + *((FILETIME *) d_dst) = *((FILETIME *) d_src); + return KHM_ERROR_SUCCESS; + } else { + *cbd_dst = sizeof(FILETIME); + return KHM_ERROR_TOO_LONG; + } +} + +/* Interval */ + +/* returns the number of milliseconds that must elapse away from the + interval specified in pft for the representation of pft to change + from whatever it is right now */ +KHMEXP long KHMAPI +FtIntervalMsToRepChange(LPFILETIME pft) +{ + __int64 ms,s,m,h,d; + __int64 ift; + long l; + + ift = FtToInt(pft); + ms = ift / 10000i64; + + if(ms < 0 || ift == _I64_MAX) + return -1; + + s = ms / 1000i64; + m = s / 60; + h = s / 3600; + d = s / (3600*24); + + if (d > 0) { + /* rep change at next hour change */ + l = (long) (ms % (3600*1000i64)); + } else if (h > 0) { + /* rep change at next minute change */ + l = (long) (ms % (60*1000i64)); + } else if (m > 5) { + /* rep change at next minute change */ + l = (long) (ms % (60*1000i64)); + } else { + /* rep change at next second change */ + l = (long) (ms % 1000); + } + + return l; +} + +KHMEXP khm_int32 KHMAPI +FtIntervalToString(LPFILETIME data, wchar_t * buffer, khm_size * cb_buf) +{ + size_t cbsize; + __int64 s,m,h,d; + __int64 ift; + wchar_t ibuf[256]; + wchar_t fbuf[256]; + wchar_t * t; + + if(!cb_buf) + return KHM_ERROR_INVALID_PARAM; + + ift = FtToInt(data); + s = ift / 10000000i64; + + m = s / 60; + h = s / 3600; + 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) { + h = (s - (d * 3600 * 24)) / 3600; + if(d == 1) { + LoadString(hinst_kcreddb, IDS_IVL_1D, ibuf, ARRAYLENGTH(ibuf)); + } else { + LoadString(hinst_kcreddb, IDS_IVL_D, fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(ibuf, sizeof(ibuf), fbuf, d); + } + if(h > 0) { + StringCbCat(ibuf, sizeof(ibuf), L" "); + t = ibuf + wcslen(ibuf); + if(h == 1) + { + LoadString(hinst_kcreddb, IDS_IVL_1H, t, + (int) (ARRAYLENGTH(ibuf) - wcslen(ibuf))); + } else { + LoadString(hinst_kcreddb, IDS_IVL_H, fbuf, + (int) ARRAYLENGTH(fbuf)); + StringCbPrintf(t, sizeof(ibuf) - wcslen(ibuf)*sizeof(wchar_t), fbuf, h); + } + } + } else if(h > 0 || m > 5) { + m = (s - (h * 3600)) / 60; + if(h == 1) { + LoadString(hinst_kcreddb, IDS_IVL_1H, ibuf, ARRAYLENGTH(ibuf)); + } else if (h > 1) { + LoadString(hinst_kcreddb, IDS_IVL_H, fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(ibuf, sizeof(ibuf), fbuf, h); + } else { + *ibuf = L'\0'; + } + + if(m > 0 || h == 0) { + if (h >= 1) + StringCbCat(ibuf, sizeof(ibuf), L" "); + + t = ibuf + wcslen(ibuf); + if(m == 1) + { + LoadString(hinst_kcreddb, IDS_IVL_1M, t, + (int) (ARRAYLENGTH(ibuf) - wcslen(ibuf))); + } else { + LoadString(hinst_kcreddb, IDS_IVL_M, fbuf, + (int) ARRAYLENGTH(fbuf)); + StringCbPrintf(t, sizeof(ibuf) - wcslen(ibuf)*sizeof(wchar_t), fbuf, m); + } + } + } else if(m > 0) { + s -= m * 60; + if(m == 1) { + LoadString(hinst_kcreddb, IDS_IVL_1M, ibuf, ARRAYLENGTH(ibuf)); + } else { + LoadString(hinst_kcreddb, IDS_IVL_M, fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(ibuf, sizeof(ibuf), fbuf, m); + } + if(s > 0) { + StringCbCat(ibuf, sizeof(ibuf), L" "); + t = ibuf + wcslen(ibuf); + if(s == 1) + { + LoadString(hinst_kcreddb, IDS_IVL_1S, t, + (int) (ARRAYLENGTH(ibuf) - wcslen(ibuf))); + } else { + LoadString(hinst_kcreddb, IDS_IVL_S, fbuf, + (int) ARRAYLENGTH(fbuf)); + StringCbPrintf(t, sizeof(ibuf) - wcslen(ibuf)*sizeof(wchar_t), fbuf, s); + } + } + } else { + if(s == 1) { + LoadString(hinst_kcreddb, IDS_IVL_1S, ibuf, ARRAYLENGTH(ibuf)); + } else { + LoadString(hinst_kcreddb, IDS_IVL_S, fbuf, sizeof(fbuf)/sizeof(wchar_t)); + StringCbPrintf(ibuf, sizeof(ibuf), fbuf, s); + } + } + + StringCbLength(ibuf, sizeof(ibuf), &cbsize); + cbsize += sizeof(wchar_t); + + if(!buffer || *cb_buf < cbsize) { + *cb_buf = cbsize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buffer, *cb_buf, ibuf); + *cb_buf = cbsize; + + return KHM_ERROR_SUCCESS; +} + +khm_int32 KHMAPI +kcdb_type_interval_toString(const void * data, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags) +{ + return FtIntervalToString((LPFILETIME) data, buffer, cb_buf); +} + +khm_boolean KHMAPI kcdb_type_interval_isValid( + const void * d, + khm_size cbd) +{ + return (d && (cbd == sizeof(FILETIME) || cbd == KCDB_CBSIZE_AUTO)); +} + +khm_int32 KHMAPI kcdb_type_interval_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2) +{ + __int64 i1, i2; + + i1 = FtToInt((FILETIME *) d1); + i2 = FtToInt((FILETIME *) d2); + + if(i1 < i2) + return -1; + else if(i1 > i2) + return 1; + else + return 0; +} + +khm_int32 KHMAPI kcdb_type_interval_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst) +{ + if(d_dst && *cbd_dst >= sizeof(FILETIME)) { + *cbd_dst = sizeof(FILETIME); + *((FILETIME *) d_dst) = *((FILETIME *) d_src); + return KHM_ERROR_SUCCESS; + } else { + *cbd_dst = sizeof(FILETIME); + return KHM_ERROR_TOO_LONG; + } +} + +/* Int32 */ + +khm_int32 KHMAPI kcdb_type_int32_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags) +{ + size_t cbsize; + wchar_t ibuf[12]; + + if(!cb_buf) + return KHM_ERROR_INVALID_PARAM; + + StringCbPrintf(ibuf, sizeof(ibuf), L"%d", *((khm_int32 *) d)); + StringCbLength(ibuf, sizeof(ibuf), &cbsize); + cbsize += sizeof(wchar_t); + + if(!buffer || *cb_buf < cbsize) { + *cb_buf = cbsize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy((wchar_t *) buffer, *cb_buf, ibuf); + *cb_buf = cbsize; + + return KHM_ERROR_SUCCESS; +} + +khm_boolean KHMAPI kcdb_type_int32_isValid( + const void * d, + khm_size cbd) +{ + return (d && (cbd == KCDB_CBSIZE_AUTO || cbd == sizeof(khm_int32))); +} + +khm_int32 KHMAPI kcdb_type_int32_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2) +{ + return *((khm_int32 *) d1) - *((khm_int32 *) d2); +} + +khm_int32 KHMAPI kcdb_type_int32_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst) +{ + if(d_dst && (*cbd_dst >= sizeof(khm_int32))) { + *cbd_dst = sizeof(khm_int32); + *((khm_int32 *) d_dst) = *((khm_int32 *) d_src); + return KHM_ERROR_SUCCESS; + } else { + *cbd_dst = sizeof(khm_int32); + return KHM_ERROR_TOO_LONG; + } +} + +/* Int64 */ + +khm_int32 KHMAPI kcdb_type_int64_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags) +{ + size_t cbsize; + wchar_t ibuf[22]; + + if(!cb_buf) + return KHM_ERROR_INVALID_PARAM; + + StringCbPrintf(ibuf, sizeof(ibuf), L"%I64d", *((__int64 *) d)); + StringCbLength(ibuf, sizeof(ibuf), &cbsize); + cbsize += sizeof(wchar_t); + + if(!buffer || *cb_buf < cbsize) { + *cb_buf = cbsize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy((wchar_t *) buffer, *cb_buf, ibuf); + *cb_buf = cbsize; + + return KHM_ERROR_SUCCESS; +} + +khm_boolean KHMAPI kcdb_type_int64_isValid( + const void * d, + khm_size cbd) +{ + return (d && (cbd == KCDB_CBSIZE_AUTO || cbd == sizeof(__int64))); +} + +khm_int32 KHMAPI kcdb_type_int64_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2) +{ + __int64 r = *((__int64 *) d1) - *((__int64 *) d2); + return (r==0i64)?0:((r>0i64)?1:-1); +} + +khm_int32 KHMAPI kcdb_type_int64_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst) +{ + if(d_dst && (*cbd_dst >= sizeof(__int64))) { + *cbd_dst = sizeof(__int64); + *((__int64 *) d_dst) = *((__int64 *) d_src); + return KHM_ERROR_SUCCESS; + } else { + *cbd_dst = sizeof(__int64); + return KHM_ERROR_TOO_LONG; + } +} + +/* Data */ +#define GENERIC_DATA_STR L"(Data)" + +khm_int32 KHMAPI kcdb_type_data_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags) +{ + size_t cbsize; + + if(!cb_buf) + return KHM_ERROR_INVALID_PARAM; + + cbsize = sizeof(GENERIC_DATA_STR); + + if(!buffer || *cb_buf < cbsize) { + *cb_buf = cbsize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buffer, *cb_buf, GENERIC_DATA_STR); + + *cb_buf = cbsize; + + return KHM_ERROR_SUCCESS; +} + +khm_boolean KHMAPI kcdb_type_data_isValid( + const void * d, + khm_size cbd) +{ + /* data is always valid */ + if (cbd != 0 && d == NULL) + return FALSE; + else + return TRUE; +} + +khm_int32 KHMAPI kcdb_type_data_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2) +{ + khm_size pref; + khm_int32 rv = 0; + + pref = min(cbd1, cbd2); + + if (pref == 0) + return (cbd1 < cbd2)? -1 : ((cbd1 > cbd2)? 1 : 0); + + rv = memcmp(d1, d2, pref); + + if (rv == 0) { + return (cbd1 < cbd2)? -1 : ((cbd1 > cbd2)? 1 : 0); + } else { + return rv; + } +} + +khm_int32 KHMAPI kcdb_type_data_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst) +{ + if(!cbd_dst || cbd_src == KCDB_CBSIZE_AUTO) + return KHM_ERROR_INVALID_PARAM; + + if(!d_dst || *cbd_dst < cbd_src) { + *cbd_dst = cbd_src; + return KHM_ERROR_TOO_LONG; + } else { + *cbd_dst = cbd_src; + memcpy(d_dst, d_src, cbd_src); + return KHM_ERROR_SUCCESS; + } +} + + +void kcdb_type_msg_completion(kmq_message * m) +{ + kcdb_type_release((kcdb_type_i *) m->vparam); +} + +void kcdb_type_post_message(khm_int32 op, kcdb_type_i * t) +{ + kcdb_type_hold(t); + kmq_post_message(KMSG_KCDB, KMSG_KCDB_TYPE, op, (void *) t); +} + +void kcdb_type_init(void) +{ + kcdb_type type; + + InitializeCriticalSection(&cs_type); + kcdb_type_namemap = hash_new_hashtable( + KCDB_TYPE_HASH_SIZE, + hash_string, + hash_string_comp, + kcdb_type_add_ref, + kcdb_type_del_ref); + kcdb_type_tbl = PMALLOC(sizeof(kcdb_type_i *) * (KCDB_TYPE_MAX_ID + 1)); + ZeroMemory(kcdb_type_tbl, sizeof(kcdb_type_i *) * (KCDB_TYPE_MAX_ID + 1)); + kcdb_types = NULL; + + /*TODO: register standard data types */ + + ZeroMemory(&type, sizeof(type)); + type.comp = kcdb_type_void_comp; + type.dup = kcdb_type_void_dup; + type.isValid = kcdb_type_void_isValid; + type.toString = kcdb_type_void_toString; + type.name = KCDB_TYPENAME_VOID; + type.id = KCDB_TYPE_VOID; + + kcdb_type_register(&type, NULL); + + ZeroMemory(&type, sizeof(type)); + type.comp = kcdb_type_string_comp; + type.dup = kcdb_type_string_dup; + type.isValid = kcdb_type_string_isValid; + type.toString = kcdb_type_string_toString; + type.name = KCDB_TYPENAME_STRING; + type.id = KCDB_TYPE_STRING; + type.flags = KCDB_TYPE_FLAG_CB_AUTO; + + kcdb_type_register(&type, NULL); + + ZeroMemory(&type, sizeof(type)); + type.comp = kcdb_type_date_comp; + type.dup = kcdb_type_date_dup; + type.isValid = kcdb_type_date_isValid; + type.toString = kcdb_type_date_toString; + type.name = KCDB_TYPENAME_DATE; + type.id = KCDB_TYPE_DATE; + type.cb_max = sizeof(FILETIME); + type.cb_min = sizeof(FILETIME); + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + + kcdb_type_register(&type, NULL); + + ZeroMemory(&type, sizeof(type)); + type.comp = kcdb_type_interval_comp; + type.dup = kcdb_type_interval_dup; + type.isValid = kcdb_type_interval_isValid; + type.toString = kcdb_type_interval_toString; + type.name = KCDB_TYPENAME_INTERVAL; + type.id = KCDB_TYPE_INTERVAL; + type.cb_max = sizeof(FILETIME); + type.cb_min = sizeof(FILETIME); + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + + kcdb_type_register(&type, NULL); + + ZeroMemory(&type, sizeof(type)); + type.comp = kcdb_type_int32_comp; + type.dup = kcdb_type_int32_dup; + type.isValid = kcdb_type_int32_isValid; + type.toString = kcdb_type_int32_toString; + type.name = KCDB_TYPENAME_INT32; + type.id = KCDB_TYPE_INT32; + type.cb_max = sizeof(khm_int32); + type.cb_min = sizeof(khm_int32); + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + + kcdb_type_register(&type, NULL); + + ZeroMemory(&type, sizeof(type)); + type.comp = kcdb_type_int64_comp; + type.dup = kcdb_type_int64_dup; + type.isValid = kcdb_type_int64_isValid; + type.toString = kcdb_type_int64_toString; + type.name = KCDB_TYPENAME_INT64; + type.id = KCDB_TYPE_INT64; + type.cb_max = sizeof(__int64); + type.cb_min = sizeof(__int64); + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + + kcdb_type_register(&type, NULL); + + ZeroMemory(&type, sizeof(type)); + type.comp = kcdb_type_data_comp; + type.dup = kcdb_type_data_dup; + type.isValid = kcdb_type_data_isValid; + type.toString = kcdb_type_data_toString; + type.name = KCDB_TYPENAME_DATA; + type.id = KCDB_TYPE_DATA; + + kcdb_type_register(&type, NULL); +} + +void kcdb_type_add_ref(const void *key, void *vt) +{ + kcdb_type_hold((kcdb_type_i *) vt); +} + +void kcdb_type_del_ref(const void *key, void *vt) +{ + kcdb_type_release((kcdb_type_i *) vt); +} + +khm_int32 kcdb_type_hold(kcdb_type_i * t) +{ + if(!t) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_type); + t->refcount++; + LeaveCriticalSection(&cs_type); + + return KHM_ERROR_SUCCESS; +} + +khm_int32 kcdb_type_release(kcdb_type_i * t) +{ + if(!t) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_type); + t->refcount--; + kcdb_type_check_and_delete(t->type.id); + LeaveCriticalSection(&cs_type); + + return KHM_ERROR_SUCCESS; +} + +void kcdb_type_exit(void) +{ + EnterCriticalSection(&cs_type); + PFREE(kcdb_type_tbl); + /*TODO: free up the individual types */ + LeaveCriticalSection(&cs_type); + DeleteCriticalSection(&cs_type); +} + +void kcdb_type_check_and_delete(khm_int32 id) +{ + kcdb_type_i * t; + + if(id < 0 || id > KCDB_TYPE_MAX_ID) + return; + + EnterCriticalSection(&cs_type); + t = kcdb_type_tbl[id]; + if(t && !t->refcount) { + kcdb_type_tbl[id] = NULL; + LDELETE(&kcdb_types, t); + /* must already be out of the hash-table, otherwise refcount should not + be zero */ + PFREE(t->type.name); + PFREE(t); + } + LeaveCriticalSection(&cs_type); +} + +KHMEXP khm_int32 KHMAPI kcdb_type_get_id(const wchar_t *name, khm_int32 * id) +{ + kcdb_type_i * t; + size_t cbsize; + + if(FAILED(StringCbLength(name, KCDB_MAXCB_NAME, &cbsize))) { + /* also fails of name is NULL */ + return KHM_ERROR_INVALID_PARAM; + } + + EnterCriticalSection(&cs_type); + t = hash_lookup(kcdb_type_namemap, (void*) name); + LeaveCriticalSection(&cs_type); + + if(!t) { + *id = KCDB_TYPE_INVALID; + return KHM_ERROR_NOT_FOUND; + } else { + *id = t->type.id; + return KHM_ERROR_SUCCESS; + } +} + +KHMEXP khm_int32 KHMAPI kcdb_type_get_info(khm_int32 id, kcdb_type ** info) +{ + kcdb_type_i * t; + + if(id < 0 || id > KCDB_TYPE_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_type); + t = kcdb_type_tbl[id]; + + if (t) + kcdb_type_hold(t); + LeaveCriticalSection(&cs_type); + + if(info) + *info = (kcdb_type *) t; + else if (t) + kcdb_type_release(t); + + return (t)? KHM_ERROR_SUCCESS : KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI kcdb_type_release_info(kcdb_type * info) +{ + return kcdb_type_release((kcdb_type_i *) info); +} + +KHMEXP khm_int32 KHMAPI kcdb_type_get_name(khm_int32 id, wchar_t * buffer, khm_size * cbbuf) +{ + size_t cbsize; + kcdb_type_i * t; + + if(id < 0 || id > KCDB_TYPE_MAX_ID || !cbbuf) + return KHM_ERROR_INVALID_PARAM; + + t = kcdb_type_tbl[id]; + + if(!t) + return KHM_ERROR_NOT_FOUND; + + if(FAILED(StringCbLength(t->type.name, KCDB_MAXCB_NAME, &cbsize))) + return KHM_ERROR_UNKNOWN; + + cbsize += sizeof(wchar_t); + + if(!buffer || *cbbuf < cbsize) { + *cbbuf = cbsize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buffer, *cbbuf, t->type.name); + *cbbuf = cbsize; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_type_register(const kcdb_type * type, khm_int32 * new_id) +{ + kcdb_type_i *t; + size_t cbsize; + khm_int32 type_id; + + if(!type || + !type->comp || + !type->dup || + !type->isValid || + !type->toString || + !type->name) + return KHM_ERROR_INVALID_PARAM; + + if((type->flags & KCDB_TYPE_FLAG_CB_MIN) && + (type->cb_min < 0 || type->cb_min > KCDB_TYPE_MAXCB)) + { + return KHM_ERROR_INVALID_PARAM; + } + + if((type->flags & KCDB_TYPE_FLAG_CB_MAX) && + (type->cb_max < 0 || type->cb_max > KCDB_TYPE_MAXCB)) + { + return KHM_ERROR_INVALID_PARAM; + } + + if((type->flags & KCDB_TYPE_FLAG_CB_MIN) && + (type->flags & KCDB_TYPE_FLAG_CB_MAX) && + (type->cb_max < type->cb_min)) + { + return KHM_ERROR_INVALID_PARAM; + } + + if(FAILED(StringCbLength(type->name, KCDB_MAXCB_NAME, &cbsize))) + return KHM_ERROR_TOO_LONG; + + cbsize += sizeof(wchar_t); + + EnterCriticalSection(&cs_type); + if(type->id == KCDB_TYPE_INVALID) { + kcdb_type_get_next_free(&type_id); + } else if(type->id < 0 || type->id > KCDB_TYPE_MAX_ID) { + LeaveCriticalSection(&cs_type); + return KHM_ERROR_INVALID_PARAM; + } else if(kcdb_type_tbl[type->id]) { + LeaveCriticalSection(&cs_type); + return KHM_ERROR_DUPLICATE; + } else { + type_id = type->id; + } + + if(type_id == KCDB_TYPE_INVALID) { + LeaveCriticalSection(&cs_type); + return KHM_ERROR_NO_RESOURCES; + } + + t = PMALLOC(sizeof(kcdb_type_i)); + ZeroMemory(t, sizeof(kcdb_type_i)); + + t->type.name = PMALLOC(cbsize); + StringCbCopy(t->type.name, cbsize, type->name); + + t->type.comp = type->comp; + t->type.dup = type->dup; + t->type.flags = type->flags; + t->type.id = type_id; + t->type.isValid = type->isValid; + t->type.toString = type->toString; + + LINIT(t); + + kcdb_type_tbl[type_id] = t; + LPUSH(&kcdb_types, t); + + hash_add(kcdb_type_namemap, (void *) t->type.name, (void *) t); + + LeaveCriticalSection(&cs_type); + + if(new_id) + *new_id = type_id; + + kcdb_type_post_message(KCDB_OP_INSERT, t); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_type_unregister(khm_int32 id) +{ + kcdb_type_i * t; + + if(id < 0 || id > KCDB_TYPE_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_type); + t = kcdb_type_tbl[id]; + if(t) { + kcdb_type_post_message(KCDB_OP_DELETE, t); + /* we are going to remove t from the hash table. If no one is holding + a reference to it, then we can free it (actually, the del_ref code + will take care of that anyway). If there is a hold, then it will + get freed when they release it. + + Actually, the post_message call above pretty much guarantees that + the type has a hold on it.*/ + t->type.flags |= KCDB_TYPE_FLAG_DELETED; + hash_del(kcdb_type_namemap, t->type.name); + } + LeaveCriticalSection(&cs_type); + + if(t) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI kcdb_type_get_next_free(khm_int32 * id) +{ + int i; + + if(!id) + return KHM_ERROR_INVALID_PARAM; + + /* do a linear search because this function only gets called a few times */ + EnterCriticalSection(&cs_type); + for(i=0; i <= KCDB_TYPE_MAX_ID; i++) { + if(!kcdb_type_tbl[i]) + break; + } + LeaveCriticalSection(&cs_type); + + if(i <= KCDB_TYPE_MAX_ID) { + *id = i; + return KHM_ERROR_SUCCESS; + } else { + *id = KCDB_TYPE_INVALID; + return KHM_ERROR_NO_RESOURCES; + } +} + +/* Conversion functions */ + +KHMEXP void KHMAPI TimetToFileTime( time_t t, LPFILETIME pft ) +{ + LONGLONG ll; + + if ( sizeof(time_t) == 4 ) + ll = Int32x32To64(t, 10000000) + 116444736000000000i64; + else { + ll = t * 10000000i64 + 116444736000000000i64; + } + pft->dwLowDateTime = (DWORD) ll; + pft->dwHighDateTime = (DWORD) (ll >> 32); +} + +KHMEXP void KHMAPI TimetToFileTimeInterval(time_t t, LPFILETIME pft) +{ + LONGLONG ll; + + if ( sizeof(time_t) == 4 ) + ll = Int32x32To64(t, 10000000); + else { + ll = t * 10000000i64; + } + pft->dwLowDateTime = (DWORD) ll; + pft->dwHighDateTime = (DWORD) (ll >> 32); +} + +KHMEXP long KHMAPI FtIntervalToSeconds(LPFILETIME pft) +{ + __int64 i = FtToInt(pft); + return (long) (i / 10000000i64); +} + +KHMEXP long KHMAPI FtIntervalToMilliseconds(LPFILETIME pft) +{ + __int64 i = FtToInt(pft); + return (long) (i / 10000i64); +} + +KHMEXP khm_int64 KHMAPI FtToInt(LPFILETIME pft) { + LARGE_INTEGER ll; + ll.LowPart = pft->dwLowDateTime; + ll.HighPart = pft->dwHighDateTime; + return ll.QuadPart; +} + +KHMEXP FILETIME KHMAPI IntToFt(khm_int64 i) { + LARGE_INTEGER ll; + FILETIME ft; + + ll.QuadPart = i; + ft.dwLowDateTime = ll.LowPart; + ft.dwHighDateTime = ll.HighPart; + + return ft; +} + +KHMEXP FILETIME KHMAPI FtSub(LPFILETIME ft1, LPFILETIME ft2) { + FILETIME d; + LARGE_INTEGER l1, l2; + + l1.LowPart = ft1->dwLowDateTime; + l1.HighPart = ft1->dwHighDateTime; + l2.LowPart = ft2->dwLowDateTime; + l2.HighPart = ft2->dwHighDateTime; + + l1.QuadPart -= l2.QuadPart; + + d.dwLowDateTime = l1.LowPart; + d.dwHighDateTime = l1.HighPart; + + return d; +} + +KHMEXP FILETIME KHMAPI FtAdd(LPFILETIME ft1, LPFILETIME ft2) { + FILETIME d; + LARGE_INTEGER l1, l2; + + l1.LowPart = ft1->dwLowDateTime; + l1.HighPart = ft1->dwHighDateTime; + l2.LowPart = ft2->dwLowDateTime; + l2.HighPart = ft2->dwHighDateTime; + + l1.QuadPart += l2.QuadPart; + + d.dwLowDateTime = l1.LowPart; + d.dwHighDateTime = l1.HighPart; + + return d; +} + +KHMEXP int KHMAPI AnsiStrToUnicode( wchar_t * wstr, size_t cbwstr, const char * astr) +{ + size_t nc; + + if(cbwstr == 0) + return 0; + + nc = strlen(astr); + if(nc == MultiByteToWideChar( + CP_ACP, + 0, + astr, + (int) nc, + wstr, + (int)(cbwstr / sizeof(wchar_t) - 1))) { + wstr[nc] = L'\0'; + } else { + wstr[0] = L'\0'; + nc = 0; + } + + return (int) nc; +} + +KHMEXP int KHMAPI UnicodeStrToAnsi( char * dest, size_t cbdest, const wchar_t * src) +{ + size_t nc; + + if(cbdest == 0) + return 0; + + dest[0] = 0; + + if(FAILED(StringCchLength(src, cbdest, &nc)) || nc*sizeof(char) >= cbdest) + // note that cbdest counts the terminating NULL, while nc doesn't + return 0; + + nc = WideCharToMultiByte( + CP_ACP, + WC_NO_BEST_FIT_CHARS, + src, + (int) nc, + dest, + (int) cbdest, + NULL, + NULL); + + dest[nc] = 0; + + return (int) nc; +} + +#define MAX_IVL_SPECLIST_LEN 256 +#define MAX_IVL_UNITS 5 + +enum _ivl_indices { + IVL_SECONDS = 0, + IVL_MINUTES, + IVL_HOURS, + IVL_DAYS, + IVL_WEEKS +}; + +typedef struct ivspec_t { + wchar_t str[MAX_IVL_SPECLIST_LEN]; + __int64 mul; +} ivspec; + +static ivspec ivspecs[MAX_IVL_UNITS]; +static BOOL ivspecs_loaded = FALSE; + +int _iv_is_in_spec(wchar_t *s, int n, wchar_t * spec) +{ + /* spec strigns are comma separated */ + wchar_t *b, *e; + + b = spec; + while(*b) { + e = wcschr(b, L','); + if(!e) + e = b + wcslen(b); + + if((e - b) == n && !_wcsnicmp(b, s, n)) { + return TRUE; + } + + if(*e) + b = e+1; + else + break; + } + + return FALSE; +} + +KHMEXP khm_int32 KHMAPI IntervalStringToFt(FILETIME * pft, wchar_t * str) +{ + size_t cb; + wchar_t * b; + __int64 t; + + *pft = IntToFt(0); + + /* ideally we should synchronize this, but it doesn't hurt if two + threads do this at the same time, because we only set the ivspecs_loaded + flag when we are done */ + if(!ivspecs_loaded) { + LoadString(hinst_kcreddb, IDS_IVL_S_SPEC, ivspecs[IVL_SECONDS].str, MAX_IVL_SPECLIST_LEN); + ivspecs[IVL_SECONDS].mul = 10000000i64; + LoadString(hinst_kcreddb, IDS_IVL_M_SPEC, ivspecs[IVL_MINUTES].str, MAX_IVL_SPECLIST_LEN); + ivspecs[IVL_MINUTES].mul = ivspecs[IVL_SECONDS].mul * 60; + LoadString(hinst_kcreddb, IDS_IVL_H_SPEC, ivspecs[2].str, MAX_IVL_SPECLIST_LEN); + ivspecs[IVL_HOURS].mul = ivspecs[IVL_MINUTES].mul * 60; + LoadString(hinst_kcreddb, IDS_IVL_D_SPEC, ivspecs[3].str, MAX_IVL_SPECLIST_LEN); + ivspecs[IVL_DAYS].mul = ivspecs[IVL_HOURS].mul * 24; + LoadString(hinst_kcreddb, IDS_IVL_W_SPEC, ivspecs[4].str, MAX_IVL_SPECLIST_LEN); + ivspecs[IVL_WEEKS].mul = ivspecs[IVL_DAYS].mul * 7; + + ivspecs_loaded = TRUE; + } + + if(!str || FAILED(StringCbLength(str, MAX_IVL_SPECLIST_LEN, &cb))) + return KHM_ERROR_INVALID_PARAM; + + b = str; + t = 0; + while(*b) { + __int64 f = 1; + wchar_t *e; + int i; + + while(*b && iswspace(*b)) + b++; + + if(*b && iswdigit(*b)) { + f = _wtoi64(b); + + while(*b && iswdigit(*b)) + b++; + } + + while(*b && iswspace(*b)) + b++; + + if(!*b) /* no unit specified */ + return KHM_ERROR_INVALID_PARAM; + + e = b; + + while(*e && !iswspace(*e)) + e++; + + for(i=0; i < MAX_IVL_UNITS; i++) { + if(_iv_is_in_spec(b, (int)(e-b), ivspecs[i].str)) + break; + } + + if(i==MAX_IVL_UNITS) + return KHM_ERROR_INVALID_PARAM; + + t += f * ivspecs[i].mul; + + b = e; + } + + *pft = IntToFt(t); + + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/kcreddb/type.h b/src/windows/identity/kcreddb/type.h index f7ef26ac4..698e5f386 100644 --- a/src/windows/identity/kcreddb/type.h +++ b/src/windows/identity/kcreddb/type.h @@ -1,216 +1,216 @@ -/* - * 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_KCDB_TYPE_H -#define __KHIMAIRA_KCDB_TYPE_H - -/* Types */ - -typedef struct kcdb_type_i_t { - kcdb_type type; - - khm_int32 refcount; - - struct kcdb_type_i_t * next; - struct kcdb_type_i_t * prev; -} kcdb_type_i; - -#define KCDB_TYPE_HASH_SIZE 31 - -#define KCDB_TYPE_FLAG_DELETED 8 - -void kcdb_type_init(void); -void kcdb_type_exit(void); -void kcdb_type_add_ref(const void *key, void *vt); -void kcdb_type_del_ref(const void *key, void *vt); -void kcdb_type_msg_completion(kmq_message * m); -khm_int32 kcdb_type_hold(kcdb_type_i * t); -khm_int32 kcdb_type_release(kcdb_type_i * t); -void kcdb_type_check_and_delete(khm_int32 id); -void kcdb_type_post_message(khm_int32 op, kcdb_type_i * t); - -khm_int32 KHMAPI kcdb_type_void_toString( - const void * d, - khm_size cbd, - wchar_t * buffer, - khm_size * cb_buf, - khm_int32 flags); - -khm_boolean KHMAPI kcdb_type_void_isValid( - const void * d, - khm_size cbd); - -khm_int32 KHMAPI kcdb_type_void_comp( - const void * d1, - khm_size cbd1, - const void * d2, - khm_size cbd2); - -khm_int32 KHMAPI kcdb_type_void_dup( - const void * d_src, - khm_size cbd_src, - void * d_dst, - khm_size * cbd_dst); - -khm_int32 KHMAPI kcdb_type_string_toString( - const void * d, - khm_size cbd, - wchar_t * buffer, - khm_size * cb_buf, - khm_int32 flags); - -khm_boolean KHMAPI kcdb_type_string_isValid( - const void * d, - khm_size cbd); - -khm_int32 KHMAPI kcdb_type_string_comp( - const void * d1, - khm_size cbd1, - const void * d2, - khm_size cbd2); - -khm_int32 KHMAPI kcdb_type_string_dup( - const void * d_src, - khm_size cbd_src, - void * d_dst, - khm_size * cbd_dst); - -khm_int32 KHMAPI kcdb_type_date_toString( - const void * d, - khm_size cbd, - wchar_t * buffer, - khm_size * cb_buf, - khm_int32 flags); - -khm_boolean KHMAPI kcdb_type_date_isValid( - const void * d, - khm_size cbd); - -khm_int32 KHMAPI kcdb_type_date_comp( - const void * d1, - khm_size cbd1, - const void * d2, - khm_size cbd2); - -khm_int32 KHMAPI kcdb_type_date_dup( - const void * d_src, - khm_size cbd_src, - void * d_dst, - khm_size * cbd_dst); - -khm_int32 KHMAPI kcdb_type_interval_toString( - const void * d, - khm_size cbd, - wchar_t * buffer, - khm_size * cb_buf, - khm_int32 flags); - -khm_boolean KHMAPI kcdb_type_interval_isValid( - const void * d, - khm_size cbd); - -khm_int32 KHMAPI kcdb_type_interval_comp( - const void * d1, - khm_size cbd1, - const void * d2, - khm_size cbd2); - -khm_int32 KHMAPI kcdb_type_interval_dup( - const void * d_src, - khm_size cbd_src, - void * d_dst, - khm_size * cbd_dst); - -khm_int32 KHMAPI kcdb_type_int32_toString( - const void * d, - khm_size cbd, - wchar_t * buffer, - khm_size * cb_buf, - khm_int32 flags); - -khm_boolean KHMAPI kcdb_type_int32_isValid( - const void * d, - khm_size cbd); - -khm_int32 KHMAPI kcdb_type_int32_comp( - const void * d1, - khm_size cbd1, - const void * d2, - khm_size cbd2); - -khm_int32 KHMAPI kcdb_type_int32_dup( - const void * d_src, - khm_size cbd_src, - void * d_dst, - khm_size * cbd_dst); - -khm_int32 KHMAPI kcdb_type_int64_toString( - const void * d, - khm_size cbd, - wchar_t * buffer, - khm_size * cb_buf, - khm_int32 flags); - -khm_boolean KHMAPI kcdb_type_int64_isValid( - const void * d, - khm_size cbd); - -khm_int32 KHMAPI kcdb_type_int64_comp( - const void * d1, - khm_size cbd1, - const void * d2, - khm_size cbd2); - -khm_int32 KHMAPI kcdb_type_int64_dup( - const void * d_src, - khm_size cbd_src, - void * d_dst, - khm_size * cbd_dst); - -khm_int32 KHMAPI kcdb_type_data_toString( - const void * d, - khm_size cbd, - wchar_t * buffer, - khm_size * cb_buf, - khm_int32 flags); - -khm_boolean KHMAPI kcdb_type_data_isValid( - const void * d, - khm_size cbd); - -khm_int32 KHMAPI kcdb_type_data_comp( - const void * d1, - khm_size cbd1, - const void * d2, - khm_size cbd2); - -khm_int32 KHMAPI kcdb_type_data_dup( - const void * d_src, - khm_size cbd_src, - void * d_dst, - khm_size * cbd_dst); - -#endif +/* + * 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_KCDB_TYPE_H +#define __KHIMAIRA_KCDB_TYPE_H + +/* Types */ + +typedef struct kcdb_type_i_t { + kcdb_type type; + + khm_int32 refcount; + + struct kcdb_type_i_t * next; + struct kcdb_type_i_t * prev; +} kcdb_type_i; + +#define KCDB_TYPE_HASH_SIZE 31 + +#define KCDB_TYPE_FLAG_DELETED 8 + +void kcdb_type_init(void); +void kcdb_type_exit(void); +void kcdb_type_add_ref(const void *key, void *vt); +void kcdb_type_del_ref(const void *key, void *vt); +void kcdb_type_msg_completion(kmq_message * m); +khm_int32 kcdb_type_hold(kcdb_type_i * t); +khm_int32 kcdb_type_release(kcdb_type_i * t); +void kcdb_type_check_and_delete(khm_int32 id); +void kcdb_type_post_message(khm_int32 op, kcdb_type_i * t); + +khm_int32 KHMAPI kcdb_type_void_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags); + +khm_boolean KHMAPI kcdb_type_void_isValid( + const void * d, + khm_size cbd); + +khm_int32 KHMAPI kcdb_type_void_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2); + +khm_int32 KHMAPI kcdb_type_void_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst); + +khm_int32 KHMAPI kcdb_type_string_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags); + +khm_boolean KHMAPI kcdb_type_string_isValid( + const void * d, + khm_size cbd); + +khm_int32 KHMAPI kcdb_type_string_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2); + +khm_int32 KHMAPI kcdb_type_string_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst); + +khm_int32 KHMAPI kcdb_type_date_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags); + +khm_boolean KHMAPI kcdb_type_date_isValid( + const void * d, + khm_size cbd); + +khm_int32 KHMAPI kcdb_type_date_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2); + +khm_int32 KHMAPI kcdb_type_date_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst); + +khm_int32 KHMAPI kcdb_type_interval_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags); + +khm_boolean KHMAPI kcdb_type_interval_isValid( + const void * d, + khm_size cbd); + +khm_int32 KHMAPI kcdb_type_interval_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2); + +khm_int32 KHMAPI kcdb_type_interval_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst); + +khm_int32 KHMAPI kcdb_type_int32_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags); + +khm_boolean KHMAPI kcdb_type_int32_isValid( + const void * d, + khm_size cbd); + +khm_int32 KHMAPI kcdb_type_int32_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2); + +khm_int32 KHMAPI kcdb_type_int32_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst); + +khm_int32 KHMAPI kcdb_type_int64_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags); + +khm_boolean KHMAPI kcdb_type_int64_isValid( + const void * d, + khm_size cbd); + +khm_int32 KHMAPI kcdb_type_int64_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2); + +khm_int32 KHMAPI kcdb_type_int64_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst); + +khm_int32 KHMAPI kcdb_type_data_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags); + +khm_boolean KHMAPI kcdb_type_data_isValid( + const void * d, + khm_size cbd); + +khm_int32 KHMAPI kcdb_type_data_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2); + +khm_int32 KHMAPI kcdb_type_data_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst); + +#endif diff --git a/src/windows/identity/kherr/kherr.c b/src/windows/identity/kherr/kherr.c index feecbe06c..d9fdf2d49 100644 --- a/src/windows/identity/kherr/kherr.c +++ b/src/windows/identity/kherr/kherr.c @@ -1,1321 +1,1321 @@ -/* - * 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 - -CRITICAL_SECTION cs_error; -DWORD tls_error = 0; -kherr_context * ctx_free_list = NULL; -kherr_context * ctx_root_list = NULL; -kherr_context * ctx_error_list = NULL; -kherr_event * evt_free_list = NULL; - -kherr_handler_node * ctx_handlers = NULL; -khm_size n_ctx_handlers; -khm_size nc_ctx_handlers; - -kherr_serial ctx_serial = 0; - -#ifdef DEBUG -#define DEBUG_CONTEXT - -KHMEXP void kherr_debug_printf(wchar_t * fmt, ...) { - va_list vl; - wchar_t buf[1024]; - - va_start(vl, fmt); - StringCbVPrintf(buf, sizeof(buf), fmt, vl); - OutputDebugString(buf); - va_end(vl); -} -#endif - -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); - if( ctx_handlers == NULL) { - nc_ctx_handlers = CTX_ALLOC_INCR; - n_ctx_handlers = 0; - ctx_handlers = PMALLOC(sizeof(*ctx_handlers) * nc_ctx_handlers); - /* No need to initialize */ - } else if (n_ctx_handlers == nc_ctx_handlers) { - khm_size new_nc; - kherr_handler_node * new_ctxs; - - new_nc = nc_ctx_handlers + CTX_ALLOC_INCR; - new_ctxs = PMALLOC(sizeof(*new_ctxs) * new_nc); - memcpy(new_ctxs, ctx_handlers, n_ctx_handlers * sizeof(*new_ctxs)); - - PFREE(ctx_handlers); - ctx_handlers = new_ctxs; - nc_ctx_handlers = new_nc; - } - - if (filter == 0) - filter = KHERR_CTX_BEGIN | - KHERR_CTX_DESCRIBE | - KHERR_CTX_END | - KHERR_CTX_ERROR; - - /* 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++; - - LeaveCriticalSection(&cs_error); -} - -KHMEXP void KHMAPI kherr_remove_ctx_handler(kherr_ctx_handler h, - kherr_serial serial) { - khm_size i; - EnterCriticalSection(&cs_error); - - for (i=0 ; i < n_ctx_handlers; i++) { - if (ctx_handlers[i].h == h && - ctx_handlers[i].serial == serial) { - break; - } - } - - if ( i < n_ctx_handlers ) { - n_ctx_handlers --; - for (; i < n_ctx_handlers; i++) { - ctx_handlers[i] = ctx_handlers[i + 1]; - } - } - - LeaveCriticalSection(&cs_error); -} - -/* Called with cs_error held */ -void notify_ctx_event(enum kherr_ctx_event e, kherr_context * c) { - khm_size i; - - kherr_ctx_handler h; - - for (i=0; iserial)) { - if (IsBadCodePtr((FARPROC) ctx_handlers[i].h)) { - ctx_handlers[i].h = NULL; - } else { - h = ctx_handlers[i].h; - (*h)(e,c); - - /* a context handler is allowed to remove itself - during a callback. It is, however, not allowed to - remove anything else. */ - 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; - } - } -} - -void attach_this_thread(void) { - kherr_thread * t; - - t = (kherr_thread *) TlsGetValue(tls_error); - if (t) - return; - - t = PMALLOC(sizeof(kherr_thread) + - sizeof(kherr_context *) * THREAD_STACK_SIZE); - t->nc_ctx = THREAD_STACK_SIZE; - t->n_ctx = 0; - t->ctx = (kherr_context **) &t[1]; - - TlsSetValue(tls_error, t); -} - -void detach_this_thread(void) { - kherr_thread * t; - khm_size i; - - t = (kherr_thread *) TlsGetValue(tls_error); - if (t) { - for(i=0; i < t->n_ctx; i++) { - kherr_release_context(t->ctx[i]); - } - PFREE(t); - TlsSetValue(tls_error, 0); - } -} - -kherr_context * peek_context(void) { - kherr_thread * t; - - t = (kherr_thread *) TlsGetValue(tls_error); - if (t) { - if (t->n_ctx > 0) - return t->ctx[t->n_ctx - 1]; - else - return NULL; - } else - return NULL; -} - -void push_context(kherr_context * c) { - kherr_thread * t; - - t = (kherr_thread *) TlsGetValue(tls_error); - if (!t) { - attach_this_thread(); - t = (kherr_thread *) TlsGetValue(tls_error); - assert(t); - } - - if (t->n_ctx == t->nc_ctx) { - khm_size nc_new; - khm_size cb_new; - kherr_thread * nt; - - nc_new = t->nc_ctx + THREAD_STACK_SIZE; - cb_new = sizeof(kherr_thread) + - sizeof(kherr_context *) * nc_new; - - nt = PMALLOC(cb_new); - memcpy(nt, t, sizeof(kherr_thread) + - sizeof(kherr_context *) * t->n_ctx); - nt->ctx = (kherr_context **) &nt[1]; - nt->nc_ctx = nc_new; - - PFREE(t); - t = nt; - TlsSetValue(tls_error, t); - } - - assert(t->n_ctx < t->nc_ctx); - t->ctx[t->n_ctx++] = c; - - kherr_hold_context(c); -} - -/* returned pointer is still held */ -kherr_context * pop_context(void) { - kherr_thread * t; - kherr_context * c; - - t = (kherr_thread *) TlsGetValue(tls_error); - if (t) { - if (t->n_ctx > 0) { - c = t->ctx[--(t->n_ctx)]; - return c; - } else - return NULL; - } else { - return NULL; - } -} - -kherr_event * get_empty_event(void) { - kherr_event * e; - - EnterCriticalSection(&cs_error); - if(evt_free_list) { - LPOP(&evt_free_list, &e); - } else { - e = PMALLOC(sizeof(*e)); - } - LeaveCriticalSection(&cs_error); - ZeroMemory(e, sizeof(*e)); - e->severity = KHERR_NONE; - e->magic = KHERR_EVENT_MAGIC; - - return e; -} - -void free_event_params(kherr_event * e) { - if(parm_type(e->p1) == KEPT_STRINGT) { - assert((void *) parm_data(e->p1)); - PFREE((void*) parm_data(e->p1)); - ZeroMemory(&e->p1, sizeof(e->p1)); - } - if(parm_type(e->p2) == KEPT_STRINGT) { - assert((void *) parm_data(e->p2)); - PFREE((void*) parm_data(e->p2)); - ZeroMemory(&e->p2, sizeof(e->p2)); - } - if(parm_type(e->p3) == KEPT_STRINGT) { - assert((void *) parm_data(e->p3)); - PFREE((void*) parm_data(e->p3)); - ZeroMemory(&e->p3, sizeof(e->p3)); - } - if(parm_type(e->p4) == KEPT_STRINGT) { - assert((void *) parm_data(e->p4)); - PFREE((void*) parm_data(e->p4)); - ZeroMemory(&e->p4, sizeof(e->p4)); - } -} - -void free_event(kherr_event * e) { - - EnterCriticalSection(&cs_error); - - assert(e->magic == KHERR_EVENT_MAGIC); - -#ifdef DEBUG_CONTEXT - kherr_debug_printf(L"Freeing event 0x%x\n", e); - if (!(e->flags & KHERR_RF_STR_RESOLVED)) - resolve_event_strings(e); - if (e->short_desc) - kherr_debug_printf(L" Desc(S):[%s]\n", e->short_desc); - if (e->long_desc) - kherr_debug_printf(L" Desc(L):[%s]\n", e->long_desc); - if (e->suggestion) - kherr_debug_printf(L" Suggest:[%s]\n", e->suggestion); - if (e->facility) - kherr_debug_printf(L" Facility:[%s]\n", e->facility); -#endif - - if(e->flags & KHERR_RF_FREE_SHORT_DESC) { - assert(e->short_desc); - PFREE((void *) e->short_desc); - } - if(e->flags & KHERR_RF_FREE_LONG_DESC) { - assert(e->long_desc); - PFREE((void *) e->long_desc); - } - if(e->flags & KHERR_RF_FREE_SUGGEST) { - assert(e->suggestion); - PFREE((void *) e->suggestion); - } - - free_event_params(e); - - ZeroMemory(e, sizeof(e)); - - LPUSH(&evt_free_list, e); - LeaveCriticalSection(&cs_error); -} - -kherr_context * get_empty_context(void) { - kherr_context * c; - - EnterCriticalSection(&cs_error); - if(ctx_free_list) - LPOP(&ctx_free_list, &c); - else { - c = PMALLOC(sizeof(kherr_context)); - } - - ZeroMemory(c,sizeof(*c)); - c->severity = KHERR_NONE; - c->flags = KHERR_CF_UNBOUND; - c->magic = KHERR_CONTEXT_MAGIC; - c->serial = ++ctx_serial; - - LPUSH(&ctx_root_list, c); - - LeaveCriticalSection(&cs_error); - - return c; -} - - -/* Assumes that the context has been deleted from all relevant - lists */ -void free_context(kherr_context * c) { - kherr_context * ch; - kherr_event * e; - - assert(c->magic == KHERR_CONTEXT_MAGIC); -#ifdef DEBUG_CONTEXT - kherr_debug_printf(L"Freeing context 0x%x\n", c); -#endif - - EnterCriticalSection(&cs_error); - - if (c->desc_event) - free_event(c->desc_event); - c->desc_event = NULL; - - TPOPCHILD(c, &ch); - while(ch) { - free_context(ch); - TPOPCHILD(c, &ch); - } - QGET(c, &e); - while(e) { - free_event(e); - QGET(c, &e); - } - - c->serial = 0; - - LPUSH(&ctx_free_list,c); - LeaveCriticalSection(&cs_error); - -#ifdef DEBUG_CONTEXT - kherr_debug_printf(L"Done with context 0x%x\n", c); -#endif -} - -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) - notify_ctx_event(KHERR_CTX_ERROR, c); - - c->severity = e->severity; - c->err_event = e; - c->flags &= ~KHERR_CF_DIRTY; - } - LeaveCriticalSection(&cs_error); -} - -void pick_err_event(kherr_context * c) -{ - kherr_event * e; - kherr_event * ce = NULL; - enum kherr_severity s; - - s = KHERR_RESERVED_BANK; - - EnterCriticalSection(&cs_error); - e = QTOP(c); - while(e) { - if(!(e->flags & KHERR_RF_INERT) && - s >= e->severity) { - ce = e; - s = e->severity; - } - e = QNEXT(e); - } - - if(ce) { - c->err_event = ce; - c->severity = ce->severity; - } else { - c->err_event = NULL; - c->severity = KHERR_NONE; - } - - c->flags &= ~KHERR_CF_DIRTY; - LeaveCriticalSection(&cs_error); -} - -static void arg_from_param(DWORD_PTR ** parm, kherr_param p) { - int t; - - if (p.type != KEPT_NONE) { - t = parm_type(p); - if (t == KEPT_INT32 || - t == KEPT_UINT32 || - t == KEPT_STRINGC || - t == KEPT_STRINGT || - t == KEPT_PTR) { - - *(*parm)++ = (DWORD_PTR) parm_data(p); - - } else if (t == KEPT_INT64 || - t == KEPT_UINT64) { - *(*parm)++ = (DWORD_PTR) parm_data(p) & 0xffffffff; - *(*parm)++ = (DWORD_PTR) (parm_data(p) >> 32) & 0xffffffff; - } else - *(*parm)++ = 0; - } -} - -/* The 'buf' parameter MUST point to a DWORD_PTR[8] array */ -static void args_from_event(DWORD_PTR * buf, kherr_event * e) { - arg_from_param(&buf, e->p1); - arg_from_param(&buf, e->p2); - arg_from_param(&buf, e->p3); - arg_from_param(&buf, e->p4); -} - -static void resolve_string_resource(kherr_event * e, - const wchar_t ** str, - khm_int32 if_flag, - khm_int32 or_flag) { - wchar_t tfmt[KHERR_MAXCCH_STRING]; - wchar_t tbuf[KHERR_MAXCCH_STRING]; - size_t chars = 0; - size_t bytes = 0; - - if(e->flags & if_flag) { - if(e->h_module != NULL) - chars = LoadString(e->h_module, (UINT)(INT_PTR) *str, - tfmt, ARRAYLENGTH(tbuf)); - if(e->h_module == NULL || chars == 0) - *str = NULL; - else { - wchar_t * s; - DWORD_PTR args[8]; - - args_from_event(args, e); - - chars = FormatMessage(FORMAT_MESSAGE_FROM_STRING | - FORMAT_MESSAGE_ARGUMENT_ARRAY, - tfmt, - 0, - 0, - tbuf, - ARRAYLENGTH(tbuf), - (va_list *) args); - - if (chars == 0) { - *str = NULL; - } else { - bytes = (chars + 1) * sizeof(wchar_t); - s = PMALLOC(bytes); - assert(s); - StringCbCopy(s, bytes, tbuf); - *str = s; - e->flags |= or_flag; - } - } - e->flags &= ~if_flag; - } -} - -static void resolve_msg_resource(kherr_event * e, - const wchar_t ** str, - khm_int32 if_flag, - khm_int32 or_flag) { - wchar_t tbuf[KHERR_MAXCCH_STRING]; - size_t chars = 0; - size_t bytes = 0; - DWORD_PTR args[8]; - - if(e->flags & if_flag) { - if(e->h_module != NULL) { - args_from_event(args, e); - - chars = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | - FORMAT_MESSAGE_ARGUMENT_ARRAY, - (LPCVOID) e->h_module, - (DWORD)(DWORD_PTR) *str, - 0, - tbuf, - ARRAYLENGTH(tbuf), - (va_list *) args); - } - - if(e->h_module == NULL || chars == 0) { - *str = NULL; - } else { - wchar_t * s; - - /* MC inserts trailing \r\n to each message unless the - message is terminated with a %0. We remove the last - line break since it is irrelevant to our handling of - the string in the UI. */ - if (tbuf[chars-1] == L'\n') - tbuf[--chars] = L'\0'; - if (tbuf[chars-1] == L'\r') - tbuf[--chars] = L'\0'; - - bytes = (chars + 1) * sizeof(wchar_t); - s = PMALLOC(bytes); - assert(s); - StringCbCopy(s, bytes, tbuf); - *str = s; - e->flags |= or_flag; - } - e->flags &= ~if_flag; - } -} - -static void resolve_string(kherr_event * e, - const wchar_t ** str, - khm_int32 mask, - khm_int32 free_if, - khm_int32 or_flag) { - - wchar_t tbuf[KHERR_MAXCCH_STRING]; - size_t chars; - size_t bytes; - DWORD_PTR args[8]; - - if (((e->flags & mask) == 0 || - (e->flags & mask) == free_if) && - *str != NULL) { - - args_from_event(args, e); - chars = FormatMessage(FORMAT_MESSAGE_FROM_STRING | - FORMAT_MESSAGE_ARGUMENT_ARRAY, - (LPCVOID) *str, - 0, - 0, - tbuf, - ARRAYLENGTH(tbuf), - (va_list *) args); - - if ((e->flags & mask) == free_if) { - PFREE((void *) *str); - } - - e->flags &= ~mask; - - if (chars == 0) { - *str = 0; - } else { - wchar_t * s; - - bytes = (chars + 1) * sizeof(wchar_t); - s = PMALLOC(bytes); - assert(s); - StringCbCopy(s, bytes, tbuf); - *str = s; - e->flags |= or_flag; - } - } - -} - -void resolve_event_strings(kherr_event * e) -{ - resolve_string(e, &e->short_desc, - KHERR_RFMASK_SHORT_DESC, - KHERR_RF_FREE_SHORT_DESC, - KHERR_RF_FREE_SHORT_DESC); - - resolve_string(e, &e->long_desc, - KHERR_RFMASK_LONG_DESC, - KHERR_RF_FREE_LONG_DESC, - KHERR_RF_FREE_LONG_DESC); - - resolve_string(e, &e->suggestion, - KHERR_RFMASK_SUGGEST, - KHERR_RF_FREE_SUGGEST, - KHERR_RF_FREE_SUGGEST); - - resolve_string_resource(e, &e->short_desc, - KHERR_RF_RES_SHORT_DESC, - KHERR_RF_FREE_SHORT_DESC); - - resolve_string_resource(e, &e->long_desc, - KHERR_RF_RES_LONG_DESC, - KHERR_RF_FREE_LONG_DESC); - - resolve_string_resource(e, &e->suggestion, - KHERR_RF_RES_SUGGEST, - KHERR_RF_FREE_SUGGEST); - - resolve_msg_resource(e, &e->short_desc, - KHERR_RF_MSG_SHORT_DESC, - KHERR_RF_FREE_SHORT_DESC); - resolve_msg_resource(e, &e->long_desc, - KHERR_RF_MSG_LONG_DESC, - KHERR_RF_FREE_LONG_DESC); - resolve_msg_resource(e, &e->suggestion, - KHERR_RF_MSG_SUGGEST, - KHERR_RF_FREE_SUGGEST); - - /* get rid of dangling reference now that we have done everything - we can with it. Since we have already dealt with all the - parameter inserts, we don't need the parameters anymore - either. */ - free_event_params(e); - - e->h_module = NULL; - e->flags |= KHERR_RF_STR_RESOLVED; -} - - -KHMEXP void KHMAPI kherr_evaluate_event(kherr_event * e) { - if (!e) - return; - - EnterCriticalSection(&cs_error); - resolve_event_strings(e); - LeaveCriticalSection(&cs_error); -} - -KHMEXP void KHMAPI kherr_evaluate_last_event(void) { - kherr_context * c; - kherr_event * e; - DWORD tid; - - c = peek_context(); - if(!c) - return; - tid = GetCurrentThreadId(); - - EnterCriticalSection(&cs_error); - e = QBOTTOM(c); - while (e != NULL && e->thread_id != tid) - e = QPREV(e); - - if(!e) - goto _exit; - - resolve_event_strings(e); - - _exit: - LeaveCriticalSection(&cs_error); -} - -KHMEXP kherr_event * __cdecl -kherr_reportf(const wchar_t * long_desc_fmt, ...) { - va_list vl; - wchar_t buf[1024]; - kherr_event * e; - - va_start(vl, long_desc_fmt); - StringCbVPrintf(buf, sizeof(buf), long_desc_fmt, vl); -#ifdef DEBUG - OutputDebugString(buf); -#endif - va_end(vl); - - e = kherr_report(KHERR_DEBUG_1, - NULL, NULL, NULL, buf, NULL, 0, - KHERR_SUGGEST_NONE, _vnull(), _vnull(), _vnull(), _vnull(), - KHERR_RF_CSTR_LONG_DESC -#ifdef _WIN32 - ,NULL -#endif - ); - if (e) { - kherr_evaluate_event(e); - } - - return e; -} - -KHMEXP kherr_event * __cdecl -kherr_reportf_ex(enum kherr_severity severity, - const wchar_t * facility, - khm_int32 facility_id, -#ifdef _WIN32 - HMODULE hModule, -#endif - const wchar_t * long_desc_fmt, ...) { - va_list vl; - wchar_t buf[1024]; - kherr_event * e; - - va_start(vl, long_desc_fmt); - StringCbVPrintf(buf, sizeof(buf), long_desc_fmt, vl); -#ifdef DEBUG - OutputDebugString(buf); -#endif - va_end(vl); - - e = kherr_report(severity, NULL, facility, NULL, buf, NULL, facility_id, - KHERR_SUGGEST_NONE, - _vnull(), - _vnull(), - _vnull(), - _vnull(), KHERR_RF_CSTR_LONG_DESC -#ifdef _WIN32 - ,hModule -#endif - ); - if (e) { - kherr_evaluate_event(e); - } - - return e; -} - -KHMEXP kherr_event * KHMAPI -kherr_report(enum kherr_severity severity, - const wchar_t * short_desc, - const wchar_t * facility, - const wchar_t * location, - const wchar_t * long_desc, - const wchar_t * suggestion, - khm_int32 facility_id, - enum kherr_suggestion suggestion_id, - kherr_param p1, - kherr_param p2, - kherr_param p3, - kherr_param p4, - khm_int32 flags -#ifdef _WIN32 - ,HMODULE h_module -#endif - ) { - kherr_context * c; - kherr_event * e; - - /*TODO: sanity check flags (ISPOW2) */ - - e = get_empty_event(); - - e->thread_id = GetCurrentThreadId(); - e->time_ticks = GetTickCount(); - GetSystemTimeAsFileTime(&e->time_ft); - - e->severity = severity; - e->short_desc = short_desc; - e->facility = facility; - e->location = location; - e->long_desc = long_desc; - e->suggestion = suggestion; - e->facility_id = facility_id; - e->suggestion_id = suggestion_id; - e->p1 = p1; - e->p2 = p2; - e->p3 = p3; - e->p4 = p4; - e->flags = flags; -#ifdef _WIN32 - e->h_module = h_module; -#endif - - EnterCriticalSection(&cs_error); - c = peek_context(); - - if(!c) { - /* the reason why we are doing it this way is because p1..p4, - the descriptions and the suggestion may contain allocations - that has to be freed. */ - free_event(e); - e = NULL; - } else { - add_event(c,e); - } - - LeaveCriticalSection(&cs_error); - - return e; -} - -KHMEXP void KHMAPI kherr_suggest(wchar_t * suggestion, - enum kherr_suggestion suggestion_id, - khm_int32 flags) { - kherr_context * c; - kherr_event * e; - DWORD tid; - - if (flags != KHERR_RF_CSTR_SUGGEST && - flags != KHERR_RF_RES_SUGGEST && - flags != KHERR_RF_MSG_SUGGEST && - flags != KHERR_RF_FREE_SUGGEST) - return; - - c = peek_context(); - if(!c) - return; - - tid = GetCurrentThreadId(); - - EnterCriticalSection(&cs_error); - e = QBOTTOM(c); - while (e != NULL && e->thread_id != tid) - e = QPREV(e); - - if(!e) - goto _exit; - - /* if strings have already been resolved in this event, we cant - add any more unresolved strings. */ - if ((flags == KHERR_RF_RES_SUGGEST || - flags == KHERR_RF_MSG_SUGGEST) && - (e->flags & KHERR_RF_STR_RESOLVED)) - goto _exit; - - e->suggestion = suggestion; - e->suggestion_id = suggestion_id; - e->flags |= flags; -_exit: - LeaveCriticalSection(&cs_error); -} - -KHMEXP void KHMAPI kherr_location(wchar_t * location) { - kherr_context * c; - kherr_event * e; - DWORD tid; - - c = peek_context(); - if(!c) - return; - tid = GetCurrentThreadId(); - - EnterCriticalSection(&cs_error); - e = QBOTTOM(c); - while (e != NULL && e->thread_id != tid) - e = QPREV(e); - - if(!e) - goto _exit; - e->location = location; -_exit: - LeaveCriticalSection(&cs_error); -} - -KHMEXP void KHMAPI kherr_facility(wchar_t * facility, - khm_int32 facility_id) { - kherr_context * c; - kherr_event * e; - DWORD tid; - - c = peek_context(); - if(!c) - return; - tid = GetCurrentThreadId(); - EnterCriticalSection(&cs_error); - e = QBOTTOM(c); - while (e != NULL && e->thread_id != tid) - e = QPREV(e); - - if(!e) - goto _exit; - e->facility = facility; - e->facility_id = facility_id; -_exit: - LeaveCriticalSection(&cs_error); -} - -KHMEXP void KHMAPI kherr_set_desc_event(void) { - kherr_context * c; - kherr_event * e; - DWORD tid; - - c = peek_context(); - if(!c) - return; - tid = GetCurrentThreadId(); - - EnterCriticalSection(&cs_error); - e = QBOTTOM(c); - while (e != NULL && e->thread_id != tid) - e = QPREV(e); - - if(!e || c->desc_event) - goto _exit; - - QDEL(c,e); - c->desc_event = e; - e->severity = KHERR_NONE; - resolve_event_strings(e); - - notify_ctx_event(KHERR_CTX_DESCRIBE, c); - -_exit: - LeaveCriticalSection(&cs_error); -} - -KHMEXP void KHMAPI kherr_del_last_event(void) { - kherr_context * c; - kherr_event * e; - DWORD tid; - - c = peek_context(); - - if(!c) - return; - - tid = GetCurrentThreadId(); - - EnterCriticalSection(&cs_error); - e = QBOTTOM(c); - while (e != NULL && e->thread_id != tid) - e = QPREV(e); - - if(e) { - QDEL(c, e); - if(c->err_event == e) { - pick_err_event(c); - } - free_event(e); - } - LeaveCriticalSection(&cs_error); -} - -KHMEXP void KHMAPI kherr_push_context(kherr_context * c) -{ - kherr_context * p; - int new_context = FALSE; - - EnterCriticalSection(&cs_error); - p = peek_context(); - if(p && (c->flags & KHERR_CF_UNBOUND)) { - LDELETE(&ctx_root_list, c); - TADDCHILD(p,c); - c->flags &= ~KHERR_CF_UNBOUND; - kherr_hold_context(p); - new_context = TRUE; - } - push_context(c); - - if (new_context) - notify_ctx_event(KHERR_CTX_BEGIN, c); - - LeaveCriticalSection(&cs_error); -} - -KHMEXP void KHMAPI kherr_push_new_context(khm_int32 flags) -{ - kherr_context * p; - kherr_context * c; - - flags &= KHERR_CFMASK_INITIAL; - - EnterCriticalSection(&cs_error); - p = peek_context(); - c = get_empty_context(); - if(p) { - LDELETE(&ctx_root_list, c); - TADDCHILD(p,c); - c->flags &= ~KHERR_CF_UNBOUND; - kherr_hold_context(p); - } - c->flags |= flags; - push_context(c); - - notify_ctx_event(KHERR_CTX_BEGIN, c); - - LeaveCriticalSection(&cs_error); -} - -kherr_param dup_parm(kherr_param p) { - if(parm_type(p) == KEPT_STRINGT) { - wchar_t * d = PWCSDUP((wchar_t *)parm_data(p)); - return kherr_val(KEPT_STRINGT, (khm_ui_8) d); - } else - return p; -} - -kherr_event * fold_context(kherr_context * c) { - kherr_event * e; - kherr_event * g; - - if (!c) - return NULL; - - EnterCriticalSection(&cs_error); - if(!c->err_event || (c->flags & KHERR_CF_DIRTY)) { - pick_err_event(c); - } - if(c->err_event) { - g = c->err_event; - e = get_empty_event(); - *e = *g; - g->short_desc = NULL; - g->long_desc = NULL; - g->suggestion = NULL; - g->flags &= - ~(KHERR_RF_FREE_SHORT_DESC | - KHERR_RF_FREE_LONG_DESC | - KHERR_RF_FREE_SUGGEST); - LINIT(e); - e->p1 = dup_parm(g->p1); - e->p2 = dup_parm(g->p2); - e->p3 = dup_parm(g->p3); - e->p4 = dup_parm(g->p4); - } else { - e = c->desc_event; - c->desc_event = NULL; - } - - if (e) - e->flags |= KHERR_RF_CONTEXT_FOLD; - - LeaveCriticalSection(&cs_error); - - return e; -} - -KHMEXP void KHMAPI kherr_hold_context(kherr_context * c) { - assert(c && c->magic == KHERR_CONTEXT_MAGIC); - EnterCriticalSection(&cs_error); - c->refcount++; - LeaveCriticalSection(&cs_error); -} - -KHMEXP void KHMAPI kherr_release_context(kherr_context * c) { - assert(c && c->magic == KHERR_CONTEXT_MAGIC); - EnterCriticalSection(&cs_error); - c->refcount--; - if (c->refcount == 0) { - 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); - if (p) { - e = fold_context(c); - if (e) - add_event(p, e); - - TDELCHILD(p, c); - kherr_release_context(p); - } else { - LDELETE(&ctx_root_list, c); - } - free_context(c); - } - LeaveCriticalSection(&cs_error); -} - -KHMEXP void KHMAPI kherr_pop_context(void) { - kherr_context * c; - - EnterCriticalSection(&cs_error); - c = pop_context(); - if(c) { - kherr_release_context(c); - } - LeaveCriticalSection(&cs_error); -} - -KHMEXP kherr_context * KHMAPI kherr_peek_context(void) { - kherr_context * c; - - c = peek_context(); - if (c) - kherr_hold_context(c); - - return c; -} - -KHMEXP khm_boolean KHMAPI kherr_is_error(void) { - kherr_context * c = peek_context(); - return kherr_is_error_i(c); -} - -KHMEXP khm_boolean KHMAPI kherr_is_error_i(kherr_context * c) { - if(c && c->severity <= KHERR_ERROR) - return TRUE; - else - return FALSE; -} - -KHMEXP void KHMAPI kherr_clear_error(void) { - kherr_context * c = peek_context(); - if (c) - kherr_clear_error_i(c); -} - -KHMEXP void KHMAPI kherr_clear_error_i(kherr_context * c) { - kherr_event * e; - if (c) { - EnterCriticalSection(&cs_error); - e = QTOP(c); - while(e) { - e->flags |= KHERR_RF_INERT; - e = QNEXT(e); - } - c->severity = KHERR_NONE; - c->err_event = NULL; - c->flags &= ~KHERR_CF_DIRTY; - LeaveCriticalSection(&cs_error); - } -} - -KHMEXP void KHMAPI kherr_set_progress(khm_ui_4 num, khm_ui_4 denom) { - kherr_context * c = peek_context(); - if(c) { - EnterCriticalSection(&cs_error); - c->progress_denom = denom; - c->progress_num = num; - LeaveCriticalSection(&cs_error); - } -} - -KHMEXP void KHMAPI kherr_get_progress(khm_ui_4 * num, khm_ui_4 * denom) { - kherr_context * c = peek_context(); - kherr_get_progress_i(c,num,denom); -} - -KHMEXP void KHMAPI kherr_get_progress_i(kherr_context * c, - khm_ui_4 * num, - khm_ui_4 * denom) { - if(c) { - EnterCriticalSection(&cs_error); - *num = c->progress_num; - *denom = c->progress_denom; - LeaveCriticalSection(&cs_error); - } else { - *num = 0; - *denom = 0; - } -} - -KHMEXP kherr_event * KHMAPI kherr_get_first_event(kherr_context * c) -{ - kherr_event * e; - EnterCriticalSection(&cs_error); - e = QTOP(c); - LeaveCriticalSection(&cs_error); - return e; -} - -KHMEXP kherr_event * KHMAPI kherr_get_next_event(kherr_event * e) -{ - kherr_event * ee; - - EnterCriticalSection(&cs_error); - ee = QNEXT(e); - LeaveCriticalSection(&cs_error); - 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; - - EnterCriticalSection(&cs_error); - if (c) { - cc = TFIRSTCHILD(c); - if (cc) - kherr_hold_context(cc); - } else { - cc = ctx_root_list; - if (cc) - kherr_hold_context(cc); - } - LeaveCriticalSection(&cs_error); - return cc; -} - -KHMEXP kherr_context * KHMAPI kherr_get_next_context(kherr_context * c) -{ - kherr_context * cc; - EnterCriticalSection(&cs_error); - cc = LNEXT(c); - if (cc) - kherr_hold_context(cc); - LeaveCriticalSection(&cs_error); - return cc; -} - -KHMEXP kherr_event * KHMAPI kherr_get_err_event(kherr_context * c) -{ - kherr_event * e; - EnterCriticalSection(&cs_error); - if(!c->err_event) { - pick_err_event(c); - } - e = c->err_event; - LeaveCriticalSection(&cs_error); - return e; -} - -KHMEXP kherr_event * KHMAPI kherr_get_desc_event(kherr_context * c) -{ - kherr_event * e; - - EnterCriticalSection(&cs_error); - e = c->desc_event; - LeaveCriticalSection(&cs_error); - return e; -} - -KHMEXP kherr_param kherr_dup_string(const wchar_t * s) -{ - wchar_t * dest; - size_t cb_s; - - if (s == NULL) - return _vnull(); - - if (FAILED(StringCbLength(s, KHERR_MAXCB_STRING, &cb_s))) - cb_s = KHERR_MAXCB_STRING; - else - cb_s += sizeof(wchar_t); - - dest = PMALLOC(cb_s); - assert(dest != NULL); - dest[0] = L'\0'; - - StringCbCopy(dest, cb_s, s); - - return _tstr(dest); -} - - -#if 0 -KHMEXP kherr_param kherr_val(khm_octet ptype, khm_ui_8 pvalue) { - kherr_param p; - p.type = ptype; - p.data = pvalue; - - return p; -} -#endif +/* + * 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 + +CRITICAL_SECTION cs_error; +DWORD tls_error = 0; +kherr_context * ctx_free_list = NULL; +kherr_context * ctx_root_list = NULL; +kherr_context * ctx_error_list = NULL; +kherr_event * evt_free_list = NULL; + +kherr_handler_node * ctx_handlers = NULL; +khm_size n_ctx_handlers; +khm_size nc_ctx_handlers; + +kherr_serial ctx_serial = 0; + +#ifdef DEBUG +#define DEBUG_CONTEXT + +KHMEXP void kherr_debug_printf(wchar_t * fmt, ...) { + va_list vl; + wchar_t buf[1024]; + + va_start(vl, fmt); + StringCbVPrintf(buf, sizeof(buf), fmt, vl); + OutputDebugString(buf); + va_end(vl); +} +#endif + +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); + if( ctx_handlers == NULL) { + nc_ctx_handlers = CTX_ALLOC_INCR; + n_ctx_handlers = 0; + ctx_handlers = PMALLOC(sizeof(*ctx_handlers) * nc_ctx_handlers); + /* No need to initialize */ + } else if (n_ctx_handlers == nc_ctx_handlers) { + khm_size new_nc; + kherr_handler_node * new_ctxs; + + new_nc = nc_ctx_handlers + CTX_ALLOC_INCR; + new_ctxs = PMALLOC(sizeof(*new_ctxs) * new_nc); + memcpy(new_ctxs, ctx_handlers, n_ctx_handlers * sizeof(*new_ctxs)); + + PFREE(ctx_handlers); + ctx_handlers = new_ctxs; + nc_ctx_handlers = new_nc; + } + + if (filter == 0) + filter = KHERR_CTX_BEGIN | + KHERR_CTX_DESCRIBE | + KHERR_CTX_END | + KHERR_CTX_ERROR; + + /* 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++; + + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_remove_ctx_handler(kherr_ctx_handler h, + kherr_serial serial) { + khm_size i; + EnterCriticalSection(&cs_error); + + for (i=0 ; i < n_ctx_handlers; i++) { + if (ctx_handlers[i].h == h && + ctx_handlers[i].serial == serial) { + break; + } + } + + if ( i < n_ctx_handlers ) { + n_ctx_handlers --; + for (; i < n_ctx_handlers; i++) { + ctx_handlers[i] = ctx_handlers[i + 1]; + } + } + + LeaveCriticalSection(&cs_error); +} + +/* Called with cs_error held */ +void notify_ctx_event(enum kherr_ctx_event e, kherr_context * c) { + khm_size i; + + kherr_ctx_handler h; + + for (i=0; iserial)) { + if (IsBadCodePtr((FARPROC) ctx_handlers[i].h)) { + ctx_handlers[i].h = NULL; + } else { + h = ctx_handlers[i].h; + (*h)(e,c); + + /* a context handler is allowed to remove itself + during a callback. It is, however, not allowed to + remove anything else. */ + 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; + } + } +} + +void attach_this_thread(void) { + kherr_thread * t; + + t = (kherr_thread *) TlsGetValue(tls_error); + if (t) + return; + + t = PMALLOC(sizeof(kherr_thread) + + sizeof(kherr_context *) * THREAD_STACK_SIZE); + t->nc_ctx = THREAD_STACK_SIZE; + t->n_ctx = 0; + t->ctx = (kherr_context **) &t[1]; + + TlsSetValue(tls_error, t); +} + +void detach_this_thread(void) { + kherr_thread * t; + khm_size i; + + t = (kherr_thread *) TlsGetValue(tls_error); + if (t) { + for(i=0; i < t->n_ctx; i++) { + kherr_release_context(t->ctx[i]); + } + PFREE(t); + TlsSetValue(tls_error, 0); + } +} + +kherr_context * peek_context(void) { + kherr_thread * t; + + t = (kherr_thread *) TlsGetValue(tls_error); + if (t) { + if (t->n_ctx > 0) + return t->ctx[t->n_ctx - 1]; + else + return NULL; + } else + return NULL; +} + +void push_context(kherr_context * c) { + kherr_thread * t; + + t = (kherr_thread *) TlsGetValue(tls_error); + if (!t) { + attach_this_thread(); + t = (kherr_thread *) TlsGetValue(tls_error); + assert(t); + } + + if (t->n_ctx == t->nc_ctx) { + khm_size nc_new; + khm_size cb_new; + kherr_thread * nt; + + nc_new = t->nc_ctx + THREAD_STACK_SIZE; + cb_new = sizeof(kherr_thread) + + sizeof(kherr_context *) * nc_new; + + nt = PMALLOC(cb_new); + memcpy(nt, t, sizeof(kherr_thread) + + sizeof(kherr_context *) * t->n_ctx); + nt->ctx = (kherr_context **) &nt[1]; + nt->nc_ctx = nc_new; + + PFREE(t); + t = nt; + TlsSetValue(tls_error, t); + } + + assert(t->n_ctx < t->nc_ctx); + t->ctx[t->n_ctx++] = c; + + kherr_hold_context(c); +} + +/* returned pointer is still held */ +kherr_context * pop_context(void) { + kherr_thread * t; + kherr_context * c; + + t = (kherr_thread *) TlsGetValue(tls_error); + if (t) { + if (t->n_ctx > 0) { + c = t->ctx[--(t->n_ctx)]; + return c; + } else + return NULL; + } else { + return NULL; + } +} + +kherr_event * get_empty_event(void) { + kherr_event * e; + + EnterCriticalSection(&cs_error); + if(evt_free_list) { + LPOP(&evt_free_list, &e); + } else { + e = PMALLOC(sizeof(*e)); + } + LeaveCriticalSection(&cs_error); + ZeroMemory(e, sizeof(*e)); + e->severity = KHERR_NONE; + e->magic = KHERR_EVENT_MAGIC; + + return e; +} + +void free_event_params(kherr_event * e) { + if(parm_type(e->p1) == KEPT_STRINGT) { + assert((void *) parm_data(e->p1)); + PFREE((void*) parm_data(e->p1)); + ZeroMemory(&e->p1, sizeof(e->p1)); + } + if(parm_type(e->p2) == KEPT_STRINGT) { + assert((void *) parm_data(e->p2)); + PFREE((void*) parm_data(e->p2)); + ZeroMemory(&e->p2, sizeof(e->p2)); + } + if(parm_type(e->p3) == KEPT_STRINGT) { + assert((void *) parm_data(e->p3)); + PFREE((void*) parm_data(e->p3)); + ZeroMemory(&e->p3, sizeof(e->p3)); + } + if(parm_type(e->p4) == KEPT_STRINGT) { + assert((void *) parm_data(e->p4)); + PFREE((void*) parm_data(e->p4)); + ZeroMemory(&e->p4, sizeof(e->p4)); + } +} + +void free_event(kherr_event * e) { + + EnterCriticalSection(&cs_error); + + assert(e->magic == KHERR_EVENT_MAGIC); + +#ifdef DEBUG_CONTEXT + kherr_debug_printf(L"Freeing event 0x%x\n", e); + if (!(e->flags & KHERR_RF_STR_RESOLVED)) + resolve_event_strings(e); + if (e->short_desc) + kherr_debug_printf(L" Desc(S):[%s]\n", e->short_desc); + if (e->long_desc) + kherr_debug_printf(L" Desc(L):[%s]\n", e->long_desc); + if (e->suggestion) + kherr_debug_printf(L" Suggest:[%s]\n", e->suggestion); + if (e->facility) + kherr_debug_printf(L" Facility:[%s]\n", e->facility); +#endif + + if(e->flags & KHERR_RF_FREE_SHORT_DESC) { + assert(e->short_desc); + PFREE((void *) e->short_desc); + } + if(e->flags & KHERR_RF_FREE_LONG_DESC) { + assert(e->long_desc); + PFREE((void *) e->long_desc); + } + if(e->flags & KHERR_RF_FREE_SUGGEST) { + assert(e->suggestion); + PFREE((void *) e->suggestion); + } + + free_event_params(e); + + ZeroMemory(e, sizeof(e)); + + LPUSH(&evt_free_list, e); + LeaveCriticalSection(&cs_error); +} + +kherr_context * get_empty_context(void) { + kherr_context * c; + + EnterCriticalSection(&cs_error); + if(ctx_free_list) + LPOP(&ctx_free_list, &c); + else { + c = PMALLOC(sizeof(kherr_context)); + } + + ZeroMemory(c,sizeof(*c)); + c->severity = KHERR_NONE; + c->flags = KHERR_CF_UNBOUND; + c->magic = KHERR_CONTEXT_MAGIC; + c->serial = ++ctx_serial; + + LPUSH(&ctx_root_list, c); + + LeaveCriticalSection(&cs_error); + + return c; +} + + +/* Assumes that the context has been deleted from all relevant + lists */ +void free_context(kherr_context * c) { + kherr_context * ch; + kherr_event * e; + + assert(c->magic == KHERR_CONTEXT_MAGIC); +#ifdef DEBUG_CONTEXT + kherr_debug_printf(L"Freeing context 0x%x\n", c); +#endif + + EnterCriticalSection(&cs_error); + + if (c->desc_event) + free_event(c->desc_event); + c->desc_event = NULL; + + TPOPCHILD(c, &ch); + while(ch) { + free_context(ch); + TPOPCHILD(c, &ch); + } + QGET(c, &e); + while(e) { + free_event(e); + QGET(c, &e); + } + + c->serial = 0; + + LPUSH(&ctx_free_list,c); + LeaveCriticalSection(&cs_error); + +#ifdef DEBUG_CONTEXT + kherr_debug_printf(L"Done with context 0x%x\n", c); +#endif +} + +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) + notify_ctx_event(KHERR_CTX_ERROR, c); + + c->severity = e->severity; + c->err_event = e; + c->flags &= ~KHERR_CF_DIRTY; + } + LeaveCriticalSection(&cs_error); +} + +void pick_err_event(kherr_context * c) +{ + kherr_event * e; + kherr_event * ce = NULL; + enum kherr_severity s; + + s = KHERR_RESERVED_BANK; + + EnterCriticalSection(&cs_error); + e = QTOP(c); + while(e) { + if(!(e->flags & KHERR_RF_INERT) && + s >= e->severity) { + ce = e; + s = e->severity; + } + e = QNEXT(e); + } + + if(ce) { + c->err_event = ce; + c->severity = ce->severity; + } else { + c->err_event = NULL; + c->severity = KHERR_NONE; + } + + c->flags &= ~KHERR_CF_DIRTY; + LeaveCriticalSection(&cs_error); +} + +static void arg_from_param(DWORD_PTR ** parm, kherr_param p) { + int t; + + if (p.type != KEPT_NONE) { + t = parm_type(p); + if (t == KEPT_INT32 || + t == KEPT_UINT32 || + t == KEPT_STRINGC || + t == KEPT_STRINGT || + t == KEPT_PTR) { + + *(*parm)++ = (DWORD_PTR) parm_data(p); + + } else if (t == KEPT_INT64 || + t == KEPT_UINT64) { + *(*parm)++ = (DWORD_PTR) parm_data(p) & 0xffffffff; + *(*parm)++ = (DWORD_PTR) (parm_data(p) >> 32) & 0xffffffff; + } else + *(*parm)++ = 0; + } +} + +/* The 'buf' parameter MUST point to a DWORD_PTR[8] array */ +static void args_from_event(DWORD_PTR * buf, kherr_event * e) { + arg_from_param(&buf, e->p1); + arg_from_param(&buf, e->p2); + arg_from_param(&buf, e->p3); + arg_from_param(&buf, e->p4); +} + +static void resolve_string_resource(kherr_event * e, + const wchar_t ** str, + khm_int32 if_flag, + khm_int32 or_flag) { + wchar_t tfmt[KHERR_MAXCCH_STRING]; + wchar_t tbuf[KHERR_MAXCCH_STRING]; + size_t chars = 0; + size_t bytes = 0; + + if(e->flags & if_flag) { + if(e->h_module != NULL) + chars = LoadString(e->h_module, (UINT)(INT_PTR) *str, + tfmt, ARRAYLENGTH(tbuf)); + if(e->h_module == NULL || chars == 0) + *str = NULL; + else { + wchar_t * s; + DWORD_PTR args[8]; + + args_from_event(args, e); + + chars = FormatMessage(FORMAT_MESSAGE_FROM_STRING | + FORMAT_MESSAGE_ARGUMENT_ARRAY, + tfmt, + 0, + 0, + tbuf, + ARRAYLENGTH(tbuf), + (va_list *) args); + + if (chars == 0) { + *str = NULL; + } else { + bytes = (chars + 1) * sizeof(wchar_t); + s = PMALLOC(bytes); + assert(s); + StringCbCopy(s, bytes, tbuf); + *str = s; + e->flags |= or_flag; + } + } + e->flags &= ~if_flag; + } +} + +static void resolve_msg_resource(kherr_event * e, + const wchar_t ** str, + khm_int32 if_flag, + khm_int32 or_flag) { + wchar_t tbuf[KHERR_MAXCCH_STRING]; + size_t chars = 0; + size_t bytes = 0; + DWORD_PTR args[8]; + + if(e->flags & if_flag) { + if(e->h_module != NULL) { + args_from_event(args, e); + + chars = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | + FORMAT_MESSAGE_ARGUMENT_ARRAY, + (LPCVOID) e->h_module, + (DWORD)(DWORD_PTR) *str, + 0, + tbuf, + ARRAYLENGTH(tbuf), + (va_list *) args); + } + + if(e->h_module == NULL || chars == 0) { + *str = NULL; + } else { + wchar_t * s; + + /* MC inserts trailing \r\n to each message unless the + message is terminated with a %0. We remove the last + line break since it is irrelevant to our handling of + the string in the UI. */ + if (tbuf[chars-1] == L'\n') + tbuf[--chars] = L'\0'; + if (tbuf[chars-1] == L'\r') + tbuf[--chars] = L'\0'; + + bytes = (chars + 1) * sizeof(wchar_t); + s = PMALLOC(bytes); + assert(s); + StringCbCopy(s, bytes, tbuf); + *str = s; + e->flags |= or_flag; + } + e->flags &= ~if_flag; + } +} + +static void resolve_string(kherr_event * e, + const wchar_t ** str, + khm_int32 mask, + khm_int32 free_if, + khm_int32 or_flag) { + + wchar_t tbuf[KHERR_MAXCCH_STRING]; + size_t chars; + size_t bytes; + DWORD_PTR args[8]; + + if (((e->flags & mask) == 0 || + (e->flags & mask) == free_if) && + *str != NULL) { + + args_from_event(args, e); + chars = FormatMessage(FORMAT_MESSAGE_FROM_STRING | + FORMAT_MESSAGE_ARGUMENT_ARRAY, + (LPCVOID) *str, + 0, + 0, + tbuf, + ARRAYLENGTH(tbuf), + (va_list *) args); + + if ((e->flags & mask) == free_if) { + PFREE((void *) *str); + } + + e->flags &= ~mask; + + if (chars == 0) { + *str = 0; + } else { + wchar_t * s; + + bytes = (chars + 1) * sizeof(wchar_t); + s = PMALLOC(bytes); + assert(s); + StringCbCopy(s, bytes, tbuf); + *str = s; + e->flags |= or_flag; + } + } + +} + +void resolve_event_strings(kherr_event * e) +{ + resolve_string(e, &e->short_desc, + KHERR_RFMASK_SHORT_DESC, + KHERR_RF_FREE_SHORT_DESC, + KHERR_RF_FREE_SHORT_DESC); + + resolve_string(e, &e->long_desc, + KHERR_RFMASK_LONG_DESC, + KHERR_RF_FREE_LONG_DESC, + KHERR_RF_FREE_LONG_DESC); + + resolve_string(e, &e->suggestion, + KHERR_RFMASK_SUGGEST, + KHERR_RF_FREE_SUGGEST, + KHERR_RF_FREE_SUGGEST); + + resolve_string_resource(e, &e->short_desc, + KHERR_RF_RES_SHORT_DESC, + KHERR_RF_FREE_SHORT_DESC); + + resolve_string_resource(e, &e->long_desc, + KHERR_RF_RES_LONG_DESC, + KHERR_RF_FREE_LONG_DESC); + + resolve_string_resource(e, &e->suggestion, + KHERR_RF_RES_SUGGEST, + KHERR_RF_FREE_SUGGEST); + + resolve_msg_resource(e, &e->short_desc, + KHERR_RF_MSG_SHORT_DESC, + KHERR_RF_FREE_SHORT_DESC); + resolve_msg_resource(e, &e->long_desc, + KHERR_RF_MSG_LONG_DESC, + KHERR_RF_FREE_LONG_DESC); + resolve_msg_resource(e, &e->suggestion, + KHERR_RF_MSG_SUGGEST, + KHERR_RF_FREE_SUGGEST); + + /* get rid of dangling reference now that we have done everything + we can with it. Since we have already dealt with all the + parameter inserts, we don't need the parameters anymore + either. */ + free_event_params(e); + + e->h_module = NULL; + e->flags |= KHERR_RF_STR_RESOLVED; +} + + +KHMEXP void KHMAPI kherr_evaluate_event(kherr_event * e) { + if (!e) + return; + + EnterCriticalSection(&cs_error); + resolve_event_strings(e); + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_evaluate_last_event(void) { + kherr_context * c; + kherr_event * e; + DWORD tid; + + c = peek_context(); + if(!c) + return; + tid = GetCurrentThreadId(); + + EnterCriticalSection(&cs_error); + e = QBOTTOM(c); + while (e != NULL && e->thread_id != tid) + e = QPREV(e); + + if(!e) + goto _exit; + + resolve_event_strings(e); + + _exit: + LeaveCriticalSection(&cs_error); +} + +KHMEXP kherr_event * __cdecl +kherr_reportf(const wchar_t * long_desc_fmt, ...) { + va_list vl; + wchar_t buf[1024]; + kherr_event * e; + + va_start(vl, long_desc_fmt); + StringCbVPrintf(buf, sizeof(buf), long_desc_fmt, vl); +#ifdef DEBUG + OutputDebugString(buf); +#endif + va_end(vl); + + e = kherr_report(KHERR_DEBUG_1, + NULL, NULL, NULL, buf, NULL, 0, + KHERR_SUGGEST_NONE, _vnull(), _vnull(), _vnull(), _vnull(), + KHERR_RF_CSTR_LONG_DESC +#ifdef _WIN32 + ,NULL +#endif + ); + if (e) { + kherr_evaluate_event(e); + } + + return e; +} + +KHMEXP kherr_event * __cdecl +kherr_reportf_ex(enum kherr_severity severity, + const wchar_t * facility, + khm_int32 facility_id, +#ifdef _WIN32 + HMODULE hModule, +#endif + const wchar_t * long_desc_fmt, ...) { + va_list vl; + wchar_t buf[1024]; + kherr_event * e; + + va_start(vl, long_desc_fmt); + StringCbVPrintf(buf, sizeof(buf), long_desc_fmt, vl); +#ifdef DEBUG + OutputDebugString(buf); +#endif + va_end(vl); + + e = kherr_report(severity, NULL, facility, NULL, buf, NULL, facility_id, + KHERR_SUGGEST_NONE, + _vnull(), + _vnull(), + _vnull(), + _vnull(), KHERR_RF_CSTR_LONG_DESC +#ifdef _WIN32 + ,hModule +#endif + ); + if (e) { + kherr_evaluate_event(e); + } + + return e; +} + +KHMEXP kherr_event * KHMAPI +kherr_report(enum kherr_severity severity, + const wchar_t * short_desc, + const wchar_t * facility, + const wchar_t * location, + const wchar_t * long_desc, + const wchar_t * suggestion, + khm_int32 facility_id, + enum kherr_suggestion suggestion_id, + kherr_param p1, + kherr_param p2, + kherr_param p3, + kherr_param p4, + khm_int32 flags +#ifdef _WIN32 + ,HMODULE h_module +#endif + ) { + kherr_context * c; + kherr_event * e; + + /*TODO: sanity check flags (ISPOW2) */ + + e = get_empty_event(); + + e->thread_id = GetCurrentThreadId(); + e->time_ticks = GetTickCount(); + GetSystemTimeAsFileTime(&e->time_ft); + + e->severity = severity; + e->short_desc = short_desc; + e->facility = facility; + e->location = location; + e->long_desc = long_desc; + e->suggestion = suggestion; + e->facility_id = facility_id; + e->suggestion_id = suggestion_id; + e->p1 = p1; + e->p2 = p2; + e->p3 = p3; + e->p4 = p4; + e->flags = flags; +#ifdef _WIN32 + e->h_module = h_module; +#endif + + EnterCriticalSection(&cs_error); + c = peek_context(); + + if(!c) { + /* the reason why we are doing it this way is because p1..p4, + the descriptions and the suggestion may contain allocations + that has to be freed. */ + free_event(e); + e = NULL; + } else { + add_event(c,e); + } + + LeaveCriticalSection(&cs_error); + + return e; +} + +KHMEXP void KHMAPI kherr_suggest(wchar_t * suggestion, + enum kherr_suggestion suggestion_id, + khm_int32 flags) { + kherr_context * c; + kherr_event * e; + DWORD tid; + + if (flags != KHERR_RF_CSTR_SUGGEST && + flags != KHERR_RF_RES_SUGGEST && + flags != KHERR_RF_MSG_SUGGEST && + flags != KHERR_RF_FREE_SUGGEST) + return; + + c = peek_context(); + if(!c) + return; + + tid = GetCurrentThreadId(); + + EnterCriticalSection(&cs_error); + e = QBOTTOM(c); + while (e != NULL && e->thread_id != tid) + e = QPREV(e); + + if(!e) + goto _exit; + + /* if strings have already been resolved in this event, we cant + add any more unresolved strings. */ + if ((flags == KHERR_RF_RES_SUGGEST || + flags == KHERR_RF_MSG_SUGGEST) && + (e->flags & KHERR_RF_STR_RESOLVED)) + goto _exit; + + e->suggestion = suggestion; + e->suggestion_id = suggestion_id; + e->flags |= flags; +_exit: + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_location(wchar_t * location) { + kherr_context * c; + kherr_event * e; + DWORD tid; + + c = peek_context(); + if(!c) + return; + tid = GetCurrentThreadId(); + + EnterCriticalSection(&cs_error); + e = QBOTTOM(c); + while (e != NULL && e->thread_id != tid) + e = QPREV(e); + + if(!e) + goto _exit; + e->location = location; +_exit: + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_facility(wchar_t * facility, + khm_int32 facility_id) { + kherr_context * c; + kherr_event * e; + DWORD tid; + + c = peek_context(); + if(!c) + return; + tid = GetCurrentThreadId(); + EnterCriticalSection(&cs_error); + e = QBOTTOM(c); + while (e != NULL && e->thread_id != tid) + e = QPREV(e); + + if(!e) + goto _exit; + e->facility = facility; + e->facility_id = facility_id; +_exit: + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_set_desc_event(void) { + kherr_context * c; + kherr_event * e; + DWORD tid; + + c = peek_context(); + if(!c) + return; + tid = GetCurrentThreadId(); + + EnterCriticalSection(&cs_error); + e = QBOTTOM(c); + while (e != NULL && e->thread_id != tid) + e = QPREV(e); + + if(!e || c->desc_event) + goto _exit; + + QDEL(c,e); + c->desc_event = e; + e->severity = KHERR_NONE; + resolve_event_strings(e); + + notify_ctx_event(KHERR_CTX_DESCRIBE, c); + +_exit: + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_del_last_event(void) { + kherr_context * c; + kherr_event * e; + DWORD tid; + + c = peek_context(); + + if(!c) + return; + + tid = GetCurrentThreadId(); + + EnterCriticalSection(&cs_error); + e = QBOTTOM(c); + while (e != NULL && e->thread_id != tid) + e = QPREV(e); + + if(e) { + QDEL(c, e); + if(c->err_event == e) { + pick_err_event(c); + } + free_event(e); + } + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_push_context(kherr_context * c) +{ + kherr_context * p; + int new_context = FALSE; + + EnterCriticalSection(&cs_error); + p = peek_context(); + if(p && (c->flags & KHERR_CF_UNBOUND)) { + LDELETE(&ctx_root_list, c); + TADDCHILD(p,c); + c->flags &= ~KHERR_CF_UNBOUND; + kherr_hold_context(p); + new_context = TRUE; + } + push_context(c); + + if (new_context) + notify_ctx_event(KHERR_CTX_BEGIN, c); + + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_push_new_context(khm_int32 flags) +{ + kherr_context * p; + kherr_context * c; + + flags &= KHERR_CFMASK_INITIAL; + + EnterCriticalSection(&cs_error); + p = peek_context(); + c = get_empty_context(); + if(p) { + LDELETE(&ctx_root_list, c); + TADDCHILD(p,c); + c->flags &= ~KHERR_CF_UNBOUND; + kherr_hold_context(p); + } + c->flags |= flags; + push_context(c); + + notify_ctx_event(KHERR_CTX_BEGIN, c); + + LeaveCriticalSection(&cs_error); +} + +kherr_param dup_parm(kherr_param p) { + if(parm_type(p) == KEPT_STRINGT) { + wchar_t * d = PWCSDUP((wchar_t *)parm_data(p)); + return kherr_val(KEPT_STRINGT, (khm_ui_8) d); + } else + return p; +} + +kherr_event * fold_context(kherr_context * c) { + kherr_event * e; + kherr_event * g; + + if (!c) + return NULL; + + EnterCriticalSection(&cs_error); + if(!c->err_event || (c->flags & KHERR_CF_DIRTY)) { + pick_err_event(c); + } + if(c->err_event) { + g = c->err_event; + e = get_empty_event(); + *e = *g; + g->short_desc = NULL; + g->long_desc = NULL; + g->suggestion = NULL; + g->flags &= + ~(KHERR_RF_FREE_SHORT_DESC | + KHERR_RF_FREE_LONG_DESC | + KHERR_RF_FREE_SUGGEST); + LINIT(e); + e->p1 = dup_parm(g->p1); + e->p2 = dup_parm(g->p2); + e->p3 = dup_parm(g->p3); + e->p4 = dup_parm(g->p4); + } else { + e = c->desc_event; + c->desc_event = NULL; + } + + if (e) + e->flags |= KHERR_RF_CONTEXT_FOLD; + + LeaveCriticalSection(&cs_error); + + return e; +} + +KHMEXP void KHMAPI kherr_hold_context(kherr_context * c) { + assert(c && c->magic == KHERR_CONTEXT_MAGIC); + EnterCriticalSection(&cs_error); + c->refcount++; + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_release_context(kherr_context * c) { + assert(c && c->magic == KHERR_CONTEXT_MAGIC); + EnterCriticalSection(&cs_error); + c->refcount--; + if (c->refcount == 0) { + 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); + if (p) { + e = fold_context(c); + if (e) + add_event(p, e); + + TDELCHILD(p, c); + kherr_release_context(p); + } else { + LDELETE(&ctx_root_list, c); + } + free_context(c); + } + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_pop_context(void) { + kherr_context * c; + + EnterCriticalSection(&cs_error); + c = pop_context(); + if(c) { + kherr_release_context(c); + } + LeaveCriticalSection(&cs_error); +} + +KHMEXP kherr_context * KHMAPI kherr_peek_context(void) { + kherr_context * c; + + c = peek_context(); + if (c) + kherr_hold_context(c); + + return c; +} + +KHMEXP khm_boolean KHMAPI kherr_is_error(void) { + kherr_context * c = peek_context(); + return kherr_is_error_i(c); +} + +KHMEXP khm_boolean KHMAPI kherr_is_error_i(kherr_context * c) { + if(c && c->severity <= KHERR_ERROR) + return TRUE; + else + return FALSE; +} + +KHMEXP void KHMAPI kherr_clear_error(void) { + kherr_context * c = peek_context(); + if (c) + kherr_clear_error_i(c); +} + +KHMEXP void KHMAPI kherr_clear_error_i(kherr_context * c) { + kherr_event * e; + if (c) { + EnterCriticalSection(&cs_error); + e = QTOP(c); + while(e) { + e->flags |= KHERR_RF_INERT; + e = QNEXT(e); + } + c->severity = KHERR_NONE; + c->err_event = NULL; + c->flags &= ~KHERR_CF_DIRTY; + LeaveCriticalSection(&cs_error); + } +} + +KHMEXP void KHMAPI kherr_set_progress(khm_ui_4 num, khm_ui_4 denom) { + kherr_context * c = peek_context(); + if(c) { + EnterCriticalSection(&cs_error); + c->progress_denom = denom; + c->progress_num = num; + LeaveCriticalSection(&cs_error); + } +} + +KHMEXP void KHMAPI kherr_get_progress(khm_ui_4 * num, khm_ui_4 * denom) { + kherr_context * c = peek_context(); + kherr_get_progress_i(c,num,denom); +} + +KHMEXP void KHMAPI kherr_get_progress_i(kherr_context * c, + khm_ui_4 * num, + khm_ui_4 * denom) { + if(c) { + EnterCriticalSection(&cs_error); + *num = c->progress_num; + *denom = c->progress_denom; + LeaveCriticalSection(&cs_error); + } else { + *num = 0; + *denom = 0; + } +} + +KHMEXP kherr_event * KHMAPI kherr_get_first_event(kherr_context * c) +{ + kherr_event * e; + EnterCriticalSection(&cs_error); + e = QTOP(c); + LeaveCriticalSection(&cs_error); + return e; +} + +KHMEXP kherr_event * KHMAPI kherr_get_next_event(kherr_event * e) +{ + kherr_event * ee; + + EnterCriticalSection(&cs_error); + ee = QNEXT(e); + LeaveCriticalSection(&cs_error); + 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; + + EnterCriticalSection(&cs_error); + if (c) { + cc = TFIRSTCHILD(c); + if (cc) + kherr_hold_context(cc); + } else { + cc = ctx_root_list; + if (cc) + kherr_hold_context(cc); + } + LeaveCriticalSection(&cs_error); + return cc; +} + +KHMEXP kherr_context * KHMAPI kherr_get_next_context(kherr_context * c) +{ + kherr_context * cc; + EnterCriticalSection(&cs_error); + cc = LNEXT(c); + if (cc) + kherr_hold_context(cc); + LeaveCriticalSection(&cs_error); + return cc; +} + +KHMEXP kherr_event * KHMAPI kherr_get_err_event(kherr_context * c) +{ + kherr_event * e; + EnterCriticalSection(&cs_error); + if(!c->err_event) { + pick_err_event(c); + } + e = c->err_event; + LeaveCriticalSection(&cs_error); + return e; +} + +KHMEXP kherr_event * KHMAPI kherr_get_desc_event(kherr_context * c) +{ + kherr_event * e; + + EnterCriticalSection(&cs_error); + e = c->desc_event; + LeaveCriticalSection(&cs_error); + return e; +} + +KHMEXP kherr_param kherr_dup_string(const wchar_t * s) +{ + wchar_t * dest; + size_t cb_s; + + if (s == NULL) + return _vnull(); + + if (FAILED(StringCbLength(s, KHERR_MAXCB_STRING, &cb_s))) + cb_s = KHERR_MAXCB_STRING; + else + cb_s += sizeof(wchar_t); + + dest = PMALLOC(cb_s); + assert(dest != NULL); + dest[0] = L'\0'; + + StringCbCopy(dest, cb_s, s); + + return _tstr(dest); +} + + +#if 0 +KHMEXP kherr_param kherr_val(khm_octet ptype, khm_ui_8 pvalue) { + kherr_param p; + p.type = ptype; + p.data = pvalue; + + return p; +} +#endif diff --git a/src/windows/identity/kherr/kherr.h b/src/windows/identity/kherr/kherr.h index 795058764..fff3d5031 100644 --- a/src/windows/identity/kherr/kherr.h +++ b/src/windows/identity/kherr/kherr.h @@ -1,1094 +1,1094 @@ -/* - * 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_KHERR_H -#define __KHIMAIRA_KHERR_H - -/*! \defgroup kherr NetIDMgr Error Reporting - - Error reporting functions provide a mechanism to construct - meaningful and user friendly error reports for the user. - - Unlike most of the other NetIDMgr API's, the error reporting APIs - are lightweight and usually do not return an error value. This is - mostly because, these functions are called \b after an error - occurs. - - @{*/ -#include -#include - -/*! \name Customizable macros -@{ */ -#ifndef KHERR_FACILITY -/*! \brief The default facility when reporting errors - - When including this header file, if the KHERR_FACILITY macro is - defined to be a wide character string, then it will be used as the - default facility when for the convenience macros. All of the - calls to the convenience macros in the source file would then have - that facility. - - If left undefined, the convenience macros will leave the facility - value undefined. - */ -#define KHERR_FACILITY NULL -#endif - -#ifndef KHERR_FACILITY_ID -/*! \brief The default facility ID when reporting errors - - When including this header file, if the KHERR_FACILITY_ID macro is - defined to be non-zero, then it will be used as the default - facility identifier for the convenience macros. All of the calls - to the convenience macros in the source file would then have that - facility identifier. - - The default value of 0 means that the facility is undefined. - */ -#define KHERR_FACILITY_ID 0 -#endif - -/*! \define KHERR_HMODULE (undefined) - \brief The default module handle - - When including this header file, if the KHERR_HMODULE macro is - defined to be an identifier that holds the module handle, then the - convenience macros that specify a module handle will use it. - - A default value is not defined for KHERR_HMODULE. Any attempt to - invoke any of the convenience macros that use it should generate a - compile time error. - */ -#ifdef _WIN32 -#ifndef KHERR_HMODULE -#endif -#endif -/*@}*/ - -/*! \brief Parameter types - */ -enum kherr_parm_types { - KEPT_NONE = 0, - KEPT_INT32 = 1, - KEPT_UINT32, - KEPT_INT64, - KEPT_UINT64, - KEPT_STRINGC, /*!< String constant */ - KEPT_STRINGT, /*!< String. Will be freed using - free() when the event is freed */ - KEPT_PTR /*!< Pointer type. */ -}; - - -typedef struct tag_kherr_param { - khm_octet type; - khm_ui_8 data; -} kherr_param; - -/*! \brief Severity levels - - Larger the value, the less severe it is. -*/ -enum tag_kherr_severity { - KHERR_FATAL = 0, /*!< Fatal error.*/ - KHERR_ERROR, /*!< Non-fatal error. We'll probably - survive. See the suggested action. */ - KHERR_WARNING, /*!< Warning. Something almost broke - or soon will. See the suggested - action. */ - KHERR_INFO, /*!< Informational. Something happened - that we would like you to know - about. */ - 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 */ -}; - -typedef enum tag_kherr_severity kherr_severity; - -/*! \brief Suggestions */ -enum tag_kherr_suggestion { - KHERR_SUGGEST_NONE = 0, /*!< No suggestions. */ - KHERR_SUGGEST_ABORT, /*!< Abort whatever it was you were - trying. It's not gonna work. */ - KHERR_SUGGEST_RETRY, /*!< Retry. It might work the second - or third time over */ - KHERR_SUGGEST_IGNORE, /*!< Ignore. It might go away. */ - KHERR_SUGGEST_INTERACT, /*!< Further user interaction is - necessary to resolve the situation. - The suggest string in the event - should be prompted to the user. */ - KHERR_SUGGEST_OTHER, /*!< Something else. */ -}; - -typedef enum tag_kherr_suggestion kherr_suggestion; - -/*! \brief An event */ -typedef struct tag_kherr_event { - khm_int32 magic; /*!< Magic number. Always set to - KHERR_EVENT_MAGIC */ - DWORD thread_id; /*!< The thread which reported this - event. */ - const wchar_t * short_desc; /*!< Short description or title - (localized) */ - const wchar_t * facility; /*!< Facility name of the reporter - (not localized) */ - const wchar_t * location; /*!< Location. Usually the function - name or such of where the event - occured (not localized) */ - const wchar_t * long_desc; /*!< A long description of what went - wrong (localized, formatted) */ - const wchar_t * suggestion; /*!< A suggested way to fix it - (localized,formatted) */ - - kherr_severity severity; - /*!< Severity level. One of the - severity levels listed in - enumeration ::kherr_severity */ - khm_int32 facility_id; /*!< Left to the application to - interpret */ - kherr_suggestion suggestion_id; - /*!< One of the suggestion ID's from - the enumeration - ::kherr_suggestion */ - - int flags; /*!< Flags. */ - - kherr_param p1; /*!< Parameter 1 for formatting */ - kherr_param p2; /*!< Parameter 2 for formatting */ - kherr_param p3; /*!< Parameter 3 for formatting */ - kherr_param p4; /*!< Parameter 4 for formatting */ - - DWORD time_ticks; /*!< Time at which event was reported - (as returned by GetTickCount(). */ - FILETIME time_ft; /*!< Time at which event was reported. - Current system time as FILETIME. */ - -#ifdef _WIN32 - HMODULE h_module; /*!< Handle to the module which should - resolve any unresolved resources - references above. */ -#endif - - LDCL(struct tag_kherr_event); -} kherr_event; - -#define KHERR_EVENT_MAGIC 0x0423e84f - -/*! \brief Flags for kherr_event - - Each set of flags that define the type of resource for one value - is mutually exclusive. - */ -enum kherr_event_flags { - KHERR_RF_CSTR_SHORT_DESC= 0x00000000, - /*!< Short description is a constant - string */ - KHERR_RF_RES_SHORT_DESC = 0x00000001, - /*!< Short description is a string - resource */ - KHERR_RF_MSG_SHORT_DESC = 0x00000002, - /*!< Short description is a message - resource */ - KHERR_RF_FREE_SHORT_DESC= 0x00000004, - /*!< Short description is an allocated - string */ - KHERR_RFMASK_SHORT_DESC = 0x00000007, - - KHERR_RF_CSTR_LONG_DESC = 0x00000000, - /*!< Long description is a constant - string */ - KHERR_RF_RES_LONG_DESC = 0x00000008, - /*!< Long description is a string - resource */ - KHERR_RF_MSG_LONG_DESC = 0x00000010, - /*!< Long description is a message - resouce */ - KHERR_RF_FREE_LONG_DESC = 0x00000020, - /*!< Long description is an allocated - string */ - KHERR_RFMASK_LONG_DESC = 0x00000038, - - KHERR_RF_CSTR_SUGGEST = 0x00000000, - /*!< Suggestion is a constant - string */ - KHERR_RF_RES_SUGGEST = 0x00000040, - /*!< Suggestion is a string - resource */ - KHERR_RF_MSG_SUGGEST = 0x00000080, - /*!< Suggestion is a message - resource */ - KHERR_RF_FREE_SUGGEST = 0x00000100, - /*!< Suggestion is an allocated - string */ - KHERR_RFMASK_SUGGEST = 0x000001C0, - - KHERR_RF_STR_RESOLVED = 0x00010000, - /*!< The string resources in the event - have been resolved. */ - KHERR_RF_CONTEXT_FOLD = 0x00020000, - /*!< The event is a representation of - a folded context. */ - - 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 */ -typedef khm_ui_4 kherr_serial; - -/*! \brief An error context -*/ -typedef struct tag_kherr_context { - khm_int32 magic; /*!< Magic number. Always set to - KHERR_CONTEXT_MAGIC */ - - kherr_serial serial; /*!< Context instance serial number. - Context objects themselves may be - reused for different contexts as - they are freed and reallocated. - However every instance of a context - is guaranteed to have a unique - serial number as specified in this - field. If an external entity wants - to keep track of the context, it - should keep track of the serial - number as well as the pointer to the - context object. */ - - kherr_severity severity; - /*!< Severity level. One of the - severity levels listed below. This - is the severity level of the context - and is the maximum severity level of - all the events in the queue of - events. */ - - khm_int32 flags; /*!< Flags. Used internally. */ - khm_ui_4 refcount; /*!< Reference count. Used - internally */ - - kherr_event *desc_event; /*!< Description event. The event that - describes the error context. This - points to an event that is not in - the event queue. */ - - kherr_event *err_event; /*!< Significant event. The last one - that caused the severity level to be - what it is right now. This points - to an event that is listed in the - event queue for this context.*/ - - khm_ui_4 progress_num; /*!< Progress numerator */ - khm_ui_4 progress_denom; /*!< Progress denominator */ - - TDCL(struct tag_kherr_context); - QDCL(struct tag_kherr_event); -} kherr_context; - -#define KHERR_CONTEXT_MAGIC 0x34f3238c - -enum kherr_context_flags { - KHERR_CF_NONE = 0x00000000, - /*!< None. */ - - KHERR_CF_DIRTY = 0x00000001, - /*!< Used Internally. Denotes that - the err_event and severity may need - to be recalculated. Cannot be set - as an initial flag. */ - - KHERR_CF_OWN_PROGRESS = 0x00000002, - /*!< The context maintains its own - progress meter as opposed to one - that is derived from child - contexts. */ - - KHERR_CF_UNBOUND = 0x00000004, - /*!< Unbound context. The context - can't be used to log events. Call - kherr_push_context() to associate - the context with the global context - hierarchy. Cannot be set as an - initial flag. */ - - KHERR_CF_TRANSITIVE = 0x00000008, - /*!< Transitive. The context is - automatically made the current - context for all other threads that - handle messages sent or posted by - threads whose current error context - is this one. */ - - KHERR_CFMASK_INITIAL = 0x0000000a, - /*!< Allowed initial flags */ -}; - -/*! \brief Maximum length of a string field in characters including terminating NULL - */ -#define KHERR_MAXCCH_STRING 1024 - -/*! \brief Maximum length of a string field in bytes including terminating NULL - */ -#define KHERR_MAXCB_STRING (KHERR_MAXCCH_STRING * sizeof(wchar_t)) - -/*! \brief Context event - - \see kherr_add_ctx_handler() -*/ -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 - state */ - KHERR_CTX_EVTCOMMIT = 0x0010 /*!< A event was committed into the - context */ -}; - -/*! \brief Context event handler - - Context event handlers are invoked when specific events occur with - respect to an error context. The ::kherr_ctx_event parameter - specifies which event occurred using one of the event values - described in the enumeration. The error context in which this - event occurred is specified by the ::kherr_context pointer. - - Note that if the handler needs to keep track of the error context - for later processing, it also needs to keep track of the \a serial - field of the error context. The same context object may be - reused, but the serial number is guaranteed to be unique. - - \see kherr_add_ctx_handler() - */ -typedef void (KHMAPI * kherr_ctx_handler)(enum kherr_ctx_event, - kherr_context *); - -/*! \brief Add a context event handler - - An application can register an event handler that gets notified of - events that pertain to error contexts. More than one handler can - be registered. The order in which the handlers are called is - undefined for any specific event. - - These event occur in the context of individual application - threads. The handler will be called from within the thread that - caused the event. Therefore it is important that the handler is - both reentrant and returns quickly. - - The events that the handler will be notified of are explained - below: - - KHERR_CTX_BEGIN: Notification that a new context was - created. A pointer to the context will be supplied to the - handler. The supplied pointer should not be used to obtain a hold - on the context, as it will prevent the context from being closed. - - KHERR_CTX_DESCRIBE: The thread called - kherr_set_desc_event() to set the description of a context. Once - again, the pointer should not be used to obtain a hold on the - context. - - KHERR_CTX_ERROR: The last event that was reported for the - context was an error event (the severity was was equal or higher - than KHERR_ERROR). The pointer may be used to obtain a hold on - the context. However, it is the application's resonsibility to - make sure that the hold is released later. Otherwise the event - will never be closed. - - KHERR_CTX_END: Closure. This event is signalled when the - last open handle to the context is closed and there is no thread - that is currently active which has this context in its error - context stack. At the time the handler is invoked, the context is - 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 - indication which notifications should be sent to the handler. - If a \a filter value of zero is provided, all of the events - will be sent to the handler. - - \param[in] serial The serial number of the error context that - should be tracked. If this is zero, all error contexts can - trigger the handler. - */ -KHMEXP void KHMAPI kherr_add_ctx_handler(kherr_ctx_handler h, - khm_int32 filter, - kherr_serial serial); - -/*! \brief Remove a context event handler - - Undoes what was done with kherr_add_ctx_handler() - - \see kherr_add_ctx_handler() - */ -KHMEXP void KHMAPI kherr_remove_ctx_handler(kherr_ctx_handler h, - kherr_serial serial); - - -/*! \brief Report an error - - Creates an event, fills in the details specified in the arguments, - and adds it to the current error context. - - If the current thread does not have an error context, no reporting - happens. However, if any of the supplied strings or parameters - are marked as allocated, they will be freed before the function - returns. - - Certain parameters that expect strings can instead be given string - resources, message resources or allocated strings in addition to - constant string. By default, the parameters are expected to be - constant strings. - - Allocated strings: The application can allocate memory for - a string. Since the application is not notified when the event is - no longer used and freed, it \b must indicate that the string is - an allocated string by setting the appropriate flag in the \a - flags parameter. When the event is no longer used, the memory - pointed to by the relevant pointer will be freed through a call to - free(). Not all string parameters take allocated strings. See - individual parameter documentation for details. - - String resources: On WIN32, string resources can be passed - in to kherr_report() using the MAKEINTRESOURCE macro. However, - the application \b must specify that the parameter is a string - resource using the appropriate flag in the \a flags parameter. - The error reporting engine will expand the string against the - module handle passed in the \a h_module parameter when the value - of the string is required. Not all string parameters take string - resources. See individual parameter documentation for details. - Strings loaded through string resources cannot be longer than - ::KHERR_MAXCCH_STRING in characters inclusive of terminating NULL. - - Message resources: On WIN32, message resources can be - passed in to kherr_report() by specifying the message ID where it - ordinarily expects a pointer to a constant string. The - application \b must indicate that the string is a message resource - by using the appropriate flag in the \a flags parameter. When the - value of the string is needed, it is expanded against the module - handle passed in the \a h_module parameter using the message ID. - Not all string parameters take message resources. See individual - parameter documentation for details. Note that the facility and - severity values associated with a message resource are ignored. - Strings loaded through message resources cannot be longer than - ::KHERR_MAXCCH_STRING in characters inclusive of terminating NULL. - - Formatted fields: Parameters that are formatted can have - can have parameter inserts like in printf(). However, specifying - inserts is different from printf() and follows the conventions - used in WIN32 API FormatMessage(). This is because for localized - strings, the order of the parameters in the string may be - different. See the documentation for FormatMessage() for details - on the format string. The same set of parameters (i.e. \a p1, \a - p2, \a p3, \a p4) is used for all formatted strings with - appropriate marshalling for 64 bit types. The size of the string - after expansion must not exceed 65536 bytes inclusive of - terminating NULL. - - \param[in] severity One of ::kherr_severity_level - \param[in] short_desc Short description or title (localized). Can - be a string resource, message resource, allocated string or - constant string. The \a flags parameter should indicate the - type of string used. - \param[in] facility Facility name of the reporter (not localized) - \param[in] location Usually the function name or such of where the - event occured (not localized) - \param[in] long_desc Long description of event (localized, - formatted). Can be a string resource, message resource, - allocated string or constant string. The \a flags parameter - should indicate the type of string used. - \param[in] suggestion Suggested action to correct situation, if - applicable (localized). Can be a string resource, message - resource, allocated string or constant string. The \a flags - parameter should indicate the type of string used. - \param[in] facility_id Identifier of facility. Application - defined. - \param[in] suggestion_id One of the suggestion identifiers from - ::kherr_suggestion_ids - \param[in] p1 First parameter. Used for formatting. - \param[in] p2 Second parameter. Used for formatting. - \param[in] p3 Third parameter. Used for formatting. - \param[in] p4 Fourth parameter. Used for formatting. - \param[in] flags Flags. See ::kherr_report_flags - \param[in] h_module Handle to a module that resolves any string or - message resources used for the \a short_description , \a - long_desc or \a suggestion parameters. This parameter is only - available on WIN32. - - \note With the exception of parameters of type KEPT_STRINGT and - parameters which are flagged for freeing using the \a flags - parameter, all other string parameters are assumed to be - pointers to constant strings. The strings are not copied and - the pointers are used as is. Also, no clean-up is performed - when the event is freed other than that implied by \a flags. - */ -KHMEXP kherr_event * KHMAPI kherr_report( - enum kherr_severity severity, - const wchar_t * short_desc, - const wchar_t * facility, - const wchar_t * location, - const wchar_t * long_desC, - const wchar_t * suggestion, - khm_int32 facility_id, - enum kherr_suggestion suggestion_id, - kherr_param p1, - kherr_param p2, - kherr_param p3, - kherr_param p4, - khm_int32 flags -#ifdef _WIN32 - ,HMODULE h_module -#endif -); - -/*! \brief Report a formatted message - - The format string \a long_desc_fmt should be a string constant and - the format specifiers follow that of \a sprintf. This creates an - event with the long description set to the expansion of the format - string against the arguments. - */ -KHMEXP kherr_event * __cdecl -kherr_reportf_ex(enum kherr_severity severity, - const wchar_t * facility, - khm_int32 facility_id, -#ifdef _WIN32 - HMODULE hModule, -#endif - const wchar_t * long_desc_fmt, - ...); -#define _reportf_ex kherr_reportf_ex - -/*! \brief Report a formatted message - - The format string \a long_desc_fmt should be a string constant and - the format specifiers follow that of \a sprintf. This creates an - event with the long description set to the expansion of the format - string against the arguments. - */ -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 - - A parameter is created by duplicating the string that is passed - into the function. If the string exceeds KHERR_MAXCCH_STRING, - then only the first part of the string that fits within the limit - is duplicated. - - The resulign ::kherr_param must be passed in to kherr_report(). - The event logging framework will free the duplicated string once - the data is no longer required. - */ -KHMEXP kherr_param kherr_dup_string(const wchar_t * s); - -__inline KHMEXP kherr_param -kherr_val(khm_octet ptype, khm_ui_8 pvalue) { - kherr_param p; - - p.type = ptype; - p.data = pvalue; - - return p; -} - -#define _int32(i) kherr_val(KEPT_INT32, (khm_ui_8) i) -#define _uint32(ui) kherr_val(KEPT_UINT32, (khm_ui_8) ui) -#define _int64(i) kherr_val(KEPT_INT64, (khm_ui_8) i) -#define _uint64(ui) kherr_val(KEPT_UINT64, (khm_ui_8) ui) -#define _cstr(cs) kherr_val(KEPT_STRINGC, (khm_ui_8) cs) -#define _tstr(ts) kherr_val(KEPT_STRINGT, (khm_ui_8) ts) -#define _cptr(p) kherr_val(KEPT_PTR, (khm_ui_8) p) -#define _vnull() kherr_val(KEPT_NONE, 0) -#define _dupstr(s) kherr_dup_string(s) - -/* convenience macros for calling kherr_report */ -#ifdef KHERR_HMODULE - -#define _report_cs0(severity, long_description) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, _vnull(), _vnull(), _vnull(), _vnull(), 0, KHERR_HMODULE) - -#define _report_cs1(severity, long_description, p1) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, _vnull(), _vnull(), _vnull(), 0, KHERR_HMODULE) - -#define _report_cs2(severity, long_description, p1, p2) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, _vnull(), _vnull(), 0, KHERR_HMODULE) - -#define _report_cs3(severity, long_description, p1, p2, p3) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, _vnull(), 0, KHERR_HMODULE) - -#define _report_cs4(severity, long_description, p1, p2, p3, p4) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, 0, KHERR_HMODULE) - -#else - -#define _report_cs0(severity, long_description) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, _vnull(), _vnull(), _vnull(), _vnull(), 0, NULL) - -#define _report_cs1(severity, long_description, p1) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, _vnull(), _vnull(), _vnull(), 0, NULL) - -#define _report_cs2(severity, long_description, p1, p2) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, _vnull(), _vnull(), 0, NULL) - -#define _report_cs3(severity, long_description, p1, p2, p3) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, _vnull(), 0, NULL) - -#define _report_cs4(severity, long_description, p1, p2, p3, p4) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, 0, NULL) -#endif /* !defined(KHERR_HMODULE) */ - -#ifdef _WIN32 -#define _report_sr0(severity, long_desc_id) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, _vnull(), _vnull(), _vnull(), _vnull(), KHERR_RF_RES_LONG_DESC, KHERR_HMODULE) - -#define _report_sr1(severity, long_desc_id, p1) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, p1, _vnull(), _vnull(), _vnull(), KHERR_RF_RES_LONG_DESC, KHERR_HMODULE) - -#define _report_sr2(severity, long_desc_id, p1, p2) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, _vnull(), _vnull(), KHERR_RF_RES_LONG_DESC, KHERR_HMODULE) - -#define _report_sr3(severity, long_desc_id, p1, p2, p3) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, _vnull(), KHERR_RF_RES_LONG_DESC, KHERR_HMODULE) - -#define _report_sr4(severity, long_desc_id, p1, p2, p3, p4) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, KHERR_RF_RES_LONG_DESC, KHERR_HMODULE) -#endif - -#ifdef _WIN32 -#define _report_mr0(severity, long_desc_msg_id) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, _vnull(), _vnull(), _vnull(), _vnull(), KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE) - -#define _report_mr1(severity, long_desc_msg_id, p1) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, p1, _vnull(), _vnull(), _vnull(), KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE) - -#define _report_mr2(severity, long_desc_msg_id, p1, p2) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, _vnull(), _vnull(), KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE) - -#define _report_mr3(severity, long_desc_msg_id, p1, p2, p3) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, _vnull(), KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE) - -#define _report_mr4(severity, long_desc_msg_id, p1, p2, p3, p4) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE) -#endif - -#define _report_ts0(severity, long_desc_ptr) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, _vnull(), _vnull(), _vnull(), _vnull(), KHERR_RF_FREE_LONG_DESC, NULL) - -#define _report_ts1(severity, long_desc_ptr, p1) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, p1, _vnull(), _vnull(), _vnull(), KHERR_RF_FREE_LONG_DESC, NULL) - -#define _report_ts2(severity, long_desc_ptr, p1, p2) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, p1, p2, _vnull(), _vnull(), KHERR_RF_FREE_LONG_DESC, NULL) - -#define _report_ts3(severity, long_desc_ptr, p1, p2, p3) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, _vnull(), KHERR_RF_FREE_LONG_DESC, NULL) - -#define _report_ts4(severity, long_desc_ptr, p1, p2, p3, p4) \ - kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, KHERR_RF_FREE_LONG_DESC, NULL) - -/*! \brief Set the suggestion and suggestion identifier for the last event - - The event that will be modified is the last event reported by the - calling thread. - */ -KHMEXP void KHMAPI kherr_suggest(wchar_t * suggestion, khm_int32 suggestion_id, khm_int32 flags); -#define _suggest_cs(cs,sid) kherr_suggest((cs), (sid), KHERR_RF_CSTR_SUGGEST) -#define _suggest_ts(ts,sid) kherr_suggest((ts), (sid), KHERR_RF_FREE_SUGGEST) -#define _suggest_sr(sr,sid) kherr_suggest(MAKEINTRESOURCE(sr), (sid), KHERR_RF_RES_SUGGEST) -#define _suggest_mr(mr,sid) kherr_suggest((wchar_t *)(DWORD_PTR)(mr), (sid), KHERR_RF_MSG_SUGGEST) - -/*! \brief Set the location string for the last event - - The event that will be modified is the last event reported by the - calling thread. - */ -KHMEXP void KHMAPI kherr_location(wchar_t * location); -#define _location(l) kherr_location(l) - -/*! \brief Set the facility string and identifier for the last event - - The event that will be modified is the last event reported by the - calling thread. - */ -KHMEXP void KHMAPI kherr_facility(wchar_t * facility, khm_int32 facility_id); -#define _facility(f,fid) kherr_facility((f),(fid)) - -/*! \brief Marks the last event as the descriptor event for the current error context - - Note that marking an event as the descriptor event has the effect - of removing the event from event queue. The event will henceforth - be used as the descriptor for the context. The only effective - fields of a descriptor event are \a short_desc, \a long_desc, \a - facility, \a facility_id and the parameters which are used for - resolving formatted strings in the aforementioned fields. - - Upon calling kherr_set_desc_event(), the event will be - automatically evaluated as if kherr_evaluate_event() was called. - - The event that will be referenced is the last event reported by - the calling thread. - */ -KHMEXP void KHMAPI kherr_set_desc_event(void); -#define _describe kherr_set_desc_event - -/*! \brief Delete the last event - - The event that will be deleted is the last event reported by the - calling thread. - */ -KHMEXP void KHMAPI kherr_del_last_event(void); -#define _del_event kherr_del_last_event - -/*! \brief Create a new context - - The created context is not bound to any thread or any context - hierarchy. Hence it cannot be used to capture any events until it - is used in a call to kherr_push_context(). - - Release the returned context pointer with a call to - kherr_release_context(). - - \param[in] flags Initial flags for the context. Combination of - ::kherr_context_flags - - \note This function is for internal use only. - */ -KHMEXP kherr_context * KHMAPI kherr_create_new_context(khm_int32 flags); - -/*! \brief Obtain a hold on a context */ -KHMEXP void KHMAPI kherr_hold_context(kherr_context * c); - -/*! \brief Release a context */ -KHMEXP void KHMAPI kherr_release_context(kherr_context * c); - -/*! \brief Push an empty context - - Creates an empty context, adds it as a child of the current - thread's error context. If the current thread does not have an - error context, then the created error context will be a root level - context. - - The new context will be the current error context for the calling - thread. - - \param[in] flags Initial flags for the context. Combination of - ::kherr_context_flags - - \see kherr_push_new_context() for more information about thread - specific context stacks. - - */ -KHMEXP void KHMAPI kherr_push_new_context(khm_int32 flags); -#define _begin_task kherr_push_new_context - -/*! \brief Push a context - - Each thread has a stack of error contexts. The topmost one is - current. The thread can push or pop contexts on to the stack - independently of the hierarchy of contexts (the only exception, as - explained below is when the context that is being pushed is - unbound). - - If the context being pushed by kherr_push_context() is unbound, - then it will be attached to the current context of the thread as a - child. Once the new context is pushed to the top of the stack, it - will become the current context for the thread. - - The calling thread must call kherr_pop_context() to remove the - context from the top of the stack. Each call to - kherr_push_new_context() or kher_push_context() must have a - corresponding kherr_pop_context() call. - - When the thread terminates, all of the contexts in the thread's - context stack will be automatically removed. - - \see kherr_pop_context() - */ -KHMEXP void KHMAPI kherr_push_context(kherr_context * c); - -/*! \brief Pop a context - - Remove the current error context from the thread's context stack. - If no other open handles exist to the error context, this causes - the error context to collapse into it's parent context or vanish - entirely unless the context contains an error. - - \see kherr_push_context() for more information about thread - specific context stacks. - */ -KHMEXP void KHMAPI kherr_pop_context(void); -#define _end_task kherr_pop_context - -/*! \brief Retrieve the current error context - - The returned pointer must be released with a call to - kherr_release_context(). -*/ -KHMEXP kherr_context * KHMAPI kherr_peek_context(void); - -/*! \brief Check if the current error context indicates an error - - \return TRUE if there is an error. FALSE otherwise. - \see kherr_analyze() - */ -KHMEXP khm_boolean KHMAPI kherr_is_error(void); - -/*! \brief Check if an error context indicates an error - - \return TRUE if there is an error. FALSE otherwise. - \see kherr_analyze() - */ -KHMEXP khm_boolean KHMAPI kherr_is_error_i(kherr_context * c); - -/*! \brief Clear the error state of the current context */ -KHMEXP void KHMAPI kherr_clear_error(void); - -/*! \brief Clear the error state of an error context */ -KHMEXP void KHMAPI kherr_clear_error_i(kherr_context * c); - -/*! \brief Set the progress meter of the current error context - - Setting \a denom to zero removes the progress meter. - */ -KHMEXP void KHMAPI kherr_set_progress(khm_ui_4 num, khm_ui_4 denom); -#define _progress(num,denom) kherr_set_progress((num),(denom)) - -/*! \brief Get the progress meter of the current error context - */ -KHMEXP void KHMAPI kherr_get_progress(khm_ui_4 * num, khm_ui_4 * denom); - -/*! \brief Get the progress meter of an error context - */ -KHMEXP void KHMAPI kherr_get_progress_i(kherr_context * c, khm_ui_4 * num, khm_ui_4 * denom); - -/*! \brief Get the first event in a context - - 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 - 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_next_event(), kherr_get_prev_event(), - kherr_get_last_event() - */ -KHMEXP kherr_event * KHMAPI kherr_get_first_event(kherr_context * c); - -/*! \brief Get the next event - - Call kherr_get_first_event() to obtain the first event in a - context. Subsequent calls to kherr_get_next_event() will yield - other events in the order in which they were reported. The list - ends when kherr_get_next_event() returns NULL. - - 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 - 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 - first child of an error context. Use kherr_get_next_context() to - obtain the other contexts. If \a c is \a NULL, this returns the - first root level context. - - The returned pointer must be released with a call to - kherr_release_context() - */ -KHMEXP kherr_context * KHMAPI kherr_get_first_context(kherr_context * c); - -/*! \brief Get the next sibling context of a context - - The returned pointer must be released with a call to - kherr_release_context() - - \see kherr_get_first_context() - */ -KHMEXP kherr_context * KHMAPI kherr_get_next_context(kherr_context * c); - -/*! \brief Get the desciption event for the context - - The description event is the event that was denoted using - kherr_set_desc_event() as the event which describes the context. - - 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. - */ -KHMEXP kherr_event * KHMAPI kherr_get_desc_event(kherr_context * c); - -/*! \brief Get the error event for the context - - The error event for a context is the last event that had the - highest severity level. - - 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. - */ -KHMEXP kherr_event * KHMAPI kherr_get_err_event(kherr_context * c); - -/*! \brief Evaluate an event - - When an event is reported, all the parameters and resource - references that were passed to kherr_report() are kept as-is until - the actual string values are required by the error reporting - library. However, if the string fields are required before then, - an application can call kherr_evaluate_event() to get them. - - This function does the following: - - - Load any referenced string or message resources that are - referenced in the event's short description, long description or - suggestion. - - - Expand any inserts using the parameters that were passed in. - - - Free up allocated strings in for the descriptions or suggestion - fields and any parameters. - - - Update the string fields in the event to contain the newly - generated strings. - - */ -KHMEXP void KHMAPI kherr_evaluate_event(kherr_event * e); - -/*! \brief Evaluate the last event - - Same as kherr_evaluate_event(), but operates on the last event - logged by the current thread. - - \see kherr_evaluate_event() - */ -KHMEXP void KHMAPI kherr_evaluate_last_event(void); -#define _resolve kherr_evaluate_last_event - -/*! \defgroup kherr_fids Standard Facility IDs -@{*/ -#define KHM_FACILITY_KMM 1 -#define KHM_FACILITY_KCDB 2 -#define KHM_FACILITY_UI 3 -#define KHM_FACILITY_KRB5 64 -#define KHM_FACILITY_KRB4 65 -#define KHM_FACILITY_AFS 66 -#define KHM_FACILITY_USER 128 -/*@}*/ - -/*@}*/ - -/* In debug mode, outputs the formatted string to the debug console */ -#ifdef DEBUG -KHMEXP void kherr_debug_printf(wchar_t * fmt, ...); -#endif - -#endif +/* + * 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_KHERR_H +#define __KHIMAIRA_KHERR_H + +/*! \defgroup kherr NetIDMgr Error Reporting + + Error reporting functions provide a mechanism to construct + meaningful and user friendly error reports for the user. + + Unlike most of the other NetIDMgr API's, the error reporting APIs + are lightweight and usually do not return an error value. This is + mostly because, these functions are called \b after an error + occurs. + + @{*/ +#include +#include + +/*! \name Customizable macros +@{ */ +#ifndef KHERR_FACILITY +/*! \brief The default facility when reporting errors + + When including this header file, if the KHERR_FACILITY macro is + defined to be a wide character string, then it will be used as the + default facility when for the convenience macros. All of the + calls to the convenience macros in the source file would then have + that facility. + + If left undefined, the convenience macros will leave the facility + value undefined. + */ +#define KHERR_FACILITY NULL +#endif + +#ifndef KHERR_FACILITY_ID +/*! \brief The default facility ID when reporting errors + + When including this header file, if the KHERR_FACILITY_ID macro is + defined to be non-zero, then it will be used as the default + facility identifier for the convenience macros. All of the calls + to the convenience macros in the source file would then have that + facility identifier. + + The default value of 0 means that the facility is undefined. + */ +#define KHERR_FACILITY_ID 0 +#endif + +/*! \define KHERR_HMODULE (undefined) + \brief The default module handle + + When including this header file, if the KHERR_HMODULE macro is + defined to be an identifier that holds the module handle, then the + convenience macros that specify a module handle will use it. + + A default value is not defined for KHERR_HMODULE. Any attempt to + invoke any of the convenience macros that use it should generate a + compile time error. + */ +#ifdef _WIN32 +#ifndef KHERR_HMODULE +#endif +#endif +/*@}*/ + +/*! \brief Parameter types + */ +enum kherr_parm_types { + KEPT_NONE = 0, + KEPT_INT32 = 1, + KEPT_UINT32, + KEPT_INT64, + KEPT_UINT64, + KEPT_STRINGC, /*!< String constant */ + KEPT_STRINGT, /*!< String. Will be freed using + free() when the event is freed */ + KEPT_PTR /*!< Pointer type. */ +}; + + +typedef struct tag_kherr_param { + khm_octet type; + khm_ui_8 data; +} kherr_param; + +/*! \brief Severity levels + + Larger the value, the less severe it is. +*/ +enum tag_kherr_severity { + KHERR_FATAL = 0, /*!< Fatal error.*/ + KHERR_ERROR, /*!< Non-fatal error. We'll probably + survive. See the suggested action. */ + KHERR_WARNING, /*!< Warning. Something almost broke + or soon will. See the suggested + action. */ + KHERR_INFO, /*!< Informational. Something happened + that we would like you to know + about. */ + 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 */ +}; + +typedef enum tag_kherr_severity kherr_severity; + +/*! \brief Suggestions */ +enum tag_kherr_suggestion { + KHERR_SUGGEST_NONE = 0, /*!< No suggestions. */ + KHERR_SUGGEST_ABORT, /*!< Abort whatever it was you were + trying. It's not gonna work. */ + KHERR_SUGGEST_RETRY, /*!< Retry. It might work the second + or third time over */ + KHERR_SUGGEST_IGNORE, /*!< Ignore. It might go away. */ + KHERR_SUGGEST_INTERACT, /*!< Further user interaction is + necessary to resolve the situation. + The suggest string in the event + should be prompted to the user. */ + KHERR_SUGGEST_OTHER, /*!< Something else. */ +}; + +typedef enum tag_kherr_suggestion kherr_suggestion; + +/*! \brief An event */ +typedef struct tag_kherr_event { + khm_int32 magic; /*!< Magic number. Always set to + KHERR_EVENT_MAGIC */ + DWORD thread_id; /*!< The thread which reported this + event. */ + const wchar_t * short_desc; /*!< Short description or title + (localized) */ + const wchar_t * facility; /*!< Facility name of the reporter + (not localized) */ + const wchar_t * location; /*!< Location. Usually the function + name or such of where the event + occured (not localized) */ + const wchar_t * long_desc; /*!< A long description of what went + wrong (localized, formatted) */ + const wchar_t * suggestion; /*!< A suggested way to fix it + (localized,formatted) */ + + kherr_severity severity; + /*!< Severity level. One of the + severity levels listed in + enumeration ::kherr_severity */ + khm_int32 facility_id; /*!< Left to the application to + interpret */ + kherr_suggestion suggestion_id; + /*!< One of the suggestion ID's from + the enumeration + ::kherr_suggestion */ + + int flags; /*!< Flags. */ + + kherr_param p1; /*!< Parameter 1 for formatting */ + kherr_param p2; /*!< Parameter 2 for formatting */ + kherr_param p3; /*!< Parameter 3 for formatting */ + kherr_param p4; /*!< Parameter 4 for formatting */ + + DWORD time_ticks; /*!< Time at which event was reported + (as returned by GetTickCount(). */ + FILETIME time_ft; /*!< Time at which event was reported. + Current system time as FILETIME. */ + +#ifdef _WIN32 + HMODULE h_module; /*!< Handle to the module which should + resolve any unresolved resources + references above. */ +#endif + + LDCL(struct tag_kherr_event); +} kherr_event; + +#define KHERR_EVENT_MAGIC 0x0423e84f + +/*! \brief Flags for kherr_event + + Each set of flags that define the type of resource for one value + is mutually exclusive. + */ +enum kherr_event_flags { + KHERR_RF_CSTR_SHORT_DESC= 0x00000000, + /*!< Short description is a constant + string */ + KHERR_RF_RES_SHORT_DESC = 0x00000001, + /*!< Short description is a string + resource */ + KHERR_RF_MSG_SHORT_DESC = 0x00000002, + /*!< Short description is a message + resource */ + KHERR_RF_FREE_SHORT_DESC= 0x00000004, + /*!< Short description is an allocated + string */ + KHERR_RFMASK_SHORT_DESC = 0x00000007, + + KHERR_RF_CSTR_LONG_DESC = 0x00000000, + /*!< Long description is a constant + string */ + KHERR_RF_RES_LONG_DESC = 0x00000008, + /*!< Long description is a string + resource */ + KHERR_RF_MSG_LONG_DESC = 0x00000010, + /*!< Long description is a message + resouce */ + KHERR_RF_FREE_LONG_DESC = 0x00000020, + /*!< Long description is an allocated + string */ + KHERR_RFMASK_LONG_DESC = 0x00000038, + + KHERR_RF_CSTR_SUGGEST = 0x00000000, + /*!< Suggestion is a constant + string */ + KHERR_RF_RES_SUGGEST = 0x00000040, + /*!< Suggestion is a string + resource */ + KHERR_RF_MSG_SUGGEST = 0x00000080, + /*!< Suggestion is a message + resource */ + KHERR_RF_FREE_SUGGEST = 0x00000100, + /*!< Suggestion is an allocated + string */ + KHERR_RFMASK_SUGGEST = 0x000001C0, + + KHERR_RF_STR_RESOLVED = 0x00010000, + /*!< The string resources in the event + have been resolved. */ + KHERR_RF_CONTEXT_FOLD = 0x00020000, + /*!< The event is a representation of + a folded context. */ + + 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 */ +typedef khm_ui_4 kherr_serial; + +/*! \brief An error context +*/ +typedef struct tag_kherr_context { + khm_int32 magic; /*!< Magic number. Always set to + KHERR_CONTEXT_MAGIC */ + + kherr_serial serial; /*!< Context instance serial number. + Context objects themselves may be + reused for different contexts as + they are freed and reallocated. + However every instance of a context + is guaranteed to have a unique + serial number as specified in this + field. If an external entity wants + to keep track of the context, it + should keep track of the serial + number as well as the pointer to the + context object. */ + + kherr_severity severity; + /*!< Severity level. One of the + severity levels listed below. This + is the severity level of the context + and is the maximum severity level of + all the events in the queue of + events. */ + + khm_int32 flags; /*!< Flags. Used internally. */ + khm_ui_4 refcount; /*!< Reference count. Used + internally */ + + kherr_event *desc_event; /*!< Description event. The event that + describes the error context. This + points to an event that is not in + the event queue. */ + + kherr_event *err_event; /*!< Significant event. The last one + that caused the severity level to be + what it is right now. This points + to an event that is listed in the + event queue for this context.*/ + + khm_ui_4 progress_num; /*!< Progress numerator */ + khm_ui_4 progress_denom; /*!< Progress denominator */ + + TDCL(struct tag_kherr_context); + QDCL(struct tag_kherr_event); +} kherr_context; + +#define KHERR_CONTEXT_MAGIC 0x34f3238c + +enum kherr_context_flags { + KHERR_CF_NONE = 0x00000000, + /*!< None. */ + + KHERR_CF_DIRTY = 0x00000001, + /*!< Used Internally. Denotes that + the err_event and severity may need + to be recalculated. Cannot be set + as an initial flag. */ + + KHERR_CF_OWN_PROGRESS = 0x00000002, + /*!< The context maintains its own + progress meter as opposed to one + that is derived from child + contexts. */ + + KHERR_CF_UNBOUND = 0x00000004, + /*!< Unbound context. The context + can't be used to log events. Call + kherr_push_context() to associate + the context with the global context + hierarchy. Cannot be set as an + initial flag. */ + + KHERR_CF_TRANSITIVE = 0x00000008, + /*!< Transitive. The context is + automatically made the current + context for all other threads that + handle messages sent or posted by + threads whose current error context + is this one. */ + + KHERR_CFMASK_INITIAL = 0x0000000a, + /*!< Allowed initial flags */ +}; + +/*! \brief Maximum length of a string field in characters including terminating NULL + */ +#define KHERR_MAXCCH_STRING 1024 + +/*! \brief Maximum length of a string field in bytes including terminating NULL + */ +#define KHERR_MAXCB_STRING (KHERR_MAXCCH_STRING * sizeof(wchar_t)) + +/*! \brief Context event + + \see kherr_add_ctx_handler() +*/ +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 + state */ + KHERR_CTX_EVTCOMMIT = 0x0010 /*!< A event was committed into the + context */ +}; + +/*! \brief Context event handler + + Context event handlers are invoked when specific events occur with + respect to an error context. The ::kherr_ctx_event parameter + specifies which event occurred using one of the event values + described in the enumeration. The error context in which this + event occurred is specified by the ::kherr_context pointer. + + Note that if the handler needs to keep track of the error context + for later processing, it also needs to keep track of the \a serial + field of the error context. The same context object may be + reused, but the serial number is guaranteed to be unique. + + \see kherr_add_ctx_handler() + */ +typedef void (KHMAPI * kherr_ctx_handler)(enum kherr_ctx_event, + kherr_context *); + +/*! \brief Add a context event handler + + An application can register an event handler that gets notified of + events that pertain to error contexts. More than one handler can + be registered. The order in which the handlers are called is + undefined for any specific event. + + These event occur in the context of individual application + threads. The handler will be called from within the thread that + caused the event. Therefore it is important that the handler is + both reentrant and returns quickly. + + The events that the handler will be notified of are explained + below: + + KHERR_CTX_BEGIN: Notification that a new context was + created. A pointer to the context will be supplied to the + handler. The supplied pointer should not be used to obtain a hold + on the context, as it will prevent the context from being closed. + + KHERR_CTX_DESCRIBE: The thread called + kherr_set_desc_event() to set the description of a context. Once + again, the pointer should not be used to obtain a hold on the + context. + + KHERR_CTX_ERROR: The last event that was reported for the + context was an error event (the severity was was equal or higher + than KHERR_ERROR). The pointer may be used to obtain a hold on + the context. However, it is the application's resonsibility to + make sure that the hold is released later. Otherwise the event + will never be closed. + + KHERR_CTX_END: Closure. This event is signalled when the + last open handle to the context is closed and there is no thread + that is currently active which has this context in its error + context stack. At the time the handler is invoked, the context is + 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 + indication which notifications should be sent to the handler. + If a \a filter value of zero is provided, all of the events + will be sent to the handler. + + \param[in] serial The serial number of the error context that + should be tracked. If this is zero, all error contexts can + trigger the handler. + */ +KHMEXP void KHMAPI kherr_add_ctx_handler(kherr_ctx_handler h, + khm_int32 filter, + kherr_serial serial); + +/*! \brief Remove a context event handler + + Undoes what was done with kherr_add_ctx_handler() + + \see kherr_add_ctx_handler() + */ +KHMEXP void KHMAPI kherr_remove_ctx_handler(kherr_ctx_handler h, + kherr_serial serial); + + +/*! \brief Report an error + + Creates an event, fills in the details specified in the arguments, + and adds it to the current error context. + + If the current thread does not have an error context, no reporting + happens. However, if any of the supplied strings or parameters + are marked as allocated, they will be freed before the function + returns. + + Certain parameters that expect strings can instead be given string + resources, message resources or allocated strings in addition to + constant string. By default, the parameters are expected to be + constant strings. + + Allocated strings: The application can allocate memory for + a string. Since the application is not notified when the event is + no longer used and freed, it \b must indicate that the string is + an allocated string by setting the appropriate flag in the \a + flags parameter. When the event is no longer used, the memory + pointed to by the relevant pointer will be freed through a call to + free(). Not all string parameters take allocated strings. See + individual parameter documentation for details. + + String resources: On WIN32, string resources can be passed + in to kherr_report() using the MAKEINTRESOURCE macro. However, + the application \b must specify that the parameter is a string + resource using the appropriate flag in the \a flags parameter. + The error reporting engine will expand the string against the + module handle passed in the \a h_module parameter when the value + of the string is required. Not all string parameters take string + resources. See individual parameter documentation for details. + Strings loaded through string resources cannot be longer than + ::KHERR_MAXCCH_STRING in characters inclusive of terminating NULL. + + Message resources: On WIN32, message resources can be + passed in to kherr_report() by specifying the message ID where it + ordinarily expects a pointer to a constant string. The + application \b must indicate that the string is a message resource + by using the appropriate flag in the \a flags parameter. When the + value of the string is needed, it is expanded against the module + handle passed in the \a h_module parameter using the message ID. + Not all string parameters take message resources. See individual + parameter documentation for details. Note that the facility and + severity values associated with a message resource are ignored. + Strings loaded through message resources cannot be longer than + ::KHERR_MAXCCH_STRING in characters inclusive of terminating NULL. + + Formatted fields: Parameters that are formatted can have + can have parameter inserts like in printf(). However, specifying + inserts is different from printf() and follows the conventions + used in WIN32 API FormatMessage(). This is because for localized + strings, the order of the parameters in the string may be + different. See the documentation for FormatMessage() for details + on the format string. The same set of parameters (i.e. \a p1, \a + p2, \a p3, \a p4) is used for all formatted strings with + appropriate marshalling for 64 bit types. The size of the string + after expansion must not exceed 65536 bytes inclusive of + terminating NULL. + + \param[in] severity One of ::kherr_severity_level + \param[in] short_desc Short description or title (localized). Can + be a string resource, message resource, allocated string or + constant string. The \a flags parameter should indicate the + type of string used. + \param[in] facility Facility name of the reporter (not localized) + \param[in] location Usually the function name or such of where the + event occured (not localized) + \param[in] long_desc Long description of event (localized, + formatted). Can be a string resource, message resource, + allocated string or constant string. The \a flags parameter + should indicate the type of string used. + \param[in] suggestion Suggested action to correct situation, if + applicable (localized). Can be a string resource, message + resource, allocated string or constant string. The \a flags + parameter should indicate the type of string used. + \param[in] facility_id Identifier of facility. Application + defined. + \param[in] suggestion_id One of the suggestion identifiers from + ::kherr_suggestion_ids + \param[in] p1 First parameter. Used for formatting. + \param[in] p2 Second parameter. Used for formatting. + \param[in] p3 Third parameter. Used for formatting. + \param[in] p4 Fourth parameter. Used for formatting. + \param[in] flags Flags. See ::kherr_report_flags + \param[in] h_module Handle to a module that resolves any string or + message resources used for the \a short_description , \a + long_desc or \a suggestion parameters. This parameter is only + available on WIN32. + + \note With the exception of parameters of type KEPT_STRINGT and + parameters which are flagged for freeing using the \a flags + parameter, all other string parameters are assumed to be + pointers to constant strings. The strings are not copied and + the pointers are used as is. Also, no clean-up is performed + when the event is freed other than that implied by \a flags. + */ +KHMEXP kherr_event * KHMAPI kherr_report( + enum kherr_severity severity, + const wchar_t * short_desc, + const wchar_t * facility, + const wchar_t * location, + const wchar_t * long_desC, + const wchar_t * suggestion, + khm_int32 facility_id, + enum kherr_suggestion suggestion_id, + kherr_param p1, + kherr_param p2, + kherr_param p3, + kherr_param p4, + khm_int32 flags +#ifdef _WIN32 + ,HMODULE h_module +#endif +); + +/*! \brief Report a formatted message + + The format string \a long_desc_fmt should be a string constant and + the format specifiers follow that of \a sprintf. This creates an + event with the long description set to the expansion of the format + string against the arguments. + */ +KHMEXP kherr_event * __cdecl +kherr_reportf_ex(enum kherr_severity severity, + const wchar_t * facility, + khm_int32 facility_id, +#ifdef _WIN32 + HMODULE hModule, +#endif + const wchar_t * long_desc_fmt, + ...); +#define _reportf_ex kherr_reportf_ex + +/*! \brief Report a formatted message + + The format string \a long_desc_fmt should be a string constant and + the format specifiers follow that of \a sprintf. This creates an + event with the long description set to the expansion of the format + string against the arguments. + */ +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 + + A parameter is created by duplicating the string that is passed + into the function. If the string exceeds KHERR_MAXCCH_STRING, + then only the first part of the string that fits within the limit + is duplicated. + + The resulign ::kherr_param must be passed in to kherr_report(). + The event logging framework will free the duplicated string once + the data is no longer required. + */ +KHMEXP kherr_param kherr_dup_string(const wchar_t * s); + +__inline KHMEXP kherr_param +kherr_val(khm_octet ptype, khm_ui_8 pvalue) { + kherr_param p; + + p.type = ptype; + p.data = pvalue; + + return p; +} + +#define _int32(i) kherr_val(KEPT_INT32, (khm_ui_8) i) +#define _uint32(ui) kherr_val(KEPT_UINT32, (khm_ui_8) ui) +#define _int64(i) kherr_val(KEPT_INT64, (khm_ui_8) i) +#define _uint64(ui) kherr_val(KEPT_UINT64, (khm_ui_8) ui) +#define _cstr(cs) kherr_val(KEPT_STRINGC, (khm_ui_8) cs) +#define _tstr(ts) kherr_val(KEPT_STRINGT, (khm_ui_8) ts) +#define _cptr(p) kherr_val(KEPT_PTR, (khm_ui_8) p) +#define _vnull() kherr_val(KEPT_NONE, 0) +#define _dupstr(s) kherr_dup_string(s) + +/* convenience macros for calling kherr_report */ +#ifdef KHERR_HMODULE + +#define _report_cs0(severity, long_description) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, _vnull(), _vnull(), _vnull(), _vnull(), 0, KHERR_HMODULE) + +#define _report_cs1(severity, long_description, p1) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, _vnull(), _vnull(), _vnull(), 0, KHERR_HMODULE) + +#define _report_cs2(severity, long_description, p1, p2) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, _vnull(), _vnull(), 0, KHERR_HMODULE) + +#define _report_cs3(severity, long_description, p1, p2, p3) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, _vnull(), 0, KHERR_HMODULE) + +#define _report_cs4(severity, long_description, p1, p2, p3, p4) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, 0, KHERR_HMODULE) + +#else + +#define _report_cs0(severity, long_description) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, _vnull(), _vnull(), _vnull(), _vnull(), 0, NULL) + +#define _report_cs1(severity, long_description, p1) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, _vnull(), _vnull(), _vnull(), 0, NULL) + +#define _report_cs2(severity, long_description, p1, p2) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, _vnull(), _vnull(), 0, NULL) + +#define _report_cs3(severity, long_description, p1, p2, p3) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, _vnull(), 0, NULL) + +#define _report_cs4(severity, long_description, p1, p2, p3, p4) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, 0, NULL) +#endif /* !defined(KHERR_HMODULE) */ + +#ifdef _WIN32 +#define _report_sr0(severity, long_desc_id) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, _vnull(), _vnull(), _vnull(), _vnull(), KHERR_RF_RES_LONG_DESC, KHERR_HMODULE) + +#define _report_sr1(severity, long_desc_id, p1) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, p1, _vnull(), _vnull(), _vnull(), KHERR_RF_RES_LONG_DESC, KHERR_HMODULE) + +#define _report_sr2(severity, long_desc_id, p1, p2) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, _vnull(), _vnull(), KHERR_RF_RES_LONG_DESC, KHERR_HMODULE) + +#define _report_sr3(severity, long_desc_id, p1, p2, p3) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, _vnull(), KHERR_RF_RES_LONG_DESC, KHERR_HMODULE) + +#define _report_sr4(severity, long_desc_id, p1, p2, p3, p4) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, KHERR_RF_RES_LONG_DESC, KHERR_HMODULE) +#endif + +#ifdef _WIN32 +#define _report_mr0(severity, long_desc_msg_id) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, _vnull(), _vnull(), _vnull(), _vnull(), KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE) + +#define _report_mr1(severity, long_desc_msg_id, p1) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, p1, _vnull(), _vnull(), _vnull(), KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE) + +#define _report_mr2(severity, long_desc_msg_id, p1, p2) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, _vnull(), _vnull(), KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE) + +#define _report_mr3(severity, long_desc_msg_id, p1, p2, p3) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, _vnull(), KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE) + +#define _report_mr4(severity, long_desc_msg_id, p1, p2, p3, p4) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE) +#endif + +#define _report_ts0(severity, long_desc_ptr) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, _vnull(), _vnull(), _vnull(), _vnull(), KHERR_RF_FREE_LONG_DESC, NULL) + +#define _report_ts1(severity, long_desc_ptr, p1) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, p1, _vnull(), _vnull(), _vnull(), KHERR_RF_FREE_LONG_DESC, NULL) + +#define _report_ts2(severity, long_desc_ptr, p1, p2) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, p1, p2, _vnull(), _vnull(), KHERR_RF_FREE_LONG_DESC, NULL) + +#define _report_ts3(severity, long_desc_ptr, p1, p2, p3) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, _vnull(), KHERR_RF_FREE_LONG_DESC, NULL) + +#define _report_ts4(severity, long_desc_ptr, p1, p2, p3, p4) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, KHERR_RF_FREE_LONG_DESC, NULL) + +/*! \brief Set the suggestion and suggestion identifier for the last event + + The event that will be modified is the last event reported by the + calling thread. + */ +KHMEXP void KHMAPI kherr_suggest(wchar_t * suggestion, khm_int32 suggestion_id, khm_int32 flags); +#define _suggest_cs(cs,sid) kherr_suggest((cs), (sid), KHERR_RF_CSTR_SUGGEST) +#define _suggest_ts(ts,sid) kherr_suggest((ts), (sid), KHERR_RF_FREE_SUGGEST) +#define _suggest_sr(sr,sid) kherr_suggest(MAKEINTRESOURCE(sr), (sid), KHERR_RF_RES_SUGGEST) +#define _suggest_mr(mr,sid) kherr_suggest((wchar_t *)(DWORD_PTR)(mr), (sid), KHERR_RF_MSG_SUGGEST) + +/*! \brief Set the location string for the last event + + The event that will be modified is the last event reported by the + calling thread. + */ +KHMEXP void KHMAPI kherr_location(wchar_t * location); +#define _location(l) kherr_location(l) + +/*! \brief Set the facility string and identifier for the last event + + The event that will be modified is the last event reported by the + calling thread. + */ +KHMEXP void KHMAPI kherr_facility(wchar_t * facility, khm_int32 facility_id); +#define _facility(f,fid) kherr_facility((f),(fid)) + +/*! \brief Marks the last event as the descriptor event for the current error context + + Note that marking an event as the descriptor event has the effect + of removing the event from event queue. The event will henceforth + be used as the descriptor for the context. The only effective + fields of a descriptor event are \a short_desc, \a long_desc, \a + facility, \a facility_id and the parameters which are used for + resolving formatted strings in the aforementioned fields. + + Upon calling kherr_set_desc_event(), the event will be + automatically evaluated as if kherr_evaluate_event() was called. + + The event that will be referenced is the last event reported by + the calling thread. + */ +KHMEXP void KHMAPI kherr_set_desc_event(void); +#define _describe kherr_set_desc_event + +/*! \brief Delete the last event + + The event that will be deleted is the last event reported by the + calling thread. + */ +KHMEXP void KHMAPI kherr_del_last_event(void); +#define _del_event kherr_del_last_event + +/*! \brief Create a new context + + The created context is not bound to any thread or any context + hierarchy. Hence it cannot be used to capture any events until it + is used in a call to kherr_push_context(). + + Release the returned context pointer with a call to + kherr_release_context(). + + \param[in] flags Initial flags for the context. Combination of + ::kherr_context_flags + + \note This function is for internal use only. + */ +KHMEXP kherr_context * KHMAPI kherr_create_new_context(khm_int32 flags); + +/*! \brief Obtain a hold on a context */ +KHMEXP void KHMAPI kherr_hold_context(kherr_context * c); + +/*! \brief Release a context */ +KHMEXP void KHMAPI kherr_release_context(kherr_context * c); + +/*! \brief Push an empty context + + Creates an empty context, adds it as a child of the current + thread's error context. If the current thread does not have an + error context, then the created error context will be a root level + context. + + The new context will be the current error context for the calling + thread. + + \param[in] flags Initial flags for the context. Combination of + ::kherr_context_flags + + \see kherr_push_new_context() for more information about thread + specific context stacks. + + */ +KHMEXP void KHMAPI kherr_push_new_context(khm_int32 flags); +#define _begin_task kherr_push_new_context + +/*! \brief Push a context + + Each thread has a stack of error contexts. The topmost one is + current. The thread can push or pop contexts on to the stack + independently of the hierarchy of contexts (the only exception, as + explained below is when the context that is being pushed is + unbound). + + If the context being pushed by kherr_push_context() is unbound, + then it will be attached to the current context of the thread as a + child. Once the new context is pushed to the top of the stack, it + will become the current context for the thread. + + The calling thread must call kherr_pop_context() to remove the + context from the top of the stack. Each call to + kherr_push_new_context() or kher_push_context() must have a + corresponding kherr_pop_context() call. + + When the thread terminates, all of the contexts in the thread's + context stack will be automatically removed. + + \see kherr_pop_context() + */ +KHMEXP void KHMAPI kherr_push_context(kherr_context * c); + +/*! \brief Pop a context + + Remove the current error context from the thread's context stack. + If no other open handles exist to the error context, this causes + the error context to collapse into it's parent context or vanish + entirely unless the context contains an error. + + \see kherr_push_context() for more information about thread + specific context stacks. + */ +KHMEXP void KHMAPI kherr_pop_context(void); +#define _end_task kherr_pop_context + +/*! \brief Retrieve the current error context + + The returned pointer must be released with a call to + kherr_release_context(). +*/ +KHMEXP kherr_context * KHMAPI kherr_peek_context(void); + +/*! \brief Check if the current error context indicates an error + + \return TRUE if there is an error. FALSE otherwise. + \see kherr_analyze() + */ +KHMEXP khm_boolean KHMAPI kherr_is_error(void); + +/*! \brief Check if an error context indicates an error + + \return TRUE if there is an error. FALSE otherwise. + \see kherr_analyze() + */ +KHMEXP khm_boolean KHMAPI kherr_is_error_i(kherr_context * c); + +/*! \brief Clear the error state of the current context */ +KHMEXP void KHMAPI kherr_clear_error(void); + +/*! \brief Clear the error state of an error context */ +KHMEXP void KHMAPI kherr_clear_error_i(kherr_context * c); + +/*! \brief Set the progress meter of the current error context + + Setting \a denom to zero removes the progress meter. + */ +KHMEXP void KHMAPI kherr_set_progress(khm_ui_4 num, khm_ui_4 denom); +#define _progress(num,denom) kherr_set_progress((num),(denom)) + +/*! \brief Get the progress meter of the current error context + */ +KHMEXP void KHMAPI kherr_get_progress(khm_ui_4 * num, khm_ui_4 * denom); + +/*! \brief Get the progress meter of an error context + */ +KHMEXP void KHMAPI kherr_get_progress_i(kherr_context * c, khm_ui_4 * num, khm_ui_4 * denom); + +/*! \brief Get the first event in a context + + 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 + 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_next_event(), kherr_get_prev_event(), + kherr_get_last_event() + */ +KHMEXP kherr_event * KHMAPI kherr_get_first_event(kherr_context * c); + +/*! \brief Get the next event + + Call kherr_get_first_event() to obtain the first event in a + context. Subsequent calls to kherr_get_next_event() will yield + other events in the order in which they were reported. The list + ends when kherr_get_next_event() returns NULL. + + 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 + 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 + first child of an error context. Use kherr_get_next_context() to + obtain the other contexts. If \a c is \a NULL, this returns the + first root level context. + + The returned pointer must be released with a call to + kherr_release_context() + */ +KHMEXP kherr_context * KHMAPI kherr_get_first_context(kherr_context * c); + +/*! \brief Get the next sibling context of a context + + The returned pointer must be released with a call to + kherr_release_context() + + \see kherr_get_first_context() + */ +KHMEXP kherr_context * KHMAPI kherr_get_next_context(kherr_context * c); + +/*! \brief Get the desciption event for the context + + The description event is the event that was denoted using + kherr_set_desc_event() as the event which describes the context. + + 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. + */ +KHMEXP kherr_event * KHMAPI kherr_get_desc_event(kherr_context * c); + +/*! \brief Get the error event for the context + + The error event for a context is the last event that had the + highest severity level. + + 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. + */ +KHMEXP kherr_event * KHMAPI kherr_get_err_event(kherr_context * c); + +/*! \brief Evaluate an event + + When an event is reported, all the parameters and resource + references that were passed to kherr_report() are kept as-is until + the actual string values are required by the error reporting + library. However, if the string fields are required before then, + an application can call kherr_evaluate_event() to get them. + + This function does the following: + + - Load any referenced string or message resources that are + referenced in the event's short description, long description or + suggestion. + + - Expand any inserts using the parameters that were passed in. + + - Free up allocated strings in for the descriptions or suggestion + fields and any parameters. + + - Update the string fields in the event to contain the newly + generated strings. + + */ +KHMEXP void KHMAPI kherr_evaluate_event(kherr_event * e); + +/*! \brief Evaluate the last event + + Same as kherr_evaluate_event(), but operates on the last event + logged by the current thread. + + \see kherr_evaluate_event() + */ +KHMEXP void KHMAPI kherr_evaluate_last_event(void); +#define _resolve kherr_evaluate_last_event + +/*! \defgroup kherr_fids Standard Facility IDs +@{*/ +#define KHM_FACILITY_KMM 1 +#define KHM_FACILITY_KCDB 2 +#define KHM_FACILITY_UI 3 +#define KHM_FACILITY_KRB5 64 +#define KHM_FACILITY_KRB4 65 +#define KHM_FACILITY_AFS 66 +#define KHM_FACILITY_USER 128 +/*@}*/ + +/*@}*/ + +/* In debug mode, outputs the formatted string to the debug console */ +#ifdef DEBUG +KHMEXP void kherr_debug_printf(wchar_t * fmt, ...); +#endif + +#endif diff --git a/src/windows/identity/kherr/kherrinternal.h b/src/windows/identity/kherr/kherrinternal.h index da33c596e..fb6412aa2 100644 --- a/src/windows/identity/kherr/kherrinternal.h +++ b/src/windows/identity/kherr/kherrinternal.h @@ -1,69 +1,69 @@ -/* - * 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_KHERRORINTERNAL_H -#define __KHIMAIRA_KHERRORINTERNAL_H - -#include -#include -#include -#include - -typedef struct tag_kherr_thread { - khm_size nc_ctx; - khm_size n_ctx; - kherr_context ** ctx; -} kherr_thread; - -#define THREAD_STACK_SIZE 8 - -typedef struct tag_kherr_handler_node { - khm_int32 filter; - kherr_ctx_handler h; - kherr_serial serial; -} kherr_handler_node; - -#define CTX_ALLOC_INCR 4 - -#define EVENT_MASK_UNRESOLVED \ - (KHERR_RF_RES_SHORT_DESC|KHERR_RF_MSG_SHORT_DESC| \ - KHERR_RF_RES_LONG_DESC|KHERR_RF_MSG_LONG_DESC| \ - KHERR_RF_RES_SUGGEST|KHERR_RF_MSG_SUGGEST) - -extern CRITICAL_SECTION cs_error; -extern DWORD tls_error; -extern kherr_context * ctx_free_list; -extern kherr_event * evt_free_list; -extern kherr_handler_node * ctx_handlers; -extern khm_size n_ctx_handlers; - -#define parm_type(p) ((p).type) -#define parm_data(p) ((p).data) - -void resolve_event_strings(kherr_event *); -void attach_this_thread(void); -void detach_this_thread(void); -#endif +/* + * 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_KHERRORINTERNAL_H +#define __KHIMAIRA_KHERRORINTERNAL_H + +#include +#include +#include +#include + +typedef struct tag_kherr_thread { + khm_size nc_ctx; + khm_size n_ctx; + kherr_context ** ctx; +} kherr_thread; + +#define THREAD_STACK_SIZE 8 + +typedef struct tag_kherr_handler_node { + khm_int32 filter; + kherr_ctx_handler h; + kherr_serial serial; +} kherr_handler_node; + +#define CTX_ALLOC_INCR 4 + +#define EVENT_MASK_UNRESOLVED \ + (KHERR_RF_RES_SHORT_DESC|KHERR_RF_MSG_SHORT_DESC| \ + KHERR_RF_RES_LONG_DESC|KHERR_RF_MSG_LONG_DESC| \ + KHERR_RF_RES_SUGGEST|KHERR_RF_MSG_SUGGEST) + +extern CRITICAL_SECTION cs_error; +extern DWORD tls_error; +extern kherr_context * ctx_free_list; +extern kherr_event * evt_free_list; +extern kherr_handler_node * ctx_handlers; +extern khm_size n_ctx_handlers; + +#define parm_type(p) ((p).type) +#define parm_data(p) ((p).data) + +void resolve_event_strings(kherr_event *); +void attach_this_thread(void); +void detach_this_thread(void); +#endif diff --git a/src/windows/identity/kherr/kherrmain.c b/src/windows/identity/kherr/kherrmain.c index 0ae229204..c7afd7bc2 100644 --- a/src/windows/identity/kherr/kherrmain.c +++ b/src/windows/identity/kherr/kherrmain.c @@ -1,52 +1,52 @@ -/* - * 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 - -void -kherr_process_attach(void) { - InitializeCriticalSection(&cs_error); - tls_error = TlsAlloc(); -} - -void -kherr_process_detach(void) { - TlsFree(tls_error); - DeleteCriticalSection(&cs_error); -} - -void -kherr_thread_attach(void) { - /* We don't call attach_this_thread() here since we only - want to create a context stack for this thread if - someone wants one. */ - /* attach_this_thread(); */ -} - -void -kherr_thread_detach(void) { - detach_this_thread(); -} +/* + * 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 + +void +kherr_process_attach(void) { + InitializeCriticalSection(&cs_error); + tls_error = TlsAlloc(); +} + +void +kherr_process_detach(void) { + TlsFree(tls_error); + DeleteCriticalSection(&cs_error); +} + +void +kherr_thread_attach(void) { + /* We don't call attach_this_thread() here since we only + want to create a context stack for this thread if + someone wants one. */ + /* attach_this_thread(); */ +} + +void +kherr_thread_detach(void) { + detach_this_thread(); +} diff --git a/src/windows/identity/kmm/kmm.c b/src/windows/identity/kmm/kmm.c index 5e955953d..721865c4d 100644 --- a/src/windows/identity/kmm/kmm.c +++ b/src/windows/identity/kmm/kmm.c @@ -1,192 +1,192 @@ -/* - * 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 - -khm_boolean kmmint_load_locale_lib(kmm_module_i * m, kmm_module_locale * l) -{ - HMODULE h; - - if(l->filename != NULL) { - wchar_t path[MAX_PATH]; - DWORD dw; - - /* construct the path name */ - assert(m->h_module != NULL); - - dw = PathIsFileSpec(l->filename); - - assert(dw); - if (!dw) - return FALSE; - - dw = GetModuleFileName(m->h_module, path, ARRAYLENGTH(path)); - assert(dw != 0); - if (dw == 0) - return FALSE; - - PathRemoveFileSpec(path); - dw = PathAppend(path, l->filename); - assert(dw); - if (!dw) - return FALSE; - - h = LoadLibrary(path); - if(!h) - return FALSE; - - EnterCriticalSection(&cs_kmm); - m->h_resource = h; - m->lcid_resource = l->language; - LeaveCriticalSection(&cs_kmm); - - return TRUE; - - } else { - /* in this case, the language resources are assumed to be in the - main module library itself. */ - - EnterCriticalSection(&cs_kmm); - m->h_resource = m->h_module; - m->lcid_resource = l->language; - LeaveCriticalSection(&cs_kmm); - - return TRUE; - } -} - - -KHMEXP khm_int32 KHMAPI kmm_set_locale_info(kmm_module module, kmm_module_locale * locales, khm_int32 n_locales) -{ - kmm_module_i * m; - LANGID lcid; - int i; - int * f; - khm_int32 rv = KHM_ERROR_SUCCESS; - - m = kmm_module_from_handle(module); - - if(!m || m->state != KMM_MODULE_STATE_INIT) - return KHM_ERROR_INVALID_OPERATION; - - if(!locales || n_locales < 0) - return KHM_ERROR_INVALID_PARAM; - - f = PMALLOC(n_locales * sizeof(int)); - if(!f) - return KHM_ERROR_UNKNOWN; - ZeroMemory(f, sizeof(int) * n_locales); - - lcid = GetUserDefaultLangID(); - - /* first search for an exact match */ - for(i=0; ih_resource; -} -#endif - -KHMEXP kmm_module KHMAPI -kmm_this_module(void) { - kmm_plugin_i * p; - kmm_module_i * m; - kmm_module vm; - - p = TlsGetValue(tls_kmm); - if (!kmm_is_plugin(p)) - return NULL; - - m = p->module; - vm = kmm_handle_from_module(m); - - kmm_hold_module(vm); - - return vm; -} - -KHMEXP kmm_plugin KHMAPI -kmm_this_plugin(void) { - kmm_plugin_i * p; - kmm_plugin vp; - - p = TlsGetValue(tls_kmm); - if (!kmm_is_plugin(p)) - return NULL; - - vp = kmm_handle_from_plugin(p); - - kmm_hold_plugin(vp); - - return vp; -} +/* + * 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 + +khm_boolean kmmint_load_locale_lib(kmm_module_i * m, kmm_module_locale * l) +{ + HMODULE h; + + if(l->filename != NULL) { + wchar_t path[MAX_PATH]; + DWORD dw; + + /* construct the path name */ + assert(m->h_module != NULL); + + dw = PathIsFileSpec(l->filename); + + assert(dw); + if (!dw) + return FALSE; + + dw = GetModuleFileName(m->h_module, path, ARRAYLENGTH(path)); + assert(dw != 0); + if (dw == 0) + return FALSE; + + PathRemoveFileSpec(path); + dw = PathAppend(path, l->filename); + assert(dw); + if (!dw) + return FALSE; + + h = LoadLibrary(path); + if(!h) + return FALSE; + + EnterCriticalSection(&cs_kmm); + m->h_resource = h; + m->lcid_resource = l->language; + LeaveCriticalSection(&cs_kmm); + + return TRUE; + + } else { + /* in this case, the language resources are assumed to be in the + main module library itself. */ + + EnterCriticalSection(&cs_kmm); + m->h_resource = m->h_module; + m->lcid_resource = l->language; + LeaveCriticalSection(&cs_kmm); + + return TRUE; + } +} + + +KHMEXP khm_int32 KHMAPI kmm_set_locale_info(kmm_module module, kmm_module_locale * locales, khm_int32 n_locales) +{ + kmm_module_i * m; + LANGID lcid; + int i; + int * f; + khm_int32 rv = KHM_ERROR_SUCCESS; + + m = kmm_module_from_handle(module); + + if(!m || m->state != KMM_MODULE_STATE_INIT) + return KHM_ERROR_INVALID_OPERATION; + + if(!locales || n_locales < 0) + return KHM_ERROR_INVALID_PARAM; + + f = PMALLOC(n_locales * sizeof(int)); + if(!f) + return KHM_ERROR_UNKNOWN; + ZeroMemory(f, sizeof(int) * n_locales); + + lcid = GetUserDefaultLangID(); + + /* first search for an exact match */ + for(i=0; ih_resource; +} +#endif + +KHMEXP kmm_module KHMAPI +kmm_this_module(void) { + kmm_plugin_i * p; + kmm_module_i * m; + kmm_module vm; + + p = TlsGetValue(tls_kmm); + if (!kmm_is_plugin(p)) + return NULL; + + m = p->module; + vm = kmm_handle_from_module(m); + + kmm_hold_module(vm); + + return vm; +} + +KHMEXP kmm_plugin KHMAPI +kmm_this_plugin(void) { + kmm_plugin_i * p; + kmm_plugin vp; + + p = TlsGetValue(tls_kmm); + if (!kmm_is_plugin(p)) + return NULL; + + vp = kmm_handle_from_plugin(p); + + kmm_hold_plugin(vp); + + return vp; +} diff --git a/src/windows/identity/kmm/kmm.h b/src/windows/identity/kmm/kmm.h index d10f2150e..735f006ad 100644 --- a/src/windows/identity/kmm/kmm.h +++ b/src/windows/identity/kmm/kmm.h @@ -1,1068 +1,1068 @@ -/* - * 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_KMM_H -#define __KHIMAIRA_KMM_H - -#include -#include - -/*! \defgroup kmm NetIDMgr Module Manager -@{*/ - -/*! \brief A handle to a module. -*/ -typedef khm_handle kmm_module; - -/*! \brief A handle to a plugin. - */ -typedef khm_handle kmm_plugin; - -/*! \name Limits - @{*/ - -/*! \brief Maximum number of characters in a name in KMM including the terminating NULL */ -#define KMM_MAXCCH_NAME 256 - -/*! \brief Maximum number of bytes in a name in KMM including the terminating NULL */ -#define KMM_MAXCB_NAME (sizeof(wchar_t) * KMM_MAXCCH_NAME) - -/*! \brief Maximum number of characters in a description in KMM including the terminating NULL */ -#define KMM_MAXCCH_DESC 512 - -/*! \brief Maximum number of bytes in a description in KMM including the terminating NULL */ -#define KMM_MAXCB_DESC (sizeof(wchar_t) * KMM_MAXCCH_NAME) - -/*! \brief Maximum number of characters in a vendor string in KMM including the terminating NULL */ -#define KMM_MAXCCH_VENDOR 256 - -/*! \brief Maximum number of bytes in a vendor string in KMM including the terminating NULL */ -#define KMM_MAXCB_VENDOR (sizeof(wchar_t) * KMM_MAXCCH_VENDOR) - -/*! \brief Maximum number of characters in a support URI in KMM including the terminating NULL */ -#define KMM_MAXCCH_SUPPORT 256 - -/*! \brief Maximum number of bytes in a vendor string in KMM including the terminating NULL */ -#define KMM_MAXCB_SUPPORT (sizeof(wchar_t) * KMM_MAXCCH_SUPPORT) - -/*! \brief Maximum number of dependencies per plugin -*/ -#define KMM_MAX_DEPENDENCIES 8 - -/*! \brief Maximum number of dependants per plugin - */ -#define KMM_MAX_DEPENDANTS 32 - -/*! \brief Maximum number of characters a dependency string including trailing double NULL */ -#define KMM_MAXCCH_DEPS (KMM_MAXCCH_NAME * KMM_MAX_DEPENDENCIES + 1) - -/*! \brief Maximum number of bytes in a dependency string including trailing double NULL */ -#define KMM_MAXCB_DEPS (sizeof(wchar_t) * KMM_MAXCCH_DEPS) -/*@}*/ /* Limits */ - -/*! \brief Plugin registration - - \see ::khm_cred_provider -*/ -typedef struct tag_kmm_plugin_reg { - wchar_t * name; /*!< Name of the plugin. Maximum of - KMM_MAXCCH_NAME characters - including the terminating - NULL. Required. */ - - wchar_t * module; /*!< Name of module that owns the - plugin. Maximum of - KMM_MAXCCH_NAME characters - including terminating NULL. - Required. */ - - khm_int32 type; /*!< Type plugin type. One of - KHM_PITYPE_*. Required. */ - khm_int32 flags; /*!< Unused. Set to 0 */ - kmq_callback_t msg_proc; /*!< Message processor. Required. */ - wchar_t * dependencies; /*!< Dependencies. Note that this is - a multi string. (you can use the - KHC multi string functions to - manipulate multi strings or to - convert a comma separated list of - dependencies to a multi string). - Each string in the multi string - is a name of a plugin that this - plugin depends on. Optional (set - to NULL if this plugin has no - dependencies). Maximum of - KMM_MAXCCH_DEPS characters - including terminating double - NULL.*/ - - wchar_t * description; /*!< Description of the plugin. - Maximum of KMM_MAXCCH_DESC - characters including the - terminating - NULL. Localized. Optional (set to - NULL if not provided) */ -#ifdef _WIN32 - HICON icon; /*!< Icon used to represent the - plugin. Optional. (set to NULL if - not provided) */ -#endif -} kmm_plugin_reg; - -/*! \brief Plugin information -*/ -typedef struct tag_kmm_plugin_info { - kmm_plugin_reg reg; /*!< Registration info */ - - khm_int32 state; /*!< Current status of the plugin. - One of ::_kmm_plugin_states */ - - khm_int32 failure_count; /*!< Number of recorded failures in - the plugin */ - FILETIME failure_time; /*!< Time of first recorded failure */ - khm_int32 failure_reason; /*!< The reason for the first recorded - 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 0x00000400 - -/*! \name Plugin types -@{*/ -/*! \brief A credentials provider - - \see \ref pi_pt_cred for more information. - */ -#define KHM_PITYPE_CRED 1 - -/*! \brief A identity provider - - \see \ref pi_pt_cred for more information - */ -#define KHM_PITYPE_IDENT 2 - -/*! \brief A configuration provider - - \see \ref pi_pt_conf for more information. - */ -#define KHM_PITYPE_CONFIG 3 - -/*! \brief Undefined plugin type - - The plugin doesn't provide any credential type. - */ -#define KHM_PITYPE_MISC 4 - -/*@}*/ - -/*! \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 - reached the maximum number - of failures and cannot be - initialized until the - failure count is reset */ - KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED = -3, /*!< Failed because the - plugin was not registered - and automatic registration - failed. */ - KMM_PLUGIN_STATE_FAIL_DISABLED = -2,/*!< Failed because plugin was - disabled by the user. */ - KMM_PLUGIN_STATE_FAIL_LOAD = -1, /*!< The plugin failed to load - due to some unknown - reason. */ - KMM_PLUGIN_STATE_NONE = 0, /*!< Unknown state */ - KMM_PLUGIN_STATE_PLACEHOLDER, /*!< Placeholder. The plugin - hasn't been provided by - anyone yet, but the plugin - record has been created to - keep track of - dependencies. */ - KMM_PLUGIN_STATE_REG, /*!< The plugin is registered - but not initialized */ - KMM_PLUGIN_STATE_PREINIT, /*!< The plugin is in the - process of being - initialized */ - KMM_PLUGIN_STATE_HOLD, /*!< On hold. One or more - dependencies of this plugin - has not been resolved */ - KMM_PLUGIN_STATE_INIT, /*!< The plugin was initialized */ - KMM_PLUGIN_STATE_RUNNING, /*!< The plugin is running */ - KMM_PLUGIN_STATE_EXITED /*!< The plugin has been stopped. */ -}; - -/*! \brief Module registration */ -typedef struct tag_kmm_module_reg { - wchar_t * name; /*!< Identifier for the module */ - wchar_t * path; /*!< Full pathname to module - binary */ - - wchar_t * description; /*!< Description of module */ - - wchar_t * vendor; /*!< Vendor/copyright string */ - - wchar_t * support; /*!< Support URL/contact */ - - khm_int32 n_plugins; /*!< Number of plugins that are - active */ - kmm_plugin_reg * plugin_reg_info; /*!< Array of kmm_plugin_reg - records for each active - plugin */ -} kmm_module_reg; - -/*! \brief Module information record */ -typedef struct tag_kmm_module_info { - kmm_module_reg reg; /*!< Registration info */ - - khm_ui_4 language; /*!< Currently loaded langugage */ - - khm_int32 state; /*!< Current status of the - module */ - - khm_version file_version; /*!< File version for the - module */ - khm_version product_version; /*!< Product version for the - module */ - - khm_int32 failure_count; /*!< Number of times the module - has failed to load */ - FILETIME failure_time; /*!< Time of first recorded - failure */ - khm_int32 failure_reason; /*!< Reason for first failure. - One of the module status - values */ - - kmm_module h_module; /*!< Handle to the module. */ -} kmm_module_info; - -/*! \brief Module states -*/ -enum KMM_MODULE_STATES { - KMM_MODULE_STATE_FAIL_INCOMPAT=-12, /*!< The library containing - the module was not - compatible with this version - of NetIDMgr. */ - KMM_MODULE_STATE_FAIL_INV_MODULE=-11, /*!< The library containing - the module was invalid. */ - KMM_MODULE_STATE_FAIL_UNKNOWN=-10, /*!< Module could not be - loaded due to unknown - reasons. */ - KMM_MODULE_STATE_FAIL_MAX_FAILURE=-9,/*!< The module has failed - too many times already. Not - attempting to restart it - again */ - KMM_MODULE_STATE_FAIL_DUPLICATE=-8, /*!< An attempt was made to - load the same module - twice. */ - KMM_MODULE_STATE_FAIL_NOT_REGISTERED=-7, /*!< The module is not - found among the registered - module list */ - KMM_MODULE_STATE_FAIL_NO_PLUGINS=-6,/*!< The module provided no - plugins, or all the plugins - that are provided are - disabled */ - KMM_MODULE_STATE_FAIL_DISABLED=-5, /*!< Module is disabled and - cannot be loaded */ - KMM_MODULE_STATE_FAIL_LOAD=-4, /*!< The module failed to - initialize */ - KMM_MODULE_STATE_FAIL_INVALID=-3, /*!< The module was invalid. - Typically caused by the - required entrypoints not - being present */ - KMM_MODULE_STATE_FAIL_SIGNATURE=-2, /*!< The module failed to load - due to an unverifiable - signature */ - KMM_MODULE_STATE_FAIL_NOT_FOUND=-1, /*!< The module was not - found */ - KMM_MODULE_STATE_NONE=0, /*!< Unknown state. The handle - is possibly invalid */ - KMM_MODULE_STATE_PREINIT, /*!< The module is being - loaded. init_module() hasn't - been called yet */ - KMM_MODULE_STATE_INIT, /*!< In init_module() */ - KMM_MODULE_STATE_INITPLUG, /*!< Initializing plugins */ - KMM_MODULE_STATE_RUNNING, /*!< Running */ - KMM_MODULE_STATE_EXITPLUG, /*!< Currently exiting plugins */ - KMM_MODULE_STATE_EXIT, /*!< Currently exiting */ - KMM_MODULE_STATE_EXITED /*!< Exited */ -}; - -/*! \brief Start the Module Manager - - \note Only called by the NetIDMgr core. -*/ -KHMEXP void KHMAPI -kmm_init(void); - -/*! \brief Stop the Module Manager - - \note Only called by the NetIDMgr core. -*/ -KHMEXP void KHMAPI -kmm_exit(void); - -/*! \brief Return the plugin handle for the current plugin - - The returned handle represents the plugin which owns the current - thread. The returned handle must be released by calling - kmm_release_plugin(). Returns NULL if the current thread is not - owned by any plugin. - */ -KHMEXP kmm_plugin KHMAPI -kmm_this_plugin(void); - -/*! \brief Return the module handle for the current module - - The returned handle represents the module which owns the current - thread. The returned handle must be released by calling - kmm_release_module() -*/ -KHMEXP kmm_module KHMAPI -kmm_this_module(void); - -/*! \name Flags for kmm_load_module() -@{*/ -/*!\brief Load synchronously - - If this flag is set, then the function waits for the module to be - loaded. The default is to load the module asynchronously. - - When loading a module asynchronously, the kmm_load_module() - function returns KHM_ERROR_SUCCESS and exits without waiting for - the module to load. If \a result is not NULL, it will receive a - valid handle to the module. - - When loading a module synchronously, kmm_load_module() will wait - for the module to completely load. If it fails to load properly, - it will return an error code and set \a result to NULL. -*/ -#define KMM_LM_FLAG_SYNC 1 - -/*! \brief Do not load - - Indicates that the module shouldn't actually be loaded. If the - specified module name identifies a module that has already been - loaded, then the function returns a held handle to the existing - module (use kmm_release_module() to free the handle). Otherwise, - the function returns KHM_ERROR_NOT_FOUND. -*/ -#define KMM_LM_FLAG_NOLOAD 2 -/*@}*/ - -/*! \brief Load a module - - The \a modulename parameter specifies a module to load. Depending - on the configuration, not all of the plugins that are provided by - the module may be loaded. If no plugins are successfully loaded, - the module will be immediately unloaded. - - If the module is currently loaded or is being loaded, then a valid - handle to the existing module is returned. - - When called with KMM_LM_FLAG_SYNC, the function does not return - until the module and the associated plugins are all initialized, - or an error occurs. - - If the KMM_LM_FLAG_NOLOAD flag is set, then a handle to an - existing instance of the module will be returned. If the module - hasn't been loaded yet, then no handle is returned and the - function returns KHM_ERROR_NOT_FOUND. - - See the associated NetIDMgr Module Manager documentation on the - sequence of events associated with loading a module. - - \param[in] modulename Name of the module. The module should have - been registered under this name prior to the call. - \param[in] flags Combination of KMM_LM_FLAG_* - \param[out] result Receives a handle to the loaded module. If the - result is not required, set this to NULL. If \a result is not - NULL, and km_load_module() returns KHM_ERROR_SUCCESS, then - kmm_release_module() must be called to release the handle to - the module. Otherwise, \a result receives NULL. If a handle - is returned, it will be valid regardless of whether the module - fails to load or not. You can use kmm_get_module_state() to - query the progress of the loading process. See - ::KMM_LM_FLAG_SYNC. - - \retval KHM_ERROR_SUCCESS The call succeeded. If \a - KMM_LM_FLAG_SYNC was specified, this means that the module was - successfully loaded. Otherwise, it only means that the module - has been queued up for loading. Use kmm_get_module_state() to - determine if it was successfully loaded. If \a result is not - NULL, a valid handle is returned. - \retval KHM_ERROR_EXISTS The module is already loaded or has been - already queued for loading. If \a result is not NULL, a valid - handle to the existing module instance is returned. - \retval KHM_ERROR_NOT_FOUND If called with KMM_LM_FLAG_NOLOAD, - indicates that the module has not been loaded. Otherwise only - returned when called with KMM_LM_FLAG_SYNC. The module image - was not found. No handle is returned. - \retval KHM_ERROR_INVALID_SIGNATURE Only returned when called with - KMM_LM_FLAG_SYNC. The module was signed with an invalid - certificate. No handle is returned. - \retval KHM_ERROR_UNKNOWN Only returned when called with - KMM_LM_FLAG_SYNC. Some other error has occured. No handle is - returned. - - \see \ref pi_fw_pm_load - \see ::KMM_LM_FLAG_SYNC, ::KMM_LM_FLAG_NOLOAD -*/ -KHMEXP khm_int32 KHMAPI -kmm_load_module(wchar_t * modname, khm_int32 flags, kmm_module * result); - -/*! \brief Hold a handle to a module - - Use kmm_release_module() to release the hold. -*/ -KHMEXP khm_int32 KHMAPI -kmm_hold_module(kmm_module module); - -/*! \brief Release a handle to a module - - Release a held referece to a module that was returned in a call to - kmm_load_module(). -*/ -KHMEXP khm_int32 KHMAPI -kmm_release_module(kmm_module m); - -/*! \brief Query the state of a module - - When loading a module asynchronously you can query the state of - the loading process using this. The return value is a status - indicator. - - \return The return value is one of the ::KMM_MODULE_STATES - enumerations. -*/ -KHMEXP khm_int32 KHMAPI -kmm_get_module_state(kmm_module m); - -/*! \brief Unload a module - - See the associated NetIDMgr Module Manager documentation on the - sequence of events associated with unloading a module. - - \see \ref pi_fw_pm_unload -*/ -KHMEXP khm_int32 KHMAPI -kmm_unload_module(kmm_module module); - -/*! \brief Loads the default modules as specified in the configuration - - The configuration can specify the default set of modules to load. - This function dispatches the necessary message for loading these - modules and reutnrs. -*/ -KHMEXP khm_int32 KHMAPI -kmm_load_default_modules(void); - -/*! \brief Checks whether there are any pending loads - - Returns TRUE if there are modules still waiting to be loaded. -*/ -KHMEXP khm_boolean KHMAPI -kmm_load_pending(void); - -#ifdef _WIN32 - -/*! \brief Returns the Windows module handle from a handle to a NetIDMgr module. - Although it is possible to obtain the Windows module handle and - use it to call Windows API functions, it is not recommended to do - so. This is because that might cause the state of the module to - change in ways which are inconsistent from the internal data - structures that kmm maintains. - */ -KHMEXP HMODULE KHMAPI -kmm_get_hmodule(kmm_module m); -#endif - -/*! \brief Hold a plugin - - Obtains a hold on a plugin. The plugin handle will remain valid - until the hold is released with a call to kmm_release_plugin(). - No guarantees are made on the handle once the handle is released. - */ -KHMEXP khm_int32 KHMAPI -kmm_hold_plugin(kmm_plugin p); - -/*! \brief Release a plugin - - Releases a hold on a plugin obtained through a call to - kmm_hold_plugin(). The plugin handle should no longer be - considered valied once this is called. - */ -KHMEXP khm_int32 KHMAPI -kmm_release_plugin(kmm_plugin p); - -/*! \brief Provide a plugin - - This function must be called for each plugin that the module - provides. - - Note that this function returns immediately and does not - initialize the plugin. All plugins that are provided by a - module will be initialized once the init_module() function - returns. If the plugin has dependencies, it will be kept in a - held state until the plugins that it depends on are successfully - initialized. If the dependencies are not resolved (the dependent - plugins are not loaded), then plugin will not be initialized. - - If the plugin is not registered and \a plugin contains enough - information to perform the registration, then it will be - automatically registered. However, if the plugin is not - registered and cannot be registered using the provided - information, the plugin will not be initialized properly. Note - that automatic registration will always register the plugin in the - user configuration store. - - The \a name and \a msg_proc members of \a plugin are required to - have valid values. The \a icon member may optionally be - specified. The other fields can be specified if the plugin should - be automatically registered, however, the \a module field will be - ignored and will be determined by the \a module handle. - - \param[in] module Handle to this module that is providing the plugin. - \param[in] plugin A plugin descriptor. - - \retval KHM_ERROR_SUCCESS Succeeded. - \retval KHM_ERROR_INVALID_OPERATION The function was not called - during init_module() - \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid - \retval KHM_ERROR_DUPLICATE The plugin was already provided - - \note This can only be called when handing init_module() -*/ -KHMEXP khm_int32 KHMAPI -kmm_provide_plugin(kmm_module module, kmm_plugin_reg * plugin); - -/*! \brief Query the state of a plugin. - - \return One of ::_kmm_plugin_states -*/ -KHMEXP khm_int32 KHMAPI -kmm_get_plugin_state(wchar_t * plugin); - -/*! \defgroup kmm_reg Registration - - The functions for managing plugin and module registration. These - functions are also available as static linked libraries for use by - external applications which must register or unregister plugins or - modules. -@{*/ - -/*! \brief Obtain the configuration space for a named plugin - - Note that the named plugin does not have to actually exist. - Configuration spaces for plugins are based solely on the plugin - name and hence can be accessed regardless of whether the specific - plugin is loaded or not. - - \param[in] flags Controls the options for opening the - configuration space. If KHM_FLAG_CREATE is specified, then - the configuration space for the plugin named \a plugin wil be - created if it doesn't already exist. The \a flags parameter - is directly passed into a call to khc_open_space(). - - \param[in] plugin Name of the plugin. The name can not contain - slashes. - - \param[out] result Receives a configuration space handle. The - calling application should free the handle using - khc_close_space(). - - \see khc_open_space() - \see khc_close_space() - */ -KHMEXP khm_int32 KHMAPI -kmm_get_plugin_config(wchar_t * plugin, khm_int32 flags, khm_handle * result); - -/*! \brief Obtain the configuration space or a named module - - The named module does not have to actually exist. Configuration - spaces for modules are based on the basename of the module - (including the extension). - - \param[in] module Name of the module. - - \param[in] flags The flags used to call khc_open_space(). You can - use this to specify a particular configuration store if - needed. - - \param[out] result Receives the handle to a configuration space if - successful. Call khc_close_space() to close the handle. - - \see khc_open_space() - \see khc_close_space() -*/ -KHMEXP khm_int32 KHMAPI -kmm_get_module_config(wchar_t * module, khm_int32 flags, khm_handle * result); - -/*! \brief Retrieve a handle to the configuration space for plugins - - The configuration space for plugins is a container which holds the - configuration subspaces for all the plugins. This is the config - space which must be used to load a configuration space for a - plugin. - - \param[in] flags The flags to pass in to the call to - khc_open_space(). The flags can be used to select a specific - configuration store if needed. - - \param[out] result Receives a handle to the configuration - space. Call khc_close_space() to close the handle - - \see khc_open_space() - \see khc_close_space() - */ -KHMEXP khm_int32 KHMAPI -kmm_get_plugins_config(khm_int32 flags, khm_handle * result); - -/*! \brief Retrieve the handle to the configuration space for modules - - The configuration space for modules is a container which hold the - configuration subspaces for all the modules. Each module - registration ends up in this subspace. - - \param[in] flags The flags to pass in to the call to - khc_open_space(). The flags can be used to select a specific - configuration store if needed. - - \param[out] result Receives a handle to the configuration space. - Call khc_close_space() to close the handle. - - \see khc_open_space() - \see khc_close_space() - */ -KHMEXP khm_int32 KHMAPI -kmm_get_modules_config(khm_int32 flags, khm_handle * result); - -/*! \brief Return information about a loaded module - - The retrieves a block of information about a module. Refer to - ::kmm_module_info for information about the format of the returned - data. - - Note that the size of the required buffer is actually greater than - the size of the ::kmm_module_info structure and accomodates the - ::kmm_plugin_info structures and strings required to complete the - information block. - - Call the function with \a buffer set to NULL and \a cb_buffer - pointing at a khm_size variable to obtain the required size of the - buffer. - - \param[in] module_name Name of a module - \param[in] flags Flags indicating which types of information to - return - \param[out] buffer Points to a buffer that recieves information. - Set this to NULL if only the size of the buffer is required. - \param[in,out] On entry, contains the size of the buffer pointed - to by \a buffer if \a buffer is not NULL. On exit, contains - the required size of the buffer or the number of actual bytes - copied. - - \retval KHM_ERROR_SUCCESS The requested information was copied - \retval KHM_ERROR_INVALID_PARAM One of the parameters was invalid - \retval KHM_ERROR_TOO_LONG The buffer was not large enough or was - NULL. The number of bytes requied is in \a cb_buffer. - \retval KHM_ERROR_NOT_FOUND The specified module is not a - registered module. - */ -KHMEXP khm_int32 KHMAPI -kmm_get_module_info(wchar_t * module_name, khm_int32 flags, - kmm_module_info * buffer, khm_size * cb_buffer); - -/*! \brief Get information about a module - - Similar to kmm_get_module_info(), but uses a module handle instead - of a name, and uses internal buffers for providing string fields. - - The information that is returned should be freed using a call to - kmm_release_module_info_i(). - - \see kmm_release_module_info_i() - */ -KHMEXP khm_int32 KHMAPI -kmm_get_module_info_i(kmm_module module, kmm_module_info * info); - -/*! \brief Release module information - - Releases the information returned by a previous call to - kmm_get_module_info_i(). The contents of the ::kmm_module_info - structure should not have been modified in any way between calling - kmm_get_module_info_i() and kmm_release_module_info_i(). - */ -KHMEXP khm_int32 KHMAPI -kmm_release_module_info_i(kmm_module_info * info); - -/*! \brief Obtain information about a plugin - - Retrieve a block of information about a plugin. See - ::kmm_plugin_info for details about what information can be - returned. Note that some fields may not be available if the - module is not loaded. - - Note that the size of the required buffer is greater than the size - of the ::kmm_plugin_info structure and accounts for strings as - well. Call kmm_get_plugin_info() with \a buffer set to NULL and - \a cb_buffer set to point to a variable of type \a khm_size to - obtain the required size of the structure. - - \param[in] plugin_name Name of the plugin - \param[out] buffer The buffer to receive the plugin information. - Set to \a NULL if only the size of the buffer is required. - \param[in,out] cb_buffer On entry, points to variable that - specifies the size of the buffer pointed to by \a buffer is \a - buffer is not \a NULL. On exit, holds the number of bytes - copied or the required size of the buffer. - - \retval KHM_ERROR_SUCCESS The requested information was - successfully copied to the \a buffer - \retval KHM_ERROR_TOO_LONG The buffer was either \a NULL or - insufficient to hold the requested information. The required - size of the buffer was stored in \a cb_buffer - \retval KHM_ERROR_INVALID_PARAM One or more parameters were - invlaid. - \retval KHM_ERROR_NOT_FOUND The specified plugin was not found - among the registered plugins. -*/ -KHMEXP khm_int32 KHMAPI -kmm_get_plugin_info(wchar_t * plugin_name, - kmm_plugin_info * buffer, - khm_size * cb_buffer); - -/*! \brief Obtain information about a plugin using a plugin handle - - Similar to kmm_get_plugin_info() but uses a plugin handle instead - of a plugin name. If the call is successful, the \a info - structure will be filled with information about the plugin. The - returned info should not be modified in any way and may contain - pointers to internal buffers. - - The returned information must be released with a call to - kmm_release_plugin_info_i(). - */ -KHMEXP khm_int32 KHMAPI -kmm_get_plugin_info_i(kmm_plugin p, kmm_plugin_info * info); - -/*! \brief Release plugin information returned by kmm_get_plugin_info_i - - The information returned by kmm_get_plugin_info_i() should not be - modified in any way before calling kmm_release_plugin_info_i(). - Once the call completes, the contents of \a info will be - initialized to zero. - */ -KHMEXP khm_int32 KHMAPI -kmm_release_plugin_info_i(kmm_plugin_info * info); - -/*! \brief Enumerates plugins - - Enumerates through known plugins. This list may not include - plugins which were not loaded by NetIDMgr in this session. - - If the call is successful, a handle to the next plugin in the list - will be placed in \a p_next. The returned handle must be freed - with a call to kmm_release_plugin(). - - If the \a p parameter is set to NULL, then the first plugin handle - will be placed in \a p_next. The handles will not be returned in - any specific order. In addition, the enumeration may not include - all known plugins if the list of plugins changes during - enumeration. - */ -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 - msg_proc and \a icon members of the structure are ignored. - - At the time kmm_register_plugin() is called, the module specified - by \a module member of the \a plugin parameter must have been already - registered. Otherwise the function call fails. - - If the plugin has already been registered, then all the fields in - the plugin registration will be updated to be in sync with the - information provided in the \a plugin parameter. The failure - counts and associated statistics will not be reset when the - configuration information is updated. - - If the plugin has not been registered, the a new registration - entry is created in the configuration space indicated by the \a - config_flags parameter. In addition, the plugin will be added to - the list of plugins associated with the owning module. - - Note that the module that owns the plugin must be registered in - the same configuration store as the plugin. - - \param[in] plugin Registration info for the plugin. The \a - msg_proc and \a icon members are ignored. All other fields - are required. The \a description member should be localized - to the system locale when registering a plugin in the machine - configuration store and should be localized to the user locale - when registering a plugin in the user configuration store. - \param[in] config_flags Flags for the configuration provider. - These flags are used verbatim to call khc_open_space(), hence - they may be used to pick whether or not the registration is - per machine or per user. - - \see kmm_register_module() - */ -KHMEXP khm_int32 KHMAPI -kmm_register_plugin(kmm_plugin_reg * plugin, khm_int32 config_flags); - -/*! \brief Register a module - - The \a module parameter specifies the parameters for the module - registration. - - The \a plugin_info member should point to an array of - ::kmm_plugin_info structures unless the \a n_plugins member is - zero, in which case \a plugin_info can be \a NULL. Plugins can be - registered separately using kmm_register_plugin(). - - \param[in] module Information about the module. The name and path - fields are required. The \a plugin_info field can only be \a - NULL if \a n_plugins is zero. - - \param[in] config_flags Flags used to call khc_open_space(). This - can be used to choose the configuration store in which the - module registration will be performed. - */ -KHMEXP khm_int32 KHMAPI -kmm_register_module(kmm_module_reg * module, khm_int32 config_flags); - -/*! \brief Unregister a plugin - - Registration information associated with the plugin will be - removed. In addtion, the plugin will be removed from the list of - plugins provided by the owner module. - - \param[in] plugin Names the plugin to be removed - \param[in] config_flags Flags used to call khc_open_space(). Can - be used to choose the configuraiton store that is affected by - the call. - - \note kmm_unregister_plugin() has no effect on whether the plugin - is loaded or not. The caller must make sure that the plugin - is unloaded and the associated module is either also unloaded - or in a state where the plugin can be unregistered. - */ -KHMEXP khm_int32 KHMAPI -kmm_unregister_plugin(wchar_t * plugin, khm_int32 config_flags); - -/*! \brief Unregister a module - - Registration information associated with the module as well as all - the plugins provided by the module will be removed from the - configuration store. - - \param[in] module Names the module to be removed - - \param[in] config_flags Flags used to call khc_open_space(). Can - be used to choose the configuration store affected by the - call. - - \note kmm_unregister_module() has no effect on the loaded state of - the module. The caller should make sure that the module is - unloaded and in a state where it can be unregistered. - */ -KHMEXP khm_int32 KHMAPI -kmm_unregister_module(wchar_t * module, khm_int32 config_flags); - -/*@}*/ /* kmm_reg */ - -/*! \defgroup kmm_loc Internationalization support - - See \ref pi_localization for more information about - internationalization. - -@{*/ - -/*! \brief Locale descriptor record - - See kmm_set_locale() -*/ -typedef struct tag_kmm_module_locale { - khm_ui_4 language; /*!< A language ID. On Windows, you can use the - MAKELANGID macro to generate this value. */ - wchar_t * filename; /*!< The filename corresponding to this language. - Use NULL to indicate that resources for this - language are to be found in the main module. */ - khm_int32 flags; /*!< Flags. Combination of KMM_MLOC_FLAG_* */ -} kmm_module_locale; - -#define LOCALE_DEF(language_id, filename, flags) {language_id, filename, flags} - -/*! \brief Default (fallback) locale -*/ -#define KMM_MLOC_FLAG_DEFAULT 1 - - -/*! \brief Sets the locale for a loaded module. - - The given locale records are searched in the given order until a - locale that matches the current user locale is found. If no - locales match, then the first locale with the - ::KMM_MLOC_FLAG_DEFAULT flag set will be loaded. If no locales - have that flag set, then the first locale is loaded. - - You can obtain a handle to the loaded library using - kmm_get_resource_hmodule(). This function does not return until a - matched library is loaded. - - Note that the ::kmm_module_locale structure only specifies a - module name for the resource module. This resource module must - exist in the same directory as the \a module. - - \param[in] module The module handle - \param[in] locales An array of ::kmm_module_locale objects - \param[in] n_locales The number of objects in the array pointed to by \a locales - - \retval KHM_ERROR_SUCCESS Succeeded. - \retval KHM_ERROR_NOT_FOUND A matching locale resource library was not found. - \retval KHM_ERROR_INVALID_OPERATION The function was called on a module which is currently not being initalized. - - \see \ref pi_localization - \see kmm_get_resource_hmodule() - - \note This can only be called when handing init_module() -*/ -KHMEXP khm_int32 KHMAPI -kmm_set_locale_info(kmm_module module, - kmm_module_locale * locales, - khm_int32 n_locales); - -#ifdef _WIN32 - -/*! \brief Return the Windows module handle of the resource library of a NetIDMgr module. - - NetIDMgr allows the specification of an alternate resource library - that will be used to load localized resources from. This function - returns a handle to this library. - - While you can use the convenience macros to access resources in a - localization library using the module handle, it is recommended, - for performance reasons, to use this function to obtain the handle - to the resource library and then use that handle in calls to - LoadString, LoadImage etc. directly. -*/ -KHMEXP HMODULE KHMAPI -kmm_get_resource_hmodule(kmm_module m); - -/*! \name Convenience Macros -@{*/ -/*! \brief Convenience macro for using calling LoadAccelerators using a module handle - - \param[in] module A handle to a loaded module. The corresponding resource - module will be located through a call to kmm_get_resource_hmodule() -*/ -#define kmm_LoadAccelerators(module, lpTableName) \ - (LoadAccelerators(kmm_get_resource_hmodule(module), lpTableName)) - -/*! \brief Convenience macro for using calling LoadBitmap using a module handle - - \param[in] module A handle to a loaded module. The corresponding resource - module will be located through a call to kmm_get_resource_hmodule() -*/ -#define kmm_LoadBitmap(module, lpBitmapName) \ - (LoadBitmap(kmm_get_resource_hmodule(module), lpBitmapName)) - -/*! \brief Convenience macro for using calling LoadImage using a module handle - - \param[in] module A handle to a loaded module. The corresponding resource - module will be located through a call to kmm_get_resource_hmodule() -*/ -#define kmm_LoadImage(module, lpszName, uType, cxDesired, cyDesired, fuLoad) \ - (LoadImage(kmm_get_resource_hmodule(module), lpszName, uType, cxDesired, cyDesired, fuLoad)) - -/*! \brief Convenience macro for using calling LoadCursor using a module handle - - \param[in] module A handle to a loaded module. The corresponding resource - module will be located through a call to kmm_get_resource_hmodule() -*/ -#define kmm_LoadCursor(module, lpCursorName) \ - (LoadCursor(kmm_get_resource_hmodule(module), lpCursorName)) - -/*! \brief Convenience macro for using calling LoadIcon using a module handle - - \param[in] module A handle to a loaded module. The corresponding resource - module will be located through a call to kmm_get_resource_hmodule() -*/ -#define kmm_LoadIcon(module, lpIconName) \ - (LoadIcon(kmm_get_resource_hmodule(module), lpIconName)) - -/*! \brief Convenience macro for using calling LoadMenu using a module handle - - \param[in] module A handle to a loaded module. The corresponding resource - module will be located through a call to kmm_get_resource_hmodule() -*/ -#define kmm_LoadMenu(module, lpMenuName) \ - (LoadMenu(kmm_get_resource_hmodule(module), lpMenuName)) - -/*! \brief Convenience macro for using calling LoadString using a module handle - - \param[in] module A handle to a loaded module. The corresponding resource - module will be located through a call to kmm_get_resource_hmodule() -*/ -#define kmm_LoadString(module, uID, lpBuffer, nBufferMax) \ - (LoadString(kmm_get_resource_hmodule(module), uID, lpBuffer, nBufferMax)) -/*@}*/ /* Convenience Macros */ -#endif -/*@}*/ /* group kmm_loc */ -/*@}*/ /* group kmm */ -#endif +/* + * 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_KMM_H +#define __KHIMAIRA_KMM_H + +#include +#include + +/*! \defgroup kmm NetIDMgr Module Manager +@{*/ + +/*! \brief A handle to a module. +*/ +typedef khm_handle kmm_module; + +/*! \brief A handle to a plugin. + */ +typedef khm_handle kmm_plugin; + +/*! \name Limits + @{*/ + +/*! \brief Maximum number of characters in a name in KMM including the terminating NULL */ +#define KMM_MAXCCH_NAME 256 + +/*! \brief Maximum number of bytes in a name in KMM including the terminating NULL */ +#define KMM_MAXCB_NAME (sizeof(wchar_t) * KMM_MAXCCH_NAME) + +/*! \brief Maximum number of characters in a description in KMM including the terminating NULL */ +#define KMM_MAXCCH_DESC 512 + +/*! \brief Maximum number of bytes in a description in KMM including the terminating NULL */ +#define KMM_MAXCB_DESC (sizeof(wchar_t) * KMM_MAXCCH_NAME) + +/*! \brief Maximum number of characters in a vendor string in KMM including the terminating NULL */ +#define KMM_MAXCCH_VENDOR 256 + +/*! \brief Maximum number of bytes in a vendor string in KMM including the terminating NULL */ +#define KMM_MAXCB_VENDOR (sizeof(wchar_t) * KMM_MAXCCH_VENDOR) + +/*! \brief Maximum number of characters in a support URI in KMM including the terminating NULL */ +#define KMM_MAXCCH_SUPPORT 256 + +/*! \brief Maximum number of bytes in a vendor string in KMM including the terminating NULL */ +#define KMM_MAXCB_SUPPORT (sizeof(wchar_t) * KMM_MAXCCH_SUPPORT) + +/*! \brief Maximum number of dependencies per plugin +*/ +#define KMM_MAX_DEPENDENCIES 8 + +/*! \brief Maximum number of dependants per plugin + */ +#define KMM_MAX_DEPENDANTS 32 + +/*! \brief Maximum number of characters a dependency string including trailing double NULL */ +#define KMM_MAXCCH_DEPS (KMM_MAXCCH_NAME * KMM_MAX_DEPENDENCIES + 1) + +/*! \brief Maximum number of bytes in a dependency string including trailing double NULL */ +#define KMM_MAXCB_DEPS (sizeof(wchar_t) * KMM_MAXCCH_DEPS) +/*@}*/ /* Limits */ + +/*! \brief Plugin registration + + \see ::khm_cred_provider +*/ +typedef struct tag_kmm_plugin_reg { + wchar_t * name; /*!< Name of the plugin. Maximum of + KMM_MAXCCH_NAME characters + including the terminating + NULL. Required. */ + + wchar_t * module; /*!< Name of module that owns the + plugin. Maximum of + KMM_MAXCCH_NAME characters + including terminating NULL. + Required. */ + + khm_int32 type; /*!< Type plugin type. One of + KHM_PITYPE_*. Required. */ + khm_int32 flags; /*!< Unused. Set to 0 */ + kmq_callback_t msg_proc; /*!< Message processor. Required. */ + wchar_t * dependencies; /*!< Dependencies. Note that this is + a multi string. (you can use the + KHC multi string functions to + manipulate multi strings or to + convert a comma separated list of + dependencies to a multi string). + Each string in the multi string + is a name of a plugin that this + plugin depends on. Optional (set + to NULL if this plugin has no + dependencies). Maximum of + KMM_MAXCCH_DEPS characters + including terminating double + NULL.*/ + + wchar_t * description; /*!< Description of the plugin. + Maximum of KMM_MAXCCH_DESC + characters including the + terminating + NULL. Localized. Optional (set to + NULL if not provided) */ +#ifdef _WIN32 + HICON icon; /*!< Icon used to represent the + plugin. Optional. (set to NULL if + not provided) */ +#endif +} kmm_plugin_reg; + +/*! \brief Plugin information +*/ +typedef struct tag_kmm_plugin_info { + kmm_plugin_reg reg; /*!< Registration info */ + + khm_int32 state; /*!< Current status of the plugin. + One of ::_kmm_plugin_states */ + + khm_int32 failure_count; /*!< Number of recorded failures in + the plugin */ + FILETIME failure_time; /*!< Time of first recorded failure */ + khm_int32 failure_reason; /*!< The reason for the first recorded + 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 0x00000400 + +/*! \name Plugin types +@{*/ +/*! \brief A credentials provider + + \see \ref pi_pt_cred for more information. + */ +#define KHM_PITYPE_CRED 1 + +/*! \brief A identity provider + + \see \ref pi_pt_cred for more information + */ +#define KHM_PITYPE_IDENT 2 + +/*! \brief A configuration provider + + \see \ref pi_pt_conf for more information. + */ +#define KHM_PITYPE_CONFIG 3 + +/*! \brief Undefined plugin type + + The plugin doesn't provide any credential type. + */ +#define KHM_PITYPE_MISC 4 + +/*@}*/ + +/*! \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 + reached the maximum number + of failures and cannot be + initialized until the + failure count is reset */ + KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED = -3, /*!< Failed because the + plugin was not registered + and automatic registration + failed. */ + KMM_PLUGIN_STATE_FAIL_DISABLED = -2,/*!< Failed because plugin was + disabled by the user. */ + KMM_PLUGIN_STATE_FAIL_LOAD = -1, /*!< The plugin failed to load + due to some unknown + reason. */ + KMM_PLUGIN_STATE_NONE = 0, /*!< Unknown state */ + KMM_PLUGIN_STATE_PLACEHOLDER, /*!< Placeholder. The plugin + hasn't been provided by + anyone yet, but the plugin + record has been created to + keep track of + dependencies. */ + KMM_PLUGIN_STATE_REG, /*!< The plugin is registered + but not initialized */ + KMM_PLUGIN_STATE_PREINIT, /*!< The plugin is in the + process of being + initialized */ + KMM_PLUGIN_STATE_HOLD, /*!< On hold. One or more + dependencies of this plugin + has not been resolved */ + KMM_PLUGIN_STATE_INIT, /*!< The plugin was initialized */ + KMM_PLUGIN_STATE_RUNNING, /*!< The plugin is running */ + KMM_PLUGIN_STATE_EXITED /*!< The plugin has been stopped. */ +}; + +/*! \brief Module registration */ +typedef struct tag_kmm_module_reg { + wchar_t * name; /*!< Identifier for the module */ + wchar_t * path; /*!< Full pathname to module + binary */ + + wchar_t * description; /*!< Description of module */ + + wchar_t * vendor; /*!< Vendor/copyright string */ + + wchar_t * support; /*!< Support URL/contact */ + + khm_int32 n_plugins; /*!< Number of plugins that are + active */ + kmm_plugin_reg * plugin_reg_info; /*!< Array of kmm_plugin_reg + records for each active + plugin */ +} kmm_module_reg; + +/*! \brief Module information record */ +typedef struct tag_kmm_module_info { + kmm_module_reg reg; /*!< Registration info */ + + khm_ui_4 language; /*!< Currently loaded langugage */ + + khm_int32 state; /*!< Current status of the + module */ + + khm_version file_version; /*!< File version for the + module */ + khm_version product_version; /*!< Product version for the + module */ + + khm_int32 failure_count; /*!< Number of times the module + has failed to load */ + FILETIME failure_time; /*!< Time of first recorded + failure */ + khm_int32 failure_reason; /*!< Reason for first failure. + One of the module status + values */ + + kmm_module h_module; /*!< Handle to the module. */ +} kmm_module_info; + +/*! \brief Module states +*/ +enum KMM_MODULE_STATES { + KMM_MODULE_STATE_FAIL_INCOMPAT=-12, /*!< The library containing + the module was not + compatible with this version + of NetIDMgr. */ + KMM_MODULE_STATE_FAIL_INV_MODULE=-11, /*!< The library containing + the module was invalid. */ + KMM_MODULE_STATE_FAIL_UNKNOWN=-10, /*!< Module could not be + loaded due to unknown + reasons. */ + KMM_MODULE_STATE_FAIL_MAX_FAILURE=-9,/*!< The module has failed + too many times already. Not + attempting to restart it + again */ + KMM_MODULE_STATE_FAIL_DUPLICATE=-8, /*!< An attempt was made to + load the same module + twice. */ + KMM_MODULE_STATE_FAIL_NOT_REGISTERED=-7, /*!< The module is not + found among the registered + module list */ + KMM_MODULE_STATE_FAIL_NO_PLUGINS=-6,/*!< The module provided no + plugins, or all the plugins + that are provided are + disabled */ + KMM_MODULE_STATE_FAIL_DISABLED=-5, /*!< Module is disabled and + cannot be loaded */ + KMM_MODULE_STATE_FAIL_LOAD=-4, /*!< The module failed to + initialize */ + KMM_MODULE_STATE_FAIL_INVALID=-3, /*!< The module was invalid. + Typically caused by the + required entrypoints not + being present */ + KMM_MODULE_STATE_FAIL_SIGNATURE=-2, /*!< The module failed to load + due to an unverifiable + signature */ + KMM_MODULE_STATE_FAIL_NOT_FOUND=-1, /*!< The module was not + found */ + KMM_MODULE_STATE_NONE=0, /*!< Unknown state. The handle + is possibly invalid */ + KMM_MODULE_STATE_PREINIT, /*!< The module is being + loaded. init_module() hasn't + been called yet */ + KMM_MODULE_STATE_INIT, /*!< In init_module() */ + KMM_MODULE_STATE_INITPLUG, /*!< Initializing plugins */ + KMM_MODULE_STATE_RUNNING, /*!< Running */ + KMM_MODULE_STATE_EXITPLUG, /*!< Currently exiting plugins */ + KMM_MODULE_STATE_EXIT, /*!< Currently exiting */ + KMM_MODULE_STATE_EXITED /*!< Exited */ +}; + +/*! \brief Start the Module Manager + + \note Only called by the NetIDMgr core. +*/ +KHMEXP void KHMAPI +kmm_init(void); + +/*! \brief Stop the Module Manager + + \note Only called by the NetIDMgr core. +*/ +KHMEXP void KHMAPI +kmm_exit(void); + +/*! \brief Return the plugin handle for the current plugin + + The returned handle represents the plugin which owns the current + thread. The returned handle must be released by calling + kmm_release_plugin(). Returns NULL if the current thread is not + owned by any plugin. + */ +KHMEXP kmm_plugin KHMAPI +kmm_this_plugin(void); + +/*! \brief Return the module handle for the current module + + The returned handle represents the module which owns the current + thread. The returned handle must be released by calling + kmm_release_module() +*/ +KHMEXP kmm_module KHMAPI +kmm_this_module(void); + +/*! \name Flags for kmm_load_module() +@{*/ +/*!\brief Load synchronously + + If this flag is set, then the function waits for the module to be + loaded. The default is to load the module asynchronously. + + When loading a module asynchronously, the kmm_load_module() + function returns KHM_ERROR_SUCCESS and exits without waiting for + the module to load. If \a result is not NULL, it will receive a + valid handle to the module. + + When loading a module synchronously, kmm_load_module() will wait + for the module to completely load. If it fails to load properly, + it will return an error code and set \a result to NULL. +*/ +#define KMM_LM_FLAG_SYNC 1 + +/*! \brief Do not load + + Indicates that the module shouldn't actually be loaded. If the + specified module name identifies a module that has already been + loaded, then the function returns a held handle to the existing + module (use kmm_release_module() to free the handle). Otherwise, + the function returns KHM_ERROR_NOT_FOUND. +*/ +#define KMM_LM_FLAG_NOLOAD 2 +/*@}*/ + +/*! \brief Load a module + + The \a modulename parameter specifies a module to load. Depending + on the configuration, not all of the plugins that are provided by + the module may be loaded. If no plugins are successfully loaded, + the module will be immediately unloaded. + + If the module is currently loaded or is being loaded, then a valid + handle to the existing module is returned. + + When called with KMM_LM_FLAG_SYNC, the function does not return + until the module and the associated plugins are all initialized, + or an error occurs. + + If the KMM_LM_FLAG_NOLOAD flag is set, then a handle to an + existing instance of the module will be returned. If the module + hasn't been loaded yet, then no handle is returned and the + function returns KHM_ERROR_NOT_FOUND. + + See the associated NetIDMgr Module Manager documentation on the + sequence of events associated with loading a module. + + \param[in] modulename Name of the module. The module should have + been registered under this name prior to the call. + \param[in] flags Combination of KMM_LM_FLAG_* + \param[out] result Receives a handle to the loaded module. If the + result is not required, set this to NULL. If \a result is not + NULL, and km_load_module() returns KHM_ERROR_SUCCESS, then + kmm_release_module() must be called to release the handle to + the module. Otherwise, \a result receives NULL. If a handle + is returned, it will be valid regardless of whether the module + fails to load or not. You can use kmm_get_module_state() to + query the progress of the loading process. See + ::KMM_LM_FLAG_SYNC. + + \retval KHM_ERROR_SUCCESS The call succeeded. If \a + KMM_LM_FLAG_SYNC was specified, this means that the module was + successfully loaded. Otherwise, it only means that the module + has been queued up for loading. Use kmm_get_module_state() to + determine if it was successfully loaded. If \a result is not + NULL, a valid handle is returned. + \retval KHM_ERROR_EXISTS The module is already loaded or has been + already queued for loading. If \a result is not NULL, a valid + handle to the existing module instance is returned. + \retval KHM_ERROR_NOT_FOUND If called with KMM_LM_FLAG_NOLOAD, + indicates that the module has not been loaded. Otherwise only + returned when called with KMM_LM_FLAG_SYNC. The module image + was not found. No handle is returned. + \retval KHM_ERROR_INVALID_SIGNATURE Only returned when called with + KMM_LM_FLAG_SYNC. The module was signed with an invalid + certificate. No handle is returned. + \retval KHM_ERROR_UNKNOWN Only returned when called with + KMM_LM_FLAG_SYNC. Some other error has occured. No handle is + returned. + + \see \ref pi_fw_pm_load + \see ::KMM_LM_FLAG_SYNC, ::KMM_LM_FLAG_NOLOAD +*/ +KHMEXP khm_int32 KHMAPI +kmm_load_module(wchar_t * modname, khm_int32 flags, kmm_module * result); + +/*! \brief Hold a handle to a module + + Use kmm_release_module() to release the hold. +*/ +KHMEXP khm_int32 KHMAPI +kmm_hold_module(kmm_module module); + +/*! \brief Release a handle to a module + + Release a held referece to a module that was returned in a call to + kmm_load_module(). +*/ +KHMEXP khm_int32 KHMAPI +kmm_release_module(kmm_module m); + +/*! \brief Query the state of a module + + When loading a module asynchronously you can query the state of + the loading process using this. The return value is a status + indicator. + + \return The return value is one of the ::KMM_MODULE_STATES + enumerations. +*/ +KHMEXP khm_int32 KHMAPI +kmm_get_module_state(kmm_module m); + +/*! \brief Unload a module + + See the associated NetIDMgr Module Manager documentation on the + sequence of events associated with unloading a module. + + \see \ref pi_fw_pm_unload +*/ +KHMEXP khm_int32 KHMAPI +kmm_unload_module(kmm_module module); + +/*! \brief Loads the default modules as specified in the configuration + + The configuration can specify the default set of modules to load. + This function dispatches the necessary message for loading these + modules and reutnrs. +*/ +KHMEXP khm_int32 KHMAPI +kmm_load_default_modules(void); + +/*! \brief Checks whether there are any pending loads + + Returns TRUE if there are modules still waiting to be loaded. +*/ +KHMEXP khm_boolean KHMAPI +kmm_load_pending(void); + +#ifdef _WIN32 + +/*! \brief Returns the Windows module handle from a handle to a NetIDMgr module. + Although it is possible to obtain the Windows module handle and + use it to call Windows API functions, it is not recommended to do + so. This is because that might cause the state of the module to + change in ways which are inconsistent from the internal data + structures that kmm maintains. + */ +KHMEXP HMODULE KHMAPI +kmm_get_hmodule(kmm_module m); +#endif + +/*! \brief Hold a plugin + + Obtains a hold on a plugin. The plugin handle will remain valid + until the hold is released with a call to kmm_release_plugin(). + No guarantees are made on the handle once the handle is released. + */ +KHMEXP khm_int32 KHMAPI +kmm_hold_plugin(kmm_plugin p); + +/*! \brief Release a plugin + + Releases a hold on a plugin obtained through a call to + kmm_hold_plugin(). The plugin handle should no longer be + considered valied once this is called. + */ +KHMEXP khm_int32 KHMAPI +kmm_release_plugin(kmm_plugin p); + +/*! \brief Provide a plugin + + This function must be called for each plugin that the module + provides. + + Note that this function returns immediately and does not + initialize the plugin. All plugins that are provided by a + module will be initialized once the init_module() function + returns. If the plugin has dependencies, it will be kept in a + held state until the plugins that it depends on are successfully + initialized. If the dependencies are not resolved (the dependent + plugins are not loaded), then plugin will not be initialized. + + If the plugin is not registered and \a plugin contains enough + information to perform the registration, then it will be + automatically registered. However, if the plugin is not + registered and cannot be registered using the provided + information, the plugin will not be initialized properly. Note + that automatic registration will always register the plugin in the + user configuration store. + + The \a name and \a msg_proc members of \a plugin are required to + have valid values. The \a icon member may optionally be + specified. The other fields can be specified if the plugin should + be automatically registered, however, the \a module field will be + ignored and will be determined by the \a module handle. + + \param[in] module Handle to this module that is providing the plugin. + \param[in] plugin A plugin descriptor. + + \retval KHM_ERROR_SUCCESS Succeeded. + \retval KHM_ERROR_INVALID_OPERATION The function was not called + during init_module() + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + \retval KHM_ERROR_DUPLICATE The plugin was already provided + + \note This can only be called when handing init_module() +*/ +KHMEXP khm_int32 KHMAPI +kmm_provide_plugin(kmm_module module, kmm_plugin_reg * plugin); + +/*! \brief Query the state of a plugin. + + \return One of ::_kmm_plugin_states +*/ +KHMEXP khm_int32 KHMAPI +kmm_get_plugin_state(wchar_t * plugin); + +/*! \defgroup kmm_reg Registration + + The functions for managing plugin and module registration. These + functions are also available as static linked libraries for use by + external applications which must register or unregister plugins or + modules. +@{*/ + +/*! \brief Obtain the configuration space for a named plugin + + Note that the named plugin does not have to actually exist. + Configuration spaces for plugins are based solely on the plugin + name and hence can be accessed regardless of whether the specific + plugin is loaded or not. + + \param[in] flags Controls the options for opening the + configuration space. If KHM_FLAG_CREATE is specified, then + the configuration space for the plugin named \a plugin wil be + created if it doesn't already exist. The \a flags parameter + is directly passed into a call to khc_open_space(). + + \param[in] plugin Name of the plugin. The name can not contain + slashes. + + \param[out] result Receives a configuration space handle. The + calling application should free the handle using + khc_close_space(). + + \see khc_open_space() + \see khc_close_space() + */ +KHMEXP khm_int32 KHMAPI +kmm_get_plugin_config(wchar_t * plugin, khm_int32 flags, khm_handle * result); + +/*! \brief Obtain the configuration space or a named module + + The named module does not have to actually exist. Configuration + spaces for modules are based on the basename of the module + (including the extension). + + \param[in] module Name of the module. + + \param[in] flags The flags used to call khc_open_space(). You can + use this to specify a particular configuration store if + needed. + + \param[out] result Receives the handle to a configuration space if + successful. Call khc_close_space() to close the handle. + + \see khc_open_space() + \see khc_close_space() +*/ +KHMEXP khm_int32 KHMAPI +kmm_get_module_config(wchar_t * module, khm_int32 flags, khm_handle * result); + +/*! \brief Retrieve a handle to the configuration space for plugins + + The configuration space for plugins is a container which holds the + configuration subspaces for all the plugins. This is the config + space which must be used to load a configuration space for a + plugin. + + \param[in] flags The flags to pass in to the call to + khc_open_space(). The flags can be used to select a specific + configuration store if needed. + + \param[out] result Receives a handle to the configuration + space. Call khc_close_space() to close the handle + + \see khc_open_space() + \see khc_close_space() + */ +KHMEXP khm_int32 KHMAPI +kmm_get_plugins_config(khm_int32 flags, khm_handle * result); + +/*! \brief Retrieve the handle to the configuration space for modules + + The configuration space for modules is a container which hold the + configuration subspaces for all the modules. Each module + registration ends up in this subspace. + + \param[in] flags The flags to pass in to the call to + khc_open_space(). The flags can be used to select a specific + configuration store if needed. + + \param[out] result Receives a handle to the configuration space. + Call khc_close_space() to close the handle. + + \see khc_open_space() + \see khc_close_space() + */ +KHMEXP khm_int32 KHMAPI +kmm_get_modules_config(khm_int32 flags, khm_handle * result); + +/*! \brief Return information about a loaded module + + The retrieves a block of information about a module. Refer to + ::kmm_module_info for information about the format of the returned + data. + + Note that the size of the required buffer is actually greater than + the size of the ::kmm_module_info structure and accomodates the + ::kmm_plugin_info structures and strings required to complete the + information block. + + Call the function with \a buffer set to NULL and \a cb_buffer + pointing at a khm_size variable to obtain the required size of the + buffer. + + \param[in] module_name Name of a module + \param[in] flags Flags indicating which types of information to + return + \param[out] buffer Points to a buffer that recieves information. + Set this to NULL if only the size of the buffer is required. + \param[in,out] On entry, contains the size of the buffer pointed + to by \a buffer if \a buffer is not NULL. On exit, contains + the required size of the buffer or the number of actual bytes + copied. + + \retval KHM_ERROR_SUCCESS The requested information was copied + \retval KHM_ERROR_INVALID_PARAM One of the parameters was invalid + \retval KHM_ERROR_TOO_LONG The buffer was not large enough or was + NULL. The number of bytes requied is in \a cb_buffer. + \retval KHM_ERROR_NOT_FOUND The specified module is not a + registered module. + */ +KHMEXP khm_int32 KHMAPI +kmm_get_module_info(wchar_t * module_name, khm_int32 flags, + kmm_module_info * buffer, khm_size * cb_buffer); + +/*! \brief Get information about a module + + Similar to kmm_get_module_info(), but uses a module handle instead + of a name, and uses internal buffers for providing string fields. + + The information that is returned should be freed using a call to + kmm_release_module_info_i(). + + \see kmm_release_module_info_i() + */ +KHMEXP khm_int32 KHMAPI +kmm_get_module_info_i(kmm_module module, kmm_module_info * info); + +/*! \brief Release module information + + Releases the information returned by a previous call to + kmm_get_module_info_i(). The contents of the ::kmm_module_info + structure should not have been modified in any way between calling + kmm_get_module_info_i() and kmm_release_module_info_i(). + */ +KHMEXP khm_int32 KHMAPI +kmm_release_module_info_i(kmm_module_info * info); + +/*! \brief Obtain information about a plugin + + Retrieve a block of information about a plugin. See + ::kmm_plugin_info for details about what information can be + returned. Note that some fields may not be available if the + module is not loaded. + + Note that the size of the required buffer is greater than the size + of the ::kmm_plugin_info structure and accounts for strings as + well. Call kmm_get_plugin_info() with \a buffer set to NULL and + \a cb_buffer set to point to a variable of type \a khm_size to + obtain the required size of the structure. + + \param[in] plugin_name Name of the plugin + \param[out] buffer The buffer to receive the plugin information. + Set to \a NULL if only the size of the buffer is required. + \param[in,out] cb_buffer On entry, points to variable that + specifies the size of the buffer pointed to by \a buffer is \a + buffer is not \a NULL. On exit, holds the number of bytes + copied or the required size of the buffer. + + \retval KHM_ERROR_SUCCESS The requested information was + successfully copied to the \a buffer + \retval KHM_ERROR_TOO_LONG The buffer was either \a NULL or + insufficient to hold the requested information. The required + size of the buffer was stored in \a cb_buffer + \retval KHM_ERROR_INVALID_PARAM One or more parameters were + invlaid. + \retval KHM_ERROR_NOT_FOUND The specified plugin was not found + among the registered plugins. +*/ +KHMEXP khm_int32 KHMAPI +kmm_get_plugin_info(wchar_t * plugin_name, + kmm_plugin_info * buffer, + khm_size * cb_buffer); + +/*! \brief Obtain information about a plugin using a plugin handle + + Similar to kmm_get_plugin_info() but uses a plugin handle instead + of a plugin name. If the call is successful, the \a info + structure will be filled with information about the plugin. The + returned info should not be modified in any way and may contain + pointers to internal buffers. + + The returned information must be released with a call to + kmm_release_plugin_info_i(). + */ +KHMEXP khm_int32 KHMAPI +kmm_get_plugin_info_i(kmm_plugin p, kmm_plugin_info * info); + +/*! \brief Release plugin information returned by kmm_get_plugin_info_i + + The information returned by kmm_get_plugin_info_i() should not be + modified in any way before calling kmm_release_plugin_info_i(). + Once the call completes, the contents of \a info will be + initialized to zero. + */ +KHMEXP khm_int32 KHMAPI +kmm_release_plugin_info_i(kmm_plugin_info * info); + +/*! \brief Enumerates plugins + + Enumerates through known plugins. This list may not include + plugins which were not loaded by NetIDMgr in this session. + + If the call is successful, a handle to the next plugin in the list + will be placed in \a p_next. The returned handle must be freed + with a call to kmm_release_plugin(). + + If the \a p parameter is set to NULL, then the first plugin handle + will be placed in \a p_next. The handles will not be returned in + any specific order. In addition, the enumeration may not include + all known plugins if the list of plugins changes during + enumeration. + */ +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 + msg_proc and \a icon members of the structure are ignored. + + At the time kmm_register_plugin() is called, the module specified + by \a module member of the \a plugin parameter must have been already + registered. Otherwise the function call fails. + + If the plugin has already been registered, then all the fields in + the plugin registration will be updated to be in sync with the + information provided in the \a plugin parameter. The failure + counts and associated statistics will not be reset when the + configuration information is updated. + + If the plugin has not been registered, the a new registration + entry is created in the configuration space indicated by the \a + config_flags parameter. In addition, the plugin will be added to + the list of plugins associated with the owning module. + + Note that the module that owns the plugin must be registered in + the same configuration store as the plugin. + + \param[in] plugin Registration info for the plugin. The \a + msg_proc and \a icon members are ignored. All other fields + are required. The \a description member should be localized + to the system locale when registering a plugin in the machine + configuration store and should be localized to the user locale + when registering a plugin in the user configuration store. + \param[in] config_flags Flags for the configuration provider. + These flags are used verbatim to call khc_open_space(), hence + they may be used to pick whether or not the registration is + per machine or per user. + + \see kmm_register_module() + */ +KHMEXP khm_int32 KHMAPI +kmm_register_plugin(kmm_plugin_reg * plugin, khm_int32 config_flags); + +/*! \brief Register a module + + The \a module parameter specifies the parameters for the module + registration. + + The \a plugin_info member should point to an array of + ::kmm_plugin_info structures unless the \a n_plugins member is + zero, in which case \a plugin_info can be \a NULL. Plugins can be + registered separately using kmm_register_plugin(). + + \param[in] module Information about the module. The name and path + fields are required. The \a plugin_info field can only be \a + NULL if \a n_plugins is zero. + + \param[in] config_flags Flags used to call khc_open_space(). This + can be used to choose the configuration store in which the + module registration will be performed. + */ +KHMEXP khm_int32 KHMAPI +kmm_register_module(kmm_module_reg * module, khm_int32 config_flags); + +/*! \brief Unregister a plugin + + Registration information associated with the plugin will be + removed. In addtion, the plugin will be removed from the list of + plugins provided by the owner module. + + \param[in] plugin Names the plugin to be removed + \param[in] config_flags Flags used to call khc_open_space(). Can + be used to choose the configuraiton store that is affected by + the call. + + \note kmm_unregister_plugin() has no effect on whether the plugin + is loaded or not. The caller must make sure that the plugin + is unloaded and the associated module is either also unloaded + or in a state where the plugin can be unregistered. + */ +KHMEXP khm_int32 KHMAPI +kmm_unregister_plugin(wchar_t * plugin, khm_int32 config_flags); + +/*! \brief Unregister a module + + Registration information associated with the module as well as all + the plugins provided by the module will be removed from the + configuration store. + + \param[in] module Names the module to be removed + + \param[in] config_flags Flags used to call khc_open_space(). Can + be used to choose the configuration store affected by the + call. + + \note kmm_unregister_module() has no effect on the loaded state of + the module. The caller should make sure that the module is + unloaded and in a state where it can be unregistered. + */ +KHMEXP khm_int32 KHMAPI +kmm_unregister_module(wchar_t * module, khm_int32 config_flags); + +/*@}*/ /* kmm_reg */ + +/*! \defgroup kmm_loc Internationalization support + + See \ref pi_localization for more information about + internationalization. + +@{*/ + +/*! \brief Locale descriptor record + + See kmm_set_locale() +*/ +typedef struct tag_kmm_module_locale { + khm_ui_4 language; /*!< A language ID. On Windows, you can use the + MAKELANGID macro to generate this value. */ + wchar_t * filename; /*!< The filename corresponding to this language. + Use NULL to indicate that resources for this + language are to be found in the main module. */ + khm_int32 flags; /*!< Flags. Combination of KMM_MLOC_FLAG_* */ +} kmm_module_locale; + +#define LOCALE_DEF(language_id, filename, flags) {language_id, filename, flags} + +/*! \brief Default (fallback) locale +*/ +#define KMM_MLOC_FLAG_DEFAULT 1 + + +/*! \brief Sets the locale for a loaded module. + + The given locale records are searched in the given order until a + locale that matches the current user locale is found. If no + locales match, then the first locale with the + ::KMM_MLOC_FLAG_DEFAULT flag set will be loaded. If no locales + have that flag set, then the first locale is loaded. + + You can obtain a handle to the loaded library using + kmm_get_resource_hmodule(). This function does not return until a + matched library is loaded. + + Note that the ::kmm_module_locale structure only specifies a + module name for the resource module. This resource module must + exist in the same directory as the \a module. + + \param[in] module The module handle + \param[in] locales An array of ::kmm_module_locale objects + \param[in] n_locales The number of objects in the array pointed to by \a locales + + \retval KHM_ERROR_SUCCESS Succeeded. + \retval KHM_ERROR_NOT_FOUND A matching locale resource library was not found. + \retval KHM_ERROR_INVALID_OPERATION The function was called on a module which is currently not being initalized. + + \see \ref pi_localization + \see kmm_get_resource_hmodule() + + \note This can only be called when handing init_module() +*/ +KHMEXP khm_int32 KHMAPI +kmm_set_locale_info(kmm_module module, + kmm_module_locale * locales, + khm_int32 n_locales); + +#ifdef _WIN32 + +/*! \brief Return the Windows module handle of the resource library of a NetIDMgr module. + + NetIDMgr allows the specification of an alternate resource library + that will be used to load localized resources from. This function + returns a handle to this library. + + While you can use the convenience macros to access resources in a + localization library using the module handle, it is recommended, + for performance reasons, to use this function to obtain the handle + to the resource library and then use that handle in calls to + LoadString, LoadImage etc. directly. +*/ +KHMEXP HMODULE KHMAPI +kmm_get_resource_hmodule(kmm_module m); + +/*! \name Convenience Macros +@{*/ +/*! \brief Convenience macro for using calling LoadAccelerators using a module handle + + \param[in] module A handle to a loaded module. The corresponding resource + module will be located through a call to kmm_get_resource_hmodule() +*/ +#define kmm_LoadAccelerators(module, lpTableName) \ + (LoadAccelerators(kmm_get_resource_hmodule(module), lpTableName)) + +/*! \brief Convenience macro for using calling LoadBitmap using a module handle + + \param[in] module A handle to a loaded module. The corresponding resource + module will be located through a call to kmm_get_resource_hmodule() +*/ +#define kmm_LoadBitmap(module, lpBitmapName) \ + (LoadBitmap(kmm_get_resource_hmodule(module), lpBitmapName)) + +/*! \brief Convenience macro for using calling LoadImage using a module handle + + \param[in] module A handle to a loaded module. The corresponding resource + module will be located through a call to kmm_get_resource_hmodule() +*/ +#define kmm_LoadImage(module, lpszName, uType, cxDesired, cyDesired, fuLoad) \ + (LoadImage(kmm_get_resource_hmodule(module), lpszName, uType, cxDesired, cyDesired, fuLoad)) + +/*! \brief Convenience macro for using calling LoadCursor using a module handle + + \param[in] module A handle to a loaded module. The corresponding resource + module will be located through a call to kmm_get_resource_hmodule() +*/ +#define kmm_LoadCursor(module, lpCursorName) \ + (LoadCursor(kmm_get_resource_hmodule(module), lpCursorName)) + +/*! \brief Convenience macro for using calling LoadIcon using a module handle + + \param[in] module A handle to a loaded module. The corresponding resource + module will be located through a call to kmm_get_resource_hmodule() +*/ +#define kmm_LoadIcon(module, lpIconName) \ + (LoadIcon(kmm_get_resource_hmodule(module), lpIconName)) + +/*! \brief Convenience macro for using calling LoadMenu using a module handle + + \param[in] module A handle to a loaded module. The corresponding resource + module will be located through a call to kmm_get_resource_hmodule() +*/ +#define kmm_LoadMenu(module, lpMenuName) \ + (LoadMenu(kmm_get_resource_hmodule(module), lpMenuName)) + +/*! \brief Convenience macro for using calling LoadString using a module handle + + \param[in] module A handle to a loaded module. The corresponding resource + module will be located through a call to kmm_get_resource_hmodule() +*/ +#define kmm_LoadString(module, uID, lpBuffer, nBufferMax) \ + (LoadString(kmm_get_resource_hmodule(module), uID, lpBuffer, nBufferMax)) +/*@}*/ /* Convenience Macros */ +#endif +/*@}*/ /* group kmm_loc */ +/*@}*/ /* group kmm */ +#endif diff --git a/src/windows/identity/kmm/kmm_module.c b/src/windows/identity/kmm/kmm_module.c index 932bdf8ef..52c34ac03 100644 --- a/src/windows/identity/kmm/kmm_module.c +++ b/src/windows/identity/kmm/kmm_module.c @@ -1,676 +1,676 @@ -/* - * 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 - -/* 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; - size_t sz; - - if(FAILED(StringCbLength(name, KMM_MAXCB_NAME, &sz))) - return NULL; - sz += sizeof(wchar_t); - - EnterCriticalSection(&cs_kmm); - m = (kmm_module_i *) hash_lookup(hash_modules, (void *) name); - - if(m == NULL) { - m = PMALLOC(sizeof(kmm_module_i)); - ZeroMemory(m, sizeof(kmm_module_i)); - - m->magic = KMM_MODULE_MAGIC; - m->name = PMALLOC(sz); - StringCbCopy(m->name, sz, name); - m->state = KMM_MODULE_STATE_NONE; - - hash_add(hash_modules, (void *) m->name, (void *) m); - LPUSH(&kmm_all_modules, m); - } - LeaveCriticalSection(&cs_kmm); - - return m; -} - -kmm_module_i * kmmint_find_module_i(wchar_t * name) -{ - kmm_module_i * m; - - EnterCriticalSection(&cs_kmm); - m = (kmm_module_i *) hash_lookup(hash_modules, (void *) name); - LeaveCriticalSection(&cs_kmm); - - return m; -} - -/* called with cs_kmm held */ -void kmmint_free_module(kmm_module_i * m) -{ - m->magic = 0; - - hash_del(hash_modules, m->name); - LDELETE(&kmm_all_modules, m); - - if (m->name) - PFREE(m->name); - - if (m->description) - PFREE(m->description); - - if (m->path) - PFREE(m->path); - - if (m->vendor) - PFREE(m->vendor); - - if (m->support) - PFREE(m->support); - - if (m->version_info) - PFREE(m->version_info); - - PFREE(m); -} - -KHMEXP khm_int32 KHMAPI kmm_hold_module(kmm_module module) -{ - if(!kmm_is_module(module)) - return KHM_ERROR_INVALID_PARAM; - EnterCriticalSection(&cs_kmm); - kmm_module_from_handle(module)->refcount++; - LeaveCriticalSection(&cs_kmm); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI kmm_release_module(kmm_module vm) -{ - kmm_module_i * m; - - if(!kmm_is_module(vm)) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_kmm); - m = kmm_module_from_handle(vm); - if(! --(m->refcount)) - { - /* note that a 0 ref count means that there are no active - plugins */ - kmmint_free_module(m); - } - LeaveCriticalSection(&cs_kmm); - return KHM_ERROR_SUCCESS; -} - -khm_int32 -kmmint_check_api_version(DWORD v) { - /* 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; -} - -struct lang_code { - WORD language; - WORD codepage; -}; - -khm_int32 -kmmint_read_module_info(kmm_module_i * m) { - /* the only fields we can count on at this point are m->name and - m->path */ - DWORD t; - size_t cb; - WORD lang; - khm_int32 rv = KHM_ERROR_SUCCESS; - struct lang_code *languages; - int n_languages; - int i; - wchar_t resname[256]; /* the resource names are a lot shorter */ - wchar_t * r; - VS_FIXEDFILEINFO *vff; - - assert(m->name); - assert(m->path); - - t = TRUE; - cb = GetFileVersionInfoSize(m->path, - &t); - /* if successful, cb gets the size in bytes of the version info - structure and sets t to zero */ - if (t) { - return KHM_ERROR_NOT_FOUND; - } else if (cb == 0) { - _report_mr1(KHERR_WARNING, MSG_RMI_NOT_FOUND, _dupstr(m->path)); - return KHM_ERROR_INVALID_PARAM; - } - - if (m->version_info) { - PFREE(m->version_info); - m->version_info = NULL; - } - - m->version_info = PMALLOC(cb); -#ifdef DEBUG - assert(m->version_info); -#endif - - if(!GetFileVersionInfo(m->path, - t, (DWORD) cb, m->version_info)) { - rv = KHM_ERROR_NOT_FOUND; - _report_mr1(KHERR_WARNING, MSG_RMI_NOT_FOUND, _dupstr(m->path)); - _location(L"GetFileVersionInfo"); - goto _cleanup; - } - - if(!VerQueryValue(m->version_info, - L"\\VarFileInfo\\Translation", - (LPVOID*) &languages, - &cb)) { - rv = KHM_ERROR_INVALID_PARAM; - _report_mr1(KHERR_WARNING, MSG_RMI_NO_TRANS, _dupstr(m->path)); - _location(L"VerQueryValue"); - goto _cleanup; - } - - n_languages = (int) (cb / sizeof(*languages)); - - /* Try searching for the user's default language first */ - lang = GetUserDefaultLangID(); - for (i = 0; i < n_languages; i++) { - if(languages[i].language == lang) - break; - } - - /* If not, try the system default */ - if (i >= n_languages) { - lang = GetSystemDefaultLangID(); - for (i=0; i= n_languages) { - lang = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); - for (i=0; i= n_languages) { - lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); - for (i=0; i= n_languages) { - i = 0; - } - - if (i >= n_languages) { - rv = KHM_ERROR_INVALID_PARAM; - _report_mr0(KHERR_WARNING, MSG_RMI_NO_LOCAL); - goto _cleanup; - } - - /* check module name */ - StringCbPrintf(resname, sizeof(resname), - L"\\StringFileInfo\\%04x%04x\\" TEXT(NIMV_MODULE), - languages[i].language, - languages[i].codepage); - - if (!VerQueryValue(m->version_info, - resname, (LPVOID *) &r, &cb)) { - rv = KHM_ERROR_INVALID_PARAM; - _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, - _cstr(TEXT(NIMV_MODULE))); - goto _cleanup; - } - - if (cb > KMM_MAXCB_NAME || - FAILED(StringCbLength(r, KMM_MAXCB_NAME, &cb))) { - rv = KHM_ERROR_INVALID_PARAM; - _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG, - _cstr(TEXT(NIMV_MODULE))); - goto _cleanup; - } - - if (wcscmp(r, m->name)) { - rv = KHM_ERROR_INVALID_PARAM; - _report_mr2(KHERR_WARNING, MSG_RMI_MOD_MISMATCH, - _dupstr(r), _dupstr(m->name)); - goto _cleanup; - } - - /* check API version */ - StringCbPrintf(resname, sizeof(resname), - L"\\StringFileInfo\\%04x%04x\\" TEXT(NIMV_APIVER), - languages[i].language, - languages[i].codepage); - - if (!VerQueryValue(m->version_info, - resname, (LPVOID *) &r, &cb)) { - rv = KHM_ERROR_INVALID_PARAM; - _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, - _cstr(TEXT(NIMV_APIVER))); - goto _cleanup; - } - - if (cb > KMM_MAXCB_NAME || - FAILED(StringCbLength(r, KMM_MAXCB_NAME, &cb))) { - rv = KHM_ERROR_INVALID_PARAM; - _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG, - _cstr(TEXT(NIMV_APIVER))); - goto _cleanup; - } - - t = wcstol(r, NULL, 10); - - rv = kmmint_check_api_version(t); - - if (KHM_FAILED(rv)) { - _report_mr2(KHERR_WARNING, MSG_RMI_API_MISMATCH, - _int32(t), _int32(KH_VERSION_API)); - goto _cleanup; - } - - /* Looks good. Now load the description, copyright, support URI - and file versions */ - if (m->description) { - PFREE(m->description); - m->description = NULL; - } - - StringCbPrintf(resname, sizeof(resname), - L"\\StringFileInfo\\%04x%04x\\FileDescription", - languages[i].language, - languages[i].codepage); - - if (!VerQueryValue(m->version_info, - resname, (LPVOID *) &r, &cb)) { - rv = KHM_ERROR_INVALID_PARAM; - _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, - _cstr(L"FileDescription")); - goto _cleanup; - } - - if (cb > KMM_MAXCB_DESC || - FAILED(StringCbLength(r, KMM_MAXCB_DESC, &cb))) { - rv = KHM_ERROR_INVALID_PARAM; - _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG, - _cstr(L"FileDescription")); - goto _cleanup; - } - - cb += sizeof(wchar_t); - - m->description = PMALLOC(cb); -#ifdef DEBUG - assert(m->description); -#endif - StringCbCopy(m->description, cb, r); - - /* on to the support URI */ - if (m->support) { - PFREE(m->support); - m->support = NULL; - } - - StringCbPrintf(resname, sizeof(resname), - L"\\StringFileInfo\\%04x%04x\\" TEXT(NIMV_SUPPORT), - languages[i].language, - languages[i].codepage); - - if (!VerQueryValue(m->version_info, - resname, (LPVOID *) &r, &cb)) { - rv = KHM_ERROR_INVALID_PARAM; - _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, - _cstr(TEXT(NIMV_SUPPORT))); - goto _cleanup; - } - - if (cb > KMM_MAXCB_SUPPORT || - FAILED(StringCbLength(r, KMM_MAXCB_SUPPORT, &cb))) { - rv = KHM_ERROR_INVALID_PARAM; - _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG, - _cstr(TEXT(NIMV_SUPPORT))); - goto _cleanup; - } - - cb += sizeof(wchar_t); - - m->support = PMALLOC(cb); -#ifdef DEBUG - assert(m->support); -#endif - StringCbCopy(m->support, cb, r); - - /* the vendor/copyright */ - if (m->vendor) { - PFREE(m->vendor); - m->vendor = NULL; - } - - StringCbPrintf(resname, sizeof(resname), - L"\\StringFileInfo\\%04x%04x\\LegalCopyright", - languages[i].language, - languages[i].codepage); - - if (!VerQueryValue(m->version_info, - resname, (LPVOID *) &r, &cb)) { - rv = KHM_ERROR_INVALID_PARAM; - _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, - _cstr(L"LegalCopyright")); - goto _cleanup; - } - - if (cb > KMM_MAXCB_SUPPORT || - FAILED(StringCbLength(r, KMM_MAXCB_SUPPORT, &cb))) { - rv = KHM_ERROR_INVALID_PARAM; - _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG, - _cstr(L"LegalCopyright")); - goto _cleanup; - } - - cb += sizeof(wchar_t); - - m->vendor = PMALLOC(cb); -#ifdef DEBUG - assert(m->vendor); -#endif - StringCbCopy(m->vendor, cb, r); - - if (!VerQueryValue(m->version_info, - L"\\", - (LPVOID *) &vff, - &cb) || - cb != sizeof(*vff)) { - - rv = KHM_ERROR_INVALID_PARAM; - _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, - _cstr(L"Fixed Version Info")); - goto _cleanup; - } - - m->file_version.major = HIWORD(vff->dwFileVersionMS); - m->file_version.minor = LOWORD(vff->dwFileVersionMS); - m->file_version.patch = HIWORD(vff->dwFileVersionLS); - m->file_version.aux = LOWORD(vff->dwFileVersionLS); - - m->prod_version.major = HIWORD(vff->dwProductVersionMS); - m->prod_version.minor = LOWORD(vff->dwProductVersionMS); - m->prod_version.patch = HIWORD(vff->dwProductVersionLS); - m->prod_version.aux = LOWORD(vff->dwProductVersionLS); - - rv = KHM_ERROR_SUCCESS; - - _cleanup: - if (KHM_FAILED(rv)) { - if (m->version_info) { - PFREE(m->version_info); - m->version_info = NULL; - } - } - - return rv; -} - -KHMEXP khm_int32 KHMAPI kmm_load_module(wchar_t * modname, - khm_int32 flags, - kmm_module * result) -{ - kmm_module_i * m = NULL; - kmm_module_i * mi; - size_t cbsize; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(FAILED(StringCbLength(modname, KMM_MAXCB_NAME, &cbsize))) - return KHM_ERROR_INVALID_PARAM; - cbsize += sizeof(wchar_t); - - EnterCriticalSection(&cs_kmm); - mi = kmmint_find_module_i(modname); - - if(mi != NULL) { - kmm_hold_module(kmm_handle_from_module(mi)); - /* check if the module has either failed to load either or if - it has been terminated. If so, we try once again to load the - module. */ - if(!(flags & KMM_LM_FLAG_NOLOAD) && - (mi->state < 0 || mi->state == KMM_MODULE_STATE_EXITED)) - { - mi->state = KMM_MODULE_STATE_PREINIT; - } - } - LeaveCriticalSection(&cs_kmm); - - if(flags & KMM_LM_FLAG_NOLOAD) { - if(result) - *result = mi; - else if(mi) - kmm_release_module(kmm_handle_from_module(mi)); - - return (mi)? KHM_ERROR_SUCCESS: KHM_ERROR_NOT_FOUND; - } - - if(mi) { - m = mi; - } else { - m = kmmint_get_module_i(modname); - m->state = KMM_MODULE_STATE_PREINIT; - kmm_hold_module(kmm_handle_from_module(m)); - } - - /* the module is already running or is already being - worked on by the registrar */ - if(m->state != KMM_MODULE_STATE_PREINIT) { - if(result) - *result = kmm_handle_from_module(m); - else - kmm_release_module(kmm_handle_from_module(m)); - - return KHM_ERROR_EXISTS; - } - - kmmint_add_to_module_queue(); - - if(flags & KMM_LM_FLAG_SYNC) { - kmm_hold_module(kmm_handle_from_module(m)); - kmq_send_message(KMSG_KMM, - KMSG_KMM_I_REG, - KMM_REG_INIT_MODULE, - (void*) m); - if(m->state <= 0) { - /* failed to load ? */ - if(m->state == KMM_MODULE_STATE_FAIL_NOT_FOUND) - rv = KHM_ERROR_NOT_FOUND; - else if(m->state == KMM_MODULE_STATE_FAIL_SIGNATURE) - rv = KHM_ERROR_INVALID_SIGNATURE; - else - rv = KHM_ERROR_UNKNOWN; - - kmm_release_module(kmm_handle_from_module(m)); - if(result) - *result = NULL; - } else { - if(result) - *result = kmm_handle_from_module(m); - else - kmm_release_module(kmm_handle_from_module(m)); - } - } else { - kmm_hold_module(kmm_handle_from_module(m)); - kmq_post_message(KMSG_KMM, - KMSG_KMM_I_REG, - KMM_REG_INIT_MODULE, - (void*) m); - if(result) - *result = kmm_handle_from_module(m); - else - kmm_release_module(kmm_handle_from_module(m)); - } - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kmm_get_module_state(kmm_module m) -{ - if(!kmm_is_module(m)) - return KMM_MODULE_STATE_NONE; - else - return kmm_module_from_handle(m)->state; -} - -KHMEXP khm_int32 KHMAPI -kmm_get_module_info_i(kmm_module vm, kmm_module_info * info) { - kmm_module_i * m; - khm_int32 rv; - - EnterCriticalSection(&cs_kmm); - if (!kmm_is_module(vm) || !info) - rv = KHM_ERROR_INVALID_PARAM; - else { - m = kmm_module_from_handle(vm); - - ZeroMemory(info, sizeof(*info)); - - info->reg.name = m->name; - info->reg.path = m->path; - info->reg.vendor = m->vendor; - - info->reg.n_plugins = m->plugin_count; - - 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; - } - LeaveCriticalSection(&cs_kmm); - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kmm_release_module_info_i(kmm_module_info * info) { - if (info->h_module) - kmm_release_module(info->h_module); - - ZeroMemory(info, sizeof(*info)); - - return KHM_ERROR_SUCCESS; -} - - -KHMEXP khm_int32 KHMAPI -kmm_unload_module(kmm_module module) { - - if(!kmm_is_module(module)) - return KHM_ERROR_INVALID_PARAM; - - kmm_hold_module(module); - kmq_post_message(KMSG_KMM, - KMSG_KMM_I_REG, - KMM_REG_EXIT_MODULE, - (void *) kmm_module_from_handle(module)); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kmm_load_default_modules(void) { - khm_handle csm = NULL; - khm_handle cs_mod = NULL; - khm_int32 rv; - wchar_t buf[KMM_MAXCCH_NAME]; - khm_size s; - - rv = kmm_get_modules_config(0, &csm); - if(KHM_FAILED(rv)) - return rv; - - _begin_task(KHERR_CF_TRANSITIVE); - _report_mr0(KHERR_NONE, MSG_LOAD_DEFAULT); - _describe(); - - kmmint_add_to_module_queue(); - - while(KHM_SUCCEEDED(khc_enum_subspaces(csm, cs_mod, &cs_mod))) { - - s = sizeof(buf); - if (KHM_FAILED(khc_get_config_space_name(cs_mod, buf, &s))) - continue; - - /* check for schema subspace. This is not an actual module. */ - if (!wcscmp(buf, L"_Schema")) - continue; - - kmm_load_module(buf, 0, NULL); - } - - kmmint_remove_from_module_queue(); - - if(csm) - khc_close_space(csm); - - _end_task(); - - return rv; -} - -#ifdef _WIN32 -KHMEXP HMODULE KHMAPI -kmm_get_hmodule(kmm_module m) -{ - if(!kmm_is_module(m)) - return NULL; - else - return kmm_module_from_handle(m)->h_module; -} -#endif +/* + * 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 + +/* 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; + size_t sz; + + if(FAILED(StringCbLength(name, KMM_MAXCB_NAME, &sz))) + return NULL; + sz += sizeof(wchar_t); + + EnterCriticalSection(&cs_kmm); + m = (kmm_module_i *) hash_lookup(hash_modules, (void *) name); + + if(m == NULL) { + m = PMALLOC(sizeof(kmm_module_i)); + ZeroMemory(m, sizeof(kmm_module_i)); + + m->magic = KMM_MODULE_MAGIC; + m->name = PMALLOC(sz); + StringCbCopy(m->name, sz, name); + m->state = KMM_MODULE_STATE_NONE; + + hash_add(hash_modules, (void *) m->name, (void *) m); + LPUSH(&kmm_all_modules, m); + } + LeaveCriticalSection(&cs_kmm); + + return m; +} + +kmm_module_i * kmmint_find_module_i(wchar_t * name) +{ + kmm_module_i * m; + + EnterCriticalSection(&cs_kmm); + m = (kmm_module_i *) hash_lookup(hash_modules, (void *) name); + LeaveCriticalSection(&cs_kmm); + + return m; +} + +/* called with cs_kmm held */ +void kmmint_free_module(kmm_module_i * m) +{ + m->magic = 0; + + hash_del(hash_modules, m->name); + LDELETE(&kmm_all_modules, m); + + if (m->name) + PFREE(m->name); + + if (m->description) + PFREE(m->description); + + if (m->path) + PFREE(m->path); + + if (m->vendor) + PFREE(m->vendor); + + if (m->support) + PFREE(m->support); + + if (m->version_info) + PFREE(m->version_info); + + PFREE(m); +} + +KHMEXP khm_int32 KHMAPI kmm_hold_module(kmm_module module) +{ + if(!kmm_is_module(module)) + return KHM_ERROR_INVALID_PARAM; + EnterCriticalSection(&cs_kmm); + kmm_module_from_handle(module)->refcount++; + LeaveCriticalSection(&cs_kmm); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kmm_release_module(kmm_module vm) +{ + kmm_module_i * m; + + if(!kmm_is_module(vm)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_kmm); + m = kmm_module_from_handle(vm); + if(! --(m->refcount)) + { + /* note that a 0 ref count means that there are no active + plugins */ + kmmint_free_module(m); + } + LeaveCriticalSection(&cs_kmm); + return KHM_ERROR_SUCCESS; +} + +khm_int32 +kmmint_check_api_version(DWORD v) { + /* 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; +} + +struct lang_code { + WORD language; + WORD codepage; +}; + +khm_int32 +kmmint_read_module_info(kmm_module_i * m) { + /* the only fields we can count on at this point are m->name and + m->path */ + DWORD t; + size_t cb; + WORD lang; + khm_int32 rv = KHM_ERROR_SUCCESS; + struct lang_code *languages; + int n_languages; + int i; + wchar_t resname[256]; /* the resource names are a lot shorter */ + wchar_t * r; + VS_FIXEDFILEINFO *vff; + + assert(m->name); + assert(m->path); + + t = TRUE; + cb = GetFileVersionInfoSize(m->path, + &t); + /* if successful, cb gets the size in bytes of the version info + structure and sets t to zero */ + if (t) { + return KHM_ERROR_NOT_FOUND; + } else if (cb == 0) { + _report_mr1(KHERR_WARNING, MSG_RMI_NOT_FOUND, _dupstr(m->path)); + return KHM_ERROR_INVALID_PARAM; + } + + if (m->version_info) { + PFREE(m->version_info); + m->version_info = NULL; + } + + m->version_info = PMALLOC(cb); +#ifdef DEBUG + assert(m->version_info); +#endif + + if(!GetFileVersionInfo(m->path, + t, (DWORD) cb, m->version_info)) { + rv = KHM_ERROR_NOT_FOUND; + _report_mr1(KHERR_WARNING, MSG_RMI_NOT_FOUND, _dupstr(m->path)); + _location(L"GetFileVersionInfo"); + goto _cleanup; + } + + if(!VerQueryValue(m->version_info, + L"\\VarFileInfo\\Translation", + (LPVOID*) &languages, + &cb)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_NO_TRANS, _dupstr(m->path)); + _location(L"VerQueryValue"); + goto _cleanup; + } + + n_languages = (int) (cb / sizeof(*languages)); + + /* Try searching for the user's default language first */ + lang = GetUserDefaultLangID(); + for (i = 0; i < n_languages; i++) { + if(languages[i].language == lang) + break; + } + + /* If not, try the system default */ + if (i >= n_languages) { + lang = GetSystemDefaultLangID(); + for (i=0; i= n_languages) { + lang = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); + for (i=0; i= n_languages) { + lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); + for (i=0; i= n_languages) { + i = 0; + } + + if (i >= n_languages) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr0(KHERR_WARNING, MSG_RMI_NO_LOCAL); + goto _cleanup; + } + + /* check module name */ + StringCbPrintf(resname, sizeof(resname), + L"\\StringFileInfo\\%04x%04x\\" TEXT(NIMV_MODULE), + languages[i].language, + languages[i].codepage); + + if (!VerQueryValue(m->version_info, + resname, (LPVOID *) &r, &cb)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, + _cstr(TEXT(NIMV_MODULE))); + goto _cleanup; + } + + if (cb > KMM_MAXCB_NAME || + FAILED(StringCbLength(r, KMM_MAXCB_NAME, &cb))) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG, + _cstr(TEXT(NIMV_MODULE))); + goto _cleanup; + } + + if (wcscmp(r, m->name)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr2(KHERR_WARNING, MSG_RMI_MOD_MISMATCH, + _dupstr(r), _dupstr(m->name)); + goto _cleanup; + } + + /* check API version */ + StringCbPrintf(resname, sizeof(resname), + L"\\StringFileInfo\\%04x%04x\\" TEXT(NIMV_APIVER), + languages[i].language, + languages[i].codepage); + + if (!VerQueryValue(m->version_info, + resname, (LPVOID *) &r, &cb)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, + _cstr(TEXT(NIMV_APIVER))); + goto _cleanup; + } + + if (cb > KMM_MAXCB_NAME || + FAILED(StringCbLength(r, KMM_MAXCB_NAME, &cb))) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG, + _cstr(TEXT(NIMV_APIVER))); + goto _cleanup; + } + + t = wcstol(r, NULL, 10); + + rv = kmmint_check_api_version(t); + + if (KHM_FAILED(rv)) { + _report_mr2(KHERR_WARNING, MSG_RMI_API_MISMATCH, + _int32(t), _int32(KH_VERSION_API)); + goto _cleanup; + } + + /* Looks good. Now load the description, copyright, support URI + and file versions */ + if (m->description) { + PFREE(m->description); + m->description = NULL; + } + + StringCbPrintf(resname, sizeof(resname), + L"\\StringFileInfo\\%04x%04x\\FileDescription", + languages[i].language, + languages[i].codepage); + + if (!VerQueryValue(m->version_info, + resname, (LPVOID *) &r, &cb)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, + _cstr(L"FileDescription")); + goto _cleanup; + } + + if (cb > KMM_MAXCB_DESC || + FAILED(StringCbLength(r, KMM_MAXCB_DESC, &cb))) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG, + _cstr(L"FileDescription")); + goto _cleanup; + } + + cb += sizeof(wchar_t); + + m->description = PMALLOC(cb); +#ifdef DEBUG + assert(m->description); +#endif + StringCbCopy(m->description, cb, r); + + /* on to the support URI */ + if (m->support) { + PFREE(m->support); + m->support = NULL; + } + + StringCbPrintf(resname, sizeof(resname), + L"\\StringFileInfo\\%04x%04x\\" TEXT(NIMV_SUPPORT), + languages[i].language, + languages[i].codepage); + + if (!VerQueryValue(m->version_info, + resname, (LPVOID *) &r, &cb)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, + _cstr(TEXT(NIMV_SUPPORT))); + goto _cleanup; + } + + if (cb > KMM_MAXCB_SUPPORT || + FAILED(StringCbLength(r, KMM_MAXCB_SUPPORT, &cb))) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG, + _cstr(TEXT(NIMV_SUPPORT))); + goto _cleanup; + } + + cb += sizeof(wchar_t); + + m->support = PMALLOC(cb); +#ifdef DEBUG + assert(m->support); +#endif + StringCbCopy(m->support, cb, r); + + /* the vendor/copyright */ + if (m->vendor) { + PFREE(m->vendor); + m->vendor = NULL; + } + + StringCbPrintf(resname, sizeof(resname), + L"\\StringFileInfo\\%04x%04x\\LegalCopyright", + languages[i].language, + languages[i].codepage); + + if (!VerQueryValue(m->version_info, + resname, (LPVOID *) &r, &cb)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, + _cstr(L"LegalCopyright")); + goto _cleanup; + } + + if (cb > KMM_MAXCB_SUPPORT || + FAILED(StringCbLength(r, KMM_MAXCB_SUPPORT, &cb))) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG, + _cstr(L"LegalCopyright")); + goto _cleanup; + } + + cb += sizeof(wchar_t); + + m->vendor = PMALLOC(cb); +#ifdef DEBUG + assert(m->vendor); +#endif + StringCbCopy(m->vendor, cb, r); + + if (!VerQueryValue(m->version_info, + L"\\", + (LPVOID *) &vff, + &cb) || + cb != sizeof(*vff)) { + + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, + _cstr(L"Fixed Version Info")); + goto _cleanup; + } + + m->file_version.major = HIWORD(vff->dwFileVersionMS); + m->file_version.minor = LOWORD(vff->dwFileVersionMS); + m->file_version.patch = HIWORD(vff->dwFileVersionLS); + m->file_version.aux = LOWORD(vff->dwFileVersionLS); + + m->prod_version.major = HIWORD(vff->dwProductVersionMS); + m->prod_version.minor = LOWORD(vff->dwProductVersionMS); + m->prod_version.patch = HIWORD(vff->dwProductVersionLS); + m->prod_version.aux = LOWORD(vff->dwProductVersionLS); + + rv = KHM_ERROR_SUCCESS; + + _cleanup: + if (KHM_FAILED(rv)) { + if (m->version_info) { + PFREE(m->version_info); + m->version_info = NULL; + } + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI kmm_load_module(wchar_t * modname, + khm_int32 flags, + kmm_module * result) +{ + kmm_module_i * m = NULL; + kmm_module_i * mi; + size_t cbsize; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(FAILED(StringCbLength(modname, KMM_MAXCB_NAME, &cbsize))) + return KHM_ERROR_INVALID_PARAM; + cbsize += sizeof(wchar_t); + + EnterCriticalSection(&cs_kmm); + mi = kmmint_find_module_i(modname); + + if(mi != NULL) { + kmm_hold_module(kmm_handle_from_module(mi)); + /* check if the module has either failed to load either or if + it has been terminated. If so, we try once again to load the + module. */ + if(!(flags & KMM_LM_FLAG_NOLOAD) && + (mi->state < 0 || mi->state == KMM_MODULE_STATE_EXITED)) + { + mi->state = KMM_MODULE_STATE_PREINIT; + } + } + LeaveCriticalSection(&cs_kmm); + + if(flags & KMM_LM_FLAG_NOLOAD) { + if(result) + *result = mi; + else if(mi) + kmm_release_module(kmm_handle_from_module(mi)); + + return (mi)? KHM_ERROR_SUCCESS: KHM_ERROR_NOT_FOUND; + } + + if(mi) { + m = mi; + } else { + m = kmmint_get_module_i(modname); + m->state = KMM_MODULE_STATE_PREINIT; + kmm_hold_module(kmm_handle_from_module(m)); + } + + /* the module is already running or is already being + worked on by the registrar */ + if(m->state != KMM_MODULE_STATE_PREINIT) { + if(result) + *result = kmm_handle_from_module(m); + else + kmm_release_module(kmm_handle_from_module(m)); + + return KHM_ERROR_EXISTS; + } + + kmmint_add_to_module_queue(); + + if(flags & KMM_LM_FLAG_SYNC) { + kmm_hold_module(kmm_handle_from_module(m)); + kmq_send_message(KMSG_KMM, + KMSG_KMM_I_REG, + KMM_REG_INIT_MODULE, + (void*) m); + if(m->state <= 0) { + /* failed to load ? */ + if(m->state == KMM_MODULE_STATE_FAIL_NOT_FOUND) + rv = KHM_ERROR_NOT_FOUND; + else if(m->state == KMM_MODULE_STATE_FAIL_SIGNATURE) + rv = KHM_ERROR_INVALID_SIGNATURE; + else + rv = KHM_ERROR_UNKNOWN; + + kmm_release_module(kmm_handle_from_module(m)); + if(result) + *result = NULL; + } else { + if(result) + *result = kmm_handle_from_module(m); + else + kmm_release_module(kmm_handle_from_module(m)); + } + } else { + kmm_hold_module(kmm_handle_from_module(m)); + kmq_post_message(KMSG_KMM, + KMSG_KMM_I_REG, + KMM_REG_INIT_MODULE, + (void*) m); + if(result) + *result = kmm_handle_from_module(m); + else + kmm_release_module(kmm_handle_from_module(m)); + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kmm_get_module_state(kmm_module m) +{ + if(!kmm_is_module(m)) + return KMM_MODULE_STATE_NONE; + else + return kmm_module_from_handle(m)->state; +} + +KHMEXP khm_int32 KHMAPI +kmm_get_module_info_i(kmm_module vm, kmm_module_info * info) { + kmm_module_i * m; + khm_int32 rv; + + EnterCriticalSection(&cs_kmm); + if (!kmm_is_module(vm) || !info) + rv = KHM_ERROR_INVALID_PARAM; + else { + m = kmm_module_from_handle(vm); + + ZeroMemory(info, sizeof(*info)); + + info->reg.name = m->name; + info->reg.path = m->path; + info->reg.vendor = m->vendor; + + info->reg.n_plugins = m->plugin_count; + + 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; + } + LeaveCriticalSection(&cs_kmm); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kmm_release_module_info_i(kmm_module_info * info) { + if (info->h_module) + kmm_release_module(info->h_module); + + ZeroMemory(info, sizeof(*info)); + + return KHM_ERROR_SUCCESS; +} + + +KHMEXP khm_int32 KHMAPI +kmm_unload_module(kmm_module module) { + + if(!kmm_is_module(module)) + return KHM_ERROR_INVALID_PARAM; + + kmm_hold_module(module); + kmq_post_message(KMSG_KMM, + KMSG_KMM_I_REG, + KMM_REG_EXIT_MODULE, + (void *) kmm_module_from_handle(module)); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kmm_load_default_modules(void) { + khm_handle csm = NULL; + khm_handle cs_mod = NULL; + khm_int32 rv; + wchar_t buf[KMM_MAXCCH_NAME]; + khm_size s; + + rv = kmm_get_modules_config(0, &csm); + if(KHM_FAILED(rv)) + return rv; + + _begin_task(KHERR_CF_TRANSITIVE); + _report_mr0(KHERR_NONE, MSG_LOAD_DEFAULT); + _describe(); + + kmmint_add_to_module_queue(); + + while(KHM_SUCCEEDED(khc_enum_subspaces(csm, cs_mod, &cs_mod))) { + + s = sizeof(buf); + if (KHM_FAILED(khc_get_config_space_name(cs_mod, buf, &s))) + continue; + + /* check for schema subspace. This is not an actual module. */ + if (!wcscmp(buf, L"_Schema")) + continue; + + kmm_load_module(buf, 0, NULL); + } + + kmmint_remove_from_module_queue(); + + if(csm) + khc_close_space(csm); + + _end_task(); + + return rv; +} + +#ifdef _WIN32 +KHMEXP HMODULE KHMAPI +kmm_get_hmodule(kmm_module m) +{ + if(!kmm_is_module(m)) + return NULL; + else + return kmm_module_from_handle(m)->h_module; +} +#endif diff --git a/src/windows/identity/kmm/kmm_plugin.c b/src/windows/identity/kmm/kmm_plugin.c index 18a46b7c4..89e31ad84 100644 --- a/src/windows/identity/kmm/kmm_plugin.c +++ b/src/windows/identity/kmm/kmm_plugin.c @@ -1,414 +1,414 @@ -/* - * 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 - -/* Called with no locks held to get a kmm_plugin_i structure - that matches the name. First we look in the hash table, and - if one isn't found, we create an empty one. -*/ - -kmm_plugin_i * -kmmint_get_plugin_i(wchar_t * name) -{ - kmm_plugin_i * p; - size_t cb; - - if(FAILED(StringCbLength(name, KMM_MAXCB_NAME, &cb))) - return NULL; - cb += sizeof(wchar_t); - - EnterCriticalSection(&cs_kmm); - p = (kmm_plugin_i *) hash_lookup(hash_plugins, (void *) name); - - if(p == NULL) { - p = PMALLOC(sizeof(kmm_plugin_i)); - ZeroMemory(p, sizeof(kmm_plugin_i)); - p->magic = KMM_PLUGIN_MAGIC; - p->p.name = PMALLOC(cb); - StringCbCopy(p->p.name, cb, name); - p->state = KMM_PLUGIN_STATE_NONE; - - hash_add(hash_plugins, (void *) p->p.name, (void *) p); - kmmint_list_plugin(p); - } - LeaveCriticalSection(&cs_kmm); - - return p; -} - -kmm_plugin_i * -kmmint_find_plugin_i(wchar_t * name) -{ - kmm_plugin_i * p; - size_t cb; - - if(FAILED(StringCbLength(name, KMM_MAXCB_NAME, &cb))) - return NULL; - - EnterCriticalSection(&cs_kmm); - p = (kmm_plugin_i *) hash_lookup(hash_plugins, (void *) name); - LeaveCriticalSection(&cs_kmm); - - return p; -} - -/* the plugin must be delisted before calling this */ -void -kmmint_list_plugin(kmm_plugin_i * p) -{ - EnterCriticalSection(&cs_kmm); - if((p->flags & KMM_PLUGIN_FLAG_IN_MODLIST) || - (p->flags & KMM_PLUGIN_FLAG_IN_LIST)) - { - RaiseException(2, EXCEPTION_NONCONTINUABLE, 0, NULL); - } - p->flags |= KMM_PLUGIN_FLAG_IN_LIST; - LPUSH(&kmm_listed_plugins, p); - LeaveCriticalSection(&cs_kmm); -} - -void -kmmint_delist_plugin(kmm_plugin_i * p) -{ - EnterCriticalSection(&cs_kmm); - if(p->flags & KMM_PLUGIN_FLAG_IN_LIST) { - p->flags &= ~KMM_PLUGIN_FLAG_IN_LIST; - LDELETE(&kmm_listed_plugins, p); - } - if(p->flags & KMM_PLUGIN_FLAG_IN_MODLIST) { - p->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST; - LDELETE(&(p->module->plugins), p); - } - LeaveCriticalSection(&cs_kmm); -} - -KHMEXP khm_int32 KHMAPI -kmm_hold_plugin(kmm_plugin p) -{ - kmm_plugin_i * pi; - - if(!kmm_is_plugin(p)) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_kmm); - pi = kmm_plugin_from_handle(p); - pi->refcount++; - LeaveCriticalSection(&cs_kmm); - - return KHM_ERROR_SUCCESS; -} - -/* called with cs_kmm held */ -void -kmmint_free_plugin(kmm_plugin_i * pi) -{ - int i; - pi->magic = 0; - - hash_del(hash_plugins, (void *) pi->p.name); - - kmmint_delist_plugin(pi); - - for(i=0; in_dependants; i++) { - kmm_release_plugin(kmm_handle_from_plugin(pi->dependants[i])); - pi->dependants[i] = NULL; - } - - if(pi->module) { - kmm_release_module(kmm_handle_from_module(pi->module)); - } - - pi->module = NULL; - pi->p.module = NULL; - - if(pi->p.name) - PFREE(pi->p.name); - pi->p.name = NULL; - - if(pi->p.description) - PFREE(pi->p.description); - pi->p.description = NULL; - - if(pi->p.dependencies) - PFREE(pi->p.dependencies); - pi->p.dependencies = NULL; - - 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; - - 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_write_int32(csp_plugin, L"Disabled", !enable))) { - 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; - kmm_plugin_i * pi; - khm_handle csp_plugin; - - if (!info) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_kmm); - if (!kmm_is_plugin(p)) { - rv = KHM_ERROR_INVALID_PARAM; - goto _cleanup; - } - - pi = kmm_plugin_from_handle(p); - - ZeroMemory(info, sizeof(*info)); - - info->reg = pi->p; - info->reg.msg_proc = NULL; - - if (KHM_FAILED(kmm_get_plugin_config(pi->p.name, KHM_PERM_READ, - &csp_plugin))) { - info->failure_count = 0; - *((khm_int64 *)&info->failure_time) = 0; - info->failure_reason = 0; - } else { - if (KHM_FAILED(khc_read_int32(csp_plugin, L"FailureCount", - &info->failure_count))) - info->failure_count = 0; - if (KHM_FAILED(khc_read_int64(csp_plugin, L"FailureTime", - (khm_int64 *) &info->failure_time))) - *((khm_int64 *) &info->failure_time) = 0; - if (KHM_FAILED(khc_read_int32(csp_plugin, L"FailureReason", - &info->failure_reason))) - info->failure_reason = 0; - - khc_close_space(csp_plugin); - } - - info->state = pi->state; - - kmm_hold_plugin(p); - info->h_plugin = p; - - info->flags = (pi->flags & KMM_PLUGIN_FLAG_DISABLED); - - _cleanup: - LeaveCriticalSection(&cs_kmm); - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kmm_release_plugin_info_i(kmm_plugin_info * info) { - khm_int32 rv; - - if (!info || !info->h_plugin) - return KHM_ERROR_INVALID_PARAM; - - rv = kmm_release_plugin(info->h_plugin); - - ZeroMemory(info, sizeof(info)); - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kmm_get_next_plugin(kmm_plugin p, kmm_plugin * p_next) { - khm_int32 rv = KHM_ERROR_SUCCESS; - kmm_plugin_i * pi; - kmm_plugin_i * pi_next = NULL; - kmm_module_i * m; - - EnterCriticalSection(&cs_kmm); - if (p == NULL) { - if (kmm_listed_plugins) - pi_next = kmm_listed_plugins; - else { - for (m = kmm_all_modules; m; m = LNEXT(m)) { - if (m->plugins) { - pi_next = m->plugins; - break; - } - } - } - } else if (kmm_is_plugin(p)) { - pi = kmm_plugin_from_handle(p); - pi_next = LNEXT(pi); - - if (!pi_next) { - /* we have either exhausted the listed plugins or we are - at the end of the module's plugin list */ - if (pi->module) { - m = LNEXT(pi->module); - } else { - m = kmm_all_modules; - } - - for(; m; m = LNEXT(m)) { - if (m->plugins) { - pi_next = m->plugins; - break; - } - } - } - } - - if (pi_next) { - *p_next = kmm_handle_from_plugin(pi_next); - kmm_hold_plugin(*p_next); - } else { - *p_next = NULL; - rv = KHM_ERROR_NOT_FOUND; - } - - LeaveCriticalSection(&cs_kmm); - return rv; -} - -KHMEXP khm_int32 KHMAPI -kmm_release_plugin(kmm_plugin p) -{ - kmm_plugin_i * pi; - - if(!kmm_is_plugin(p)) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_kmm); - pi = kmm_plugin_from_handle(p); - pi->refcount--; - if(pi->refcount == 0) { - kmmint_free_plugin(pi); - } - LeaveCriticalSection(&cs_kmm); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kmm_provide_plugin(kmm_module module, kmm_plugin_reg * plugin) -{ - kmm_module_i * m; - kmm_plugin_i * p; - size_t cb_name = 0; - size_t cb_desc = 0; - size_t cb_dep = 0; - - m = kmm_module_from_handle(module); - - /* can only called when handing init_module() */ - if(m->state != KMM_MODULE_STATE_INIT) - return KHM_ERROR_INVALID_OPERATION; - - if(!plugin || - FAILED(StringCbLength(plugin->name, KMM_MAXCB_NAME - sizeof(wchar_t), - &cb_name)) || - (plugin->description && - FAILED(StringCbLength(plugin->description, - KMM_MAXCB_DESC - sizeof(wchar_t), - &cb_desc))) || - (plugin->dependencies && - KHM_FAILED(multi_string_length_cb(plugin->dependencies, - KMM_MAXCB_DEPS, &cb_dep)))) { - return KHM_ERROR_INVALID_PARAM; - } - - cb_name += sizeof(wchar_t); - cb_desc += sizeof(wchar_t); - - p = kmmint_get_plugin_i(plugin->name); - - /* released below or in kmmint_init_module() */ - kmm_hold_plugin(kmm_handle_from_plugin(p)); - - if(p->state != KMM_PLUGIN_STATE_NONE && - p->state != KMM_PLUGIN_STATE_PLACEHOLDER) - { - kmm_release_plugin(kmm_handle_from_plugin(p)); - return KHM_ERROR_DUPLICATE; - } - - /* released when the plugin quits */ - kmm_hold_module(module); - - p->module = m; - p->p.flags = plugin->flags; - p->p.msg_proc = plugin->msg_proc; - p->p.type = plugin->type; - - if(plugin->description) { - p->p.description = PMALLOC(cb_desc); - StringCbCopy(p->p.description, cb_desc, plugin->description); - } else - p->p.description = NULL; - - if(plugin->dependencies) { - p->p.dependencies = PMALLOC(cb_dep); - multi_string_copy_cb(p->p.dependencies, cb_dep, plugin->dependencies); - } else - p->p.dependencies = NULL; - - p->p.module = p->module->name; - - p->p.icon = plugin->icon; - - p->state = KMM_PLUGIN_STATE_REG; - - kmmint_delist_plugin(p); - EnterCriticalSection(&cs_kmm); - LPUSH(&(m->plugins), p); - p->flags |= KMM_PLUGIN_FLAG_IN_MODLIST; - LeaveCriticalSection(&cs_kmm); - - /* leave the plugin held because it is in the module's plugin list */ - return KHM_ERROR_SUCCESS; -} - +/* + * 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 + +/* Called with no locks held to get a kmm_plugin_i structure + that matches the name. First we look in the hash table, and + if one isn't found, we create an empty one. +*/ + +kmm_plugin_i * +kmmint_get_plugin_i(wchar_t * name) +{ + kmm_plugin_i * p; + size_t cb; + + if(FAILED(StringCbLength(name, KMM_MAXCB_NAME, &cb))) + return NULL; + cb += sizeof(wchar_t); + + EnterCriticalSection(&cs_kmm); + p = (kmm_plugin_i *) hash_lookup(hash_plugins, (void *) name); + + if(p == NULL) { + p = PMALLOC(sizeof(kmm_plugin_i)); + ZeroMemory(p, sizeof(kmm_plugin_i)); + p->magic = KMM_PLUGIN_MAGIC; + p->p.name = PMALLOC(cb); + StringCbCopy(p->p.name, cb, name); + p->state = KMM_PLUGIN_STATE_NONE; + + hash_add(hash_plugins, (void *) p->p.name, (void *) p); + kmmint_list_plugin(p); + } + LeaveCriticalSection(&cs_kmm); + + return p; +} + +kmm_plugin_i * +kmmint_find_plugin_i(wchar_t * name) +{ + kmm_plugin_i * p; + size_t cb; + + if(FAILED(StringCbLength(name, KMM_MAXCB_NAME, &cb))) + return NULL; + + EnterCriticalSection(&cs_kmm); + p = (kmm_plugin_i *) hash_lookup(hash_plugins, (void *) name); + LeaveCriticalSection(&cs_kmm); + + return p; +} + +/* the plugin must be delisted before calling this */ +void +kmmint_list_plugin(kmm_plugin_i * p) +{ + EnterCriticalSection(&cs_kmm); + if((p->flags & KMM_PLUGIN_FLAG_IN_MODLIST) || + (p->flags & KMM_PLUGIN_FLAG_IN_LIST)) + { + RaiseException(2, EXCEPTION_NONCONTINUABLE, 0, NULL); + } + p->flags |= KMM_PLUGIN_FLAG_IN_LIST; + LPUSH(&kmm_listed_plugins, p); + LeaveCriticalSection(&cs_kmm); +} + +void +kmmint_delist_plugin(kmm_plugin_i * p) +{ + EnterCriticalSection(&cs_kmm); + if(p->flags & KMM_PLUGIN_FLAG_IN_LIST) { + p->flags &= ~KMM_PLUGIN_FLAG_IN_LIST; + LDELETE(&kmm_listed_plugins, p); + } + if(p->flags & KMM_PLUGIN_FLAG_IN_MODLIST) { + p->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST; + LDELETE(&(p->module->plugins), p); + } + LeaveCriticalSection(&cs_kmm); +} + +KHMEXP khm_int32 KHMAPI +kmm_hold_plugin(kmm_plugin p) +{ + kmm_plugin_i * pi; + + if(!kmm_is_plugin(p)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_kmm); + pi = kmm_plugin_from_handle(p); + pi->refcount++; + LeaveCriticalSection(&cs_kmm); + + return KHM_ERROR_SUCCESS; +} + +/* called with cs_kmm held */ +void +kmmint_free_plugin(kmm_plugin_i * pi) +{ + int i; + pi->magic = 0; + + hash_del(hash_plugins, (void *) pi->p.name); + + kmmint_delist_plugin(pi); + + for(i=0; in_dependants; i++) { + kmm_release_plugin(kmm_handle_from_plugin(pi->dependants[i])); + pi->dependants[i] = NULL; + } + + if(pi->module) { + kmm_release_module(kmm_handle_from_module(pi->module)); + } + + pi->module = NULL; + pi->p.module = NULL; + + if(pi->p.name) + PFREE(pi->p.name); + pi->p.name = NULL; + + if(pi->p.description) + PFREE(pi->p.description); + pi->p.description = NULL; + + if(pi->p.dependencies) + PFREE(pi->p.dependencies); + pi->p.dependencies = NULL; + + 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; + + 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_write_int32(csp_plugin, L"Disabled", !enable))) { + 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; + kmm_plugin_i * pi; + khm_handle csp_plugin; + + if (!info) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_kmm); + if (!kmm_is_plugin(p)) { + rv = KHM_ERROR_INVALID_PARAM; + goto _cleanup; + } + + pi = kmm_plugin_from_handle(p); + + ZeroMemory(info, sizeof(*info)); + + info->reg = pi->p; + info->reg.msg_proc = NULL; + + if (KHM_FAILED(kmm_get_plugin_config(pi->p.name, KHM_PERM_READ, + &csp_plugin))) { + info->failure_count = 0; + *((khm_int64 *)&info->failure_time) = 0; + info->failure_reason = 0; + } else { + if (KHM_FAILED(khc_read_int32(csp_plugin, L"FailureCount", + &info->failure_count))) + info->failure_count = 0; + if (KHM_FAILED(khc_read_int64(csp_plugin, L"FailureTime", + (khm_int64 *) &info->failure_time))) + *((khm_int64 *) &info->failure_time) = 0; + if (KHM_FAILED(khc_read_int32(csp_plugin, L"FailureReason", + &info->failure_reason))) + info->failure_reason = 0; + + khc_close_space(csp_plugin); + } + + info->state = pi->state; + + kmm_hold_plugin(p); + info->h_plugin = p; + + info->flags = (pi->flags & KMM_PLUGIN_FLAG_DISABLED); + + _cleanup: + LeaveCriticalSection(&cs_kmm); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kmm_release_plugin_info_i(kmm_plugin_info * info) { + khm_int32 rv; + + if (!info || !info->h_plugin) + return KHM_ERROR_INVALID_PARAM; + + rv = kmm_release_plugin(info->h_plugin); + + ZeroMemory(info, sizeof(info)); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kmm_get_next_plugin(kmm_plugin p, kmm_plugin * p_next) { + khm_int32 rv = KHM_ERROR_SUCCESS; + kmm_plugin_i * pi; + kmm_plugin_i * pi_next = NULL; + kmm_module_i * m; + + EnterCriticalSection(&cs_kmm); + if (p == NULL) { + if (kmm_listed_plugins) + pi_next = kmm_listed_plugins; + else { + for (m = kmm_all_modules; m; m = LNEXT(m)) { + if (m->plugins) { + pi_next = m->plugins; + break; + } + } + } + } else if (kmm_is_plugin(p)) { + pi = kmm_plugin_from_handle(p); + pi_next = LNEXT(pi); + + if (!pi_next) { + /* we have either exhausted the listed plugins or we are + at the end of the module's plugin list */ + if (pi->module) { + m = LNEXT(pi->module); + } else { + m = kmm_all_modules; + } + + for(; m; m = LNEXT(m)) { + if (m->plugins) { + pi_next = m->plugins; + break; + } + } + } + } + + if (pi_next) { + *p_next = kmm_handle_from_plugin(pi_next); + kmm_hold_plugin(*p_next); + } else { + *p_next = NULL; + rv = KHM_ERROR_NOT_FOUND; + } + + LeaveCriticalSection(&cs_kmm); + return rv; +} + +KHMEXP khm_int32 KHMAPI +kmm_release_plugin(kmm_plugin p) +{ + kmm_plugin_i * pi; + + if(!kmm_is_plugin(p)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_kmm); + pi = kmm_plugin_from_handle(p); + pi->refcount--; + if(pi->refcount == 0) { + kmmint_free_plugin(pi); + } + LeaveCriticalSection(&cs_kmm); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kmm_provide_plugin(kmm_module module, kmm_plugin_reg * plugin) +{ + kmm_module_i * m; + kmm_plugin_i * p; + size_t cb_name = 0; + size_t cb_desc = 0; + size_t cb_dep = 0; + + m = kmm_module_from_handle(module); + + /* can only called when handing init_module() */ + if(m->state != KMM_MODULE_STATE_INIT) + return KHM_ERROR_INVALID_OPERATION; + + if(!plugin || + FAILED(StringCbLength(plugin->name, KMM_MAXCB_NAME - sizeof(wchar_t), + &cb_name)) || + (plugin->description && + FAILED(StringCbLength(plugin->description, + KMM_MAXCB_DESC - sizeof(wchar_t), + &cb_desc))) || + (plugin->dependencies && + KHM_FAILED(multi_string_length_cb(plugin->dependencies, + KMM_MAXCB_DEPS, &cb_dep)))) { + return KHM_ERROR_INVALID_PARAM; + } + + cb_name += sizeof(wchar_t); + cb_desc += sizeof(wchar_t); + + p = kmmint_get_plugin_i(plugin->name); + + /* released below or in kmmint_init_module() */ + kmm_hold_plugin(kmm_handle_from_plugin(p)); + + if(p->state != KMM_PLUGIN_STATE_NONE && + p->state != KMM_PLUGIN_STATE_PLACEHOLDER) + { + kmm_release_plugin(kmm_handle_from_plugin(p)); + return KHM_ERROR_DUPLICATE; + } + + /* released when the plugin quits */ + kmm_hold_module(module); + + p->module = m; + p->p.flags = plugin->flags; + p->p.msg_proc = plugin->msg_proc; + p->p.type = plugin->type; + + if(plugin->description) { + p->p.description = PMALLOC(cb_desc); + StringCbCopy(p->p.description, cb_desc, plugin->description); + } else + p->p.description = NULL; + + if(plugin->dependencies) { + p->p.dependencies = PMALLOC(cb_dep); + multi_string_copy_cb(p->p.dependencies, cb_dep, plugin->dependencies); + } else + p->p.dependencies = NULL; + + p->p.module = p->module->name; + + p->p.icon = plugin->icon; + + p->state = KMM_PLUGIN_STATE_REG; + + kmmint_delist_plugin(p); + EnterCriticalSection(&cs_kmm); + LPUSH(&(m->plugins), p); + p->flags |= KMM_PLUGIN_FLAG_IN_MODLIST; + LeaveCriticalSection(&cs_kmm); + + /* leave the plugin held because it is in the module's plugin list */ + return KHM_ERROR_SUCCESS; +} + diff --git a/src/windows/identity/kmm/kmm_reg.c b/src/windows/identity/kmm/kmm_reg.c index 60159df37..66354229f 100644 --- a/src/windows/identity/kmm/kmm_reg.c +++ b/src/windows/identity/kmm/kmm_reg.c @@ -1,336 +1,336 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2006 Secure Endpoints Inc. - * - * 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 - -KHMEXP khm_int32 KHMAPI -kmm_get_module_info(wchar_t * module_name, khm_int32 flags, - kmm_module_info * buffer, khm_size * cb_buffer) -{ - /*TODO:Implement this */ - return KHM_ERROR_NOT_IMPLEMENTED; -} - -KHMEXP khm_int32 KHMAPI -kmm_get_plugin_info(wchar_t * plugin_name, - kmm_plugin_info * buffer, khm_size * cb_buffer) -{ - /*TODO:Implement this */ - return KHM_ERROR_NOT_IMPLEMENTED; -} - -KHMEXP khm_int32 KHMAPI -kmm_get_plugins_config(khm_int32 flags, khm_handle * result) { - khm_handle csp_root; - khm_handle csp_plugins; - khm_int32 rv; - - rv = khc_open_space(KHM_INVALID_HANDLE, KMM_CSNAME_ROOT, flags, &csp_root); - - if(KHM_FAILED(rv)) - return rv; - - rv = khc_open_space(csp_root, KMM_CSNAME_PLUGINS, flags, &csp_plugins); - khc_close_space(csp_root); - - if(KHM_SUCCEEDED(rv)) - *result = csp_plugins; - else - *result = NULL; - - return rv; -} - - -KHMEXP khm_int32 KHMAPI -kmm_get_modules_config(khm_int32 flags, khm_handle * result) { - khm_handle croot; - khm_handle kmm_all_modules; - khm_int32 rv; - - rv = khc_open_space(NULL, KMM_CSNAME_ROOT, flags, &croot); - - if(KHM_FAILED(rv)) - return rv; - - rv = khc_open_space(croot, KMM_CSNAME_MODULES, flags, &kmm_all_modules); - khc_close_space(croot); - - if(KHM_SUCCEEDED(rv)) - *result = kmm_all_modules; - else - *result = NULL; - - return rv; -} - - -KHMEXP khm_int32 KHMAPI -kmm_get_plugin_config(wchar_t * plugin, khm_int32 flags, khm_handle * result) -{ - khm_handle csplugins; - khm_handle csplugin; - khm_int32 rv; - - if(!plugin || wcschr(plugin, L'/') || wcschr(plugin, L'\\')) - return KHM_ERROR_INVALID_PARAM; - - if(KHM_FAILED(kmm_get_plugins_config(flags, &csplugins))) - return KHM_ERROR_UNKNOWN; - - rv = khc_open_space(csplugins, plugin, flags, &csplugin); - *result = csplugin; - - khc_close_space(csplugins); - - return rv; -} - - -KHMEXP khm_int32 KHMAPI -kmm_get_module_config(wchar_t * module, khm_int32 flags, khm_handle * result) -{ - khm_handle csmodules; - khm_handle csmodule; - khm_int32 rv; - - if(!module || wcschr(module, L'/') || wcschr(module, L'\\')) - return KHM_ERROR_INVALID_PARAM; - - if(KHM_FAILED(kmm_get_modules_config(flags, &csmodules))) - return KHM_ERROR_UNKNOWN; - - rv = khc_open_space(csmodules, module, flags, &csmodule); - *result = csmodule; - - khc_close_space(csmodules); - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kmm_register_plugin(kmm_plugin_reg * plugin, khm_int32 config_flags) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - khm_handle csp_plugin = NULL; - khm_handle csp_module = NULL; - size_t cch; - - /* avoid accidently creating the module key if it doesn't exist */ - config_flags &= ~KHM_FLAG_CREATE; - - if((plugin == NULL) || - (plugin->dependencies && - KHM_FAILED(multi_string_length_cch(plugin->dependencies, - KMM_MAXCCH_DEPS, &cch))) || - FAILED(StringCchLength(plugin->module, KMM_MAXCCH_NAME, &cch)) || - (plugin->description && - FAILED(StringCchLength(plugin->description, - KMM_MAXCCH_DESC, &cch))) || - FAILED(StringCchLength(plugin->name, KMM_MAXCCH_NAME, &cch))) - { - return KHM_ERROR_INVALID_PARAM; - } - - /* note that we are retaining the length of the plugin name in - chars in cch */ - cch ++; - -#define CKRV if(KHM_FAILED(rv)) goto _exit - - rv = kmm_get_plugin_config(plugin->name, - config_flags | KHM_FLAG_CREATE, &csp_plugin); - CKRV; - - /* should fail if the module key doesn't exist */ - rv = kmm_get_module_config(plugin->module, config_flags, &csp_module); - CKRV; - - /*TODO: Make sure that the module registration is in the same - config store as the one in which the plugin is going to be - registered */ - - rv = khc_write_string(csp_plugin, L"Module", plugin->module); - CKRV; - if(plugin->description) { - rv = khc_write_string(csp_plugin, L"Description", plugin->description); - CKRV; - } - - if(plugin->dependencies) { - rv = khc_write_multi_string(csp_plugin, L"Dependencies", - plugin->dependencies); - CKRV; - } - - rv = khc_write_int32(csp_plugin, L"Type", plugin->type); - CKRV; - rv = khc_write_int32(csp_plugin, L"Disabled", - !!(plugin->flags & KMM_PLUGIN_FLAG_DISABLED)); - CKRV; - - { - khm_size cb = 0; - wchar_t * pl = NULL; - size_t scb = 0; - - rv = khc_read_multi_string(csp_module, L"PluginList", NULL, &cb); - if(rv != KHM_ERROR_TOO_LONG) { - if (rv == KHM_ERROR_NOT_FOUND) { - - scb = cb = cch * sizeof(wchar_t); - pl = PMALLOC(cb); - multi_string_init(pl, cb); - rv = KHM_ERROR_SUCCESS; - - goto add_plugin_to_list; - - } else { - goto _exit; - } - } - - cb += cch * sizeof(wchar_t); - scb = cb; - - pl = PMALLOC(cb); - - rv = khc_read_multi_string(csp_module, L"PluginList", pl, &cb); - if(KHM_FAILED(rv)) { - if(pl) - PFREE(pl); - goto _exit; - } - - add_plugin_to_list: - - if(!multi_string_find(pl, plugin->name, 0)) { - multi_string_append(pl, &scb, plugin->name); - rv = khc_write_multi_string(csp_module, L"PluginList", pl); - } - - PFREE(pl); - CKRV; - } - -#undef CKRV - -_exit: - if(csp_plugin) - khc_close_space(csp_plugin); - if(csp_module) - khc_close_space(csp_module); - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kmm_register_module(kmm_module_reg * module, khm_int32 config_flags) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - khm_handle csp_module = NULL; - size_t cch; - int i; - - if((module == NULL) || - FAILED(StringCchLength(module->name, KMM_MAXCCH_NAME, &cch)) || - (module->description && - FAILED(StringCchLength(module->description, - KMM_MAXCCH_DESC, &cch))) || - FAILED(StringCchLength(module->path, MAX_PATH, &cch)) || - (module->n_plugins > 0 && module->plugin_reg_info == NULL)) { - return KHM_ERROR_INVALID_PARAM; - } - -#define CKRV if(KHM_FAILED(rv)) goto _exit - - rv = kmm_get_module_config(module->name, config_flags | KHM_FLAG_CREATE, - &csp_module); - CKRV; - - rv = khc_write_string(csp_module, L"ImagePath", module->path); - CKRV; - - rv = khc_write_int32(csp_module, L"Disabled", 0); - CKRV; - - /* FileVersion and ProductVersion will be set when the module - is loaded for the first time */ - - for(i=0; in_plugins; i++) { - rv = kmm_register_plugin(&(module->plugin_reg_info[i]), config_flags); - CKRV; - } - -#undef CKRV -_exit: - if(csp_module) - khc_close_space(csp_module); - - return rv; -} - -KHMEXP khm_int32 KHMAPI -kmm_unregister_plugin(wchar_t * plugin, khm_int32 config_flags) -{ - 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) -{ - 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; -} +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2006 Secure Endpoints Inc. + * + * 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 + +KHMEXP khm_int32 KHMAPI +kmm_get_module_info(wchar_t * module_name, khm_int32 flags, + kmm_module_info * buffer, khm_size * cb_buffer) +{ + /*TODO:Implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} + +KHMEXP khm_int32 KHMAPI +kmm_get_plugin_info(wchar_t * plugin_name, + kmm_plugin_info * buffer, khm_size * cb_buffer) +{ + /*TODO:Implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} + +KHMEXP khm_int32 KHMAPI +kmm_get_plugins_config(khm_int32 flags, khm_handle * result) { + khm_handle csp_root; + khm_handle csp_plugins; + khm_int32 rv; + + rv = khc_open_space(KHM_INVALID_HANDLE, KMM_CSNAME_ROOT, flags, &csp_root); + + if(KHM_FAILED(rv)) + return rv; + + rv = khc_open_space(csp_root, KMM_CSNAME_PLUGINS, flags, &csp_plugins); + khc_close_space(csp_root); + + if(KHM_SUCCEEDED(rv)) + *result = csp_plugins; + else + *result = NULL; + + return rv; +} + + +KHMEXP khm_int32 KHMAPI +kmm_get_modules_config(khm_int32 flags, khm_handle * result) { + khm_handle croot; + khm_handle kmm_all_modules; + khm_int32 rv; + + rv = khc_open_space(NULL, KMM_CSNAME_ROOT, flags, &croot); + + if(KHM_FAILED(rv)) + return rv; + + rv = khc_open_space(croot, KMM_CSNAME_MODULES, flags, &kmm_all_modules); + khc_close_space(croot); + + if(KHM_SUCCEEDED(rv)) + *result = kmm_all_modules; + else + *result = NULL; + + return rv; +} + + +KHMEXP khm_int32 KHMAPI +kmm_get_plugin_config(wchar_t * plugin, khm_int32 flags, khm_handle * result) +{ + khm_handle csplugins; + khm_handle csplugin; + khm_int32 rv; + + if(!plugin || wcschr(plugin, L'/') || wcschr(plugin, L'\\')) + return KHM_ERROR_INVALID_PARAM; + + if(KHM_FAILED(kmm_get_plugins_config(flags, &csplugins))) + return KHM_ERROR_UNKNOWN; + + rv = khc_open_space(csplugins, plugin, flags, &csplugin); + *result = csplugin; + + khc_close_space(csplugins); + + return rv; +} + + +KHMEXP khm_int32 KHMAPI +kmm_get_module_config(wchar_t * module, khm_int32 flags, khm_handle * result) +{ + khm_handle csmodules; + khm_handle csmodule; + khm_int32 rv; + + if(!module || wcschr(module, L'/') || wcschr(module, L'\\')) + return KHM_ERROR_INVALID_PARAM; + + if(KHM_FAILED(kmm_get_modules_config(flags, &csmodules))) + return KHM_ERROR_UNKNOWN; + + rv = khc_open_space(csmodules, module, flags, &csmodule); + *result = csmodule; + + khc_close_space(csmodules); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kmm_register_plugin(kmm_plugin_reg * plugin, khm_int32 config_flags) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_handle csp_plugin = NULL; + khm_handle csp_module = NULL; + size_t cch; + + /* avoid accidently creating the module key if it doesn't exist */ + config_flags &= ~KHM_FLAG_CREATE; + + if((plugin == NULL) || + (plugin->dependencies && + KHM_FAILED(multi_string_length_cch(plugin->dependencies, + KMM_MAXCCH_DEPS, &cch))) || + FAILED(StringCchLength(plugin->module, KMM_MAXCCH_NAME, &cch)) || + (plugin->description && + FAILED(StringCchLength(plugin->description, + KMM_MAXCCH_DESC, &cch))) || + FAILED(StringCchLength(plugin->name, KMM_MAXCCH_NAME, &cch))) + { + return KHM_ERROR_INVALID_PARAM; + } + + /* note that we are retaining the length of the plugin name in + chars in cch */ + cch ++; + +#define CKRV if(KHM_FAILED(rv)) goto _exit + + rv = kmm_get_plugin_config(plugin->name, + config_flags | KHM_FLAG_CREATE, &csp_plugin); + CKRV; + + /* should fail if the module key doesn't exist */ + rv = kmm_get_module_config(plugin->module, config_flags, &csp_module); + CKRV; + + /*TODO: Make sure that the module registration is in the same + config store as the one in which the plugin is going to be + registered */ + + rv = khc_write_string(csp_plugin, L"Module", plugin->module); + CKRV; + if(plugin->description) { + rv = khc_write_string(csp_plugin, L"Description", plugin->description); + CKRV; + } + + if(plugin->dependencies) { + rv = khc_write_multi_string(csp_plugin, L"Dependencies", + plugin->dependencies); + CKRV; + } + + rv = khc_write_int32(csp_plugin, L"Type", plugin->type); + CKRV; + rv = khc_write_int32(csp_plugin, L"Disabled", + !!(plugin->flags & KMM_PLUGIN_FLAG_DISABLED)); + CKRV; + + { + khm_size cb = 0; + wchar_t * pl = NULL; + size_t scb = 0; + + rv = khc_read_multi_string(csp_module, L"PluginList", NULL, &cb); + if(rv != KHM_ERROR_TOO_LONG) { + if (rv == KHM_ERROR_NOT_FOUND) { + + scb = cb = cch * sizeof(wchar_t); + pl = PMALLOC(cb); + multi_string_init(pl, cb); + rv = KHM_ERROR_SUCCESS; + + goto add_plugin_to_list; + + } else { + goto _exit; + } + } + + cb += cch * sizeof(wchar_t); + scb = cb; + + pl = PMALLOC(cb); + + rv = khc_read_multi_string(csp_module, L"PluginList", pl, &cb); + if(KHM_FAILED(rv)) { + if(pl) + PFREE(pl); + goto _exit; + } + + add_plugin_to_list: + + if(!multi_string_find(pl, plugin->name, 0)) { + multi_string_append(pl, &scb, plugin->name); + rv = khc_write_multi_string(csp_module, L"PluginList", pl); + } + + PFREE(pl); + CKRV; + } + +#undef CKRV + +_exit: + if(csp_plugin) + khc_close_space(csp_plugin); + if(csp_module) + khc_close_space(csp_module); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kmm_register_module(kmm_module_reg * module, khm_int32 config_flags) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_handle csp_module = NULL; + size_t cch; + int i; + + if((module == NULL) || + FAILED(StringCchLength(module->name, KMM_MAXCCH_NAME, &cch)) || + (module->description && + FAILED(StringCchLength(module->description, + KMM_MAXCCH_DESC, &cch))) || + FAILED(StringCchLength(module->path, MAX_PATH, &cch)) || + (module->n_plugins > 0 && module->plugin_reg_info == NULL)) { + return KHM_ERROR_INVALID_PARAM; + } + +#define CKRV if(KHM_FAILED(rv)) goto _exit + + rv = kmm_get_module_config(module->name, config_flags | KHM_FLAG_CREATE, + &csp_module); + CKRV; + + rv = khc_write_string(csp_module, L"ImagePath", module->path); + CKRV; + + rv = khc_write_int32(csp_module, L"Disabled", 0); + CKRV; + + /* FileVersion and ProductVersion will be set when the module + is loaded for the first time */ + + for(i=0; in_plugins; i++) { + rv = kmm_register_plugin(&(module->plugin_reg_info[i]), config_flags); + CKRV; + } + +#undef CKRV +_exit: + if(csp_module) + khc_close_space(csp_module); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kmm_unregister_plugin(wchar_t * plugin, khm_int32 config_flags) +{ + 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) +{ + 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 636e8579f..0aa4b425f 100644 --- a/src/windows/identity/kmm/kmm_registrar.c +++ b/src/windows/identity/kmm/kmm_registrar.c @@ -1,1038 +1,1038 @@ -/* - * 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 -#ifdef DEBUG -#include -#endif - -static LONG pending_modules = 0; -static LONG pending_plugins = 0; -static LONG startup_signal = 0; -static BOOL load_done = FALSE; - -void -kmmint_check_completion(void) { - if (pending_modules == 0 && - pending_plugins == 0 && - InterlockedIncrement(&startup_signal) == 1) { - - load_done = TRUE; - - /* TODO: check for orphaned plugins */ - - kmq_post_message(KMSG_KMM, KMSG_KMM_I_DONE, 0, 0); - } -} - -void -kmmint_add_to_module_queue(void) { - InterlockedIncrement(&pending_modules); -} - -void -kmmint_remove_from_module_queue(void) { - - InterlockedDecrement(&pending_modules); - - kmmint_check_completion(); -} - -void -kmmint_add_to_plugin_queue(kmm_plugin_i * plugin) { - EnterCriticalSection(&cs_kmm); - if (!(plugin->flags & KMM_PLUGIN_FLAG_IN_QUEUE)) { - InterlockedIncrement(&pending_plugins); - plugin->flags |= KMM_PLUGIN_FLAG_IN_QUEUE; - } - LeaveCriticalSection(&cs_kmm); -} - -void -kmmint_remove_from_plugin_queue(kmm_plugin_i * plugin) { - EnterCriticalSection(&cs_kmm); - - if (plugin->flags & KMM_PLUGIN_FLAG_IN_QUEUE) { - InterlockedDecrement(&pending_plugins); - plugin->flags &= ~KMM_PLUGIN_FLAG_IN_QUEUE; - } - - LeaveCriticalSection(&cs_kmm); - kmmint_check_completion(); -} - -KHMEXP khm_boolean KHMAPI -kmm_load_pending(void) { - return !load_done; -} - -/*! \internal - \brief Message handler for the registrar thread. */ -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) - return FALSE; - - switch(uparam) { - case KMM_REG_INIT_MODULE: - kmmint_init_module((kmm_module_i *) vparam); - kmm_release_module(kmm_handle_from_module((kmm_module_i *) vparam)); - break; - - case KMM_REG_EXIT_MODULE: - kmmint_exit_module((kmm_module_i *) vparam); - kmm_release_module(kmm_handle_from_module((kmm_module_i *) vparam)); - break; - - case KMM_REG_INIT_PLUGIN: - kmmint_init_plugin((kmm_plugin_i *) vparam); - kmm_release_plugin(kmm_handle_from_plugin((kmm_plugin_i *) vparam)); - break; - - case KMM_REG_EXIT_PLUGIN: - kmmint_exit_plugin((kmm_plugin_i *) vparam); - kmm_release_plugin(kmm_handle_from_plugin((kmm_plugin_i *) vparam)); - break; - } - return TRUE; -} - -/*! \internal - \brief The registrar thread. - - The only thing this function does is to dispatch messages to the - callback routine ( kmmint_reg_cb() ) */ -DWORD WINAPI kmmint_registrar(LPVOID lpParameter) -{ - - PDESCTHREAD(L"KMM Registrar", L"KMM"); - - tid_registrar = GetCurrentThreadId(); - - kmq_subscribe(KMSG_KMM, kmmint_reg_cb); - kmq_subscribe(KMSG_SYSTEM, kmmint_reg_cb); - - SetEvent(evt_startup); - - while(KHM_SUCCEEDED(kmq_dispatch(INFINITE))); - - kmq_unsubscribe(KMSG_KMM, kmmint_reg_cb); - kmq_unsubscribe(KMSG_SYSTEM, kmmint_reg_cb); - - ExitThread(0); - /* not reached */ - return 0; -} - -/*! \internal - \brief Manages a plugin message thread. - - 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 kmmint_plugin_broker(LPVOID lpParameter) -{ - DWORD rv = 0; - kmm_plugin_i * p = (kmm_plugin_i *) lpParameter; - - PDESCTHREAD(p->p.name, L"KMM"); - - _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)); - - 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)); - _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; - } - - /* subscribe to default message classes by plugin type */ - if(p->p.type == KHM_PITYPE_CRED) { - kmq_subscribe(KMSG_SYSTEM, p->p.msg_proc); - kmq_subscribe(KMSG_KCDB, p->p.msg_proc); - kmq_subscribe(KMSG_CRED, p->p.msg_proc); - } else if(p->p.type == KHM_PITYPE_IDENT) { - khm_handle h = NULL; - - kmq_subscribe(KMSG_SYSTEM, p->p.msg_proc); - kmq_subscribe(KMSG_KCDB, p->p.msg_proc); - - kmq_create_subscription(p->p.msg_proc, &h); - kcdb_identity_set_provider(h); - /* kcdb deletes the subscription when it's done with it */ - } else if(p->p.type == KHM_PITYPE_CONFIG) { - /*TODO: subscribe to configuration provider messages here */ - } - - 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); - do { - kmm_plugin_i * pd; - int i; - - for(i=0; i < p->n_dependants; i++) { - pd = p->dependants[i]; - - pd->n_unresolved--; - - if(pd->n_unresolved == 0) { - kmmint_add_to_plugin_queue(pd); - kmm_hold_plugin(kmm_handle_from_plugin(pd)); - kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_INIT_PLUGIN, (void *) pd); - } - } - } while(FALSE); - LeaveCriticalSection(&cs_kmm); - - kmmint_remove_from_plugin_queue(p); - - /* main message loop */ - while(KHM_SUCCEEDED(kmq_dispatch(INFINITE))); - - /* unsubscribe from default message classes by plugin type */ - if(p->p.type == KHM_PITYPE_CRED) { - kmq_unsubscribe(KMSG_SYSTEM, p->p.msg_proc); - kmq_unsubscribe(KMSG_KCDB, p->p.msg_proc); - kmq_unsubscribe(KMSG_CRED, p->p.msg_proc); - } else if (p->p.type == KHM_PITYPE_IDENT) { - kmq_unsubscribe(KMSG_KCDB, p->p.msg_proc); - kmq_unsubscribe(KMSG_SYSTEM, p->p.msg_proc); - kcdb_identity_set_provider(NULL); - } else if(p->p.type == KHM_PITYPE_CONFIG) { - /*TODO: unsubscribe from configuration provider messages here */ - } - - p->p.msg_proc(KMSG_SYSTEM, KMSG_SYSTEM_EXIT, 0, (void *) &(p->p)); - - _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, - KMM_REG_EXIT_PLUGIN, (void *) p); - - TlsSetValue(tls_kmm, (LPVOID) 0); - - ExitThread(rv); - - /* not reached */ - return rv; -} - -/*! \internal - \brief Initialize a 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 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 kmmint_exit_plugin() */ - kmm_hold_plugin(kmm_handle_from_plugin(p)); - - EnterCriticalSection(&cs_kmm); - if(p->state != KMM_PLUGIN_STATE_REG && - p->state != KMM_PLUGIN_STATE_HOLD) - { - LeaveCriticalSection(&cs_kmm); - goto _exit; - } - - _begin_task(0); - _report_mr1(KHERR_NONE, MSG_IP_TASK_DESC, _cstr(p->p.name)); - _describe(); - - if(p->state == KMM_PLUGIN_STATE_HOLD) { - /* if this plugin was held, then we already had a hold - from the initial attempt to start the plugin. Undo - the hold we did a few lines earlier. */ - kmm_release_plugin(kmm_handle_from_plugin(p)); - - /* same for the plugin count for the module. */ -#ifdef DEBUG - assert(p->flags & KMM_PLUGIN_FLAG_IN_MODCOUNT); -#endif - p->module->plugin_count--; - p->flags &= ~KMM_PLUGIN_FLAG_IN_MODCOUNT; - } - - 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))) { - _report_mr0(KHERR_ERROR, MSG_IP_GET_CONFIG); - - p->state = KMM_PLUGIN_STATE_FAIL_UNKNOWN; - goto _exit; - } - - if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin))) { - if(KHM_FAILED(kmm_register_plugin(&(p->p), 0))) { - _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED); - - p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED; - goto _exit; - } - - if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin))) { - _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED); - - p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED; - goto _exit; - } - } - - if (KHM_SUCCEEDED(khc_read_int32(csp_plugin, L"Disabled", &t)) && t) { - p->flags |= KMM_PLUGIN_FLAG_DISABLED; - p->state = KMM_PLUGIN_STATE_FAIL_DISABLED; - goto _exit; - } - -#if 0 - /*TODO: check the failure count and act accordingly */ - if(KHM_SUCCEEDED(khc_read_int32(csp_plugin, L"FailureCount", &t)) && (t > 0)) { - } -#endif - - EnterCriticalSection(&cs_kmm); - - p->n_depends = 0; - p->n_unresolved = 0; - - do { - wchar_t * deps = NULL; - wchar_t * d; - khm_size sz = 0; - - if(khc_read_multi_string(csp_plugin, L"Dependencies", - NULL, &sz) != KHM_ERROR_TOO_LONG) - break; - - deps = PMALLOC(sz); - if(KHM_FAILED(khc_read_multi_string(csp_plugin, L"Dependencies", - deps, &sz))) { - if(deps) - PFREE(deps); - break; - } - - for(d = deps; d && *d; d = multi_string_next(d)) { - kmm_plugin_i * pd; - int i; - - pd = kmmint_get_plugin_i(d); - - if(pd->state == KMM_PLUGIN_STATE_NONE) { - /* the dependant was not previously known */ - pd->state = KMM_PLUGIN_STATE_PLACEHOLDER; - } - - for(i=0; i < pd->n_dependants; i++) { - if(pd->dependants[i] == p) - break; - } - - if(i >= pd->n_dependants) { - if( pd->n_dependants >= KMM_MAX_DEPENDANTS ) { - /*TODO: handle this gracefully */ - RaiseException(1, EXCEPTION_NONCONTINUABLE, 0, NULL); - } - - /* released in kmmint_free_plugin() */ - kmm_hold_plugin(kmm_handle_from_plugin(p)); - pd->dependants[pd->n_dependants] = p; - pd->n_dependants++; - } - - p->n_depends++; - - if(pd->state != KMM_PLUGIN_STATE_RUNNING) { - p->n_unresolved++; - } - } - - if(p->n_unresolved > 0) { - p->state = KMM_PLUGIN_STATE_HOLD; - } - - PFREE(deps); - - } while(FALSE); - -#ifdef DEBUG - assert(!(p->flags & KMM_PLUGIN_FLAG_IN_MODCOUNT)); -#endif - p->flags |= KMM_PLUGIN_FLAG_IN_MODCOUNT; - p->module->plugin_count++; - - LeaveCriticalSection(&cs_kmm); - - if(p->state == KMM_PLUGIN_STATE_HOLD) { - _report_mr1(KHERR_INFO, MSG_IP_HOLD, _dupstr(p->p.name)); - - goto _exit_post; - } - - kmmint_add_to_plugin_queue(p); - - p->ht_thread = CreateThread(NULL, - 0, - kmmint_plugin_broker, - (LPVOID) p, - CREATE_SUSPENDED, - &dummy); - - p->state = KMM_PLUGIN_STATE_INIT; - - ResumeThread(p->ht_thread); - -_exit_post: - if(csp_plugin != NULL) - khc_close_space(csp_plugin); - - if(csp_plugins != NULL) - khc_close_space(csp_plugins); - - _report_mr2(KHERR_INFO, MSG_IP_STATE, - _dupstr(p->p.name), _int32(p->state)); - - _end_task(); - - return; - - /* jump here if an error condition happens before the plugin - broker thread starts and the plugin should be unloaded */ - -_exit: - if(csp_plugin != NULL) - khc_close_space(csp_plugin); - if(csp_plugins != NULL) - khc_close_space(csp_plugins); - - _report_mr2(KHERR_WARNING, MSG_IP_EXITING, - _dupstr(p->p.name), _int32(p->state)); - _end_task(); - - -#ifdef ASYNC_PLUGIN_UNLOAD_ON_FAILURE - - kmm_hold_plugin(kmm_handle_from_plugin(p)); - - kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_PLUGIN, (void *) p); - -#else - - kmmint_exit_plugin(p); - -#endif -} - -/*! \internal - \brief Uninitialize a plugin - - In addition to terminating the thread, and removing p from the - linked list and hashtable, it also frees up p. - - \note Should only be called from the context of the registrar thread. */ -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) { - - 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) { - /* wait for the thread to terminate */ - WaitForSingleObject(p->ht_thread, INFINITE); - p->ht_thread = NULL; - } - - EnterCriticalSection(&cs_kmm); - - /* undo reference count done in kmmint_init_plugin() */ - if(p->flags & KMM_PLUGIN_FLAG_IN_MODCOUNT) { - - np = --(p->module->plugin_count); - p->flags &= ~KMM_PLUGIN_FLAG_IN_MODCOUNT; - - } else { - /* the plugin was not included in the module's plugin_count. - We can't base a decision to unload the module based on this - plugin exiting. */ - 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) { - /* if this is the last plugin to exit, then notify the - registrar that the module should be removed as well */ - kmm_hold_module(kmm_handle_from_module(p->module)); - kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_MODULE, (void *) p->module); - } - - /* release the hold obtained in kmmint_init_plugin() */ - if (release_plugin) - kmm_release_plugin(kmm_handle_from_plugin(p)); -} - -/*! \internal - \brief Initialize a module - - \a m is not in the linked list yet. - - \note Should only be called from the context of the registrar thread. */ -void kmmint_init_module(kmm_module_i * m) { - HMODULE hm; - init_module_t p_init_module; - kmm_plugin_i * pi; - khm_int32 rv; - khm_handle csp_mod = NULL; - khm_handle csp_mods = NULL; - khm_size sz; - khm_int32 i; - - /* error condition handling */ - BOOL exit_module = FALSE; - BOOL release_module = TRUE; - BOOL record_failure = FALSE; - - /* failure handling */ - khm_int32 max_fail_count = 0; - khm_int64 fail_reset_time = 0; - - _begin_task(0); - _report_mr1(KHERR_NONE, MSG_INIT_MODULE, _cstr(m->name)); - _describe(); - - kmm_hold_module(kmm_handle_from_module(m)); - - if(KHM_FAILED(kmm_get_modules_config(0, &csp_mods))) { - _report_mr0(KHERR_ERROR, MSG_IM_GET_CONFIG); - _location(L"kmm_get_modules_config()"); - - m->state = KMM_MODULE_STATE_FAIL_UNKNOWN; - goto _exit; - } - - khc_read_int32(csp_mods, L"ModuleMaxFailureCount", &max_fail_count); - khc_read_int64(csp_mods, L"ModuleFailureCountResetTime", &fail_reset_time); - - /* If the module is not in the pre-init state, we can't - initialize it. */ - if(m->state != KMM_MODULE_STATE_PREINIT) { - _report_mr1(KHERR_INFO, MSG_IM_NOT_PREINIT, _int32(m->state)); - goto _exit; - } - - if(KHM_FAILED(kmm_get_module_config(m->name, 0, &csp_mod))) { - _report_mr0(KHERR_ERROR, MSG_IM_NOT_REGISTERED); - - m->state = KMM_MODULE_STATE_FAIL_NOT_REGISTERED; - goto _exit; - } - - if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"Disabled", &i)) && i) { - _report_mr0(KHERR_INFO, MSG_IM_DISABLED); - - m->state = KMM_MODULE_STATE_FAIL_DISABLED; - goto _exit; - } - - if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"NoUnload", &i)) && i) { - m->flags |= KMM_MODULE_FLAG_NOUNLOAD; - } - - if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"FailureCount", &i))) { - khm_int64 tm; - khm_int64 ct; - FILETIME fct; - khm_int32 last_reason = 0; - - /* reset the failure count if the failure count reset time - period has elapsed */ - tm = 0; - khc_read_int64(csp_mod, L"FailureTime", &tm); - GetSystemTimeAsFileTime(&fct); - - ct = (FtToInt(&fct) - tm) / 10000000i64; - - if(tm > 0 && - ct > fail_reset_time) { - i = 0; - khc_write_int32(csp_mod, L"FailureCount", 0); - khc_write_int64(csp_mod, L"FailureTime", 0); - } - - khc_read_int32(csp_mod, L"FailureReason", &last_reason); - - /* did we exceed the max failure count? However, we ignore - the max failure count if the reason why it didn't load the - last time was because the module wasn't found. */ - if(i > max_fail_count && - last_reason != KMM_MODULE_STATE_FAIL_NOT_FOUND) { - /* failed too many times */ - _report_mr0(KHERR_INFO, MSG_IM_MAX_FAIL); - - m->state = KMM_MODULE_STATE_FAIL_MAX_FAILURE; - goto _exit; - } - } - - if(khc_read_string(csp_mod, L"ImagePath", NULL, &sz) == - KHM_ERROR_TOO_LONG) { - if(m->path) - PFREE(m->path); - m->path = PMALLOC(sz); - khc_read_string(csp_mod, L"ImagePath", m->path, &sz); - } else { - _report_mr0(KHERR_ERROR, MSG_IM_NOT_REGISTERED); - - m->state = KMM_MODULE_STATE_FAIL_NOT_REGISTERED; - goto _exit; - } - - rv = kmmint_read_module_info(m); - - if (KHM_FAILED(rv)) { - if (rv == KHM_ERROR_INCOMPATIBLE) { - _report_mr0(KHERR_ERROR, MSG_IM_INCOMPATIBLE); - - m->state = KMM_MODULE_STATE_FAIL_INCOMPAT; - } else if (rv == KHM_ERROR_NOT_FOUND) { - _report_mr1(KHERR_ERROR, MSG_IM_NOT_FOUND, _dupstr(m->path)); - - m->state = KMM_MODULE_STATE_FAIL_NOT_FOUND; - } else { - _report_mr0(KHERR_ERROR, MSG_IM_INVALID_MODULE); - - m->state = KMM_MODULE_STATE_FAIL_INV_MODULE; - } - goto _exit; - } - - /* check again */ - if(m->state != KMM_MODULE_STATE_PREINIT) { - _report_mr0(KHERR_ERROR, MSG_IM_NOT_PREINIT); - - goto _exit; - } - - /* from this point on, we must record any failure codes */ - record_failure = TRUE; - - hm = LoadLibrary(m->path); - if(!hm) { - m->h_module = NULL; - m->state = KMM_MODULE_STATE_FAIL_NOT_FOUND; - - _report_mr1(KHERR_ERROR, MSG_IM_NOT_FOUND, _dupstr(m->path)); - - goto _exit; - } - - /* 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; - - m->flags |= KMM_MODULE_FLAG_LOADED; - m->h_module = hm; - - /* TODO: check signatures */ - - p_init_module = (init_module_t) GetProcAddress(hm, EXP_INIT_MODULE); - - if(!p_init_module) { - _report_mr1(KHERR_ERROR, MSG_IM_NO_ENTRY, _cstr(EXP_INIT_MODULE)); - - m->state = KMM_MODULE_STATE_FAIL_INVALID; - goto _exit; - } - - m->state = KMM_MODULE_STATE_INIT; - - /* call init_module() */ - rv = (*p_init_module)(kmm_handle_from_module(m)); - - m->flags |= KMM_MODULE_FLAG_INITP; - - if(KHM_FAILED(rv)) { - _report_mr1(KHERR_ERROR, MSG_IM_INIT_FAIL, _int32(rv)); - - m->state = KMM_MODULE_STATE_FAIL_LOAD; - goto _exit; - } - - if(!m->plugins) { - _report_mr0(KHERR_ERROR, MSG_IM_NO_PLUGINS); - - m->state = KMM_MODULE_STATE_FAIL_NO_PLUGINS; - record_failure = FALSE; - goto _exit; - } - - m->state = KMM_MODULE_STATE_INITPLUG; - - do { - LPOP(&(m->plugins), &pi); - if(pi) { - pi->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST; - kmmint_init_plugin(pi); - - /* release the hold obtained in kmm_provide_plugin() */ - kmm_release_plugin(kmm_handle_from_plugin(pi)); - } - } 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; - } - - m->state = KMM_MODULE_STATE_RUNNING; - - exit_module = FALSE; - record_failure = FALSE; - - _exit: - if(csp_mod) { - if(record_failure) { - FILETIME fct; - - i = 0; - khc_read_int32(csp_mod, L"FailureCount", &i); - i++; - khc_write_int32(csp_mod, L"FailureCount", i); - - if(i==1) { /* first fault */ - GetSystemTimeAsFileTime(&fct); - khc_write_int64(csp_mod, L"FailureTime", FtToInt(&fct)); - } - - khc_write_int32(csp_mod, L"FailureReason", m->state); - } - khc_close_space(csp_mod); - } - - if(csp_mods) - khc_close_space(csp_mods); - - _report_mr2(KHERR_INFO, MSG_IM_MOD_STATE, - _dupstr(m->name), _int32(m->state)); - - kmmint_remove_from_module_queue(); - - /* if something went wrong after init_module was called on the - module code, we need to call exit_module */ - if(exit_module) - kmmint_exit_module(m); - - if(release_module) - kmm_release_module(kmm_handle_from_module(m)); - - if (kherr_is_error()) { - kherr_context * c; - kherr_event * err_e = NULL; - kherr_event * warn_e = NULL; - kherr_event * e; - - c = kherr_peek_context(); - err_e = kherr_get_err_event(c); - for(e = kherr_get_first_event(c); - e; - e = kherr_get_next_event(e)) { - if (e != err_e && - e->severity == KHERR_WARNING) { - warn_e = e; - break; - } - } - - kherr_evaluate_event(err_e); - if (warn_e) - kherr_evaluate_event(warn_e); - - kherr_clear_error(); - - e = kherr_report(KHERR_ERROR, - (wchar_t *) MSG_IMERR_TITLE, - KHERR_FACILITY, - NULL, - err_e->long_desc, - ((warn_e)? (wchar_t *)MSG_IMERR_SUGGEST: NULL), - KHERR_FACILITY_ID, - KHERR_SUGGEST_NONE, - _cstr(m->name), - ((warn_e)? _cstr(warn_e->long_desc):_vnull()), - _vnull(),_vnull(), - KHERR_RF_MSG_SHORT_DESC | - ((warn_e)? KHERR_RF_MSG_SUGGEST: 0), - KHERR_HMODULE); - - kherr_evaluate_event(e); - - kherr_release_context(c); - } - - _end_task(); -} - - -/*! \internal - \brief Uninitializes a module - - \note Should only be called from the context of the registrar - thread */ -void kmmint_exit_module(kmm_module_i * m) { - kmm_plugin_i * p; - - /* 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 - kmmint_exit_module(). - - When the last plugin is exited, the plugin management code - automatically signalls the registrar to remove the module. - kmmint_exit_module() gets called again. This is the second - stage, where we call exit_module() for the module and start - unloading everything. - */ - - EnterCriticalSection(&cs_kmm); - - /* get rid of any dangling uninitialized plugins */ - LPOP(&(m->plugins), &p); - while(p) { - p->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST; - kmmint_exit_plugin(p); - - /* release hold from kmm_provide_plugin() */ - kmm_release_plugin(kmm_handle_from_plugin(p)); - - LPOP(&(m->plugins), &p); - } - - if(m->state == KMM_MODULE_STATE_RUNNING) { - int np = 0; - - m->state = KMM_MODULE_STATE_EXITPLUG; - - p = kmm_listed_plugins; - - while(p) { - if(p->module == m && - (p->flags & KMM_PLUGIN_FLAG_IN_MODCOUNT)) { - - kmm_hold_plugin(kmm_handle_from_plugin(p)); - kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, - KMM_REG_EXIT_PLUGIN, (void *) p); - np++; - - } - - p = LNEXT(p); - } - -#ifdef DEBUG - assert(np == m->plugin_count); -#endif - - if(np > 0) { - /* we have to go back and wait for the plugins to exit. - when the last plugin exits, it automatically posts - EXIT_MODULE. We can pick up from there when this - happens. */ - LeaveCriticalSection(&cs_kmm); - return; - } - - } else { - -#ifdef DEBUG - assert(m->plugin_count == 0 || - m->state == KMM_MODULE_STATE_EXITPLUG); -#endif - - /* if there are still plug-ins waiting to be unloaded, then we - have to go back and wait for them to finish. Once they are - done, kmmint_exit_module() will get called again. */ - if (m->plugin_count > 0) { - LeaveCriticalSection(&cs_kmm); - return; - } - } - - if(m->flags & KMM_MODULE_FLAG_INITP) { - exit_module_t p_exit_module; - - if(m->state > 0) - m->state = KMM_MODULE_STATE_EXIT; - - p_exit_module = - (exit_module_t) GetProcAddress(m->h_module, - EXP_EXIT_MODULE); - if(p_exit_module) { - LeaveCriticalSection(&cs_kmm); - (*p_exit_module)(kmm_handle_from_module(m)); - EnterCriticalSection(&cs_kmm); - } - } - - if(m->state > 0) - m->state = KMM_MODULE_STATE_EXITED; - - LeaveCriticalSection(&cs_kmm); - - if(!(m->flags & KMM_MODULE_FLAG_NOUNLOAD) && - m->h_module) { - FreeLibrary(m->h_module); - } - - if(!(m->flags & KMM_MODULE_FLAG_NOUNLOAD) && - m->h_resource && (m->h_resource != m->h_module)) { - FreeLibrary(m->h_resource); - } - - m->h_module = NULL; - m->h_resource = NULL; - - if (m->flags & KMM_MODULE_FLAG_LOADED) { -#ifdef DEBUG - assert(kmm_active_modules > 0); -#endif - kmm_active_modules--; - } - - m->flags = 0; - - /* 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. */ - if (kmm_active_modules == 0) { - SetEvent(evt_exit); - } -} +/* + * 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 +#ifdef DEBUG +#include +#endif + +static LONG pending_modules = 0; +static LONG pending_plugins = 0; +static LONG startup_signal = 0; +static BOOL load_done = FALSE; + +void +kmmint_check_completion(void) { + if (pending_modules == 0 && + pending_plugins == 0 && + InterlockedIncrement(&startup_signal) == 1) { + + load_done = TRUE; + + /* TODO: check for orphaned plugins */ + + kmq_post_message(KMSG_KMM, KMSG_KMM_I_DONE, 0, 0); + } +} + +void +kmmint_add_to_module_queue(void) { + InterlockedIncrement(&pending_modules); +} + +void +kmmint_remove_from_module_queue(void) { + + InterlockedDecrement(&pending_modules); + + kmmint_check_completion(); +} + +void +kmmint_add_to_plugin_queue(kmm_plugin_i * plugin) { + EnterCriticalSection(&cs_kmm); + if (!(plugin->flags & KMM_PLUGIN_FLAG_IN_QUEUE)) { + InterlockedIncrement(&pending_plugins); + plugin->flags |= KMM_PLUGIN_FLAG_IN_QUEUE; + } + LeaveCriticalSection(&cs_kmm); +} + +void +kmmint_remove_from_plugin_queue(kmm_plugin_i * plugin) { + EnterCriticalSection(&cs_kmm); + + if (plugin->flags & KMM_PLUGIN_FLAG_IN_QUEUE) { + InterlockedDecrement(&pending_plugins); + plugin->flags &= ~KMM_PLUGIN_FLAG_IN_QUEUE; + } + + LeaveCriticalSection(&cs_kmm); + kmmint_check_completion(); +} + +KHMEXP khm_boolean KHMAPI +kmm_load_pending(void) { + return !load_done; +} + +/*! \internal + \brief Message handler for the registrar thread. */ +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) + return FALSE; + + switch(uparam) { + case KMM_REG_INIT_MODULE: + kmmint_init_module((kmm_module_i *) vparam); + kmm_release_module(kmm_handle_from_module((kmm_module_i *) vparam)); + break; + + case KMM_REG_EXIT_MODULE: + kmmint_exit_module((kmm_module_i *) vparam); + kmm_release_module(kmm_handle_from_module((kmm_module_i *) vparam)); + break; + + case KMM_REG_INIT_PLUGIN: + kmmint_init_plugin((kmm_plugin_i *) vparam); + kmm_release_plugin(kmm_handle_from_plugin((kmm_plugin_i *) vparam)); + break; + + case KMM_REG_EXIT_PLUGIN: + kmmint_exit_plugin((kmm_plugin_i *) vparam); + kmm_release_plugin(kmm_handle_from_plugin((kmm_plugin_i *) vparam)); + break; + } + return TRUE; +} + +/*! \internal + \brief The registrar thread. + + The only thing this function does is to dispatch messages to the + callback routine ( kmmint_reg_cb() ) */ +DWORD WINAPI kmmint_registrar(LPVOID lpParameter) +{ + + PDESCTHREAD(L"KMM Registrar", L"KMM"); + + tid_registrar = GetCurrentThreadId(); + + kmq_subscribe(KMSG_KMM, kmmint_reg_cb); + kmq_subscribe(KMSG_SYSTEM, kmmint_reg_cb); + + SetEvent(evt_startup); + + while(KHM_SUCCEEDED(kmq_dispatch(INFINITE))); + + kmq_unsubscribe(KMSG_KMM, kmmint_reg_cb); + kmq_unsubscribe(KMSG_SYSTEM, kmmint_reg_cb); + + ExitThread(0); + /* not reached */ + return 0; +} + +/*! \internal + \brief Manages a plugin message thread. + + 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 kmmint_plugin_broker(LPVOID lpParameter) +{ + DWORD rv = 0; + kmm_plugin_i * p = (kmm_plugin_i *) lpParameter; + + PDESCTHREAD(p->p.name, L"KMM"); + + _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)); + + 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)); + _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; + } + + /* subscribe to default message classes by plugin type */ + if(p->p.type == KHM_PITYPE_CRED) { + kmq_subscribe(KMSG_SYSTEM, p->p.msg_proc); + kmq_subscribe(KMSG_KCDB, p->p.msg_proc); + kmq_subscribe(KMSG_CRED, p->p.msg_proc); + } else if(p->p.type == KHM_PITYPE_IDENT) { + khm_handle h = NULL; + + kmq_subscribe(KMSG_SYSTEM, p->p.msg_proc); + kmq_subscribe(KMSG_KCDB, p->p.msg_proc); + + kmq_create_subscription(p->p.msg_proc, &h); + kcdb_identity_set_provider(h); + /* kcdb deletes the subscription when it's done with it */ + } else if(p->p.type == KHM_PITYPE_CONFIG) { + /*TODO: subscribe to configuration provider messages here */ + } + + 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); + do { + kmm_plugin_i * pd; + int i; + + for(i=0; i < p->n_dependants; i++) { + pd = p->dependants[i]; + + pd->n_unresolved--; + + if(pd->n_unresolved == 0) { + kmmint_add_to_plugin_queue(pd); + kmm_hold_plugin(kmm_handle_from_plugin(pd)); + kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_INIT_PLUGIN, (void *) pd); + } + } + } while(FALSE); + LeaveCriticalSection(&cs_kmm); + + kmmint_remove_from_plugin_queue(p); + + /* main message loop */ + while(KHM_SUCCEEDED(kmq_dispatch(INFINITE))); + + /* unsubscribe from default message classes by plugin type */ + if(p->p.type == KHM_PITYPE_CRED) { + kmq_unsubscribe(KMSG_SYSTEM, p->p.msg_proc); + kmq_unsubscribe(KMSG_KCDB, p->p.msg_proc); + kmq_unsubscribe(KMSG_CRED, p->p.msg_proc); + } else if (p->p.type == KHM_PITYPE_IDENT) { + kmq_unsubscribe(KMSG_KCDB, p->p.msg_proc); + kmq_unsubscribe(KMSG_SYSTEM, p->p.msg_proc); + kcdb_identity_set_provider(NULL); + } else if(p->p.type == KHM_PITYPE_CONFIG) { + /*TODO: unsubscribe from configuration provider messages here */ + } + + p->p.msg_proc(KMSG_SYSTEM, KMSG_SYSTEM_EXIT, 0, (void *) &(p->p)); + + _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, + KMM_REG_EXIT_PLUGIN, (void *) p); + + TlsSetValue(tls_kmm, (LPVOID) 0); + + ExitThread(rv); + + /* not reached */ + return rv; +} + +/*! \internal + \brief Initialize a 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 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 kmmint_exit_plugin() */ + kmm_hold_plugin(kmm_handle_from_plugin(p)); + + EnterCriticalSection(&cs_kmm); + if(p->state != KMM_PLUGIN_STATE_REG && + p->state != KMM_PLUGIN_STATE_HOLD) + { + LeaveCriticalSection(&cs_kmm); + goto _exit; + } + + _begin_task(0); + _report_mr1(KHERR_NONE, MSG_IP_TASK_DESC, _cstr(p->p.name)); + _describe(); + + if(p->state == KMM_PLUGIN_STATE_HOLD) { + /* if this plugin was held, then we already had a hold + from the initial attempt to start the plugin. Undo + the hold we did a few lines earlier. */ + kmm_release_plugin(kmm_handle_from_plugin(p)); + + /* same for the plugin count for the module. */ +#ifdef DEBUG + assert(p->flags & KMM_PLUGIN_FLAG_IN_MODCOUNT); +#endif + p->module->plugin_count--; + p->flags &= ~KMM_PLUGIN_FLAG_IN_MODCOUNT; + } + + 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))) { + _report_mr0(KHERR_ERROR, MSG_IP_GET_CONFIG); + + p->state = KMM_PLUGIN_STATE_FAIL_UNKNOWN; + goto _exit; + } + + if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin))) { + if(KHM_FAILED(kmm_register_plugin(&(p->p), 0))) { + _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED); + + p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED; + goto _exit; + } + + if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin))) { + _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED); + + p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED; + goto _exit; + } + } + + if (KHM_SUCCEEDED(khc_read_int32(csp_plugin, L"Disabled", &t)) && t) { + p->flags |= KMM_PLUGIN_FLAG_DISABLED; + p->state = KMM_PLUGIN_STATE_FAIL_DISABLED; + goto _exit; + } + +#if 0 + /*TODO: check the failure count and act accordingly */ + if(KHM_SUCCEEDED(khc_read_int32(csp_plugin, L"FailureCount", &t)) && (t > 0)) { + } +#endif + + EnterCriticalSection(&cs_kmm); + + p->n_depends = 0; + p->n_unresolved = 0; + + do { + wchar_t * deps = NULL; + wchar_t * d; + khm_size sz = 0; + + if(khc_read_multi_string(csp_plugin, L"Dependencies", + NULL, &sz) != KHM_ERROR_TOO_LONG) + break; + + deps = PMALLOC(sz); + if(KHM_FAILED(khc_read_multi_string(csp_plugin, L"Dependencies", + deps, &sz))) { + if(deps) + PFREE(deps); + break; + } + + for(d = deps; d && *d; d = multi_string_next(d)) { + kmm_plugin_i * pd; + int i; + + pd = kmmint_get_plugin_i(d); + + if(pd->state == KMM_PLUGIN_STATE_NONE) { + /* the dependant was not previously known */ + pd->state = KMM_PLUGIN_STATE_PLACEHOLDER; + } + + for(i=0; i < pd->n_dependants; i++) { + if(pd->dependants[i] == p) + break; + } + + if(i >= pd->n_dependants) { + if( pd->n_dependants >= KMM_MAX_DEPENDANTS ) { + /*TODO: handle this gracefully */ + RaiseException(1, EXCEPTION_NONCONTINUABLE, 0, NULL); + } + + /* released in kmmint_free_plugin() */ + kmm_hold_plugin(kmm_handle_from_plugin(p)); + pd->dependants[pd->n_dependants] = p; + pd->n_dependants++; + } + + p->n_depends++; + + if(pd->state != KMM_PLUGIN_STATE_RUNNING) { + p->n_unresolved++; + } + } + + if(p->n_unresolved > 0) { + p->state = KMM_PLUGIN_STATE_HOLD; + } + + PFREE(deps); + + } while(FALSE); + +#ifdef DEBUG + assert(!(p->flags & KMM_PLUGIN_FLAG_IN_MODCOUNT)); +#endif + p->flags |= KMM_PLUGIN_FLAG_IN_MODCOUNT; + p->module->plugin_count++; + + LeaveCriticalSection(&cs_kmm); + + if(p->state == KMM_PLUGIN_STATE_HOLD) { + _report_mr1(KHERR_INFO, MSG_IP_HOLD, _dupstr(p->p.name)); + + goto _exit_post; + } + + kmmint_add_to_plugin_queue(p); + + p->ht_thread = CreateThread(NULL, + 0, + kmmint_plugin_broker, + (LPVOID) p, + CREATE_SUSPENDED, + &dummy); + + p->state = KMM_PLUGIN_STATE_INIT; + + ResumeThread(p->ht_thread); + +_exit_post: + if(csp_plugin != NULL) + khc_close_space(csp_plugin); + + if(csp_plugins != NULL) + khc_close_space(csp_plugins); + + _report_mr2(KHERR_INFO, MSG_IP_STATE, + _dupstr(p->p.name), _int32(p->state)); + + _end_task(); + + return; + + /* jump here if an error condition happens before the plugin + broker thread starts and the plugin should be unloaded */ + +_exit: + if(csp_plugin != NULL) + khc_close_space(csp_plugin); + if(csp_plugins != NULL) + khc_close_space(csp_plugins); + + _report_mr2(KHERR_WARNING, MSG_IP_EXITING, + _dupstr(p->p.name), _int32(p->state)); + _end_task(); + + +#ifdef ASYNC_PLUGIN_UNLOAD_ON_FAILURE + + kmm_hold_plugin(kmm_handle_from_plugin(p)); + + kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_PLUGIN, (void *) p); + +#else + + kmmint_exit_plugin(p); + +#endif +} + +/*! \internal + \brief Uninitialize a plugin + + In addition to terminating the thread, and removing p from the + linked list and hashtable, it also frees up p. + + \note Should only be called from the context of the registrar thread. */ +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) { + + 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) { + /* wait for the thread to terminate */ + WaitForSingleObject(p->ht_thread, INFINITE); + p->ht_thread = NULL; + } + + EnterCriticalSection(&cs_kmm); + + /* undo reference count done in kmmint_init_plugin() */ + if(p->flags & KMM_PLUGIN_FLAG_IN_MODCOUNT) { + + np = --(p->module->plugin_count); + p->flags &= ~KMM_PLUGIN_FLAG_IN_MODCOUNT; + + } else { + /* the plugin was not included in the module's plugin_count. + We can't base a decision to unload the module based on this + plugin exiting. */ + 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) { + /* if this is the last plugin to exit, then notify the + registrar that the module should be removed as well */ + kmm_hold_module(kmm_handle_from_module(p->module)); + kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_MODULE, (void *) p->module); + } + + /* release the hold obtained in kmmint_init_plugin() */ + if (release_plugin) + kmm_release_plugin(kmm_handle_from_plugin(p)); +} + +/*! \internal + \brief Initialize a module + + \a m is not in the linked list yet. + + \note Should only be called from the context of the registrar thread. */ +void kmmint_init_module(kmm_module_i * m) { + HMODULE hm; + init_module_t p_init_module; + kmm_plugin_i * pi; + khm_int32 rv; + khm_handle csp_mod = NULL; + khm_handle csp_mods = NULL; + khm_size sz; + khm_int32 i; + + /* error condition handling */ + BOOL exit_module = FALSE; + BOOL release_module = TRUE; + BOOL record_failure = FALSE; + + /* failure handling */ + khm_int32 max_fail_count = 0; + khm_int64 fail_reset_time = 0; + + _begin_task(0); + _report_mr1(KHERR_NONE, MSG_INIT_MODULE, _cstr(m->name)); + _describe(); + + kmm_hold_module(kmm_handle_from_module(m)); + + if(KHM_FAILED(kmm_get_modules_config(0, &csp_mods))) { + _report_mr0(KHERR_ERROR, MSG_IM_GET_CONFIG); + _location(L"kmm_get_modules_config()"); + + m->state = KMM_MODULE_STATE_FAIL_UNKNOWN; + goto _exit; + } + + khc_read_int32(csp_mods, L"ModuleMaxFailureCount", &max_fail_count); + khc_read_int64(csp_mods, L"ModuleFailureCountResetTime", &fail_reset_time); + + /* If the module is not in the pre-init state, we can't + initialize it. */ + if(m->state != KMM_MODULE_STATE_PREINIT) { + _report_mr1(KHERR_INFO, MSG_IM_NOT_PREINIT, _int32(m->state)); + goto _exit; + } + + if(KHM_FAILED(kmm_get_module_config(m->name, 0, &csp_mod))) { + _report_mr0(KHERR_ERROR, MSG_IM_NOT_REGISTERED); + + m->state = KMM_MODULE_STATE_FAIL_NOT_REGISTERED; + goto _exit; + } + + if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"Disabled", &i)) && i) { + _report_mr0(KHERR_INFO, MSG_IM_DISABLED); + + m->state = KMM_MODULE_STATE_FAIL_DISABLED; + goto _exit; + } + + if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"NoUnload", &i)) && i) { + m->flags |= KMM_MODULE_FLAG_NOUNLOAD; + } + + if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"FailureCount", &i))) { + khm_int64 tm; + khm_int64 ct; + FILETIME fct; + khm_int32 last_reason = 0; + + /* reset the failure count if the failure count reset time + period has elapsed */ + tm = 0; + khc_read_int64(csp_mod, L"FailureTime", &tm); + GetSystemTimeAsFileTime(&fct); + + ct = (FtToInt(&fct) - tm) / 10000000i64; + + if(tm > 0 && + ct > fail_reset_time) { + i = 0; + khc_write_int32(csp_mod, L"FailureCount", 0); + khc_write_int64(csp_mod, L"FailureTime", 0); + } + + khc_read_int32(csp_mod, L"FailureReason", &last_reason); + + /* did we exceed the max failure count? However, we ignore + the max failure count if the reason why it didn't load the + last time was because the module wasn't found. */ + if(i > max_fail_count && + last_reason != KMM_MODULE_STATE_FAIL_NOT_FOUND) { + /* failed too many times */ + _report_mr0(KHERR_INFO, MSG_IM_MAX_FAIL); + + m->state = KMM_MODULE_STATE_FAIL_MAX_FAILURE; + goto _exit; + } + } + + if(khc_read_string(csp_mod, L"ImagePath", NULL, &sz) == + KHM_ERROR_TOO_LONG) { + if(m->path) + PFREE(m->path); + m->path = PMALLOC(sz); + khc_read_string(csp_mod, L"ImagePath", m->path, &sz); + } else { + _report_mr0(KHERR_ERROR, MSG_IM_NOT_REGISTERED); + + m->state = KMM_MODULE_STATE_FAIL_NOT_REGISTERED; + goto _exit; + } + + rv = kmmint_read_module_info(m); + + if (KHM_FAILED(rv)) { + if (rv == KHM_ERROR_INCOMPATIBLE) { + _report_mr0(KHERR_ERROR, MSG_IM_INCOMPATIBLE); + + m->state = KMM_MODULE_STATE_FAIL_INCOMPAT; + } else if (rv == KHM_ERROR_NOT_FOUND) { + _report_mr1(KHERR_ERROR, MSG_IM_NOT_FOUND, _dupstr(m->path)); + + m->state = KMM_MODULE_STATE_FAIL_NOT_FOUND; + } else { + _report_mr0(KHERR_ERROR, MSG_IM_INVALID_MODULE); + + m->state = KMM_MODULE_STATE_FAIL_INV_MODULE; + } + goto _exit; + } + + /* check again */ + if(m->state != KMM_MODULE_STATE_PREINIT) { + _report_mr0(KHERR_ERROR, MSG_IM_NOT_PREINIT); + + goto _exit; + } + + /* from this point on, we must record any failure codes */ + record_failure = TRUE; + + hm = LoadLibrary(m->path); + if(!hm) { + m->h_module = NULL; + m->state = KMM_MODULE_STATE_FAIL_NOT_FOUND; + + _report_mr1(KHERR_ERROR, MSG_IM_NOT_FOUND, _dupstr(m->path)); + + goto _exit; + } + + /* 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; + + m->flags |= KMM_MODULE_FLAG_LOADED; + m->h_module = hm; + + /* TODO: check signatures */ + + p_init_module = (init_module_t) GetProcAddress(hm, EXP_INIT_MODULE); + + if(!p_init_module) { + _report_mr1(KHERR_ERROR, MSG_IM_NO_ENTRY, _cstr(EXP_INIT_MODULE)); + + m->state = KMM_MODULE_STATE_FAIL_INVALID; + goto _exit; + } + + m->state = KMM_MODULE_STATE_INIT; + + /* call init_module() */ + rv = (*p_init_module)(kmm_handle_from_module(m)); + + m->flags |= KMM_MODULE_FLAG_INITP; + + if(KHM_FAILED(rv)) { + _report_mr1(KHERR_ERROR, MSG_IM_INIT_FAIL, _int32(rv)); + + m->state = KMM_MODULE_STATE_FAIL_LOAD; + goto _exit; + } + + if(!m->plugins) { + _report_mr0(KHERR_ERROR, MSG_IM_NO_PLUGINS); + + m->state = KMM_MODULE_STATE_FAIL_NO_PLUGINS; + record_failure = FALSE; + goto _exit; + } + + m->state = KMM_MODULE_STATE_INITPLUG; + + do { + LPOP(&(m->plugins), &pi); + if(pi) { + pi->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST; + kmmint_init_plugin(pi); + + /* release the hold obtained in kmm_provide_plugin() */ + kmm_release_plugin(kmm_handle_from_plugin(pi)); + } + } 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; + } + + m->state = KMM_MODULE_STATE_RUNNING; + + exit_module = FALSE; + record_failure = FALSE; + + _exit: + if(csp_mod) { + if(record_failure) { + FILETIME fct; + + i = 0; + khc_read_int32(csp_mod, L"FailureCount", &i); + i++; + khc_write_int32(csp_mod, L"FailureCount", i); + + if(i==1) { /* first fault */ + GetSystemTimeAsFileTime(&fct); + khc_write_int64(csp_mod, L"FailureTime", FtToInt(&fct)); + } + + khc_write_int32(csp_mod, L"FailureReason", m->state); + } + khc_close_space(csp_mod); + } + + if(csp_mods) + khc_close_space(csp_mods); + + _report_mr2(KHERR_INFO, MSG_IM_MOD_STATE, + _dupstr(m->name), _int32(m->state)); + + kmmint_remove_from_module_queue(); + + /* if something went wrong after init_module was called on the + module code, we need to call exit_module */ + if(exit_module) + kmmint_exit_module(m); + + if(release_module) + kmm_release_module(kmm_handle_from_module(m)); + + if (kherr_is_error()) { + kherr_context * c; + kherr_event * err_e = NULL; + kherr_event * warn_e = NULL; + kherr_event * e; + + c = kherr_peek_context(); + err_e = kherr_get_err_event(c); + for(e = kherr_get_first_event(c); + e; + e = kherr_get_next_event(e)) { + if (e != err_e && + e->severity == KHERR_WARNING) { + warn_e = e; + break; + } + } + + kherr_evaluate_event(err_e); + if (warn_e) + kherr_evaluate_event(warn_e); + + kherr_clear_error(); + + e = kherr_report(KHERR_ERROR, + (wchar_t *) MSG_IMERR_TITLE, + KHERR_FACILITY, + NULL, + err_e->long_desc, + ((warn_e)? (wchar_t *)MSG_IMERR_SUGGEST: NULL), + KHERR_FACILITY_ID, + KHERR_SUGGEST_NONE, + _cstr(m->name), + ((warn_e)? _cstr(warn_e->long_desc):_vnull()), + _vnull(),_vnull(), + KHERR_RF_MSG_SHORT_DESC | + ((warn_e)? KHERR_RF_MSG_SUGGEST: 0), + KHERR_HMODULE); + + kherr_evaluate_event(e); + + kherr_release_context(c); + } + + _end_task(); +} + + +/*! \internal + \brief Uninitializes a module + + \note Should only be called from the context of the registrar + thread */ +void kmmint_exit_module(kmm_module_i * m) { + kmm_plugin_i * p; + + /* 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 + kmmint_exit_module(). + + When the last plugin is exited, the plugin management code + automatically signalls the registrar to remove the module. + kmmint_exit_module() gets called again. This is the second + stage, where we call exit_module() for the module and start + unloading everything. + */ + + EnterCriticalSection(&cs_kmm); + + /* get rid of any dangling uninitialized plugins */ + LPOP(&(m->plugins), &p); + while(p) { + p->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST; + kmmint_exit_plugin(p); + + /* release hold from kmm_provide_plugin() */ + kmm_release_plugin(kmm_handle_from_plugin(p)); + + LPOP(&(m->plugins), &p); + } + + if(m->state == KMM_MODULE_STATE_RUNNING) { + int np = 0; + + m->state = KMM_MODULE_STATE_EXITPLUG; + + p = kmm_listed_plugins; + + while(p) { + if(p->module == m && + (p->flags & KMM_PLUGIN_FLAG_IN_MODCOUNT)) { + + kmm_hold_plugin(kmm_handle_from_plugin(p)); + kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, + KMM_REG_EXIT_PLUGIN, (void *) p); + np++; + + } + + p = LNEXT(p); + } + +#ifdef DEBUG + assert(np == m->plugin_count); +#endif + + if(np > 0) { + /* we have to go back and wait for the plugins to exit. + when the last plugin exits, it automatically posts + EXIT_MODULE. We can pick up from there when this + happens. */ + LeaveCriticalSection(&cs_kmm); + return; + } + + } else { + +#ifdef DEBUG + assert(m->plugin_count == 0 || + m->state == KMM_MODULE_STATE_EXITPLUG); +#endif + + /* if there are still plug-ins waiting to be unloaded, then we + have to go back and wait for them to finish. Once they are + done, kmmint_exit_module() will get called again. */ + if (m->plugin_count > 0) { + LeaveCriticalSection(&cs_kmm); + return; + } + } + + if(m->flags & KMM_MODULE_FLAG_INITP) { + exit_module_t p_exit_module; + + if(m->state > 0) + m->state = KMM_MODULE_STATE_EXIT; + + p_exit_module = + (exit_module_t) GetProcAddress(m->h_module, + EXP_EXIT_MODULE); + if(p_exit_module) { + LeaveCriticalSection(&cs_kmm); + (*p_exit_module)(kmm_handle_from_module(m)); + EnterCriticalSection(&cs_kmm); + } + } + + if(m->state > 0) + m->state = KMM_MODULE_STATE_EXITED; + + LeaveCriticalSection(&cs_kmm); + + if(!(m->flags & KMM_MODULE_FLAG_NOUNLOAD) && + m->h_module) { + FreeLibrary(m->h_module); + } + + if(!(m->flags & KMM_MODULE_FLAG_NOUNLOAD) && + m->h_resource && (m->h_resource != m->h_module)) { + FreeLibrary(m->h_resource); + } + + m->h_module = NULL; + m->h_resource = NULL; + + if (m->flags & KMM_MODULE_FLAG_LOADED) { +#ifdef DEBUG + assert(kmm_active_modules > 0); +#endif + kmm_active_modules--; + } + + m->flags = 0; + + /* 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. */ + 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 38fce2422..1712e976c 100644 --- a/src/windows/identity/kmm/kmminternal.h +++ b/src/windows/identity/kmm/kmminternal.h @@ -1,258 +1,258 @@ -/* - * 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_KMMINTERNAL_H -#define __KHIMAIRA_KMMINTERNAL_H - -#include -#include -#include - -#define KHERR_FACILITY kmm_facility -#define KHERR_FACILITY_ID KHM_FACILITY_KMM -#define KHERR_HMODULE ((HMODULE) kmm_hInstance) -#include - -#include -#include -#include -#include - -#define NOEXPORT - -#include -#include -#include -#include - -struct kmm_plugin_i_t; /* forward dcl */ - -typedef struct kmm_module_i_t { - khm_int32 magic; - - wchar_t * name; - wchar_t * path; - wchar_t * description; - wchar_t * vendor; - wchar_t * support; - - khm_version file_version; - khm_version prod_version; - - HMODULE h_module; - - HMODULE h_resource; - WORD lcid_resource; - - khm_int32 flags; - khm_int32 state; - khm_int32 plugin_count; /* number of active plugins */ - - void * version_info; - - khm_int32 refcount; - - struct kmm_plugin_i_t * plugins; /* only used for registration */ - - LDCL(struct kmm_module_i_t); -} kmm_module_i; - -#define KMM_MODULE_MAGIC 0x482f4e88 - -#define kmm_is_module(m) ((m) && ((kmm_module_i *)m)->magic == KMM_MODULE_MAGIC) - -#define kmm_module_from_handle(m) ((kmm_module_i *) m) -#define kmm_handle_from_module(m) ((kmm_module) m) - -/* LoadLibrary succeeded for module */ -#define KMM_MODULE_FLAG_LOADED 0x00000001 - -/* init_module entry called */ -#define KMM_MODULE_FLAG_INITP 0x00000002 - -/* the resources have been loaded */ -#define KMM_MODULE_FLAG_RES_LOADED 0x00000008 - -/* the signature has been verified */ -#define KMM_MODULE_FLAG_SIG 0x00000010 - -/* the module is disabled by the user - (option specified in configuration) */ -#define KMM_MODULE_FLAG_DISABLED 0x00000400 - -/* the module should not be unloaded - (option specified in configuration)*/ -#define KMM_MODULE_FLAG_NOUNLOAD 0x00000800 - -/* the module has been removed from the active modules list. */ -#define KMM_MODULE_FLAG_INACTIVE 0x00001000 - -typedef struct kmm_plugin_i_t { - kmm_plugin_reg p; - - khm_int32 magic; - - kmm_module_i * module; - HANDLE ht_thread; - DWORD tid_thread; - - khm_int32 state; - khm_int32 flags; - - int refcount; - - int n_depends; - int n_unresolved; - struct kmm_plugin_i_t * dependants[KMM_MAX_DEPENDANTS]; - int n_dependants; - - LDCL(struct kmm_plugin_i_t); -} kmm_plugin_i; - -#define KMM_PLUGIN_MAGIC 0x320e8fb4 - -#define kmm_is_plugin(p) ((p) && ((kmm_plugin_i *) (p))->magic == KMM_PLUGIN_MAGIC) - -#define kmm_handle_from_plugin(p) ((kmm_plugin) p) -#define kmm_plugin_from_handle(ph) ((kmm_plugin_i *) ph) - -/* the plugin has already been marked for unload */ -#define KMM_PLUGIN_FLAG_UNLOAD 0x00000001 - -/* the plugin is in the kmm_listed_plugins list */ -#define KMM_PLUGIN_FLAG_IN_LIST 0x00000002 - -/* the plugin is in the module's plugin list */ -#define KMM_PLUGIN_FLAG_IN_MODLIST 0x00000004 - -/* the plugin has been included in the pending_plugins count. */ -#define KMM_PLUGIN_FLAG_IN_QUEUE 0x00000010 - -/* the plugin is included in the module's plugin count */ -#define KMM_PLUGIN_FLAG_IN_MODCOUNT 0x00000020 - -/* the plugin is disabled by the user - (option specified in configuration) */ -/* (this is defined in kmm.h) - - #define KMM_PLUGIN_FLAG_DISABLED 0x00000400 - -*/ - -enum kmm_registrar_uparam_t { - KMM_REG_INIT_MODULE, - KMM_REG_EXIT_MODULE, - KMM_REG_INIT_PLUGIN, - KMM_REG_EXIT_PLUGIN -}; - -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; -extern DWORD tls_kmm; - -extern hashtable * hash_plugins; -extern hashtable * hash_modules; - -extern CRITICAL_SECTION cs_kmm; -extern int ready; -extern HANDLE evt_startup; -extern HANDLE evt_exit; -extern const wchar_t * kmm_facility; - -extern HINSTANCE kmm_hInstance; - -extern kconf_schema schema_kmmconfig[]; - -/* Registrar */ - -khm_boolean KHMAPI -kmmint_reg_cb(khm_int32 msg_type, - khm_int32 msg_sub_type, - khm_ui_4 uparam, - void *vparam); - -DWORD WINAPI kmmint_registrar(LPVOID lpParameter); - -DWORD WINAPI kmmint_plugin_broker(LPVOID lpParameter); - -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 * -kmmint_get_module_i(wchar_t * name); - -kmm_module_i * -kmmint_find_module_i(wchar_t * name); - -void -kmmint_free_module(kmm_module_i * m); - -khm_int32 -kmmint_read_module_info(kmm_module_i * m); - -/* Plugins */ -kmm_plugin_i * -kmmint_get_plugin_i(wchar_t * name); - -kmm_plugin_i * -kmmint_find_plugin_i(wchar_t * name); - -void -kmmint_free_plugin(kmm_plugin_i * pi); - -void -kmmint_list_plugin(kmm_plugin_i * p); - -void -kmmint_delist_plugin(kmm_plugin_i * p); - -khm_boolean -kmmint_load_locale_lib(kmm_module_i * m, kmm_module_locale * l); - -#define KMM_CSNAME_ROOT L"PluginManager" -#define KMM_CSNAME_PLUGINS L"Plugins" -#define KMM_CSNAME_MODULES L"Modules" -#define KMM_VALNAME_LOADLIST L"LoadList" - -void -kmmint_add_to_module_queue(void); - -void -kmmint_remove_from_module_queue(void); - -#define _WAIT_FOR_START \ - do { \ - if(ready) break; \ - WaitForSingleObject(evt_startup, INFINITE); \ - } while(0) - -#endif +/* + * 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_KMMINTERNAL_H +#define __KHIMAIRA_KMMINTERNAL_H + +#include +#include +#include + +#define KHERR_FACILITY kmm_facility +#define KHERR_FACILITY_ID KHM_FACILITY_KMM +#define KHERR_HMODULE ((HMODULE) kmm_hInstance) +#include + +#include +#include +#include +#include + +#define NOEXPORT + +#include +#include +#include +#include + +struct kmm_plugin_i_t; /* forward dcl */ + +typedef struct kmm_module_i_t { + khm_int32 magic; + + wchar_t * name; + wchar_t * path; + wchar_t * description; + wchar_t * vendor; + wchar_t * support; + + khm_version file_version; + khm_version prod_version; + + HMODULE h_module; + + HMODULE h_resource; + WORD lcid_resource; + + khm_int32 flags; + khm_int32 state; + khm_int32 plugin_count; /* number of active plugins */ + + void * version_info; + + khm_int32 refcount; + + struct kmm_plugin_i_t * plugins; /* only used for registration */ + + LDCL(struct kmm_module_i_t); +} kmm_module_i; + +#define KMM_MODULE_MAGIC 0x482f4e88 + +#define kmm_is_module(m) ((m) && ((kmm_module_i *)m)->magic == KMM_MODULE_MAGIC) + +#define kmm_module_from_handle(m) ((kmm_module_i *) m) +#define kmm_handle_from_module(m) ((kmm_module) m) + +/* LoadLibrary succeeded for module */ +#define KMM_MODULE_FLAG_LOADED 0x00000001 + +/* init_module entry called */ +#define KMM_MODULE_FLAG_INITP 0x00000002 + +/* the resources have been loaded */ +#define KMM_MODULE_FLAG_RES_LOADED 0x00000008 + +/* the signature has been verified */ +#define KMM_MODULE_FLAG_SIG 0x00000010 + +/* the module is disabled by the user + (option specified in configuration) */ +#define KMM_MODULE_FLAG_DISABLED 0x00000400 + +/* the module should not be unloaded + (option specified in configuration)*/ +#define KMM_MODULE_FLAG_NOUNLOAD 0x00000800 + +/* the module has been removed from the active modules list. */ +#define KMM_MODULE_FLAG_INACTIVE 0x00001000 + +typedef struct kmm_plugin_i_t { + kmm_plugin_reg p; + + khm_int32 magic; + + kmm_module_i * module; + HANDLE ht_thread; + DWORD tid_thread; + + khm_int32 state; + khm_int32 flags; + + int refcount; + + int n_depends; + int n_unresolved; + struct kmm_plugin_i_t * dependants[KMM_MAX_DEPENDANTS]; + int n_dependants; + + LDCL(struct kmm_plugin_i_t); +} kmm_plugin_i; + +#define KMM_PLUGIN_MAGIC 0x320e8fb4 + +#define kmm_is_plugin(p) ((p) && ((kmm_plugin_i *) (p))->magic == KMM_PLUGIN_MAGIC) + +#define kmm_handle_from_plugin(p) ((kmm_plugin) p) +#define kmm_plugin_from_handle(ph) ((kmm_plugin_i *) ph) + +/* the plugin has already been marked for unload */ +#define KMM_PLUGIN_FLAG_UNLOAD 0x00000001 + +/* the plugin is in the kmm_listed_plugins list */ +#define KMM_PLUGIN_FLAG_IN_LIST 0x00000002 + +/* the plugin is in the module's plugin list */ +#define KMM_PLUGIN_FLAG_IN_MODLIST 0x00000004 + +/* the plugin has been included in the pending_plugins count. */ +#define KMM_PLUGIN_FLAG_IN_QUEUE 0x00000010 + +/* the plugin is included in the module's plugin count */ +#define KMM_PLUGIN_FLAG_IN_MODCOUNT 0x00000020 + +/* the plugin is disabled by the user + (option specified in configuration) */ +/* (this is defined in kmm.h) + + #define KMM_PLUGIN_FLAG_DISABLED 0x00000400 + +*/ + +enum kmm_registrar_uparam_t { + KMM_REG_INIT_MODULE, + KMM_REG_EXIT_MODULE, + KMM_REG_INIT_PLUGIN, + KMM_REG_EXIT_PLUGIN +}; + +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; +extern DWORD tls_kmm; + +extern hashtable * hash_plugins; +extern hashtable * hash_modules; + +extern CRITICAL_SECTION cs_kmm; +extern int ready; +extern HANDLE evt_startup; +extern HANDLE evt_exit; +extern const wchar_t * kmm_facility; + +extern HINSTANCE kmm_hInstance; + +extern kconf_schema schema_kmmconfig[]; + +/* Registrar */ + +khm_boolean KHMAPI +kmmint_reg_cb(khm_int32 msg_type, + khm_int32 msg_sub_type, + khm_ui_4 uparam, + void *vparam); + +DWORD WINAPI kmmint_registrar(LPVOID lpParameter); + +DWORD WINAPI kmmint_plugin_broker(LPVOID lpParameter); + +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 * +kmmint_get_module_i(wchar_t * name); + +kmm_module_i * +kmmint_find_module_i(wchar_t * name); + +void +kmmint_free_module(kmm_module_i * m); + +khm_int32 +kmmint_read_module_info(kmm_module_i * m); + +/* Plugins */ +kmm_plugin_i * +kmmint_get_plugin_i(wchar_t * name); + +kmm_plugin_i * +kmmint_find_plugin_i(wchar_t * name); + +void +kmmint_free_plugin(kmm_plugin_i * pi); + +void +kmmint_list_plugin(kmm_plugin_i * p); + +void +kmmint_delist_plugin(kmm_plugin_i * p); + +khm_boolean +kmmint_load_locale_lib(kmm_module_i * m, kmm_module_locale * l); + +#define KMM_CSNAME_ROOT L"PluginManager" +#define KMM_CSNAME_PLUGINS L"Plugins" +#define KMM_CSNAME_MODULES L"Modules" +#define KMM_VALNAME_LOADLIST L"LoadList" + +void +kmmint_add_to_module_queue(void); + +void +kmmint_remove_from_module_queue(void); + +#define _WAIT_FOR_START \ + do { \ + if(ready) break; \ + WaitForSingleObject(evt_startup, INFINITE); \ + } while(0) + +#endif diff --git a/src/windows/identity/kmm/kmmmain.c b/src/windows/identity/kmm/kmmmain.c index aa94a59a1..e54dd6de2 100644 --- a/src/windows/identity/kmm/kmmmain.c +++ b/src/windows/identity/kmm/kmmmain.c @@ -1,159 +1,159 @@ -/* - * 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 - -kmm_module_i * kmm_all_modules = NULL; -kmm_plugin_i * kmm_listed_plugins = NULL; - -HANDLE ht_registrar = NULL; -DWORD tid_registrar = 0; -DWORD tls_kmm = 0; - -#define KMM_HASH_SIZE 31 -hashtable * hash_plugins = NULL; -hashtable * hash_modules = NULL; - -CRITICAL_SECTION cs_kmm; -HANDLE evt_startup = NULL; -HANDLE evt_exit = NULL; -int ready = 0; - -HINSTANCE kmm_hInstance; -const wchar_t * kmm_facility = L"KMM"; - -KHMEXP void KHMAPI kmm_init(void) -{ - DWORD dummy; - - EnterCriticalSection(&cs_kmm); - kmm_all_modules = NULL; - kmm_listed_plugins = NULL; - - tls_kmm = TlsAlloc(); - - hash_plugins = hash_new_hashtable( - KMM_HASH_SIZE, - hash_string, - hash_string_comp, - NULL, - NULL); - - hash_modules = hash_new_hashtable( - KMM_HASH_SIZE, - hash_string, - hash_string_comp, - NULL, - NULL); - - ht_registrar = CreateThread( - NULL, - 0, - kmmint_registrar, - NULL, - 0, - &dummy); - - _WAIT_FOR_START; - - khc_load_schema(NULL, schema_kmmconfig); - - LeaveCriticalSection(&cs_kmm); -} - -KHMEXP void KHMAPI kmm_exit(void) -{ - kmm_module_i * m; - kmm_plugin_i * p; - - EnterCriticalSection(&cs_kmm); - - p = kmm_listed_plugins; - while(p) { - kmm_plugin_i * pn; - - pn = LNEXT(p); - /* plugins that were never resolved should be kicked off the - list. Flipping the refcount will do that if no other - references exist for the plugin. The plugins that were - waiting for unresolved dependencies will automatically get - freed when the placeholders and other plugins get freed. */ - if(p->state == KMM_PLUGIN_STATE_PLACEHOLDER) { - kmm_hold_plugin(kmm_handle_from_plugin(p)); - kmm_release_plugin(kmm_handle_from_plugin(p)); - } - - p = pn; - } - - m = kmm_all_modules; - while(m) { - kmm_unload_module(kmm_handle_from_module(m)); - m = LNEXT(m); - } - - LeaveCriticalSection(&cs_kmm); - WaitForSingleObject(evt_exit, INFINITE); - EnterCriticalSection(&cs_kmm); - - kmq_post_thread_quit_message(tid_registrar, 0, NULL); - - hash_del_hashtable(hash_plugins); - hash_del_hashtable(hash_modules); - - LeaveCriticalSection(&cs_kmm); - - TlsFree(tls_kmm); - - tls_kmm = 0; -} - -void kmm_dll_init(void) -{ - InitializeCriticalSection(&cs_kmm); - evt_startup = CreateEvent(NULL, TRUE, FALSE, NULL); - evt_exit = CreateEvent(NULL, TRUE, TRUE, NULL); -} - -void kmm_dll_exit(void) -{ - DeleteCriticalSection(&cs_kmm); - if(evt_startup) - CloseHandle(evt_startup); - evt_startup = NULL; -} - -void -kmm_process_attach(HINSTANCE hinstDLL) { - kmm_hInstance = hinstDLL; - kmm_dll_init(); -} - -void -kmm_process_detach(void) { - kmm_dll_exit(); -} - +/* + * 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 + +kmm_module_i * kmm_all_modules = NULL; +kmm_plugin_i * kmm_listed_plugins = NULL; + +HANDLE ht_registrar = NULL; +DWORD tid_registrar = 0; +DWORD tls_kmm = 0; + +#define KMM_HASH_SIZE 31 +hashtable * hash_plugins = NULL; +hashtable * hash_modules = NULL; + +CRITICAL_SECTION cs_kmm; +HANDLE evt_startup = NULL; +HANDLE evt_exit = NULL; +int ready = 0; + +HINSTANCE kmm_hInstance; +const wchar_t * kmm_facility = L"KMM"; + +KHMEXP void KHMAPI kmm_init(void) +{ + DWORD dummy; + + EnterCriticalSection(&cs_kmm); + kmm_all_modules = NULL; + kmm_listed_plugins = NULL; + + tls_kmm = TlsAlloc(); + + hash_plugins = hash_new_hashtable( + KMM_HASH_SIZE, + hash_string, + hash_string_comp, + NULL, + NULL); + + hash_modules = hash_new_hashtable( + KMM_HASH_SIZE, + hash_string, + hash_string_comp, + NULL, + NULL); + + ht_registrar = CreateThread( + NULL, + 0, + kmmint_registrar, + NULL, + 0, + &dummy); + + _WAIT_FOR_START; + + khc_load_schema(NULL, schema_kmmconfig); + + LeaveCriticalSection(&cs_kmm); +} + +KHMEXP void KHMAPI kmm_exit(void) +{ + kmm_module_i * m; + kmm_plugin_i * p; + + EnterCriticalSection(&cs_kmm); + + p = kmm_listed_plugins; + while(p) { + kmm_plugin_i * pn; + + pn = LNEXT(p); + /* plugins that were never resolved should be kicked off the + list. Flipping the refcount will do that if no other + references exist for the plugin. The plugins that were + waiting for unresolved dependencies will automatically get + freed when the placeholders and other plugins get freed. */ + if(p->state == KMM_PLUGIN_STATE_PLACEHOLDER) { + kmm_hold_plugin(kmm_handle_from_plugin(p)); + kmm_release_plugin(kmm_handle_from_plugin(p)); + } + + p = pn; + } + + m = kmm_all_modules; + while(m) { + kmm_unload_module(kmm_handle_from_module(m)); + m = LNEXT(m); + } + + LeaveCriticalSection(&cs_kmm); + WaitForSingleObject(evt_exit, INFINITE); + EnterCriticalSection(&cs_kmm); + + kmq_post_thread_quit_message(tid_registrar, 0, NULL); + + hash_del_hashtable(hash_plugins); + hash_del_hashtable(hash_modules); + + LeaveCriticalSection(&cs_kmm); + + TlsFree(tls_kmm); + + tls_kmm = 0; +} + +void kmm_dll_init(void) +{ + InitializeCriticalSection(&cs_kmm); + evt_startup = CreateEvent(NULL, TRUE, FALSE, NULL); + evt_exit = CreateEvent(NULL, TRUE, TRUE, NULL); +} + +void kmm_dll_exit(void) +{ + DeleteCriticalSection(&cs_kmm); + if(evt_startup) + CloseHandle(evt_startup); + evt_startup = NULL; +} + +void +kmm_process_attach(HINSTANCE hinstDLL) { + kmm_hInstance = hinstDLL; + kmm_dll_init(); +} + +void +kmm_process_detach(void) { + kmm_dll_exit(); +} + diff --git a/src/windows/identity/kmm/kplugin.h b/src/windows/identity/kmm/kplugin.h index e4e6003ee..6eb4e13c2 100644 --- a/src/windows/identity/kmm/kplugin.h +++ b/src/windows/identity/kmm/kplugin.h @@ -1,146 +1,146 @@ -/* - * 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_KPLUGIN_H -#define __KHIMAIRA_KPLUGIN_H - -#include -#include - -/*! \addtogroup kmm -@{*/ -/*! \defgroup kplugin NetIDMgr Plugin Callbacks - -See the following related documentation pages for more information -about NetIDMgr plugins. - -These are prototypes of functions that must be implemented by a NetIDMgr -plugin. - -- \ref plugins -@{*/ - -/*! \brief Initialize the module - - This is the first callback function to be called in a module. - Perform all the required intialization when this is called. As - mentioned in \ref plugins, you should not attempt to call any - NetIDMgr API function from DLLMain or other initialization code - other than this one. - - You should use this call back to register the plugins that will be - implemented in this module and to notify the plugin manager of any - resource libraries that this module will use. - - Call: - - kmm_set_locale() : to set the notify the plugin manager of the - locale specifc resource libraries that are used by this module. - - kmm_provide_plugin() : to register each plugin that is - implemented in this module. - - This function is called in the context of the current user, from - the plug-in manager thread. This same thread is used by the - plug-in manager to load and initialize all the modules for a - session. - - The name of the callback must be init_module(). The calling - convention is KHMAPI, which is currently __stdcall. - - If this function does not register any plugins, the plugin manager - will immediately call exit_module() and unload the module even if - the init_module() function completes successfully. - - \return Return the following values to indicate whether the module - successfully initialized or not. - - KHM_ERROR_SUCCESS : Succeeded. The module manager will call - init_plugin() for each of the registered plugins for the - module. - - any other error code: Signals that the module did not - successfully initialize. The plugin manager will - immediately call exit_module() and then unload the module. - - \note This callback is required. -*/ -KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module); - -/*! \brief Type for init_module() */ -typedef khm_int32 (KHMAPI *init_module_t)(kmm_module); - -#if defined(_WIN64) -#define EXP_INIT_MODULE "init_module" -#elif defined(_WIN32) -#define EXP_INIT_MODULE "_init_module@4" -#else -#error EXP_INIT_MODULE not defined for platform -#endif - -/*! \brief Plugin procedure - - This is the message processor for a plugin. See \ref pi_fw_pnm_p - for more information. - - Essentially, this is a message subscriber for KMQ messages. -*/ -KHMEXP khm_int32 KHMAPI _plugin_proc(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam); - -/*! \brief Type for init_plugin() */ -typedef kmq_callback_t _plugin_proc_t; - -/*! \brief Exit a module - - This is the last callback function that the NetIDMgr module - manager calls before unloading the module. When this function is - called, all of the plugins for the module have already been - stopped. However, any localization libraries that were loaded as - a result of init_module() calling kmm_set_locale_info() will still - be loaded. These localization libraries will be unloaded - immediately after this callback returns. - - Use this callback to perform any required cleanup tasks. However, - it is advisable that each plugin perform its own cleanup tasks, - since each plugin may be stopped independently of others. - - \return The return value of this function is ignored. - - \note This callback is not required. -*/ -KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module); - -/*! \brief Type for exit_module() */ -typedef khm_int32 (KHMAPI *exit_module_t)(kmm_module); - -#if defined(_WIN64) -#define EXP_EXIT_MODULE "exit_module" -#elif defined(_WIN32) -#define EXP_EXIT_MODULE "_exit_module@4" -#else -#error EXP_EXIT_MODULE not defined for platform -#endif - -/*@}*/ -/*@}*/ - -#endif +/* + * 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_KPLUGIN_H +#define __KHIMAIRA_KPLUGIN_H + +#include +#include + +/*! \addtogroup kmm +@{*/ +/*! \defgroup kplugin NetIDMgr Plugin Callbacks + +See the following related documentation pages for more information +about NetIDMgr plugins. + +These are prototypes of functions that must be implemented by a NetIDMgr +plugin. + +- \ref plugins +@{*/ + +/*! \brief Initialize the module + + This is the first callback function to be called in a module. + Perform all the required intialization when this is called. As + mentioned in \ref plugins, you should not attempt to call any + NetIDMgr API function from DLLMain or other initialization code + other than this one. + + You should use this call back to register the plugins that will be + implemented in this module and to notify the plugin manager of any + resource libraries that this module will use. + + Call: + - kmm_set_locale() : to set the notify the plugin manager of the + locale specifc resource libraries that are used by this module. + - kmm_provide_plugin() : to register each plugin that is + implemented in this module. + + This function is called in the context of the current user, from + the plug-in manager thread. This same thread is used by the + plug-in manager to load and initialize all the modules for a + session. + + The name of the callback must be init_module(). The calling + convention is KHMAPI, which is currently __stdcall. + + If this function does not register any plugins, the plugin manager + will immediately call exit_module() and unload the module even if + the init_module() function completes successfully. + + \return Return the following values to indicate whether the module + successfully initialized or not. + - KHM_ERROR_SUCCESS : Succeeded. The module manager will call + init_plugin() for each of the registered plugins for the + module. + - any other error code: Signals that the module did not + successfully initialize. The plugin manager will + immediately call exit_module() and then unload the module. + + \note This callback is required. +*/ +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module); + +/*! \brief Type for init_module() */ +typedef khm_int32 (KHMAPI *init_module_t)(kmm_module); + +#if defined(_WIN64) +#define EXP_INIT_MODULE "init_module" +#elif defined(_WIN32) +#define EXP_INIT_MODULE "_init_module@4" +#else +#error EXP_INIT_MODULE not defined for platform +#endif + +/*! \brief Plugin procedure + + This is the message processor for a plugin. See \ref pi_fw_pnm_p + for more information. + + Essentially, this is a message subscriber for KMQ messages. +*/ +KHMEXP khm_int32 KHMAPI _plugin_proc(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam); + +/*! \brief Type for init_plugin() */ +typedef kmq_callback_t _plugin_proc_t; + +/*! \brief Exit a module + + This is the last callback function that the NetIDMgr module + manager calls before unloading the module. When this function is + called, all of the plugins for the module have already been + stopped. However, any localization libraries that were loaded as + a result of init_module() calling kmm_set_locale_info() will still + be loaded. These localization libraries will be unloaded + immediately after this callback returns. + + Use this callback to perform any required cleanup tasks. However, + it is advisable that each plugin perform its own cleanup tasks, + since each plugin may be stopped independently of others. + + \return The return value of this function is ignored. + + \note This callback is not required. +*/ +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module); + +/*! \brief Type for exit_module() */ +typedef khm_int32 (KHMAPI *exit_module_t)(kmm_module); + +#if defined(_WIN64) +#define EXP_EXIT_MODULE "exit_module" +#elif defined(_WIN32) +#define EXP_EXIT_MODULE "_exit_module@4" +#else +#error EXP_EXIT_MODULE not defined for platform +#endif + +/*@}*/ +/*@}*/ + +#endif diff --git a/src/windows/identity/kmq/consumer.c b/src/windows/identity/kmq/consumer.c index d6041779f..32bafec6e 100644 --- a/src/windows/identity/kmq/consumer.c +++ b/src/windows/identity/kmq/consumer.c @@ -1,573 +1,573 @@ -/* - * 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 - -DWORD kmq_tls_queue; - -CRITICAL_SECTION cs_kmq_msg_ref; - -kmq_message_ref * kmq_msg_ref_free = NULL; - -/* ad-hoc subscriptions */ -kmq_msg_subscription * kmq_adhoc_subs = NULL; - -#ifdef DEBUG - -#include - -void -kmqint_dump_consumer(FILE * f) { - kmq_message_ref * r; - kmq_msg_subscription * s; - - int n_free = 0; - int n_adhoc = 0; - - EnterCriticalSection(&cs_kmq_msg_ref); - - fprintf(f, "qc0\t*** Free Message References ***\n"); - - fprintf(f, "qc1\tAddress\n"); - - r = kmq_msg_ref_free; - while(r) { - n_free ++; - - fprintf(f, "qc2\t0x%p\n", r); - - r = LNEXT(r); - } - - fprintf(f, "qc3\tTotal free message references : %d\n", n_free); - - fprintf(f, "qc4\t--- End ---\n"); - - LeaveCriticalSection(&cs_kmq_msg_ref); - - EnterCriticalSection(&cs_kmq_global); - - fprintf(f, "qc5\t*** Adhoc Message Subscriptions ***\n"); - - fprintf(f, "qc6\tAddress\tMsg Type\tRcpt Type\tRcpt\tQueue\n"); - - s = kmq_adhoc_subs; - - while(s) { - n_adhoc ++; - - fprintf(f, "qc7\t0x%p\t%d\t%s\t0x%p\t0x%p\n", - s, - s->type, - (s->rcpt_type == KMQ_RCPTTYPE_CB)?"CALLBACK":"HWND", - (s->rcpt_type == KMQ_RCPTTYPE_CB) ? (void *) s->recipient.cb: (void *) s->recipient.hwnd, - s->queue); - - s = LNEXT(s); - } - - fprintf(f, "qc8\tTotal ad-hoc subscriptions : %d\n", n_adhoc); - - fprintf(f, "qc9\t--- End ---\n"); - - LeaveCriticalSection(&cs_kmq_global); - -} - -#endif - -/*! \internal - \brief Get a message ref object - \note called with cs_kmq_msg_ref held */ -kmq_message_ref * kmqint_get_message_ref(void) { - kmq_message_ref * r; - - LPOP(&kmq_msg_ref_free, &r); - if(!r) { - r = PMALLOC(sizeof(kmq_message_ref)); - } - ZeroMemory(r, sizeof(kmq_message_ref)); - - r->msg = NULL; - r->recipient = NULL; - - return r; -} - -/*! \internal - \brief Free a message ref object - \note called with cs_kmq_msg_ref and cs_kmq_msg held */ -void kmqint_put_message_ref(kmq_message_ref * r) { - if(!r) - return; - if(r->msg) { - r->msg->refcount--; - r->msg = NULL; - } - LPUSH(&kmq_msg_ref_free, r); -} - -/*! \internal - \brief Get the queue associated with the current thread - \note Obtains ::cs_kmq_global - */ -kmq_queue * kmqint_get_thread_queue(void) { - kmq_queue * q; - - q = (kmq_queue *) TlsGetValue(kmq_tls_queue); - if(!q) { - kmqint_attach_this_thread(); - q = (kmq_queue *) TlsGetValue(kmq_tls_queue); - } - - return q; -} - -/*! \internal - \brief Get the topmost message ref for a queue - \note Obtains kmq_queue::cs - */ -void kmqint_get_queue_message_ref(kmq_queue * q, kmq_message_ref ** r) { - EnterCriticalSection(&q->cs); - - if (q->flags & KMQ_QUEUE_FLAG_DELETED) { - *r = NULL; - } else { - QGET(q,r); - if(QTOP(q)) - SetEvent(q->wait_o); - } - - LeaveCriticalSection(&q->cs); -} - -/*! \internal - \brief Post a message to a queue - \note Obtains ::cs_kmq_msg_ref, ::cs_kmq_msg, kmq_queue::cs - */ -void kmqint_post_queue(kmq_queue * q, kmq_message *m) { - kmq_message_ref *r; - - EnterCriticalSection(&q->cs); - if (q->flags & KMQ_QUEUE_FLAG_DELETED) { - LeaveCriticalSection(&q->cs); - return; - } - LeaveCriticalSection(&q->cs); - - EnterCriticalSection(&cs_kmq_msg_ref); - r = kmqint_get_message_ref(); - LeaveCriticalSection(&cs_kmq_msg_ref); - - r->msg = m; - r->recipient = NULL; - - EnterCriticalSection(&cs_kmq_msg); - m->refcount++; - m->nSent++; - LeaveCriticalSection(&cs_kmq_msg); - - EnterCriticalSection(&q->cs); - QPUT(q,r); - SetEvent(q->wait_o); - LeaveCriticalSection(&q->cs); -} - -/*! \internal - \brief Post a message to a subscriber - \note Obtains ::cs_kmq_msg_ref, ::cs_kmq_msg, kmq_queue::cs - \note Should be called with ::cs_kmq_msg held - */ -void kmqint_post(kmq_msg_subscription * s, kmq_message * m, khm_boolean try_send) { - if(s->rcpt_type == KMQ_RCPTTYPE_CB) { - kmq_queue *q; - kmq_message_ref *r; - - q = s->queue; - - if(try_send && q->thread == GetCurrentThreadId()) { - khm_int32 rv; - /* we are sending a message from this thread to this - thread. just call the recipient directly, bypassing - the message queue. */ - m->refcount++; - m->nSent++; - if (IsBadCodePtr(s->recipient.cb)) { - rv = KHM_ERROR_INVALID_OPERATION; - } else { - rv = s->recipient.cb(m->type, m->subtype, - m->uparam, m->vparam); - } - m->refcount--; - if(KHM_SUCCEEDED(rv)) - m->nCompleted++; - else - m->nFailed++; - } else { - - EnterCriticalSection(&q->cs); - if (q->flags & KMQ_QUEUE_FLAG_DELETED) { - LeaveCriticalSection(&q->cs); - return; - } - LeaveCriticalSection(&q->cs); - - EnterCriticalSection(&cs_kmq_msg_ref); - r = kmqint_get_message_ref(); - LeaveCriticalSection(&cs_kmq_msg_ref); - - r->msg = m; - r->recipient = s->recipient.cb; - - m->refcount++; - m->nSent++; - - EnterCriticalSection(&q->cs); - QPUT(q,r); - SetEvent(q->wait_o); - LeaveCriticalSection(&q->cs); - } - } - -#ifdef _WIN32 - else if(s->rcpt_type == KMQ_RCPTTYPE_HWND) { - if(try_send && - GetCurrentThreadId() == GetWindowThreadProcessId(s->recipient.hwnd, - NULL)) { - /* kmqint_post does not know whether there are any other - messages waiting to be posted at this point. Hence, - simply sending the message is not the right thing to do - as the recipient may incorrectly assume that the - message has completed when (m->nCompleted + m->nFailed - == m->nSent). Therefore, we only increment nSent after - the message is sent. */ - - m->refcount++; - - /* the kmq_wm_begin()/kmq_wm_end() and kmq_wm_dispatch() - handlers decrement the reference count on the message - when they are done. */ - SendMessage(s->recipient.hwnd, KMQ_WM_DISPATCH, - m->type, (LPARAM) m); - - m->nSent++; - - } else { - m->nSent++; - m->refcount++; - - /* the kmq_wm_begin()/kmq_wm_end() and kmq_wm_dispatch() - handlers decrement the reference count on the message - when they are done. */ - PostMessage(s->recipient.hwnd, KMQ_WM_DISPATCH, - m->type, (LPARAM) m); - } - } -#endif - - else { - /* This could either be because we were passed in an invalid - subscription or because we lost a race to a thread that - deleted an ad-hoc subscription. */ -#ifdef DEBUG - assert(FALSE); -#endif - } -} - -/*! \internal - \brief Subscribes a window to a message type - \note Obtains ::cs_kmq_types - */ -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; - s->recipient.hwnd = hwnd; - kmqint_msg_type_add_sub(type, s); - - return KHM_ERROR_SUCCESS; -} - -/*! \internal - \note Obtains ::cs_kmq_types, ::cs_kmq_global - */ -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; - s->recipient.cb = cb; - kmqint_msg_type_add_sub(type, s); - - 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 -*/ -KHMEXP khm_int32 KHMAPI kmq_create_subscription(kmq_callback_t cb, - 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 = kmqint_get_thread_queue(); - s->rcpt_type = KMQ_RCPTTYPE_CB; - s->recipient.cb = cb; - - EnterCriticalSection(&cs_kmq_global); - LPUSH(&kmq_adhoc_subs, s); - LeaveCriticalSection(&cs_kmq_global); - - *result = (khm_handle) s; - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI kmq_delete_subscription(khm_handle sub) -{ - kmq_msg_subscription * s; - - s = (kmq_msg_subscription *) sub; - - assert(s->magic == KMQ_MSG_SUB_MAGIC); - - s->type = 0; - - EnterCriticalSection(&cs_kmq_global); - LDELETE(&kmq_adhoc_subs, s); - LeaveCriticalSection(&cs_kmq_global); - - PFREE(s); - - return KHM_ERROR_SUCCESS; -} - -/*! \internal - \brief Unsubscribes a window from a message type - \note Obtains ::cs_kmq_types - */ -KHMEXP khm_int32 KHMAPI kmq_unsubscribe_hwnd(khm_int32 type, HWND hwnd) { - kmq_msg_subscription * s; - - s = kmqint_msg_type_del_sub_hwnd(type, hwnd); - if(s) - PFREE(s); - return (s)?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND; -} - -/*! \internal - \brief Unsubscribe a callback from a message type - \note Obtains ::cs_kmq_types, ::cs_kmq_global - */ -KHMEXP khm_int32 KHMAPI kmq_unsubscribe(khm_int32 type, kmq_callback_t cb) { - kmq_msg_subscription * s; - - s = kmqint_msg_type_del_sub_cb(type,cb); - if(s) - PFREE(s); - - return (s)?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND; -} - -KHMEXP LRESULT KHMAPI kmq_wm_begin(LPARAM lparm, kmq_message ** m) { - *m = (kmq_message *) lparm; - if ((*m)->err_ctx) { - kherr_push_context((*m)->err_ctx); - } - return TRUE; -} - -/*! \internal - \note Obtains ::cs_kmq_msg - */ -KHMEXP LRESULT KHMAPI kmq_wm_end(kmq_message *m, khm_int32 rv) { - if (m->err_ctx) - kherr_pop_context(); - - EnterCriticalSection(&cs_kmq_msg); - m->refcount--; - if(KHM_SUCCEEDED(rv)) - m->nCompleted++; - else - m->nFailed++; - - if(m->nCompleted + m->nFailed == m->nSent) { - kmqint_put_message(m); - } - LeaveCriticalSection(&cs_kmq_msg); - - return TRUE; -} - -/*! \internal - \note Obtains ::cs_kmq_msg - */ -KHMEXP LRESULT KHMAPI kmq_wm_dispatch(LPARAM lparm, kmq_callback_t cb) { - kmq_message *m; - khm_int32 rv; - - m = (kmq_message *) lparm; - - if (m->err_ctx) - kherr_push_context(m->err_ctx); - - rv = cb(m->type, m->subtype, m->uparam, m->vparam); - - if (m->err_ctx) - kherr_pop_context(); - - EnterCriticalSection(&cs_kmq_msg); - - m->refcount--; - if(KHM_SUCCEEDED(rv)) - m->nCompleted++; - else - m->nFailed++; - - if(m->nCompleted + m->nFailed == m->nSent) { - kmqint_put_message(m); - } - LeaveCriticalSection(&cs_kmq_msg); - - return TRUE; -} - -KHMEXP khm_boolean KHMAPI kmq_is_call_aborted(void) { - /* TODO: Implement this */ - return FALSE; -} - -/*! \internal - - \note Obtains ::cs_kmq_global, kmq_queue::cs, ::cs_kmq_msg_ref, ::cs_kmq_msg, -*/ -KHMEXP khm_int32 KHMAPI kmq_dispatch(kmq_timer timeout) { - kmq_queue * q; - kmq_message_ref * r; - kmq_message *m; - DWORD hr; - - q = kmqint_get_thread_queue(); - - assert(q->wait_o); - - hr = WaitForSingleObject(q->wait_o, timeout); - if(hr == WAIT_OBJECT_0) { - /* signalled */ - kmqint_get_queue_message_ref(q, &r); - - m = r->msg; - - if(m->type != KMSG_SYSTEM || m->subtype != KMSG_SYSTEM_EXIT) { - khm_boolean rv; - - if (m->err_ctx) - kherr_push_context(m->err_ctx); - - /* TODO: before dispatching the message, the message being - dispatched for this thread needs to be stored so that - it can be looked up in kmq_is_call_aborted(). This - needs to happen in kmq_wm_dispatch() and - kmq_wm_begin() as well. */ - - /* dispatch */ - rv = r->recipient(m->type, m->subtype, m->uparam, m->vparam); - - if (m->err_ctx) - kherr_pop_context(); - - EnterCriticalSection(&cs_kmq_msg); - EnterCriticalSection(&cs_kmq_msg_ref); - kmqint_put_message_ref(r); - LeaveCriticalSection(&cs_kmq_msg_ref); - - if(KHM_SUCCEEDED(rv)) - m->nCompleted++; - else - m->nFailed++; - - if(m->nCompleted + m->nFailed == m->nSent) { - kmqint_put_message(m); - } - LeaveCriticalSection(&cs_kmq_msg); - - return KHM_ERROR_SUCCESS; - } else { - EnterCriticalSection(&cs_kmq_msg); - EnterCriticalSection(&cs_kmq_msg_ref); - kmqint_put_message_ref(r); - LeaveCriticalSection(&cs_kmq_msg_ref); - m->nCompleted++; - if(m->nCompleted + m->nFailed == m->nSent) { - kmqint_put_message(m); - } - LeaveCriticalSection(&cs_kmq_msg); - - return KHM_ERROR_EXIT; - } - } else { - return KHM_ERROR_TIMEOUT; - } -} - -/* TODO: rename this file to subscriber.c */ +/* + * 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 + +DWORD kmq_tls_queue; + +CRITICAL_SECTION cs_kmq_msg_ref; + +kmq_message_ref * kmq_msg_ref_free = NULL; + +/* ad-hoc subscriptions */ +kmq_msg_subscription * kmq_adhoc_subs = NULL; + +#ifdef DEBUG + +#include + +void +kmqint_dump_consumer(FILE * f) { + kmq_message_ref * r; + kmq_msg_subscription * s; + + int n_free = 0; + int n_adhoc = 0; + + EnterCriticalSection(&cs_kmq_msg_ref); + + fprintf(f, "qc0\t*** Free Message References ***\n"); + + fprintf(f, "qc1\tAddress\n"); + + r = kmq_msg_ref_free; + while(r) { + n_free ++; + + fprintf(f, "qc2\t0x%p\n", r); + + r = LNEXT(r); + } + + fprintf(f, "qc3\tTotal free message references : %d\n", n_free); + + fprintf(f, "qc4\t--- End ---\n"); + + LeaveCriticalSection(&cs_kmq_msg_ref); + + EnterCriticalSection(&cs_kmq_global); + + fprintf(f, "qc5\t*** Adhoc Message Subscriptions ***\n"); + + fprintf(f, "qc6\tAddress\tMsg Type\tRcpt Type\tRcpt\tQueue\n"); + + s = kmq_adhoc_subs; + + while(s) { + n_adhoc ++; + + fprintf(f, "qc7\t0x%p\t%d\t%s\t0x%p\t0x%p\n", + s, + s->type, + (s->rcpt_type == KMQ_RCPTTYPE_CB)?"CALLBACK":"HWND", + (s->rcpt_type == KMQ_RCPTTYPE_CB) ? (void *) s->recipient.cb: (void *) s->recipient.hwnd, + s->queue); + + s = LNEXT(s); + } + + fprintf(f, "qc8\tTotal ad-hoc subscriptions : %d\n", n_adhoc); + + fprintf(f, "qc9\t--- End ---\n"); + + LeaveCriticalSection(&cs_kmq_global); + +} + +#endif + +/*! \internal + \brief Get a message ref object + \note called with cs_kmq_msg_ref held */ +kmq_message_ref * kmqint_get_message_ref(void) { + kmq_message_ref * r; + + LPOP(&kmq_msg_ref_free, &r); + if(!r) { + r = PMALLOC(sizeof(kmq_message_ref)); + } + ZeroMemory(r, sizeof(kmq_message_ref)); + + r->msg = NULL; + r->recipient = NULL; + + return r; +} + +/*! \internal + \brief Free a message ref object + \note called with cs_kmq_msg_ref and cs_kmq_msg held */ +void kmqint_put_message_ref(kmq_message_ref * r) { + if(!r) + return; + if(r->msg) { + r->msg->refcount--; + r->msg = NULL; + } + LPUSH(&kmq_msg_ref_free, r); +} + +/*! \internal + \brief Get the queue associated with the current thread + \note Obtains ::cs_kmq_global + */ +kmq_queue * kmqint_get_thread_queue(void) { + kmq_queue * q; + + q = (kmq_queue *) TlsGetValue(kmq_tls_queue); + if(!q) { + kmqint_attach_this_thread(); + q = (kmq_queue *) TlsGetValue(kmq_tls_queue); + } + + return q; +} + +/*! \internal + \brief Get the topmost message ref for a queue + \note Obtains kmq_queue::cs + */ +void kmqint_get_queue_message_ref(kmq_queue * q, kmq_message_ref ** r) { + EnterCriticalSection(&q->cs); + + if (q->flags & KMQ_QUEUE_FLAG_DELETED) { + *r = NULL; + } else { + QGET(q,r); + if(QTOP(q)) + SetEvent(q->wait_o); + } + + LeaveCriticalSection(&q->cs); +} + +/*! \internal + \brief Post a message to a queue + \note Obtains ::cs_kmq_msg_ref, ::cs_kmq_msg, kmq_queue::cs + */ +void kmqint_post_queue(kmq_queue * q, kmq_message *m) { + kmq_message_ref *r; + + EnterCriticalSection(&q->cs); + if (q->flags & KMQ_QUEUE_FLAG_DELETED) { + LeaveCriticalSection(&q->cs); + return; + } + LeaveCriticalSection(&q->cs); + + EnterCriticalSection(&cs_kmq_msg_ref); + r = kmqint_get_message_ref(); + LeaveCriticalSection(&cs_kmq_msg_ref); + + r->msg = m; + r->recipient = NULL; + + EnterCriticalSection(&cs_kmq_msg); + m->refcount++; + m->nSent++; + LeaveCriticalSection(&cs_kmq_msg); + + EnterCriticalSection(&q->cs); + QPUT(q,r); + SetEvent(q->wait_o); + LeaveCriticalSection(&q->cs); +} + +/*! \internal + \brief Post a message to a subscriber + \note Obtains ::cs_kmq_msg_ref, ::cs_kmq_msg, kmq_queue::cs + \note Should be called with ::cs_kmq_msg held + */ +void kmqint_post(kmq_msg_subscription * s, kmq_message * m, khm_boolean try_send) { + if(s->rcpt_type == KMQ_RCPTTYPE_CB) { + kmq_queue *q; + kmq_message_ref *r; + + q = s->queue; + + if(try_send && q->thread == GetCurrentThreadId()) { + khm_int32 rv; + /* we are sending a message from this thread to this + thread. just call the recipient directly, bypassing + the message queue. */ + m->refcount++; + m->nSent++; + if (IsBadCodePtr(s->recipient.cb)) { + rv = KHM_ERROR_INVALID_OPERATION; + } else { + rv = s->recipient.cb(m->type, m->subtype, + m->uparam, m->vparam); + } + m->refcount--; + if(KHM_SUCCEEDED(rv)) + m->nCompleted++; + else + m->nFailed++; + } else { + + EnterCriticalSection(&q->cs); + if (q->flags & KMQ_QUEUE_FLAG_DELETED) { + LeaveCriticalSection(&q->cs); + return; + } + LeaveCriticalSection(&q->cs); + + EnterCriticalSection(&cs_kmq_msg_ref); + r = kmqint_get_message_ref(); + LeaveCriticalSection(&cs_kmq_msg_ref); + + r->msg = m; + r->recipient = s->recipient.cb; + + m->refcount++; + m->nSent++; + + EnterCriticalSection(&q->cs); + QPUT(q,r); + SetEvent(q->wait_o); + LeaveCriticalSection(&q->cs); + } + } + +#ifdef _WIN32 + else if(s->rcpt_type == KMQ_RCPTTYPE_HWND) { + if(try_send && + GetCurrentThreadId() == GetWindowThreadProcessId(s->recipient.hwnd, + NULL)) { + /* kmqint_post does not know whether there are any other + messages waiting to be posted at this point. Hence, + simply sending the message is not the right thing to do + as the recipient may incorrectly assume that the + message has completed when (m->nCompleted + m->nFailed + == m->nSent). Therefore, we only increment nSent after + the message is sent. */ + + m->refcount++; + + /* the kmq_wm_begin()/kmq_wm_end() and kmq_wm_dispatch() + handlers decrement the reference count on the message + when they are done. */ + SendMessage(s->recipient.hwnd, KMQ_WM_DISPATCH, + m->type, (LPARAM) m); + + m->nSent++; + + } else { + m->nSent++; + m->refcount++; + + /* the kmq_wm_begin()/kmq_wm_end() and kmq_wm_dispatch() + handlers decrement the reference count on the message + when they are done. */ + PostMessage(s->recipient.hwnd, KMQ_WM_DISPATCH, + m->type, (LPARAM) m); + } + } +#endif + + else { + /* This could either be because we were passed in an invalid + subscription or because we lost a race to a thread that + deleted an ad-hoc subscription. */ +#ifdef DEBUG + assert(FALSE); +#endif + } +} + +/*! \internal + \brief Subscribes a window to a message type + \note Obtains ::cs_kmq_types + */ +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; + s->recipient.hwnd = hwnd; + kmqint_msg_type_add_sub(type, s); + + return KHM_ERROR_SUCCESS; +} + +/*! \internal + \note Obtains ::cs_kmq_types, ::cs_kmq_global + */ +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; + s->recipient.cb = cb; + kmqint_msg_type_add_sub(type, s); + + 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 +*/ +KHMEXP khm_int32 KHMAPI kmq_create_subscription(kmq_callback_t cb, + 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 = kmqint_get_thread_queue(); + s->rcpt_type = KMQ_RCPTTYPE_CB; + s->recipient.cb = cb; + + EnterCriticalSection(&cs_kmq_global); + LPUSH(&kmq_adhoc_subs, s); + LeaveCriticalSection(&cs_kmq_global); + + *result = (khm_handle) s; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kmq_delete_subscription(khm_handle sub) +{ + kmq_msg_subscription * s; + + s = (kmq_msg_subscription *) sub; + + assert(s->magic == KMQ_MSG_SUB_MAGIC); + + s->type = 0; + + EnterCriticalSection(&cs_kmq_global); + LDELETE(&kmq_adhoc_subs, s); + LeaveCriticalSection(&cs_kmq_global); + + PFREE(s); + + return KHM_ERROR_SUCCESS; +} + +/*! \internal + \brief Unsubscribes a window from a message type + \note Obtains ::cs_kmq_types + */ +KHMEXP khm_int32 KHMAPI kmq_unsubscribe_hwnd(khm_int32 type, HWND hwnd) { + kmq_msg_subscription * s; + + s = kmqint_msg_type_del_sub_hwnd(type, hwnd); + if(s) + PFREE(s); + return (s)?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND; +} + +/*! \internal + \brief Unsubscribe a callback from a message type + \note Obtains ::cs_kmq_types, ::cs_kmq_global + */ +KHMEXP khm_int32 KHMAPI kmq_unsubscribe(khm_int32 type, kmq_callback_t cb) { + kmq_msg_subscription * s; + + s = kmqint_msg_type_del_sub_cb(type,cb); + if(s) + PFREE(s); + + return (s)?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND; +} + +KHMEXP LRESULT KHMAPI kmq_wm_begin(LPARAM lparm, kmq_message ** m) { + *m = (kmq_message *) lparm; + if ((*m)->err_ctx) { + kherr_push_context((*m)->err_ctx); + } + return TRUE; +} + +/*! \internal + \note Obtains ::cs_kmq_msg + */ +KHMEXP LRESULT KHMAPI kmq_wm_end(kmq_message *m, khm_int32 rv) { + if (m->err_ctx) + kherr_pop_context(); + + EnterCriticalSection(&cs_kmq_msg); + m->refcount--; + if(KHM_SUCCEEDED(rv)) + m->nCompleted++; + else + m->nFailed++; + + if(m->nCompleted + m->nFailed == m->nSent) { + kmqint_put_message(m); + } + LeaveCriticalSection(&cs_kmq_msg); + + return TRUE; +} + +/*! \internal + \note Obtains ::cs_kmq_msg + */ +KHMEXP LRESULT KHMAPI kmq_wm_dispatch(LPARAM lparm, kmq_callback_t cb) { + kmq_message *m; + khm_int32 rv; + + m = (kmq_message *) lparm; + + if (m->err_ctx) + kherr_push_context(m->err_ctx); + + rv = cb(m->type, m->subtype, m->uparam, m->vparam); + + if (m->err_ctx) + kherr_pop_context(); + + EnterCriticalSection(&cs_kmq_msg); + + m->refcount--; + if(KHM_SUCCEEDED(rv)) + m->nCompleted++; + else + m->nFailed++; + + if(m->nCompleted + m->nFailed == m->nSent) { + kmqint_put_message(m); + } + LeaveCriticalSection(&cs_kmq_msg); + + return TRUE; +} + +KHMEXP khm_boolean KHMAPI kmq_is_call_aborted(void) { + /* TODO: Implement this */ + return FALSE; +} + +/*! \internal + + \note Obtains ::cs_kmq_global, kmq_queue::cs, ::cs_kmq_msg_ref, ::cs_kmq_msg, +*/ +KHMEXP khm_int32 KHMAPI kmq_dispatch(kmq_timer timeout) { + kmq_queue * q; + kmq_message_ref * r; + kmq_message *m; + DWORD hr; + + q = kmqint_get_thread_queue(); + + assert(q->wait_o); + + hr = WaitForSingleObject(q->wait_o, timeout); + if(hr == WAIT_OBJECT_0) { + /* signalled */ + kmqint_get_queue_message_ref(q, &r); + + m = r->msg; + + if(m->type != KMSG_SYSTEM || m->subtype != KMSG_SYSTEM_EXIT) { + khm_boolean rv; + + if (m->err_ctx) + kherr_push_context(m->err_ctx); + + /* TODO: before dispatching the message, the message being + dispatched for this thread needs to be stored so that + it can be looked up in kmq_is_call_aborted(). This + needs to happen in kmq_wm_dispatch() and + kmq_wm_begin() as well. */ + + /* dispatch */ + rv = r->recipient(m->type, m->subtype, m->uparam, m->vparam); + + if (m->err_ctx) + kherr_pop_context(); + + EnterCriticalSection(&cs_kmq_msg); + EnterCriticalSection(&cs_kmq_msg_ref); + kmqint_put_message_ref(r); + LeaveCriticalSection(&cs_kmq_msg_ref); + + if(KHM_SUCCEEDED(rv)) + m->nCompleted++; + else + m->nFailed++; + + if(m->nCompleted + m->nFailed == m->nSent) { + kmqint_put_message(m); + } + LeaveCriticalSection(&cs_kmq_msg); + + return KHM_ERROR_SUCCESS; + } else { + EnterCriticalSection(&cs_kmq_msg); + EnterCriticalSection(&cs_kmq_msg_ref); + kmqint_put_message_ref(r); + LeaveCriticalSection(&cs_kmq_msg_ref); + m->nCompleted++; + if(m->nCompleted + m->nFailed == m->nSent) { + kmqint_put_message(m); + } + LeaveCriticalSection(&cs_kmq_msg); + + return KHM_ERROR_EXIT; + } + } else { + return KHM_ERROR_TIMEOUT; + } +} + +/* TODO: rename this file to subscriber.c */ diff --git a/src/windows/identity/kmq/init.c b/src/windows/identity/kmq/init.c index 875e3eaf3..493780f79 100644 --- a/src/windows/identity/kmq/init.c +++ b/src/windows/identity/kmq/init.c @@ -1,313 +1,313 @@ -/* - * 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 - -CRITICAL_SECTION cs_kmq_global; -kmq_timer kmq_queue_dead_timeout; -kmq_timer kmq_call_dead_timeout; - -kmq_queue * queues; - -LONG kmq_init_once = 0; - -void kmqint_init(void) { - khm_handle hconfig = NULL; - - queues = NULL; - - InitializeCriticalSection(&cs_kmq_global); - InitializeCriticalSection(&cs_kmq_msg); - InitializeCriticalSection(&cs_kmq_msg_ref); - - EnterCriticalSection(&cs_kmq_global); - khc_load_schema(NULL, schema_kmqconfig); - khc_open_space(NULL, KMQ_CONF_SPACE_NAME, KHM_PERM_READ, &hconfig); - if(hconfig) { - khm_int32 t = 0; - - khc_read_int32(hconfig, KMQ_CONF_QUEUE_DEAD_TIMEOUT_NAME, &t); - kmq_queue_dead_timeout = t; - - khc_read_int32(hconfig, KMQ_CONF_CALL_DEAD_TIMEOUT_NAME, &t); - kmq_call_dead_timeout = t; - - khc_close_space(hconfig); - } - kmqint_init_msg_types(); - LeaveCriticalSection(&cs_kmq_global); - - kmq_tls_queue = TlsAlloc(); -} - -void kmqint_exit(void) { - EnterCriticalSection(&cs_kmq_global); - kmqint_exit_msg_types(); - LeaveCriticalSection(&cs_kmq_global); - DeleteCriticalSection(&cs_kmq_msg); - DeleteCriticalSection(&cs_kmq_msg_ref); - DeleteCriticalSection(&cs_kmq_global); - - TlsFree(kmq_tls_queue); -} - -/*! \internal - \brief Preps a thread for use with kmq - \note Obtains ::cs_kmq_global - */ -void kmqint_attach_this_thread(void) { - kmq_queue * q; - - EnterCriticalSection(&cs_kmq_global); - - q = (kmq_queue *) TlsGetValue(kmq_tls_queue); - if(!q) { - q = PMALLOC(sizeof(kmq_queue)); - - InitializeCriticalSection(&q->cs); - q->thread = GetCurrentThreadId(); - QINIT(q); - LINIT(q); - 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); -} - -/*! \internal - \brief Detaches the current thread from kmq - \note Obtains ::cs_kmq_global - */ -void kmqint_detach_this_thread(void) { - kmq_queue * q; - - q = (kmq_queue *) TlsGetValue(kmq_tls_queue); - if(q) { - kmq_message_ref * r; - kmq_message * m; - - EnterCriticalSection(&q->cs); - - if (q->flags & KMQ_QUEUE_FLAG_DETACHING) { -#ifdef DEBUG - assert(FALSE); -#endif - LeaveCriticalSection(&q->cs); - return; - } - - q->flags |= KMQ_QUEUE_FLAG_DELETED | KMQ_QUEUE_FLAG_DETACHING; - - QGET(q, &r); - while(r) { - - m = r->msg; - - LeaveCriticalSection(&q->cs); - - EnterCriticalSection(&cs_kmq_msg); - EnterCriticalSection(&cs_kmq_msg_ref); - kmqint_put_message_ref(r); - LeaveCriticalSection(&cs_kmq_msg_ref); - - m->nFailed++; - if(m->nCompleted + m->nFailed == m->nSent) { - kmqint_put_message(m); - } - LeaveCriticalSection(&cs_kmq_msg); - - EnterCriticalSection(&q->cs); - - QGET(q, &r); - } - - CloseHandle(q->wait_o); - - q->wait_o = NULL; - - q->flags &= ~KMQ_QUEUE_FLAG_DETACHING; - - LeaveCriticalSection(&q->cs); - - /* For now, we don't free the queue. */ - - /* TODO: before we can free the queue, we have to go through - all the message type subscriptions and ad-hoc subscriptions - and make sure no subscriptions exist which refer to this - message queue. */ - } -} - -HANDLE kmq_h_compl = NULL; -kmq_thread_id kmq_tid_compl; - -/* Message transfer */ -struct tag_kmq_msg_xfer { - QDCL(kmq_message); -} kmq_completion_xfer; - -HANDLE compl_wx; -BOOL compl_continue; -CRITICAL_SECTION cs_compl; - -DWORD WINAPI kmqint_completion_thread_proc(LPVOID p) { - kmq_message * m; - kherr_context * ctx; - - PDESCTHREAD(L"Msg completion thread", L"KMQ"); - - EnterCriticalSection(&cs_compl); - do { - - if (QTOP(&kmq_completion_xfer) == NULL) { - LeaveCriticalSection(&cs_compl); - WaitForSingleObject(compl_wx, INFINITE); - EnterCriticalSection(&cs_compl); - /* go through the loop again before checking the queue */ - } else { - QGET(&kmq_completion_xfer, &m); - LeaveCriticalSection(&cs_compl); - EnterCriticalSection(&cs_kmq_msg); - - ctx = m->err_ctx; - - if (ctx) - kherr_push_context(ctx); - - kmqint_put_message(m); - - if (ctx) - kherr_pop_context(); - - LeaveCriticalSection(&cs_kmq_msg); - EnterCriticalSection(&cs_compl); - } - - } while(compl_continue); - - LeaveCriticalSection(&cs_compl); - - ExitThread(0); - - /* not reached */ - return 0; -} - -int kmqint_call_completion_handler(kmq_msg_completion_handler h, - kmq_message * m) { - if (h == NULL) - return 0; - - /* We only dispatch to the completion thread if we are not the - completion thread. If calling the completion handler results - in more messages completing, then we just call the completion - handler directly. We also make an exception for completions - that happen before the message queue is properly intiailized. */ - - if (kmq_tid_compl != GetCurrentThreadId() && - kmq_h_compl != NULL) { - - EnterCriticalSection(&cs_compl); - QPUT(&kmq_completion_xfer, m); - SetEvent(compl_wx); - LeaveCriticalSection(&cs_compl); - - return 1; - - } else { - h(m); - - return 0; - } -} - -KHMEXP khm_int32 KHMAPI kmq_init(void) { - if (InterlockedIncrement(&kmq_init_once) == 1) { - EnterCriticalSection(&cs_kmq_global); - - InitializeCriticalSection(&cs_compl); - compl_wx = CreateEvent(NULL, FALSE, FALSE, NULL); - compl_continue = TRUE; - QINIT(&kmq_completion_xfer); - - kmq_h_compl = CreateThread(NULL, - 0, - kmqint_completion_thread_proc, - NULL, - 0, - &kmq_tid_compl); - - assert(kmq_h_compl != NULL); - - LeaveCriticalSection(&cs_kmq_global); - } - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI kmq_exit(void) { - if (InterlockedDecrement(&kmq_init_once) == 0) { - - EnterCriticalSection(&cs_compl); - compl_continue = FALSE; - SetEvent(compl_wx); - LeaveCriticalSection(&cs_compl); - - WaitForSingleObject(kmq_h_compl, INFINITE); - - EnterCriticalSection(&cs_kmq_global); - CloseHandle(kmq_h_compl); - kmq_h_compl = NULL; - kmq_tid_compl = 0; - CloseHandle(compl_wx); - DeleteCriticalSection(&cs_compl); - LeaveCriticalSection(&cs_kmq_global); - } - - return KHM_ERROR_SUCCESS; -} - -#ifdef DEBUG - -void kmqint_dump_consumer(FILE * f); -void kmqint_dump_publisher(FILE * f); - - -KHMEXP void KHMAPI kmqint_dump(FILE * f) { - kmqint_dump_consumer(f); - kmqint_dump_publisher(f); -} - -#endif +/* + * 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 + +CRITICAL_SECTION cs_kmq_global; +kmq_timer kmq_queue_dead_timeout; +kmq_timer kmq_call_dead_timeout; + +kmq_queue * queues; + +LONG kmq_init_once = 0; + +void kmqint_init(void) { + khm_handle hconfig = NULL; + + queues = NULL; + + InitializeCriticalSection(&cs_kmq_global); + InitializeCriticalSection(&cs_kmq_msg); + InitializeCriticalSection(&cs_kmq_msg_ref); + + EnterCriticalSection(&cs_kmq_global); + khc_load_schema(NULL, schema_kmqconfig); + khc_open_space(NULL, KMQ_CONF_SPACE_NAME, KHM_PERM_READ, &hconfig); + if(hconfig) { + khm_int32 t = 0; + + khc_read_int32(hconfig, KMQ_CONF_QUEUE_DEAD_TIMEOUT_NAME, &t); + kmq_queue_dead_timeout = t; + + khc_read_int32(hconfig, KMQ_CONF_CALL_DEAD_TIMEOUT_NAME, &t); + kmq_call_dead_timeout = t; + + khc_close_space(hconfig); + } + kmqint_init_msg_types(); + LeaveCriticalSection(&cs_kmq_global); + + kmq_tls_queue = TlsAlloc(); +} + +void kmqint_exit(void) { + EnterCriticalSection(&cs_kmq_global); + kmqint_exit_msg_types(); + LeaveCriticalSection(&cs_kmq_global); + DeleteCriticalSection(&cs_kmq_msg); + DeleteCriticalSection(&cs_kmq_msg_ref); + DeleteCriticalSection(&cs_kmq_global); + + TlsFree(kmq_tls_queue); +} + +/*! \internal + \brief Preps a thread for use with kmq + \note Obtains ::cs_kmq_global + */ +void kmqint_attach_this_thread(void) { + kmq_queue * q; + + EnterCriticalSection(&cs_kmq_global); + + q = (kmq_queue *) TlsGetValue(kmq_tls_queue); + if(!q) { + q = PMALLOC(sizeof(kmq_queue)); + + InitializeCriticalSection(&q->cs); + q->thread = GetCurrentThreadId(); + QINIT(q); + LINIT(q); + 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); +} + +/*! \internal + \brief Detaches the current thread from kmq + \note Obtains ::cs_kmq_global + */ +void kmqint_detach_this_thread(void) { + kmq_queue * q; + + q = (kmq_queue *) TlsGetValue(kmq_tls_queue); + if(q) { + kmq_message_ref * r; + kmq_message * m; + + EnterCriticalSection(&q->cs); + + if (q->flags & KMQ_QUEUE_FLAG_DETACHING) { +#ifdef DEBUG + assert(FALSE); +#endif + LeaveCriticalSection(&q->cs); + return; + } + + q->flags |= KMQ_QUEUE_FLAG_DELETED | KMQ_QUEUE_FLAG_DETACHING; + + QGET(q, &r); + while(r) { + + m = r->msg; + + LeaveCriticalSection(&q->cs); + + EnterCriticalSection(&cs_kmq_msg); + EnterCriticalSection(&cs_kmq_msg_ref); + kmqint_put_message_ref(r); + LeaveCriticalSection(&cs_kmq_msg_ref); + + m->nFailed++; + if(m->nCompleted + m->nFailed == m->nSent) { + kmqint_put_message(m); + } + LeaveCriticalSection(&cs_kmq_msg); + + EnterCriticalSection(&q->cs); + + QGET(q, &r); + } + + CloseHandle(q->wait_o); + + q->wait_o = NULL; + + q->flags &= ~KMQ_QUEUE_FLAG_DETACHING; + + LeaveCriticalSection(&q->cs); + + /* For now, we don't free the queue. */ + + /* TODO: before we can free the queue, we have to go through + all the message type subscriptions and ad-hoc subscriptions + and make sure no subscriptions exist which refer to this + message queue. */ + } +} + +HANDLE kmq_h_compl = NULL; +kmq_thread_id kmq_tid_compl; + +/* Message transfer */ +struct tag_kmq_msg_xfer { + QDCL(kmq_message); +} kmq_completion_xfer; + +HANDLE compl_wx; +BOOL compl_continue; +CRITICAL_SECTION cs_compl; + +DWORD WINAPI kmqint_completion_thread_proc(LPVOID p) { + kmq_message * m; + kherr_context * ctx; + + PDESCTHREAD(L"Msg completion thread", L"KMQ"); + + EnterCriticalSection(&cs_compl); + do { + + if (QTOP(&kmq_completion_xfer) == NULL) { + LeaveCriticalSection(&cs_compl); + WaitForSingleObject(compl_wx, INFINITE); + EnterCriticalSection(&cs_compl); + /* go through the loop again before checking the queue */ + } else { + QGET(&kmq_completion_xfer, &m); + LeaveCriticalSection(&cs_compl); + EnterCriticalSection(&cs_kmq_msg); + + ctx = m->err_ctx; + + if (ctx) + kherr_push_context(ctx); + + kmqint_put_message(m); + + if (ctx) + kherr_pop_context(); + + LeaveCriticalSection(&cs_kmq_msg); + EnterCriticalSection(&cs_compl); + } + + } while(compl_continue); + + LeaveCriticalSection(&cs_compl); + + ExitThread(0); + + /* not reached */ + return 0; +} + +int kmqint_call_completion_handler(kmq_msg_completion_handler h, + kmq_message * m) { + if (h == NULL) + return 0; + + /* We only dispatch to the completion thread if we are not the + completion thread. If calling the completion handler results + in more messages completing, then we just call the completion + handler directly. We also make an exception for completions + that happen before the message queue is properly intiailized. */ + + if (kmq_tid_compl != GetCurrentThreadId() && + kmq_h_compl != NULL) { + + EnterCriticalSection(&cs_compl); + QPUT(&kmq_completion_xfer, m); + SetEvent(compl_wx); + LeaveCriticalSection(&cs_compl); + + return 1; + + } else { + h(m); + + return 0; + } +} + +KHMEXP khm_int32 KHMAPI kmq_init(void) { + if (InterlockedIncrement(&kmq_init_once) == 1) { + EnterCriticalSection(&cs_kmq_global); + + InitializeCriticalSection(&cs_compl); + compl_wx = CreateEvent(NULL, FALSE, FALSE, NULL); + compl_continue = TRUE; + QINIT(&kmq_completion_xfer); + + kmq_h_compl = CreateThread(NULL, + 0, + kmqint_completion_thread_proc, + NULL, + 0, + &kmq_tid_compl); + + assert(kmq_h_compl != NULL); + + LeaveCriticalSection(&cs_kmq_global); + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kmq_exit(void) { + if (InterlockedDecrement(&kmq_init_once) == 0) { + + EnterCriticalSection(&cs_compl); + compl_continue = FALSE; + SetEvent(compl_wx); + LeaveCriticalSection(&cs_compl); + + WaitForSingleObject(kmq_h_compl, INFINITE); + + EnterCriticalSection(&cs_kmq_global); + CloseHandle(kmq_h_compl); + kmq_h_compl = NULL; + kmq_tid_compl = 0; + CloseHandle(compl_wx); + DeleteCriticalSection(&cs_compl); + LeaveCriticalSection(&cs_kmq_global); + } + + return KHM_ERROR_SUCCESS; +} + +#ifdef DEBUG + +void kmqint_dump_consumer(FILE * f); +void kmqint_dump_publisher(FILE * f); + + +KHMEXP void KHMAPI kmqint_dump(FILE * f) { + kmqint_dump_consumer(f); + kmqint_dump_publisher(f); +} + +#endif diff --git a/src/windows/identity/kmq/kmq.h b/src/windows/identity/kmq/kmq.h index 46ce74f3b..d1a3db3c2 100644 --- a/src/windows/identity/kmq/kmq.h +++ b/src/windows/identity/kmq/kmq.h @@ -1,701 +1,701 @@ -/* - * 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_KMQ_H__ -#define __KHIMAIRA_KMQ_H__ - -/*! \defgroup kmq NetIDMgr Message Queue */ -/*@{*/ - -#include -#include -#include - -/* general */ -#ifdef _WIN32 -typedef DWORD kmq_thread_id; -typedef DWORD kmq_timer; -#endif - -#ifdef _WIN32 -/*! \brief Window message for kmq - - This message is sent to the window procedure of a window if that - window is a subscriber to KMQ messages. - - \see kmq_subscribe_hwnd() for more information about handling this - window message - */ -#define KMQ_WM_DISPATCH (WM_APP+0x100) -#endif - -/* callback */ - -/*! \brief A message callback - - Should return TRUE if the message is properly handled. Otherwise - return FALSE */ -typedef khm_int32 (KHMAPI *kmq_callback_t)(khm_int32 msg_type, - khm_int32 msg_sub_type, - khm_ui_4 uparam, - void * vparam); - -/* message */ - -/*! \brief A single response. - - Certain broadcast messages may user scatter-gather type - notification and result gathering. Individual subscribers to a - message attach their individual responses to a ::kmq_response - object and attach that to the message which can later be read by - the sender of the message. - */ -typedef struct tag_kmq_response { - kmq_thread_id thread; - void * response; - - LDCL(struct tag_kmq_response); -} kmq_response; - -/*! \brief A single message - */ -typedef struct tag_kmq_message { - khm_int32 type; /*!< Type of message */ - khm_int32 subtype; /*!< Subtype of message */ - - khm_ui_4 uparam; /*!< Integer parameter */ - void * vparam; /*!< Pointer to parameter blob */ - - khm_int32 nSent; /*!< Number of instances of message - sent (for broadcast messages) */ - - khm_int32 nCompleted; /*!< Number of instances that have - completed processing (for broadcast - messages) */ - - khm_int32 nFailed; /*!< Number of instances that failed - to process (for broadcast - messages) */ - - kmq_response * responses; /*!< List of responses */ - HANDLE wait_o; /*!< Event to wait on (only valid if - the publisher of the message - requested a handle to the call) */ - - kmq_timer timeSent; /*!< Time at which the message was - sent */ - kmq_timer timeExpire; /*!< Time at which the message - expires */ - - kherr_context * err_ctx; /*!< Error context for the message */ - - khm_boolean aborted; /*!< TRUE if the message has been - aborted. */ - - khm_int32 refcount; /*!< Internal use */ - - LDCL(struct tag_kmq_message); /*!< Internal use */ -} kmq_message; - -/*! \brief A handle to a call - */ -typedef kmq_message *kmq_call; - -/* publishers */ - -/*! \brief A completion handler for a message - - Each message type can have a completion handler. Once a message - of this a specific type has been broadcast and handled by all the - subscripbers, the message will be passed down to the completion - handler before the associated data structures are freed. This - allows applications that define message type to also define clean - up for each message. For example, the completion handler can - initiate another message if the messages form a sequence or free - up blocks of memory that was passed as the parameter to the - message. - */ -typedef void (KHMAPI *kmq_msg_completion_handler)(kmq_message *); - -#ifdef NOEXPORT - -KHMEXP khm_int32 KHMAPI kmq_init(void); - -KHMEXP khm_int32 KHMAPI kmq_exit(void); - -#endif - -/*! \brief Register a message type - - Registers a custom message type. The \a name parameter specifies - a language independent name for the message type and must be - unique and must be less than ::KMQ_MAXCCH_TYPE_NAME characters. - - \param[in] name Name of the message type. Upto - ::KMQ_MAXCCH_TYPE_NAME characters including terminating NULL. - The \a name cannot be a zero length string. - - \param[out] new_id Receives the new message type ID. Specify NULL - if the new message type is not required. - - \see kmq_find_type() and kmq_unregister_type() - - \retval KHM_ERROR_INVALID_PARAM The \a name parameter was invalid. - \retval KHM_ERROR_EXISTS A message type with that name already exists. - \retval KHM_ERROR_NO_RESOURCES Can't register any more message types. - \retval KHM_ERROR_SUCCESS The operation succeeded. - */ -KHMEXP khm_int32 KHMAPI kmq_register_type(wchar_t * name, khm_int32 * new_id); - -/*! \brief Find a message type - - Find the message type with the given name. If found, the type ID - is returned in \a id. - - \retval KHM_ERROR_SUCCESS A message type with the given name was - found. - \retval KHM_ERROR_NOT_FOUND A message type with the given name was - not found. - */ -KHMEXP khm_int32 KHMAPI kmq_find_type(wchar_t * name, khm_int32 * id); - -/*! \brief Unregister a message type - - Unregisters a message type that was registered using - kmq_register_type(). - - \retval KHM_ERROR_SUCCESS The specified message type was - successfully unregistered. - - \retval KHM_ERROR_NOT_FOUND The message type was not found. - */ -KHMEXP khm_int32 KHMAPI kmq_unregister_type(khm_int32 id); - -/*! \brief Subscribte to a message type. - - Adds a subscription to messages of type \a type. Subscriptions - are managed per thread. Therefore the subscription is actually - added to the subscription list for the current thread (the thread - which calls kmq_subscribe()). - - When a message of type \a type is received by the thread, it is - dispatched to the callback function identified by \a cb within the - context of this thread. - - \note Calling kmq_subscribe() from within multiple threads with - the same \a type and \a cb will result in multiple - subscriptions. - - \see kmq_unsubscribe() - \see kmq_dispatch() -*/ -KHMEXP khm_int32 KHMAPI kmq_subscribe(khm_int32 type, kmq_callback_t cb); - -/*! \brief Subscribe a window to a message type - - Adds the window specified by \a hwnd to the subscription list for - the message type \a type. When a message of this type is posted, - then the window procedure of the window \a hwnd receives a message - ::KMQ_WM_DISPATCH. - - When a window receives a ::KMQ_WM_DISPATCH message, it means that - a message has been posted which is of a type that the window has - subscribed for. Because of the way Windows handles window - messages and the way NetIDMgr message queues work, a thread which - has a window (or thread) procedure can not call kmq_dispatch() to - handle these messages. For threads that have window or thread - message loops, they must call kmq_subscribe_hwnd() to subscribe a - particular window (for thread message loops, this would be the - HWND of the message window for the thread) to NetIDMgr messages. - - There are two supported ways of handling the ::KMQ_WM_DISPATCH - message. Examples of both are provided below. - - Handling the message inline: - - \code - LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - kmq_message * m; - khm_int32 rv; - ... - switch(uMsg) { - case WM_CREATE: - ... - kmq_subscribe_hwnd(KMSG_CRED, hwnd); - ... - break; - - case WM_DESTROY: - ... - kmq_unsubscribe_hwnd(KMSG_CRED, hwnd); - ... - break; - - ... - case KMQ_WM_DISPATCH: - kmq_wm_begin(lParam,&m); - - if(m->type == KMSG_CRED && m->subtype == KMSG_CRED_ROOTDELTA) { - // do something - rv = KHM_ERROR_SUCCESS; - } - - return kmq_wm_end(m, rv); - ... - }; - ... - } - \endcode - - The other method is to dispatch the ::KMQ_WM_DISPATCH message to a - secondary callback function: - - \code - khm_int32 msg_handler(khm_int32 t, khm_int32 st, khm_ui_4 up, void * pb) { - khm_int32 rv = KHM_ERROR_SUCCESS; - - //handle message - - return rv; - } - - LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - kmq_message * m; - khm_int32 rv; - ... - switch(uMsg) { - ... - - case WM_CREATE: - ... - kmq_subscribe_hwnd(KMSG_CRED, hwnd); - ... - break; - - case WM_DESTROY: - ... - kmq_unsubscribe_hwnd(KMSG_CRED, hwnd); - ... - break; - - ... - case KMQ_WM_DISPATCH: - return kmq_wm_dispatch(lParam, msg_handler); - ... - }; - ... - } - \endcode - - \note Make sure you unsubscribe from the message type when the - window is destroyed. - - \see kmq_unsubscribe_hwnd() - \see kmq_wm_begin() - \see kmq_wm_end() - \see kmq_wm_dispatch() - */ -KHMEXP khm_int32 KHMAPI kmq_subscribe_hwnd(khm_int32 type, HWND hwnd); - -#ifdef _WIN32 -/*! \brief Begins handling a KMQ_WM_DISPATCH message - - \return The return value of this function should be ignored. - - \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH - */ -KHMEXP LRESULT KHMAPI kmq_wm_begin(LPARAM lparm, kmq_message ** m); - -/*! \brief Ends handling a KMQ_WM_DISPATCH message - - \return The return value of this function should be the return - value of the window procedure. See kmq_subscribe_hwnd() - documentation for example - - \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH - */ -KHMEXP LRESULT KHMAPI kmq_wm_end(kmq_message *m, khm_int32 rv); - -/*! \brief Dispatches a KMQ_WM_DISPATCH message to a callback - - \return The return value of this function should be the return - value of the window procedure. See kmq_subscribe_hwnd() - documentation for example. - - \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH - */ -KHMEXP LRESULT KHMAPI kmq_wm_dispatch(LPARAM lparm, kmq_callback_t cb); -#endif - -/*! \brief Unsubscribe a callback from a message type - - Removes the subscription for message type \a type for callback - function \a cb from the subscription list for the current thread - (the thread that calls kmq_unsubscribe()). - - \note kmq_unsubscribe() can only remove subscriptions for the subscription - list for the current thread. - - \see kmq_subscribe() - \see kmq_dispatch() -*/ -KHMEXP khm_int32 KHMAPI kmq_unsubscribe(khm_int32 type, kmq_callback_t cb); - -/*! \brief Unsubscribe a window from a message type - - Removes the specific window from the subsription list for message - type \a type. - - \see kmq_subscribe_hwnd() -*/ -KHMEXP khm_int32 KHMAPI kmq_unsubscribe_hwnd(khm_int32 type, HWND hwnd); - -/*! \brief Create an ad-hoc subscription - - An ad-hoc subscription describes a callback point in a thread that - can be dispatched messages to 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_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 - kmq_create_subscription() - */ -KHMEXP khm_int32 KHMAPI kmq_delete_subscription(khm_handle sub); - -/*! \brief Post a message to a subscription - - Equivalent of kmq_post_msg() but only posts the message to the - specified subscription. - */ -KHMEXP khm_int32 KHMAPI kmq_post_sub_msg( - khm_handle sub, - khm_int32 type, - khm_int32 subtype, - khm_ui_4 uparam, - void * vparam); - -/*! \brief Post a message to a subscription and acquire a handle to the call - */ -KHMEXP khm_int32 KHMAPI kmq_post_sub_msg_ex( - khm_handle sub, - khm_int32 type, - khm_int32 subtype, - khm_ui_4 uparam, - void * vparam, - kmq_call * call); - -/*! \brief Send a synchronous message to a subscription - - \retval KHM_ERROR_SUCCESS The call succeeded, and no subscribers reported errors - \retval KHM_ERROR_PARTIAL The call succeeded, but at least one subscriber reported errors - */ -KHMEXP khm_int32 KHMAPI kmq_send_sub_msg( - khm_handle sub, - khm_int32 type, - khm_int32 subtype, - khm_ui_4 uparam, - void * vparam); - -/*! \brief Post a message to a group of subscriptions - - The block of memory pointed to by \a subs should be an array of - subscriptions. The number of elements in that array should be \a - n_subs. A message as specified by the remaining parameters will - be dispatched to all of the subscription points in the array. - */ -KHMEXP khm_int32 KHMAPI kmq_post_subs_msg( - khm_handle * subs, - khm_size n_subs, - khm_int32 type, - khm_int32 subtype, - khm_ui_4 uparam, - void * vparam); - -/*! \brief Post a message to a group of subscriptions and acquire a handle to the call - - The block of memory pointed to by \a subs should be an array of - subscriptions. The number of elements in that array should be \a - n_subs. A message as specified by the remaining parameters will - be dispatched to all of the subscription points in the array, and - a handle to the call will be returned in \a call. - - The returned \a call will reference all of the dispatches that - were made. -*/ -KHMEXP khm_int32 KHMAPI kmq_post_subs_msg_ex( - khm_handle * subs, - khm_int32 n_subs, - khm_int32 type, - khm_int32 subtype, - khm_ui_4 uparam, - void * vparam, - kmq_call * call); - -/*! \brief Send a synchronous message to a group of subscriptions - - The block of memory pointed to by \a subs should be an array of - subscriptions. The number of elements in that array should be \a - n_subs. A message as specified by the remaining parameters will - be dispatched to all of the subscription points in the array. The - function will not return until all of the calls have succeeded. - - \retval KHM_ERROR_SUCCESS The call succeeded, and no subscribers reported errors - \retval KHM_ERROR_PARTIAL The call succeeded, but at least one subscriber reported errors -*/ -KHMEXP khm_int32 KHMAPI kmq_send_subs_msg( - khm_handle *subs, - khm_int32 n_subs, - khm_int32 type, - khm_int32 subtype, - khm_ui_4 uparam, - void * vparam); - -/*! \brief Dispatch a message for the current thread. - - This function opens the message list for the current thread and - dispatches the first message instance that is found. Note that if - multiple callbacks subscribe to the same message type in the same - thread, then when a message of that type is received, multiple - message instances are added to the message queue corresponding to - each subscription. - - If no message instances are waiting in the queue, kmq_dispatch() - waits for the \a timeout period for a message. - - \param[in] timeout The timeout period in milliseconds. Specify INFINITE for - kmq_dispatch() to wait indefinitely. - - \retval KHM_ERROR_SUCCESS A message instance was dispatched - \retval KHM_ERROR_TIMEOUT The timeout period elapsed - \retval KHM_ERROR_EXIT The message found on the queue was -*/ -KHMEXP khm_int32 KHMAPI kmq_dispatch(kmq_timer timeout); - -/*! \brief Send a message - - The specified message will be posted to all the subscribers of the - message type. Then the function will wait for all the subscribers - to finish processing the message before returning. - - \param[in] type The type of the message - \param[in] subtype The subtype - \param[in] uparam The khm_ui_4 parameter for the message - \param[in] blob The parameter blob for the message - - \note The internal timeout for this function is INFINITE. If you - it is desirable to use a different timeout, use - kmq_post_message_ex() and kmq_wait() functions. - - \retval KHM_ERROR_SUCCESS The call succeeded and no subscribers returned errors - \retval KHM_ERROR_PARTIAL The call succeeded but at least one subscriber returned an error -*/ -KHMEXP khm_int32 KHMAPI kmq_send_message( - khm_int32 type, - khm_int32 subtype, - khm_ui_4 uparam, - void * blob); - -/*! \brief Post a message - - The specified message will be posted to all the subscribers of the - message type. The function returns immediately. - - If you want to be able to wait for all the subscribers to finish - processing the message, you should use kmq_post_message_ex() - instead. - - \param[in] type The type of the message - \param[in] subtype The subtype - \param[in] uparam The khm_ui_4 parameter for the message - \param[in] blob The parameter blob for the message -*/ -KHMEXP khm_int32 KHMAPI kmq_post_message( - khm_int32 type, - khm_int32 subtype, - khm_ui_4 uparam, - void * blob); - -/*! \brief Post a message and acquire a handle to the call. - - The specified message is posted to all the subscribers. In - addition, a handle is obtained for the call which can be used in - subsequent call to kmq_free_call() or kmq_wait(). - - Call kmq_free_call() to free the handle. - - \param[in] type The type of the message - \param[in] subtype The subtype - \param[in] uparam The khm_ui_4 parameter for the message - \param[in] blob The parameter blob for the message - \param[out] call Receives the call handle. Set to NULL if the call handle is not required. - - \see kmq_free_call() -*/ -KHMEXP khm_int32 KHMAPI kmq_post_message_ex( - khm_int32 type, - khm_int32 subtype, - khm_ui_4 uparam, - void * blob, - kmq_call * call); - -/*! \brief Free a handle to a call obtained through kmq_post_message_ex() - - All call handles obtained through kmq_post_message_ex() must be - freed via a call to kmq_free_call(). -*/ -KHMEXP khm_int32 KHMAPI kmq_free_call(kmq_call call); - -/*! \brief Sends a message to the specified thread. - - The message itself will not be received by any callback function, - however, any kmq_dispatch() function that is currently active of - becomes active will exit with a KHM_ERROR_EXIT code. - kmq_send_thread_quit_message() will wait for this to happen before - returning. - */ -KHMEXP khm_int32 KHMAPI kmq_send_thread_quit_message( - kmq_thread_id thread, - khm_ui_4 uparam); - -/*! \brief Post a message to the specified thread. - - The message itself will not be received by any callback function, - however, any kmq_dispatch() function that is currently active of - becomes active will exit with a KHM_ERROR_EXIT code. - kmq_post_thread_quit_message() will return immediately. - */ -KHMEXP khm_int32 KHMAPI kmq_post_thread_quit_message( - kmq_thread_id thread, - khm_ui_4 uparam, - kmq_call * call); - -KHMEXP khm_int32 KHMAPI kmq_get_next_response(kmq_call call, void ** resp); - -/*! \brief Check if a specific call has completed - - \return TRUE if the call has completed. FALSE otherwise. -*/ -KHMEXP khm_boolean KHMAPI kmq_has_completed(kmq_call call); - -/*! \brief Wait for a call to complete. - - Waits for the specified call to complete. If the call dispatched - to multiple recipients, the function waits for all dispatches to - complete. - - If the call has already completed, then the function returns - immediately. - - If more than one thread is waiting for a single message to - complete, then only one of them will be released when the message - compeltes. Each subsequent thread will be released as each - released thread calls kmq_free_call(). - - \param[in] call A handle to a call. - \param[in] timeout Specifies, in milliseconds, the amount of time - to wait for the call to complete. Specify INFINITE to wait - indefinitely. - - \retval KHM_ERROR_SUCCESS The call completed - \retval KHM_ERROR_TIMEOUT The timeout period expired - \retval KHM_ERROR_INVALID_PARAM One of the parameters were invalid. -*/ -KHMEXP khm_int32 KHMAPI kmq_wait(kmq_call call, kmq_timer timeout); - -/*! \brief Abort a call - - Abort a pending call. The call handle should have been obtained - using a prior call to kmq_post_message_ex(). - - Note that this function may not abort the call immediately. It - merely marks the message as being in an aborted state. It is upto - the individual handlers of the message to check if the message has - been aborted and act accordingly. - - The handlers are expected to call kmq_is_call_aborted() - periodicially during the processing of specially lengthy - operations during the course of handling a message. That function - will return \a TRUE if the last dispatched message is now in an - aborted state. In which case, the handler is expected to abort - handling the message and return control to the dispatcher. - */ -KHMEXP khm_int32 KHMAPI kmq_abort_call(kmq_call call); - -/*! \brief Check if the last dispatched message was aborted - - The sender of a message may abort it using a call to - kmq_abort_call(). This function checks if the last dispatched - message was aborted. - - A handler of a message is expected to call this function - periodically if handling the message is going to take a specially - long time (e.g. more than 5 or 10 seconds). If the message is - found to be aborted, the handler is expected to abort handling the - message, perform any necessary cleanup and return control to the - dispatcher. - - Doing this allows operations like new credentials acquisition to - be cleanly aborted by the user if she so wishes. Otherwise, - Network Identity Manager has to wait for the message to complete - processing since it has no means of cleanly terminating an - executing plug-in thread. -*/ -KHMEXP khm_boolean KHMAPI kmq_is_call_aborted(void); - -/*! \brief Sets the completion handler for a specified message type. - - \note Only one completion handler can exist for one message type. - Calling this function overwrites the previous completion - handler. -*/ -KHMEXP khm_int32 KHMAPI kmq_set_completion_handler( - khm_int32 type, - kmq_msg_completion_handler hander); - -/*@}*/ -#endif +/* + * 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_KMQ_H__ +#define __KHIMAIRA_KMQ_H__ + +/*! \defgroup kmq NetIDMgr Message Queue */ +/*@{*/ + +#include +#include +#include + +/* general */ +#ifdef _WIN32 +typedef DWORD kmq_thread_id; +typedef DWORD kmq_timer; +#endif + +#ifdef _WIN32 +/*! \brief Window message for kmq + + This message is sent to the window procedure of a window if that + window is a subscriber to KMQ messages. + + \see kmq_subscribe_hwnd() for more information about handling this + window message + */ +#define KMQ_WM_DISPATCH (WM_APP+0x100) +#endif + +/* callback */ + +/*! \brief A message callback + + Should return TRUE if the message is properly handled. Otherwise + return FALSE */ +typedef khm_int32 (KHMAPI *kmq_callback_t)(khm_int32 msg_type, + khm_int32 msg_sub_type, + khm_ui_4 uparam, + void * vparam); + +/* message */ + +/*! \brief A single response. + + Certain broadcast messages may user scatter-gather type + notification and result gathering. Individual subscribers to a + message attach their individual responses to a ::kmq_response + object and attach that to the message which can later be read by + the sender of the message. + */ +typedef struct tag_kmq_response { + kmq_thread_id thread; + void * response; + + LDCL(struct tag_kmq_response); +} kmq_response; + +/*! \brief A single message + */ +typedef struct tag_kmq_message { + khm_int32 type; /*!< Type of message */ + khm_int32 subtype; /*!< Subtype of message */ + + khm_ui_4 uparam; /*!< Integer parameter */ + void * vparam; /*!< Pointer to parameter blob */ + + khm_int32 nSent; /*!< Number of instances of message + sent (for broadcast messages) */ + + khm_int32 nCompleted; /*!< Number of instances that have + completed processing (for broadcast + messages) */ + + khm_int32 nFailed; /*!< Number of instances that failed + to process (for broadcast + messages) */ + + kmq_response * responses; /*!< List of responses */ + HANDLE wait_o; /*!< Event to wait on (only valid if + the publisher of the message + requested a handle to the call) */ + + kmq_timer timeSent; /*!< Time at which the message was + sent */ + kmq_timer timeExpire; /*!< Time at which the message + expires */ + + kherr_context * err_ctx; /*!< Error context for the message */ + + khm_boolean aborted; /*!< TRUE if the message has been + aborted. */ + + khm_int32 refcount; /*!< Internal use */ + + LDCL(struct tag_kmq_message); /*!< Internal use */ +} kmq_message; + +/*! \brief A handle to a call + */ +typedef kmq_message *kmq_call; + +/* publishers */ + +/*! \brief A completion handler for a message + + Each message type can have a completion handler. Once a message + of this a specific type has been broadcast and handled by all the + subscripbers, the message will be passed down to the completion + handler before the associated data structures are freed. This + allows applications that define message type to also define clean + up for each message. For example, the completion handler can + initiate another message if the messages form a sequence or free + up blocks of memory that was passed as the parameter to the + message. + */ +typedef void (KHMAPI *kmq_msg_completion_handler)(kmq_message *); + +#ifdef NOEXPORT + +KHMEXP khm_int32 KHMAPI kmq_init(void); + +KHMEXP khm_int32 KHMAPI kmq_exit(void); + +#endif + +/*! \brief Register a message type + + Registers a custom message type. The \a name parameter specifies + a language independent name for the message type and must be + unique and must be less than ::KMQ_MAXCCH_TYPE_NAME characters. + + \param[in] name Name of the message type. Upto + ::KMQ_MAXCCH_TYPE_NAME characters including terminating NULL. + The \a name cannot be a zero length string. + + \param[out] new_id Receives the new message type ID. Specify NULL + if the new message type is not required. + + \see kmq_find_type() and kmq_unregister_type() + + \retval KHM_ERROR_INVALID_PARAM The \a name parameter was invalid. + \retval KHM_ERROR_EXISTS A message type with that name already exists. + \retval KHM_ERROR_NO_RESOURCES Can't register any more message types. + \retval KHM_ERROR_SUCCESS The operation succeeded. + */ +KHMEXP khm_int32 KHMAPI kmq_register_type(wchar_t * name, khm_int32 * new_id); + +/*! \brief Find a message type + + Find the message type with the given name. If found, the type ID + is returned in \a id. + + \retval KHM_ERROR_SUCCESS A message type with the given name was + found. + \retval KHM_ERROR_NOT_FOUND A message type with the given name was + not found. + */ +KHMEXP khm_int32 KHMAPI kmq_find_type(wchar_t * name, khm_int32 * id); + +/*! \brief Unregister a message type + + Unregisters a message type that was registered using + kmq_register_type(). + + \retval KHM_ERROR_SUCCESS The specified message type was + successfully unregistered. + + \retval KHM_ERROR_NOT_FOUND The message type was not found. + */ +KHMEXP khm_int32 KHMAPI kmq_unregister_type(khm_int32 id); + +/*! \brief Subscribte to a message type. + + Adds a subscription to messages of type \a type. Subscriptions + are managed per thread. Therefore the subscription is actually + added to the subscription list for the current thread (the thread + which calls kmq_subscribe()). + + When a message of type \a type is received by the thread, it is + dispatched to the callback function identified by \a cb within the + context of this thread. + + \note Calling kmq_subscribe() from within multiple threads with + the same \a type and \a cb will result in multiple + subscriptions. + + \see kmq_unsubscribe() + \see kmq_dispatch() +*/ +KHMEXP khm_int32 KHMAPI kmq_subscribe(khm_int32 type, kmq_callback_t cb); + +/*! \brief Subscribe a window to a message type + + Adds the window specified by \a hwnd to the subscription list for + the message type \a type. When a message of this type is posted, + then the window procedure of the window \a hwnd receives a message + ::KMQ_WM_DISPATCH. + + When a window receives a ::KMQ_WM_DISPATCH message, it means that + a message has been posted which is of a type that the window has + subscribed for. Because of the way Windows handles window + messages and the way NetIDMgr message queues work, a thread which + has a window (or thread) procedure can not call kmq_dispatch() to + handle these messages. For threads that have window or thread + message loops, they must call kmq_subscribe_hwnd() to subscribe a + particular window (for thread message loops, this would be the + HWND of the message window for the thread) to NetIDMgr messages. + + There are two supported ways of handling the ::KMQ_WM_DISPATCH + message. Examples of both are provided below. + + Handling the message inline: + + \code + LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + kmq_message * m; + khm_int32 rv; + ... + switch(uMsg) { + case WM_CREATE: + ... + kmq_subscribe_hwnd(KMSG_CRED, hwnd); + ... + break; + + case WM_DESTROY: + ... + kmq_unsubscribe_hwnd(KMSG_CRED, hwnd); + ... + break; + + ... + case KMQ_WM_DISPATCH: + kmq_wm_begin(lParam,&m); + + if(m->type == KMSG_CRED && m->subtype == KMSG_CRED_ROOTDELTA) { + // do something + rv = KHM_ERROR_SUCCESS; + } + + return kmq_wm_end(m, rv); + ... + }; + ... + } + \endcode + + The other method is to dispatch the ::KMQ_WM_DISPATCH message to a + secondary callback function: + + \code + khm_int32 msg_handler(khm_int32 t, khm_int32 st, khm_ui_4 up, void * pb) { + khm_int32 rv = KHM_ERROR_SUCCESS; + + //handle message + + return rv; + } + + LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + kmq_message * m; + khm_int32 rv; + ... + switch(uMsg) { + ... + + case WM_CREATE: + ... + kmq_subscribe_hwnd(KMSG_CRED, hwnd); + ... + break; + + case WM_DESTROY: + ... + kmq_unsubscribe_hwnd(KMSG_CRED, hwnd); + ... + break; + + ... + case KMQ_WM_DISPATCH: + return kmq_wm_dispatch(lParam, msg_handler); + ... + }; + ... + } + \endcode + + \note Make sure you unsubscribe from the message type when the + window is destroyed. + + \see kmq_unsubscribe_hwnd() + \see kmq_wm_begin() + \see kmq_wm_end() + \see kmq_wm_dispatch() + */ +KHMEXP khm_int32 KHMAPI kmq_subscribe_hwnd(khm_int32 type, HWND hwnd); + +#ifdef _WIN32 +/*! \brief Begins handling a KMQ_WM_DISPATCH message + + \return The return value of this function should be ignored. + + \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH + */ +KHMEXP LRESULT KHMAPI kmq_wm_begin(LPARAM lparm, kmq_message ** m); + +/*! \brief Ends handling a KMQ_WM_DISPATCH message + + \return The return value of this function should be the return + value of the window procedure. See kmq_subscribe_hwnd() + documentation for example + + \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH + */ +KHMEXP LRESULT KHMAPI kmq_wm_end(kmq_message *m, khm_int32 rv); + +/*! \brief Dispatches a KMQ_WM_DISPATCH message to a callback + + \return The return value of this function should be the return + value of the window procedure. See kmq_subscribe_hwnd() + documentation for example. + + \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH + */ +KHMEXP LRESULT KHMAPI kmq_wm_dispatch(LPARAM lparm, kmq_callback_t cb); +#endif + +/*! \brief Unsubscribe a callback from a message type + + Removes the subscription for message type \a type for callback + function \a cb from the subscription list for the current thread + (the thread that calls kmq_unsubscribe()). + + \note kmq_unsubscribe() can only remove subscriptions for the subscription + list for the current thread. + + \see kmq_subscribe() + \see kmq_dispatch() +*/ +KHMEXP khm_int32 KHMAPI kmq_unsubscribe(khm_int32 type, kmq_callback_t cb); + +/*! \brief Unsubscribe a window from a message type + + Removes the specific window from the subsription list for message + type \a type. + + \see kmq_subscribe_hwnd() +*/ +KHMEXP khm_int32 KHMAPI kmq_unsubscribe_hwnd(khm_int32 type, HWND hwnd); + +/*! \brief Create an ad-hoc subscription + + An ad-hoc subscription describes a callback point in a thread that + can be dispatched messages to 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_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 + kmq_create_subscription() + */ +KHMEXP khm_int32 KHMAPI kmq_delete_subscription(khm_handle sub); + +/*! \brief Post a message to a subscription + + Equivalent of kmq_post_msg() but only posts the message to the + specified subscription. + */ +KHMEXP khm_int32 KHMAPI kmq_post_sub_msg( + khm_handle sub, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam); + +/*! \brief Post a message to a subscription and acquire a handle to the call + */ +KHMEXP khm_int32 KHMAPI kmq_post_sub_msg_ex( + khm_handle sub, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam, + kmq_call * call); + +/*! \brief Send a synchronous message to a subscription + + \retval KHM_ERROR_SUCCESS The call succeeded, and no subscribers reported errors + \retval KHM_ERROR_PARTIAL The call succeeded, but at least one subscriber reported errors + */ +KHMEXP khm_int32 KHMAPI kmq_send_sub_msg( + khm_handle sub, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam); + +/*! \brief Post a message to a group of subscriptions + + The block of memory pointed to by \a subs should be an array of + subscriptions. The number of elements in that array should be \a + n_subs. A message as specified by the remaining parameters will + be dispatched to all of the subscription points in the array. + */ +KHMEXP khm_int32 KHMAPI kmq_post_subs_msg( + khm_handle * subs, + khm_size n_subs, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam); + +/*! \brief Post a message to a group of subscriptions and acquire a handle to the call + + The block of memory pointed to by \a subs should be an array of + subscriptions. The number of elements in that array should be \a + n_subs. A message as specified by the remaining parameters will + be dispatched to all of the subscription points in the array, and + a handle to the call will be returned in \a call. + + The returned \a call will reference all of the dispatches that + were made. +*/ +KHMEXP khm_int32 KHMAPI kmq_post_subs_msg_ex( + khm_handle * subs, + khm_int32 n_subs, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam, + kmq_call * call); + +/*! \brief Send a synchronous message to a group of subscriptions + + The block of memory pointed to by \a subs should be an array of + subscriptions. The number of elements in that array should be \a + n_subs. A message as specified by the remaining parameters will + be dispatched to all of the subscription points in the array. The + function will not return until all of the calls have succeeded. + + \retval KHM_ERROR_SUCCESS The call succeeded, and no subscribers reported errors + \retval KHM_ERROR_PARTIAL The call succeeded, but at least one subscriber reported errors +*/ +KHMEXP khm_int32 KHMAPI kmq_send_subs_msg( + khm_handle *subs, + khm_int32 n_subs, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam); + +/*! \brief Dispatch a message for the current thread. + + This function opens the message list for the current thread and + dispatches the first message instance that is found. Note that if + multiple callbacks subscribe to the same message type in the same + thread, then when a message of that type is received, multiple + message instances are added to the message queue corresponding to + each subscription. + + If no message instances are waiting in the queue, kmq_dispatch() + waits for the \a timeout period for a message. + + \param[in] timeout The timeout period in milliseconds. Specify INFINITE for + kmq_dispatch() to wait indefinitely. + + \retval KHM_ERROR_SUCCESS A message instance was dispatched + \retval KHM_ERROR_TIMEOUT The timeout period elapsed + \retval KHM_ERROR_EXIT The message found on the queue was +*/ +KHMEXP khm_int32 KHMAPI kmq_dispatch(kmq_timer timeout); + +/*! \brief Send a message + + The specified message will be posted to all the subscribers of the + message type. Then the function will wait for all the subscribers + to finish processing the message before returning. + + \param[in] type The type of the message + \param[in] subtype The subtype + \param[in] uparam The khm_ui_4 parameter for the message + \param[in] blob The parameter blob for the message + + \note The internal timeout for this function is INFINITE. If you + it is desirable to use a different timeout, use + kmq_post_message_ex() and kmq_wait() functions. + + \retval KHM_ERROR_SUCCESS The call succeeded and no subscribers returned errors + \retval KHM_ERROR_PARTIAL The call succeeded but at least one subscriber returned an error +*/ +KHMEXP khm_int32 KHMAPI kmq_send_message( + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * blob); + +/*! \brief Post a message + + The specified message will be posted to all the subscribers of the + message type. The function returns immediately. + + If you want to be able to wait for all the subscribers to finish + processing the message, you should use kmq_post_message_ex() + instead. + + \param[in] type The type of the message + \param[in] subtype The subtype + \param[in] uparam The khm_ui_4 parameter for the message + \param[in] blob The parameter blob for the message +*/ +KHMEXP khm_int32 KHMAPI kmq_post_message( + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * blob); + +/*! \brief Post a message and acquire a handle to the call. + + The specified message is posted to all the subscribers. In + addition, a handle is obtained for the call which can be used in + subsequent call to kmq_free_call() or kmq_wait(). + + Call kmq_free_call() to free the handle. + + \param[in] type The type of the message + \param[in] subtype The subtype + \param[in] uparam The khm_ui_4 parameter for the message + \param[in] blob The parameter blob for the message + \param[out] call Receives the call handle. Set to NULL if the call handle is not required. + + \see kmq_free_call() +*/ +KHMEXP khm_int32 KHMAPI kmq_post_message_ex( + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * blob, + kmq_call * call); + +/*! \brief Free a handle to a call obtained through kmq_post_message_ex() + + All call handles obtained through kmq_post_message_ex() must be + freed via a call to kmq_free_call(). +*/ +KHMEXP khm_int32 KHMAPI kmq_free_call(kmq_call call); + +/*! \brief Sends a message to the specified thread. + + The message itself will not be received by any callback function, + however, any kmq_dispatch() function that is currently active of + becomes active will exit with a KHM_ERROR_EXIT code. + kmq_send_thread_quit_message() will wait for this to happen before + returning. + */ +KHMEXP khm_int32 KHMAPI kmq_send_thread_quit_message( + kmq_thread_id thread, + khm_ui_4 uparam); + +/*! \brief Post a message to the specified thread. + + The message itself will not be received by any callback function, + however, any kmq_dispatch() function that is currently active of + becomes active will exit with a KHM_ERROR_EXIT code. + kmq_post_thread_quit_message() will return immediately. + */ +KHMEXP khm_int32 KHMAPI kmq_post_thread_quit_message( + kmq_thread_id thread, + khm_ui_4 uparam, + kmq_call * call); + +KHMEXP khm_int32 KHMAPI kmq_get_next_response(kmq_call call, void ** resp); + +/*! \brief Check if a specific call has completed + + \return TRUE if the call has completed. FALSE otherwise. +*/ +KHMEXP khm_boolean KHMAPI kmq_has_completed(kmq_call call); + +/*! \brief Wait for a call to complete. + + Waits for the specified call to complete. If the call dispatched + to multiple recipients, the function waits for all dispatches to + complete. + + If the call has already completed, then the function returns + immediately. + + If more than one thread is waiting for a single message to + complete, then only one of them will be released when the message + compeltes. Each subsequent thread will be released as each + released thread calls kmq_free_call(). + + \param[in] call A handle to a call. + \param[in] timeout Specifies, in milliseconds, the amount of time + to wait for the call to complete. Specify INFINITE to wait + indefinitely. + + \retval KHM_ERROR_SUCCESS The call completed + \retval KHM_ERROR_TIMEOUT The timeout period expired + \retval KHM_ERROR_INVALID_PARAM One of the parameters were invalid. +*/ +KHMEXP khm_int32 KHMAPI kmq_wait(kmq_call call, kmq_timer timeout); + +/*! \brief Abort a call + + Abort a pending call. The call handle should have been obtained + using a prior call to kmq_post_message_ex(). + + Note that this function may not abort the call immediately. It + merely marks the message as being in an aborted state. It is upto + the individual handlers of the message to check if the message has + been aborted and act accordingly. + + The handlers are expected to call kmq_is_call_aborted() + periodicially during the processing of specially lengthy + operations during the course of handling a message. That function + will return \a TRUE if the last dispatched message is now in an + aborted state. In which case, the handler is expected to abort + handling the message and return control to the dispatcher. + */ +KHMEXP khm_int32 KHMAPI kmq_abort_call(kmq_call call); + +/*! \brief Check if the last dispatched message was aborted + + The sender of a message may abort it using a call to + kmq_abort_call(). This function checks if the last dispatched + message was aborted. + + A handler of a message is expected to call this function + periodically if handling the message is going to take a specially + long time (e.g. more than 5 or 10 seconds). If the message is + found to be aborted, the handler is expected to abort handling the + message, perform any necessary cleanup and return control to the + dispatcher. + + Doing this allows operations like new credentials acquisition to + be cleanly aborted by the user if she so wishes. Otherwise, + Network Identity Manager has to wait for the message to complete + processing since it has no means of cleanly terminating an + executing plug-in thread. +*/ +KHMEXP khm_boolean KHMAPI kmq_is_call_aborted(void); + +/*! \brief Sets the completion handler for a specified message type. + + \note Only one completion handler can exist for one message type. + Calling this function overwrites the previous completion + handler. +*/ +KHMEXP khm_int32 KHMAPI kmq_set_completion_handler( + khm_int32 type, + kmq_msg_completion_handler hander); + +/*@}*/ +#endif diff --git a/src/windows/identity/kmq/kmqinternal.h b/src/windows/identity/kmq/kmqinternal.h index 1d6196b30..bd97f1bb6 100644 --- a/src/windows/identity/kmq/kmqinternal.h +++ b/src/windows/identity/kmq/kmqinternal.h @@ -1,239 +1,239 @@ -/* - * 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_KMQINTERNAL_H -#define __KHIMAIRA_KMQINTERNAL_H - -#include -#include -#include -#include -#include -#include - -#define NOEXPORT - -#include -#include - - - - -/*! \brief Message reference */ -typedef struct tag_kmq_message_ref { - kmq_message * msg; /*!< Message that we are referring - to */ - kmq_callback_t recipient; /*!< The recipient of the message */ - - LDCL(struct tag_kmq_message_ref); -} kmq_message_ref; - - - - -/*! \brief Message queue - - Each thread gets its own message queue. When a message is - broadcast to which there is a subscriber in a particular thread, a - reference to the message is placed in the message queue of the - thread. The dispatch procedure then dispatches the message as - described in the message reference. -*/ -typedef struct tag_kmq_queue { - kmq_thread_id thread; /*!< The thread id */ - - CRITICAL_SECTION cs; - HANDLE wait_o; - - khm_int32 load; /*!< Number of messages waiting to be - processed on this message 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 */ - - /*Lnode*/ - LDCL(struct tag_kmq_queue); -} kmq_queue; - -#define KMQ_QUEUE_FLAG_DELETED 0x00000008 -#define KMQ_QUEUE_FLAG_DETACHING 0x00000010 - -/*! \brief Message subscription - - A subscription binds a recipient with a message type. These are - specific to a thread. I.e. a subscription that was made in one - 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 - ::KMQ_RCPTTYPE_HWND */ - union { - kmq_callback_t cb; /*!< Callback if the subscription is - of callback type */ - HWND hwnd; /*!< Window handle if the subscription - is a windows message type */ - } recipient; - - kmq_queue * queue; /*!< Associated queue */ - - /*lnode*/ - 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 */ -#define KMQ_RCPTTYPE_CB 1 - -/*! \brief Windows recipient type - - The recipient is a window */ -#define KMQ_RCPTTYPE_HWND 2 - - - - -/*! \brief A message type - */ -typedef struct tag_kmq_msg_type { - khm_int32 id; /*!< Identifier for the message - type. */ - kmq_msg_subscription * subs; /*!< The list of subscriptions */ - kmq_msg_completion_handler completion_handler; /*!< Completion - handler for the message type */ - - wchar_t * name; /*!< Name of the message type for - named types. Message type names are - language independant. */ - - /*Lnode*/ - LDCL(struct tag_kmq_msg_type); -} kmq_msg_type; - -/*! \brief The maximum number of message types - */ -#define KMQ_MSG_TYPE_MAX 255 - -/*! \brief Maximum number of characters in a message type name - - The count includes the terminating NULL - */ -#define KMQ_MAXCCH_TYPE_NAME 256 - -/*! \brief Maximum number of bytes in a message type name - - Type count includes the terminating NULL - */ -#define KMQ_MAXCB_TYPE_NAME (KMQ_MAXCCH_TYPE_NAME * sizeof(wchar_t)) - - - - -#define KMQ_CONF_SPACE_NAME L"KMQ" -#define KMQ_CONF_QUEUE_DEAD_TIMEOUT_NAME L"QueueDeadTimeout" -#define KMQ_CONF_CALL_DEAD_TIMEOUT_NAME L"CallDeadTimeout" - -extern CRITICAL_SECTION cs_kmq_global; -extern kmq_timer kmq_queue_dead_timeout; -extern kmq_timer kmq_call_dead_timeout; - -extern kmq_queue * queues; - -/* message type */ -extern CRITICAL_SECTION cs_kmq_types; -extern kmq_msg_type *msg_types[KMQ_MSG_TYPE_MAX+1]; - -void kmqint_init_msg_types(void); -void kmqint_exit_msg_types(void); -void kmqint_free_msg_type(int t); -void kmqint_msg_type_create(int t); -void kmqint_msg_type_add_sub(int t, kmq_msg_subscription *s); -void kmqint_msg_type_del_sub(kmq_msg_subscription *s); -kmq_msg_subscription * kmqint_msg_type_del_sub_hwnd(khm_int32 t, HWND hwnd); -kmq_msg_subscription * kmqint_msg_type_del_sub_cb(khm_int32 t, kmq_callback_t cb); -khm_int32 kmqint_msg_publish(kmq_message * m, khm_boolean try_send); -khm_int32 kmqint_msg_type_set_handler(khm_int32 type, kmq_msg_completion_handler handler); -int kmqint_notify_msg_completion(kmq_message * m); - -/* consumer */ -extern DWORD kmq_tls_queue; - -void kmqint_post_queue(kmq_queue * q, kmq_message *m); -void kmqint_post(kmq_msg_subscription * s, kmq_message * m, khm_boolean try_send); -kmq_queue * kmqint_get_thread_queue(void); -void kmqint_get_queue_message_ref(kmq_queue * q, kmq_message_ref ** r); -void kmqint_put_message_ref(kmq_message_ref * r); - -/* publisher */ -extern CRITICAL_SECTION cs_kmq_msg; -extern CRITICAL_SECTION cs_kmq_msg_ref; - -kmq_message * kmqint_get_message(void); -void kmqint_put_message(kmq_message *m); - -void kmqint_init(void); -void kmqint_exit(void); -void kmqint_attach_this_thread(void); -void kmqint_detach_this_thread(void); - -khm_int32 kmqint_post_message_ex( - khm_int32 type, - khm_int32 subtype, - khm_ui_4 uparam, - void * blob, - kmq_call * call, - khm_boolean try_send); - -int kmqint_call_completion_handler(kmq_msg_completion_handler h, - kmq_message * m); - -/* global */ -extern kconf_schema schema_kmqconfig[]; - -/* Lock hiearchy : - - cs_kmq_types - cs_kmq_msg - cs_kmq_msg_ref - cs_compl - cs_kmq_global - kmq_queue::cs - - If you have a level 'x' lock, you can obtain a level 'x+n' lock. - You can't obtain a 'x-n' lock if you already have a level 'x' lock. - If you don't have any locks, you can obtain any lock. - */ -#endif +/* + * 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_KMQINTERNAL_H +#define __KHIMAIRA_KMQINTERNAL_H + +#include +#include +#include +#include +#include +#include + +#define NOEXPORT + +#include +#include + + + + +/*! \brief Message reference */ +typedef struct tag_kmq_message_ref { + kmq_message * msg; /*!< Message that we are referring + to */ + kmq_callback_t recipient; /*!< The recipient of the message */ + + LDCL(struct tag_kmq_message_ref); +} kmq_message_ref; + + + + +/*! \brief Message queue + + Each thread gets its own message queue. When a message is + broadcast to which there is a subscriber in a particular thread, a + reference to the message is placed in the message queue of the + thread. The dispatch procedure then dispatches the message as + described in the message reference. +*/ +typedef struct tag_kmq_queue { + kmq_thread_id thread; /*!< The thread id */ + + CRITICAL_SECTION cs; + HANDLE wait_o; + + khm_int32 load; /*!< Number of messages waiting to be + processed on this message 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 */ + + /*Lnode*/ + LDCL(struct tag_kmq_queue); +} kmq_queue; + +#define KMQ_QUEUE_FLAG_DELETED 0x00000008 +#define KMQ_QUEUE_FLAG_DETACHING 0x00000010 + +/*! \brief Message subscription + + A subscription binds a recipient with a message type. These are + specific to a thread. I.e. a subscription that was made in one + 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 + ::KMQ_RCPTTYPE_HWND */ + union { + kmq_callback_t cb; /*!< Callback if the subscription is + of callback type */ + HWND hwnd; /*!< Window handle if the subscription + is a windows message type */ + } recipient; + + kmq_queue * queue; /*!< Associated queue */ + + /*lnode*/ + 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 */ +#define KMQ_RCPTTYPE_CB 1 + +/*! \brief Windows recipient type + + The recipient is a window */ +#define KMQ_RCPTTYPE_HWND 2 + + + + +/*! \brief A message type + */ +typedef struct tag_kmq_msg_type { + khm_int32 id; /*!< Identifier for the message + type. */ + kmq_msg_subscription * subs; /*!< The list of subscriptions */ + kmq_msg_completion_handler completion_handler; /*!< Completion + handler for the message type */ + + wchar_t * name; /*!< Name of the message type for + named types. Message type names are + language independant. */ + + /*Lnode*/ + LDCL(struct tag_kmq_msg_type); +} kmq_msg_type; + +/*! \brief The maximum number of message types + */ +#define KMQ_MSG_TYPE_MAX 255 + +/*! \brief Maximum number of characters in a message type name + + The count includes the terminating NULL + */ +#define KMQ_MAXCCH_TYPE_NAME 256 + +/*! \brief Maximum number of bytes in a message type name + + Type count includes the terminating NULL + */ +#define KMQ_MAXCB_TYPE_NAME (KMQ_MAXCCH_TYPE_NAME * sizeof(wchar_t)) + + + + +#define KMQ_CONF_SPACE_NAME L"KMQ" +#define KMQ_CONF_QUEUE_DEAD_TIMEOUT_NAME L"QueueDeadTimeout" +#define KMQ_CONF_CALL_DEAD_TIMEOUT_NAME L"CallDeadTimeout" + +extern CRITICAL_SECTION cs_kmq_global; +extern kmq_timer kmq_queue_dead_timeout; +extern kmq_timer kmq_call_dead_timeout; + +extern kmq_queue * queues; + +/* message type */ +extern CRITICAL_SECTION cs_kmq_types; +extern kmq_msg_type *msg_types[KMQ_MSG_TYPE_MAX+1]; + +void kmqint_init_msg_types(void); +void kmqint_exit_msg_types(void); +void kmqint_free_msg_type(int t); +void kmqint_msg_type_create(int t); +void kmqint_msg_type_add_sub(int t, kmq_msg_subscription *s); +void kmqint_msg_type_del_sub(kmq_msg_subscription *s); +kmq_msg_subscription * kmqint_msg_type_del_sub_hwnd(khm_int32 t, HWND hwnd); +kmq_msg_subscription * kmqint_msg_type_del_sub_cb(khm_int32 t, kmq_callback_t cb); +khm_int32 kmqint_msg_publish(kmq_message * m, khm_boolean try_send); +khm_int32 kmqint_msg_type_set_handler(khm_int32 type, kmq_msg_completion_handler handler); +int kmqint_notify_msg_completion(kmq_message * m); + +/* consumer */ +extern DWORD kmq_tls_queue; + +void kmqint_post_queue(kmq_queue * q, kmq_message *m); +void kmqint_post(kmq_msg_subscription * s, kmq_message * m, khm_boolean try_send); +kmq_queue * kmqint_get_thread_queue(void); +void kmqint_get_queue_message_ref(kmq_queue * q, kmq_message_ref ** r); +void kmqint_put_message_ref(kmq_message_ref * r); + +/* publisher */ +extern CRITICAL_SECTION cs_kmq_msg; +extern CRITICAL_SECTION cs_kmq_msg_ref; + +kmq_message * kmqint_get_message(void); +void kmqint_put_message(kmq_message *m); + +void kmqint_init(void); +void kmqint_exit(void); +void kmqint_attach_this_thread(void); +void kmqint_detach_this_thread(void); + +khm_int32 kmqint_post_message_ex( + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * blob, + kmq_call * call, + khm_boolean try_send); + +int kmqint_call_completion_handler(kmq_msg_completion_handler h, + kmq_message * m); + +/* global */ +extern kconf_schema schema_kmqconfig[]; + +/* Lock hiearchy : + + cs_kmq_types + cs_kmq_msg + cs_kmq_msg_ref + cs_compl + cs_kmq_global + kmq_queue::cs + + If you have a level 'x' lock, you can obtain a level 'x+n' lock. + You can't obtain a 'x-n' lock if you already have a level 'x' lock. + If you don't have any locks, you can obtain any lock. + */ +#endif diff --git a/src/windows/identity/kmq/kmqmain.c b/src/windows/identity/kmq/kmqmain.c index 3e8176f1b..fecfc17fd 100644 --- a/src/windows/identity/kmq/kmqmain.c +++ b/src/windows/identity/kmq/kmqmain.c @@ -1,47 +1,47 @@ -/* - * 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 - -void -kmq_process_attach(void) { - kmqint_init(); -} - -void -kmq_process_detach(void) { - kmqint_exit(); -} - -void -kmq_thread_attach(void) { - kmqint_attach_this_thread(); -} - -void -kmq_thread_detach(void) { - kmqint_detach_this_thread(); -} +/* + * 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 + +void +kmq_process_attach(void) { + kmqint_init(); +} + +void +kmq_process_detach(void) { + kmqint_exit(); +} + +void +kmq_thread_attach(void) { + kmqint_attach_this_thread(); +} + +void +kmq_thread_detach(void) { + kmqint_detach_this_thread(); +} diff --git a/src/windows/identity/kmq/msgtype.c b/src/windows/identity/kmq/msgtype.c index 1b0868d83..b7ea21fca 100644 --- a/src/windows/identity/kmq/msgtype.c +++ b/src/windows/identity/kmq/msgtype.c @@ -1,388 +1,388 @@ -/* - * 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 - -CRITICAL_SECTION cs_kmq_types; - -kmq_msg_type *msg_types[KMQ_MSG_TYPE_MAX + 1]; -kmq_msg_type *all_msg_types = NULL; - -/*! \internal - \brief Initializes the message type data structures - \note called with cs_mkq_global held */ -void kmqint_init_msg_types(void) { - ZeroMemory(msg_types, sizeof(kmq_msg_type *) * (KMQ_MSG_TYPE_MAX + 1)); - InitializeCriticalSection(&cs_kmq_types); -} - -/*! \internal - \brief Frees up the message type data structures - \note called with cs_mkq_global held */ -void kmqint_exit_msg_types(void) { - int i; - - EnterCriticalSection(&cs_kmq_types); - for(i=0;itype]; - if(mt == NULL) - return 0; - h = mt->completion_handler; - - /* handler is set to NULL before freeing type */ - if(h == NULL || msg_types[m->type] == NULL) - return 0; - - return kmqint_call_completion_handler(h,m); -} - -/* called with cs_mkq_global && cs_kmq_types held */ -void kmqint_free_msg_type(int t) { - kmq_msg_type * pt; - kmq_msg_subscription * s; - - pt = msg_types[t]; - - msg_types[t] = NULL; - - if (pt == NULL) - return; - - /* all the subscriptions attached to a message type are owned by - the message type */ - LPOP(&pt->subs, &s); - while(s) { - s->magic = 0; - - PFREE(s); - - LPOP(&pt->subs, &s); - } - - pt->completion_handler = NULL; - - PFREE(pt); -} - -/*! \internal - \brief Create a message type - \note Obtains ::cs_kmq_types - */ -void kmqint_msg_type_create(int t) { - if(t < 0 || t > KMQ_MSG_TYPE_MAX) - return; - - EnterCriticalSection(&cs_kmq_types); - if(!msg_types[t]) { - kmq_msg_type * mt; - mt = PMALLOC(sizeof(kmq_msg_type)); - ZeroMemory(mt, sizeof(kmq_msg_type)); - mt->id = t; - LINIT(mt); - mt->subs = NULL; - msg_types[t] = mt; - - LPUSH(&all_msg_types, mt); - } - LeaveCriticalSection(&cs_kmq_types); -} - -KHMEXP khm_int32 KHMAPI kmq_register_type(wchar_t * name, - khm_int32 * new_id) -{ - int i; - khm_int32 rv = KHM_ERROR_SUCCESS; - BOOL registered = FALSE; - int first_free = 0; - size_t sz; - - if(FAILED(StringCbLength(name, KMQ_MAXCB_TYPE_NAME, &sz)) || - sz == 0) - return KHM_ERROR_INVALID_PARAM; - sz += sizeof(wchar_t); - - EnterCriticalSection(&cs_kmq_types); - for(i=KMSGBASE_USER; i <= KMQ_MSG_TYPE_MAX; i++) { - if(msg_types[i] == NULL) { - if(first_free == 0) - first_free = i; - /* continue searching since we might find that this type - is already registered. */ - } else { - if(msg_types[i]->name != NULL && - !wcscmp(msg_types[i]->name, name)) { - - registered = TRUE; - if (new_id) - *new_id = i; - break; - } - } - } - - if(registered) { - rv = KHM_ERROR_EXISTS; - } else if(first_free == 0) { - rv = KHM_ERROR_NO_RESOURCES; - } else { - kmqint_msg_type_create(first_free); - msg_types[first_free]->name = PMALLOC(sz); - StringCbCopy(msg_types[first_free]->name, sz, name); - - if(new_id != NULL) - *new_id = first_free; - } - LeaveCriticalSection(&cs_kmq_types); - - return rv; -} - -KHMEXP khm_int32 KHMAPI kmq_find_type(wchar_t * name, khm_int32 * id) -{ - int i; - - EnterCriticalSection(&cs_kmq_types); - for(i=KMSGBASE_USER; i <= KMQ_MSG_TYPE_MAX; i++) { - if(msg_types[i] != NULL && msg_types[i]->name != NULL) { - if(!wcscmp(msg_types[i]->name, name)) - break; - } - } - LeaveCriticalSection(&cs_kmq_types); - - if(i <= KMQ_MSG_TYPE_MAX) { - if(id != NULL) - *id = i; - return KHM_ERROR_SUCCESS; - } - - return KHM_ERROR_NOT_FOUND; -} - -KHMEXP khm_int32 KHMAPI kmq_unregister_type(khm_int32 id) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(id < KMSGBASE_USER || id > KMQ_MSG_TYPE_MAX) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_kmq_types); - if(msg_types[id] != NULL) { - EnterCriticalSection(&cs_kmq_global); - kmqint_free_msg_type(id); - LeaveCriticalSection(&cs_kmq_global); - } else { - rv = KHM_ERROR_NOT_FOUND; - } - LeaveCriticalSection(&cs_kmq_types); - - return rv; -} - -/*! \internal - \brief Adds a subscription to a message type - \note Obtains ::cs_kmq_types - */ -void kmqint_msg_type_add_sub(int t, kmq_msg_subscription *s) { - kmq_msg_subscription * ts; - - if(t < 0 || t > KMQ_MSG_TYPE_MAX) - return; - - if(!msg_types[t]) - kmqint_msg_type_create(t); - - EnterCriticalSection(&cs_kmq_types); - s->type = t; - /* check if we already have this subscription */ - ts = msg_types[t]->subs; - while(ts) { - if((ts->rcpt_type == s->rcpt_type) && - (((ts->rcpt_type == KMQ_RCPTTYPE_CB) && (ts->recipient.cb == s->recipient.cb)) || - ((ts->rcpt_type == KMQ_RCPTTYPE_HWND) && (ts->recipient.hwnd == s->recipient.hwnd)))) - break; - ts = LNEXT(ts); - } - /* add it if we didn't find it */ - if(!ts) { - LPUSH(&msg_types[t]->subs, s); - } - LeaveCriticalSection(&cs_kmq_types); -} - -/*! \internal - \brief Delete a subscription - \note Obtains ::cs_kmq_types - */ -void kmqint_msg_type_del_sub(kmq_msg_subscription *s) { - int t = s->type; - - EnterCriticalSection(&cs_kmq_types); - if(msg_types[t]) { - LDELETE(&msg_types[t]->subs,s); - } - LeaveCriticalSection(&cs_kmq_types); -} - - -/*! \internal - \brief Deletes a window subscription from a message type - \note Obtains ::cs_kmq_types -*/ -kmq_msg_subscription * kmqint_msg_type_del_sub_hwnd(khm_int32 t, HWND hwnd) { - kmq_msg_subscription *s = NULL; - - if(t < 0 || t > KMQ_MSG_TYPE_MAX) - return NULL; - - EnterCriticalSection(&cs_kmq_types); - if(msg_types[t]) { - s = msg_types[t]->subs; - while(s) { - kmq_msg_subscription * n = LNEXT(s); - if(s->rcpt_type == KMQ_RCPTTYPE_HWND && s->recipient.hwnd == hwnd) { - /*TODO: do more here? */ - LDELETE(&msg_types[t]->subs, s); - break; - } - s = n; - } - } - LeaveCriticalSection(&cs_kmq_types); - - return s; -} - -/*! \internal - \brief Delete a callback from a message type - \note Obtains ::cs_kmq_types, ::cs_kmq_global - */ -kmq_msg_subscription * kmqint_msg_type_del_sub_cb(khm_int32 t, kmq_callback_t cb) { - kmq_msg_subscription *s; - kmq_queue *q; - - if(t < 0 || t > KMQ_MSG_TYPE_MAX) - return NULL; - - if(!msg_types[t]) - return NULL; - - q = kmqint_get_thread_queue(); - - EnterCriticalSection(&cs_kmq_types); - s = msg_types[t]->subs; - while(s) { - kmq_msg_subscription * n = LNEXT(s); - if(s->rcpt_type == KMQ_RCPTTYPE_CB && - s->recipient.cb == cb && - s->queue == q) { - /*TODO: do more here? */ - LDELETE(&msg_types[t]->subs, s); - break; - } - s = n; - } - LeaveCriticalSection(&cs_kmq_types); - - return s; -} - -/*! \internal - \brief Publish a message - \note Obtains ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs, ::cs_kmq_msg - */ -khm_int32 kmqint_msg_publish(kmq_message * m, khm_boolean try_send) { - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(msg_types[m->type]) { - kmq_msg_type *t; - kmq_msg_subscription * s; - - EnterCriticalSection(&cs_kmq_types); - EnterCriticalSection(&cs_kmq_msg); - t = msg_types[m->type]; - s = t->subs; - while(s) { - kmqint_post(s, m, try_send); - s = LNEXT(s); - } - - if(m->nCompleted + m->nFailed == m->nSent) { - kmqint_put_message(m); - } - - LeaveCriticalSection(&cs_kmq_msg); - LeaveCriticalSection(&cs_kmq_types); - - } else { - EnterCriticalSection(&cs_kmq_msg); - kmqint_put_message(m); - LeaveCriticalSection(&cs_kmq_msg); - } - return rv; -} - -/*! \internal - \brief Sets the completion handler for a message type - \note Obtains ::cs_kmq_types - */ -khm_int32 kmqint_msg_type_set_handler(khm_int32 type, kmq_msg_completion_handler handler) { - - if (type == KMSG_SYSTEM) - return KHM_ERROR_INVALID_PARAM; - - if(!msg_types[type]) - kmqint_msg_type_create(type); - - if(!msg_types[type]) - return KHM_ERROR_NO_RESOURCES; - - EnterCriticalSection(&cs_kmq_types); - msg_types[type]->completion_handler = handler; - LeaveCriticalSection(&cs_kmq_types); - - return KHM_ERROR_SUCCESS; -} +/* + * 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 + +CRITICAL_SECTION cs_kmq_types; + +kmq_msg_type *msg_types[KMQ_MSG_TYPE_MAX + 1]; +kmq_msg_type *all_msg_types = NULL; + +/*! \internal + \brief Initializes the message type data structures + \note called with cs_mkq_global held */ +void kmqint_init_msg_types(void) { + ZeroMemory(msg_types, sizeof(kmq_msg_type *) * (KMQ_MSG_TYPE_MAX + 1)); + InitializeCriticalSection(&cs_kmq_types); +} + +/*! \internal + \brief Frees up the message type data structures + \note called with cs_mkq_global held */ +void kmqint_exit_msg_types(void) { + int i; + + EnterCriticalSection(&cs_kmq_types); + for(i=0;itype]; + if(mt == NULL) + return 0; + h = mt->completion_handler; + + /* handler is set to NULL before freeing type */ + if(h == NULL || msg_types[m->type] == NULL) + return 0; + + return kmqint_call_completion_handler(h,m); +} + +/* called with cs_mkq_global && cs_kmq_types held */ +void kmqint_free_msg_type(int t) { + kmq_msg_type * pt; + kmq_msg_subscription * s; + + pt = msg_types[t]; + + msg_types[t] = NULL; + + if (pt == NULL) + return; + + /* all the subscriptions attached to a message type are owned by + the message type */ + LPOP(&pt->subs, &s); + while(s) { + s->magic = 0; + + PFREE(s); + + LPOP(&pt->subs, &s); + } + + pt->completion_handler = NULL; + + PFREE(pt); +} + +/*! \internal + \brief Create a message type + \note Obtains ::cs_kmq_types + */ +void kmqint_msg_type_create(int t) { + if(t < 0 || t > KMQ_MSG_TYPE_MAX) + return; + + EnterCriticalSection(&cs_kmq_types); + if(!msg_types[t]) { + kmq_msg_type * mt; + mt = PMALLOC(sizeof(kmq_msg_type)); + ZeroMemory(mt, sizeof(kmq_msg_type)); + mt->id = t; + LINIT(mt); + mt->subs = NULL; + msg_types[t] = mt; + + LPUSH(&all_msg_types, mt); + } + LeaveCriticalSection(&cs_kmq_types); +} + +KHMEXP khm_int32 KHMAPI kmq_register_type(wchar_t * name, + khm_int32 * new_id) +{ + int i; + khm_int32 rv = KHM_ERROR_SUCCESS; + BOOL registered = FALSE; + int first_free = 0; + size_t sz; + + if(FAILED(StringCbLength(name, KMQ_MAXCB_TYPE_NAME, &sz)) || + sz == 0) + return KHM_ERROR_INVALID_PARAM; + sz += sizeof(wchar_t); + + EnterCriticalSection(&cs_kmq_types); + for(i=KMSGBASE_USER; i <= KMQ_MSG_TYPE_MAX; i++) { + if(msg_types[i] == NULL) { + if(first_free == 0) + first_free = i; + /* continue searching since we might find that this type + is already registered. */ + } else { + if(msg_types[i]->name != NULL && + !wcscmp(msg_types[i]->name, name)) { + + registered = TRUE; + if (new_id) + *new_id = i; + break; + } + } + } + + if(registered) { + rv = KHM_ERROR_EXISTS; + } else if(first_free == 0) { + rv = KHM_ERROR_NO_RESOURCES; + } else { + kmqint_msg_type_create(first_free); + msg_types[first_free]->name = PMALLOC(sz); + StringCbCopy(msg_types[first_free]->name, sz, name); + + if(new_id != NULL) + *new_id = first_free; + } + LeaveCriticalSection(&cs_kmq_types); + + return rv; +} + +KHMEXP khm_int32 KHMAPI kmq_find_type(wchar_t * name, khm_int32 * id) +{ + int i; + + EnterCriticalSection(&cs_kmq_types); + for(i=KMSGBASE_USER; i <= KMQ_MSG_TYPE_MAX; i++) { + if(msg_types[i] != NULL && msg_types[i]->name != NULL) { + if(!wcscmp(msg_types[i]->name, name)) + break; + } + } + LeaveCriticalSection(&cs_kmq_types); + + if(i <= KMQ_MSG_TYPE_MAX) { + if(id != NULL) + *id = i; + return KHM_ERROR_SUCCESS; + } + + return KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI kmq_unregister_type(khm_int32 id) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(id < KMSGBASE_USER || id > KMQ_MSG_TYPE_MAX) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_kmq_types); + if(msg_types[id] != NULL) { + EnterCriticalSection(&cs_kmq_global); + kmqint_free_msg_type(id); + LeaveCriticalSection(&cs_kmq_global); + } else { + rv = KHM_ERROR_NOT_FOUND; + } + LeaveCriticalSection(&cs_kmq_types); + + return rv; +} + +/*! \internal + \brief Adds a subscription to a message type + \note Obtains ::cs_kmq_types + */ +void kmqint_msg_type_add_sub(int t, kmq_msg_subscription *s) { + kmq_msg_subscription * ts; + + if(t < 0 || t > KMQ_MSG_TYPE_MAX) + return; + + if(!msg_types[t]) + kmqint_msg_type_create(t); + + EnterCriticalSection(&cs_kmq_types); + s->type = t; + /* check if we already have this subscription */ + ts = msg_types[t]->subs; + while(ts) { + if((ts->rcpt_type == s->rcpt_type) && + (((ts->rcpt_type == KMQ_RCPTTYPE_CB) && (ts->recipient.cb == s->recipient.cb)) || + ((ts->rcpt_type == KMQ_RCPTTYPE_HWND) && (ts->recipient.hwnd == s->recipient.hwnd)))) + break; + ts = LNEXT(ts); + } + /* add it if we didn't find it */ + if(!ts) { + LPUSH(&msg_types[t]->subs, s); + } + LeaveCriticalSection(&cs_kmq_types); +} + +/*! \internal + \brief Delete a subscription + \note Obtains ::cs_kmq_types + */ +void kmqint_msg_type_del_sub(kmq_msg_subscription *s) { + int t = s->type; + + EnterCriticalSection(&cs_kmq_types); + if(msg_types[t]) { + LDELETE(&msg_types[t]->subs,s); + } + LeaveCriticalSection(&cs_kmq_types); +} + + +/*! \internal + \brief Deletes a window subscription from a message type + \note Obtains ::cs_kmq_types +*/ +kmq_msg_subscription * kmqint_msg_type_del_sub_hwnd(khm_int32 t, HWND hwnd) { + kmq_msg_subscription *s = NULL; + + if(t < 0 || t > KMQ_MSG_TYPE_MAX) + return NULL; + + EnterCriticalSection(&cs_kmq_types); + if(msg_types[t]) { + s = msg_types[t]->subs; + while(s) { + kmq_msg_subscription * n = LNEXT(s); + if(s->rcpt_type == KMQ_RCPTTYPE_HWND && s->recipient.hwnd == hwnd) { + /*TODO: do more here? */ + LDELETE(&msg_types[t]->subs, s); + break; + } + s = n; + } + } + LeaveCriticalSection(&cs_kmq_types); + + return s; +} + +/*! \internal + \brief Delete a callback from a message type + \note Obtains ::cs_kmq_types, ::cs_kmq_global + */ +kmq_msg_subscription * kmqint_msg_type_del_sub_cb(khm_int32 t, kmq_callback_t cb) { + kmq_msg_subscription *s; + kmq_queue *q; + + if(t < 0 || t > KMQ_MSG_TYPE_MAX) + return NULL; + + if(!msg_types[t]) + return NULL; + + q = kmqint_get_thread_queue(); + + EnterCriticalSection(&cs_kmq_types); + s = msg_types[t]->subs; + while(s) { + kmq_msg_subscription * n = LNEXT(s); + if(s->rcpt_type == KMQ_RCPTTYPE_CB && + s->recipient.cb == cb && + s->queue == q) { + /*TODO: do more here? */ + LDELETE(&msg_types[t]->subs, s); + break; + } + s = n; + } + LeaveCriticalSection(&cs_kmq_types); + + return s; +} + +/*! \internal + \brief Publish a message + \note Obtains ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs, ::cs_kmq_msg + */ +khm_int32 kmqint_msg_publish(kmq_message * m, khm_boolean try_send) { + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(msg_types[m->type]) { + kmq_msg_type *t; + kmq_msg_subscription * s; + + EnterCriticalSection(&cs_kmq_types); + EnterCriticalSection(&cs_kmq_msg); + t = msg_types[m->type]; + s = t->subs; + while(s) { + kmqint_post(s, m, try_send); + s = LNEXT(s); + } + + if(m->nCompleted + m->nFailed == m->nSent) { + kmqint_put_message(m); + } + + LeaveCriticalSection(&cs_kmq_msg); + LeaveCriticalSection(&cs_kmq_types); + + } else { + EnterCriticalSection(&cs_kmq_msg); + kmqint_put_message(m); + LeaveCriticalSection(&cs_kmq_msg); + } + return rv; +} + +/*! \internal + \brief Sets the completion handler for a message type + \note Obtains ::cs_kmq_types + */ +khm_int32 kmqint_msg_type_set_handler(khm_int32 type, kmq_msg_completion_handler handler) { + + if (type == KMSG_SYSTEM) + return KHM_ERROR_INVALID_PARAM; + + if(!msg_types[type]) + kmqint_msg_type_create(type); + + if(!msg_types[type]) + return KHM_ERROR_NO_RESOURCES; + + EnterCriticalSection(&cs_kmq_types); + msg_types[type]->completion_handler = handler; + LeaveCriticalSection(&cs_kmq_types); + + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/kmq/publisher.c b/src/windows/identity/kmq/publisher.c index 66360fb50..2323837e2 100644 --- a/src/windows/identity/kmq/publisher.c +++ b/src/windows/identity/kmq/publisher.c @@ -1,556 +1,556 @@ -/* - * 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 - -CRITICAL_SECTION cs_kmq_msg; -kmq_message * msg_free = NULL; -kmq_message * msg_active = NULL; - -#ifdef DEBUG - -#include - -void -kmqint_dump_publisher(FILE * f) { - - int n_free = 0; - int n_active = 0; - kmq_message * m; - - EnterCriticalSection(&cs_kmq_msg); - - fprintf(f, "qp0\t*** Free Messages ***\n"); - fprintf(f, "qp1\tAddress\n"); - - m = msg_free; - while(m) { - n_free++; - - fprintf(f, "qp2\t0x%p\n", m); - - m = LNEXT(m); - } - - fprintf(f, "qp3\tTotal free messages : %d\n", n_free); - - fprintf(f, "qp4\t*** Active Messages ***\n"); - fprintf(f, "qp5\tAddress\tType\tSubtype\tuParam\tvParam\tnSent\tnCompleted\tnFailed\twait_o\trefcount\n"); - - m = msg_active; - while(m) { - - n_active++; - - fprintf(f, "qp6\t0x%p\t%d\t%d\t0x%x\t0x%p\t%d\t%d\t%d\t0x%p\t%d\n", - m, - (int) m->type, - (int) m->subtype, - (unsigned int) m->uparam, - m->vparam, - (int) m->nSent, - (int) m->nCompleted, - (int) m->nFailed, - (void *) m->wait_o, - (int) m->refcount); - - m = LNEXT(m); - } - - fprintf(f, "qp7\tTotal number of active messages = %d\n", n_active); - - fprintf(f, "qp8\t--- End ---\n"); - - LeaveCriticalSection(&cs_kmq_msg); - -} - -#endif - -/*! \internal - \brief Get a message object - \note called with ::cs_kmq_msg held */ -kmq_message * -kmqint_get_message(void) { - kmq_message * m; - - LPOP(&msg_free,&m); - if(!m) { - /* allocate one */ - m = PMALLOC(sizeof(kmq_message)); - } - ZeroMemory((void*)m, sizeof(kmq_message)); - - LPUSH(&msg_active, m); - - return m; -} - -/*! \internal - \brief Frees a message object - \note called with ::cs_kmq_msg held - */ -void -kmqint_put_message(kmq_message *m) { - int queued; - /* we can only free a message if the refcount is zero. - Otherwise we have to wait until the call is freed. */ - if(m->refcount == 0) { - LDELETE(&msg_active, m); - LeaveCriticalSection(&cs_kmq_msg); - queued = kmqint_notify_msg_completion(m); - EnterCriticalSection(&cs_kmq_msg); - if (!queued) { - if(m->err_ctx) { - kherr_release_context(m->err_ctx); - m->err_ctx = NULL; - } - if(m->wait_o) { - CloseHandle(m->wait_o); - m->wait_o = NULL; - } - LPUSH(&msg_free,m); - } - } else if(m->wait_o) { - SetEvent(m->wait_o); - } -} - -/*! \internal - \note Obtains ::cs_kmq_msg, ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs - */ -KHMEXP khm_int32 KHMAPI -kmq_send_message(khm_int32 type, khm_int32 subtype, - khm_ui_4 uparam, void * blob) { - kmq_call c; - khm_int32 rv = KHM_ERROR_SUCCESS; - - rv = kmqint_post_message_ex(type, subtype, uparam, blob, &c, TRUE); - if(KHM_FAILED(rv)) - return rv; - - rv = kmq_wait(c, INFINITE); - if(KHM_SUCCEEDED(rv) && c->nFailed > 0) - rv = KHM_ERROR_PARTIAL; - - kmq_free_call(c); - - return rv; -} - -/*! \internal - \note Obtains ::cs_kmq_msg, ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs - */ -KHMEXP khm_int32 KHMAPI -kmq_post_message(khm_int32 type, khm_int32 subtype, - khm_ui_4 uparam, void * blob) { - return kmqint_post_message_ex(type, subtype, uparam, blob, NULL, FALSE); -} - -/*! \internal - \brief Frees a call - \note Obtains ::cs_kmq_msg - */ -KHMEXP khm_int32 KHMAPI -kmq_free_call(kmq_call call) { - kmq_message * m; - - m = call; - - EnterCriticalSection(&cs_kmq_msg); - m->refcount--; - if(!m->refcount) { - kmqint_put_message(m); - } - LeaveCriticalSection(&cs_kmq_msg); - - return KHM_ERROR_SUCCESS; -} - -/*! \internal - \note Obtains ::cs_kmq_msg, ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs - */ -khm_int32 -kmqint_post_message_ex(khm_int32 type, khm_int32 subtype, khm_ui_4 uparam, - void * blob, kmq_call * call, khm_boolean try_send) -{ - kmq_message * m; - kherr_context * ctx; - - EnterCriticalSection(&cs_kmq_msg); - m = kmqint_get_message(); - LeaveCriticalSection(&cs_kmq_msg); - - m->type = type; - m->subtype = subtype; - m->uparam = uparam; - m->vparam = blob; - - m->timeSent = GetTickCount(); - m->timeExpire = m->timeSent + kmq_call_dead_timeout; - - ctx = kherr_peek_context(); - if (ctx) { - if (ctx->flags & KHERR_CF_TRANSITIVE) { - m->err_ctx = ctx; - /* leave it held */ - } else { - kherr_release_context(ctx); - } - } - - if(call) { - m->wait_o = CreateEvent(NULL,FALSE,FALSE,NULL); - *call = m; - m->refcount++; - } else - m->wait_o = NULL; - - kmqint_msg_publish(m, try_send); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kmq_post_message_ex(khm_int32 type, khm_int32 subtype, - khm_ui_4 uparam, void * blob, kmq_call * call) -{ - return kmqint_post_message_ex(type, subtype, uparam, blob, call, FALSE); -} - -KHMEXP khm_int32 KHMAPI -kmq_abort_call(kmq_call call) -{ - /* TODO: Implement this */ - return KHM_ERROR_NOT_IMPLEMENTED; -} - -/*! \internal -*/ -KHMEXP khm_int32 KHMAPI -kmq_post_sub_msg(khm_handle sub, khm_int32 type, khm_int32 subtype, - khm_ui_4 uparam, void * vparam) -{ - return kmq_post_sub_msg_ex(sub, type, subtype, uparam, vparam, NULL); -} - -/*! \internal -*/ -khm_int32 -kmqint_post_sub_msg_ex(khm_handle sub, khm_int32 type, khm_int32 subtype, - khm_ui_4 uparam, void * vparam, - kmq_call * call, khm_boolean try_send) -{ - kmq_message * m; - kherr_context * ctx; - - EnterCriticalSection(&cs_kmq_msg); - m = kmqint_get_message(); - LeaveCriticalSection(&cs_kmq_msg); - - m->type = type; - m->subtype = subtype; - m->uparam = uparam; - m->vparam = vparam; - - m->timeSent = GetTickCount(); - m->timeExpire = m->timeSent + kmq_call_dead_timeout; - - ctx = kherr_peek_context(); - if (ctx) { - if (ctx->flags & KHERR_CF_TRANSITIVE) { - m->err_ctx = ctx; - /* leave it held */ - } else { - kherr_release_context(ctx); - } - } - - if(call) { - m->wait_o = CreateEvent(NULL,FALSE,FALSE,NULL); - *call = m; - m->refcount++; - } else - m->wait_o = NULL; - - EnterCriticalSection(&cs_kmq_msg); - kmqint_post((kmq_msg_subscription *) sub, m, try_send); - - if(m->nCompleted + m->nFailed == m->nSent) { - kmqint_put_message(m); - } - LeaveCriticalSection(&cs_kmq_msg); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kmq_post_sub_msg_ex(khm_handle sub, khm_int32 type, khm_int32 subtype, - khm_ui_4 uparam, void * vparam, kmq_call * call) -{ - return kmqint_post_sub_msg_ex(sub, type, subtype, - uparam, vparam, call, FALSE); -} - -khm_int32 -kmqint_post_subs_msg_ex(khm_handle * subs, khm_size n_subs, khm_int32 type, - khm_int32 subtype, khm_ui_4 uparam, void * vparam, - kmq_call * call, khm_boolean try_send) -{ - kmq_message * m; - kherr_context * ctx; - khm_size i; - - if(n_subs == 0) - return KHM_ERROR_SUCCESS; - - EnterCriticalSection(&cs_kmq_msg); - m = kmqint_get_message(); - LeaveCriticalSection(&cs_kmq_msg); - - m->type = type; - m->subtype = subtype; - m->uparam = uparam; - m->vparam = vparam; - - m->timeSent = GetTickCount(); - m->timeExpire = m->timeSent + kmq_call_dead_timeout; - - ctx = kherr_peek_context(); - if (ctx) { - if (ctx->flags & KHERR_CF_TRANSITIVE) { - m->err_ctx = ctx; - /* leave it held */ - } else { - kherr_release_context(ctx); - } - } - - if(call) { - m->wait_o = CreateEvent(NULL,FALSE,FALSE,NULL); - *call = m; - m->refcount++; - } else - m->wait_o = NULL; - - EnterCriticalSection(&cs_kmq_msg); - for(i=0;inCompleted + m->nFailed == m->nSent) { - kmqint_put_message(m); - } - LeaveCriticalSection(&cs_kmq_msg); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kmq_post_subs_msg(khm_handle * subs, - khm_size n_subs, - khm_int32 type, - khm_int32 subtype, - khm_ui_4 uparam, - void * vparam) -{ - return kmqint_post_subs_msg_ex(subs, - n_subs, - type, - subtype, - uparam, - vparam, - NULL, - FALSE); -} - -KHMEXP khm_int32 KHMAPI -kmq_post_subs_msg_ex(khm_handle * subs, - khm_int32 n_subs, - khm_int32 type, - khm_int32 subtype, - khm_ui_4 uparam, - void * vparam, - kmq_call * call) -{ - return kmqint_post_subs_msg_ex(subs, n_subs, type, subtype, - uparam, vparam, call, FALSE); -} - -KHMEXP khm_int32 KHMAPI -kmq_send_subs_msg(khm_handle *subs, - khm_int32 n_subs, - khm_int32 type, - khm_int32 subtype, - khm_ui_4 uparam, - void * vparam) -{ - kmq_call c; - khm_int32 rv = KHM_ERROR_SUCCESS; - - rv = kmqint_post_subs_msg_ex(subs, n_subs, type, subtype, - uparam, vparam, &c, TRUE); - if(KHM_FAILED(rv)) - return rv; - - rv = kmq_wait(c, INFINITE); - if(KHM_SUCCEEDED(rv) && c->nFailed > 0) - rv = KHM_ERROR_PARTIAL; - - kmq_free_call(c); - - return rv; -} - -/*! \internal -*/ -KHMEXP khm_int32 KHMAPI -kmq_send_sub_msg(khm_handle sub, khm_int32 type, khm_int32 subtype, - khm_ui_4 uparam, void * vparam) -{ - kmq_call c; - khm_int32 rv = KHM_ERROR_SUCCESS; - - rv = kmqint_post_sub_msg_ex(sub, type, subtype, uparam, vparam, &c, TRUE); - if(KHM_FAILED(rv)) - return rv; - - rv = kmq_wait(c, INFINITE); - if(KHM_SUCCEEDED(rv) && c->nFailed > 0) - rv = KHM_ERROR_PARTIAL; - - kmq_free_call(c); - - return rv; -} - -/*! \internal - \note Obtains ::cs_kmq_global, ::cs_kmq_msg, ::cs_kmq_msg_ref, kmq_queue::cs - */ -KHMEXP khm_int32 KHMAPI -kmq_send_thread_quit_message(kmq_thread_id thread, khm_ui_4 uparam) { - kmq_call c; - khm_int32 rv = KHM_ERROR_SUCCESS; - - rv = kmq_post_thread_quit_message(thread, uparam, &c); - if(KHM_FAILED(rv)) - return rv; - - rv = kmq_wait(c, INFINITE); - - kmq_free_call(c); - - return rv; -} - -/*! \internal - \note Obtains ::cs_kmq_global, ::cs_kmq_msg, ::cs_kmq_msg_ref, kmq_queue::cs - */ -KHMEXP khm_int32 KHMAPI -kmq_post_thread_quit_message(kmq_thread_id thread, - khm_ui_4 uparam, kmq_call * call) { - kmq_message * m; - kmq_queue * q; - - EnterCriticalSection(&cs_kmq_global); - q = queues; - while(q) { - if(q->thread == thread) - break; - q = LNEXT(q); - } - LeaveCriticalSection(&cs_kmq_global); - - if(!q) - return KHM_ERROR_NOT_FOUND; - - EnterCriticalSection(&cs_kmq_msg); - m = kmqint_get_message(); - LeaveCriticalSection(&cs_kmq_msg); - - m->type = KMSG_SYSTEM; - m->subtype = KMSG_SYSTEM_EXIT; - m->uparam = uparam; - m->vparam = NULL; - - m->timeSent = GetTickCount(); - m->timeExpire = m->timeSent + kmq_call_dead_timeout; - - if(call) { - m->wait_o = CreateEvent(NULL,FALSE,FALSE,NULL); - *call = m; - m->refcount++; - } else - m->wait_o = NULL; - - kmqint_post_queue(q, m); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -kmq_get_next_response(kmq_call call, void ** resp) { - /* TODO: Implement this */ - return 0; -} - -KHMEXP khm_boolean KHMAPI -kmq_has_completed(kmq_call call) { - khm_boolean completed; - - EnterCriticalSection(&cs_kmq_msg); - completed = (call->nCompleted + call->nFailed == call->nSent); - LeaveCriticalSection(&cs_kmq_msg); - - return completed; -} - -KHMEXP khm_int32 KHMAPI -kmq_wait(kmq_call call, kmq_timer timeout) { - kmq_message * m = call; - DWORD rv; - /*TODO: check for call free */ - - if(m && m->wait_o) { - rv = WaitForSingleObject(m->wait_o, timeout); - if(rv == WAIT_OBJECT_0) - return KHM_ERROR_SUCCESS; - else - return KHM_ERROR_TIMEOUT; - } else - return KHM_ERROR_INVALID_PARAM; -} - -/*! \internal - \note Obtains ::cs_kmq_types - */ -KHMEXP khm_int32 KHMAPI -kmq_set_completion_handler(khm_int32 type, - kmq_msg_completion_handler handler) { - return kmqint_msg_type_set_handler(type, handler); -} - - +/* + * 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 + +CRITICAL_SECTION cs_kmq_msg; +kmq_message * msg_free = NULL; +kmq_message * msg_active = NULL; + +#ifdef DEBUG + +#include + +void +kmqint_dump_publisher(FILE * f) { + + int n_free = 0; + int n_active = 0; + kmq_message * m; + + EnterCriticalSection(&cs_kmq_msg); + + fprintf(f, "qp0\t*** Free Messages ***\n"); + fprintf(f, "qp1\tAddress\n"); + + m = msg_free; + while(m) { + n_free++; + + fprintf(f, "qp2\t0x%p\n", m); + + m = LNEXT(m); + } + + fprintf(f, "qp3\tTotal free messages : %d\n", n_free); + + fprintf(f, "qp4\t*** Active Messages ***\n"); + fprintf(f, "qp5\tAddress\tType\tSubtype\tuParam\tvParam\tnSent\tnCompleted\tnFailed\twait_o\trefcount\n"); + + m = msg_active; + while(m) { + + n_active++; + + fprintf(f, "qp6\t0x%p\t%d\t%d\t0x%x\t0x%p\t%d\t%d\t%d\t0x%p\t%d\n", + m, + (int) m->type, + (int) m->subtype, + (unsigned int) m->uparam, + m->vparam, + (int) m->nSent, + (int) m->nCompleted, + (int) m->nFailed, + (void *) m->wait_o, + (int) m->refcount); + + m = LNEXT(m); + } + + fprintf(f, "qp7\tTotal number of active messages = %d\n", n_active); + + fprintf(f, "qp8\t--- End ---\n"); + + LeaveCriticalSection(&cs_kmq_msg); + +} + +#endif + +/*! \internal + \brief Get a message object + \note called with ::cs_kmq_msg held */ +kmq_message * +kmqint_get_message(void) { + kmq_message * m; + + LPOP(&msg_free,&m); + if(!m) { + /* allocate one */ + m = PMALLOC(sizeof(kmq_message)); + } + ZeroMemory((void*)m, sizeof(kmq_message)); + + LPUSH(&msg_active, m); + + return m; +} + +/*! \internal + \brief Frees a message object + \note called with ::cs_kmq_msg held + */ +void +kmqint_put_message(kmq_message *m) { + int queued; + /* we can only free a message if the refcount is zero. + Otherwise we have to wait until the call is freed. */ + if(m->refcount == 0) { + LDELETE(&msg_active, m); + LeaveCriticalSection(&cs_kmq_msg); + queued = kmqint_notify_msg_completion(m); + EnterCriticalSection(&cs_kmq_msg); + if (!queued) { + if(m->err_ctx) { + kherr_release_context(m->err_ctx); + m->err_ctx = NULL; + } + if(m->wait_o) { + CloseHandle(m->wait_o); + m->wait_o = NULL; + } + LPUSH(&msg_free,m); + } + } else if(m->wait_o) { + SetEvent(m->wait_o); + } +} + +/*! \internal + \note Obtains ::cs_kmq_msg, ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs + */ +KHMEXP khm_int32 KHMAPI +kmq_send_message(khm_int32 type, khm_int32 subtype, + khm_ui_4 uparam, void * blob) { + kmq_call c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + rv = kmqint_post_message_ex(type, subtype, uparam, blob, &c, TRUE); + if(KHM_FAILED(rv)) + return rv; + + rv = kmq_wait(c, INFINITE); + if(KHM_SUCCEEDED(rv) && c->nFailed > 0) + rv = KHM_ERROR_PARTIAL; + + kmq_free_call(c); + + return rv; +} + +/*! \internal + \note Obtains ::cs_kmq_msg, ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs + */ +KHMEXP khm_int32 KHMAPI +kmq_post_message(khm_int32 type, khm_int32 subtype, + khm_ui_4 uparam, void * blob) { + return kmqint_post_message_ex(type, subtype, uparam, blob, NULL, FALSE); +} + +/*! \internal + \brief Frees a call + \note Obtains ::cs_kmq_msg + */ +KHMEXP khm_int32 KHMAPI +kmq_free_call(kmq_call call) { + kmq_message * m; + + m = call; + + EnterCriticalSection(&cs_kmq_msg); + m->refcount--; + if(!m->refcount) { + kmqint_put_message(m); + } + LeaveCriticalSection(&cs_kmq_msg); + + return KHM_ERROR_SUCCESS; +} + +/*! \internal + \note Obtains ::cs_kmq_msg, ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs + */ +khm_int32 +kmqint_post_message_ex(khm_int32 type, khm_int32 subtype, khm_ui_4 uparam, + void * blob, kmq_call * call, khm_boolean try_send) +{ + kmq_message * m; + kherr_context * ctx; + + EnterCriticalSection(&cs_kmq_msg); + m = kmqint_get_message(); + LeaveCriticalSection(&cs_kmq_msg); + + m->type = type; + m->subtype = subtype; + m->uparam = uparam; + m->vparam = blob; + + m->timeSent = GetTickCount(); + m->timeExpire = m->timeSent + kmq_call_dead_timeout; + + ctx = kherr_peek_context(); + if (ctx) { + if (ctx->flags & KHERR_CF_TRANSITIVE) { + m->err_ctx = ctx; + /* leave it held */ + } else { + kherr_release_context(ctx); + } + } + + if(call) { + m->wait_o = CreateEvent(NULL,FALSE,FALSE,NULL); + *call = m; + m->refcount++; + } else + m->wait_o = NULL; + + kmqint_msg_publish(m, try_send); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kmq_post_message_ex(khm_int32 type, khm_int32 subtype, + khm_ui_4 uparam, void * blob, kmq_call * call) +{ + return kmqint_post_message_ex(type, subtype, uparam, blob, call, FALSE); +} + +KHMEXP khm_int32 KHMAPI +kmq_abort_call(kmq_call call) +{ + /* TODO: Implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} + +/*! \internal +*/ +KHMEXP khm_int32 KHMAPI +kmq_post_sub_msg(khm_handle sub, khm_int32 type, khm_int32 subtype, + khm_ui_4 uparam, void * vparam) +{ + return kmq_post_sub_msg_ex(sub, type, subtype, uparam, vparam, NULL); +} + +/*! \internal +*/ +khm_int32 +kmqint_post_sub_msg_ex(khm_handle sub, khm_int32 type, khm_int32 subtype, + khm_ui_4 uparam, void * vparam, + kmq_call * call, khm_boolean try_send) +{ + kmq_message * m; + kherr_context * ctx; + + EnterCriticalSection(&cs_kmq_msg); + m = kmqint_get_message(); + LeaveCriticalSection(&cs_kmq_msg); + + m->type = type; + m->subtype = subtype; + m->uparam = uparam; + m->vparam = vparam; + + m->timeSent = GetTickCount(); + m->timeExpire = m->timeSent + kmq_call_dead_timeout; + + ctx = kherr_peek_context(); + if (ctx) { + if (ctx->flags & KHERR_CF_TRANSITIVE) { + m->err_ctx = ctx; + /* leave it held */ + } else { + kherr_release_context(ctx); + } + } + + if(call) { + m->wait_o = CreateEvent(NULL,FALSE,FALSE,NULL); + *call = m; + m->refcount++; + } else + m->wait_o = NULL; + + EnterCriticalSection(&cs_kmq_msg); + kmqint_post((kmq_msg_subscription *) sub, m, try_send); + + if(m->nCompleted + m->nFailed == m->nSent) { + kmqint_put_message(m); + } + LeaveCriticalSection(&cs_kmq_msg); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kmq_post_sub_msg_ex(khm_handle sub, khm_int32 type, khm_int32 subtype, + khm_ui_4 uparam, void * vparam, kmq_call * call) +{ + return kmqint_post_sub_msg_ex(sub, type, subtype, + uparam, vparam, call, FALSE); +} + +khm_int32 +kmqint_post_subs_msg_ex(khm_handle * subs, khm_size n_subs, khm_int32 type, + khm_int32 subtype, khm_ui_4 uparam, void * vparam, + kmq_call * call, khm_boolean try_send) +{ + kmq_message * m; + kherr_context * ctx; + khm_size i; + + if(n_subs == 0) + return KHM_ERROR_SUCCESS; + + EnterCriticalSection(&cs_kmq_msg); + m = kmqint_get_message(); + LeaveCriticalSection(&cs_kmq_msg); + + m->type = type; + m->subtype = subtype; + m->uparam = uparam; + m->vparam = vparam; + + m->timeSent = GetTickCount(); + m->timeExpire = m->timeSent + kmq_call_dead_timeout; + + ctx = kherr_peek_context(); + if (ctx) { + if (ctx->flags & KHERR_CF_TRANSITIVE) { + m->err_ctx = ctx; + /* leave it held */ + } else { + kherr_release_context(ctx); + } + } + + if(call) { + m->wait_o = CreateEvent(NULL,FALSE,FALSE,NULL); + *call = m; + m->refcount++; + } else + m->wait_o = NULL; + + EnterCriticalSection(&cs_kmq_msg); + for(i=0;inCompleted + m->nFailed == m->nSent) { + kmqint_put_message(m); + } + LeaveCriticalSection(&cs_kmq_msg); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kmq_post_subs_msg(khm_handle * subs, + khm_size n_subs, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam) +{ + return kmqint_post_subs_msg_ex(subs, + n_subs, + type, + subtype, + uparam, + vparam, + NULL, + FALSE); +} + +KHMEXP khm_int32 KHMAPI +kmq_post_subs_msg_ex(khm_handle * subs, + khm_int32 n_subs, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam, + kmq_call * call) +{ + return kmqint_post_subs_msg_ex(subs, n_subs, type, subtype, + uparam, vparam, call, FALSE); +} + +KHMEXP khm_int32 KHMAPI +kmq_send_subs_msg(khm_handle *subs, + khm_int32 n_subs, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam) +{ + kmq_call c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + rv = kmqint_post_subs_msg_ex(subs, n_subs, type, subtype, + uparam, vparam, &c, TRUE); + if(KHM_FAILED(rv)) + return rv; + + rv = kmq_wait(c, INFINITE); + if(KHM_SUCCEEDED(rv) && c->nFailed > 0) + rv = KHM_ERROR_PARTIAL; + + kmq_free_call(c); + + return rv; +} + +/*! \internal +*/ +KHMEXP khm_int32 KHMAPI +kmq_send_sub_msg(khm_handle sub, khm_int32 type, khm_int32 subtype, + khm_ui_4 uparam, void * vparam) +{ + kmq_call c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + rv = kmqint_post_sub_msg_ex(sub, type, subtype, uparam, vparam, &c, TRUE); + if(KHM_FAILED(rv)) + return rv; + + rv = kmq_wait(c, INFINITE); + if(KHM_SUCCEEDED(rv) && c->nFailed > 0) + rv = KHM_ERROR_PARTIAL; + + kmq_free_call(c); + + return rv; +} + +/*! \internal + \note Obtains ::cs_kmq_global, ::cs_kmq_msg, ::cs_kmq_msg_ref, kmq_queue::cs + */ +KHMEXP khm_int32 KHMAPI +kmq_send_thread_quit_message(kmq_thread_id thread, khm_ui_4 uparam) { + kmq_call c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + rv = kmq_post_thread_quit_message(thread, uparam, &c); + if(KHM_FAILED(rv)) + return rv; + + rv = kmq_wait(c, INFINITE); + + kmq_free_call(c); + + return rv; +} + +/*! \internal + \note Obtains ::cs_kmq_global, ::cs_kmq_msg, ::cs_kmq_msg_ref, kmq_queue::cs + */ +KHMEXP khm_int32 KHMAPI +kmq_post_thread_quit_message(kmq_thread_id thread, + khm_ui_4 uparam, kmq_call * call) { + kmq_message * m; + kmq_queue * q; + + EnterCriticalSection(&cs_kmq_global); + q = queues; + while(q) { + if(q->thread == thread) + break; + q = LNEXT(q); + } + LeaveCriticalSection(&cs_kmq_global); + + if(!q) + return KHM_ERROR_NOT_FOUND; + + EnterCriticalSection(&cs_kmq_msg); + m = kmqint_get_message(); + LeaveCriticalSection(&cs_kmq_msg); + + m->type = KMSG_SYSTEM; + m->subtype = KMSG_SYSTEM_EXIT; + m->uparam = uparam; + m->vparam = NULL; + + m->timeSent = GetTickCount(); + m->timeExpire = m->timeSent + kmq_call_dead_timeout; + + if(call) { + m->wait_o = CreateEvent(NULL,FALSE,FALSE,NULL); + *call = m; + m->refcount++; + } else + m->wait_o = NULL; + + kmqint_post_queue(q, m); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kmq_get_next_response(kmq_call call, void ** resp) { + /* TODO: Implement this */ + return 0; +} + +KHMEXP khm_boolean KHMAPI +kmq_has_completed(kmq_call call) { + khm_boolean completed; + + EnterCriticalSection(&cs_kmq_msg); + completed = (call->nCompleted + call->nFailed == call->nSent); + LeaveCriticalSection(&cs_kmq_msg); + + return completed; +} + +KHMEXP khm_int32 KHMAPI +kmq_wait(kmq_call call, kmq_timer timeout) { + kmq_message * m = call; + DWORD rv; + /*TODO: check for call free */ + + if(m && m->wait_o) { + rv = WaitForSingleObject(m->wait_o, timeout); + if(rv == WAIT_OBJECT_0) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_TIMEOUT; + } else + return KHM_ERROR_INVALID_PARAM; +} + +/*! \internal + \note Obtains ::cs_kmq_types + */ +KHMEXP khm_int32 KHMAPI +kmq_set_completion_handler(khm_int32 type, + kmq_msg_completion_handler handler) { + return kmqint_msg_type_set_handler(type, handler); +} + + diff --git a/src/windows/identity/nidmgrdll/dllmain.c b/src/windows/identity/nidmgrdll/dllmain.c index e54e28137..696911df4 100644 --- a/src/windows/identity/nidmgrdll/dllmain.c +++ b/src/windows/identity/nidmgrdll/dllmain.c @@ -1,114 +1,114 @@ -/* - * 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 - -/* forward dcls */ -void -kherr_process_attach(void); - -void -kherr_process_detach(void); - -void -kherr_thread_attach(void); - -void -kherr_thread_detach(void); - -void -kconfig_process_attach(void); - -void -kconfig_process_detach(void); - -void -kmq_process_attach(void); - -void -kmq_process_detach(void); - -void -kmq_thread_attach(void); - -void -kmq_thread_detach(void); - -void -kcdb_process_attach(HINSTANCE); - -void -kcdb_process_detach(void); - -void -kmm_process_attach(HINSTANCE); - -void -kmm_process_detach(void); - -void -uilib_process_attach(void); - -void -uilib_process_detach(void); - - -BOOL WINAPI DllMain( - HINSTANCE hinstDLL, // handle to DLL module - DWORD fdwReason, // reason for calling function - LPVOID lpReserved ) // reserved -{ - switch(fdwReason) { - case DLL_PROCESS_ATTACH: - kherr_process_attach(); - kconfig_process_attach(); - kmq_process_attach(); - kcdb_process_attach(hinstDLL); - kmm_process_attach(hinstDLL); - uilib_process_attach(); - break; - - case DLL_PROCESS_DETACH: - kherr_process_detach(); - kconfig_process_detach(); - kmq_process_detach(); - kcdb_process_detach(); - kmm_process_detach(); - uilib_process_detach(); - break; - - case DLL_THREAD_ATTACH: - kherr_thread_attach(); - kmq_thread_attach(); - break; - - case DLL_THREAD_DETACH: - kherr_thread_detach(); - kmq_thread_detach(); - break; - } - return TRUE; -} +/* + * 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 + +/* forward dcls */ +void +kherr_process_attach(void); + +void +kherr_process_detach(void); + +void +kherr_thread_attach(void); + +void +kherr_thread_detach(void); + +void +kconfig_process_attach(void); + +void +kconfig_process_detach(void); + +void +kmq_process_attach(void); + +void +kmq_process_detach(void); + +void +kmq_thread_attach(void); + +void +kmq_thread_detach(void); + +void +kcdb_process_attach(HINSTANCE); + +void +kcdb_process_detach(void); + +void +kmm_process_attach(HINSTANCE); + +void +kmm_process_detach(void); + +void +uilib_process_attach(void); + +void +uilib_process_detach(void); + + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, // handle to DLL module + DWORD fdwReason, // reason for calling function + LPVOID lpReserved ) // reserved +{ + switch(fdwReason) { + case DLL_PROCESS_ATTACH: + kherr_process_attach(); + kconfig_process_attach(); + kmq_process_attach(); + kcdb_process_attach(hinstDLL); + kmm_process_attach(hinstDLL); + uilib_process_attach(); + break; + + case DLL_PROCESS_DETACH: + kherr_process_detach(); + kconfig_process_detach(); + kmq_process_detach(); + kcdb_process_detach(); + kmm_process_detach(); + uilib_process_detach(); + break; + + case DLL_THREAD_ATTACH: + kherr_thread_attach(); + kmq_thread_attach(); + break; + + case DLL_THREAD_DETACH: + kherr_thread_detach(); + kmq_thread_detach(); + break; + } + return TRUE; +} diff --git a/src/windows/identity/plugins/common/dynimport.c b/src/windows/identity/plugins/common/dynimport.c index f49987ca7..24fa1a551 100644 --- a/src/windows/identity/plugins/common/dynimport.c +++ b/src/windows/identity/plugins/common/dynimport.c @@ -1,477 +1,477 @@ -/* -* Copyright (c) 2005 Massachusetts Institute of Technology -* Copyright (c) 2007 Secure Endpoints Inc. -* -* 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 - -HINSTANCE hKrb4 = 0; -HINSTANCE hKrb5 = 0; -HINSTANCE hKrb524 = 0; -HINSTANCE hSecur32 = 0; -HINSTANCE hComErr = 0; -HINSTANCE hService = 0; -HINSTANCE hProfile = 0; -HINSTANCE hPsapi = 0; -HINSTANCE hToolHelp32 = 0; -HINSTANCE hCCAPI = 0; - -DWORD AfsAvailable = 0; - -// CCAPI -DECL_FUNC_PTR(cc_initialize); -DECL_FUNC_PTR(cc_shutdown); -DECL_FUNC_PTR(cc_get_NC_info); -DECL_FUNC_PTR(cc_free_NC_info); - -// krb4 functions -DECL_FUNC_PTR(get_krb_err_txt_entry); -DECL_FUNC_PTR(k_isinst); -DECL_FUNC_PTR(k_isname); -DECL_FUNC_PTR(k_isrealm); -DECL_FUNC_PTR(kadm_change_your_password); -DECL_FUNC_PTR(kname_parse); -DECL_FUNC_PTR(krb_get_cred); -DECL_FUNC_PTR(krb_get_krbhst); -DECL_FUNC_PTR(krb_get_lrealm); -DECL_FUNC_PTR(krb_get_pw_in_tkt); -DECL_FUNC_PTR(krb_get_tf_realm); -DECL_FUNC_PTR(krb_mk_req); -DECL_FUNC_PTR(krb_realmofhost); -DECL_FUNC_PTR(tf_init); -DECL_FUNC_PTR(tf_close); -DECL_FUNC_PTR(tf_get_cred); -DECL_FUNC_PTR(tf_get_pname); -DECL_FUNC_PTR(tf_get_pinst); -DECL_FUNC_PTR(LocalHostAddr); -DECL_FUNC_PTR(tkt_string); -DECL_FUNC_PTR(krb_set_tkt_string); -DECL_FUNC_PTR(initialize_krb_error_func); -DECL_FUNC_PTR(initialize_kadm_error_table); -DECL_FUNC_PTR(dest_tkt); -DECL_FUNC_PTR(krb_in_tkt); -DECL_FUNC_PTR(krb_save_credentials); -DECL_FUNC_PTR(krb_get_krbconf2); -DECL_FUNC_PTR(krb_get_krbrealm2); -DECL_FUNC_PTR(krb_life_to_time); - -// krb5 functions -DECL_FUNC_PTR(krb5_change_password); -DECL_FUNC_PTR(krb5_get_init_creds_opt_init); -DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life); -DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); -DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable); -DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable); -DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list); -DECL_FUNC_PTR(krb5_get_init_creds_opt_set_change_password_prompt); -DECL_FUNC_PTR(krb5_get_init_creds_password); -DECL_FUNC_PTR(krb5_get_prompt_types); -DECL_FUNC_PTR(krb5_build_principal_ext); -DECL_FUNC_PTR(krb5_cc_get_name); -DECL_FUNC_PTR(krb5_cc_get_type); -DECL_FUNC_PTR(krb5_cc_resolve); -DECL_FUNC_PTR(krb5_cc_default); -DECL_FUNC_PTR(krb5_cc_default_name); -DECL_FUNC_PTR(krb5_cc_set_default_name); -DECL_FUNC_PTR(krb5_cc_initialize); -DECL_FUNC_PTR(krb5_cc_destroy); -DECL_FUNC_PTR(krb5_cc_close); -DECL_FUNC_PTR(krb5_cc_store_cred); -DECL_FUNC_PTR(krb5_cc_copy_creds); -DECL_FUNC_PTR(krb5_cc_retrieve_cred); -DECL_FUNC_PTR(krb5_cc_get_principal); -DECL_FUNC_PTR(krb5_cc_start_seq_get); -DECL_FUNC_PTR(krb5_cc_next_cred); -DECL_FUNC_PTR(krb5_cc_end_seq_get); -DECL_FUNC_PTR(krb5_cc_remove_cred); -DECL_FUNC_PTR(krb5_cc_set_flags); -// DECL_FUNC_PTR(krb5_cc_get_type); -DECL_FUNC_PTR(krb5_free_context); -DECL_FUNC_PTR(krb5_free_cred_contents); -DECL_FUNC_PTR(krb5_free_principal); -DECL_FUNC_PTR(krb5_get_in_tkt_with_password); -DECL_FUNC_PTR(krb5_init_context); -DECL_FUNC_PTR(krb5_parse_name); -DECL_FUNC_PTR(krb5_timeofday); -DECL_FUNC_PTR(krb5_timestamp_to_sfstring); -DECL_FUNC_PTR(krb5_unparse_name); -DECL_FUNC_PTR(krb5_get_credentials); -DECL_FUNC_PTR(krb5_mk_req); -DECL_FUNC_PTR(krb5_sname_to_principal); -DECL_FUNC_PTR(krb5_get_credentials_renew); -DECL_FUNC_PTR(krb5_free_data); -DECL_FUNC_PTR(krb5_free_data_contents); -// DECL_FUNC_PTR(krb5_get_realm_domain); -DECL_FUNC_PTR(krb5_free_unparsed_name); -DECL_FUNC_PTR(krb5_os_localaddr); -DECL_FUNC_PTR(krb5_copy_keyblock_contents); -DECL_FUNC_PTR(krb5_copy_data); -DECL_FUNC_PTR(krb5_free_creds); -DECL_FUNC_PTR(krb5_build_principal); -DECL_FUNC_PTR(krb5_get_renewed_creds); -DECL_FUNC_PTR(krb5_get_default_config_files); -DECL_FUNC_PTR(krb5_free_config_files); -DECL_FUNC_PTR(krb5_get_default_realm); -DECL_FUNC_PTR(krb5_set_default_realm); -DECL_FUNC_PTR(krb5_free_ticket); -DECL_FUNC_PTR(krb5_decode_ticket); -DECL_FUNC_PTR(krb5_get_host_realm); -DECL_FUNC_PTR(krb5_free_host_realm); -DECL_FUNC_PTR(krb5_c_random_make_octets); -DECL_FUNC_PTR(krb5_free_addresses); -DECL_FUNC_PTR(krb5_free_default_realm); -DECL_FUNC_PTR(krb5_string_to_deltat); - -// Krb524 functions -DECL_FUNC_PTR(krb524_init_ets); -DECL_FUNC_PTR(krb524_convert_creds_kdc); - -// ComErr functions -DECL_FUNC_PTR(com_err); -DECL_FUNC_PTR(error_message); - -// Profile functions -DECL_FUNC_PTR(profile_init); -DECL_FUNC_PTR(profile_flush); -DECL_FUNC_PTR(profile_release); -DECL_FUNC_PTR(profile_get_subsection_names); -DECL_FUNC_PTR(profile_free_list); -DECL_FUNC_PTR(profile_get_string); -DECL_FUNC_PTR(profile_get_integer); -DECL_FUNC_PTR(profile_get_values); -DECL_FUNC_PTR(profile_get_relation_names); -DECL_FUNC_PTR(profile_clear_relation); -DECL_FUNC_PTR(profile_add_relation); -DECL_FUNC_PTR(profile_update_relation); -DECL_FUNC_PTR(profile_release_string); -DECL_FUNC_PTR(profile_rename_section); - -// Service functions -DECL_FUNC_PTR(OpenSCManagerA); -DECL_FUNC_PTR(OpenServiceA); -DECL_FUNC_PTR(QueryServiceStatus); -DECL_FUNC_PTR(CloseServiceHandle); -DECL_FUNC_PTR(LsaNtStatusToWinError); - -// LSA Functions -DECL_FUNC_PTR(LsaConnectUntrusted); -DECL_FUNC_PTR(LsaLookupAuthenticationPackage); -DECL_FUNC_PTR(LsaCallAuthenticationPackage); -DECL_FUNC_PTR(LsaFreeReturnBuffer); -DECL_FUNC_PTR(LsaGetLogonSessionData); - -// CCAPI -FUNC_INFO ccapi_fi[] = { - MAKE_FUNC_INFO(cc_initialize), - MAKE_FUNC_INFO(cc_shutdown), - MAKE_FUNC_INFO(cc_get_NC_info), - MAKE_FUNC_INFO(cc_free_NC_info), - END_FUNC_INFO -}; - -FUNC_INFO k4_fi[] = { - MAKE_FUNC_INFO(get_krb_err_txt_entry), - MAKE_FUNC_INFO(k_isinst), - MAKE_FUNC_INFO(k_isname), - MAKE_FUNC_INFO(k_isrealm), - MAKE_FUNC_INFO(kadm_change_your_password), - MAKE_FUNC_INFO(kname_parse), - MAKE_FUNC_INFO(krb_get_cred), - MAKE_FUNC_INFO(krb_get_krbhst), - MAKE_FUNC_INFO(krb_get_lrealm), - MAKE_FUNC_INFO(krb_get_pw_in_tkt), - MAKE_FUNC_INFO(krb_get_tf_realm), - MAKE_FUNC_INFO(krb_mk_req), - MAKE_FUNC_INFO(krb_realmofhost), - MAKE_FUNC_INFO(tf_init), - MAKE_FUNC_INFO(tf_close), - MAKE_FUNC_INFO(tf_get_cred), - MAKE_FUNC_INFO(tf_get_pname), - MAKE_FUNC_INFO(tf_get_pinst), - MAKE_FUNC_INFO(LocalHostAddr), - MAKE_FUNC_INFO(tkt_string), - MAKE_FUNC_INFO(krb_set_tkt_string), - MAKE_FUNC_INFO(initialize_krb_error_func), - MAKE_FUNC_INFO(initialize_kadm_error_table), - MAKE_FUNC_INFO(dest_tkt), - /* MAKE_FUNC_INFO(lsh_LoadKrb4LeashErrorTables), */// XXX - MAKE_FUNC_INFO(krb_in_tkt), - MAKE_FUNC_INFO(krb_save_credentials), - MAKE_FUNC_INFO(krb_get_krbconf2), - MAKE_FUNC_INFO(krb_get_krbrealm2), - MAKE_FUNC_INFO(krb_life_to_time), - END_FUNC_INFO -}; - -FUNC_INFO k5_fi[] = { - MAKE_FUNC_INFO(krb5_change_password), - MAKE_FUNC_INFO(krb5_get_init_creds_opt_init), - MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life), - MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life), - MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable), - MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable), - MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list), - MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_change_password_prompt), - MAKE_FUNC_INFO(krb5_get_init_creds_password), - MAKE_FUNC_INFO(krb5_get_prompt_types), - MAKE_FUNC_INFO(krb5_build_principal_ext), - MAKE_FUNC_INFO(krb5_cc_get_name), - MAKE_FUNC_INFO(krb5_cc_get_type), - MAKE_FUNC_INFO(krb5_cc_resolve), - MAKE_FUNC_INFO(krb5_cc_default), - MAKE_FUNC_INFO(krb5_cc_default_name), - MAKE_FUNC_INFO(krb5_cc_set_default_name), - MAKE_FUNC_INFO(krb5_cc_initialize), - MAKE_FUNC_INFO(krb5_cc_destroy), - MAKE_FUNC_INFO(krb5_cc_close), - MAKE_FUNC_INFO(krb5_cc_copy_creds), - MAKE_FUNC_INFO(krb5_cc_store_cred), - MAKE_FUNC_INFO(krb5_cc_retrieve_cred), - MAKE_FUNC_INFO(krb5_cc_get_principal), - MAKE_FUNC_INFO(krb5_cc_start_seq_get), - MAKE_FUNC_INFO(krb5_cc_next_cred), - MAKE_FUNC_INFO(krb5_cc_end_seq_get), - MAKE_FUNC_INFO(krb5_cc_remove_cred), - MAKE_FUNC_INFO(krb5_cc_set_flags), - // MAKE_FUNC_INFO(krb5_cc_get_type), - MAKE_FUNC_INFO(krb5_free_context), - MAKE_FUNC_INFO(krb5_free_cred_contents), - MAKE_FUNC_INFO(krb5_free_principal), - MAKE_FUNC_INFO(krb5_get_in_tkt_with_password), - MAKE_FUNC_INFO(krb5_init_context), - MAKE_FUNC_INFO(krb5_parse_name), - MAKE_FUNC_INFO(krb5_timeofday), - MAKE_FUNC_INFO(krb5_timestamp_to_sfstring), - MAKE_FUNC_INFO(krb5_unparse_name), - MAKE_FUNC_INFO(krb5_get_credentials), - MAKE_FUNC_INFO(krb5_mk_req), - MAKE_FUNC_INFO(krb5_sname_to_principal), - MAKE_FUNC_INFO(krb5_get_credentials_renew), - MAKE_FUNC_INFO(krb5_free_data), - MAKE_FUNC_INFO(krb5_free_data_contents), - // MAKE_FUNC_INFO(krb5_get_realm_domain), - MAKE_FUNC_INFO(krb5_free_unparsed_name), - MAKE_FUNC_INFO(krb5_os_localaddr), - MAKE_FUNC_INFO(krb5_copy_keyblock_contents), - MAKE_FUNC_INFO(krb5_copy_data), - MAKE_FUNC_INFO(krb5_free_creds), - MAKE_FUNC_INFO(krb5_build_principal), - MAKE_FUNC_INFO(krb5_get_renewed_creds), - MAKE_FUNC_INFO(krb5_free_addresses), - MAKE_FUNC_INFO(krb5_get_default_config_files), - MAKE_FUNC_INFO(krb5_free_config_files), - MAKE_FUNC_INFO(krb5_get_default_realm), - MAKE_FUNC_INFO(krb5_set_default_realm), - MAKE_FUNC_INFO(krb5_free_ticket), - MAKE_FUNC_INFO(krb5_decode_ticket), - MAKE_FUNC_INFO(krb5_get_host_realm), - MAKE_FUNC_INFO(krb5_free_host_realm), - MAKE_FUNC_INFO(krb5_c_random_make_octets), - MAKE_FUNC_INFO(krb5_free_default_realm), - MAKE_FUNC_INFO(krb5_string_to_deltat), - END_FUNC_INFO -}; - -FUNC_INFO k524_fi[] = { - MAKE_FUNC_INFO(krb524_init_ets), - MAKE_FUNC_INFO(krb524_convert_creds_kdc), - END_FUNC_INFO -}; - -FUNC_INFO profile_fi[] = { - MAKE_FUNC_INFO(profile_init), - MAKE_FUNC_INFO(profile_flush), - MAKE_FUNC_INFO(profile_release), - MAKE_FUNC_INFO(profile_get_subsection_names), - MAKE_FUNC_INFO(profile_free_list), - MAKE_FUNC_INFO(profile_get_string), - MAKE_FUNC_INFO(profile_get_integer), - MAKE_FUNC_INFO(profile_get_values), - MAKE_FUNC_INFO(profile_get_relation_names), - MAKE_FUNC_INFO(profile_clear_relation), - MAKE_FUNC_INFO(profile_add_relation), - MAKE_FUNC_INFO(profile_update_relation), - MAKE_FUNC_INFO(profile_release_string), - MAKE_FUNC_INFO(profile_rename_section), - END_FUNC_INFO -}; - -FUNC_INFO ce_fi[] = { - MAKE_FUNC_INFO(com_err), - MAKE_FUNC_INFO(error_message), - END_FUNC_INFO -}; - -FUNC_INFO service_fi[] = { - MAKE_FUNC_INFO(OpenSCManagerA), - MAKE_FUNC_INFO(OpenServiceA), - MAKE_FUNC_INFO(QueryServiceStatus), - MAKE_FUNC_INFO(CloseServiceHandle), - MAKE_FUNC_INFO(LsaNtStatusToWinError), - END_FUNC_INFO -}; - -FUNC_INFO lsa_fi[] = { - MAKE_FUNC_INFO(LsaConnectUntrusted), - MAKE_FUNC_INFO(LsaLookupAuthenticationPackage), - MAKE_FUNC_INFO(LsaCallAuthenticationPackage), - MAKE_FUNC_INFO(LsaFreeReturnBuffer), - MAKE_FUNC_INFO(LsaGetLogonSessionData), - END_FUNC_INFO -}; - -// psapi functions -DECL_FUNC_PTR(GetModuleFileNameExA); -DECL_FUNC_PTR(EnumProcessModules); - -FUNC_INFO psapi_fi[] = { - MAKE_FUNC_INFO(GetModuleFileNameExA), - MAKE_FUNC_INFO(EnumProcessModules), - END_FUNC_INFO -}; - -// toolhelp functions -DECL_FUNC_PTR(CreateToolhelp32Snapshot); -DECL_FUNC_PTR(Module32First); -DECL_FUNC_PTR(Module32Next); - -FUNC_INFO toolhelp_fi[] = { - MAKE_FUNC_INFO(CreateToolhelp32Snapshot), - MAKE_FUNC_INFO(Module32First), - MAKE_FUNC_INFO(Module32Next), - END_FUNC_INFO -}; - -khm_int32 init_imports(void) { - OSVERSIONINFO osvi; - int imp_rv = 1; - -#define CKRV(m) \ - do { \ - if(!imp_rv) { \ - _reportf(L"Can't locate all required exports from module [%S]", (m)); \ - goto _err_ret; \ - } \ - } while (FALSE) - -#ifndef _WIN64 - imp_rv = LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0); - CKRV(KRB4_DLL); -#endif - - imp_rv = LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0); - CKRV(KRB5_DLL); - - imp_rv = LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0); - CKRV(COMERR_DLL); - - imp_rv = LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0); - CKRV(SERVICE_DLL); - - imp_rv = LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1); - CKRV(SECUR32_DLL); - - imp_rv = LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1); - CKRV(KRB524_DLL); - - imp_rv = LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0); - CKRV(PROFILE_DLL); - - imp_rv = LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0); - /* CCAPI_DLL is optional. No error check. */ - - memset(&osvi, 0, sizeof(OSVERSIONINFO)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&osvi); - - // XXX: We should really use feature testing, first - // checking for CreateToolhelp32Snapshot. If that's - // not around, we try the psapi stuff. - // - // Only load LSA functions if on NT/2000/XP - if(osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) - { - // Windows 9x - imp_rv = LoadFuncs(TOOLHELPDLL, toolhelp_fi, &hToolHelp32, 0, 1, 0, 0); - CKRV(TOOLHELPDLL); - - hPsapi = 0; - } - else if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - // Windows NT - imp_rv = LoadFuncs(PSAPIDLL, psapi_fi, &hPsapi, 0, 1, 0, 0); - CKRV(PSAPIDLL); - - hToolHelp32 = 0; - } - - AfsAvailable = TRUE; //afscompat_init(); - - return KHM_ERROR_SUCCESS; - - _err_ret: - return KHM_ERROR_NOT_FOUND; -} - -khm_int32 exit_imports(void) { - //afscompat_close(); - - if (hKrb4) - FreeLibrary(hKrb4); - if (hKrb5) - FreeLibrary(hKrb5); - if (hProfile) - FreeLibrary(hProfile); - if (hComErr) - FreeLibrary(hComErr); - if (hService) - FreeLibrary(hService); - if (hSecur32) - FreeLibrary(hSecur32); - if (hKrb524) - FreeLibrary(hKrb524); - if (hPsapi) - FreeLibrary(hPsapi); - if (hToolHelp32) - FreeLibrary(hToolHelp32); - - return KHM_ERROR_SUCCESS; -} - -int (*Lcom_err)(LPSTR,long,LPSTR,...); -LPSTR (*Lerror_message)(long); -LPSTR (*Lerror_table_name)(long); - -void Leash_load_com_err_callback(FARPROC ce, - FARPROC em, - FARPROC etn) -{ - (FARPROC)Lcom_err=ce; - (FARPROC)Lerror_message=em; - (FARPROC)Lerror_table_name=etn; -} +/* +* Copyright (c) 2005 Massachusetts Institute of Technology +* Copyright (c) 2007 Secure Endpoints Inc. +* +* 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 + +HINSTANCE hKrb4 = 0; +HINSTANCE hKrb5 = 0; +HINSTANCE hKrb524 = 0; +HINSTANCE hSecur32 = 0; +HINSTANCE hComErr = 0; +HINSTANCE hService = 0; +HINSTANCE hProfile = 0; +HINSTANCE hPsapi = 0; +HINSTANCE hToolHelp32 = 0; +HINSTANCE hCCAPI = 0; + +DWORD AfsAvailable = 0; + +// CCAPI +DECL_FUNC_PTR(cc_initialize); +DECL_FUNC_PTR(cc_shutdown); +DECL_FUNC_PTR(cc_get_NC_info); +DECL_FUNC_PTR(cc_free_NC_info); + +// krb4 functions +DECL_FUNC_PTR(get_krb_err_txt_entry); +DECL_FUNC_PTR(k_isinst); +DECL_FUNC_PTR(k_isname); +DECL_FUNC_PTR(k_isrealm); +DECL_FUNC_PTR(kadm_change_your_password); +DECL_FUNC_PTR(kname_parse); +DECL_FUNC_PTR(krb_get_cred); +DECL_FUNC_PTR(krb_get_krbhst); +DECL_FUNC_PTR(krb_get_lrealm); +DECL_FUNC_PTR(krb_get_pw_in_tkt); +DECL_FUNC_PTR(krb_get_tf_realm); +DECL_FUNC_PTR(krb_mk_req); +DECL_FUNC_PTR(krb_realmofhost); +DECL_FUNC_PTR(tf_init); +DECL_FUNC_PTR(tf_close); +DECL_FUNC_PTR(tf_get_cred); +DECL_FUNC_PTR(tf_get_pname); +DECL_FUNC_PTR(tf_get_pinst); +DECL_FUNC_PTR(LocalHostAddr); +DECL_FUNC_PTR(tkt_string); +DECL_FUNC_PTR(krb_set_tkt_string); +DECL_FUNC_PTR(initialize_krb_error_func); +DECL_FUNC_PTR(initialize_kadm_error_table); +DECL_FUNC_PTR(dest_tkt); +DECL_FUNC_PTR(krb_in_tkt); +DECL_FUNC_PTR(krb_save_credentials); +DECL_FUNC_PTR(krb_get_krbconf2); +DECL_FUNC_PTR(krb_get_krbrealm2); +DECL_FUNC_PTR(krb_life_to_time); + +// krb5 functions +DECL_FUNC_PTR(krb5_change_password); +DECL_FUNC_PTR(krb5_get_init_creds_opt_init); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_change_password_prompt); +DECL_FUNC_PTR(krb5_get_init_creds_password); +DECL_FUNC_PTR(krb5_get_prompt_types); +DECL_FUNC_PTR(krb5_build_principal_ext); +DECL_FUNC_PTR(krb5_cc_get_name); +DECL_FUNC_PTR(krb5_cc_get_type); +DECL_FUNC_PTR(krb5_cc_resolve); +DECL_FUNC_PTR(krb5_cc_default); +DECL_FUNC_PTR(krb5_cc_default_name); +DECL_FUNC_PTR(krb5_cc_set_default_name); +DECL_FUNC_PTR(krb5_cc_initialize); +DECL_FUNC_PTR(krb5_cc_destroy); +DECL_FUNC_PTR(krb5_cc_close); +DECL_FUNC_PTR(krb5_cc_store_cred); +DECL_FUNC_PTR(krb5_cc_copy_creds); +DECL_FUNC_PTR(krb5_cc_retrieve_cred); +DECL_FUNC_PTR(krb5_cc_get_principal); +DECL_FUNC_PTR(krb5_cc_start_seq_get); +DECL_FUNC_PTR(krb5_cc_next_cred); +DECL_FUNC_PTR(krb5_cc_end_seq_get); +DECL_FUNC_PTR(krb5_cc_remove_cred); +DECL_FUNC_PTR(krb5_cc_set_flags); +// DECL_FUNC_PTR(krb5_cc_get_type); +DECL_FUNC_PTR(krb5_free_context); +DECL_FUNC_PTR(krb5_free_cred_contents); +DECL_FUNC_PTR(krb5_free_principal); +DECL_FUNC_PTR(krb5_get_in_tkt_with_password); +DECL_FUNC_PTR(krb5_init_context); +DECL_FUNC_PTR(krb5_parse_name); +DECL_FUNC_PTR(krb5_timeofday); +DECL_FUNC_PTR(krb5_timestamp_to_sfstring); +DECL_FUNC_PTR(krb5_unparse_name); +DECL_FUNC_PTR(krb5_get_credentials); +DECL_FUNC_PTR(krb5_mk_req); +DECL_FUNC_PTR(krb5_sname_to_principal); +DECL_FUNC_PTR(krb5_get_credentials_renew); +DECL_FUNC_PTR(krb5_free_data); +DECL_FUNC_PTR(krb5_free_data_contents); +// DECL_FUNC_PTR(krb5_get_realm_domain); +DECL_FUNC_PTR(krb5_free_unparsed_name); +DECL_FUNC_PTR(krb5_os_localaddr); +DECL_FUNC_PTR(krb5_copy_keyblock_contents); +DECL_FUNC_PTR(krb5_copy_data); +DECL_FUNC_PTR(krb5_free_creds); +DECL_FUNC_PTR(krb5_build_principal); +DECL_FUNC_PTR(krb5_get_renewed_creds); +DECL_FUNC_PTR(krb5_get_default_config_files); +DECL_FUNC_PTR(krb5_free_config_files); +DECL_FUNC_PTR(krb5_get_default_realm); +DECL_FUNC_PTR(krb5_set_default_realm); +DECL_FUNC_PTR(krb5_free_ticket); +DECL_FUNC_PTR(krb5_decode_ticket); +DECL_FUNC_PTR(krb5_get_host_realm); +DECL_FUNC_PTR(krb5_free_host_realm); +DECL_FUNC_PTR(krb5_c_random_make_octets); +DECL_FUNC_PTR(krb5_free_addresses); +DECL_FUNC_PTR(krb5_free_default_realm); +DECL_FUNC_PTR(krb5_string_to_deltat); + +// Krb524 functions +DECL_FUNC_PTR(krb524_init_ets); +DECL_FUNC_PTR(krb524_convert_creds_kdc); + +// ComErr functions +DECL_FUNC_PTR(com_err); +DECL_FUNC_PTR(error_message); + +// Profile functions +DECL_FUNC_PTR(profile_init); +DECL_FUNC_PTR(profile_flush); +DECL_FUNC_PTR(profile_release); +DECL_FUNC_PTR(profile_get_subsection_names); +DECL_FUNC_PTR(profile_free_list); +DECL_FUNC_PTR(profile_get_string); +DECL_FUNC_PTR(profile_get_integer); +DECL_FUNC_PTR(profile_get_values); +DECL_FUNC_PTR(profile_get_relation_names); +DECL_FUNC_PTR(profile_clear_relation); +DECL_FUNC_PTR(profile_add_relation); +DECL_FUNC_PTR(profile_update_relation); +DECL_FUNC_PTR(profile_release_string); +DECL_FUNC_PTR(profile_rename_section); + +// Service functions +DECL_FUNC_PTR(OpenSCManagerA); +DECL_FUNC_PTR(OpenServiceA); +DECL_FUNC_PTR(QueryServiceStatus); +DECL_FUNC_PTR(CloseServiceHandle); +DECL_FUNC_PTR(LsaNtStatusToWinError); + +// LSA Functions +DECL_FUNC_PTR(LsaConnectUntrusted); +DECL_FUNC_PTR(LsaLookupAuthenticationPackage); +DECL_FUNC_PTR(LsaCallAuthenticationPackage); +DECL_FUNC_PTR(LsaFreeReturnBuffer); +DECL_FUNC_PTR(LsaGetLogonSessionData); + +// CCAPI +FUNC_INFO ccapi_fi[] = { + MAKE_FUNC_INFO(cc_initialize), + MAKE_FUNC_INFO(cc_shutdown), + MAKE_FUNC_INFO(cc_get_NC_info), + MAKE_FUNC_INFO(cc_free_NC_info), + END_FUNC_INFO +}; + +FUNC_INFO k4_fi[] = { + MAKE_FUNC_INFO(get_krb_err_txt_entry), + MAKE_FUNC_INFO(k_isinst), + MAKE_FUNC_INFO(k_isname), + MAKE_FUNC_INFO(k_isrealm), + MAKE_FUNC_INFO(kadm_change_your_password), + MAKE_FUNC_INFO(kname_parse), + MAKE_FUNC_INFO(krb_get_cred), + MAKE_FUNC_INFO(krb_get_krbhst), + MAKE_FUNC_INFO(krb_get_lrealm), + MAKE_FUNC_INFO(krb_get_pw_in_tkt), + MAKE_FUNC_INFO(krb_get_tf_realm), + MAKE_FUNC_INFO(krb_mk_req), + MAKE_FUNC_INFO(krb_realmofhost), + MAKE_FUNC_INFO(tf_init), + MAKE_FUNC_INFO(tf_close), + MAKE_FUNC_INFO(tf_get_cred), + MAKE_FUNC_INFO(tf_get_pname), + MAKE_FUNC_INFO(tf_get_pinst), + MAKE_FUNC_INFO(LocalHostAddr), + MAKE_FUNC_INFO(tkt_string), + MAKE_FUNC_INFO(krb_set_tkt_string), + MAKE_FUNC_INFO(initialize_krb_error_func), + MAKE_FUNC_INFO(initialize_kadm_error_table), + MAKE_FUNC_INFO(dest_tkt), + /* MAKE_FUNC_INFO(lsh_LoadKrb4LeashErrorTables), */// XXX + MAKE_FUNC_INFO(krb_in_tkt), + MAKE_FUNC_INFO(krb_save_credentials), + MAKE_FUNC_INFO(krb_get_krbconf2), + MAKE_FUNC_INFO(krb_get_krbrealm2), + MAKE_FUNC_INFO(krb_life_to_time), + END_FUNC_INFO +}; + +FUNC_INFO k5_fi[] = { + MAKE_FUNC_INFO(krb5_change_password), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_init), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_change_password_prompt), + MAKE_FUNC_INFO(krb5_get_init_creds_password), + MAKE_FUNC_INFO(krb5_get_prompt_types), + MAKE_FUNC_INFO(krb5_build_principal_ext), + MAKE_FUNC_INFO(krb5_cc_get_name), + MAKE_FUNC_INFO(krb5_cc_get_type), + MAKE_FUNC_INFO(krb5_cc_resolve), + MAKE_FUNC_INFO(krb5_cc_default), + MAKE_FUNC_INFO(krb5_cc_default_name), + MAKE_FUNC_INFO(krb5_cc_set_default_name), + MAKE_FUNC_INFO(krb5_cc_initialize), + MAKE_FUNC_INFO(krb5_cc_destroy), + MAKE_FUNC_INFO(krb5_cc_close), + MAKE_FUNC_INFO(krb5_cc_copy_creds), + MAKE_FUNC_INFO(krb5_cc_store_cred), + MAKE_FUNC_INFO(krb5_cc_retrieve_cred), + MAKE_FUNC_INFO(krb5_cc_get_principal), + MAKE_FUNC_INFO(krb5_cc_start_seq_get), + MAKE_FUNC_INFO(krb5_cc_next_cred), + MAKE_FUNC_INFO(krb5_cc_end_seq_get), + MAKE_FUNC_INFO(krb5_cc_remove_cred), + MAKE_FUNC_INFO(krb5_cc_set_flags), + // MAKE_FUNC_INFO(krb5_cc_get_type), + MAKE_FUNC_INFO(krb5_free_context), + MAKE_FUNC_INFO(krb5_free_cred_contents), + MAKE_FUNC_INFO(krb5_free_principal), + MAKE_FUNC_INFO(krb5_get_in_tkt_with_password), + MAKE_FUNC_INFO(krb5_init_context), + MAKE_FUNC_INFO(krb5_parse_name), + MAKE_FUNC_INFO(krb5_timeofday), + MAKE_FUNC_INFO(krb5_timestamp_to_sfstring), + MAKE_FUNC_INFO(krb5_unparse_name), + MAKE_FUNC_INFO(krb5_get_credentials), + MAKE_FUNC_INFO(krb5_mk_req), + MAKE_FUNC_INFO(krb5_sname_to_principal), + MAKE_FUNC_INFO(krb5_get_credentials_renew), + MAKE_FUNC_INFO(krb5_free_data), + MAKE_FUNC_INFO(krb5_free_data_contents), + // MAKE_FUNC_INFO(krb5_get_realm_domain), + MAKE_FUNC_INFO(krb5_free_unparsed_name), + MAKE_FUNC_INFO(krb5_os_localaddr), + MAKE_FUNC_INFO(krb5_copy_keyblock_contents), + MAKE_FUNC_INFO(krb5_copy_data), + MAKE_FUNC_INFO(krb5_free_creds), + MAKE_FUNC_INFO(krb5_build_principal), + MAKE_FUNC_INFO(krb5_get_renewed_creds), + MAKE_FUNC_INFO(krb5_free_addresses), + MAKE_FUNC_INFO(krb5_get_default_config_files), + MAKE_FUNC_INFO(krb5_free_config_files), + MAKE_FUNC_INFO(krb5_get_default_realm), + MAKE_FUNC_INFO(krb5_set_default_realm), + MAKE_FUNC_INFO(krb5_free_ticket), + MAKE_FUNC_INFO(krb5_decode_ticket), + MAKE_FUNC_INFO(krb5_get_host_realm), + MAKE_FUNC_INFO(krb5_free_host_realm), + MAKE_FUNC_INFO(krb5_c_random_make_octets), + MAKE_FUNC_INFO(krb5_free_default_realm), + MAKE_FUNC_INFO(krb5_string_to_deltat), + END_FUNC_INFO +}; + +FUNC_INFO k524_fi[] = { + MAKE_FUNC_INFO(krb524_init_ets), + MAKE_FUNC_INFO(krb524_convert_creds_kdc), + END_FUNC_INFO +}; + +FUNC_INFO profile_fi[] = { + MAKE_FUNC_INFO(profile_init), + MAKE_FUNC_INFO(profile_flush), + MAKE_FUNC_INFO(profile_release), + MAKE_FUNC_INFO(profile_get_subsection_names), + MAKE_FUNC_INFO(profile_free_list), + MAKE_FUNC_INFO(profile_get_string), + MAKE_FUNC_INFO(profile_get_integer), + MAKE_FUNC_INFO(profile_get_values), + MAKE_FUNC_INFO(profile_get_relation_names), + MAKE_FUNC_INFO(profile_clear_relation), + MAKE_FUNC_INFO(profile_add_relation), + MAKE_FUNC_INFO(profile_update_relation), + MAKE_FUNC_INFO(profile_release_string), + MAKE_FUNC_INFO(profile_rename_section), + END_FUNC_INFO +}; + +FUNC_INFO ce_fi[] = { + MAKE_FUNC_INFO(com_err), + MAKE_FUNC_INFO(error_message), + END_FUNC_INFO +}; + +FUNC_INFO service_fi[] = { + MAKE_FUNC_INFO(OpenSCManagerA), + MAKE_FUNC_INFO(OpenServiceA), + MAKE_FUNC_INFO(QueryServiceStatus), + MAKE_FUNC_INFO(CloseServiceHandle), + MAKE_FUNC_INFO(LsaNtStatusToWinError), + END_FUNC_INFO +}; + +FUNC_INFO lsa_fi[] = { + MAKE_FUNC_INFO(LsaConnectUntrusted), + MAKE_FUNC_INFO(LsaLookupAuthenticationPackage), + MAKE_FUNC_INFO(LsaCallAuthenticationPackage), + MAKE_FUNC_INFO(LsaFreeReturnBuffer), + MAKE_FUNC_INFO(LsaGetLogonSessionData), + END_FUNC_INFO +}; + +// psapi functions +DECL_FUNC_PTR(GetModuleFileNameExA); +DECL_FUNC_PTR(EnumProcessModules); + +FUNC_INFO psapi_fi[] = { + MAKE_FUNC_INFO(GetModuleFileNameExA), + MAKE_FUNC_INFO(EnumProcessModules), + END_FUNC_INFO +}; + +// toolhelp functions +DECL_FUNC_PTR(CreateToolhelp32Snapshot); +DECL_FUNC_PTR(Module32First); +DECL_FUNC_PTR(Module32Next); + +FUNC_INFO toolhelp_fi[] = { + MAKE_FUNC_INFO(CreateToolhelp32Snapshot), + MAKE_FUNC_INFO(Module32First), + MAKE_FUNC_INFO(Module32Next), + END_FUNC_INFO +}; + +khm_int32 init_imports(void) { + OSVERSIONINFO osvi; + int imp_rv = 1; + +#define CKRV(m) \ + do { \ + if(!imp_rv) { \ + _reportf(L"Can't locate all required exports from module [%S]", (m)); \ + goto _err_ret; \ + } \ + } while (FALSE) + +#ifndef _WIN64 + imp_rv = LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0); + CKRV(KRB4_DLL); +#endif + + imp_rv = LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0); + CKRV(KRB5_DLL); + + imp_rv = LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0); + CKRV(COMERR_DLL); + + imp_rv = LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0); + CKRV(SERVICE_DLL); + + imp_rv = LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1); + CKRV(SECUR32_DLL); + + imp_rv = LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1); + CKRV(KRB524_DLL); + + imp_rv = LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0); + CKRV(PROFILE_DLL); + + imp_rv = LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0); + /* CCAPI_DLL is optional. No error check. */ + + memset(&osvi, 0, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + + // XXX: We should really use feature testing, first + // checking for CreateToolhelp32Snapshot. If that's + // not around, we try the psapi stuff. + // + // Only load LSA functions if on NT/2000/XP + if(osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) + { + // Windows 9x + imp_rv = LoadFuncs(TOOLHELPDLL, toolhelp_fi, &hToolHelp32, 0, 1, 0, 0); + CKRV(TOOLHELPDLL); + + hPsapi = 0; + } + else if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + // Windows NT + imp_rv = LoadFuncs(PSAPIDLL, psapi_fi, &hPsapi, 0, 1, 0, 0); + CKRV(PSAPIDLL); + + hToolHelp32 = 0; + } + + AfsAvailable = TRUE; //afscompat_init(); + + return KHM_ERROR_SUCCESS; + + _err_ret: + return KHM_ERROR_NOT_FOUND; +} + +khm_int32 exit_imports(void) { + //afscompat_close(); + + if (hKrb4) + FreeLibrary(hKrb4); + if (hKrb5) + FreeLibrary(hKrb5); + if (hProfile) + FreeLibrary(hProfile); + if (hComErr) + FreeLibrary(hComErr); + if (hService) + FreeLibrary(hService); + if (hSecur32) + FreeLibrary(hSecur32); + if (hKrb524) + FreeLibrary(hKrb524); + if (hPsapi) + FreeLibrary(hPsapi); + if (hToolHelp32) + FreeLibrary(hToolHelp32); + + return KHM_ERROR_SUCCESS; +} + +int (*Lcom_err)(LPSTR,long,LPSTR,...); +LPSTR (*Lerror_message)(long); +LPSTR (*Lerror_table_name)(long); + +void Leash_load_com_err_callback(FARPROC ce, + FARPROC em, + FARPROC etn) +{ + (FARPROC)Lcom_err=ce; + (FARPROC)Lerror_message=em; + (FARPROC)Lerror_table_name=etn; +} diff --git a/src/windows/identity/plugins/common/dynimport.h b/src/windows/identity/plugins/common/dynimport.h index 7f3f598b0..850d96e5f 100644 --- a/src/windows/identity/plugins/common/dynimport.h +++ b/src/windows/identity/plugins/common/dynimport.h @@ -1,361 +1,361 @@ -/* - * 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_DYNIMPORT_H -#define __KHIMAIRA_DYNIMPORT_H - -/* Dynamic imports */ -#include -#include - -#if _WIN32_WINNT < 0x0501 -#define KHM_SAVE_WIN32_WINNT _WIN32_WINNT -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif -#include -#ifdef KHM_SAVE_WIN32_WINNT -#undef _WIN32_WINNT -#define _WIN32_WINNT KHM_SAVE_WIN32_WINNT -#undef KHM_SAVE_WIN32_WINNT -#endif - -extern HINSTANCE hKrb4; -extern HINSTANCE hKrb5; -extern HINSTANCE hProfile; - -/////////////////////////////////////////////////////////////////////////////// - -#define CCAPI_DLL "krbcc32.dll" -#define KRBCC32_DLL "krbcc32.dll" -#define SERVICE_DLL "advapi32.dll" -#define SECUR32_DLL "secur32.dll" -#define PROFILE_DLL "xpprof32.dll" - -////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include - -//// CCAPI -/* In order to avoid including the private CCAPI headers */ -typedef int cc_int32; - -#define CC_API_VER_1 1 -#define CC_API_VER_2 2 - -#define CCACHE_API cc_int32 - -/* -** The Official Error Codes -*/ -#define CC_NOERROR 0 -#define CC_BADNAME 1 -#define CC_NOTFOUND 2 -#define CC_END 3 -#define CC_IO 4 -#define CC_WRITE 5 -#define CC_NOMEM 6 -#define CC_FORMAT 7 -#define CC_LOCKED 8 -#define CC_BAD_API_VERSION 9 -#define CC_NO_EXIST 10 -#define CC_NOT_SUPP 11 -#define CC_BAD_PARM 12 -#define CC_ERR_CACHE_ATTACH 13 -#define CC_ERR_CACHE_RELEASE 14 -#define CC_ERR_CACHE_FULL 15 -#define CC_ERR_CRED_VERSION 16 - -enum { - CC_CRED_VUNKNOWN = 0, // For validation - CC_CRED_V4 = 1, - CC_CRED_V5 = 2, - CC_CRED_VMAX = 3 // For validation -}; - -typedef struct opaque_dll_control_block_type* apiCB; -typedef struct _infoNC { - char* name; - char* principal; - cc_int32 vers; -} infoNC; - -TYPEDEF_FUNC( -CCACHE_API, -CALLCONV_C, -cc_initialize, - ( - apiCB** cc_ctx, // < DLL's primary control structure. - // returned here, passed everywhere else - cc_int32 api_version, // > ver supported by caller (use CC_API_VER_1) - cc_int32* api_supported, // < if ~NULL, max ver supported by DLL - const char** vendor // < if ~NULL, vendor name in read only C string - ) -); - -TYPEDEF_FUNC( -CCACHE_API, -CALLCONV_C, -cc_shutdown, - ( - apiCB** cc_ctx // <> DLL's primary control structure. NULL after - ) -); - -TYPEDEF_FUNC( -CCACHE_API, -CALLCONV_C, -cc_get_NC_info, - ( - apiCB* cc_ctx, // > DLL's primary control structure - struct _infoNC*** ppNCi // < (NULL before call) null terminated, - // list of a structs (free via cc_free_infoNC()) - ) -); - -TYPEDEF_FUNC( -CCACHE_API, -CALLCONV_C, -cc_free_NC_info, - ( - apiCB* cc_ctx, - struct _infoNC*** ppNCi // < free list of structs returned by - // cc_get_cache_names(). set to NULL on return - ) -); -//// \CCAPI - -extern DWORD AfsAvailable; - -// service definitions -typedef SC_HANDLE (WINAPI *FP_OpenSCManagerA)(char *, char *, DWORD); -typedef SC_HANDLE (WINAPI *FP_OpenServiceA)(SC_HANDLE, char *, DWORD); -typedef BOOL (WINAPI *FP_QueryServiceStatus)(SC_HANDLE, LPSERVICE_STATUS); -typedef BOOL (WINAPI *FP_CloseServiceHandle)(SC_HANDLE); - -////////////////////////////////////////////////////////////////////////////// - -// CCAPI -extern DECL_FUNC_PTR(cc_initialize); -extern DECL_FUNC_PTR(cc_shutdown); -extern DECL_FUNC_PTR(cc_get_NC_info); -extern DECL_FUNC_PTR(cc_free_NC_info); - -// krb4 functions -extern DECL_FUNC_PTR(get_krb_err_txt_entry); -extern DECL_FUNC_PTR(k_isinst); -extern DECL_FUNC_PTR(k_isname); -extern DECL_FUNC_PTR(k_isrealm); -extern DECL_FUNC_PTR(kadm_change_your_password); -extern DECL_FUNC_PTR(kname_parse); -extern DECL_FUNC_PTR(krb_get_cred); -extern DECL_FUNC_PTR(krb_get_krbhst); -extern DECL_FUNC_PTR(krb_get_lrealm); -extern DECL_FUNC_PTR(krb_get_pw_in_tkt); -extern DECL_FUNC_PTR(krb_get_tf_realm); -extern DECL_FUNC_PTR(krb_mk_req); -extern DECL_FUNC_PTR(krb_realmofhost); -extern DECL_FUNC_PTR(tf_init); -extern DECL_FUNC_PTR(tf_close); -extern DECL_FUNC_PTR(tf_get_cred); -extern DECL_FUNC_PTR(tf_get_pname); -extern DECL_FUNC_PTR(tf_get_pinst); -extern DECL_FUNC_PTR(LocalHostAddr); -extern DECL_FUNC_PTR(tkt_string); -extern DECL_FUNC_PTR(krb_set_tkt_string); -extern DECL_FUNC_PTR(initialize_krb_error_func); -extern DECL_FUNC_PTR(initialize_kadm_error_table); -extern DECL_FUNC_PTR(dest_tkt); -extern DECL_FUNC_PTR(lsh_LoadKrb4LeashErrorTables); // XXX -extern DECL_FUNC_PTR(krb_in_tkt); -extern DECL_FUNC_PTR(krb_save_credentials); -extern DECL_FUNC_PTR(krb_get_krbconf2); -extern DECL_FUNC_PTR(krb_get_krbrealm2); -extern DECL_FUNC_PTR(krb_life_to_time); - -// krb5 functions -extern DECL_FUNC_PTR(krb5_change_password); -extern DECL_FUNC_PTR(krb5_get_init_creds_opt_init); -extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life); -extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); -extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable); -extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable); -extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); -extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list); -extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_change_password_prompt); -extern DECL_FUNC_PTR(krb5_get_init_creds_password); -extern DECL_FUNC_PTR(krb5_get_prompt_types); -extern DECL_FUNC_PTR(krb5_build_principal_ext); -extern DECL_FUNC_PTR(krb5_cc_get_name); -extern DECL_FUNC_PTR(krb5_cc_get_type); -extern DECL_FUNC_PTR(krb5_cc_resolve); -extern DECL_FUNC_PTR(krb5_cc_default); -extern DECL_FUNC_PTR(krb5_cc_default_name); -extern DECL_FUNC_PTR(krb5_cc_set_default_name); -extern DECL_FUNC_PTR(krb5_cc_initialize); -extern DECL_FUNC_PTR(krb5_cc_destroy); -extern DECL_FUNC_PTR(krb5_cc_close); -extern DECL_FUNC_PTR(krb5_cc_copy_creds); -extern DECL_FUNC_PTR(krb5_cc_store_cred); -extern DECL_FUNC_PTR(krb5_cc_retrieve_cred); -extern DECL_FUNC_PTR(krb5_cc_get_principal); -extern DECL_FUNC_PTR(krb5_cc_start_seq_get); -extern DECL_FUNC_PTR(krb5_cc_next_cred); -extern DECL_FUNC_PTR(krb5_cc_end_seq_get); -extern DECL_FUNC_PTR(krb5_cc_remove_cred); -extern DECL_FUNC_PTR(krb5_cc_set_flags); -// extern DECL_FUNC_PTR(krb5_cc_get_type); -extern DECL_FUNC_PTR(krb5_free_context); -extern DECL_FUNC_PTR(krb5_free_cred_contents); -extern DECL_FUNC_PTR(krb5_free_principal); -extern DECL_FUNC_PTR(krb5_get_in_tkt_with_password); -extern DECL_FUNC_PTR(krb5_init_context); -extern DECL_FUNC_PTR(krb5_parse_name); -extern DECL_FUNC_PTR(krb5_timeofday); -extern DECL_FUNC_PTR(krb5_timestamp_to_sfstring); -extern DECL_FUNC_PTR(krb5_unparse_name); -extern DECL_FUNC_PTR(krb5_get_credentials); -extern DECL_FUNC_PTR(krb5_mk_req); -extern DECL_FUNC_PTR(krb5_sname_to_principal); -extern DECL_FUNC_PTR(krb5_get_credentials_renew); -extern DECL_FUNC_PTR(krb5_free_data); -extern DECL_FUNC_PTR(krb5_free_data_contents); -// extern DECL_FUNC_PTR(krb5_get_realm_domain); -extern DECL_FUNC_PTR(krb5_free_unparsed_name); -extern DECL_FUNC_PTR(krb5_os_localaddr); -extern DECL_FUNC_PTR(krb5_copy_keyblock_contents); -extern DECL_FUNC_PTR(krb5_copy_data); -extern DECL_FUNC_PTR(krb5_free_creds); -extern DECL_FUNC_PTR(krb5_build_principal); -extern DECL_FUNC_PTR(krb5_get_renewed_creds); -extern DECL_FUNC_PTR(krb5_free_addresses); -extern DECL_FUNC_PTR(krb5_get_default_config_files); -extern DECL_FUNC_PTR(krb5_free_config_files); -extern DECL_FUNC_PTR(krb5_get_default_realm); -extern DECL_FUNC_PTR(krb5_set_default_realm); -extern DECL_FUNC_PTR(krb5_free_ticket); -extern DECL_FUNC_PTR(krb5_decode_ticket); -extern DECL_FUNC_PTR(krb5_get_host_realm); -extern DECL_FUNC_PTR(krb5_free_host_realm); -extern DECL_FUNC_PTR(krb5_c_random_make_octets); -extern DECL_FUNC_PTR(krb5_free_default_realm); -extern DECL_FUNC_PTR(krb5_string_to_deltat); - -// Krb524 functions -extern DECL_FUNC_PTR(krb524_init_ets); -extern DECL_FUNC_PTR(krb524_convert_creds_kdc); - -// ComErr functions -extern DECL_FUNC_PTR(com_err); -extern DECL_FUNC_PTR(error_message); - -// Profile functions -extern DECL_FUNC_PTR(profile_init); -extern DECL_FUNC_PTR(profile_flush); -extern DECL_FUNC_PTR(profile_release); -extern DECL_FUNC_PTR(profile_get_subsection_names); -extern DECL_FUNC_PTR(profile_free_list); -extern DECL_FUNC_PTR(profile_get_string); -extern DECL_FUNC_PTR(profile_get_integer); -extern DECL_FUNC_PTR(profile_get_values); -extern DECL_FUNC_PTR(profile_get_relation_names); -extern DECL_FUNC_PTR(profile_clear_relation); -extern DECL_FUNC_PTR(profile_add_relation); -extern DECL_FUNC_PTR(profile_update_relation); -extern DECL_FUNC_PTR(profile_release_string); -extern DECL_FUNC_PTR(profile_rename_section); - -// Service functions -extern DECL_FUNC_PTR(OpenSCManagerA); -extern DECL_FUNC_PTR(OpenServiceA); -extern DECL_FUNC_PTR(QueryServiceStatus); -extern DECL_FUNC_PTR(CloseServiceHandle); -extern DECL_FUNC_PTR(LsaNtStatusToWinError); - -// LSA Functions -extern DECL_FUNC_PTR(LsaConnectUntrusted); -extern DECL_FUNC_PTR(LsaLookupAuthenticationPackage); -extern DECL_FUNC_PTR(LsaCallAuthenticationPackage); -extern DECL_FUNC_PTR(LsaFreeReturnBuffer); -extern DECL_FUNC_PTR(LsaGetLogonSessionData); - -// toolhelp functions -TYPEDEF_FUNC( - HANDLE, - WINAPI, - CreateToolhelp32Snapshot, - (DWORD, DWORD) - ); -TYPEDEF_FUNC( - BOOL, - WINAPI, - Module32First, - (HANDLE, LPMODULEENTRY32) - ); -TYPEDEF_FUNC( - BOOL, - WINAPI, - Module32Next, - (HANDLE, LPMODULEENTRY32) - ); - -// psapi functions -TYPEDEF_FUNC( - DWORD, - WINAPI, - GetModuleFileNameExA, - (HANDLE, HMODULE, LPSTR, DWORD) - ); - -TYPEDEF_FUNC( - BOOL, - WINAPI, - EnumProcessModules, - (HANDLE, HMODULE*, DWORD, LPDWORD) - ); - -#define pGetModuleFileNameEx pGetModuleFileNameExA -#define TOOLHELPDLL "kernel32.dll" -#define PSAPIDLL "psapi.dll" - -// psapi functions -extern DECL_FUNC_PTR(GetModuleFileNameExA); -extern DECL_FUNC_PTR(EnumProcessModules); - -// toolhelp functions -extern DECL_FUNC_PTR(CreateToolhelp32Snapshot); -extern DECL_FUNC_PTR(Module32First); -extern DECL_FUNC_PTR(Module32Next); - -khm_int32 init_imports(void); -khm_int32 exit_imports(void); - -#endif +/* + * 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_DYNIMPORT_H +#define __KHIMAIRA_DYNIMPORT_H + +/* Dynamic imports */ +#include +#include + +#if _WIN32_WINNT < 0x0501 +#define KHM_SAVE_WIN32_WINNT _WIN32_WINNT +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#ifdef KHM_SAVE_WIN32_WINNT +#undef _WIN32_WINNT +#define _WIN32_WINNT KHM_SAVE_WIN32_WINNT +#undef KHM_SAVE_WIN32_WINNT +#endif + +extern HINSTANCE hKrb4; +extern HINSTANCE hKrb5; +extern HINSTANCE hProfile; + +/////////////////////////////////////////////////////////////////////////////// + +#define CCAPI_DLL "krbcc32.dll" +#define KRBCC32_DLL "krbcc32.dll" +#define SERVICE_DLL "advapi32.dll" +#define SECUR32_DLL "secur32.dll" +#define PROFILE_DLL "xpprof32.dll" + +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +//// CCAPI +/* In order to avoid including the private CCAPI headers */ +typedef int cc_int32; + +#define CC_API_VER_1 1 +#define CC_API_VER_2 2 + +#define CCACHE_API cc_int32 + +/* +** The Official Error Codes +*/ +#define CC_NOERROR 0 +#define CC_BADNAME 1 +#define CC_NOTFOUND 2 +#define CC_END 3 +#define CC_IO 4 +#define CC_WRITE 5 +#define CC_NOMEM 6 +#define CC_FORMAT 7 +#define CC_LOCKED 8 +#define CC_BAD_API_VERSION 9 +#define CC_NO_EXIST 10 +#define CC_NOT_SUPP 11 +#define CC_BAD_PARM 12 +#define CC_ERR_CACHE_ATTACH 13 +#define CC_ERR_CACHE_RELEASE 14 +#define CC_ERR_CACHE_FULL 15 +#define CC_ERR_CRED_VERSION 16 + +enum { + CC_CRED_VUNKNOWN = 0, // For validation + CC_CRED_V4 = 1, + CC_CRED_V5 = 2, + CC_CRED_VMAX = 3 // For validation +}; + +typedef struct opaque_dll_control_block_type* apiCB; +typedef struct _infoNC { + char* name; + char* principal; + cc_int32 vers; +} infoNC; + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_initialize, + ( + apiCB** cc_ctx, // < DLL's primary control structure. + // returned here, passed everywhere else + cc_int32 api_version, // > ver supported by caller (use CC_API_VER_1) + cc_int32* api_supported, // < if ~NULL, max ver supported by DLL + const char** vendor // < if ~NULL, vendor name in read only C string + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_shutdown, + ( + apiCB** cc_ctx // <> DLL's primary control structure. NULL after + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_get_NC_info, + ( + apiCB* cc_ctx, // > DLL's primary control structure + struct _infoNC*** ppNCi // < (NULL before call) null terminated, + // list of a structs (free via cc_free_infoNC()) + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_free_NC_info, + ( + apiCB* cc_ctx, + struct _infoNC*** ppNCi // < free list of structs returned by + // cc_get_cache_names(). set to NULL on return + ) +); +//// \CCAPI + +extern DWORD AfsAvailable; + +// service definitions +typedef SC_HANDLE (WINAPI *FP_OpenSCManagerA)(char *, char *, DWORD); +typedef SC_HANDLE (WINAPI *FP_OpenServiceA)(SC_HANDLE, char *, DWORD); +typedef BOOL (WINAPI *FP_QueryServiceStatus)(SC_HANDLE, LPSERVICE_STATUS); +typedef BOOL (WINAPI *FP_CloseServiceHandle)(SC_HANDLE); + +////////////////////////////////////////////////////////////////////////////// + +// CCAPI +extern DECL_FUNC_PTR(cc_initialize); +extern DECL_FUNC_PTR(cc_shutdown); +extern DECL_FUNC_PTR(cc_get_NC_info); +extern DECL_FUNC_PTR(cc_free_NC_info); + +// krb4 functions +extern DECL_FUNC_PTR(get_krb_err_txt_entry); +extern DECL_FUNC_PTR(k_isinst); +extern DECL_FUNC_PTR(k_isname); +extern DECL_FUNC_PTR(k_isrealm); +extern DECL_FUNC_PTR(kadm_change_your_password); +extern DECL_FUNC_PTR(kname_parse); +extern DECL_FUNC_PTR(krb_get_cred); +extern DECL_FUNC_PTR(krb_get_krbhst); +extern DECL_FUNC_PTR(krb_get_lrealm); +extern DECL_FUNC_PTR(krb_get_pw_in_tkt); +extern DECL_FUNC_PTR(krb_get_tf_realm); +extern DECL_FUNC_PTR(krb_mk_req); +extern DECL_FUNC_PTR(krb_realmofhost); +extern DECL_FUNC_PTR(tf_init); +extern DECL_FUNC_PTR(tf_close); +extern DECL_FUNC_PTR(tf_get_cred); +extern DECL_FUNC_PTR(tf_get_pname); +extern DECL_FUNC_PTR(tf_get_pinst); +extern DECL_FUNC_PTR(LocalHostAddr); +extern DECL_FUNC_PTR(tkt_string); +extern DECL_FUNC_PTR(krb_set_tkt_string); +extern DECL_FUNC_PTR(initialize_krb_error_func); +extern DECL_FUNC_PTR(initialize_kadm_error_table); +extern DECL_FUNC_PTR(dest_tkt); +extern DECL_FUNC_PTR(lsh_LoadKrb4LeashErrorTables); // XXX +extern DECL_FUNC_PTR(krb_in_tkt); +extern DECL_FUNC_PTR(krb_save_credentials); +extern DECL_FUNC_PTR(krb_get_krbconf2); +extern DECL_FUNC_PTR(krb_get_krbrealm2); +extern DECL_FUNC_PTR(krb_life_to_time); + +// krb5 functions +extern DECL_FUNC_PTR(krb5_change_password); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_init); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_change_password_prompt); +extern DECL_FUNC_PTR(krb5_get_init_creds_password); +extern DECL_FUNC_PTR(krb5_get_prompt_types); +extern DECL_FUNC_PTR(krb5_build_principal_ext); +extern DECL_FUNC_PTR(krb5_cc_get_name); +extern DECL_FUNC_PTR(krb5_cc_get_type); +extern DECL_FUNC_PTR(krb5_cc_resolve); +extern DECL_FUNC_PTR(krb5_cc_default); +extern DECL_FUNC_PTR(krb5_cc_default_name); +extern DECL_FUNC_PTR(krb5_cc_set_default_name); +extern DECL_FUNC_PTR(krb5_cc_initialize); +extern DECL_FUNC_PTR(krb5_cc_destroy); +extern DECL_FUNC_PTR(krb5_cc_close); +extern DECL_FUNC_PTR(krb5_cc_copy_creds); +extern DECL_FUNC_PTR(krb5_cc_store_cred); +extern DECL_FUNC_PTR(krb5_cc_retrieve_cred); +extern DECL_FUNC_PTR(krb5_cc_get_principal); +extern DECL_FUNC_PTR(krb5_cc_start_seq_get); +extern DECL_FUNC_PTR(krb5_cc_next_cred); +extern DECL_FUNC_PTR(krb5_cc_end_seq_get); +extern DECL_FUNC_PTR(krb5_cc_remove_cred); +extern DECL_FUNC_PTR(krb5_cc_set_flags); +// extern DECL_FUNC_PTR(krb5_cc_get_type); +extern DECL_FUNC_PTR(krb5_free_context); +extern DECL_FUNC_PTR(krb5_free_cred_contents); +extern DECL_FUNC_PTR(krb5_free_principal); +extern DECL_FUNC_PTR(krb5_get_in_tkt_with_password); +extern DECL_FUNC_PTR(krb5_init_context); +extern DECL_FUNC_PTR(krb5_parse_name); +extern DECL_FUNC_PTR(krb5_timeofday); +extern DECL_FUNC_PTR(krb5_timestamp_to_sfstring); +extern DECL_FUNC_PTR(krb5_unparse_name); +extern DECL_FUNC_PTR(krb5_get_credentials); +extern DECL_FUNC_PTR(krb5_mk_req); +extern DECL_FUNC_PTR(krb5_sname_to_principal); +extern DECL_FUNC_PTR(krb5_get_credentials_renew); +extern DECL_FUNC_PTR(krb5_free_data); +extern DECL_FUNC_PTR(krb5_free_data_contents); +// extern DECL_FUNC_PTR(krb5_get_realm_domain); +extern DECL_FUNC_PTR(krb5_free_unparsed_name); +extern DECL_FUNC_PTR(krb5_os_localaddr); +extern DECL_FUNC_PTR(krb5_copy_keyblock_contents); +extern DECL_FUNC_PTR(krb5_copy_data); +extern DECL_FUNC_PTR(krb5_free_creds); +extern DECL_FUNC_PTR(krb5_build_principal); +extern DECL_FUNC_PTR(krb5_get_renewed_creds); +extern DECL_FUNC_PTR(krb5_free_addresses); +extern DECL_FUNC_PTR(krb5_get_default_config_files); +extern DECL_FUNC_PTR(krb5_free_config_files); +extern DECL_FUNC_PTR(krb5_get_default_realm); +extern DECL_FUNC_PTR(krb5_set_default_realm); +extern DECL_FUNC_PTR(krb5_free_ticket); +extern DECL_FUNC_PTR(krb5_decode_ticket); +extern DECL_FUNC_PTR(krb5_get_host_realm); +extern DECL_FUNC_PTR(krb5_free_host_realm); +extern DECL_FUNC_PTR(krb5_c_random_make_octets); +extern DECL_FUNC_PTR(krb5_free_default_realm); +extern DECL_FUNC_PTR(krb5_string_to_deltat); + +// Krb524 functions +extern DECL_FUNC_PTR(krb524_init_ets); +extern DECL_FUNC_PTR(krb524_convert_creds_kdc); + +// ComErr functions +extern DECL_FUNC_PTR(com_err); +extern DECL_FUNC_PTR(error_message); + +// Profile functions +extern DECL_FUNC_PTR(profile_init); +extern DECL_FUNC_PTR(profile_flush); +extern DECL_FUNC_PTR(profile_release); +extern DECL_FUNC_PTR(profile_get_subsection_names); +extern DECL_FUNC_PTR(profile_free_list); +extern DECL_FUNC_PTR(profile_get_string); +extern DECL_FUNC_PTR(profile_get_integer); +extern DECL_FUNC_PTR(profile_get_values); +extern DECL_FUNC_PTR(profile_get_relation_names); +extern DECL_FUNC_PTR(profile_clear_relation); +extern DECL_FUNC_PTR(profile_add_relation); +extern DECL_FUNC_PTR(profile_update_relation); +extern DECL_FUNC_PTR(profile_release_string); +extern DECL_FUNC_PTR(profile_rename_section); + +// Service functions +extern DECL_FUNC_PTR(OpenSCManagerA); +extern DECL_FUNC_PTR(OpenServiceA); +extern DECL_FUNC_PTR(QueryServiceStatus); +extern DECL_FUNC_PTR(CloseServiceHandle); +extern DECL_FUNC_PTR(LsaNtStatusToWinError); + +// LSA Functions +extern DECL_FUNC_PTR(LsaConnectUntrusted); +extern DECL_FUNC_PTR(LsaLookupAuthenticationPackage); +extern DECL_FUNC_PTR(LsaCallAuthenticationPackage); +extern DECL_FUNC_PTR(LsaFreeReturnBuffer); +extern DECL_FUNC_PTR(LsaGetLogonSessionData); + +// toolhelp functions +TYPEDEF_FUNC( + HANDLE, + WINAPI, + CreateToolhelp32Snapshot, + (DWORD, DWORD) + ); +TYPEDEF_FUNC( + BOOL, + WINAPI, + Module32First, + (HANDLE, LPMODULEENTRY32) + ); +TYPEDEF_FUNC( + BOOL, + WINAPI, + Module32Next, + (HANDLE, LPMODULEENTRY32) + ); + +// psapi functions +TYPEDEF_FUNC( + DWORD, + WINAPI, + GetModuleFileNameExA, + (HANDLE, HMODULE, LPSTR, DWORD) + ); + +TYPEDEF_FUNC( + BOOL, + WINAPI, + EnumProcessModules, + (HANDLE, HMODULE*, DWORD, LPDWORD) + ); + +#define pGetModuleFileNameEx pGetModuleFileNameExA +#define TOOLHELPDLL "kernel32.dll" +#define PSAPIDLL "psapi.dll" + +// psapi functions +extern DECL_FUNC_PTR(GetModuleFileNameExA); +extern DECL_FUNC_PTR(EnumProcessModules); + +// toolhelp functions +extern DECL_FUNC_PTR(CreateToolhelp32Snapshot); +extern DECL_FUNC_PTR(Module32First); +extern DECL_FUNC_PTR(Module32Next); + +khm_int32 init_imports(void); +khm_int32 exit_imports(void); + +#endif diff --git a/src/windows/identity/plugins/common/krb5common.c b/src/windows/identity/plugins/common/krb5common.c index 6c3958694..1278fbcfa 100644 --- a/src/windows/identity/plugins/common/krb5common.c +++ b/src/windows/identity/plugins/common/krb5common.c @@ -1,451 +1,451 @@ -/* - * 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 -#ifdef DEBUG -#include -#endif -#include - -/**************************************/ -/* khm_krb5_error(): */ -/**************************************/ -int -khm_krb5_error(krb5_error_code rc, LPCSTR FailedFunctionName, - int FreeContextFlag, krb5_context * ctx, - krb5_ccache * cache) -{ -#ifdef NO_KRB5 - return 0; -#else - -#ifdef SHOW_MESSAGE_IN_AN_ANNOYING_WAY - char message[256]; - const char *errText; - int krb5Error = ((int)(rc & 255)); - - errText = perror_message(rc); - _snprintf(message, sizeof(message), - "%s\n(Kerberos error %ld)\n\n%s failed", - errText, - krb5Error, - FailedFunctionName); - - MessageBoxA(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR | - MB_TASKMODAL | - MB_SETFOREGROUND); -#endif - - if (FreeContextFlag == 1) - { - if (*ctx != NULL) - { - if (*cache != NULL) { - pkrb5_cc_close(*ctx, *cache); - *cache = NULL; - } - - pkrb5_free_context(*ctx); - *ctx = NULL; - } - } - - return rc; - -#endif //!NO_KRB5 -} - -int -khm_krb5_initialize(khm_handle ident, - krb5_context *ctx, - krb5_ccache *cache) -{ -#ifdef NO_KRB5 - return(0); -#else - - LPCSTR functionName = NULL; - int freeContextFlag = 0; - krb5_error_code rc = 0; - krb5_flags flags = 0; - - if (pkrb5_init_context == NULL) - return 1; - - if (*ctx == 0 && (rc = (*pkrb5_init_context)(ctx))) { - functionName = "krb5_init_context()"; - freeContextFlag = 0; - goto on_error; - } - - if(*cache == 0) { - wchar_t wccname[MAX_PATH]; - khm_size cbwccname; - - if(ident != NULL) { - cbwccname = sizeof(wccname); - do { - char ccname[256]; - - if(KHM_FAILED(kcdb_identity_get_attrib(ident, L"Krb5CCName", - NULL, wccname, - &cbwccname))) { - cbwccname = sizeof(wccname); - if (KHM_FAILED - (khm_krb5_find_ccache_for_identity(ident, - ctx, - wccname, - &cbwccname))) { -#ifdef DEBUG_LIKE_A_MADMAN - assert(FALSE); -#endif - break; - } - } - - if(UnicodeStrToAnsi(ccname, sizeof(ccname), wccname) == 0) - break; - - if((*pkrb5_cc_resolve)(*ctx, ccname, cache)) { - functionName = "krb5_cc_resolve()"; - freeContextFlag = 1; - goto on_error; - } - } while(FALSE); - } - -#ifndef FAILOVER_TO_DEFAULT_CCACHE - rc = 1; -#endif - if (*cache == 0 -#ifdef FAILOVER_TO_DEFAULT_CCACHE - && (rc = (*pkrb5_cc_default)(*ctx, cache)) -#endif - ) { - functionName = "krb5_cc_default()"; - freeContextFlag = 1; - goto on_error; - } - } - -#ifdef KRB5_TC_NOTICKET - flags = KRB5_TC_NOTICKET; -#endif - - if ((rc = (*pkrb5_cc_set_flags)(*ctx, *cache, flags))) - { - if (rc != KRB5_FCC_NOFILE && rc != KRB5_CC_NOTFOUND) - khm_krb5_error(rc, "krb5_cc_set_flags()", 0, ctx, - cache); - else if ((rc == KRB5_FCC_NOFILE || rc == KRB5_CC_NOTFOUND) && *ctx != NULL) { - if (*cache != NULL) { - (*pkrb5_cc_close)(*ctx, *cache); - *cache = NULL; - } - } - return rc; - } - return 0; - -on_error: - return khm_krb5_error(rc, functionName, freeContextFlag, ctx, cache); -#endif //!NO_KRB5 -} - -#define TIMET_TOLERANCE (60*5) - -khm_int32 KHMAPI -khm_get_identity_expiration_time(krb5_context ctx, krb5_ccache cc, - khm_handle ident, - krb5_timestamp * pexpiration) -{ - krb5_principal principal = 0; - char * princ_name = NULL; - krb5_creds creds; - krb5_error_code code; - krb5_error_code cc_code; - krb5_cc_cursor cur; - krb5_timestamp now, expiration = 0; - - wchar_t w_ident_name[KCDB_IDENT_MAXCCH_NAME]; - char ident_name[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - - khm_int32 rv = KHM_ERROR_NOT_FOUND; - - if (!ctx || !cc || !ident || !pexpiration) - return KHM_ERROR_GENERAL; - - code = pkrb5_cc_get_principal(ctx, cc, &principal); - - if ( code ) - return KHM_ERROR_INVALID_PARAM; - - cb = sizeof(w_ident_name); - kcdb_identity_get_name(ident, w_ident_name, &cb); - UnicodeStrToAnsi(ident_name, sizeof(ident_name), w_ident_name); - - code = pkrb5_unparse_name(ctx, principal, &princ_name); - - /* compare principal to ident. */ - - if ( code || !princ_name || - strcmp(princ_name, ident_name) ) { - if (princ_name) - pkrb5_free_unparsed_name(ctx, princ_name); - pkrb5_free_principal(ctx, principal); - return KHM_ERROR_UNKNOWN; - } - - pkrb5_free_unparsed_name(ctx, princ_name); - pkrb5_free_principal(ctx, principal); - - code = pkrb5_timeofday(ctx, &now); - - if (code) - return KHM_ERROR_UNKNOWN; - - cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur); - - while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) { - krb5_data * c0 = krb5_princ_name(ctx, creds.server); - krb5_data * c1 = krb5_princ_component(ctx, creds.server, 1); - krb5_data * r = krb5_princ_realm(ctx, creds.server); - - if ( c0 && c1 && r && c1->length == r->length && - !strncmp(c1->data,r->data,r->length) && - !strncmp("krbtgt",c0->data,c0->length) ) { - - /* we have a TGT, check for the expiration time. - * if it is valid and renewable, use the renew time - */ - - if (!(creds.ticket_flags & TKT_FLG_INVALID) && - creds.times.starttime < (now + TIMET_TOLERANCE) && - (creds.times.endtime + TIMET_TOLERANCE) > now) { - expiration = creds.times.endtime; - - if ((creds.ticket_flags & TKT_FLG_RENEWABLE) && - (creds.times.renew_till > creds.times.endtime)) { - expiration = creds.times.renew_till; - } - } - } - } - - if (cc_code == KRB5_CC_END) { - cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur); - rv = KHM_ERROR_SUCCESS; - *pexpiration = expiration; - } - - return rv; -} - -khm_int32 KHMAPI -khm_krb5_find_ccache_for_identity(khm_handle ident, krb5_context *pctx, - void * buffer, khm_size * pcbbuf) -{ - krb5_context ctx = 0; - krb5_ccache cache = 0; - krb5_error_code code; - apiCB * cc_ctx = 0; - struct _infoNC ** pNCi = NULL; - int i; - khm_int32 t; - wchar_t * ms = NULL; - khm_size cb; - krb5_timestamp expiration = 0; - krb5_timestamp best_match_expiration = 0; - char best_match_ccname[256] = ""; - khm_handle csp_params = NULL; - khm_handle csp_plugins = NULL; - - if (!buffer || !pcbbuf) - return KHM_ERROR_GENERAL; - - ctx = *pctx; - - if (!pcc_initialize || - !pcc_get_NC_info || - !pcc_free_NC_info || - !pcc_shutdown) - goto _skip_cc_iter; - - code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL); - if (code) - goto _exit; - - code = pcc_get_NC_info(cc_ctx, &pNCi); - - if (code) - goto _exit; - - for(i=0; pNCi[i]; i++) { - if (pNCi[i]->vers != CC_CRED_V5) - continue; - - code = (*pkrb5_cc_resolve)(ctx, pNCi[i]->name, &cache); - if (code) - continue; - - /* need a function to check the cache for the identity - * and determine if it has valid tickets. If it has - * the right identity and valid tickets, store the - * expiration time and the cache name. If it has the - * right identity but no valid tickets, store the ccache - * name and an expiration time of zero. if it does not - * have the right identity don't save the name. - * - * Keep searching to find the best cache available. - */ - - if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache, - ident, - &expiration))) { - if ( expiration > best_match_expiration ) { - best_match_expiration = expiration; - StringCbCopyA(best_match_ccname, - sizeof(best_match_ccname), - "API:"); - StringCbCatA(best_match_ccname, - sizeof(best_match_ccname), - pNCi[i]->name); - expiration = 0; - } - } - - if(ctx != NULL && cache != NULL) - (*pkrb5_cc_close)(ctx, cache); - cache = 0; - } - - _skip_cc_iter: - - if (KHM_SUCCEEDED(kmm_get_plugins_config(0, &csp_plugins))) { - khc_open_space(csp_plugins, L"Krb5Cred\\Parameters", 0, &csp_params); - khc_close_space(csp_plugins); - csp_plugins = NULL; - } - -#ifdef DEBUG - if (csp_params == NULL) { - assert(FALSE); - } -#endif - - if (csp_params && - KHM_SUCCEEDED(khc_read_int32(csp_params, L"MsLsaList", &t)) && t) { - code = (*pkrb5_cc_resolve)(ctx, "MSLSA:", &cache); - if (code == 0 && cache) { - if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache, - ident, - &expiration))) { - if ( expiration > best_match_expiration ) { - best_match_expiration = expiration; - StringCbCopyA(best_match_ccname, sizeof(best_match_ccname), - "MSLSA:"); - expiration = 0; - } - } - } - - if (ctx != NULL && cache != NULL) - (*pkrb5_cc_close)(ctx, cache); - - cache = 0; - } - - if (csp_params && - khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb) - == KHM_ERROR_TOO_LONG && - cb > sizeof(wchar_t) * 2) { - - wchar_t * t; - char ccname[MAX_PATH + 6]; - - ms = PMALLOC(cb); - -#ifdef DEBUG - assert(ms); -#endif - - khc_read_multi_string(csp_params, L"FileCCList", ms, &cb); - for(t = ms; t && *t; t = multi_string_next(t)) { - StringCchPrintfA(ccname, ARRAYLENGTH(ccname), - "FILE:%S", t); - - code = (*pkrb5_cc_resolve)(ctx, ccname, &cache); - if (code) - continue; - - if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache, - ident, - &expiration))) { - if ( expiration > best_match_expiration ) { - best_match_expiration = expiration; - StringCbCopyA(best_match_ccname, - sizeof(best_match_ccname), - ccname); - expiration = 0; - } - } - - if (ctx != NULL && cache != NULL) - (*pkrb5_cc_close)(ctx, cache); - cache = 0; - } - - PFREE(ms); - } - _exit: - if (csp_params) - khc_close_space(csp_params); - - if (pNCi) - (*pcc_free_NC_info)(cc_ctx, &pNCi); - - if (cc_ctx) - (*pcc_shutdown)(&cc_ctx); - - if (best_match_ccname[0]) { - - if (*pcbbuf = AnsiStrToUnicode((wchar_t *)buffer, - *pcbbuf, - best_match_ccname)) { - - *pcbbuf = (*pcbbuf + 1) * sizeof(wchar_t); - - return KHM_ERROR_SUCCESS; - } - - } - - return KHM_ERROR_GENERAL; -} +/* + * 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 +#ifdef DEBUG +#include +#endif +#include + +/**************************************/ +/* khm_krb5_error(): */ +/**************************************/ +int +khm_krb5_error(krb5_error_code rc, LPCSTR FailedFunctionName, + int FreeContextFlag, krb5_context * ctx, + krb5_ccache * cache) +{ +#ifdef NO_KRB5 + return 0; +#else + +#ifdef SHOW_MESSAGE_IN_AN_ANNOYING_WAY + char message[256]; + const char *errText; + int krb5Error = ((int)(rc & 255)); + + errText = perror_message(rc); + _snprintf(message, sizeof(message), + "%s\n(Kerberos error %ld)\n\n%s failed", + errText, + krb5Error, + FailedFunctionName); + + MessageBoxA(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR | + MB_TASKMODAL | + MB_SETFOREGROUND); +#endif + + if (FreeContextFlag == 1) + { + if (*ctx != NULL) + { + if (*cache != NULL) { + pkrb5_cc_close(*ctx, *cache); + *cache = NULL; + } + + pkrb5_free_context(*ctx); + *ctx = NULL; + } + } + + return rc; + +#endif //!NO_KRB5 +} + +int +khm_krb5_initialize(khm_handle ident, + krb5_context *ctx, + krb5_ccache *cache) +{ +#ifdef NO_KRB5 + return(0); +#else + + LPCSTR functionName = NULL; + int freeContextFlag = 0; + krb5_error_code rc = 0; + krb5_flags flags = 0; + + if (pkrb5_init_context == NULL) + return 1; + + if (*ctx == 0 && (rc = (*pkrb5_init_context)(ctx))) { + functionName = "krb5_init_context()"; + freeContextFlag = 0; + goto on_error; + } + + if(*cache == 0) { + wchar_t wccname[MAX_PATH]; + khm_size cbwccname; + + if(ident != NULL) { + cbwccname = sizeof(wccname); + do { + char ccname[256]; + + if(KHM_FAILED(kcdb_identity_get_attrib(ident, L"Krb5CCName", + NULL, wccname, + &cbwccname))) { + cbwccname = sizeof(wccname); + if (KHM_FAILED + (khm_krb5_find_ccache_for_identity(ident, + ctx, + wccname, + &cbwccname))) { +#ifdef DEBUG_LIKE_A_MADMAN + assert(FALSE); +#endif + break; + } + } + + if(UnicodeStrToAnsi(ccname, sizeof(ccname), wccname) == 0) + break; + + if((*pkrb5_cc_resolve)(*ctx, ccname, cache)) { + functionName = "krb5_cc_resolve()"; + freeContextFlag = 1; + goto on_error; + } + } while(FALSE); + } + +#ifndef FAILOVER_TO_DEFAULT_CCACHE + rc = 1; +#endif + if (*cache == 0 +#ifdef FAILOVER_TO_DEFAULT_CCACHE + && (rc = (*pkrb5_cc_default)(*ctx, cache)) +#endif + ) { + functionName = "krb5_cc_default()"; + freeContextFlag = 1; + goto on_error; + } + } + +#ifdef KRB5_TC_NOTICKET + flags = KRB5_TC_NOTICKET; +#endif + + if ((rc = (*pkrb5_cc_set_flags)(*ctx, *cache, flags))) + { + if (rc != KRB5_FCC_NOFILE && rc != KRB5_CC_NOTFOUND) + khm_krb5_error(rc, "krb5_cc_set_flags()", 0, ctx, + cache); + else if ((rc == KRB5_FCC_NOFILE || rc == KRB5_CC_NOTFOUND) && *ctx != NULL) { + if (*cache != NULL) { + (*pkrb5_cc_close)(*ctx, *cache); + *cache = NULL; + } + } + return rc; + } + return 0; + +on_error: + return khm_krb5_error(rc, functionName, freeContextFlag, ctx, cache); +#endif //!NO_KRB5 +} + +#define TIMET_TOLERANCE (60*5) + +khm_int32 KHMAPI +khm_get_identity_expiration_time(krb5_context ctx, krb5_ccache cc, + khm_handle ident, + krb5_timestamp * pexpiration) +{ + krb5_principal principal = 0; + char * princ_name = NULL; + krb5_creds creds; + krb5_error_code code; + krb5_error_code cc_code; + krb5_cc_cursor cur; + krb5_timestamp now, expiration = 0; + + wchar_t w_ident_name[KCDB_IDENT_MAXCCH_NAME]; + char ident_name[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + + khm_int32 rv = KHM_ERROR_NOT_FOUND; + + if (!ctx || !cc || !ident || !pexpiration) + return KHM_ERROR_GENERAL; + + code = pkrb5_cc_get_principal(ctx, cc, &principal); + + if ( code ) + return KHM_ERROR_INVALID_PARAM; + + cb = sizeof(w_ident_name); + kcdb_identity_get_name(ident, w_ident_name, &cb); + UnicodeStrToAnsi(ident_name, sizeof(ident_name), w_ident_name); + + code = pkrb5_unparse_name(ctx, principal, &princ_name); + + /* compare principal to ident. */ + + if ( code || !princ_name || + strcmp(princ_name, ident_name) ) { + if (princ_name) + pkrb5_free_unparsed_name(ctx, princ_name); + pkrb5_free_principal(ctx, principal); + return KHM_ERROR_UNKNOWN; + } + + pkrb5_free_unparsed_name(ctx, princ_name); + pkrb5_free_principal(ctx, principal); + + code = pkrb5_timeofday(ctx, &now); + + if (code) + return KHM_ERROR_UNKNOWN; + + cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur); + + while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) { + krb5_data * c0 = krb5_princ_name(ctx, creds.server); + krb5_data * c1 = krb5_princ_component(ctx, creds.server, 1); + krb5_data * r = krb5_princ_realm(ctx, creds.server); + + if ( c0 && c1 && r && c1->length == r->length && + !strncmp(c1->data,r->data,r->length) && + !strncmp("krbtgt",c0->data,c0->length) ) { + + /* we have a TGT, check for the expiration time. + * if it is valid and renewable, use the renew time + */ + + if (!(creds.ticket_flags & TKT_FLG_INVALID) && + creds.times.starttime < (now + TIMET_TOLERANCE) && + (creds.times.endtime + TIMET_TOLERANCE) > now) { + expiration = creds.times.endtime; + + if ((creds.ticket_flags & TKT_FLG_RENEWABLE) && + (creds.times.renew_till > creds.times.endtime)) { + expiration = creds.times.renew_till; + } + } + } + } + + if (cc_code == KRB5_CC_END) { + cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur); + rv = KHM_ERROR_SUCCESS; + *pexpiration = expiration; + } + + return rv; +} + +khm_int32 KHMAPI +khm_krb5_find_ccache_for_identity(khm_handle ident, krb5_context *pctx, + void * buffer, khm_size * pcbbuf) +{ + krb5_context ctx = 0; + krb5_ccache cache = 0; + krb5_error_code code; + apiCB * cc_ctx = 0; + struct _infoNC ** pNCi = NULL; + int i; + khm_int32 t; + wchar_t * ms = NULL; + khm_size cb; + krb5_timestamp expiration = 0; + krb5_timestamp best_match_expiration = 0; + char best_match_ccname[256] = ""; + khm_handle csp_params = NULL; + khm_handle csp_plugins = NULL; + + if (!buffer || !pcbbuf) + return KHM_ERROR_GENERAL; + + ctx = *pctx; + + if (!pcc_initialize || + !pcc_get_NC_info || + !pcc_free_NC_info || + !pcc_shutdown) + goto _skip_cc_iter; + + code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL); + if (code) + goto _exit; + + code = pcc_get_NC_info(cc_ctx, &pNCi); + + if (code) + goto _exit; + + for(i=0; pNCi[i]; i++) { + if (pNCi[i]->vers != CC_CRED_V5) + continue; + + code = (*pkrb5_cc_resolve)(ctx, pNCi[i]->name, &cache); + if (code) + continue; + + /* need a function to check the cache for the identity + * and determine if it has valid tickets. If it has + * the right identity and valid tickets, store the + * expiration time and the cache name. If it has the + * right identity but no valid tickets, store the ccache + * name and an expiration time of zero. if it does not + * have the right identity don't save the name. + * + * Keep searching to find the best cache available. + */ + + if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache, + ident, + &expiration))) { + if ( expiration > best_match_expiration ) { + best_match_expiration = expiration; + StringCbCopyA(best_match_ccname, + sizeof(best_match_ccname), + "API:"); + StringCbCatA(best_match_ccname, + sizeof(best_match_ccname), + pNCi[i]->name); + expiration = 0; + } + } + + if(ctx != NULL && cache != NULL) + (*pkrb5_cc_close)(ctx, cache); + cache = 0; + } + + _skip_cc_iter: + + if (KHM_SUCCEEDED(kmm_get_plugins_config(0, &csp_plugins))) { + khc_open_space(csp_plugins, L"Krb5Cred\\Parameters", 0, &csp_params); + khc_close_space(csp_plugins); + csp_plugins = NULL; + } + +#ifdef DEBUG + if (csp_params == NULL) { + assert(FALSE); + } +#endif + + if (csp_params && + KHM_SUCCEEDED(khc_read_int32(csp_params, L"MsLsaList", &t)) && t) { + code = (*pkrb5_cc_resolve)(ctx, "MSLSA:", &cache); + if (code == 0 && cache) { + if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache, + ident, + &expiration))) { + if ( expiration > best_match_expiration ) { + best_match_expiration = expiration; + StringCbCopyA(best_match_ccname, sizeof(best_match_ccname), + "MSLSA:"); + expiration = 0; + } + } + } + + if (ctx != NULL && cache != NULL) + (*pkrb5_cc_close)(ctx, cache); + + cache = 0; + } + + if (csp_params && + khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb) + == KHM_ERROR_TOO_LONG && + cb > sizeof(wchar_t) * 2) { + + wchar_t * t; + char ccname[MAX_PATH + 6]; + + ms = PMALLOC(cb); + +#ifdef DEBUG + assert(ms); +#endif + + khc_read_multi_string(csp_params, L"FileCCList", ms, &cb); + for(t = ms; t && *t; t = multi_string_next(t)) { + StringCchPrintfA(ccname, ARRAYLENGTH(ccname), + "FILE:%S", t); + + code = (*pkrb5_cc_resolve)(ctx, ccname, &cache); + if (code) + continue; + + if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache, + ident, + &expiration))) { + if ( expiration > best_match_expiration ) { + best_match_expiration = expiration; + StringCbCopyA(best_match_ccname, + sizeof(best_match_ccname), + ccname); + expiration = 0; + } + } + + if (ctx != NULL && cache != NULL) + (*pkrb5_cc_close)(ctx, cache); + cache = 0; + } + + PFREE(ms); + } + _exit: + if (csp_params) + khc_close_space(csp_params); + + if (pNCi) + (*pcc_free_NC_info)(cc_ctx, &pNCi); + + if (cc_ctx) + (*pcc_shutdown)(&cc_ctx); + + if (best_match_ccname[0]) { + + if (*pcbbuf = AnsiStrToUnicode((wchar_t *)buffer, + *pcbbuf, + best_match_ccname)) { + + *pcbbuf = (*pcbbuf + 1) * sizeof(wchar_t); + + return KHM_ERROR_SUCCESS; + } + + } + + return KHM_ERROR_GENERAL; +} diff --git a/src/windows/identity/plugins/common/krb5common.h b/src/windows/identity/plugins/common/krb5common.h index df3db93ae..29cae71ee 100644 --- a/src/windows/identity/plugins/common/krb5common.h +++ b/src/windows/identity/plugins/common/krb5common.h @@ -1,56 +1,56 @@ -/* - * 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$ */ - -/* Adapted from multiple Leash header files */ - -#ifndef __KHIMAIRA_KRB5COMMON_H -#define __KHIMAIRA_KRB5COMMON_H - -#include - -#ifndef NO_KRB5 -int khm_krb5_error(krb5_error_code rc, LPCSTR FailedFunctionName, - int FreeContextFlag, krb5_context *ctx, - krb5_ccache *cache); - -int -khm_krb5_get_error_string(krb5_error_code rc, - wchar_t * buffer, - khm_size cb_buffer); - -int khm_krb5_initialize(khm_handle ident, krb5_context *, krb5_ccache *); - -khm_int32 KHMAPI -khm_krb5_find_ccache_for_identity(khm_handle ident, krb5_context *pctx, - void * buffer, khm_size * pcbbuf); - -khm_int32 KHMAPI -khm_get_identity_expiration_time(krb5_context ctx, krb5_ccache cc, - khm_handle ident, - krb5_timestamp * pexpiration); -#endif /* NO_KRB5 */ - -#endif +/* + * 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$ */ + +/* Adapted from multiple Leash header files */ + +#ifndef __KHIMAIRA_KRB5COMMON_H +#define __KHIMAIRA_KRB5COMMON_H + +#include + +#ifndef NO_KRB5 +int khm_krb5_error(krb5_error_code rc, LPCSTR FailedFunctionName, + int FreeContextFlag, krb5_context *ctx, + krb5_ccache *cache); + +int +khm_krb5_get_error_string(krb5_error_code rc, + wchar_t * buffer, + khm_size cb_buffer); + +int khm_krb5_initialize(khm_handle ident, krb5_context *, krb5_ccache *); + +khm_int32 KHMAPI +khm_krb5_find_ccache_for_identity(khm_handle ident, krb5_context *pctx, + void * buffer, khm_size * pcbbuf); + +khm_int32 KHMAPI +khm_get_identity_expiration_time(krb5_context ctx, krb5_ccache cc, + khm_handle ident, + krb5_timestamp * pexpiration); +#endif /* NO_KRB5 */ + +#endif diff --git a/src/windows/identity/plugins/krb4/errorfuncs.c b/src/windows/identity/plugins/krb4/errorfuncs.c index f1aa63d88..f436a40a7 100644 --- a/src/windows/identity/plugins/krb4/errorfuncs.c +++ b/src/windows/identity/plugins/krb4/errorfuncs.c @@ -1,226 +1,226 @@ -/* - * 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 - -extern void (__cdecl *pinitialize_krb_error_func)(); -extern void (__cdecl *pinitialize_kadm_error_table)(); - - -khm_int32 init_error_funcs() -{ - -#if 0 - /*TODO: Do something about this */ - if (plsh_LoadKrb4LeashErrorTables) - plsh_LoadKrb4LeashErrorTables(hLeashInst, 0); -#endif - return KHM_ERROR_SUCCESS; -} - -khm_int32 exit_error_funcs() -{ - return KHM_ERROR_SUCCESS; -} - -// Global Variables. -static long lsh_errno; -static char *err_context; /* error context */ -extern int (*Lcom_err)(LPSTR,long,LPSTR,...); -extern LPSTR (*Lerror_message)(long); -extern LPSTR (*Lerror_table_name)(long); - -#ifdef WIN16 -#define UNDERSCORE "_" -#else -#define UNDERSCORE -#endif - -HWND GetRootParent (HWND Child) -{ - HWND Last = NULL; - while (Child) - { - Last = Child; - Child = GetParent (Child); - } - return Last; -} - - -LPSTR err_describe(LPSTR buf, size_t len, long code) -{ - LPSTR cp, com_err_msg; - int offset; - long table_num; - char *etype; - - offset = (int) (code & 255); - table_num = code - offset; - com_err_msg = Lerror_message(code); - - switch(table_num) - { - case krb_err_base: - case kadm_err_base: - break; - default: - StringCbCopyA(buf, len, com_err_msg); - return buf; - } - - cp = buf; - if (table_num == krb_err_base) - switch(offset) - { - case KDC_NAME_EXP: /* 001 Principal expired */ - case KDC_SERVICE_EXP: /* 002 Service expired */ - case KDC_AUTH_EXP: /* 003 Auth expired */ - case KDC_PKT_VER: /* 004 Protocol version unknown */ - case KDC_P_MKEY_VER: /* 005 Wrong master key version */ - case KDC_S_MKEY_VER: /* 006 Wrong master key version */ - case KDC_BYTE_ORDER: /* 007 Byte order unknown */ - case KDC_PR_N_UNIQUE: /* 009 Principal not unique */ - case KDC_NULL_KEY: /* 010 Principal has null key */ - case KDC_GEN_ERR: /* 011 Generic error from KDC */ - case INTK_W_NOTALL : /* 061 Not ALL tickets returned */ - case INTK_PROT : /* 063 Protocol Error */ - case INTK_ERR : /* 070 Other error */ - com_err_msg = "Something weird happened... try again, and if Leash" - " continues to fail, contact Network Services as listed in the " - "About box."; - break; - case KDC_PR_UNKNOWN: /* 008 Principal unknown */ - com_err_msg = "You have entered an unknown username/instance/realm" - " combination."; - break; - case GC_TKFIL : /* 021 Can't read ticket file */ - case GC_NOTKT : /* 022 Can't find ticket or TGT */ - com_err_msg = "Something is wrong with the memory where your " - "tickets are stored. Try exiting Windows and restarting your " - "computer."; - break; - case MK_AP_TGTEXP : /* 026 TGT Expired */ - /* no extra error msg */ - break; - case RD_AP_TIME : /* 037 delta_t too big */ - com_err_msg = "Your computer's clock is out of sync with the " - "Kerberos server. Please see the help file about correcting " - "your clock."; - break; - - case RD_AP_UNDEC : /* 031 Can't decode authenticator */ - case RD_AP_EXP : /* 032 Ticket expired */ - case RD_AP_NYV : /* 033 Ticket not yet valid */ - case RD_AP_REPEAT : /* 034 Repeated request */ - case RD_AP_NOT_US : /* 035 The ticket isn't for us */ - case RD_AP_INCON : /* 036 Request is inconsistent */ - case RD_AP_BADD : /* 038 Incorrect net address */ - case RD_AP_VERSION : /* 039 protocol version mismatch */ - case RD_AP_MSG_TYPE : /* 040 invalid msg type */ - case RD_AP_MODIFIED : /* 041 message stream modified */ - case RD_AP_ORDER : /* 042 message out of order */ - case RD_AP_UNAUTHOR : /* 043 unauthorized request */ - /* no extra error msg */ - break; - case GT_PW_NULL: /* 51 Current PW is null */ - case GT_PW_BADPW: /* 52 Incorrect current password */ - case GT_PW_PROT: /* 53 Protocol Error */ - case GT_PW_KDCERR: /* 54 Error returned by KDC */ - case GT_PW_NULLTKT: /* 55 Null tkt returned by KDC */ - /* no error msg yet */ - break; - - /* Values returned by send_to_kdc */ - case SKDC_RETRY : /* 56 Retry count exceeded */ - case SKDC_CANT : /* 57 Can't send request */ - com_err_msg = "Cannot contact the kerberos server for the selected realm."; - break; - /* no error message on purpose: */ - case INTK_BADPW : /* 062 Incorrect password */ - break; - default: - /* no extra error msg */ - break; - } - else - switch(code) - { - case KADM_INSECURE_PW: - /* if( kadm_info != NULL ){ - * wsprintf(buf, "%s\n%s", com_err_msg, kadm_info); - * } else { - * wsprintf(buf, "%s\nPlease see the help file for information " - * "about secure passwords.", com_err_msg); - * } - * com_err_msg = buf; - */ - - /* The above code would be preferred since it allows site specific - * information to be delivered from the Kerberos server. However the - * message box is too small for VGA screens. - * It does work well if we only have to support 1024x768 - */ - - com_err_msg = "You have entered an insecure or weak password."; - - default: - /* no extra error msg */ - break; - } - if(com_err_msg != buf) { - StringCbCopyA(buf, len, com_err_msg); - } - cp = buf + strlen(buf); - *cp++ = '\n'; - switch(table_num) { - case krb_err_base: - etype = "Kerberos"; - break; - case kadm_err_base: - etype = "Kerberos supplemental"; - break; - default: - etype = Lerror_table_name(table_num); - break; - } - StringCbPrintfA((LPSTR) cp, len - (cp-buf), (LPSTR) "(%s error %d" -#ifdef DEBUG_COM_ERR - " (absolute error %ld)" -#endif - ")", etype, offset - //")\nPress F1 for help on this error.", etype, offset -#ifdef DEBUG_COM_ERR - , code -#endif - ); - - return (LPSTR)buf; -} - +/* + * 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 + +extern void (__cdecl *pinitialize_krb_error_func)(); +extern void (__cdecl *pinitialize_kadm_error_table)(); + + +khm_int32 init_error_funcs() +{ + +#if 0 + /*TODO: Do something about this */ + if (plsh_LoadKrb4LeashErrorTables) + plsh_LoadKrb4LeashErrorTables(hLeashInst, 0); +#endif + return KHM_ERROR_SUCCESS; +} + +khm_int32 exit_error_funcs() +{ + return KHM_ERROR_SUCCESS; +} + +// Global Variables. +static long lsh_errno; +static char *err_context; /* error context */ +extern int (*Lcom_err)(LPSTR,long,LPSTR,...); +extern LPSTR (*Lerror_message)(long); +extern LPSTR (*Lerror_table_name)(long); + +#ifdef WIN16 +#define UNDERSCORE "_" +#else +#define UNDERSCORE +#endif + +HWND GetRootParent (HWND Child) +{ + HWND Last = NULL; + while (Child) + { + Last = Child; + Child = GetParent (Child); + } + return Last; +} + + +LPSTR err_describe(LPSTR buf, size_t len, long code) +{ + LPSTR cp, com_err_msg; + int offset; + long table_num; + char *etype; + + offset = (int) (code & 255); + table_num = code - offset; + com_err_msg = Lerror_message(code); + + switch(table_num) + { + case krb_err_base: + case kadm_err_base: + break; + default: + StringCbCopyA(buf, len, com_err_msg); + return buf; + } + + cp = buf; + if (table_num == krb_err_base) + switch(offset) + { + case KDC_NAME_EXP: /* 001 Principal expired */ + case KDC_SERVICE_EXP: /* 002 Service expired */ + case KDC_AUTH_EXP: /* 003 Auth expired */ + case KDC_PKT_VER: /* 004 Protocol version unknown */ + case KDC_P_MKEY_VER: /* 005 Wrong master key version */ + case KDC_S_MKEY_VER: /* 006 Wrong master key version */ + case KDC_BYTE_ORDER: /* 007 Byte order unknown */ + case KDC_PR_N_UNIQUE: /* 009 Principal not unique */ + case KDC_NULL_KEY: /* 010 Principal has null key */ + case KDC_GEN_ERR: /* 011 Generic error from KDC */ + case INTK_W_NOTALL : /* 061 Not ALL tickets returned */ + case INTK_PROT : /* 063 Protocol Error */ + case INTK_ERR : /* 070 Other error */ + com_err_msg = "Something weird happened... try again, and if Leash" + " continues to fail, contact Network Services as listed in the " + "About box."; + break; + case KDC_PR_UNKNOWN: /* 008 Principal unknown */ + com_err_msg = "You have entered an unknown username/instance/realm" + " combination."; + break; + case GC_TKFIL : /* 021 Can't read ticket file */ + case GC_NOTKT : /* 022 Can't find ticket or TGT */ + com_err_msg = "Something is wrong with the memory where your " + "tickets are stored. Try exiting Windows and restarting your " + "computer."; + break; + case MK_AP_TGTEXP : /* 026 TGT Expired */ + /* no extra error msg */ + break; + case RD_AP_TIME : /* 037 delta_t too big */ + com_err_msg = "Your computer's clock is out of sync with the " + "Kerberos server. Please see the help file about correcting " + "your clock."; + break; + + case RD_AP_UNDEC : /* 031 Can't decode authenticator */ + case RD_AP_EXP : /* 032 Ticket expired */ + case RD_AP_NYV : /* 033 Ticket not yet valid */ + case RD_AP_REPEAT : /* 034 Repeated request */ + case RD_AP_NOT_US : /* 035 The ticket isn't for us */ + case RD_AP_INCON : /* 036 Request is inconsistent */ + case RD_AP_BADD : /* 038 Incorrect net address */ + case RD_AP_VERSION : /* 039 protocol version mismatch */ + case RD_AP_MSG_TYPE : /* 040 invalid msg type */ + case RD_AP_MODIFIED : /* 041 message stream modified */ + case RD_AP_ORDER : /* 042 message out of order */ + case RD_AP_UNAUTHOR : /* 043 unauthorized request */ + /* no extra error msg */ + break; + case GT_PW_NULL: /* 51 Current PW is null */ + case GT_PW_BADPW: /* 52 Incorrect current password */ + case GT_PW_PROT: /* 53 Protocol Error */ + case GT_PW_KDCERR: /* 54 Error returned by KDC */ + case GT_PW_NULLTKT: /* 55 Null tkt returned by KDC */ + /* no error msg yet */ + break; + + /* Values returned by send_to_kdc */ + case SKDC_RETRY : /* 56 Retry count exceeded */ + case SKDC_CANT : /* 57 Can't send request */ + com_err_msg = "Cannot contact the kerberos server for the selected realm."; + break; + /* no error message on purpose: */ + case INTK_BADPW : /* 062 Incorrect password */ + break; + default: + /* no extra error msg */ + break; + } + else + switch(code) + { + case KADM_INSECURE_PW: + /* if( kadm_info != NULL ){ + * wsprintf(buf, "%s\n%s", com_err_msg, kadm_info); + * } else { + * wsprintf(buf, "%s\nPlease see the help file for information " + * "about secure passwords.", com_err_msg); + * } + * com_err_msg = buf; + */ + + /* The above code would be preferred since it allows site specific + * information to be delivered from the Kerberos server. However the + * message box is too small for VGA screens. + * It does work well if we only have to support 1024x768 + */ + + com_err_msg = "You have entered an insecure or weak password."; + + default: + /* no extra error msg */ + break; + } + if(com_err_msg != buf) { + StringCbCopyA(buf, len, com_err_msg); + } + cp = buf + strlen(buf); + *cp++ = '\n'; + switch(table_num) { + case krb_err_base: + etype = "Kerberos"; + break; + case kadm_err_base: + etype = "Kerberos supplemental"; + break; + default: + etype = Lerror_table_name(table_num); + break; + } + StringCbPrintfA((LPSTR) cp, len - (cp-buf), (LPSTR) "(%s error %d" +#ifdef DEBUG_COM_ERR + " (absolute error %ld)" +#endif + ")", etype, offset + //")\nPress F1 for help on this error.", etype, offset +#ifdef DEBUG_COM_ERR + , code +#endif + ); + + return (LPSTR)buf; +} + diff --git a/src/windows/identity/plugins/krb4/errorfuncs.h b/src/windows/identity/plugins/krb4/errorfuncs.h index e339eca4f..d760c6259 100644 --- a/src/windows/identity/plugins/krb4/errorfuncs.h +++ b/src/windows/identity/plugins/krb4/errorfuncs.h @@ -1,65 +1,65 @@ -/* - * 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_ERR_H -#define __KHIMAIRA_ERR_H - -/* All error handling and reporting related functions for the krb4/5 - and AFS plugins */ - -#include -#include -/* - * This is a hack needed because the real com_err.h does - * not define err_func. We need it in the case where - * we pull in the real com_err instead of the krb4 - * impostor. - */ -#ifndef _DCNS_MIT_COM_ERR_H -typedef LPSTR (*err_func)(int, long); -#endif - -#include -#include - -#define kadm_err_base ERROR_TABLE_BASE_kadm - -#include - -#ifndef KRBERR -#define KRBERR(code) (code + krb_err_base) -#endif - -LPSTR err_describe(LPSTR buf, size_t len, long code); - - -/* */ -khm_int32 init_error_funcs(); - -khm_int32 exit_error_funcs(); - - -#endif +/* + * 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_ERR_H +#define __KHIMAIRA_ERR_H + +/* All error handling and reporting related functions for the krb4/5 + and AFS plugins */ + +#include +#include +/* + * This is a hack needed because the real com_err.h does + * not define err_func. We need it in the case where + * we pull in the real com_err instead of the krb4 + * impostor. + */ +#ifndef _DCNS_MIT_COM_ERR_H +typedef LPSTR (*err_func)(int, long); +#endif + +#include +#include + +#define kadm_err_base ERROR_TABLE_BASE_kadm + +#include + +#ifndef KRBERR +#define KRBERR(code) (code + krb_err_base) +#endif + +LPSTR err_describe(LPSTR buf, size_t len, long code); + + +/* */ +khm_int32 init_error_funcs(); + +khm_int32 exit_error_funcs(); + + +#endif diff --git a/src/windows/identity/plugins/krb4/krb4configdlg.c b/src/windows/identity/plugins/krb4/krb4configdlg.c index 523fbac5e..338cf7fa8 100644 --- a/src/windows/identity/plugins/krb4/krb4configdlg.c +++ b/src/windows/identity/plugins/krb4/krb4configdlg.c @@ -1,539 +1,539 @@ -/* - * 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 - -typedef struct tag_k4_ids_data { - khui_config_init_data cfg; - - khm_int32 get_tix; -} k4_ids_data; - -static void -k4_ids_read_params(k4_ids_data * d) { - khm_int32 t; -#ifdef DEBUG - assert(csp_params); -#endif - - t = 1; - khc_read_int32(csp_params, L"Krb4NewCreds", &t); - d->get_tix = !!t; -} - -static void -k4_ids_write_params(HWND hw, k4_ids_data * d) { - khm_int32 nv; - khm_boolean applied = FALSE; - - if (IsDlgButtonChecked(hw, IDC_CFG_GETTIX) == BST_CHECKED) - nv = TRUE; - else - nv = FALSE; - - if (!!nv != !!d->get_tix) { - d->get_tix = !!nv; - khc_write_int32(csp_params, L"Krb4NewCreds", d->get_tix); - applied = TRUE; - } - - khui_cfg_set_flags_inst(&d->cfg, - (applied)?KHUI_CNFLAG_APPLIED:0, - KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); -} - -static void -k4_ids_check_mod(HWND hw, k4_ids_data * d) { - khm_int32 nv; - - if (IsDlgButtonChecked(hw, IDC_CFG_GETTIX) == BST_CHECKED) - nv = TRUE; - else - nv = FALSE; - - khui_cfg_set_flags_inst(&d->cfg, - (!!nv != !!d->get_tix)? KHUI_CNFLAG_MODIFIED: 0, - KHUI_CNFLAG_MODIFIED); -} - -INT_PTR CALLBACK -krb4_ids_config_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - k4_ids_data * d; - - switch(uMsg) { - case WM_INITDIALOG: - d = PMALLOC(sizeof(*d)); - ZeroMemory(d, sizeof(*d)); - - d->cfg = *((khui_config_init_data *) lParam); - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); -#pragma warning(pop) - - k4_ids_read_params(d); - - CheckDlgButton(hwnd, IDC_CFG_GETTIX, - (d->get_tix)? BST_CHECKED: BST_UNCHECKED); - - break; - - case WM_COMMAND: - d = (k4_ids_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (HIWORD(wParam) == BN_CLICKED) { - k4_ids_check_mod(hwnd, d); - } - break; - - case KHUI_WM_CFG_NOTIFY: - d = (k4_ids_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (HIWORD(wParam) == WMCFG_APPLY) { - k4_ids_write_params(hwnd, d); - } - break; - - case WM_DESTROY: - d = (k4_ids_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - PFREE(d); - break; - } - - return FALSE; -} - -typedef struct tag_k4_id_data { - khui_config_init_data cfg; - khm_int32 gettix; /* get tickets? */ - khm_boolean is_default_ident; -} k4_id_data; - -void -k4_id_read_params(k4_id_data * d) { - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - khm_handle ident = NULL; - khm_handle csp_ident = NULL; - khm_handle csp_idk4 = NULL; - khm_int32 flags = 0; - khm_int32 t; - - khc_read_int32(csp_params, L"Krb4NewCreds", &d->gettix); - - *idname = 0; - cb = sizeof(idname); - khui_cfg_get_name(d->cfg.ctx_node, idname, &cb); - - kcdb_identity_create(idname, 0, &ident); - - if (ident == NULL) { - d->gettix = 0; - goto done; - } - - kcdb_identity_get_flags(ident, &flags); - - if (!(flags & KCDB_IDENT_FLAG_DEFAULT)) { - d->gettix = 0; - goto done; - } - - d->is_default_ident = TRUE; - - if (d->gettix == 0) - goto done; - - if (KHM_FAILED(kcdb_identity_get_config(ident, 0, &csp_ident))) - goto done; - - if (KHM_FAILED(khc_open_space(csp_ident, CSNAME_KRB4CRED, - 0, &csp_idk4))) - goto close_config; - - if (KHM_SUCCEEDED(khc_read_int32(csp_idk4, L"Krb4NewCreds", &t)) && - !t) - d->gettix = 1; - - close_config: - if (csp_ident) - khc_close_space(csp_ident); - - if (csp_idk4) - khc_close_space(csp_idk4); - - done: - if (ident) - kcdb_identity_release(ident); - - return; -} - -khm_boolean -k4_id_write_params(HWND hwnd, k4_id_data * d) { - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb_idname = sizeof(idname); - khm_handle ident = NULL; - khm_int32 flags = 0; - khm_handle csp_ident = NULL; - khm_handle csp_idk4 = NULL; - khm_int32 gettix = 0; - khm_boolean applied = FALSE; - - khui_cfg_get_name(d->cfg.ctx_node, idname, &cb_idname); - - kcdb_identity_create(idname, 0, &ident); - - if (ident == NULL) - return FALSE; - - kcdb_identity_get_flags(ident, &flags); - - if (!(flags & KCDB_IDENT_FLAG_DEFAULT)) - goto done_apply; - - if (IsDlgButtonChecked(hwnd, IDC_CFG_GETTIX) == BST_CHECKED) - gettix = TRUE; - - if (KHM_FAILED(kcdb_identity_get_config(ident, KHM_FLAG_CREATE, - &csp_ident))) - goto done_apply; - - if (KHM_FAILED(khc_open_space(csp_ident, CSNAME_KRB4CRED, - KHM_FLAG_CREATE | KCONF_FLAG_WRITEIFMOD, - &csp_idk4))) - goto done_apply; - - khc_write_int32(csp_idk4, L"Krb4NewCreds", gettix); - - applied = TRUE; - - done_apply: - if (ident) - kcdb_identity_release(ident); - - if (csp_ident) - khc_close_space(csp_ident); - - if (csp_idk4) - khc_close_space(csp_idk4); - - return applied; -} - -INT_PTR CALLBACK -krb4_id_config_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - switch(uMsg) { - case WM_INITDIALOG: - { - k4_id_data * d; - - d = PMALLOC(sizeof(k4_id_data)); - - if (!d) - break; - - ZeroMemory(d, sizeof(*d)); - - d->cfg = *((khui_config_init_data *) lParam); - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); -#pragma warning(pop) - - k4_id_read_params(d); - - CheckDlgButton(hwnd, IDC_CFG_GETTIX, - (d->gettix)?BST_CHECKED: BST_UNCHECKED); - EnableWindow(GetDlgItem(hwnd, IDC_CFG_GETTIX), - d->is_default_ident); - - } - break; - - case WM_COMMAND: - { - k4_id_data * d; - - d = (k4_id_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (wParam == MAKEWPARAM(IDC_CFG_GETTIX, - BN_CLICKED)) { - int gettix = 0; - int modified = 0; - - gettix = (IsDlgButtonChecked(hwnd, IDC_CFG_GETTIX) == - BST_CHECKED); - - modified = (!!gettix != !!d->gettix); - - khui_cfg_set_flags_inst(&d->cfg, - ((modified)?KHUI_CNFLAG_MODIFIED: 0), - KHUI_CNFLAG_MODIFIED); - } - } - break; - - case KHUI_WM_CFG_NOTIFY: - { - k4_id_data * d; - - d = (k4_id_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (!d) - break; - - if (HIWORD(wParam) == WMCFG_APPLY) { - khm_int32 applied; - - applied = k4_id_write_params(hwnd, d); - - khui_cfg_set_flags_inst(&d->cfg, - ((applied)? KHUI_CNFLAG_APPLIED: 0), - (KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED)); - } - } - break; - - case WM_DESTROY: - { - k4_id_data * d; - - d = (k4_id_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (!d) - break; - - PFREE(d); - } - break; - } - - return FALSE; -} - -typedef struct tag_k4_config_dlg_data { - khui_config_node node; - char krb_path[MAX_PATH]; - char krbrealm_path[MAX_PATH]; - char tkt_string[MAX_PATH]; -} k4_config_dlg_data; - -INT_PTR CALLBACK -krb4_confg_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - - static BOOL in_init = FALSE; - k4_config_dlg_data * d; - - switch(uMsg) { - case WM_INITDIALOG: - { - wchar_t wbuf[MAX_PATH]; - CHAR krb_path[MAX_PATH]; - CHAR krbrealm_path[MAX_PATH]; - CHAR ticketName[MAX_PATH]; - char * pticketName; - unsigned int krb_path_sz = sizeof(krb_path); - unsigned int krbrealm_path_sz = sizeof(krbrealm_path); - khm_size cbsize; - - d = PMALLOC(sizeof(*d)); - ZeroMemory(d, sizeof(*d)); - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); -#pragma warning(pop) - - d->node = (khui_config_node) lParam; - - in_init = TRUE; - - // Set KRB.CON - memset(krb_path, '\0', sizeof(krb_path)); - if (!pkrb_get_krbconf2(krb_path, &krb_path_sz)) { - // Error has happened - } else { // normal find - AnsiStrToUnicode(wbuf, sizeof(wbuf), krb_path); - SetDlgItemText(hwnd, IDC_CFG_CFGPATH, wbuf); - StringCbCopyA(d->krb_path, sizeof(d->krb_path), krb_path); - } - - // Set KRBREALM.CON - memset(krbrealm_path, '\0', sizeof(krbrealm_path)); - if (!pkrb_get_krbrealm2(krbrealm_path, &krbrealm_path_sz)) { - // Error has happened - } else { - AnsiStrToUnicode(wbuf, sizeof(wbuf), krbrealm_path); - SetDlgItemText(hwnd, IDC_CFG_RLMPATH, wbuf); - StringCbCopyA(d->krbrealm_path, sizeof(d->krbrealm_path), - krbrealm_path); - } - - cbsize = sizeof(wbuf); - if (KHM_SUCCEEDED(khc_read_string(csp_params, L"TktString", - wbuf, &cbsize)) && - wbuf[0] != L'\0') { - - UnicodeStrToAnsi(ticketName, sizeof(ticketName), wbuf); - - } else { - - // Set TICKET.KRB file Editbox - *ticketName = 0; - pkrb_set_tkt_string(0); - - pticketName = ptkt_string(); - if (pticketName) - StringCbCopyA(ticketName, sizeof(ticketName), pticketName); - - } - - if (!*ticketName) { - // error - } else { - AnsiStrToUnicode(wbuf, sizeof(wbuf), ticketName); - SetDlgItemText(hwnd, IDC_CFG_CACHE, wbuf); - StringCbCopyA(d->tkt_string, sizeof(d->tkt_string), - ticketName); - } - - in_init = FALSE; - - } - break; - - case WM_COMMAND: - if (MAKEWPARAM(IDC_CFG_CACHE, EN_CHANGE)) { - char tkt_string[MAX_PATH]; - wchar_t wtkt_string[MAX_PATH]; - - if (in_init) { - return TRUE; - } - - d = (k4_config_dlg_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (d == NULL) - return TRUE; - - tkt_string[0] = 0; - wtkt_string[0] = 0; - - GetDlgItemText(hwnd, IDC_CFG_CACHE, - wtkt_string, ARRAYLENGTH(wtkt_string)); - UnicodeStrToAnsi(tkt_string, sizeof(tkt_string), - wtkt_string); - - if (_stricmp(tkt_string, d->tkt_string)) { - khui_cfg_set_flags(d->node, - KHUI_CNFLAG_MODIFIED, - KHUI_CNFLAG_MODIFIED); - } else { - khui_cfg_set_flags(d->node, - 0, - KHUI_CNFLAG_MODIFIED); - } - - return TRUE; - } - break; - - case KHUI_WM_CFG_NOTIFY: - if (HIWORD(wParam) == WMCFG_APPLY) { - wchar_t wtkt_string[MAX_PATH]; - char tkt_string[MAX_PATH]; - int t; - - d = (k4_config_dlg_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (d == NULL) - return TRUE; - - t = GetDlgItemText(hwnd, IDC_CFG_CACHE, - wtkt_string, ARRAYLENGTH(wtkt_string)); - if (t == 0) - return TRUE; - - UnicodeStrToAnsi(tkt_string, sizeof(tkt_string), wtkt_string); - - if (_stricmp(tkt_string, d->tkt_string)) { - - pkrb_set_tkt_string(tkt_string); - - khc_write_string(csp_params, L"TktString", wtkt_string); - - khui_cfg_set_flags(d->node, - KHUI_CNFLAG_APPLIED, - KHUI_CNFLAG_APPLIED | - KHUI_CNFLAG_MODIFIED); - khm_krb4_list_tickets(); - } else { - khui_cfg_set_flags(d->node, - 0, - KHUI_CNFLAG_MODIFIED); - } - - return TRUE; - } - break; - - case WM_DESTROY: - d = (k4_config_dlg_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (d) { - PFREE(d); - } - - break; - } - return FALSE; -} +/* + * 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 + +typedef struct tag_k4_ids_data { + khui_config_init_data cfg; + + khm_int32 get_tix; +} k4_ids_data; + +static void +k4_ids_read_params(k4_ids_data * d) { + khm_int32 t; +#ifdef DEBUG + assert(csp_params); +#endif + + t = 1; + khc_read_int32(csp_params, L"Krb4NewCreds", &t); + d->get_tix = !!t; +} + +static void +k4_ids_write_params(HWND hw, k4_ids_data * d) { + khm_int32 nv; + khm_boolean applied = FALSE; + + if (IsDlgButtonChecked(hw, IDC_CFG_GETTIX) == BST_CHECKED) + nv = TRUE; + else + nv = FALSE; + + if (!!nv != !!d->get_tix) { + d->get_tix = !!nv; + khc_write_int32(csp_params, L"Krb4NewCreds", d->get_tix); + applied = TRUE; + } + + khui_cfg_set_flags_inst(&d->cfg, + (applied)?KHUI_CNFLAG_APPLIED:0, + KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); +} + +static void +k4_ids_check_mod(HWND hw, k4_ids_data * d) { + khm_int32 nv; + + if (IsDlgButtonChecked(hw, IDC_CFG_GETTIX) == BST_CHECKED) + nv = TRUE; + else + nv = FALSE; + + khui_cfg_set_flags_inst(&d->cfg, + (!!nv != !!d->get_tix)? KHUI_CNFLAG_MODIFIED: 0, + KHUI_CNFLAG_MODIFIED); +} + +INT_PTR CALLBACK +krb4_ids_config_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + k4_ids_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + d = PMALLOC(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + + d->cfg = *((khui_config_init_data *) lParam); + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + k4_ids_read_params(d); + + CheckDlgButton(hwnd, IDC_CFG_GETTIX, + (d->get_tix)? BST_CHECKED: BST_UNCHECKED); + + break; + + case WM_COMMAND: + d = (k4_ids_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == BN_CLICKED) { + k4_ids_check_mod(hwnd, d); + } + break; + + case KHUI_WM_CFG_NOTIFY: + d = (k4_ids_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == WMCFG_APPLY) { + k4_ids_write_params(hwnd, d); + } + break; + + case WM_DESTROY: + d = (k4_ids_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + PFREE(d); + break; + } + + return FALSE; +} + +typedef struct tag_k4_id_data { + khui_config_init_data cfg; + khm_int32 gettix; /* get tickets? */ + khm_boolean is_default_ident; +} k4_id_data; + +void +k4_id_read_params(k4_id_data * d) { + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khm_handle ident = NULL; + khm_handle csp_ident = NULL; + khm_handle csp_idk4 = NULL; + khm_int32 flags = 0; + khm_int32 t; + + khc_read_int32(csp_params, L"Krb4NewCreds", &d->gettix); + + *idname = 0; + cb = sizeof(idname); + khui_cfg_get_name(d->cfg.ctx_node, idname, &cb); + + kcdb_identity_create(idname, 0, &ident); + + if (ident == NULL) { + d->gettix = 0; + goto done; + } + + kcdb_identity_get_flags(ident, &flags); + + if (!(flags & KCDB_IDENT_FLAG_DEFAULT)) { + d->gettix = 0; + goto done; + } + + d->is_default_ident = TRUE; + + if (d->gettix == 0) + goto done; + + if (KHM_FAILED(kcdb_identity_get_config(ident, 0, &csp_ident))) + goto done; + + if (KHM_FAILED(khc_open_space(csp_ident, CSNAME_KRB4CRED, + 0, &csp_idk4))) + goto close_config; + + if (KHM_SUCCEEDED(khc_read_int32(csp_idk4, L"Krb4NewCreds", &t)) && + !t) + d->gettix = 1; + + close_config: + if (csp_ident) + khc_close_space(csp_ident); + + if (csp_idk4) + khc_close_space(csp_idk4); + + done: + if (ident) + kcdb_identity_release(ident); + + return; +} + +khm_boolean +k4_id_write_params(HWND hwnd, k4_id_data * d) { + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb_idname = sizeof(idname); + khm_handle ident = NULL; + khm_int32 flags = 0; + khm_handle csp_ident = NULL; + khm_handle csp_idk4 = NULL; + khm_int32 gettix = 0; + khm_boolean applied = FALSE; + + khui_cfg_get_name(d->cfg.ctx_node, idname, &cb_idname); + + kcdb_identity_create(idname, 0, &ident); + + if (ident == NULL) + return FALSE; + + kcdb_identity_get_flags(ident, &flags); + + if (!(flags & KCDB_IDENT_FLAG_DEFAULT)) + goto done_apply; + + if (IsDlgButtonChecked(hwnd, IDC_CFG_GETTIX) == BST_CHECKED) + gettix = TRUE; + + if (KHM_FAILED(kcdb_identity_get_config(ident, KHM_FLAG_CREATE, + &csp_ident))) + goto done_apply; + + if (KHM_FAILED(khc_open_space(csp_ident, CSNAME_KRB4CRED, + KHM_FLAG_CREATE | KCONF_FLAG_WRITEIFMOD, + &csp_idk4))) + goto done_apply; + + khc_write_int32(csp_idk4, L"Krb4NewCreds", gettix); + + applied = TRUE; + + done_apply: + if (ident) + kcdb_identity_release(ident); + + if (csp_ident) + khc_close_space(csp_ident); + + if (csp_idk4) + khc_close_space(csp_idk4); + + return applied; +} + +INT_PTR CALLBACK +krb4_id_config_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + { + k4_id_data * d; + + d = PMALLOC(sizeof(k4_id_data)); + + if (!d) + break; + + ZeroMemory(d, sizeof(*d)); + + d->cfg = *((khui_config_init_data *) lParam); + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + k4_id_read_params(d); + + CheckDlgButton(hwnd, IDC_CFG_GETTIX, + (d->gettix)?BST_CHECKED: BST_UNCHECKED); + EnableWindow(GetDlgItem(hwnd, IDC_CFG_GETTIX), + d->is_default_ident); + + } + break; + + case WM_COMMAND: + { + k4_id_data * d; + + d = (k4_id_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (wParam == MAKEWPARAM(IDC_CFG_GETTIX, + BN_CLICKED)) { + int gettix = 0; + int modified = 0; + + gettix = (IsDlgButtonChecked(hwnd, IDC_CFG_GETTIX) == + BST_CHECKED); + + modified = (!!gettix != !!d->gettix); + + khui_cfg_set_flags_inst(&d->cfg, + ((modified)?KHUI_CNFLAG_MODIFIED: 0), + KHUI_CNFLAG_MODIFIED); + } + } + break; + + case KHUI_WM_CFG_NOTIFY: + { + k4_id_data * d; + + d = (k4_id_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (!d) + break; + + if (HIWORD(wParam) == WMCFG_APPLY) { + khm_int32 applied; + + applied = k4_id_write_params(hwnd, d); + + khui_cfg_set_flags_inst(&d->cfg, + ((applied)? KHUI_CNFLAG_APPLIED: 0), + (KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED)); + } + } + break; + + case WM_DESTROY: + { + k4_id_data * d; + + d = (k4_id_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (!d) + break; + + PFREE(d); + } + break; + } + + return FALSE; +} + +typedef struct tag_k4_config_dlg_data { + khui_config_node node; + char krb_path[MAX_PATH]; + char krbrealm_path[MAX_PATH]; + char tkt_string[MAX_PATH]; +} k4_config_dlg_data; + +INT_PTR CALLBACK +krb4_confg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + static BOOL in_init = FALSE; + k4_config_dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + { + wchar_t wbuf[MAX_PATH]; + CHAR krb_path[MAX_PATH]; + CHAR krbrealm_path[MAX_PATH]; + CHAR ticketName[MAX_PATH]; + char * pticketName; + unsigned int krb_path_sz = sizeof(krb_path); + unsigned int krbrealm_path_sz = sizeof(krbrealm_path); + khm_size cbsize; + + d = PMALLOC(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + d->node = (khui_config_node) lParam; + + in_init = TRUE; + + // Set KRB.CON + memset(krb_path, '\0', sizeof(krb_path)); + if (!pkrb_get_krbconf2(krb_path, &krb_path_sz)) { + // Error has happened + } else { // normal find + AnsiStrToUnicode(wbuf, sizeof(wbuf), krb_path); + SetDlgItemText(hwnd, IDC_CFG_CFGPATH, wbuf); + StringCbCopyA(d->krb_path, sizeof(d->krb_path), krb_path); + } + + // Set KRBREALM.CON + memset(krbrealm_path, '\0', sizeof(krbrealm_path)); + if (!pkrb_get_krbrealm2(krbrealm_path, &krbrealm_path_sz)) { + // Error has happened + } else { + AnsiStrToUnicode(wbuf, sizeof(wbuf), krbrealm_path); + SetDlgItemText(hwnd, IDC_CFG_RLMPATH, wbuf); + StringCbCopyA(d->krbrealm_path, sizeof(d->krbrealm_path), + krbrealm_path); + } + + cbsize = sizeof(wbuf); + if (KHM_SUCCEEDED(khc_read_string(csp_params, L"TktString", + wbuf, &cbsize)) && + wbuf[0] != L'\0') { + + UnicodeStrToAnsi(ticketName, sizeof(ticketName), wbuf); + + } else { + + // Set TICKET.KRB file Editbox + *ticketName = 0; + pkrb_set_tkt_string(0); + + pticketName = ptkt_string(); + if (pticketName) + StringCbCopyA(ticketName, sizeof(ticketName), pticketName); + + } + + if (!*ticketName) { + // error + } else { + AnsiStrToUnicode(wbuf, sizeof(wbuf), ticketName); + SetDlgItemText(hwnd, IDC_CFG_CACHE, wbuf); + StringCbCopyA(d->tkt_string, sizeof(d->tkt_string), + ticketName); + } + + in_init = FALSE; + + } + break; + + case WM_COMMAND: + if (MAKEWPARAM(IDC_CFG_CACHE, EN_CHANGE)) { + char tkt_string[MAX_PATH]; + wchar_t wtkt_string[MAX_PATH]; + + if (in_init) { + return TRUE; + } + + d = (k4_config_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (d == NULL) + return TRUE; + + tkt_string[0] = 0; + wtkt_string[0] = 0; + + GetDlgItemText(hwnd, IDC_CFG_CACHE, + wtkt_string, ARRAYLENGTH(wtkt_string)); + UnicodeStrToAnsi(tkt_string, sizeof(tkt_string), + wtkt_string); + + if (_stricmp(tkt_string, d->tkt_string)) { + khui_cfg_set_flags(d->node, + KHUI_CNFLAG_MODIFIED, + KHUI_CNFLAG_MODIFIED); + } else { + khui_cfg_set_flags(d->node, + 0, + KHUI_CNFLAG_MODIFIED); + } + + return TRUE; + } + break; + + case KHUI_WM_CFG_NOTIFY: + if (HIWORD(wParam) == WMCFG_APPLY) { + wchar_t wtkt_string[MAX_PATH]; + char tkt_string[MAX_PATH]; + int t; + + d = (k4_config_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (d == NULL) + return TRUE; + + t = GetDlgItemText(hwnd, IDC_CFG_CACHE, + wtkt_string, ARRAYLENGTH(wtkt_string)); + if (t == 0) + return TRUE; + + UnicodeStrToAnsi(tkt_string, sizeof(tkt_string), wtkt_string); + + if (_stricmp(tkt_string, d->tkt_string)) { + + pkrb_set_tkt_string(tkt_string); + + khc_write_string(csp_params, L"TktString", wtkt_string); + + khui_cfg_set_flags(d->node, + KHUI_CNFLAG_APPLIED, + KHUI_CNFLAG_APPLIED | + KHUI_CNFLAG_MODIFIED); + khm_krb4_list_tickets(); + } else { + khui_cfg_set_flags(d->node, + 0, + KHUI_CNFLAG_MODIFIED); + } + + return TRUE; + } + break; + + case WM_DESTROY: + d = (k4_config_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (d) { + PFREE(d); + } + + break; + } + return FALSE; +} diff --git a/src/windows/identity/plugins/krb4/krb4funcs.c b/src/windows/identity/plugins/krb4/krb4funcs.c index b2b5fef4e..9e9ba42d2 100644 --- a/src/windows/identity/plugins/krb4/krb4funcs.c +++ b/src/windows/identity/plugins/krb4/krb4funcs.c @@ -1,897 +1,897 @@ -/* -* 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$ */ - -/* Originally this was krb5routines.c in Leash sources. Subsequently -modified and adapted for NetIDMgr */ - -#include -#include - -#define SECURITY_WIN32 -#include - -#include -#include -#include -#include - - - -int com_addr(void) -{ - long ipAddr; - char loc_addr[ADDR_SZ]; - CREDENTIALS cred; - char service[40]; - char instance[40]; - // char addr[40]; - char realm[40]; - struct in_addr LocAddr; - int k_errno; - - if (pkrb_get_cred == NULL) - return(KSUCCESS); - - k_errno = (*pkrb_get_cred)(service,instance,realm,&cred); - if (k_errno) - return KRBERR(k_errno); - - while(1) { - ipAddr = (*pLocalHostAddr)(); - LocAddr.s_addr = ipAddr; - StringCbCopyA(loc_addr, sizeof(loc_addr), inet_ntoa(LocAddr)); - if ( strcmp(cred.address,loc_addr) != 0) { - /* TODO: do something about this */ - //Leash_kdestroy (); - break; - } - break; - } // while() - return 0; -} - - -long -khm_krb4_list_tickets(void) -{ - char ptktname[MAX_PATH + 5]; - char pname[ANAME_SZ]; - char pinst[INST_SZ]; - char prealm[REALM_SZ]; - wchar_t wbuf[256]; - int k_errno = 0; - CREDENTIALS c; - int newtickets = 0; - int open = 0; - khm_handle ident = NULL; - khm_handle cred = NULL; - time_t tt; - FILETIME ft; - - kcdb_credset_flush(krb4_credset); - - // Since krb_get_tf_realm will return a ticket_file error, - // we will call tf_init and tf_close first to filter out - // things like no ticket file. Otherwise, the error that - // the user would see would be - // klist: can't find realm of ticket file: No ticket file (tf_util) - // instead of klist: No ticket file (tf_util) - if (ptf_init == NULL) - goto collect; - - com_addr(); - - // Open ticket file - if ((k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL))) - { - goto cleanup; - } - // Close ticket file - (void) (*ptf_close)(); - - // We must find the realm of the ticket file here before calling - // tf_init because since the realm of the ticket file is not - // really stored in the principal section of the file, the - // routine we use must itself call tf_init and tf_close. - - if ((k_errno = (*pkrb_get_tf_realm)((*ptkt_string)(), prealm)) != KSUCCESS) - { - goto cleanup; - } - - // Open ticket file - if (k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL)) - { - goto cleanup; - } - - StringCchCopyA(ptktname, ARRAYLENGTH(ptktname), (*ptkt_string)()); - - open = 1; - - // Get principal name and instance - if ((k_errno = (*ptf_get_pname)(pname)) || (k_errno = (*ptf_get_pinst)(pinst))) - { - goto cleanup; - } - - // You may think that this is the obvious place to get the - // realm of the ticket file, but it can't be done here as the - // routine to do this must open the ticket file. This is why - // it was done before tf_init. - StringCbPrintf(wbuf, sizeof(wbuf), L"%S%S%S%S%S", (LPSTR)pname, - (LPSTR)(pinst[0] ? "." : ""), (LPSTR)pinst, - (LPSTR)(prealm[0] ? "@" : ""), (LPSTR)prealm); - - if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, &ident))) - { - goto cleanup; - } - - // Get KRB4 tickets - while ((k_errno = (*ptf_get_cred)(&c)) == KSUCCESS) - { - StringCbPrintf(wbuf, sizeof(wbuf), L"%S%S%S%S%S", - c.service, - (c.instance[0] ? "." : ""), - c.instance, - (c.realm[0] ? "@" : ""), - c.realm); - - if(KHM_FAILED(kcdb_cred_create(wbuf, ident, credtype_id_krb4, &cred))) - continue; - - tt = c.issue_date + c.lifetime * 5L * 60L; - TimetToFileTime(tt, &ft); - kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &ft, sizeof(ft)); - - tt = c.issue_date; - TimetToFileTime(tt, &ft); - kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft)); - - tt = c.lifetime * 5L * 60L; - TimetToFileTimeInterval(tt, &ft); - kcdb_cred_set_attr(cred, KCDB_ATTR_LIFETIME, &ft, sizeof(ft)); - - AnsiStrToUnicode(wbuf, sizeof(wbuf), ptktname); - kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION, wbuf, KCDB_CBSIZE_AUTO); - - kcdb_credset_add_cred(krb4_credset, cred, -1); - - kcdb_cred_release(cred); - } // while - - cleanup: - if (ptf_close == NULL) - return(KSUCCESS); - - if (open) - (*ptf_close)(); //close ticket file - - if (k_errno == EOF) - k_errno = 0; - - // XXX the if statement directly below was inserted to eliminate - // an error NO_TKT_FIL on Leash startup. The error occurs from an - // error number thrown from krb_get_tf_realm. We believe this - // change does not eliminate other errors, but it may. - - if (k_errno == NO_TKT_FIL) - k_errno = 0; - - if(ident) - kcdb_identity_release(ident); - -#if 0 - /*TODO: Handle errors here */ - if (k_errno) - { - CHAR message[256]; - CHAR errBuf[256]; - LPCSTR errText; - - if (!Lerror_message) - return -1; - - errText = err_describe(errBuf, KRBERR(k_errno)); - - sprintf(message, "%s\n\n%s failed", errText, functionName); - MessageBox(NULL, message, "Kerberos Four", - MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND); - } -#endif - - collect: - kcdb_credset_collect(NULL, krb4_credset, ident, credtype_id_krb4, NULL); - - return k_errno; -} - -#define KRB_FILE "KRB.CON" -#define KRBREALM_FILE "KRBREALM.CON" -#define KRB5_FILE "KRB5.INI" - -BOOL -khm_krb5_get_profile_file(LPSTR confname, UINT szConfname) -{ - char **configFile = NULL; - if (pkrb5_get_default_config_files(&configFile)) - { - GetWindowsDirectoryA(confname,szConfname); - confname[szConfname-1] = '\0'; - - StringCchCatA(confname, szConfname, "\\"); - StringCchCatA(confname, szConfname, KRB5_FILE); - - return FALSE; - } - - *confname = 0; - - if (configFile) - { - StringCchCopyA(confname, szConfname, *configFile); - pkrb5_free_config_files(configFile); - } - - if (!*confname) - { - GetWindowsDirectoryA(confname,szConfname); - confname[szConfname-1] = '\0'; - - StringCchCatA(confname, szConfname, "\\"); - StringCchCatA(confname, szConfname, KRB5_FILE); - } - - return FALSE; -} - -BOOL -khm_get_krb4_con_file(LPSTR confname, UINT szConfname) -{ - if (hKrb5 && !hKrb4) { - // hold krb.con where krb5.ini is located - CHAR krbConFile[MAX_PATH]=""; - LPSTR pFind; - - if (khm_krb5_get_profile_file(krbConFile, sizeof(krbConFile))) { - GetWindowsDirectoryA(krbConFile,sizeof(krbConFile)); - krbConFile[MAX_PATH-1] = '\0'; - - StringCbCatA(krbConFile, sizeof(krbConFile), "\\"); - } - - pFind = strrchr(krbConFile, '\\'); - - if (pFind) { - *pFind = '\0'; - - StringCbCatA(krbConFile, sizeof(krbConFile), "\\"); - StringCbCatA(krbConFile, sizeof(krbConFile), KRB_FILE); - } else { - krbConFile[0] = '\0'; - } - - StringCchCopyA(confname, szConfname, krbConFile); - } else if (hKrb4) { - unsigned int size = szConfname; - memset(confname, '\0', szConfname); - if (!pkrb_get_krbconf2(confname, &size)) { - GetWindowsDirectoryA(confname,szConfname); - confname[szConfname-1] = '\0'; - StringCchCatA(confname, szConfname, "\\"); - StringCchCatA(confname, szConfname, KRB_FILE); - } - } - - return FALSE; -} - -int -readstring(FILE * file, char * buf, int len) -{ - int c,i; - memset(buf, '\0', sizeof(buf)); - for (i=0, c=fgetc(file); c != EOF ; c=fgetc(file), i++) - { - if (i < sizeof(buf)) { - if (c == '\n') { - buf[i] = '\0'; - return i; - } else { - buf[i] = c; - } - } else { - if (c == '\n') { - buf[len-1] = '\0'; - return(i); - } - } - } - if (c == EOF) { - if (i > 0 && i < len) { - buf[i] = '\0'; - return(i); - } else { - buf[len-1] = '\0'; - return(-1); - } - } - return(-1); -} - -/*! \internal - \brief Return a list of configured realms - - The string that is returned is a set of null terminated unicode strings, - each of which denotes one realm. The set is terminated by a zero length - null terminated string. - - The caller should free the returned string using free() - - \return The string with the list of realms or NULL if the operation fails. -*/ -wchar_t * khm_krb5_get_realm_list(void) -{ - wchar_t * rlist = NULL; - - if (pprofile_get_subsection_names && pprofile_free_list) { - const char* rootSection[] = {"realms", NULL}; - const char** rootsec = rootSection; - char **sections = NULL, **cpp = NULL, *value = NULL; - - char krb5_conf[MAX_PATH+1]; - - if (!khm_krb5_get_profile_file(krb5_conf,sizeof(krb5_conf))) { - profile_t profile; - long retval; - const char *filenames[2]; - wchar_t * d; - size_t cbsize; - size_t t; - - filenames[0] = krb5_conf; - filenames[1] = NULL; - retval = pprofile_init(filenames, &profile); - if (!retval) { - retval = pprofile_get_subsection_names(profile, rootsec, §ions); - - if (!retval) - { - /* first figure out how much space to allocate */ - cbsize = 0; - for (cpp = sections; *cpp; cpp++) - { - cbsize += sizeof(wchar_t) * (strlen(*cpp) + 1); - } - cbsize += sizeof(wchar_t); /* double null terminated */ - - rlist = PMALLOC(cbsize); - d = rlist; - for (cpp = sections; *cpp; cpp++) - { - AnsiStrToUnicode(d, cbsize, *cpp); - t = wcslen(d) + 1; - d += t; - cbsize -= sizeof(wchar_t) * t; - } - *d = L'\0'; - } - - pprofile_free_list(sections); - -#if 0 - retval = pprofile_get_string(profile, "libdefaults","noaddresses", 0, "true", &value); - if ( value ) { - disable_noaddresses = config_boolean_to_int(value); - pprofile_release_string(value); - } -#endif - pprofile_release(profile); - } - } - } else { - FILE * file; - char krb_conf[MAX_PATH+1]; - char * p; - size_t cbsize, t; - wchar_t * d; - - if (!khm_get_krb4_con_file(krb_conf,sizeof(krb_conf)) && -#if _MSC_VER >= 1400 - !fopen_s(&file, krb_conf, "rt") -#else - (file = fopen(krb_conf, "rt")) -#endif - ) - { - char lineBuf[256]; - - /*TODO: compute the actual required buffer size instead of hardcoding */ - cbsize = 16384; // arbitrary - rlist = PMALLOC(cbsize); - d = rlist; - - // Skip the default realm - readstring(file,lineBuf,sizeof(lineBuf)); - - // Read the defined realms - while (TRUE) - { - if (readstring(file,lineBuf,sizeof(lineBuf)) < 0) - break; - - if (*(lineBuf + strlen(lineBuf) - 1) == '\r') - *(lineBuf + strlen(lineBuf) - 1) = 0; - - for (p=lineBuf; *p ; p++) - { - if (isspace(*p)) { - *p = 0; - break; - } - } - - if ( strncmp(".KERBEROS.OPTION.",lineBuf,17) ) { - t = strlen(lineBuf) + 1; - if(cbsize > (1 + t*sizeof(wchar_t))) { - AnsiStrToUnicode(d, cbsize, lineBuf); - d += t; - cbsize -= t * sizeof(wchar_t); - } else - break; - } - } - - *d = L'\0'; - - fclose(file); - } - } - - return rlist; -} - -/*! \internal - \brief Get the default realm - - A string will be returned that specifies the default realm. The caller - should free the string using free(). - - Returns NULL if the operation fails. -*/ -wchar_t * khm_krb5_get_default_realm(void) -{ - wchar_t * realm; - size_t cch; - krb5_context ctx=0; - char * def = 0; - - pkrb5_init_context(&ctx); - pkrb5_get_default_realm(ctx,&def); - - if (def) { - cch = strlen(def) + 1; - realm = PMALLOC(sizeof(wchar_t) * cch); - AnsiStrToUnicode(realm, sizeof(wchar_t) * cch, def); - pkrb5_free_default_realm(ctx, def); - } else - realm = NULL; - - pkrb5_free_context(ctx); - - return realm; -} - -static -char * -make_postfix(const char * base, - const char * postfix, - char ** rcopy) -{ - size_t base_size; - size_t ret_size; - char * copy = 0; - char * ret = 0; - size_t t; - - if (FAILED(StringCbLengthA(base, STRSAFE_MAX_CCH * sizeof(char), &t))) - goto cleanup; - - base_size = t + 1; - - if (FAILED(StringCbLengthA(postfix, STRSAFE_MAX_CCH * sizeof(char), &t))) - goto cleanup; - - ret_size = base_size + t + 1; - - copy = malloc(base_size); - ret = malloc(ret_size); - - if (!copy || !ret) - goto cleanup; - - StringCbCopyNA(copy, base_size, base, base_size); - StringCbCopyNA(ret, ret_size, base, base_size); - StringCbCopyNA(ret + (base_size - 1), ret_size - (base_size - 1), - postfix, ret_size - (base_size - 1)); - - cleanup: - if (!copy || !ret) { - if (copy) - free(copy); - if (ret) - free(ret); - copy = ret = 0; - } - // INVARIANT: (ret ==> copy) && (copy ==> ret) - *rcopy = copy; - return ret; -} - -void -khm_krb4_set_def_tkt_string(void) { - wchar_t wtkt_string[MAX_PATH]; - char tkt_string[MAX_PATH]; - khm_size cb; - - cb = sizeof(wtkt_string); - - if (KHM_FAILED(khc_read_string(csp_params, L"TktString", - wtkt_string, &cb)) || - wtkt_string[0] == L'\0') { - - pkrb_set_tkt_string(0); - - } else { - - UnicodeStrToAnsi(tkt_string, sizeof(tkt_string), - wtkt_string); - pkrb_set_tkt_string(tkt_string); - } -} - - -static -long -make_temp_cache_v4(const char * postfix) -{ - static char * old_cache = 0; - - if (!pkrb_set_tkt_string || !ptkt_string || !pdest_tkt) - return 0; // XXX - is this appropriate? - - if (old_cache) { - pdest_tkt(); - pkrb_set_tkt_string(old_cache); - free(old_cache); - old_cache = 0; - } - - if (postfix) - { - char * tmp_cache = make_postfix(ptkt_string(), postfix, &old_cache); - - if (!tmp_cache) - return KFAILURE; - - pkrb_set_tkt_string(tmp_cache); - free(tmp_cache); - } - return 0; -} - -long -khm_krb4_changepwd(char * principal, - char * password, - char * newpassword, - char** error_str) -{ - long k_errno; - - if (!pkrb_set_tkt_string || !ptkt_string || !pkadm_change_your_password || - !pdest_tkt) - return KFAILURE; - - k_errno = make_temp_cache_v4("_chgpwd"); - if (k_errno) return k_errno; - k_errno = pkadm_change_your_password(principal, password, newpassword, - error_str); - make_temp_cache_v4(0); - return k_errno; -} - -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) -{ -#ifdef NO_KRB5 - return(0); -#else - krb5_context ctx = 0; - krb5_error_code code = 0; - int icode = 0; - krb5_principal me = 0; - krb5_principal server = 0; - krb5_creds *v5creds = 0; - krb5_creds increds; - krb5_ccache cc = 0; - CREDENTIALS * v4creds = NULL; - static int init_ets = 1; - - if (!pkrb5_init_context || - !pkrb_in_tkt || - !pkrb524_init_ets || - !pkrb524_convert_creds_kdc) - return 0; - - v4creds = (CREDENTIALS *) malloc(sizeof(CREDENTIALS)); - memset((char *) v4creds, 0, sizeof(CREDENTIALS)); - - memset((char *) &increds, 0, sizeof(increds)); - /* - From this point on, we can goto cleanup because increds is - initialized. - */ - - code = khm_krb5_initialize(identity, &ctx, &cc); - if (code) - goto cleanup; - - if ( init_ets ) { - pkrb524_init_ets(ctx); - init_ets = 0; - } - - if (code = pkrb5_cc_get_principal(ctx, cc, &me)) - goto cleanup; - - if ((code = pkrb5_build_principal(ctx, - &server, - krb5_princ_realm(ctx, me)->length, - krb5_princ_realm(ctx, me)->data, - "krbtgt", - krb5_princ_realm(ctx, me)->data, - NULL))) { - goto cleanup; - } - - increds.client = me; - increds.server = server; - increds.times.endtime = 0; - increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; - if ((code = pkrb5_get_credentials(ctx, 0, - cc, - &increds, - &v5creds))) { - goto cleanup; - } - - if ((icode = pkrb524_convert_creds_kdc(ctx, - v5creds, - v4creds))) { - goto cleanup; - } - - /* initialize ticket cache */ - if ((icode = pkrb_in_tkt(v4creds->pname, v4creds->pinst, v4creds->realm) - != KSUCCESS)) { - goto cleanup; - } - - /* stash ticket, session key, etc. for future use */ - if ((icode = pkrb_save_credentials(v4creds->service, - v4creds->instance, - v4creds->realm, - v4creds->session, - v4creds->lifetime, - v4creds->kvno, - &(v4creds->ticket_st), - v4creds->issue_date))) { - goto cleanup; - } - - cleanup: - memset(v4creds, 0, sizeof(v4creds)); - free(v4creds); - - if (v5creds) { - pkrb5_free_creds(ctx, v5creds); - } - if (increds.client == me) - me = 0; - if (increds.server == server) - server = 0; - - if (ctx) - pkrb5_free_cred_contents(ctx, &increds); - - if (server) { - pkrb5_free_principal(ctx, server); - } - - if (me) { - pkrb5_free_principal(ctx, me); - } - - if (ctx && cc) - pkrb5_cc_close(ctx, cc); - - if (ctx) { - pkrb5_free_context(ctx); - } - - return (code || icode); -#endif /* NO_KRB5 */ -} - -long -khm_krb4_kinit(char * aname, - char * inst, - char * realm, - long lifetime, - char * password) { - - wchar_t * functionName = NULL; - wchar_t * err_context = NULL; - int rc4 = 0; - int msg = 0; - - if (pkname_parse == NULL) { - goto cleanup; - } - - err_context = L"getting realm"; - if (!*realm && (rc4 = (int)(*pkrb_get_lrealm)(realm, 1))) { - functionName = L"krb_get_lrealm()"; - msg = IDS_ERR_REALM; - goto cleanup; - } - - err_context = L"checking principal"; - if ((!*aname) || (!(rc4 = (int)(*pk_isname)(aname)))) { - functionName = L"krb_get_lrealm()"; - msg = IDS_ERR_PRINCIPAL; - goto cleanup; - } - - /* optional instance */ - if (!(rc4 = (int)(*pk_isinst)(inst))) { - functionName = L"k_isinst()"; - msg = IDS_ERR_INVINST; - goto cleanup; - } - - if (!(rc4 = (int)(*pk_isrealm)(realm))) { - functionName = L"k_isrealm()"; - msg = IDS_ERR_REALM; - goto cleanup; - } - - khm_krb4_set_def_tkt_string(); - - err_context = L"fetching ticket"; - rc4 = (*pkrb_get_pw_in_tkt)(aname, inst, realm, "krbtgt", realm, - lifetime, password); - - if (rc4) /* XXX: do we want: && (rc != NO_TKT_FIL) as well? */ { - functionName = L"krb_get_pw_in_tkt()"; - msg = IDS_ERR_PWINTKT; - goto cleanup; - } - - return 0; - - cleanup: - { - _report_sr0(KHERR_ERROR, msg); - _location(functionName); - } - return rc4; -} - - -int khm_krb4_kdestroy(void) { - int k_errno = 0; - - if (pdest_tkt != NULL) - { - k_errno = (*pdest_tkt)(); - if (k_errno && (k_errno != RET_TKFIL)) - return KRBERR(k_errno); - } - - return k_errno; -} +/* +* 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$ */ + +/* Originally this was krb5routines.c in Leash sources. Subsequently +modified and adapted for NetIDMgr */ + +#include +#include + +#define SECURITY_WIN32 +#include + +#include +#include +#include +#include + + + +int com_addr(void) +{ + long ipAddr; + char loc_addr[ADDR_SZ]; + CREDENTIALS cred; + char service[40]; + char instance[40]; + // char addr[40]; + char realm[40]; + struct in_addr LocAddr; + int k_errno; + + if (pkrb_get_cred == NULL) + return(KSUCCESS); + + k_errno = (*pkrb_get_cred)(service,instance,realm,&cred); + if (k_errno) + return KRBERR(k_errno); + + while(1) { + ipAddr = (*pLocalHostAddr)(); + LocAddr.s_addr = ipAddr; + StringCbCopyA(loc_addr, sizeof(loc_addr), inet_ntoa(LocAddr)); + if ( strcmp(cred.address,loc_addr) != 0) { + /* TODO: do something about this */ + //Leash_kdestroy (); + break; + } + break; + } // while() + return 0; +} + + +long +khm_krb4_list_tickets(void) +{ + char ptktname[MAX_PATH + 5]; + char pname[ANAME_SZ]; + char pinst[INST_SZ]; + char prealm[REALM_SZ]; + wchar_t wbuf[256]; + int k_errno = 0; + CREDENTIALS c; + int newtickets = 0; + int open = 0; + khm_handle ident = NULL; + khm_handle cred = NULL; + time_t tt; + FILETIME ft; + + kcdb_credset_flush(krb4_credset); + + // Since krb_get_tf_realm will return a ticket_file error, + // we will call tf_init and tf_close first to filter out + // things like no ticket file. Otherwise, the error that + // the user would see would be + // klist: can't find realm of ticket file: No ticket file (tf_util) + // instead of klist: No ticket file (tf_util) + if (ptf_init == NULL) + goto collect; + + com_addr(); + + // Open ticket file + if ((k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL))) + { + goto cleanup; + } + // Close ticket file + (void) (*ptf_close)(); + + // We must find the realm of the ticket file here before calling + // tf_init because since the realm of the ticket file is not + // really stored in the principal section of the file, the + // routine we use must itself call tf_init and tf_close. + + if ((k_errno = (*pkrb_get_tf_realm)((*ptkt_string)(), prealm)) != KSUCCESS) + { + goto cleanup; + } + + // Open ticket file + if (k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL)) + { + goto cleanup; + } + + StringCchCopyA(ptktname, ARRAYLENGTH(ptktname), (*ptkt_string)()); + + open = 1; + + // Get principal name and instance + if ((k_errno = (*ptf_get_pname)(pname)) || (k_errno = (*ptf_get_pinst)(pinst))) + { + goto cleanup; + } + + // You may think that this is the obvious place to get the + // realm of the ticket file, but it can't be done here as the + // routine to do this must open the ticket file. This is why + // it was done before tf_init. + StringCbPrintf(wbuf, sizeof(wbuf), L"%S%S%S%S%S", (LPSTR)pname, + (LPSTR)(pinst[0] ? "." : ""), (LPSTR)pinst, + (LPSTR)(prealm[0] ? "@" : ""), (LPSTR)prealm); + + if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, &ident))) + { + goto cleanup; + } + + // Get KRB4 tickets + while ((k_errno = (*ptf_get_cred)(&c)) == KSUCCESS) + { + StringCbPrintf(wbuf, sizeof(wbuf), L"%S%S%S%S%S", + c.service, + (c.instance[0] ? "." : ""), + c.instance, + (c.realm[0] ? "@" : ""), + c.realm); + + if(KHM_FAILED(kcdb_cred_create(wbuf, ident, credtype_id_krb4, &cred))) + continue; + + tt = c.issue_date + c.lifetime * 5L * 60L; + TimetToFileTime(tt, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &ft, sizeof(ft)); + + tt = c.issue_date; + TimetToFileTime(tt, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft)); + + tt = c.lifetime * 5L * 60L; + TimetToFileTimeInterval(tt, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_LIFETIME, &ft, sizeof(ft)); + + AnsiStrToUnicode(wbuf, sizeof(wbuf), ptktname); + kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION, wbuf, KCDB_CBSIZE_AUTO); + + kcdb_credset_add_cred(krb4_credset, cred, -1); + + kcdb_cred_release(cred); + } // while + + cleanup: + if (ptf_close == NULL) + return(KSUCCESS); + + if (open) + (*ptf_close)(); //close ticket file + + if (k_errno == EOF) + k_errno = 0; + + // XXX the if statement directly below was inserted to eliminate + // an error NO_TKT_FIL on Leash startup. The error occurs from an + // error number thrown from krb_get_tf_realm. We believe this + // change does not eliminate other errors, but it may. + + if (k_errno == NO_TKT_FIL) + k_errno = 0; + + if(ident) + kcdb_identity_release(ident); + +#if 0 + /*TODO: Handle errors here */ + if (k_errno) + { + CHAR message[256]; + CHAR errBuf[256]; + LPCSTR errText; + + if (!Lerror_message) + return -1; + + errText = err_describe(errBuf, KRBERR(k_errno)); + + sprintf(message, "%s\n\n%s failed", errText, functionName); + MessageBox(NULL, message, "Kerberos Four", + MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND); + } +#endif + + collect: + kcdb_credset_collect(NULL, krb4_credset, ident, credtype_id_krb4, NULL); + + return k_errno; +} + +#define KRB_FILE "KRB.CON" +#define KRBREALM_FILE "KRBREALM.CON" +#define KRB5_FILE "KRB5.INI" + +BOOL +khm_krb5_get_profile_file(LPSTR confname, UINT szConfname) +{ + char **configFile = NULL; + if (pkrb5_get_default_config_files(&configFile)) + { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + + StringCchCatA(confname, szConfname, "\\"); + StringCchCatA(confname, szConfname, KRB5_FILE); + + return FALSE; + } + + *confname = 0; + + if (configFile) + { + StringCchCopyA(confname, szConfname, *configFile); + pkrb5_free_config_files(configFile); + } + + if (!*confname) + { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + + StringCchCatA(confname, szConfname, "\\"); + StringCchCatA(confname, szConfname, KRB5_FILE); + } + + return FALSE; +} + +BOOL +khm_get_krb4_con_file(LPSTR confname, UINT szConfname) +{ + if (hKrb5 && !hKrb4) { + // hold krb.con where krb5.ini is located + CHAR krbConFile[MAX_PATH]=""; + LPSTR pFind; + + if (khm_krb5_get_profile_file(krbConFile, sizeof(krbConFile))) { + GetWindowsDirectoryA(krbConFile,sizeof(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + + StringCbCatA(krbConFile, sizeof(krbConFile), "\\"); + } + + pFind = strrchr(krbConFile, '\\'); + + if (pFind) { + *pFind = '\0'; + + StringCbCatA(krbConFile, sizeof(krbConFile), "\\"); + StringCbCatA(krbConFile, sizeof(krbConFile), KRB_FILE); + } else { + krbConFile[0] = '\0'; + } + + StringCchCopyA(confname, szConfname, krbConFile); + } else if (hKrb4) { + unsigned int size = szConfname; + memset(confname, '\0', szConfname); + if (!pkrb_get_krbconf2(confname, &size)) { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + StringCchCatA(confname, szConfname, "\\"); + StringCchCatA(confname, szConfname, KRB_FILE); + } + } + + return FALSE; +} + +int +readstring(FILE * file, char * buf, int len) +{ + int c,i; + memset(buf, '\0', sizeof(buf)); + for (i=0, c=fgetc(file); c != EOF ; c=fgetc(file), i++) + { + if (i < sizeof(buf)) { + if (c == '\n') { + buf[i] = '\0'; + return i; + } else { + buf[i] = c; + } + } else { + if (c == '\n') { + buf[len-1] = '\0'; + return(i); + } + } + } + if (c == EOF) { + if (i > 0 && i < len) { + buf[i] = '\0'; + return(i); + } else { + buf[len-1] = '\0'; + return(-1); + } + } + return(-1); +} + +/*! \internal + \brief Return a list of configured realms + + The string that is returned is a set of null terminated unicode strings, + each of which denotes one realm. The set is terminated by a zero length + null terminated string. + + The caller should free the returned string using free() + + \return The string with the list of realms or NULL if the operation fails. +*/ +wchar_t * khm_krb5_get_realm_list(void) +{ + wchar_t * rlist = NULL; + + if (pprofile_get_subsection_names && pprofile_free_list) { + const char* rootSection[] = {"realms", NULL}; + const char** rootsec = rootSection; + char **sections = NULL, **cpp = NULL, *value = NULL; + + char krb5_conf[MAX_PATH+1]; + + if (!khm_krb5_get_profile_file(krb5_conf,sizeof(krb5_conf))) { + profile_t profile; + long retval; + const char *filenames[2]; + wchar_t * d; + size_t cbsize; + size_t t; + + filenames[0] = krb5_conf; + filenames[1] = NULL; + retval = pprofile_init(filenames, &profile); + if (!retval) { + retval = pprofile_get_subsection_names(profile, rootsec, §ions); + + if (!retval) + { + /* first figure out how much space to allocate */ + cbsize = 0; + for (cpp = sections; *cpp; cpp++) + { + cbsize += sizeof(wchar_t) * (strlen(*cpp) + 1); + } + cbsize += sizeof(wchar_t); /* double null terminated */ + + rlist = PMALLOC(cbsize); + d = rlist; + for (cpp = sections; *cpp; cpp++) + { + AnsiStrToUnicode(d, cbsize, *cpp); + t = wcslen(d) + 1; + d += t; + cbsize -= sizeof(wchar_t) * t; + } + *d = L'\0'; + } + + pprofile_free_list(sections); + +#if 0 + retval = pprofile_get_string(profile, "libdefaults","noaddresses", 0, "true", &value); + if ( value ) { + disable_noaddresses = config_boolean_to_int(value); + pprofile_release_string(value); + } +#endif + pprofile_release(profile); + } + } + } else { + FILE * file; + char krb_conf[MAX_PATH+1]; + char * p; + size_t cbsize, t; + wchar_t * d; + + if (!khm_get_krb4_con_file(krb_conf,sizeof(krb_conf)) && +#if _MSC_VER >= 1400 + !fopen_s(&file, krb_conf, "rt") +#else + (file = fopen(krb_conf, "rt")) +#endif + ) + { + char lineBuf[256]; + + /*TODO: compute the actual required buffer size instead of hardcoding */ + cbsize = 16384; // arbitrary + rlist = PMALLOC(cbsize); + d = rlist; + + // Skip the default realm + readstring(file,lineBuf,sizeof(lineBuf)); + + // Read the defined realms + while (TRUE) + { + if (readstring(file,lineBuf,sizeof(lineBuf)) < 0) + break; + + if (*(lineBuf + strlen(lineBuf) - 1) == '\r') + *(lineBuf + strlen(lineBuf) - 1) = 0; + + for (p=lineBuf; *p ; p++) + { + if (isspace(*p)) { + *p = 0; + break; + } + } + + if ( strncmp(".KERBEROS.OPTION.",lineBuf,17) ) { + t = strlen(lineBuf) + 1; + if(cbsize > (1 + t*sizeof(wchar_t))) { + AnsiStrToUnicode(d, cbsize, lineBuf); + d += t; + cbsize -= t * sizeof(wchar_t); + } else + break; + } + } + + *d = L'\0'; + + fclose(file); + } + } + + return rlist; +} + +/*! \internal + \brief Get the default realm + + A string will be returned that specifies the default realm. The caller + should free the string using free(). + + Returns NULL if the operation fails. +*/ +wchar_t * khm_krb5_get_default_realm(void) +{ + wchar_t * realm; + size_t cch; + krb5_context ctx=0; + char * def = 0; + + pkrb5_init_context(&ctx); + pkrb5_get_default_realm(ctx,&def); + + if (def) { + cch = strlen(def) + 1; + realm = PMALLOC(sizeof(wchar_t) * cch); + AnsiStrToUnicode(realm, sizeof(wchar_t) * cch, def); + pkrb5_free_default_realm(ctx, def); + } else + realm = NULL; + + pkrb5_free_context(ctx); + + return realm; +} + +static +char * +make_postfix(const char * base, + const char * postfix, + char ** rcopy) +{ + size_t base_size; + size_t ret_size; + char * copy = 0; + char * ret = 0; + size_t t; + + if (FAILED(StringCbLengthA(base, STRSAFE_MAX_CCH * sizeof(char), &t))) + goto cleanup; + + base_size = t + 1; + + if (FAILED(StringCbLengthA(postfix, STRSAFE_MAX_CCH * sizeof(char), &t))) + goto cleanup; + + ret_size = base_size + t + 1; + + copy = malloc(base_size); + ret = malloc(ret_size); + + if (!copy || !ret) + goto cleanup; + + StringCbCopyNA(copy, base_size, base, base_size); + StringCbCopyNA(ret, ret_size, base, base_size); + StringCbCopyNA(ret + (base_size - 1), ret_size - (base_size - 1), + postfix, ret_size - (base_size - 1)); + + cleanup: + if (!copy || !ret) { + if (copy) + free(copy); + if (ret) + free(ret); + copy = ret = 0; + } + // INVARIANT: (ret ==> copy) && (copy ==> ret) + *rcopy = copy; + return ret; +} + +void +khm_krb4_set_def_tkt_string(void) { + wchar_t wtkt_string[MAX_PATH]; + char tkt_string[MAX_PATH]; + khm_size cb; + + cb = sizeof(wtkt_string); + + if (KHM_FAILED(khc_read_string(csp_params, L"TktString", + wtkt_string, &cb)) || + wtkt_string[0] == L'\0') { + + pkrb_set_tkt_string(0); + + } else { + + UnicodeStrToAnsi(tkt_string, sizeof(tkt_string), + wtkt_string); + pkrb_set_tkt_string(tkt_string); + } +} + + +static +long +make_temp_cache_v4(const char * postfix) +{ + static char * old_cache = 0; + + if (!pkrb_set_tkt_string || !ptkt_string || !pdest_tkt) + return 0; // XXX - is this appropriate? + + if (old_cache) { + pdest_tkt(); + pkrb_set_tkt_string(old_cache); + free(old_cache); + old_cache = 0; + } + + if (postfix) + { + char * tmp_cache = make_postfix(ptkt_string(), postfix, &old_cache); + + if (!tmp_cache) + return KFAILURE; + + pkrb_set_tkt_string(tmp_cache); + free(tmp_cache); + } + return 0; +} + +long +khm_krb4_changepwd(char * principal, + char * password, + char * newpassword, + char** error_str) +{ + long k_errno; + + if (!pkrb_set_tkt_string || !ptkt_string || !pkadm_change_your_password || + !pdest_tkt) + return KFAILURE; + + k_errno = make_temp_cache_v4("_chgpwd"); + if (k_errno) return k_errno; + k_errno = pkadm_change_your_password(principal, password, newpassword, + error_str); + make_temp_cache_v4(0); + return k_errno; +} + +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) +{ +#ifdef NO_KRB5 + return(0); +#else + krb5_context ctx = 0; + krb5_error_code code = 0; + int icode = 0; + krb5_principal me = 0; + krb5_principal server = 0; + krb5_creds *v5creds = 0; + krb5_creds increds; + krb5_ccache cc = 0; + CREDENTIALS * v4creds = NULL; + static int init_ets = 1; + + if (!pkrb5_init_context || + !pkrb_in_tkt || + !pkrb524_init_ets || + !pkrb524_convert_creds_kdc) + return 0; + + v4creds = (CREDENTIALS *) malloc(sizeof(CREDENTIALS)); + memset((char *) v4creds, 0, sizeof(CREDENTIALS)); + + memset((char *) &increds, 0, sizeof(increds)); + /* + From this point on, we can goto cleanup because increds is + initialized. + */ + + code = khm_krb5_initialize(identity, &ctx, &cc); + if (code) + goto cleanup; + + if ( init_ets ) { + pkrb524_init_ets(ctx); + init_ets = 0; + } + + if (code = pkrb5_cc_get_principal(ctx, cc, &me)) + goto cleanup; + + if ((code = pkrb5_build_principal(ctx, + &server, + krb5_princ_realm(ctx, me)->length, + krb5_princ_realm(ctx, me)->data, + "krbtgt", + krb5_princ_realm(ctx, me)->data, + NULL))) { + goto cleanup; + } + + increds.client = me; + increds.server = server; + increds.times.endtime = 0; + increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; + if ((code = pkrb5_get_credentials(ctx, 0, + cc, + &increds, + &v5creds))) { + goto cleanup; + } + + if ((icode = pkrb524_convert_creds_kdc(ctx, + v5creds, + v4creds))) { + goto cleanup; + } + + /* initialize ticket cache */ + if ((icode = pkrb_in_tkt(v4creds->pname, v4creds->pinst, v4creds->realm) + != KSUCCESS)) { + goto cleanup; + } + + /* stash ticket, session key, etc. for future use */ + if ((icode = pkrb_save_credentials(v4creds->service, + v4creds->instance, + v4creds->realm, + v4creds->session, + v4creds->lifetime, + v4creds->kvno, + &(v4creds->ticket_st), + v4creds->issue_date))) { + goto cleanup; + } + + cleanup: + memset(v4creds, 0, sizeof(v4creds)); + free(v4creds); + + if (v5creds) { + pkrb5_free_creds(ctx, v5creds); + } + if (increds.client == me) + me = 0; + if (increds.server == server) + server = 0; + + if (ctx) + pkrb5_free_cred_contents(ctx, &increds); + + if (server) { + pkrb5_free_principal(ctx, server); + } + + if (me) { + pkrb5_free_principal(ctx, me); + } + + if (ctx && cc) + pkrb5_cc_close(ctx, cc); + + if (ctx) { + pkrb5_free_context(ctx); + } + + return (code || icode); +#endif /* NO_KRB5 */ +} + +long +khm_krb4_kinit(char * aname, + char * inst, + char * realm, + long lifetime, + char * password) { + + wchar_t * functionName = NULL; + wchar_t * err_context = NULL; + int rc4 = 0; + int msg = 0; + + if (pkname_parse == NULL) { + goto cleanup; + } + + err_context = L"getting realm"; + if (!*realm && (rc4 = (int)(*pkrb_get_lrealm)(realm, 1))) { + functionName = L"krb_get_lrealm()"; + msg = IDS_ERR_REALM; + goto cleanup; + } + + err_context = L"checking principal"; + if ((!*aname) || (!(rc4 = (int)(*pk_isname)(aname)))) { + functionName = L"krb_get_lrealm()"; + msg = IDS_ERR_PRINCIPAL; + goto cleanup; + } + + /* optional instance */ + if (!(rc4 = (int)(*pk_isinst)(inst))) { + functionName = L"k_isinst()"; + msg = IDS_ERR_INVINST; + goto cleanup; + } + + if (!(rc4 = (int)(*pk_isrealm)(realm))) { + functionName = L"k_isrealm()"; + msg = IDS_ERR_REALM; + goto cleanup; + } + + khm_krb4_set_def_tkt_string(); + + err_context = L"fetching ticket"; + rc4 = (*pkrb_get_pw_in_tkt)(aname, inst, realm, "krbtgt", realm, + lifetime, password); + + if (rc4) /* XXX: do we want: && (rc != NO_TKT_FIL) as well? */ { + functionName = L"krb_get_pw_in_tkt()"; + msg = IDS_ERR_PWINTKT; + goto cleanup; + } + + return 0; + + cleanup: + { + _report_sr0(KHERR_ERROR, msg); + _location(functionName); + } + return rc4; +} + + +int khm_krb4_kdestroy(void) { + int k_errno = 0; + + if (pdest_tkt != NULL) + { + k_errno = (*pdest_tkt)(); + if (k_errno && (k_errno != RET_TKFIL)) + return KRBERR(k_errno); + } + + return k_errno; +} diff --git a/src/windows/identity/plugins/krb4/krb4funcs.h b/src/windows/identity/plugins/krb4/krb4funcs.h index 5ec11cc63..05ed3e75d 100644 --- a/src/windows/identity/plugins/krb4/krb4funcs.h +++ b/src/windows/identity/plugins/krb4/krb4funcs.h @@ -1,132 +1,132 @@ -/* - * 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$ */ - -/* Adapted from multiple Leash header files */ - -#ifndef __KHIMAIRA_KRB5FUNCS_H -#define __KHIMAIRA_KRB5FUNCS_H - -#include -#include - -#include -#define SECURITY_WIN32 -#include - -#if _WIN32_WINNT < 0x0501 -#define KHM_SAVE_WIN32_WINNT _WIN32_WINNT -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif -#include -#ifdef KHM_SAVE_WIN32_WINNT -#undef _WIN32_WINNT -#define _WIN32_WINNT KHM_SAVE_WIN32_WINNT -#undef KHM_SAVE_WIN32_WINNT -#endif - -#include - -#define LEASH_DEBUG_CLASS_GENERIC 0 -#define LEASH_DEBUG_CLASS_KRB4 1 -#define LEASH_DEBUG_CLASS_KRB4_APP 2 - -#define LEASH_PRIORITY_LOW 0 -#define LEASH_PRIORITY_HIGH 1 - -#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ - - -long -khm_convert524(khm_handle identity); - -long -khm_krb4_kinit(char * aname, - char * inst, - char * realm, - long lifetime, - char * password); - -long -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, - DWORD type, - void* buffer, - size_t size - ); - -LONG -read_registry_setting_user( - char* setting, - void* buffer, - size_t size - ); - -LONG -read_registry_setting( - char* setting, - void* buffer, - size_t size - ); - -BOOL -get_STRING_from_registry( - HKEY hBaseKey, - char * key, - char * value, - char * outbuf, - DWORD outlen - ); - -BOOL -get_DWORD_from_registry( - HKEY hBaseKey, - char * key, - char * value, - DWORD * result - ); - -int -config_boolean_to_int( - const char *s - ); - -void -khm_krb4_set_def_tkt_string(void); - -wchar_t * khm_krb5_get_default_realm(void); -wchar_t * khm_krb5_get_realm_list(void); - -#endif +/* + * 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$ */ + +/* Adapted from multiple Leash header files */ + +#ifndef __KHIMAIRA_KRB5FUNCS_H +#define __KHIMAIRA_KRB5FUNCS_H + +#include +#include + +#include +#define SECURITY_WIN32 +#include + +#if _WIN32_WINNT < 0x0501 +#define KHM_SAVE_WIN32_WINNT _WIN32_WINNT +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#ifdef KHM_SAVE_WIN32_WINNT +#undef _WIN32_WINNT +#define _WIN32_WINNT KHM_SAVE_WIN32_WINNT +#undef KHM_SAVE_WIN32_WINNT +#endif + +#include + +#define LEASH_DEBUG_CLASS_GENERIC 0 +#define LEASH_DEBUG_CLASS_KRB4 1 +#define LEASH_DEBUG_CLASS_KRB4_APP 2 + +#define LEASH_PRIORITY_LOW 0 +#define LEASH_PRIORITY_HIGH 1 + +#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ + + +long +khm_convert524(khm_handle identity); + +long +khm_krb4_kinit(char * aname, + char * inst, + char * realm, + long lifetime, + char * password); + +long +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, + DWORD type, + void* buffer, + size_t size + ); + +LONG +read_registry_setting_user( + char* setting, + void* buffer, + size_t size + ); + +LONG +read_registry_setting( + char* setting, + void* buffer, + size_t size + ); + +BOOL +get_STRING_from_registry( + HKEY hBaseKey, + char * key, + char * value, + char * outbuf, + DWORD outlen + ); + +BOOL +get_DWORD_from_registry( + HKEY hBaseKey, + char * key, + char * value, + DWORD * result + ); + +int +config_boolean_to_int( + const char *s + ); + +void +khm_krb4_set_def_tkt_string(void); + +wchar_t * khm_krb5_get_default_realm(void); +wchar_t * khm_krb5_get_realm_list(void); + +#endif diff --git a/src/windows/identity/plugins/krb4/krb4main.c b/src/windows/identity/plugins/krb4/krb4main.c index 57e33a8d8..7ab2d71f3 100644 --- a/src/windows/identity/plugins/krb4/krb4main.c +++ b/src/windows/identity/plugins/krb4/krb4main.c @@ -1,157 +1,157 @@ -/* - * 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 - -kmm_module h_khModule; /* KMM's handle to this module */ -HINSTANCE hInstance; -HMODULE hResModule; /* HMODULE to the resource library */ - -khm_int32 type_id_enctype = -1; -khm_int32 type_id_addr_list = -1; -khm_int32 type_id_krb5_flags = -1; - -khm_int32 attr_id_key_enctype = -1; -khm_int32 attr_id_tkt_enctype = -1; -khm_int32 attr_id_addr_list = -1; -khm_int32 attr_id_krb5_flags = -1; - -khm_handle csp_plugins = NULL; -khm_handle csp_krbcred = NULL; -khm_handle csp_params = NULL; - -kmm_module_locale locales[] = { - LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), L"krb4cred_en_us.dll", KMM_MLOC_FLAG_DEFAULT) -}; - -int n_locales = ARRAYLENGTH(locales); - -/* These two probably should not do anything */ -void init_krb() { -} - -void exit_krb() { -} - -/* called by the NetIDMgr module manager */ -KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { - khm_int32 rv = KHM_ERROR_SUCCESS; - kmm_plugin_reg pi; - wchar_t buf[256]; - - h_khModule = h_module; - - rv = kmm_set_locale_info(h_module, locales, n_locales); - if(KHM_SUCCEEDED(rv)) { - hResModule = kmm_get_resource_hmodule(h_module); - } else - goto _exit; - - ZeroMemory(&pi, sizeof(pi)); - pi.name = KRB4_PLUGIN_NAME; - pi.type = KHM_PITYPE_CRED; - pi.icon = 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; - pi.description = buf; - LoadString(hResModule, IDS_PLUGIN_DESC, - buf, ARRAYLENGTH(buf)); - kmm_provide_plugin(h_module, &pi); - - if(KHM_FAILED(rv = init_imports())) - goto _exit; - - if(KHM_FAILED(rv = init_error_funcs())) - goto _exit; - - rv = kmm_get_plugins_config(0, &csp_plugins); - if(KHM_FAILED(rv)) goto _exit; - - rv = khc_load_schema(csp_plugins, schema_krbconfig); - if(KHM_FAILED(rv)) goto _exit; - - rv = khc_open_space(csp_plugins, CSNAME_KRB4CRED, 0, &csp_krbcred); - if(KHM_FAILED(rv)) goto _exit; - - rv = khc_open_space(csp_krbcred, CSNAME_PARAMS, 0, &csp_params); - if(KHM_FAILED(rv)) goto _exit; - - _exit: - return rv; -} - -/* called by the NetIDMgr module manager */ -KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module) { - exit_imports(); - exit_error_funcs(); - - if(csp_params) { - khc_close_space(csp_params); - csp_params = NULL; - } - - if(csp_krbcred) { - khc_close_space(csp_krbcred); - csp_krbcred = NULL; - } - - if(csp_plugins) { - khc_unload_schema(csp_plugins, schema_krbconfig); - khc_close_space(csp_plugins); - csp_plugins = NULL; - } - - return KHM_ERROR_SUCCESS; /* the return code is ignored */ -} - -BOOL WINAPI DllMain( - HINSTANCE hinstDLL, - DWORD fdwReason, - LPVOID lpvReserved -) -{ - switch(fdwReason) { - case DLL_PROCESS_ATTACH: - hInstance = hinstDLL; - init_krb(); - break; - - case DLL_PROCESS_DETACH: - exit_krb(); - break; - - case DLL_THREAD_ATTACH: - break; - - case DLL_THREAD_DETACH: - break; - } - - return TRUE; -} +/* + * 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 + +kmm_module h_khModule; /* KMM's handle to this module */ +HINSTANCE hInstance; +HMODULE hResModule; /* HMODULE to the resource library */ + +khm_int32 type_id_enctype = -1; +khm_int32 type_id_addr_list = -1; +khm_int32 type_id_krb5_flags = -1; + +khm_int32 attr_id_key_enctype = -1; +khm_int32 attr_id_tkt_enctype = -1; +khm_int32 attr_id_addr_list = -1; +khm_int32 attr_id_krb5_flags = -1; + +khm_handle csp_plugins = NULL; +khm_handle csp_krbcred = NULL; +khm_handle csp_params = NULL; + +kmm_module_locale locales[] = { + LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), L"krb4cred_en_us.dll", KMM_MLOC_FLAG_DEFAULT) +}; + +int n_locales = ARRAYLENGTH(locales); + +/* These two probably should not do anything */ +void init_krb() { +} + +void exit_krb() { +} + +/* called by the NetIDMgr module manager */ +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { + khm_int32 rv = KHM_ERROR_SUCCESS; + kmm_plugin_reg pi; + wchar_t buf[256]; + + h_khModule = h_module; + + rv = kmm_set_locale_info(h_module, locales, n_locales); + if(KHM_SUCCEEDED(rv)) { + hResModule = kmm_get_resource_hmodule(h_module); + } else + goto _exit; + + ZeroMemory(&pi, sizeof(pi)); + pi.name = KRB4_PLUGIN_NAME; + pi.type = KHM_PITYPE_CRED; + pi.icon = 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; + pi.description = buf; + LoadString(hResModule, IDS_PLUGIN_DESC, + buf, ARRAYLENGTH(buf)); + kmm_provide_plugin(h_module, &pi); + + if(KHM_FAILED(rv = init_imports())) + goto _exit; + + if(KHM_FAILED(rv = init_error_funcs())) + goto _exit; + + rv = kmm_get_plugins_config(0, &csp_plugins); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_load_schema(csp_plugins, schema_krbconfig); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_open_space(csp_plugins, CSNAME_KRB4CRED, 0, &csp_krbcred); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_open_space(csp_krbcred, CSNAME_PARAMS, 0, &csp_params); + if(KHM_FAILED(rv)) goto _exit; + + _exit: + return rv; +} + +/* called by the NetIDMgr module manager */ +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module) { + exit_imports(); + exit_error_funcs(); + + if(csp_params) { + khc_close_space(csp_params); + csp_params = NULL; + } + + if(csp_krbcred) { + khc_close_space(csp_krbcred); + csp_krbcred = NULL; + } + + if(csp_plugins) { + khc_unload_schema(csp_plugins, schema_krbconfig); + khc_close_space(csp_plugins); + csp_plugins = NULL; + } + + return KHM_ERROR_SUCCESS; /* the return code is ignored */ +} + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved +) +{ + switch(fdwReason) { + case DLL_PROCESS_ATTACH: + hInstance = hinstDLL; + init_krb(); + break; + + case DLL_PROCESS_DETACH: + exit_krb(); + break; + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + break; + } + + return TRUE; +} diff --git a/src/windows/identity/plugins/krb4/krb4newcreds.c b/src/windows/identity/plugins/krb4/krb4newcreds.c index 54feae5b3..c2d477e0e 100644 --- a/src/windows/identity/plugins/krb4/krb4newcreds.c +++ b/src/windows/identity/plugins/krb4/krb4newcreds.c @@ -1,873 +1,873 @@ -/* - * 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 -#include -#include -#include -#include - -/* method identifiers should be contiguous */ -#define K4_METHOD_AUTO 0 -#define K4_METHOD_PASSWORD 1 -#define K4_METHOD_K524 2 - -int method_to_id[] = { - IDC_NCK4_AUTO, - IDC_NCK4_PWD, - IDC_NCK4_K524 -}; - -typedef struct tag_k4_dlg_data { - HWND hwnd; - khui_new_creds * nc; - khui_new_creds_by_type * nct; - - khm_boolean k4_enabled; - khm_int32 method; - time_t lifetime; -} k4_dlg_data; - -void k4_update_display(k4_dlg_data * d, BOOL update_methods) { - CheckDlgButton(d->hwnd, IDC_NCK4_OBTAIN, - (d->k4_enabled)?BST_CHECKED: BST_UNCHECKED); - - if (d->k4_enabled) { - EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_AUTO), TRUE); - EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_K524), TRUE); - EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_PWD ), TRUE); - } else { - EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_AUTO), FALSE); - EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_K524), FALSE); - EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_PWD ), FALSE); - } - -#ifdef DEBUG - assert(d->method >= 0 && d->method < ARRAYLENGTH(method_to_id)); -#endif - - CheckRadioButton(d->hwnd, IDC_NCK4_AUTO, IDC_NCK4_PWD, method_to_id[d->method]); - - khui_cw_enable_type(d->nc, credtype_id_krb4, d->k4_enabled); -} - -void k4_update_data(k4_dlg_data * d) { - int i; - khm_boolean oldstate; - - oldstate = d->k4_enabled; - - if (IsDlgButtonChecked(d->hwnd, IDC_NCK4_OBTAIN) == BST_CHECKED) - d->k4_enabled = TRUE; - else - d->k4_enabled = FALSE; - - if ((oldstate && !d->k4_enabled) || - (!oldstate && d->k4_enabled)) { - - khui_cw_enable_type(d->nc, credtype_id_krb4, d->k4_enabled); - } - - d->method = K4_METHOD_AUTO; - - for (i=K4_METHOD_AUTO; i<=K4_METHOD_K524; i++) { - if (IsDlgButtonChecked(d->hwnd, method_to_id[i]) == BST_CHECKED) { - d->method = i; - break; - } - } -} - -khm_boolean k4_should_identity_get_k4(khm_handle ident) { - khm_int32 idflags = 0; - khm_int32 t = TRUE; - khm_handle csp_ident = NULL; - khm_handle csp_k4 = NULL; - khm_boolean get_k4 = TRUE; - khm_boolean id_spec = FALSE; - - if (KHM_FAILED(kcdb_identity_get_flags(ident, &idflags))) - return FALSE; - - if (!(idflags & KCDB_IDENT_FLAG_DEFAULT)) { - /* we only support k4 for one identity, and that is the - default identity. If we are trying to get tickets for a - non-default identity, then we start off as disabled unless - there is no default identity. */ - - khm_handle defident = NULL; - - if (KHM_SUCCEEDED(kcdb_identity_get_default(&defident))) { - kcdb_identity_release(defident); - - return FALSE; - } - } - - 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))) { - get_k4 = !!t; - id_spec = TRUE; - } - - khc_close_space(csp_k4); - } - khc_close_space(csp_ident); - } - - /* if there was a value specified for the identity, then that - takes precedence. */ - if (id_spec || !get_k4) - return get_k4; - - if (KHM_SUCCEEDED(khc_read_int32(csp_params, L"Krb4NewCreds", &t)) && - !t) - return FALSE; - - return TRUE; -} - -void k4_read_identity_data(k4_dlg_data * d) { - khm_handle csp_ident = NULL; - khm_handle csp_k4 = NULL; - - khm_int32 idflags = 0; - khm_int32 t; - - if (KHM_SUCCEEDED(khc_read_int32(csp_params, L"Krb4NewCreds", &t))) - d->k4_enabled = !!t; - else - d->k4_enabled = TRUE; - - if (KHM_SUCCEEDED(khc_read_int32(csp_params, L"Krb4Method", &t))) - d->method = t; - else - d->method = K4_METHOD_AUTO; - - if (KHM_SUCCEEDED(khc_read_int32(csp_params, L"DefaultLifetime", &t))) - d->lifetime = t; - else - d->lifetime = 10 * 60 * 60; /* 10 hours */ - - if (d->nc->n_identities > 0 && - d->nc->identities[0]) { - - if (KHM_SUCCEEDED(kcdb_identity_get_config(d->nc->identities[0], - 0, - &csp_ident))) { - - khc_open_space(csp_ident, CSNAME_KRB4CRED, 0, &csp_k4); - - if (csp_k4) { - if (KHM_SUCCEEDED(khc_read_int32(csp_k4, L"Krb4NewCreds", &t))) - d->k4_enabled = !!t; - if (KHM_SUCCEEDED(khc_read_int32(csp_k4, L"Krb4Method", &t))) - d->method = t; - khc_close_space(csp_k4); - } - - khc_close_space(csp_ident); - } - - if (d->k4_enabled) { - d->k4_enabled = k4_should_identity_get_k4(d->nc->identities[0]); - } - } else { - d->k4_enabled = FALSE; - } - - if (d->method < 0 || d->method > K4_METHOD_K524) - d->method = K4_METHOD_AUTO; -} - -void k4_write_identity_data(k4_dlg_data * d) { - khm_handle csp_ident = NULL; - khm_handle csp_k4 = NULL; - - if (d->nc->n_identities > 0 && - d->nc->identities[0] && - KHM_SUCCEEDED(kcdb_identity_get_config(d->nc->identities[0], - KHM_FLAG_CREATE, - &csp_ident))) { - khc_open_space(csp_ident, CSNAME_KRB4CRED, - KHM_FLAG_CREATE | KCONF_FLAG_WRITEIFMOD, - &csp_k4); - - if (csp_k4) { - khc_write_int32(csp_k4, L"Krb4NewCreds", !!d->k4_enabled); - khc_write_int32(csp_k4, L"Krb4Method", d->method); - - khc_close_space(csp_k4); - } - - khc_close_space(csp_ident); - } -} - -void k4_handle_wmnc_notify(k4_dlg_data * d, - WPARAM wParam, - LPARAM lParam) { - switch(HIWORD(wParam)) { - case WMNC_UPDATE_CREDTEXT: - { - if (d->nct->credtext) { - PFREE(d->nct->credtext); - d->nct->credtext = NULL; - } - - if (d->nc->n_identities > 0 && - d->nc->identities[0]) { - - khm_int32 flags = 0; - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - wchar_t * atsign; - wchar_t * realm; - khm_size cb; - - kcdb_identity_get_flags(d->nc->identities[0], &flags); - - if (!(flags & KCDB_IDENT_FLAG_VALID)) { - break; - } - - cb = sizeof(idname); - kcdb_identity_get_name(d->nc->identities[0], idname, - &cb); - - atsign = wcsrchr(idname, L'@'); - - if (atsign == NULL || !atsign[1]) - break; - - realm = ++atsign; - - if (d->k4_enabled) { - wchar_t wmethod[128]; - wchar_t wfmt[128]; - wchar_t wct[512]; - - LoadString(hResModule, IDS_CT_TGTFOR, - wfmt, ARRAYLENGTH(wfmt)); - - if (d->method == K4_METHOD_AUTO) - LoadString(hResModule, IDS_METHOD_AUTO, wmethod, - ARRAYLENGTH(wmethod)); - else if (d->method == K4_METHOD_PASSWORD) - LoadString(hResModule, IDS_METHOD_PWD, wmethod, - ARRAYLENGTH(wmethod)); - else if (d->method == K4_METHOD_K524) - LoadString(hResModule, IDS_METHOD_K524, wmethod, - ARRAYLENGTH(wmethod)); - else { - assert(FALSE); - } - - StringCbPrintf(wct, sizeof(wct), wfmt, realm, wmethod); - - StringCbLength(wct, sizeof(wct), &cb); - cb += sizeof(wchar_t); - - d->nct->credtext = PMALLOC(cb); - - StringCbCopy(d->nct->credtext, cb, wct); - } else { - wchar_t wct[256]; - - LoadString(hResModule, IDS_CT_DISABLED, - wct, ARRAYLENGTH(wct)); - - StringCbLength(wct, sizeof(wct), &cb); - cb += sizeof(wchar_t); - - d->nct->credtext = PMALLOC(cb); - - StringCbCopy(d->nct->credtext, cb, wct); - } - } - /* no identities were selected. it is not the - responsibility of krb4 to complain about this. */ - } - break; - - case WMNC_IDENTITY_CHANGE: - k4_read_identity_data(d); - k4_update_display(d, TRUE); - break; - - case WMNC_CREDTEXT_LINK: - { - wchar_t wid[KHUI_MAXCCH_HTLINK_FIELD]; - wchar_t * wids; - khui_htwnd_link * l; - - l = (khui_htwnd_link *) lParam; - - StringCchCopyN(wid, ARRAYLENGTH(wid), l->id, l->id_len); - wids = wcschr(wid, L':'); - - if (!wids) - break; - else - wids++; - - if (!wcscmp(wids, L"Enable")) { - d->k4_enabled = TRUE; - - k4_update_display(d, TRUE); - khui_cw_enable_type(d->nc, credtype_id_krb4, TRUE); - } - } - break; - } -} - -INT_PTR CALLBACK k4_nc_dlg_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - - k4_dlg_data * d; - - switch(uMsg) { - case WM_INITDIALOG: - { - d = PMALLOC(sizeof(*d)); - ZeroMemory(d, sizeof(*d)); - - d->nc = (khui_new_creds *) lParam; - khui_cw_find_type(d->nc, credtype_id_krb4, &d->nct); - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM) d); -#pragma warning(pop) - - d->nct->aux = (LPARAM) d; - d->hwnd = hwnd; - - d->k4_enabled = TRUE; - d->method = K4_METHOD_AUTO; - - k4_update_display(d, TRUE); - } - break; - - case WM_COMMAND: - { - if (HIWORD(wParam) == BN_CLICKED) { - d = (k4_dlg_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - k4_update_data(d); - - if (LOWORD(wParam) == IDC_NCK4_OBTAIN) { - k4_update_display(d, TRUE); - } - - return TRUE; - } - } - break; - - case KHUI_WM_NC_NOTIFY: - { - d = (k4_dlg_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - k4_handle_wmnc_notify(d, wParam, lParam); - } - break; - - case WM_DESTROY: - { - d = (k4_dlg_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - d->nct->aux = 0; - - PFREE(d); - } - break; - } - - return FALSE; -} - -khm_int32 -krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, - khm_ui_4 uparam, void * vparam) { - - switch(msg_subtype) { - case KMSG_CRED_NEW_CREDS: - { - khui_new_creds * nc; - khui_new_creds_by_type * nct; - khm_size cbsize; - wchar_t wbuf[256]; - - nc = (khui_new_creds *) vparam; - - nct = PMALLOC(sizeof(*nct)); -#ifdef DEBUG - assert(nct); -#endif - ZeroMemory(nct, sizeof(*nct)); - - nct->type = credtype_id_krb4; - nct->ordinal = 3; - LoadString(hResModule, IDS_NC_K4_SHORT, - wbuf, ARRAYLENGTH(wbuf)); - StringCbLength(wbuf, sizeof(wbuf), &cbsize); - cbsize += sizeof(wchar_t); - - nct->name = PMALLOC(cbsize); - StringCbCopy(nct->name, cbsize, wbuf); - - nct->type_deps[nct->n_type_deps++] = credtype_id_krb5; - - nct->h_module = hResModule; - nct->dlg_proc = k4_nc_dlg_proc; - nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB4); - - khui_cw_add_type(nc, nct); - } - break; - - case KMSG_CRED_RENEW_CREDS: - { - khui_new_creds * nc; - khui_new_creds_by_type * nct; - khm_size cbsize; - wchar_t wbuf[256]; - - nc = (khui_new_creds *) vparam; - - if (!nc->ctx.identity) - break; - - nct = PMALLOC(sizeof(*nct)); -#ifdef DEBUG - assert(nct); -#endif - - ZeroMemory(nct, sizeof(*nct)); - - nct->type = credtype_id_krb4; - nct->ordinal = 3; - LoadString(hResModule, IDS_NC_K4_SHORT, - wbuf, ARRAYLENGTH(wbuf)); - StringCbLength(wbuf, sizeof(wbuf), &cbsize); - cbsize += sizeof(wchar_t); - - nct->name = PMALLOC(cbsize); - StringCbCopy(nct->name, cbsize, wbuf); - - nct->type_deps[nct->n_type_deps++] = credtype_id_krb5; - - khui_cw_add_type(nc, nct); - } - break; - - case KMSG_CRED_DIALOG_SETUP: - break; - - case KMSG_CRED_PROCESS: - { - khui_new_creds * nc; - khui_new_creds_by_type * nct = NULL; - 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))) - break; - - if (nc->subtype == KMSG_CRED_NEW_CREDS || - nc->subtype == KMSG_CRED_RENEW_CREDS) { - khm_int32 method; - - if (nc->subtype == KMSG_CRED_NEW_CREDS) { - - d = (k4_dlg_data *) nct->aux; - if (!d || - nc->n_identities == 0 || - nc->identities[0] == NULL || - 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 && - nc->ctx.identity != NULL) || - - (nc->ctx.scope == KHUI_SCOPE_CREDTYPE && - nc->ctx.cred_type == credtype_id_krb4 && - nc->ctx.identity != NULL) || - - (nc->ctx.scope == KHUI_SCOPE_CRED && - nc->ctx.cred_type == credtype_id_krb4 && - nc->ctx.identity != NULL && - nc->ctx.cred != NULL)) { - - ident = nc->ctx.identity; - - if (!k4_should_identity_get_k4(ident)) { - - _reportf(L"Kerberos 4 is not enabled for this identity. Skipping"); - - khui_cw_set_response(nc, credtype_id_krb4, - KHUI_NC_RESPONSE_FAILED | - KHUI_NC_RESPONSE_EXIT); - break; - } - - } else { - - _reportf(L"Kerberos 4 is not within renewal scope. Skipping"); - - 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); - break; - } - - if ((method == K4_METHOD_AUTO || - 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 | - KHUI_NC_RESPONSE_EXIT); - - if (nc->subtype == KMSG_CRED_NEW_CREDS) { - 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; - - } - } - - /* only supported for new credentials */ - if (method == K4_METHOD_AUTO || - method == K4_METHOD_PASSWORD) { - - khm_size n_prompts = 0; - khm_size idx; - khm_size cb; - wchar_t wpwd[KHUI_MAXCCH_PROMPT_VALUE]; - char pwd[KHUI_MAXCCH_PROMPT_VALUE]; - wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; - char idname[KCDB_IDENT_MAXCCH_NAME]; - - char * aname = NULL; - char * inst = NULL; - char * realm = NULL; - - 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); - - if (n_prompts == 0) - goto _skip_pwd; - - for (idx = 0; idx < n_prompts; idx++) { - khui_new_creds_prompt * p; - - if (KHM_FAILED(khui_cw_get_prompt(nc, idx, &p))) - continue; - - if (p->type == KHUI_NCPROMPT_TYPE_PASSWORD) - break; - } - - 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))) { - _reportf(L"Failed to obtain password value"); - goto _skip_pwd; - } - - UnicodeStrToAnsi(pwd, sizeof(pwd), wpwd); - - cb = sizeof(widname); - kcdb_identity_get_name(ident, - widname, - &cb); - - UnicodeStrToAnsi(idname, sizeof(idname), widname); - - { - char * atsign; - - atsign = strchr(idname, '@'); - if (atsign == NULL) { - _reportf(L"Identity name does not contain an '@'"); - goto _skip_pwd; - } - - *atsign++ = 0; - - realm = atsign; - } - - { - char * slash; - - slash = strchr(idname, '/'); - if (slash != NULL) { - *slash++ = 0; - inst = slash; - } else { - inst = ""; - } - } - - aname = idname; - - code = khm_krb4_kinit(aname, inst, realm, - (long) d->lifetime, pwd); - - _reportf(L"khm_krb4_kinit returns code %d", code); - - _skip_pwd: - - if (code) { - khui_cw_set_response(nc, credtype_id_krb4, - KHUI_NC_RESPONSE_EXIT | - KHUI_NC_RESPONSE_FAILED); - - } else { - khui_cw_set_response(nc, credtype_id_krb4, - KHUI_NC_RESPONSE_EXIT | - KHUI_NC_RESPONSE_SUCCESS); - - if (nc->subtype == KMSG_CRED_NEW_CREDS) { - - assert(d != NULL); - k4_write_identity_data(d); - - } - } - } - - _end_task(); - } - } - break; - - case KMSG_CRED_END: - { - khui_new_creds * nc; - khui_new_creds_by_type * nct = NULL; - - nc = (khui_new_creds *) vparam; - if (KHM_FAILED(khui_cw_find_type(nc, credtype_id_krb4, &nct))) - break; - - khui_cw_del_type(nc, credtype_id_krb4); - - if (nct->name) - PFREE(nct->name); - - if (nct->credtext) - PFREE(nct->credtext); - - PFREE(nct); - } - break; - } - - return KHM_ERROR_SUCCESS; -} +/* + * 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 +#include +#include +#include +#include + +/* method identifiers should be contiguous */ +#define K4_METHOD_AUTO 0 +#define K4_METHOD_PASSWORD 1 +#define K4_METHOD_K524 2 + +int method_to_id[] = { + IDC_NCK4_AUTO, + IDC_NCK4_PWD, + IDC_NCK4_K524 +}; + +typedef struct tag_k4_dlg_data { + HWND hwnd; + khui_new_creds * nc; + khui_new_creds_by_type * nct; + + khm_boolean k4_enabled; + khm_int32 method; + time_t lifetime; +} k4_dlg_data; + +void k4_update_display(k4_dlg_data * d, BOOL update_methods) { + CheckDlgButton(d->hwnd, IDC_NCK4_OBTAIN, + (d->k4_enabled)?BST_CHECKED: BST_UNCHECKED); + + if (d->k4_enabled) { + EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_AUTO), TRUE); + EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_K524), TRUE); + EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_PWD ), TRUE); + } else { + EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_AUTO), FALSE); + EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_K524), FALSE); + EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_PWD ), FALSE); + } + +#ifdef DEBUG + assert(d->method >= 0 && d->method < ARRAYLENGTH(method_to_id)); +#endif + + CheckRadioButton(d->hwnd, IDC_NCK4_AUTO, IDC_NCK4_PWD, method_to_id[d->method]); + + khui_cw_enable_type(d->nc, credtype_id_krb4, d->k4_enabled); +} + +void k4_update_data(k4_dlg_data * d) { + int i; + khm_boolean oldstate; + + oldstate = d->k4_enabled; + + if (IsDlgButtonChecked(d->hwnd, IDC_NCK4_OBTAIN) == BST_CHECKED) + d->k4_enabled = TRUE; + else + d->k4_enabled = FALSE; + + if ((oldstate && !d->k4_enabled) || + (!oldstate && d->k4_enabled)) { + + khui_cw_enable_type(d->nc, credtype_id_krb4, d->k4_enabled); + } + + d->method = K4_METHOD_AUTO; + + for (i=K4_METHOD_AUTO; i<=K4_METHOD_K524; i++) { + if (IsDlgButtonChecked(d->hwnd, method_to_id[i]) == BST_CHECKED) { + d->method = i; + break; + } + } +} + +khm_boolean k4_should_identity_get_k4(khm_handle ident) { + khm_int32 idflags = 0; + khm_int32 t = TRUE; + khm_handle csp_ident = NULL; + khm_handle csp_k4 = NULL; + khm_boolean get_k4 = TRUE; + khm_boolean id_spec = FALSE; + + if (KHM_FAILED(kcdb_identity_get_flags(ident, &idflags))) + return FALSE; + + if (!(idflags & KCDB_IDENT_FLAG_DEFAULT)) { + /* we only support k4 for one identity, and that is the + default identity. If we are trying to get tickets for a + non-default identity, then we start off as disabled unless + there is no default identity. */ + + khm_handle defident = NULL; + + if (KHM_SUCCEEDED(kcdb_identity_get_default(&defident))) { + kcdb_identity_release(defident); + + return FALSE; + } + } + + 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))) { + get_k4 = !!t; + id_spec = TRUE; + } + + khc_close_space(csp_k4); + } + khc_close_space(csp_ident); + } + + /* if there was a value specified for the identity, then that + takes precedence. */ + if (id_spec || !get_k4) + return get_k4; + + if (KHM_SUCCEEDED(khc_read_int32(csp_params, L"Krb4NewCreds", &t)) && + !t) + return FALSE; + + return TRUE; +} + +void k4_read_identity_data(k4_dlg_data * d) { + khm_handle csp_ident = NULL; + khm_handle csp_k4 = NULL; + + khm_int32 idflags = 0; + khm_int32 t; + + if (KHM_SUCCEEDED(khc_read_int32(csp_params, L"Krb4NewCreds", &t))) + d->k4_enabled = !!t; + else + d->k4_enabled = TRUE; + + if (KHM_SUCCEEDED(khc_read_int32(csp_params, L"Krb4Method", &t))) + d->method = t; + else + d->method = K4_METHOD_AUTO; + + if (KHM_SUCCEEDED(khc_read_int32(csp_params, L"DefaultLifetime", &t))) + d->lifetime = t; + else + d->lifetime = 10 * 60 * 60; /* 10 hours */ + + if (d->nc->n_identities > 0 && + d->nc->identities[0]) { + + if (KHM_SUCCEEDED(kcdb_identity_get_config(d->nc->identities[0], + 0, + &csp_ident))) { + + khc_open_space(csp_ident, CSNAME_KRB4CRED, 0, &csp_k4); + + if (csp_k4) { + if (KHM_SUCCEEDED(khc_read_int32(csp_k4, L"Krb4NewCreds", &t))) + d->k4_enabled = !!t; + if (KHM_SUCCEEDED(khc_read_int32(csp_k4, L"Krb4Method", &t))) + d->method = t; + khc_close_space(csp_k4); + } + + khc_close_space(csp_ident); + } + + if (d->k4_enabled) { + d->k4_enabled = k4_should_identity_get_k4(d->nc->identities[0]); + } + } else { + d->k4_enabled = FALSE; + } + + if (d->method < 0 || d->method > K4_METHOD_K524) + d->method = K4_METHOD_AUTO; +} + +void k4_write_identity_data(k4_dlg_data * d) { + khm_handle csp_ident = NULL; + khm_handle csp_k4 = NULL; + + if (d->nc->n_identities > 0 && + d->nc->identities[0] && + KHM_SUCCEEDED(kcdb_identity_get_config(d->nc->identities[0], + KHM_FLAG_CREATE, + &csp_ident))) { + khc_open_space(csp_ident, CSNAME_KRB4CRED, + KHM_FLAG_CREATE | KCONF_FLAG_WRITEIFMOD, + &csp_k4); + + if (csp_k4) { + khc_write_int32(csp_k4, L"Krb4NewCreds", !!d->k4_enabled); + khc_write_int32(csp_k4, L"Krb4Method", d->method); + + khc_close_space(csp_k4); + } + + khc_close_space(csp_ident); + } +} + +void k4_handle_wmnc_notify(k4_dlg_data * d, + WPARAM wParam, + LPARAM lParam) { + switch(HIWORD(wParam)) { + case WMNC_UPDATE_CREDTEXT: + { + if (d->nct->credtext) { + PFREE(d->nct->credtext); + d->nct->credtext = NULL; + } + + if (d->nc->n_identities > 0 && + d->nc->identities[0]) { + + khm_int32 flags = 0; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t * atsign; + wchar_t * realm; + khm_size cb; + + kcdb_identity_get_flags(d->nc->identities[0], &flags); + + if (!(flags & KCDB_IDENT_FLAG_VALID)) { + break; + } + + cb = sizeof(idname); + kcdb_identity_get_name(d->nc->identities[0], idname, + &cb); + + atsign = wcsrchr(idname, L'@'); + + if (atsign == NULL || !atsign[1]) + break; + + realm = ++atsign; + + if (d->k4_enabled) { + wchar_t wmethod[128]; + wchar_t wfmt[128]; + wchar_t wct[512]; + + LoadString(hResModule, IDS_CT_TGTFOR, + wfmt, ARRAYLENGTH(wfmt)); + + if (d->method == K4_METHOD_AUTO) + LoadString(hResModule, IDS_METHOD_AUTO, wmethod, + ARRAYLENGTH(wmethod)); + else if (d->method == K4_METHOD_PASSWORD) + LoadString(hResModule, IDS_METHOD_PWD, wmethod, + ARRAYLENGTH(wmethod)); + else if (d->method == K4_METHOD_K524) + LoadString(hResModule, IDS_METHOD_K524, wmethod, + ARRAYLENGTH(wmethod)); + else { + assert(FALSE); + } + + StringCbPrintf(wct, sizeof(wct), wfmt, realm, wmethod); + + StringCbLength(wct, sizeof(wct), &cb); + cb += sizeof(wchar_t); + + d->nct->credtext = PMALLOC(cb); + + StringCbCopy(d->nct->credtext, cb, wct); + } else { + wchar_t wct[256]; + + LoadString(hResModule, IDS_CT_DISABLED, + wct, ARRAYLENGTH(wct)); + + StringCbLength(wct, sizeof(wct), &cb); + cb += sizeof(wchar_t); + + d->nct->credtext = PMALLOC(cb); + + StringCbCopy(d->nct->credtext, cb, wct); + } + } + /* no identities were selected. it is not the + responsibility of krb4 to complain about this. */ + } + break; + + case WMNC_IDENTITY_CHANGE: + k4_read_identity_data(d); + k4_update_display(d, TRUE); + break; + + case WMNC_CREDTEXT_LINK: + { + wchar_t wid[KHUI_MAXCCH_HTLINK_FIELD]; + wchar_t * wids; + khui_htwnd_link * l; + + l = (khui_htwnd_link *) lParam; + + StringCchCopyN(wid, ARRAYLENGTH(wid), l->id, l->id_len); + wids = wcschr(wid, L':'); + + if (!wids) + break; + else + wids++; + + if (!wcscmp(wids, L"Enable")) { + d->k4_enabled = TRUE; + + k4_update_display(d, TRUE); + khui_cw_enable_type(d->nc, credtype_id_krb4, TRUE); + } + } + break; + } +} + +INT_PTR CALLBACK k4_nc_dlg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + k4_dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + { + d = PMALLOC(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + + d->nc = (khui_new_creds *) lParam; + khui_cw_find_type(d->nc, credtype_id_krb4, &d->nct); + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM) d); +#pragma warning(pop) + + d->nct->aux = (LPARAM) d; + d->hwnd = hwnd; + + d->k4_enabled = TRUE; + d->method = K4_METHOD_AUTO; + + k4_update_display(d, TRUE); + } + break; + + case WM_COMMAND: + { + if (HIWORD(wParam) == BN_CLICKED) { + d = (k4_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + k4_update_data(d); + + if (LOWORD(wParam) == IDC_NCK4_OBTAIN) { + k4_update_display(d, TRUE); + } + + return TRUE; + } + } + break; + + case KHUI_WM_NC_NOTIFY: + { + d = (k4_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + k4_handle_wmnc_notify(d, wParam, lParam); + } + break; + + case WM_DESTROY: + { + d = (k4_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + d->nct->aux = 0; + + PFREE(d); + } + break; + } + + return FALSE; +} + +khm_int32 +krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) { + + switch(msg_subtype) { + case KMSG_CRED_NEW_CREDS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + khm_size cbsize; + wchar_t wbuf[256]; + + nc = (khui_new_creds *) vparam; + + nct = PMALLOC(sizeof(*nct)); +#ifdef DEBUG + assert(nct); +#endif + ZeroMemory(nct, sizeof(*nct)); + + nct->type = credtype_id_krb4; + nct->ordinal = 3; + LoadString(hResModule, IDS_NC_K4_SHORT, + wbuf, ARRAYLENGTH(wbuf)); + StringCbLength(wbuf, sizeof(wbuf), &cbsize); + cbsize += sizeof(wchar_t); + + nct->name = PMALLOC(cbsize); + StringCbCopy(nct->name, cbsize, wbuf); + + nct->type_deps[nct->n_type_deps++] = credtype_id_krb5; + + nct->h_module = hResModule; + nct->dlg_proc = k4_nc_dlg_proc; + nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB4); + + khui_cw_add_type(nc, nct); + } + break; + + case KMSG_CRED_RENEW_CREDS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + khm_size cbsize; + wchar_t wbuf[256]; + + nc = (khui_new_creds *) vparam; + + if (!nc->ctx.identity) + break; + + nct = PMALLOC(sizeof(*nct)); +#ifdef DEBUG + assert(nct); +#endif + + ZeroMemory(nct, sizeof(*nct)); + + nct->type = credtype_id_krb4; + nct->ordinal = 3; + LoadString(hResModule, IDS_NC_K4_SHORT, + wbuf, ARRAYLENGTH(wbuf)); + StringCbLength(wbuf, sizeof(wbuf), &cbsize); + cbsize += sizeof(wchar_t); + + nct->name = PMALLOC(cbsize); + StringCbCopy(nct->name, cbsize, wbuf); + + nct->type_deps[nct->n_type_deps++] = credtype_id_krb5; + + khui_cw_add_type(nc, nct); + } + break; + + case KMSG_CRED_DIALOG_SETUP: + break; + + case KMSG_CRED_PROCESS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct = NULL; + 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))) + break; + + if (nc->subtype == KMSG_CRED_NEW_CREDS || + nc->subtype == KMSG_CRED_RENEW_CREDS) { + khm_int32 method; + + if (nc->subtype == KMSG_CRED_NEW_CREDS) { + + d = (k4_dlg_data *) nct->aux; + if (!d || + nc->n_identities == 0 || + nc->identities[0] == NULL || + 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 && + nc->ctx.identity != NULL) || + + (nc->ctx.scope == KHUI_SCOPE_CREDTYPE && + nc->ctx.cred_type == credtype_id_krb4 && + nc->ctx.identity != NULL) || + + (nc->ctx.scope == KHUI_SCOPE_CRED && + nc->ctx.cred_type == credtype_id_krb4 && + nc->ctx.identity != NULL && + nc->ctx.cred != NULL)) { + + ident = nc->ctx.identity; + + if (!k4_should_identity_get_k4(ident)) { + + _reportf(L"Kerberos 4 is not enabled for this identity. Skipping"); + + khui_cw_set_response(nc, credtype_id_krb4, + KHUI_NC_RESPONSE_FAILED | + KHUI_NC_RESPONSE_EXIT); + break; + } + + } else { + + _reportf(L"Kerberos 4 is not within renewal scope. Skipping"); + + 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); + break; + } + + if ((method == K4_METHOD_AUTO || + 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 | + KHUI_NC_RESPONSE_EXIT); + + if (nc->subtype == KMSG_CRED_NEW_CREDS) { + 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; + + } + } + + /* only supported for new credentials */ + if (method == K4_METHOD_AUTO || + method == K4_METHOD_PASSWORD) { + + khm_size n_prompts = 0; + khm_size idx; + khm_size cb; + wchar_t wpwd[KHUI_MAXCCH_PROMPT_VALUE]; + char pwd[KHUI_MAXCCH_PROMPT_VALUE]; + wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; + char idname[KCDB_IDENT_MAXCCH_NAME]; + + char * aname = NULL; + char * inst = NULL; + char * realm = NULL; + + 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); + + if (n_prompts == 0) + goto _skip_pwd; + + for (idx = 0; idx < n_prompts; idx++) { + khui_new_creds_prompt * p; + + if (KHM_FAILED(khui_cw_get_prompt(nc, idx, &p))) + continue; + + if (p->type == KHUI_NCPROMPT_TYPE_PASSWORD) + break; + } + + 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))) { + _reportf(L"Failed to obtain password value"); + goto _skip_pwd; + } + + UnicodeStrToAnsi(pwd, sizeof(pwd), wpwd); + + cb = sizeof(widname); + kcdb_identity_get_name(ident, + widname, + &cb); + + UnicodeStrToAnsi(idname, sizeof(idname), widname); + + { + char * atsign; + + atsign = strchr(idname, '@'); + if (atsign == NULL) { + _reportf(L"Identity name does not contain an '@'"); + goto _skip_pwd; + } + + *atsign++ = 0; + + realm = atsign; + } + + { + char * slash; + + slash = strchr(idname, '/'); + if (slash != NULL) { + *slash++ = 0; + inst = slash; + } else { + inst = ""; + } + } + + aname = idname; + + code = khm_krb4_kinit(aname, inst, realm, + (long) d->lifetime, pwd); + + _reportf(L"khm_krb4_kinit returns code %d", code); + + _skip_pwd: + + if (code) { + khui_cw_set_response(nc, credtype_id_krb4, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_FAILED); + + } else { + khui_cw_set_response(nc, credtype_id_krb4, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_SUCCESS); + + if (nc->subtype == KMSG_CRED_NEW_CREDS) { + + assert(d != NULL); + k4_write_identity_data(d); + + } + } + } + + _end_task(); + } + } + break; + + case KMSG_CRED_END: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct = NULL; + + nc = (khui_new_creds *) vparam; + if (KHM_FAILED(khui_cw_find_type(nc, credtype_id_krb4, &nct))) + break; + + khui_cw_del_type(nc, credtype_id_krb4); + + if (nct->name) + PFREE(nct->name); + + if (nct->credtext) + PFREE(nct->credtext); + + PFREE(nct); + } + break; + } + + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/plugins/krb4/krb4plugin.c b/src/windows/identity/plugins/krb4/krb4plugin.c index b4edd4192..9a50249f7 100644 --- a/src/windows/identity/plugins/krb4/krb4plugin.c +++ b/src/windows/identity/plugins/krb4/krb4plugin.c @@ -1,297 +1,297 @@ -/* - * 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 -#include -#include -#include - -khm_int32 credtype_id_krb4 = KCDB_CREDTYPE_INVALID; -khm_int32 credtype_id_krb5 = KCDB_CREDTYPE_INVALID; - -khm_boolean krb4_initialized = FALSE; -khm_handle krb4_credset = NULL; - -/* Kerberos IV stuff */ -khm_int32 KHMAPI -krb4_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, - khm_ui_4 uparam, void * vparam) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - - switch(msg_subtype) { - case KMSG_SYSTEM_INIT: - { -#ifdef _WIN64 - return KHM_ERROR_NOT_IMPLEMENTED; -#else - kcdb_credtype ct; - wchar_t buf[KCDB_MAXCCH_SHORT_DESC]; - size_t cbsize; - khui_config_node_reg reg; - wchar_t wshort_desc[KHUI_MAXCCH_SHORT_DESC]; - wchar_t wlong_desc[KHUI_MAXCCH_LONG_DESC]; - - /* perform critical registrations and initialization - stuff */ - ZeroMemory(&ct, sizeof(ct)); - ct.id = KCDB_CREDTYPE_AUTO; - ct.name = KRB4_CREDTYPE_NAME; - - if(LoadString(hResModule, IDS_KRB4_SHORT_DESC, - buf, ARRAYLENGTH(buf))) - { - StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); - cbsize += sizeof(wchar_t); - ct.short_desc = PMALLOC(cbsize); - StringCbCopy(ct.short_desc, cbsize, buf); - } - - /* even though ideally we should be setting limits - based KCDB_MAXCB_LONG_DESC, our long description - actually fits nicely in KCDB_MAXCB_SHORT_DESC */ - if(LoadString(hResModule, IDS_KRB4_LONG_DESC, - buf, ARRAYLENGTH(buf))) - { - StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); - cbsize += sizeof(wchar_t); - ct.long_desc = PMALLOC(cbsize); - StringCbCopy(ct.long_desc, cbsize, buf); - } - - ct.icon = NULL; /* TODO: set a proper icon */ - kmq_create_subscription(krb4_cb, &ct.sub); - - rv = kcdb_credtype_register(&ct, &credtype_id_krb4); - - if(KHM_SUCCEEDED(rv)) - rv = kcdb_credset_create(&krb4_credset); - - if (KHM_SUCCEEDED(rv)) - rv = kcdb_credtype_get_id(KRB5_CREDTYPE_NAME, - &credtype_id_krb5); - - if(ct.short_desc) - PFREE(ct.short_desc); - - if(ct.long_desc) - PFREE(ct.long_desc); - - if (KHM_SUCCEEDED(rv)) { - khui_config_node idents; - - ZeroMemory(®, sizeof(reg)); - - reg.name = KRB4_CONFIG_NODE_NAME; - reg.short_desc = wshort_desc; - reg.long_desc = wlong_desc; - reg.h_module = hResModule; - reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_KRB4); - reg.dlg_proc = krb4_confg_proc; - reg.flags = 0; - - LoadString(hResModule, IDS_CFG_KRB4_LONG, - wlong_desc, ARRAYLENGTH(wlong_desc)); - LoadString(hResModule, IDS_CFG_KRB4_SHORT, - wshort_desc, ARRAYLENGTH(wshort_desc)); - - khui_cfg_register(NULL, ®); - - khui_cfg_open(NULL, L"KhmIdentities", &idents); - - ZeroMemory(®, sizeof(reg)); - - reg.name = KRB4_IDS_CONFIG_NODE_NAME; - reg.short_desc = wshort_desc; - reg.long_desc = wlong_desc; - reg.h_module = hResModule; - reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDS_KRB4); - reg.dlg_proc = krb4_ids_config_proc; - reg.flags = KHUI_CNFLAG_SUBPANEL; - - LoadString(hResModule, IDS_CFG_KRB4_SHORT, - wlong_desc, ARRAYLENGTH(wlong_desc)); - LoadString(hResModule, IDS_CFG_KRB4_SHORT, - wshort_desc, ARRAYLENGTH(wshort_desc)); - - khui_cfg_register(idents, ®); - - ZeroMemory(®, sizeof(reg)); - - reg.name = KRB4_ID_CONFIG_NODE_NAME; - reg.short_desc = wshort_desc; - reg.long_desc = wlong_desc; - reg.h_module = hResModule; - reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_ID_KRB4); - reg.dlg_proc = krb4_id_config_proc; - reg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_PLURAL; - - LoadString(hResModule, IDS_CFG_KRB4_SHORT, - wlong_desc, ARRAYLENGTH(wlong_desc)); - LoadString(hResModule, IDS_CFG_KRB4_SHORT, - wshort_desc, ARRAYLENGTH(wshort_desc)); - - khui_cfg_register(idents, ®); - - khui_cfg_release(idents); - - } - - /* Lookup common data types */ - if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ENCTYPE, - &type_id_enctype))) { - rv = KHM_ERROR_UNKNOWN; - } - - if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ADDR_LIST, - &type_id_addr_list))) { - rv = KHM_ERROR_UNKNOWN; - } - - if(KHM_FAILED(kcdb_type_get_id(TYPENAME_KRB5_FLAGS, - &type_id_krb5_flags))) { - rv = KHM_ERROR_UNKNOWN; - } - - /* Lookup common attributes */ - if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KEY_ENCTYPE, - &attr_id_key_enctype))) { - rv = KHM_ERROR_UNKNOWN; - } - - if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_TKT_ENCTYPE, - &attr_id_tkt_enctype))) { - rv = KHM_ERROR_UNKNOWN; - } - - if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_ADDR_LIST, - &attr_id_addr_list))) { - rv = KHM_ERROR_UNKNOWN; - } - - if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_FLAGS, - &attr_id_krb5_flags))) { - rv = KHM_ERROR_UNKNOWN; - } - - krb4_initialized = TRUE; - - khm_krb4_set_def_tkt_string(); - - khm_krb4_list_tickets(); -#endif - } - break; - - case KMSG_SYSTEM_EXIT: -#ifdef _WIN64 - /* See above. On 64-bit platforms, we don't support Krb4 at - all. */ - return 0; -#else - if(credtype_id_krb4 >= 0) - { - /* basically just unregister the credential type */ - kcdb_credtype_unregister(credtype_id_krb4); - - kcdb_credset_delete(krb4_credset); - } - break; -#endif - } - - return rv; -} - -khm_int32 KHMAPI -krb4_msg_cred(khm_int32 msg_type, khm_int32 msg_subtype, - khm_ui_4 uparam, void * vparam) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - - switch(msg_subtype) { - case KMSG_CRED_REFRESH: - { - khm_krb4_list_tickets(); - } - break; - - case KMSG_CRED_DESTROY_CREDS: - { - khui_action_context * ctx; - khm_handle credset; - khm_size nc_root = 0; - khm_size nc_sel = 0; - - ctx = (khui_action_context *) vparam; - - /* if all krb4 tickets are selected, then we destroy all - of them. Otherwise, we do nothing. */ - - kcdb_credset_create(&credset); - - kcdb_credset_extract(credset, ctx->credset, - NULL, credtype_id_krb4); - kcdb_credset_get_size(credset, &nc_sel); - - kcdb_credset_flush(credset); - - kcdb_credset_extract(credset, NULL, - NULL, credtype_id_krb4); - kcdb_credset_get_size(credset, &nc_root); - - kcdb_credset_delete(credset); - - if (nc_root == nc_sel) { - khm_krb4_kdestroy(); - } - } - break; - - default: - if (IS_CRED_ACQ_MSG(msg_subtype)) - return krb4_msg_newcred(msg_type, msg_subtype, uparam, vparam); - } - - return rv; -} - -khm_int32 KHMAPI -krb4_cb(khm_int32 msg_type, khm_int32 msg_subtype, - khm_ui_4 uparam, void * vparam) -{ - switch(msg_type) { - case KMSG_SYSTEM: - return krb4_msg_system(msg_type, msg_subtype, uparam, vparam); - case KMSG_CRED: - return krb4_msg_cred(msg_type, msg_subtype, uparam, vparam); - } - return KHM_ERROR_SUCCESS; -} +/* + * 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 +#include +#include +#include + +khm_int32 credtype_id_krb4 = KCDB_CREDTYPE_INVALID; +khm_int32 credtype_id_krb5 = KCDB_CREDTYPE_INVALID; + +khm_boolean krb4_initialized = FALSE; +khm_handle krb4_credset = NULL; + +/* Kerberos IV stuff */ +khm_int32 KHMAPI +krb4_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_SYSTEM_INIT: + { +#ifdef _WIN64 + return KHM_ERROR_NOT_IMPLEMENTED; +#else + kcdb_credtype ct; + wchar_t buf[KCDB_MAXCCH_SHORT_DESC]; + size_t cbsize; + khui_config_node_reg reg; + wchar_t wshort_desc[KHUI_MAXCCH_SHORT_DESC]; + wchar_t wlong_desc[KHUI_MAXCCH_LONG_DESC]; + + /* perform critical registrations and initialization + stuff */ + ZeroMemory(&ct, sizeof(ct)); + ct.id = KCDB_CREDTYPE_AUTO; + ct.name = KRB4_CREDTYPE_NAME; + + if(LoadString(hResModule, IDS_KRB4_SHORT_DESC, + buf, ARRAYLENGTH(buf))) + { + StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); + cbsize += sizeof(wchar_t); + ct.short_desc = PMALLOC(cbsize); + StringCbCopy(ct.short_desc, cbsize, buf); + } + + /* even though ideally we should be setting limits + based KCDB_MAXCB_LONG_DESC, our long description + actually fits nicely in KCDB_MAXCB_SHORT_DESC */ + if(LoadString(hResModule, IDS_KRB4_LONG_DESC, + buf, ARRAYLENGTH(buf))) + { + StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); + cbsize += sizeof(wchar_t); + ct.long_desc = PMALLOC(cbsize); + StringCbCopy(ct.long_desc, cbsize, buf); + } + + ct.icon = NULL; /* TODO: set a proper icon */ + kmq_create_subscription(krb4_cb, &ct.sub); + + rv = kcdb_credtype_register(&ct, &credtype_id_krb4); + + if(KHM_SUCCEEDED(rv)) + rv = kcdb_credset_create(&krb4_credset); + + if (KHM_SUCCEEDED(rv)) + rv = kcdb_credtype_get_id(KRB5_CREDTYPE_NAME, + &credtype_id_krb5); + + if(ct.short_desc) + PFREE(ct.short_desc); + + if(ct.long_desc) + PFREE(ct.long_desc); + + if (KHM_SUCCEEDED(rv)) { + khui_config_node idents; + + ZeroMemory(®, sizeof(reg)); + + reg.name = KRB4_CONFIG_NODE_NAME; + reg.short_desc = wshort_desc; + reg.long_desc = wlong_desc; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_KRB4); + reg.dlg_proc = krb4_confg_proc; + reg.flags = 0; + + LoadString(hResModule, IDS_CFG_KRB4_LONG, + wlong_desc, ARRAYLENGTH(wlong_desc)); + LoadString(hResModule, IDS_CFG_KRB4_SHORT, + wshort_desc, ARRAYLENGTH(wshort_desc)); + + khui_cfg_register(NULL, ®); + + khui_cfg_open(NULL, L"KhmIdentities", &idents); + + ZeroMemory(®, sizeof(reg)); + + reg.name = KRB4_IDS_CONFIG_NODE_NAME; + reg.short_desc = wshort_desc; + reg.long_desc = wlong_desc; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDS_KRB4); + reg.dlg_proc = krb4_ids_config_proc; + reg.flags = KHUI_CNFLAG_SUBPANEL; + + LoadString(hResModule, IDS_CFG_KRB4_SHORT, + wlong_desc, ARRAYLENGTH(wlong_desc)); + LoadString(hResModule, IDS_CFG_KRB4_SHORT, + wshort_desc, ARRAYLENGTH(wshort_desc)); + + khui_cfg_register(idents, ®); + + ZeroMemory(®, sizeof(reg)); + + reg.name = KRB4_ID_CONFIG_NODE_NAME; + reg.short_desc = wshort_desc; + reg.long_desc = wlong_desc; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_ID_KRB4); + reg.dlg_proc = krb4_id_config_proc; + reg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_PLURAL; + + LoadString(hResModule, IDS_CFG_KRB4_SHORT, + wlong_desc, ARRAYLENGTH(wlong_desc)); + LoadString(hResModule, IDS_CFG_KRB4_SHORT, + wshort_desc, ARRAYLENGTH(wshort_desc)); + + khui_cfg_register(idents, ®); + + khui_cfg_release(idents); + + } + + /* Lookup common data types */ + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ENCTYPE, + &type_id_enctype))) { + rv = KHM_ERROR_UNKNOWN; + } + + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ADDR_LIST, + &type_id_addr_list))) { + rv = KHM_ERROR_UNKNOWN; + } + + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_KRB5_FLAGS, + &type_id_krb5_flags))) { + rv = KHM_ERROR_UNKNOWN; + } + + /* Lookup common attributes */ + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KEY_ENCTYPE, + &attr_id_key_enctype))) { + rv = KHM_ERROR_UNKNOWN; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_TKT_ENCTYPE, + &attr_id_tkt_enctype))) { + rv = KHM_ERROR_UNKNOWN; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_ADDR_LIST, + &attr_id_addr_list))) { + rv = KHM_ERROR_UNKNOWN; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_FLAGS, + &attr_id_krb5_flags))) { + rv = KHM_ERROR_UNKNOWN; + } + + krb4_initialized = TRUE; + + khm_krb4_set_def_tkt_string(); + + khm_krb4_list_tickets(); +#endif + } + break; + + case KMSG_SYSTEM_EXIT: +#ifdef _WIN64 + /* See above. On 64-bit platforms, we don't support Krb4 at + all. */ + return 0; +#else + if(credtype_id_krb4 >= 0) + { + /* basically just unregister the credential type */ + kcdb_credtype_unregister(credtype_id_krb4); + + kcdb_credset_delete(krb4_credset); + } + break; +#endif + } + + return rv; +} + +khm_int32 KHMAPI +krb4_msg_cred(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_CRED_REFRESH: + { + khm_krb4_list_tickets(); + } + break; + + case KMSG_CRED_DESTROY_CREDS: + { + khui_action_context * ctx; + khm_handle credset; + khm_size nc_root = 0; + khm_size nc_sel = 0; + + ctx = (khui_action_context *) vparam; + + /* if all krb4 tickets are selected, then we destroy all + of them. Otherwise, we do nothing. */ + + kcdb_credset_create(&credset); + + kcdb_credset_extract(credset, ctx->credset, + NULL, credtype_id_krb4); + kcdb_credset_get_size(credset, &nc_sel); + + kcdb_credset_flush(credset); + + kcdb_credset_extract(credset, NULL, + NULL, credtype_id_krb4); + kcdb_credset_get_size(credset, &nc_root); + + kcdb_credset_delete(credset); + + if (nc_root == nc_sel) { + khm_krb4_kdestroy(); + } + } + break; + + default: + if (IS_CRED_ACQ_MSG(msg_subtype)) + return krb4_msg_newcred(msg_type, msg_subtype, uparam, vparam); + } + + return rv; +} + +khm_int32 KHMAPI +krb4_cb(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + switch(msg_type) { + case KMSG_SYSTEM: + return krb4_msg_system(msg_type, msg_subtype, uparam, vparam); + case KMSG_CRED: + return krb4_msg_cred(msg_type, msg_subtype, uparam, vparam); + } + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/plugins/krb4/krbcred.h b/src/windows/identity/plugins/krb4/krbcred.h index 7c3b31a13..53e22c892 100644 --- a/src/windows/identity/plugins/krb4/krbcred.h +++ b/src/windows/identity/plugins/krb4/krbcred.h @@ -1,136 +1,136 @@ -/* - * 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_KRBAFSCRED_H -#define __KHIMAIRA_KRBAFSCRED_H - -#include - -#define KHERR_FACILITY L"Krb4Cred" -#define KHERR_FACILITY_ID 65 -#define KHERR_HMODULE hResModule - -#include - -#include -#include -#include -#include - -#include -#include - -#define TYPENAME_ENCTYPE L"EncType" -#define TYPENAME_ADDR_LIST L"AddrList" -#define TYPENAME_KRB5_FLAGS L"Krb5Flags" - -#define ATTRNAME_KEY_ENCTYPE L"KeyEncType" -#define ATTRNAME_TKT_ENCTYPE L"TktEncType" -#define ATTRNAME_ADDR_LIST L"AddrList" -#define ATTRNAME_KRB5_FLAGS L"Krb5Flags" -#define ATTRNAME_RENEW_TILL L"RenewTill" -#define ATTRNAME_RENEW_FOR L"RenewFor" - -void init_krb(); -void exit_krb(); -KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module); -KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module); - -/* globals */ -extern kmm_module h_khModule; -extern HMODULE hResModule; -extern HINSTANCE hInstance; - -extern khm_int32 type_id_enctype; -extern khm_int32 type_id_addr_list; -extern khm_int32 type_id_krb5_flags; - -extern khm_int32 attr_id_key_enctype; -extern khm_int32 attr_id_tkt_enctype; -extern khm_int32 attr_id_addr_list; -extern khm_int32 attr_id_krb5_flags; -extern khm_int32 attr_id_renew_till; -extern khm_int32 attr_id_renew_for; - -/* Configuration spaces */ -#define CSNAME_KRB4CRED L"Krb4Cred" -#define CSNAME_PARAMS L"Parameters" - -/* plugin constants */ -#define KRB4_PLUGIN_NAME L"Krb4Cred" - -#define KRB4_PLUGIN_DEPS L"Krb5Cred\0" - -#define KRB4_CREDTYPE_NAME L"Krb4Cred" - -#define KRB5_CREDTYPE_NAME L"Krb5Cred" - -#define KRB4_CONFIG_NODE_NAME L"Krb4Config" - -#define KRB4_ID_CONFIG_NODE_NAME L"Krb4IdentConfig" -#define KRB4_IDS_CONFIG_NODE_NAME L"Krb4IdentsConfig" - -extern khm_handle csp_plugins; -extern khm_handle csp_krbcred; -extern khm_handle csp_params; - -extern kconf_schema schema_krbconfig[]; - -/* other globals */ -extern khm_int32 credtype_id_krb4; -extern khm_int32 credtype_id_krb5; - -extern khm_boolean krb4_initialized; - -extern khm_handle krb4_credset; - -/* plugin callbacks */ -khm_int32 KHMAPI -krb4_cb(khm_int32 msg_type, khm_int32 msg_subtype, - khm_ui_4 uparam, void * vparam); - -INT_PTR CALLBACK -krb4_confg_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -INT_PTR CALLBACK -krb4_ids_config_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -INT_PTR CALLBACK -krb4_id_config_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -khm_int32 -krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, - khm_ui_4 uparam, void * vparam); -#endif +/* + * 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_KRBAFSCRED_H +#define __KHIMAIRA_KRBAFSCRED_H + +#include + +#define KHERR_FACILITY L"Krb4Cred" +#define KHERR_FACILITY_ID 65 +#define KHERR_HMODULE hResModule + +#include + +#include +#include +#include +#include + +#include +#include + +#define TYPENAME_ENCTYPE L"EncType" +#define TYPENAME_ADDR_LIST L"AddrList" +#define TYPENAME_KRB5_FLAGS L"Krb5Flags" + +#define ATTRNAME_KEY_ENCTYPE L"KeyEncType" +#define ATTRNAME_TKT_ENCTYPE L"TktEncType" +#define ATTRNAME_ADDR_LIST L"AddrList" +#define ATTRNAME_KRB5_FLAGS L"Krb5Flags" +#define ATTRNAME_RENEW_TILL L"RenewTill" +#define ATTRNAME_RENEW_FOR L"RenewFor" + +void init_krb(); +void exit_krb(); +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module); +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module); + +/* globals */ +extern kmm_module h_khModule; +extern HMODULE hResModule; +extern HINSTANCE hInstance; + +extern khm_int32 type_id_enctype; +extern khm_int32 type_id_addr_list; +extern khm_int32 type_id_krb5_flags; + +extern khm_int32 attr_id_key_enctype; +extern khm_int32 attr_id_tkt_enctype; +extern khm_int32 attr_id_addr_list; +extern khm_int32 attr_id_krb5_flags; +extern khm_int32 attr_id_renew_till; +extern khm_int32 attr_id_renew_for; + +/* Configuration spaces */ +#define CSNAME_KRB4CRED L"Krb4Cred" +#define CSNAME_PARAMS L"Parameters" + +/* plugin constants */ +#define KRB4_PLUGIN_NAME L"Krb4Cred" + +#define KRB4_PLUGIN_DEPS L"Krb5Cred\0" + +#define KRB4_CREDTYPE_NAME L"Krb4Cred" + +#define KRB5_CREDTYPE_NAME L"Krb5Cred" + +#define KRB4_CONFIG_NODE_NAME L"Krb4Config" + +#define KRB4_ID_CONFIG_NODE_NAME L"Krb4IdentConfig" +#define KRB4_IDS_CONFIG_NODE_NAME L"Krb4IdentsConfig" + +extern khm_handle csp_plugins; +extern khm_handle csp_krbcred; +extern khm_handle csp_params; + +extern kconf_schema schema_krbconfig[]; + +/* other globals */ +extern khm_int32 credtype_id_krb4; +extern khm_int32 credtype_id_krb5; + +extern khm_boolean krb4_initialized; + +extern khm_handle krb4_credset; + +/* plugin callbacks */ +khm_int32 KHMAPI +krb4_cb(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam); + +INT_PTR CALLBACK +krb4_confg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +krb4_ids_config_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +krb4_id_config_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +khm_int32 +krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam); +#endif diff --git a/src/windows/identity/plugins/krb4/langres.h b/src/windows/identity/plugins/krb4/langres.h index c78ae4167..5c0e46f9a 100644 --- a/src/windows/identity/plugins/krb4/langres.h +++ b/src/windows/identity/plugins/krb4/langres.h @@ -1,49 +1,49 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by C:\work\pismere\athena\auth\krb5\src\windows\identity\plugins\krb4\lang\en_us\langres.rc -// -#define IDD_NC_KRB4 103 -#define IDS_PLUGIN_DESC 103 -#define IDD_CFG_KRB4 104 -#define IDS_NC_K4_SHORT 104 -#define IDS_ERR_REALM 105 -#define IDD_CFG_IDS_KRB4 105 -#define IDS_ERR_PRINCIPAL 106 -#define IDD_CFG_ID_KRB4 106 -#define IDS_ERR_INVINST 107 -#define IDI_PLUGIN 107 -#define IDS_ERR_PWINTKT 108 -#define IDS_CT_DISABLED 109 -#define IDS_CT_TGTFOR 110 -#define IDS_METHOD_AUTO 111 -#define IDS_METHOD_PWD 112 -#define IDS_METHOD_K524 113 -#define IDS_CFG_IDS_KRB4_SHORT 114 -#define IDS_KRB4_SHORT_DESC 128 -#define IDS_KRB4_LONG_DESC 129 -#define IDS_CFG_KRB4_LONG 135 -#define IDS_CFG_KRB4_SHORT 136 -#define IDC_CFG_LBL_CACHE 1025 -#define IDC_CFG_LBL_CFGFILE 1026 -#define IDC_CFG_LBL_RLMPATH 1027 -#define IDC_CFG_CACHE 1028 -#define IDC_CFG_CFGPATH 1029 -#define IDC_CFG_RLMPATH 1030 -#define IDC_CFG_CFGBROW 1031 -#define IDC_CFG_RLMBROW 1032 -#define IDC_NCK4_OBTAIN 1033 -#define IDC_NCK4_AUTO 1034 -#define IDC_NCK4_K524 1035 -#define IDC_NCK4_PWD 1036 -#define IDC_CFG_GETTIX 1037 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 108 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1043 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by C:\work\pismere\athena\auth\krb5\src\windows\identity\plugins\krb4\lang\en_us\langres.rc +// +#define IDD_NC_KRB4 103 +#define IDS_PLUGIN_DESC 103 +#define IDD_CFG_KRB4 104 +#define IDS_NC_K4_SHORT 104 +#define IDS_ERR_REALM 105 +#define IDD_CFG_IDS_KRB4 105 +#define IDS_ERR_PRINCIPAL 106 +#define IDD_CFG_ID_KRB4 106 +#define IDS_ERR_INVINST 107 +#define IDI_PLUGIN 107 +#define IDS_ERR_PWINTKT 108 +#define IDS_CT_DISABLED 109 +#define IDS_CT_TGTFOR 110 +#define IDS_METHOD_AUTO 111 +#define IDS_METHOD_PWD 112 +#define IDS_METHOD_K524 113 +#define IDS_CFG_IDS_KRB4_SHORT 114 +#define IDS_KRB4_SHORT_DESC 128 +#define IDS_KRB4_LONG_DESC 129 +#define IDS_CFG_KRB4_LONG 135 +#define IDS_CFG_KRB4_SHORT 136 +#define IDC_CFG_LBL_CACHE 1025 +#define IDC_CFG_LBL_CFGFILE 1026 +#define IDC_CFG_LBL_RLMPATH 1027 +#define IDC_CFG_CACHE 1028 +#define IDC_CFG_CFGPATH 1029 +#define IDC_CFG_RLMPATH 1030 +#define IDC_CFG_CFGBROW 1031 +#define IDC_CFG_RLMBROW 1032 +#define IDC_NCK4_OBTAIN 1033 +#define IDC_NCK4_AUTO 1034 +#define IDC_NCK4_K524 1035 +#define IDC_NCK4_PWD 1036 +#define IDC_CFG_GETTIX 1037 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 108 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1043 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/windows/identity/plugins/krb5/datarep.c b/src/windows/identity/plugins/krb5/datarep.c index 92eabf4da..5c292e478 100644 --- a/src/windows/identity/plugins/krb5/datarep.c +++ b/src/windows/identity/plugins/krb5/datarep.c @@ -1,407 +1,407 @@ -/* - * 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$ */ - -/* 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) -{ - int resid = 0; - int etype; - wchar_t buf[256]; - size_t cblength; - - if(cbdata != sizeof(khm_int32)) - return KHM_ERROR_INVALID_PARAM; - - etype = *((khm_int32 *) data); - - switch(etype) { - case ENCTYPE_NULL: - resid = IDS_ETYPE_NULL; - break; - - case ENCTYPE_DES_CBC_CRC: - resid = IDS_ETYPE_DES_CBC_CRC; - break; - - case ENCTYPE_DES_CBC_MD4: - resid = IDS_ETYPE_DES_CBC_MD4; - break; - - case ENCTYPE_DES_CBC_MD5: - resid = IDS_ETYPE_DES_CBC_MD5; - break; - - case ENCTYPE_DES_CBC_RAW: - resid = IDS_ETYPE_DES_CBC_RAW; - break; - - case ENCTYPE_DES3_CBC_SHA: - resid = IDS_ETYPE_DES3_CBC_SHA; - break; - - case ENCTYPE_DES3_CBC_RAW: - resid = IDS_ETYPE_DES3_CBC_RAW; - break; - - case ENCTYPE_DES_HMAC_SHA1: - resid = IDS_ETYPE_DES_HMAC_SHA1; - break; - - case ENCTYPE_DES3_CBC_SHA1: - resid = IDS_ETYPE_DES3_CBC_SHA1; - break; - - case ENCTYPE_AES128_CTS_HMAC_SHA1_96: - resid = IDS_ETYPE_AES128_CTS_HMAC_SHA1_96; - break; - - case ENCTYPE_AES256_CTS_HMAC_SHA1_96: - resid = IDS_ETYPE_AES256_CTS_HMAC_SHA1_96; - break; - - case ENCTYPE_ARCFOUR_HMAC: - resid = IDS_ETYPE_ARCFOUR_HMAC; - break; - - case ENCTYPE_ARCFOUR_HMAC_EXP: - resid = IDS_ETYPE_ARCFOUR_HMAC_EXP; - break; - - case ENCTYPE_UNKNOWN: - resid = IDS_ETYPE_UNKNOWN; - break; - -#if 0 - case ENCTYPE_LOCAL_DES3_HMAC_SHA1: - resid = IDS_ETYPE_LOCAL_DES3_HMAC_SHA1; - break; - - case ENCTYPE_LOCAL_RC4_MD4: - resid = IDS_ETYPE_LOCAL_RC4_MD4; - break; -#endif - } - - if(resid != 0) { - LoadString(hResModule, (UINT) resid, buf, ARRAYLENGTH(buf)); - } else { - StringCbPrintf(buf, sizeof(buf), L"#%d", etype); - } - - StringCbLength(buf, ARRAYLENGTH(buf), &cblength); - cblength += sizeof(wchar_t); - - if(!destbuf || *pcbdestbuf < cblength) { - *pcbdestbuf = cblength; - return KHM_ERROR_TOO_LONG; - } else { - StringCbCopy(destbuf, *pcbdestbuf, buf); - *pcbdestbuf = cblength; - return KHM_ERROR_SUCCESS; - } -} - -khm_int32 KHMAPI -addr_list_comp(const void *d1, khm_size cb_d1, - const void *d2, khm_size cb_d2) -{ - if (cb_d1 < cb_d2) - return -1; - if (cb_d1 > cb_d2) - return 1; - return memcmp(d1, d2, cb_d1); -} - -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; - khm_size cb; - khm_int32 flags; - - flags = *((khm_int32 *) d); - - if (flags & TKT_FLG_FORWARDABLE) - sbuf[i++] = L'F'; - - if (flags & TKT_FLG_FORWARDED) - sbuf[i++] = L'f'; - - if (flags & TKT_FLG_PROXIABLE) - sbuf[i++] = L'P'; - - if (flags & TKT_FLG_PROXY) - sbuf[i++] = L'p'; - - if (flags & TKT_FLG_MAY_POSTDATE) - sbuf[i++] = L'D'; - - if (flags & TKT_FLG_POSTDATED) - sbuf[i++] = L'd'; - - if (flags & TKT_FLG_INVALID) - sbuf[i++] = L'i'; - - if (flags & TKT_FLG_RENEWABLE) - sbuf[i++] = L'R'; - - if (flags & TKT_FLG_INITIAL) - sbuf[i++] = L'I'; - - if (flags & TKT_FLG_HW_AUTH) - sbuf[i++] = L'H'; - - if (flags & TKT_FLG_PRE_AUTH) - sbuf[i++] = L'A'; - - sbuf[i++] = L'\0'; - - cb = i * sizeof(wchar_t); - - if (!buf || *pcb_buf < cb) { - *pcb_buf = cb; - return KHM_ERROR_TOO_LONG; - } else { - StringCbCopy(buf, *pcb_buf, sbuf); - *pcb_buf = cb; - return KHM_ERROR_SUCCESS; - } -} - -khm_int32 KHMAPI -kvno_toString(const void * data, khm_size cbdata, - wchar_t *destbuf, khm_size *pcbdestbuf, - khm_int32 flags) -{ - int resid = 0; - int kvno; - wchar_t buf[256]; - size_t cblength; - - if (cbdata != sizeof(khm_int32)) - return KHM_ERROR_INVALID_PARAM; - - kvno = *((khm_int32 *) data); - - StringCbPrintf(buf, sizeof(buf), L"#%d", kvno); - - StringCbLength(buf, ARRAYLENGTH(buf), &cblength); - cblength += sizeof(wchar_t); - - if (!destbuf || *pcbdestbuf < cblength) { - *pcbdestbuf = cblength; - return KHM_ERROR_TOO_LONG; - } else { - StringCbCopy(destbuf, *pcbdestbuf, buf); - *pcbdestbuf = cblength; - return KHM_ERROR_SUCCESS; - } -} - -khm_int32 -serialize_krb5_addresses(krb5_address ** a, void * buf, size_t * pcbbuf) -{ - 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; - } - } - - *pcbbuf = cb_req; - - return (overflow)?KHM_ERROR_TOO_LONG: KHM_ERROR_SUCCESS; -} - -void -one_addr(k5_serial_address *a, wchar_t * buf, khm_size cbbuf) -{ - wchar_t retstr[256]; - struct hostent *h = NULL; - int no_resolve = 1; - - retstr[0] = L'\0'; - - if ((a->addrtype == ADDRTYPE_INET && a->length == 4) -#ifdef AF_INET6 - || (a->addrtype == ADDRTYPE_INET6 && a->length == 16) -#endif - ) - { - int af = AF_INET; -#ifdef AF_INET6 - if (a->addrtype == ADDRTYPE_INET6) - af = AF_INET6; -#endif - if (!no_resolve) { -#ifdef HAVE_GETIPNODEBYADDR - int err; - h = getipnodebyaddr(&a->data, a->length, af, &err); - if (h) { - StringCbPrintf(retstr, sizeof(retstr), L"%S", h->h_name); - freehostent(h); - } - else - h = gethostbyaddr(&a->data, a->length, af); - if (h) { - StringCbPrintf(retstr, sizeof(retstr), L"%S", h->h_name); - } -#endif - if (h) - goto _copy_string; - } - if (no_resolve || !h) { -#ifdef HAVE_INET_NTOP - char buf[46]; - const char *name = inet_ntop(a->addrtype, &a->data, buf, sizeof(buf)); - if (name) { - StringCbPrintf(retstr, sizeof(retstr), L"%S", name); - goto _copy_string; - } -#else - if (a->addrtype == ADDRTYPE_INET) { - khm_ui_4 addr = a->data; - StringCbPrintf(retstr, sizeof(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); - } - - _copy_string: - StringCbCopy(buf, cbbuf, retstr); -} - +/* + * 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$ */ + +/* 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) +{ + int resid = 0; + int etype; + wchar_t buf[256]; + size_t cblength; + + if(cbdata != sizeof(khm_int32)) + return KHM_ERROR_INVALID_PARAM; + + etype = *((khm_int32 *) data); + + switch(etype) { + case ENCTYPE_NULL: + resid = IDS_ETYPE_NULL; + break; + + case ENCTYPE_DES_CBC_CRC: + resid = IDS_ETYPE_DES_CBC_CRC; + break; + + case ENCTYPE_DES_CBC_MD4: + resid = IDS_ETYPE_DES_CBC_MD4; + break; + + case ENCTYPE_DES_CBC_MD5: + resid = IDS_ETYPE_DES_CBC_MD5; + break; + + case ENCTYPE_DES_CBC_RAW: + resid = IDS_ETYPE_DES_CBC_RAW; + break; + + case ENCTYPE_DES3_CBC_SHA: + resid = IDS_ETYPE_DES3_CBC_SHA; + break; + + case ENCTYPE_DES3_CBC_RAW: + resid = IDS_ETYPE_DES3_CBC_RAW; + break; + + case ENCTYPE_DES_HMAC_SHA1: + resid = IDS_ETYPE_DES_HMAC_SHA1; + break; + + case ENCTYPE_DES3_CBC_SHA1: + resid = IDS_ETYPE_DES3_CBC_SHA1; + break; + + case ENCTYPE_AES128_CTS_HMAC_SHA1_96: + resid = IDS_ETYPE_AES128_CTS_HMAC_SHA1_96; + break; + + case ENCTYPE_AES256_CTS_HMAC_SHA1_96: + resid = IDS_ETYPE_AES256_CTS_HMAC_SHA1_96; + break; + + case ENCTYPE_ARCFOUR_HMAC: + resid = IDS_ETYPE_ARCFOUR_HMAC; + break; + + case ENCTYPE_ARCFOUR_HMAC_EXP: + resid = IDS_ETYPE_ARCFOUR_HMAC_EXP; + break; + + case ENCTYPE_UNKNOWN: + resid = IDS_ETYPE_UNKNOWN; + break; + +#if 0 + case ENCTYPE_LOCAL_DES3_HMAC_SHA1: + resid = IDS_ETYPE_LOCAL_DES3_HMAC_SHA1; + break; + + case ENCTYPE_LOCAL_RC4_MD4: + resid = IDS_ETYPE_LOCAL_RC4_MD4; + break; +#endif + } + + if(resid != 0) { + LoadString(hResModule, (UINT) resid, buf, ARRAYLENGTH(buf)); + } else { + StringCbPrintf(buf, sizeof(buf), L"#%d", etype); + } + + StringCbLength(buf, ARRAYLENGTH(buf), &cblength); + cblength += sizeof(wchar_t); + + if(!destbuf || *pcbdestbuf < cblength) { + *pcbdestbuf = cblength; + return KHM_ERROR_TOO_LONG; + } else { + StringCbCopy(destbuf, *pcbdestbuf, buf); + *pcbdestbuf = cblength; + return KHM_ERROR_SUCCESS; + } +} + +khm_int32 KHMAPI +addr_list_comp(const void *d1, khm_size cb_d1, + const void *d2, khm_size cb_d2) +{ + if (cb_d1 < cb_d2) + return -1; + if (cb_d1 > cb_d2) + return 1; + return memcmp(d1, d2, cb_d1); +} + +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; + khm_size cb; + khm_int32 flags; + + flags = *((khm_int32 *) d); + + if (flags & TKT_FLG_FORWARDABLE) + sbuf[i++] = L'F'; + + if (flags & TKT_FLG_FORWARDED) + sbuf[i++] = L'f'; + + if (flags & TKT_FLG_PROXIABLE) + sbuf[i++] = L'P'; + + if (flags & TKT_FLG_PROXY) + sbuf[i++] = L'p'; + + if (flags & TKT_FLG_MAY_POSTDATE) + sbuf[i++] = L'D'; + + if (flags & TKT_FLG_POSTDATED) + sbuf[i++] = L'd'; + + if (flags & TKT_FLG_INVALID) + sbuf[i++] = L'i'; + + if (flags & TKT_FLG_RENEWABLE) + sbuf[i++] = L'R'; + + if (flags & TKT_FLG_INITIAL) + sbuf[i++] = L'I'; + + if (flags & TKT_FLG_HW_AUTH) + sbuf[i++] = L'H'; + + if (flags & TKT_FLG_PRE_AUTH) + sbuf[i++] = L'A'; + + sbuf[i++] = L'\0'; + + cb = i * sizeof(wchar_t); + + if (!buf || *pcb_buf < cb) { + *pcb_buf = cb; + return KHM_ERROR_TOO_LONG; + } else { + StringCbCopy(buf, *pcb_buf, sbuf); + *pcb_buf = cb; + return KHM_ERROR_SUCCESS; + } +} + +khm_int32 KHMAPI +kvno_toString(const void * data, khm_size cbdata, + wchar_t *destbuf, khm_size *pcbdestbuf, + khm_int32 flags) +{ + int resid = 0; + int kvno; + wchar_t buf[256]; + size_t cblength; + + if (cbdata != sizeof(khm_int32)) + return KHM_ERROR_INVALID_PARAM; + + kvno = *((khm_int32 *) data); + + StringCbPrintf(buf, sizeof(buf), L"#%d", kvno); + + StringCbLength(buf, ARRAYLENGTH(buf), &cblength); + cblength += sizeof(wchar_t); + + if (!destbuf || *pcbdestbuf < cblength) { + *pcbdestbuf = cblength; + return KHM_ERROR_TOO_LONG; + } else { + StringCbCopy(destbuf, *pcbdestbuf, buf); + *pcbdestbuf = cblength; + return KHM_ERROR_SUCCESS; + } +} + +khm_int32 +serialize_krb5_addresses(krb5_address ** a, void * buf, size_t * pcbbuf) +{ + 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; + } + } + + *pcbbuf = cb_req; + + return (overflow)?KHM_ERROR_TOO_LONG: KHM_ERROR_SUCCESS; +} + +void +one_addr(k5_serial_address *a, wchar_t * buf, khm_size cbbuf) +{ + wchar_t retstr[256]; + struct hostent *h = NULL; + int no_resolve = 1; + + retstr[0] = L'\0'; + + if ((a->addrtype == ADDRTYPE_INET && a->length == 4) +#ifdef AF_INET6 + || (a->addrtype == ADDRTYPE_INET6 && a->length == 16) +#endif + ) + { + int af = AF_INET; +#ifdef AF_INET6 + if (a->addrtype == ADDRTYPE_INET6) + af = AF_INET6; +#endif + if (!no_resolve) { +#ifdef HAVE_GETIPNODEBYADDR + int err; + h = getipnodebyaddr(&a->data, a->length, af, &err); + if (h) { + StringCbPrintf(retstr, sizeof(retstr), L"%S", h->h_name); + freehostent(h); + } + else + h = gethostbyaddr(&a->data, a->length, af); + if (h) { + StringCbPrintf(retstr, sizeof(retstr), L"%S", h->h_name); + } +#endif + if (h) + goto _copy_string; + } + if (no_resolve || !h) { +#ifdef HAVE_INET_NTOP + char buf[46]; + const char *name = inet_ntop(a->addrtype, &a->data, buf, sizeof(buf)); + if (name) { + StringCbPrintf(retstr, sizeof(retstr), L"%S", name); + goto _copy_string; + } +#else + if (a->addrtype == ADDRTYPE_INET) { + khm_ui_4 addr = a->data; + StringCbPrintf(retstr, sizeof(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); + } + + _copy_string: + StringCbCopy(buf, cbbuf, retstr); +} + diff --git a/src/windows/identity/plugins/krb5/datarep.h b/src/windows/identity/plugins/krb5/datarep.h index 90f1923fa..d81e7b91e 100644 --- a/src/windows/identity/plugins/krb5/datarep.h +++ b/src/windows/identity/plugins/krb5/datarep.h @@ -1,76 +1,76 @@ -/* - * 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_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; - -#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 -kvno_toString(const void * data, khm_size cbdata, - wchar_t *destbuf, khm_size *pcbdestbuf, - khm_int32 flags); - -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 +/* + * 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_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; + +#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 +kvno_toString(const void * data, khm_size cbdata, + wchar_t *destbuf, khm_size *pcbdestbuf, + khm_int32 flags); + +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/errorfuncs.c b/src/windows/identity/plugins/krb5/errorfuncs.c index f631b3c0c..4c2d78c63 100644 --- a/src/windows/identity/plugins/krb5/errorfuncs.c +++ b/src/windows/identity/plugins/krb5/errorfuncs.c @@ -1,297 +1,297 @@ -/* - * 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 - -extern void (__cdecl *pinitialize_krb_error_func)(); -extern void (__cdecl *pinitialize_kadm_error_table)(); - - -khm_int32 init_error_funcs() -{ - return KHM_ERROR_SUCCESS; -} - -khm_int32 exit_error_funcs() -{ - return KHM_ERROR_SUCCESS; -} - -#ifdef DEPRECATED_REMOVABLE -HWND GetRootParent (HWND Child) -{ - HWND Last; - while (Child) - { - Last = Child; - Child = GetParent (Child); - } - return Last; -} -#endif - -void khm_err_describe(long code, wchar_t * buf, khm_size cbbuf, - DWORD * suggestion, - kherr_suggestion * suggest_code) -{ - const char * com_err_msg; - int offset; - long table_num; - DWORD msg_id = 0; - DWORD sugg_id = 0; - kherr_suggestion sugg_code = KHERR_SUGGEST_NONE; - - if (suggestion == NULL || buf == NULL || cbbuf == 0 || suggest_code == 0) - return; - - *buf = L'\0'; - - offset = (int) (code & 255); - table_num = code - offset; - com_err_msg = perror_message(code); - - *suggestion = 0; - *suggest_code = KHERR_SUGGEST_NONE; - - if (WSABASEERR <= code && code < (WSABASEERR + 1064)) { - /* winsock error */ - table_num = WSABASEERR; - offset = code - WSABASEERR; - } - - switch(table_num) - { - case krb_err_base: - case kadm_err_base: - case WSABASEERR: - break; - default: - - if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) { - *suggestion = MSG_ERR_S_INTEGRITY; - } - *suggest_code = KHERR_SUGGEST_RETRY; - AnsiStrToUnicode(buf, cbbuf, com_err_msg); - return; - } - - if (table_num == krb_err_base) { - switch(offset) { - case KDC_NAME_EXP: /* 001 Principal expired */ - case KDC_SERVICE_EXP: /* 002 Service expired */ - case KDC_AUTH_EXP: /* 003 Auth expired */ - case KDC_PKT_VER: /* 004 Protocol version unknown */ - case KDC_P_MKEY_VER: /* 005 Wrong master key version */ - case KDC_S_MKEY_VER: /* 006 Wrong master key version */ - case KDC_BYTE_ORDER: /* 007 Byte order unknown */ - case KDC_PR_N_UNIQUE: /* 009 Principal not unique */ - case KDC_NULL_KEY: /* 010 Principal has null key */ - case KDC_GEN_ERR: /* 011 Generic error from KDC */ - case INTK_W_NOTALL : /* 061 Not ALL tickets returned */ - case INTK_PROT : /* 063 Protocol Error */ - case INTK_ERR : /* 070 Other error */ - msg_id = MSG_ERR_UNKNOWN; - sugg_code = KHERR_SUGGEST_RETRY; - break; - - case KDC_PR_UNKNOWN: /* 008 Principal unknown */ - msg_id = MSG_ERR_PR_UNKNOWN; - sugg_code = KHERR_SUGGEST_RETRY; - break; - case GC_TKFIL : /* 021 Can't read ticket file */ - case GC_NOTKT : /* 022 Can't find ticket or TGT */ - msg_id = MSG_ERR_TKFIL; - sugg_id = MSG_ERR_S_TKFIL; - sugg_code = KHERR_SUGGEST_RETRY; - break; - case MK_AP_TGTEXP : /* 026 TGT Expired */ - /* no extra error msg */ - break; - - case RD_AP_TIME : /* 037 delta_t too big */ - msg_id = MSG_ERR_CLOCKSKEW; - sugg_id = MSG_ERR_S_CLOCKSKEW; - sugg_code = KHERR_SUGGEST_RETRY; - break; - - case RD_AP_UNDEC : /* 031 Can't decode - authenticator */ - case RD_AP_EXP : /* 032 Ticket expired */ - case RD_AP_NYV : /* 033 Ticket not yet valid */ - case RD_AP_REPEAT : /* 034 Repeated request */ - case RD_AP_NOT_US : /* 035 The ticket isn't for us */ - case RD_AP_INCON : /* 036 Request is inconsistent */ - case RD_AP_BADD : /* 038 Incorrect net address */ - case RD_AP_VERSION : /* 039 protocol version mismatch */ - case RD_AP_MSG_TYPE : /* 040 invalid msg type */ - case RD_AP_MODIFIED : /* 041 message stream modified */ - case RD_AP_ORDER : /* 042 message out of order */ - case RD_AP_UNAUTHOR : /* 043 unauthorized request */ - /* no extra error msg */ - sugg_code = KHERR_SUGGEST_RETRY; - break; - - case GT_PW_NULL: /* 51 Current PW is null */ - case GT_PW_BADPW: /* 52 Incorrect current password */ - case GT_PW_PROT: /* 53 Protocol Error */ - case GT_PW_KDCERR: /* 54 Error returned by KDC */ - case GT_PW_NULLTKT: /* 55 Null tkt returned by KDC */ - /* no error msg yet */ - sugg_code = KHERR_SUGGEST_RETRY; - break; - - /* Values returned by send_to_kdc */ - case SKDC_RETRY : /* 56 Retry count exceeded */ - case SKDC_CANT : /* 57 Can't send request */ - msg_id = MSG_ERR_KDC_CONTACT; - break; - /* no error message on purpose: */ - case INTK_BADPW : /* 062 Incorrect password */ - sugg_code = KHERR_SUGGEST_RETRY; - break; - default: - /* no extra error msg */ - break; - } - } else if (table_num == kadm_err_base) { - switch(code) { - case KADM_INSECURE_PW: - /* if( kadm_info != NULL ){ - * wsprintf(buf, "%s\n%s", com_err_msg, kadm_info); - * } else { - * wsprintf(buf, "%s\nPlease see the help file for information " - * "about secure passwords.", com_err_msg); - * } - * com_err_msg = buf; - */ - - /* The above code would be preferred since it allows site - * specific information to be delivered from the Kerberos - * server. However the message box is too small for VGA - * screens. It does work well if we only have to support - * 1024x768 - */ - - msg_id = MSG_ERR_INSECURE_PW; - sugg_code = KHERR_SUGGEST_RETRY; - break; - - default: - /* no extra error msg */ - break; - } - } else if (table_num == WSABASEERR) { - switch(code) { - case WSAENETDOWN: - msg_id = MSG_ERR_NETDOWN; - sugg_id = MSG_ERR_S_NETRETRY; - sugg_code = KHERR_SUGGEST_RETRY; - break; - - case WSATRY_AGAIN: - msg_id = MSG_ERR_TEMPDOWN; - sugg_id = MSG_ERR_S_TEMPDOWN; - sugg_code = KHERR_SUGGEST_RETRY; - break; - - case WSAENETUNREACH: - case WSAENETRESET: - case WSAECONNABORTED: - case WSAECONNRESET: - case WSAETIMEDOUT: - case WSAECONNREFUSED: - case WSAEHOSTDOWN: - case WSAEHOSTUNREACH: - msg_id = MSG_ERR_NOHOST; - sugg_id = MSG_ERR_S_NOHOST; - sugg_code = KHERR_SUGGEST_RETRY; - break; - } - } - - if (msg_id != 0) { - FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | - FORMAT_MESSAGE_IGNORE_INSERTS, - KHERR_HMODULE, - msg_id, - 0, - buf, - (int) (cbbuf / sizeof(buf[0])), - NULL); - } - - if (sugg_id != 0) { - *suggestion = sugg_id; - } - - if (sugg_code != KHERR_SUGGEST_NONE) - *suggest_code = sugg_code; -} - -#ifdef DEPRECATED_REMOVABLE -int lsh_com_err_proc (LPSTR whoami, long code, - LPSTR fmt, va_list args) -{ - int retval; - HWND hOldFocus; - char buf[1024], *cp; - WORD mbformat = MB_OK | MB_ICONEXCLAMATION; - - cp = buf; - memset(buf, '\0', sizeof(buf)); - cp[0] = '\0'; - - if (code) - { - err_describe(buf, code); - while (*cp) - cp++; - } - - if (fmt) - { - if (fmt[0] == '%' && fmt[1] == 'b') - { - fmt += 2; - mbformat = va_arg(args, WORD); - /* if the first arg is a %b, we use it for the message - box MB_??? flags. */ - } - if (code) - { - *cp++ = '\n'; - *cp++ = '\n'; - } - wvsprintfA((LPSTR)cp, fmt, args); - } - hOldFocus = GetFocus(); - retval = MessageBoxA(/*GetRootParent(hOldFocus)*/NULL, buf, whoami, - mbformat | MB_ICONHAND | MB_TASKMODAL); - SetFocus(hOldFocus); - return retval; -} -#endif +/* + * 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 + +extern void (__cdecl *pinitialize_krb_error_func)(); +extern void (__cdecl *pinitialize_kadm_error_table)(); + + +khm_int32 init_error_funcs() +{ + return KHM_ERROR_SUCCESS; +} + +khm_int32 exit_error_funcs() +{ + return KHM_ERROR_SUCCESS; +} + +#ifdef DEPRECATED_REMOVABLE +HWND GetRootParent (HWND Child) +{ + HWND Last; + while (Child) + { + Last = Child; + Child = GetParent (Child); + } + return Last; +} +#endif + +void khm_err_describe(long code, wchar_t * buf, khm_size cbbuf, + DWORD * suggestion, + kherr_suggestion * suggest_code) +{ + const char * com_err_msg; + int offset; + long table_num; + DWORD msg_id = 0; + DWORD sugg_id = 0; + kherr_suggestion sugg_code = KHERR_SUGGEST_NONE; + + if (suggestion == NULL || buf == NULL || cbbuf == 0 || suggest_code == 0) + return; + + *buf = L'\0'; + + offset = (int) (code & 255); + table_num = code - offset; + com_err_msg = perror_message(code); + + *suggestion = 0; + *suggest_code = KHERR_SUGGEST_NONE; + + if (WSABASEERR <= code && code < (WSABASEERR + 1064)) { + /* winsock error */ + table_num = WSABASEERR; + offset = code - WSABASEERR; + } + + switch(table_num) + { + case krb_err_base: + case kadm_err_base: + case WSABASEERR: + break; + default: + + if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) { + *suggestion = MSG_ERR_S_INTEGRITY; + } + *suggest_code = KHERR_SUGGEST_RETRY; + AnsiStrToUnicode(buf, cbbuf, com_err_msg); + return; + } + + if (table_num == krb_err_base) { + switch(offset) { + case KDC_NAME_EXP: /* 001 Principal expired */ + case KDC_SERVICE_EXP: /* 002 Service expired */ + case KDC_AUTH_EXP: /* 003 Auth expired */ + case KDC_PKT_VER: /* 004 Protocol version unknown */ + case KDC_P_MKEY_VER: /* 005 Wrong master key version */ + case KDC_S_MKEY_VER: /* 006 Wrong master key version */ + case KDC_BYTE_ORDER: /* 007 Byte order unknown */ + case KDC_PR_N_UNIQUE: /* 009 Principal not unique */ + case KDC_NULL_KEY: /* 010 Principal has null key */ + case KDC_GEN_ERR: /* 011 Generic error from KDC */ + case INTK_W_NOTALL : /* 061 Not ALL tickets returned */ + case INTK_PROT : /* 063 Protocol Error */ + case INTK_ERR : /* 070 Other error */ + msg_id = MSG_ERR_UNKNOWN; + sugg_code = KHERR_SUGGEST_RETRY; + break; + + case KDC_PR_UNKNOWN: /* 008 Principal unknown */ + msg_id = MSG_ERR_PR_UNKNOWN; + sugg_code = KHERR_SUGGEST_RETRY; + break; + case GC_TKFIL : /* 021 Can't read ticket file */ + case GC_NOTKT : /* 022 Can't find ticket or TGT */ + msg_id = MSG_ERR_TKFIL; + sugg_id = MSG_ERR_S_TKFIL; + sugg_code = KHERR_SUGGEST_RETRY; + break; + case MK_AP_TGTEXP : /* 026 TGT Expired */ + /* no extra error msg */ + break; + + case RD_AP_TIME : /* 037 delta_t too big */ + msg_id = MSG_ERR_CLOCKSKEW; + sugg_id = MSG_ERR_S_CLOCKSKEW; + sugg_code = KHERR_SUGGEST_RETRY; + break; + + case RD_AP_UNDEC : /* 031 Can't decode + authenticator */ + case RD_AP_EXP : /* 032 Ticket expired */ + case RD_AP_NYV : /* 033 Ticket not yet valid */ + case RD_AP_REPEAT : /* 034 Repeated request */ + case RD_AP_NOT_US : /* 035 The ticket isn't for us */ + case RD_AP_INCON : /* 036 Request is inconsistent */ + case RD_AP_BADD : /* 038 Incorrect net address */ + case RD_AP_VERSION : /* 039 protocol version mismatch */ + case RD_AP_MSG_TYPE : /* 040 invalid msg type */ + case RD_AP_MODIFIED : /* 041 message stream modified */ + case RD_AP_ORDER : /* 042 message out of order */ + case RD_AP_UNAUTHOR : /* 043 unauthorized request */ + /* no extra error msg */ + sugg_code = KHERR_SUGGEST_RETRY; + break; + + case GT_PW_NULL: /* 51 Current PW is null */ + case GT_PW_BADPW: /* 52 Incorrect current password */ + case GT_PW_PROT: /* 53 Protocol Error */ + case GT_PW_KDCERR: /* 54 Error returned by KDC */ + case GT_PW_NULLTKT: /* 55 Null tkt returned by KDC */ + /* no error msg yet */ + sugg_code = KHERR_SUGGEST_RETRY; + break; + + /* Values returned by send_to_kdc */ + case SKDC_RETRY : /* 56 Retry count exceeded */ + case SKDC_CANT : /* 57 Can't send request */ + msg_id = MSG_ERR_KDC_CONTACT; + break; + /* no error message on purpose: */ + case INTK_BADPW : /* 062 Incorrect password */ + sugg_code = KHERR_SUGGEST_RETRY; + break; + default: + /* no extra error msg */ + break; + } + } else if (table_num == kadm_err_base) { + switch(code) { + case KADM_INSECURE_PW: + /* if( kadm_info != NULL ){ + * wsprintf(buf, "%s\n%s", com_err_msg, kadm_info); + * } else { + * wsprintf(buf, "%s\nPlease see the help file for information " + * "about secure passwords.", com_err_msg); + * } + * com_err_msg = buf; + */ + + /* The above code would be preferred since it allows site + * specific information to be delivered from the Kerberos + * server. However the message box is too small for VGA + * screens. It does work well if we only have to support + * 1024x768 + */ + + msg_id = MSG_ERR_INSECURE_PW; + sugg_code = KHERR_SUGGEST_RETRY; + break; + + default: + /* no extra error msg */ + break; + } + } else if (table_num == WSABASEERR) { + switch(code) { + case WSAENETDOWN: + msg_id = MSG_ERR_NETDOWN; + sugg_id = MSG_ERR_S_NETRETRY; + sugg_code = KHERR_SUGGEST_RETRY; + break; + + case WSATRY_AGAIN: + msg_id = MSG_ERR_TEMPDOWN; + sugg_id = MSG_ERR_S_TEMPDOWN; + sugg_code = KHERR_SUGGEST_RETRY; + break; + + case WSAENETUNREACH: + case WSAENETRESET: + case WSAECONNABORTED: + case WSAECONNRESET: + case WSAETIMEDOUT: + case WSAECONNREFUSED: + case WSAEHOSTDOWN: + case WSAEHOSTUNREACH: + msg_id = MSG_ERR_NOHOST; + sugg_id = MSG_ERR_S_NOHOST; + sugg_code = KHERR_SUGGEST_RETRY; + break; + } + } + + if (msg_id != 0) { + FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | + FORMAT_MESSAGE_IGNORE_INSERTS, + KHERR_HMODULE, + msg_id, + 0, + buf, + (int) (cbbuf / sizeof(buf[0])), + NULL); + } + + if (sugg_id != 0) { + *suggestion = sugg_id; + } + + if (sugg_code != KHERR_SUGGEST_NONE) + *suggest_code = sugg_code; +} + +#ifdef DEPRECATED_REMOVABLE +int lsh_com_err_proc (LPSTR whoami, long code, + LPSTR fmt, va_list args) +{ + int retval; + HWND hOldFocus; + char buf[1024], *cp; + WORD mbformat = MB_OK | MB_ICONEXCLAMATION; + + cp = buf; + memset(buf, '\0', sizeof(buf)); + cp[0] = '\0'; + + if (code) + { + err_describe(buf, code); + while (*cp) + cp++; + } + + if (fmt) + { + if (fmt[0] == '%' && fmt[1] == 'b') + { + fmt += 2; + mbformat = va_arg(args, WORD); + /* if the first arg is a %b, we use it for the message + box MB_??? flags. */ + } + if (code) + { + *cp++ = '\n'; + *cp++ = '\n'; + } + wvsprintfA((LPSTR)cp, fmt, args); + } + hOldFocus = GetFocus(); + retval = MessageBoxA(/*GetRootParent(hOldFocus)*/NULL, buf, whoami, + mbformat | MB_ICONHAND | MB_TASKMODAL); + SetFocus(hOldFocus); + return retval; +} +#endif diff --git a/src/windows/identity/plugins/krb5/errorfuncs.h b/src/windows/identity/plugins/krb5/errorfuncs.h index 86fc5b440..4b1d2e2b5 100644 --- a/src/windows/identity/plugins/krb5/errorfuncs.h +++ b/src/windows/identity/plugins/krb5/errorfuncs.h @@ -1,75 +1,75 @@ -/* - * 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_ERR_H -#define __KHIMAIRA_ERR_H - -/* All error handling and reporting related functions for the krb4/5 - and AFS plugins */ - -#include -#include -/* - * This is a hack needed because the real com_err.h does - * not define err_func. We need it in the case where - * we pull in the real com_err instead of the krb4 - * impostor. - */ -#ifndef _DCNS_MIT_COM_ERR_H -typedef LPSTR (*err_func)(int, long); -#endif - -#include -#include - -#define kadm_err_base ERROR_TABLE_BASE_kadm - -#include - -#ifndef KRBERR -#define KRBERR(code) (code + krb_err_base) -#endif - -/*! \internal - \brief Describe an error - - \param[in] code Error code returned by Kerberos - \param[out] buf Receives the error string - \param[in] cbbuf Size of buffer pointed to by \a buf - \param[out] suggestion Message ID of suggestion - \param[out] suggest_code Suggestion ID -*/ -void khm_err_describe(long code, wchar_t * buf, khm_size cbbuf, - DWORD * suggestion, - kherr_suggestion * suggest_code); - -/* */ -khm_int32 init_error_funcs(); - -khm_int32 exit_error_funcs(); - - -#endif +/* + * 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_ERR_H +#define __KHIMAIRA_ERR_H + +/* All error handling and reporting related functions for the krb4/5 + and AFS plugins */ + +#include +#include +/* + * This is a hack needed because the real com_err.h does + * not define err_func. We need it in the case where + * we pull in the real com_err instead of the krb4 + * impostor. + */ +#ifndef _DCNS_MIT_COM_ERR_H +typedef LPSTR (*err_func)(int, long); +#endif + +#include +#include + +#define kadm_err_base ERROR_TABLE_BASE_kadm + +#include + +#ifndef KRBERR +#define KRBERR(code) (code + krb_err_base) +#endif + +/*! \internal + \brief Describe an error + + \param[in] code Error code returned by Kerberos + \param[out] buf Receives the error string + \param[in] cbbuf Size of buffer pointed to by \a buf + \param[out] suggestion Message ID of suggestion + \param[out] suggest_code Suggestion ID +*/ +void khm_err_describe(long code, wchar_t * buf, khm_size cbbuf, + DWORD * suggestion, + kherr_suggestion * suggest_code); + +/* */ +khm_int32 init_error_funcs(); + +khm_int32 exit_error_funcs(); + + +#endif diff --git a/src/windows/identity/plugins/krb5/krb5configcc.c b/src/windows/identity/plugins/krb5/krb5configcc.c index 5edc02b1f..b2b498e68 100644 --- a/src/windows/identity/plugins/krb5/krb5configcc.c +++ b/src/windows/identity/plugins/krb5/krb5configcc.c @@ -1,571 +1,571 @@ -/* - * 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$ */ - -#if _WIN32_WINNT < 0x501 -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x501 -#endif - -#include -#include -#include -#include -#include -#include - -#include - -typedef struct tag_k5_file_cc { - wchar_t path[MAX_PATH]; - khm_int32 flags; -} k5_file_cc; - -#define K5_FCC_ALLOC_INCR 8 - -#define K5_FCC_FLAG_EXISTS 1 - -typedef struct tag_k5_ccc_data { - khm_boolean inc_api; - khm_boolean inc_mslsa; - k5_file_cc * file_ccs; - khm_size n_file_ccs; - khm_size nc_file_ccs; -} k5_ccc_data; - -typedef struct tag_k5_ccc_dlg_data { - khui_config_node node; - k5_ccc_data save; - k5_ccc_data work; -} k5_ccc_dlg_data; - -void k5_free_file_ccs(k5_ccc_data * d) { - if (d->file_ccs) - PFREE(d->file_ccs); - d->n_file_ccs = 0; - d->nc_file_ccs = 0; -} - -void k5_flush_file_ccs(k5_ccc_data * d) { - d->n_file_ccs = 0; -} - -void k5_del_file_cc(k5_ccc_data * d, khm_size idx) { - if (idx > d->n_file_ccs) - return; - - if (idx < d->n_file_ccs - 1) { - MoveMemory(&d->file_ccs[idx], - &d->file_ccs[idx + 1], - sizeof(d->file_ccs[0]) * (d->n_file_ccs - (idx + 1))); - } - - d->n_file_ccs--; -} - -void k5_add_file_cc(k5_ccc_data * d, wchar_t * path) { - khm_size i; - khm_size cch; - - if (FAILED(StringCchLength(path, MAX_PATH, &cch)) || - cch == 0) - return; - - /* see if it's there first */ - for (i=0; i < d->n_file_ccs; i++) { - if(!_wcsicmp(d->file_ccs[i].path, path)) - return; - } - - if (d->n_file_ccs == d->nc_file_ccs) { - k5_file_cc * f; - - d->nc_file_ccs = UBOUNDSS(d->n_file_ccs + 1, - K5_FCC_ALLOC_INCR, - K5_FCC_ALLOC_INCR); -#ifdef DEBUG - assert(d->nc_file_ccs > d->n_file_ccs); -#endif - f = PMALLOC(sizeof(*f) * d->nc_file_ccs); - ZeroMemory(f, sizeof(*f) * d->nc_file_ccs); - - if (d->n_file_ccs > 0) { -#ifdef DEBUG - assert(d->file_ccs != NULL); -#endif - memcpy(f, d->file_ccs, sizeof(*f) * d->n_file_ccs); - } - if (d->file_ccs) - PFREE(d->file_ccs); - d->file_ccs = f; - } - - StringCbCopy(d->file_ccs[d->n_file_ccs].path, - sizeof(d->file_ccs[0].path), - path); - if(PathFileExists(path)) - d->file_ccs[d->n_file_ccs].flags = K5_FCC_FLAG_EXISTS; - else - d->file_ccs[d->n_file_ccs].flags = 0; - - d->n_file_ccs++; -} - -void k5_read_file_cc_data(k5_ccc_data * d) { - khm_int32 t; - wchar_t * fclist = NULL; - wchar_t * fc; - khm_size cb; - -#ifdef DEBUG - assert(csp_params); -#endif - - d->inc_api = TRUE; - t = TRUE; - khc_read_int32(csp_params, L"MsLsaList", &t); - d->inc_mslsa = t; - - if (khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb) - != KHM_ERROR_TOO_LONG || - cb <= sizeof(wchar_t) * 2) { - - k5_flush_file_ccs(d); - } else { - fclist = PMALLOC(cb); -#ifdef DEBUG - assert(fclist); -#endif - khc_read_multi_string(csp_params, L"FileCCList", fclist, &cb); - - for(fc = fclist; fc && *fc; fc = multi_string_next(fc)) { - k5_add_file_cc(d, fc); - } - - PFREE(fclist); - } -} - -void k5_write_file_cc_data(k5_ccc_data * d) { - wchar_t * ms; - khm_size cb; - khm_size cbt; - khm_int32 t; - khm_size i; - -#ifdef DEBUG - assert(csp_params); -#endif - if (KHM_FAILED(khc_read_int32(csp_params, L"MsLsaList", &t)) || - !!t != !!d->inc_mslsa) { - khc_write_int32(csp_params, L"MsLsaList", !!d->inc_mslsa); - } - - if (d->n_file_ccs > 0) { - cb = d->n_file_ccs * MAX_PATH * sizeof(wchar_t); - ms = PMALLOC(cb); -#ifdef DEBUG - assert(ms); -#endif - multi_string_init(ms, cb); - - for(i=0; in_file_ccs; i++) { - cbt = cb; - multi_string_append(ms, &cbt, d->file_ccs[i].path); - } - - khc_write_multi_string(csp_params, L"FileCCList", ms); - - PFREE(ms); - } else { - if (khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb) - != KHM_ERROR_TOO_LONG || - cb != sizeof(wchar_t) * 2) - - khc_write_multi_string(csp_params, L"FileCCList", L"\0\0"); - } -} - -void k5_copy_file_cc_data(k5_ccc_data * dest, const k5_ccc_data * src) { - khm_size i; - - k5_flush_file_ccs(dest); - dest->inc_mslsa = src->inc_mslsa; - dest->inc_api = src->inc_api; - - for (i=0; i < src->n_file_ccs; i++) { - k5_add_file_cc(dest, src->file_ccs[i].path); - } -} - -BOOL k5_ccc_get_mod(k5_ccc_dlg_data * d) { - khm_size i, j; - - if (!!d->work.inc_mslsa != !!d->save.inc_mslsa || - !!d->work.inc_api != !!d->save.inc_api || - d->work.n_file_ccs != d->save.n_file_ccs) - return TRUE; - - for (i=0; i < d->work.n_file_ccs; i++) { - for (j=0; j < d->save.n_file_ccs; j++) { - if (!_wcsicmp(d->work.file_ccs[i].path, - d->save.file_ccs[j].path)) - break; - } - if (j >= d->save.n_file_ccs) - return TRUE; - } - - return FALSE; -} - -void k5_ccc_update_ui(HWND hwnd, k5_ccc_dlg_data * d) { - khm_size i; - HWND lv; - - if (d->work.inc_api) - CheckDlgButton(hwnd, IDC_CFG_INCAPI, BST_CHECKED); - else - CheckDlgButton(hwnd, IDC_CFG_INCAPI, BST_UNCHECKED); - if (d->work.inc_mslsa) - CheckDlgButton(hwnd, IDC_CFG_INCMSLSA, BST_CHECKED); - else - CheckDlgButton(hwnd, IDC_CFG_INCMSLSA, BST_UNCHECKED); - - lv = GetDlgItem(hwnd, IDC_CFG_FCLIST); -#ifdef DEBUG - assert(lv); -#endif - ListView_DeleteAllItems(lv); - - for (i=0; iwork.n_file_ccs; i++) { - LVITEM lvi; - - ZeroMemory(&lvi, sizeof(lvi)); - - lvi.mask = LVIF_PARAM | LVIF_TEXT; - lvi.lParam = (LPARAM) i; - lvi.pszText = d->work.file_ccs[i].path; - - ListView_InsertItem(lv, &lvi); - } - - if (k5_ccc_get_mod(d)) { - khui_cfg_set_flags(d->node, - KHUI_CNFLAG_MODIFIED, - KHUI_CNFLAG_MODIFIED); - } else { - khui_cfg_set_flags(d->node, - 0, - KHUI_CNFLAG_MODIFIED); - } -} - -void k5_ccc_update_data(HWND hwnd, k5_ccc_data * d) { - if (IsDlgButtonChecked(hwnd, IDC_CFG_INCAPI) == BST_CHECKED) - d->inc_api = TRUE; - else - d->inc_api = FALSE; - - if (IsDlgButtonChecked(hwnd, IDC_CFG_INCMSLSA) == BST_CHECKED) - d->inc_mslsa = TRUE; - else - d->inc_mslsa = FALSE; - /* everything else is controlled by buttons */ -} - -INT_PTR CALLBACK -k5_ccconfig_dlgproc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - - k5_ccc_dlg_data * d; - - switch(uMsg) { - case WM_INITDIALOG: - d = PMALLOC(sizeof(*d)); -#ifdef DEBUG - assert(d); -#endif - ZeroMemory(d, sizeof(*d)); - k5_read_file_cc_data(&d->save); - k5_copy_file_cc_data(&d->work, &d->save); - - d->node = (khui_config_node) lParam; - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); -#pragma warning(pop) - - { - LVCOLUMN lvc; - HWND lv; - wchar_t buf[256]; - RECT r; - - lv = GetDlgItem(hwnd, IDC_CFG_FCLIST); -#ifdef DEBUG - assert(lv); -#endif - ZeroMemory(&lvc, sizeof(lvc)); - lvc.mask = LVCF_TEXT | LVCF_WIDTH; - - LoadString(hResModule, IDS_CFG_FCTITLE, - buf, ARRAYLENGTH(buf)); - - GetWindowRect(lv, &r); - - lvc.pszText = buf; - lvc.cx = (r.right - r.left) * 9 / 10; - - ListView_InsertColumn(lv, 0, &lvc); - } - - SendDlgItemMessage(hwnd, IDC_CFG_FCNAME, EM_SETLIMITTEXT, - MAX_PATH - 1, 0); - - k5_ccc_update_ui(hwnd, d); - break; - - case WM_COMMAND: - d = (k5_ccc_dlg_data *) (DWORD_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - switch(wParam) { - case MAKEWPARAM(IDC_CFG_ADD, BN_CLICKED): - { - wchar_t path[MAX_PATH]; - wchar_t cpath[MAX_PATH]; - khm_size i; - - GetDlgItemText(hwnd, IDC_CFG_FCNAME, - cpath, ARRAYLENGTH(cpath)); - - PathCanonicalize(path, cpath); - - if (!*path) - return TRUE; /* nothing to add */ - - for (i=0; i < d->work.n_file_ccs; i++) { - if (!_wcsicmp(path, d->work.file_ccs[i].path)) { - - /* allow the user to correct case, as appropriate */ - StringCbCopy(d->work.file_ccs[i].path, - sizeof(d->work.file_ccs[i].path), - path); - k5_ccc_update_ui(hwnd, d); - return TRUE; - } - } - - /* not there. we need to add. but check a few things - first */ - if (!PathFileExists(path)) { - wchar_t title[64]; - wchar_t text[128]; - - LoadString(hResModule, IDS_CFG_FCN_WARNING, - title, ARRAYLENGTH(title)); - - LoadString(hResModule, IDS_CFG_FCN_W_NOTFOUND, - text, ARRAYLENGTH(text)); -#if _WIN32_WINNT >= 0x501 - if (IS_COMMCTL6()) - { - EDITBALLOONTIP bt; - - bt.cbStruct = sizeof(bt); - bt.pszTitle = title; - bt.pszText = text; - bt.ttiIcon = TTI_WARNING; - - SendDlgItemMessage(hwnd, IDC_CFG_FCNAME, - EM_SHOWBALLOONTIP, - 0, - (LPARAM) &bt); - } else { -#endif - MessageBox(hwnd, text, title, MB_OK | MB_ICONWARNING); -#if _WIN32_WINNT >= 0x501 - } -#endif - } else if (PathIsRelative(path)) { - wchar_t title[64]; - wchar_t text[128]; - - LoadString(hResModule, IDS_CFG_FCN_WARNING, - title, ARRAYLENGTH(title)); - LoadString(hResModule, IDS_CFG_FCN_W_RELATIVE, - text, ARRAYLENGTH(text)); - -#if _WIN32_WINNT >= 0x501 - if (IS_COMMCTL6()) - { - EDITBALLOONTIP bt; - - bt.cbStruct = sizeof(bt); - bt.pszTitle = title; - bt.pszText = text; - bt.ttiIcon = TTI_WARNING; - - SendDlgItemMessage(hwnd, IDC_CFG_FCNAME, - EM_SHOWBALLOONTIP, - 0, - (LPARAM) &bt); - } else { -#endif - MessageBox(hwnd, text, title, MB_OK | MB_ICONWARNING); -#if _WIN32_WINNT >= 0x501 - } -#endif - } - - k5_add_file_cc(&d->work, path); - - k5_ccc_update_ui(hwnd, d); - } - return TRUE; - - case MAKEWPARAM(IDC_CFG_BROWSE, BN_CLICKED): - { - OPENFILENAME ofn; - wchar_t path[MAX_PATH * 8]; - wchar_t title[128]; - - ZeroMemory(&ofn, sizeof(ofn)); - ZeroMemory(path, sizeof(path)); - - GetDlgItemText(hwnd, IDC_CFG_FCNAME, - path, ARRAYLENGTH(path)); - - /* don't pass in invalid paths */ - if (!PathFileExists(path)) - *path = 0; - - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = hwnd; - ofn.lpstrFilter = L"All files\0*.*\0\0"; - ofn.nFilterIndex = 1; - ofn.lpstrFile = path; - ofn.nMaxFile = ARRAYLENGTH(path); - ofn.lpstrTitle = title; - - LoadString(hResModule, IDS_CFG_FCOPENTITLE, - title, ARRAYLENGTH(title)); - - ofn.Flags = OFN_ALLOWMULTISELECT | - OFN_DONTADDTORECENT | - OFN_FORCESHOWHIDDEN | - OFN_EXPLORER; - - if (GetOpenFileName(&ofn)) { - wchar_t * p; - wchar_t spath[MAX_PATH]; - - p = multi_string_next(path); - if (p) { - /* multi select */ - for(;p && *p; p = multi_string_next(p)) { - StringCbCopy(spath, sizeof(spath), path); - PathAppend(spath, p); - - k5_add_file_cc(&d->work, spath); - } - } else { - /* single select */ - k5_add_file_cc(&d->work, path); - } - k5_ccc_update_ui(hwnd, d); - } - } - return TRUE; - - case MAKEWPARAM(IDC_CFG_REMOVE, BN_CLICKED): - { - khm_size i; - int lv_idx; - HWND lv; - wchar_t buf[MAX_PATH]; - - lv = GetDlgItem(hwnd, IDC_CFG_FCLIST); -#ifdef DEBUG - assert(lv); -#endif - - lv_idx = -1; - while((lv_idx = ListView_GetNextItem(lv, lv_idx, - LVNI_SELECTED)) != -1) { - ListView_GetItemText(lv, lv_idx, 0, buf, ARRAYLENGTH(buf)); - for (i=0; i < d->work.n_file_ccs; i++) { - if (!_wcsicmp(buf, d->work.file_ccs[i].path)) { - k5_del_file_cc(&d->work, i); - break; - } - } - } - - k5_ccc_update_ui(hwnd, d); - } - return TRUE; - - case MAKEWPARAM(IDC_CFG_INCAPI, BN_CLICKED): - case MAKEWPARAM(IDC_CFG_INCMSLSA, BN_CLICKED): - k5_ccc_update_data(hwnd, &d->work); - k5_ccc_update_ui(hwnd, d); - return TRUE; - } - break; - - case WM_DESTROY: - d = (k5_ccc_dlg_data *) (DWORD_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - k5_free_file_ccs(&d->work); - k5_free_file_ccs(&d->save); - PFREE(d); - return TRUE; - - case KHUI_WM_CFG_NOTIFY: - d = (k5_ccc_dlg_data *) (DWORD_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - switch(HIWORD(wParam)) { - case WMCFG_APPLY: - if (k5_ccc_get_mod(d)) { - k5_write_file_cc_data(&d->work); - k5_copy_file_cc_data(&d->save, &d->work); - khui_cfg_set_flags(d->node, - KHUI_CNFLAG_APPLIED, - KHUI_CNFLAG_APPLIED); - k5_ccc_update_ui(hwnd, d); - - kmq_post_sub_msg(k5_sub, KMSG_CRED, KMSG_CRED_REFRESH, 0, 0); - } - break; - } - } - return FALSE; -} +/* + * 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$ */ + +#if _WIN32_WINNT < 0x501 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x501 +#endif + +#include +#include +#include +#include +#include +#include + +#include + +typedef struct tag_k5_file_cc { + wchar_t path[MAX_PATH]; + khm_int32 flags; +} k5_file_cc; + +#define K5_FCC_ALLOC_INCR 8 + +#define K5_FCC_FLAG_EXISTS 1 + +typedef struct tag_k5_ccc_data { + khm_boolean inc_api; + khm_boolean inc_mslsa; + k5_file_cc * file_ccs; + khm_size n_file_ccs; + khm_size nc_file_ccs; +} k5_ccc_data; + +typedef struct tag_k5_ccc_dlg_data { + khui_config_node node; + k5_ccc_data save; + k5_ccc_data work; +} k5_ccc_dlg_data; + +void k5_free_file_ccs(k5_ccc_data * d) { + if (d->file_ccs) + PFREE(d->file_ccs); + d->n_file_ccs = 0; + d->nc_file_ccs = 0; +} + +void k5_flush_file_ccs(k5_ccc_data * d) { + d->n_file_ccs = 0; +} + +void k5_del_file_cc(k5_ccc_data * d, khm_size idx) { + if (idx > d->n_file_ccs) + return; + + if (idx < d->n_file_ccs - 1) { + MoveMemory(&d->file_ccs[idx], + &d->file_ccs[idx + 1], + sizeof(d->file_ccs[0]) * (d->n_file_ccs - (idx + 1))); + } + + d->n_file_ccs--; +} + +void k5_add_file_cc(k5_ccc_data * d, wchar_t * path) { + khm_size i; + khm_size cch; + + if (FAILED(StringCchLength(path, MAX_PATH, &cch)) || + cch == 0) + return; + + /* see if it's there first */ + for (i=0; i < d->n_file_ccs; i++) { + if(!_wcsicmp(d->file_ccs[i].path, path)) + return; + } + + if (d->n_file_ccs == d->nc_file_ccs) { + k5_file_cc * f; + + d->nc_file_ccs = UBOUNDSS(d->n_file_ccs + 1, + K5_FCC_ALLOC_INCR, + K5_FCC_ALLOC_INCR); +#ifdef DEBUG + assert(d->nc_file_ccs > d->n_file_ccs); +#endif + f = PMALLOC(sizeof(*f) * d->nc_file_ccs); + ZeroMemory(f, sizeof(*f) * d->nc_file_ccs); + + if (d->n_file_ccs > 0) { +#ifdef DEBUG + assert(d->file_ccs != NULL); +#endif + memcpy(f, d->file_ccs, sizeof(*f) * d->n_file_ccs); + } + if (d->file_ccs) + PFREE(d->file_ccs); + d->file_ccs = f; + } + + StringCbCopy(d->file_ccs[d->n_file_ccs].path, + sizeof(d->file_ccs[0].path), + path); + if(PathFileExists(path)) + d->file_ccs[d->n_file_ccs].flags = K5_FCC_FLAG_EXISTS; + else + d->file_ccs[d->n_file_ccs].flags = 0; + + d->n_file_ccs++; +} + +void k5_read_file_cc_data(k5_ccc_data * d) { + khm_int32 t; + wchar_t * fclist = NULL; + wchar_t * fc; + khm_size cb; + +#ifdef DEBUG + assert(csp_params); +#endif + + d->inc_api = TRUE; + t = TRUE; + khc_read_int32(csp_params, L"MsLsaList", &t); + d->inc_mslsa = t; + + if (khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb) + != KHM_ERROR_TOO_LONG || + cb <= sizeof(wchar_t) * 2) { + + k5_flush_file_ccs(d); + } else { + fclist = PMALLOC(cb); +#ifdef DEBUG + assert(fclist); +#endif + khc_read_multi_string(csp_params, L"FileCCList", fclist, &cb); + + for(fc = fclist; fc && *fc; fc = multi_string_next(fc)) { + k5_add_file_cc(d, fc); + } + + PFREE(fclist); + } +} + +void k5_write_file_cc_data(k5_ccc_data * d) { + wchar_t * ms; + khm_size cb; + khm_size cbt; + khm_int32 t; + khm_size i; + +#ifdef DEBUG + assert(csp_params); +#endif + if (KHM_FAILED(khc_read_int32(csp_params, L"MsLsaList", &t)) || + !!t != !!d->inc_mslsa) { + khc_write_int32(csp_params, L"MsLsaList", !!d->inc_mslsa); + } + + if (d->n_file_ccs > 0) { + cb = d->n_file_ccs * MAX_PATH * sizeof(wchar_t); + ms = PMALLOC(cb); +#ifdef DEBUG + assert(ms); +#endif + multi_string_init(ms, cb); + + for(i=0; in_file_ccs; i++) { + cbt = cb; + multi_string_append(ms, &cbt, d->file_ccs[i].path); + } + + khc_write_multi_string(csp_params, L"FileCCList", ms); + + PFREE(ms); + } else { + if (khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb) + != KHM_ERROR_TOO_LONG || + cb != sizeof(wchar_t) * 2) + + khc_write_multi_string(csp_params, L"FileCCList", L"\0\0"); + } +} + +void k5_copy_file_cc_data(k5_ccc_data * dest, const k5_ccc_data * src) { + khm_size i; + + k5_flush_file_ccs(dest); + dest->inc_mslsa = src->inc_mslsa; + dest->inc_api = src->inc_api; + + for (i=0; i < src->n_file_ccs; i++) { + k5_add_file_cc(dest, src->file_ccs[i].path); + } +} + +BOOL k5_ccc_get_mod(k5_ccc_dlg_data * d) { + khm_size i, j; + + if (!!d->work.inc_mslsa != !!d->save.inc_mslsa || + !!d->work.inc_api != !!d->save.inc_api || + d->work.n_file_ccs != d->save.n_file_ccs) + return TRUE; + + for (i=0; i < d->work.n_file_ccs; i++) { + for (j=0; j < d->save.n_file_ccs; j++) { + if (!_wcsicmp(d->work.file_ccs[i].path, + d->save.file_ccs[j].path)) + break; + } + if (j >= d->save.n_file_ccs) + return TRUE; + } + + return FALSE; +} + +void k5_ccc_update_ui(HWND hwnd, k5_ccc_dlg_data * d) { + khm_size i; + HWND lv; + + if (d->work.inc_api) + CheckDlgButton(hwnd, IDC_CFG_INCAPI, BST_CHECKED); + else + CheckDlgButton(hwnd, IDC_CFG_INCAPI, BST_UNCHECKED); + if (d->work.inc_mslsa) + CheckDlgButton(hwnd, IDC_CFG_INCMSLSA, BST_CHECKED); + else + CheckDlgButton(hwnd, IDC_CFG_INCMSLSA, BST_UNCHECKED); + + lv = GetDlgItem(hwnd, IDC_CFG_FCLIST); +#ifdef DEBUG + assert(lv); +#endif + ListView_DeleteAllItems(lv); + + for (i=0; iwork.n_file_ccs; i++) { + LVITEM lvi; + + ZeroMemory(&lvi, sizeof(lvi)); + + lvi.mask = LVIF_PARAM | LVIF_TEXT; + lvi.lParam = (LPARAM) i; + lvi.pszText = d->work.file_ccs[i].path; + + ListView_InsertItem(lv, &lvi); + } + + if (k5_ccc_get_mod(d)) { + khui_cfg_set_flags(d->node, + KHUI_CNFLAG_MODIFIED, + KHUI_CNFLAG_MODIFIED); + } else { + khui_cfg_set_flags(d->node, + 0, + KHUI_CNFLAG_MODIFIED); + } +} + +void k5_ccc_update_data(HWND hwnd, k5_ccc_data * d) { + if (IsDlgButtonChecked(hwnd, IDC_CFG_INCAPI) == BST_CHECKED) + d->inc_api = TRUE; + else + d->inc_api = FALSE; + + if (IsDlgButtonChecked(hwnd, IDC_CFG_INCMSLSA) == BST_CHECKED) + d->inc_mslsa = TRUE; + else + d->inc_mslsa = FALSE; + /* everything else is controlled by buttons */ +} + +INT_PTR CALLBACK +k5_ccconfig_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + k5_ccc_dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + d = PMALLOC(sizeof(*d)); +#ifdef DEBUG + assert(d); +#endif + ZeroMemory(d, sizeof(*d)); + k5_read_file_cc_data(&d->save); + k5_copy_file_cc_data(&d->work, &d->save); + + d->node = (khui_config_node) lParam; + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + { + LVCOLUMN lvc; + HWND lv; + wchar_t buf[256]; + RECT r; + + lv = GetDlgItem(hwnd, IDC_CFG_FCLIST); +#ifdef DEBUG + assert(lv); +#endif + ZeroMemory(&lvc, sizeof(lvc)); + lvc.mask = LVCF_TEXT | LVCF_WIDTH; + + LoadString(hResModule, IDS_CFG_FCTITLE, + buf, ARRAYLENGTH(buf)); + + GetWindowRect(lv, &r); + + lvc.pszText = buf; + lvc.cx = (r.right - r.left) * 9 / 10; + + ListView_InsertColumn(lv, 0, &lvc); + } + + SendDlgItemMessage(hwnd, IDC_CFG_FCNAME, EM_SETLIMITTEXT, + MAX_PATH - 1, 0); + + k5_ccc_update_ui(hwnd, d); + break; + + case WM_COMMAND: + d = (k5_ccc_dlg_data *) (DWORD_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + switch(wParam) { + case MAKEWPARAM(IDC_CFG_ADD, BN_CLICKED): + { + wchar_t path[MAX_PATH]; + wchar_t cpath[MAX_PATH]; + khm_size i; + + GetDlgItemText(hwnd, IDC_CFG_FCNAME, + cpath, ARRAYLENGTH(cpath)); + + PathCanonicalize(path, cpath); + + if (!*path) + return TRUE; /* nothing to add */ + + for (i=0; i < d->work.n_file_ccs; i++) { + if (!_wcsicmp(path, d->work.file_ccs[i].path)) { + + /* allow the user to correct case, as appropriate */ + StringCbCopy(d->work.file_ccs[i].path, + sizeof(d->work.file_ccs[i].path), + path); + k5_ccc_update_ui(hwnd, d); + return TRUE; + } + } + + /* not there. we need to add. but check a few things + first */ + if (!PathFileExists(path)) { + wchar_t title[64]; + wchar_t text[128]; + + LoadString(hResModule, IDS_CFG_FCN_WARNING, + title, ARRAYLENGTH(title)); + + LoadString(hResModule, IDS_CFG_FCN_W_NOTFOUND, + text, ARRAYLENGTH(text)); +#if _WIN32_WINNT >= 0x501 + if (IS_COMMCTL6()) + { + EDITBALLOONTIP bt; + + bt.cbStruct = sizeof(bt); + bt.pszTitle = title; + bt.pszText = text; + bt.ttiIcon = TTI_WARNING; + + SendDlgItemMessage(hwnd, IDC_CFG_FCNAME, + EM_SHOWBALLOONTIP, + 0, + (LPARAM) &bt); + } else { +#endif + MessageBox(hwnd, text, title, MB_OK | MB_ICONWARNING); +#if _WIN32_WINNT >= 0x501 + } +#endif + } else if (PathIsRelative(path)) { + wchar_t title[64]; + wchar_t text[128]; + + LoadString(hResModule, IDS_CFG_FCN_WARNING, + title, ARRAYLENGTH(title)); + LoadString(hResModule, IDS_CFG_FCN_W_RELATIVE, + text, ARRAYLENGTH(text)); + +#if _WIN32_WINNT >= 0x501 + if (IS_COMMCTL6()) + { + EDITBALLOONTIP bt; + + bt.cbStruct = sizeof(bt); + bt.pszTitle = title; + bt.pszText = text; + bt.ttiIcon = TTI_WARNING; + + SendDlgItemMessage(hwnd, IDC_CFG_FCNAME, + EM_SHOWBALLOONTIP, + 0, + (LPARAM) &bt); + } else { +#endif + MessageBox(hwnd, text, title, MB_OK | MB_ICONWARNING); +#if _WIN32_WINNT >= 0x501 + } +#endif + } + + k5_add_file_cc(&d->work, path); + + k5_ccc_update_ui(hwnd, d); + } + return TRUE; + + case MAKEWPARAM(IDC_CFG_BROWSE, BN_CLICKED): + { + OPENFILENAME ofn; + wchar_t path[MAX_PATH * 8]; + wchar_t title[128]; + + ZeroMemory(&ofn, sizeof(ofn)); + ZeroMemory(path, sizeof(path)); + + GetDlgItemText(hwnd, IDC_CFG_FCNAME, + path, ARRAYLENGTH(path)); + + /* don't pass in invalid paths */ + if (!PathFileExists(path)) + *path = 0; + + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFilter = L"All files\0*.*\0\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFile = path; + ofn.nMaxFile = ARRAYLENGTH(path); + ofn.lpstrTitle = title; + + LoadString(hResModule, IDS_CFG_FCOPENTITLE, + title, ARRAYLENGTH(title)); + + ofn.Flags = OFN_ALLOWMULTISELECT | + OFN_DONTADDTORECENT | + OFN_FORCESHOWHIDDEN | + OFN_EXPLORER; + + if (GetOpenFileName(&ofn)) { + wchar_t * p; + wchar_t spath[MAX_PATH]; + + p = multi_string_next(path); + if (p) { + /* multi select */ + for(;p && *p; p = multi_string_next(p)) { + StringCbCopy(spath, sizeof(spath), path); + PathAppend(spath, p); + + k5_add_file_cc(&d->work, spath); + } + } else { + /* single select */ + k5_add_file_cc(&d->work, path); + } + k5_ccc_update_ui(hwnd, d); + } + } + return TRUE; + + case MAKEWPARAM(IDC_CFG_REMOVE, BN_CLICKED): + { + khm_size i; + int lv_idx; + HWND lv; + wchar_t buf[MAX_PATH]; + + lv = GetDlgItem(hwnd, IDC_CFG_FCLIST); +#ifdef DEBUG + assert(lv); +#endif + + lv_idx = -1; + while((lv_idx = ListView_GetNextItem(lv, lv_idx, + LVNI_SELECTED)) != -1) { + ListView_GetItemText(lv, lv_idx, 0, buf, ARRAYLENGTH(buf)); + for (i=0; i < d->work.n_file_ccs; i++) { + if (!_wcsicmp(buf, d->work.file_ccs[i].path)) { + k5_del_file_cc(&d->work, i); + break; + } + } + } + + k5_ccc_update_ui(hwnd, d); + } + return TRUE; + + case MAKEWPARAM(IDC_CFG_INCAPI, BN_CLICKED): + case MAKEWPARAM(IDC_CFG_INCMSLSA, BN_CLICKED): + k5_ccc_update_data(hwnd, &d->work); + k5_ccc_update_ui(hwnd, d); + return TRUE; + } + break; + + case WM_DESTROY: + d = (k5_ccc_dlg_data *) (DWORD_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + k5_free_file_ccs(&d->work); + k5_free_file_ccs(&d->save); + PFREE(d); + return TRUE; + + case KHUI_WM_CFG_NOTIFY: + d = (k5_ccc_dlg_data *) (DWORD_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + switch(HIWORD(wParam)) { + case WMCFG_APPLY: + if (k5_ccc_get_mod(d)) { + k5_write_file_cc_data(&d->work); + k5_copy_file_cc_data(&d->save, &d->work); + khui_cfg_set_flags(d->node, + KHUI_CNFLAG_APPLIED, + KHUI_CNFLAG_APPLIED); + k5_ccc_update_ui(hwnd, d); + + kmq_post_sub_msg(k5_sub, KMSG_CRED, KMSG_CRED_REFRESH, 0, 0); + } + break; + } + } + return FALSE; +} diff --git a/src/windows/identity/plugins/krb5/krb5configid.c b/src/windows/identity/plugins/krb5/krb5configid.c index e09281906..b5af1c2b2 100644 --- a/src/windows/identity/plugins/krb5/krb5configid.c +++ b/src/windows/identity/plugins/krb5/krb5configid.c @@ -1,355 +1,355 @@ -/* - * 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 -#include - -#include - -typedef struct tag_k5_id_dlg_data { - khui_config_init_data cfg; - - khm_handle ident; - - khui_tracker tc_life; - khui_tracker tc_renew; - - 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; - -static void -k5_id_read_params(k5_id_dlg_data * d) { - - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - khm_int32 rv; - khm_int32 t; - khm_handle csp_ident; - khm_handle csp_idroot = NULL; - - cb = sizeof(idname); - rv = khui_cfg_get_name(d->cfg.ctx_node, idname, &cb); -#ifdef DEBUG - assert(KHM_SUCCEEDED(rv)); -#endif - - rv = kcdb_identity_create(idname, 0, &d->ident); -#ifdef DEBUG - assert(KHM_SUCCEEDED(rv)); -#endif - - rv = kcdb_identity_get_config(d->ident, 0, &csp_idroot); - if (KHM_SUCCEEDED(rv) && - KHM_SUCCEEDED(khc_open_space(csp_idroot, CSNAME_KRB5CRED, 0, - &csp_ident))) { - khc_shadow_space(csp_ident, csp_params); - } else { - csp_ident = csp_params; - } - - if (csp_idroot) - khc_close_space(csp_idroot); - - rv = khc_read_int32(csp_ident, L"DefaultLifetime", &t); - if (KHM_SUCCEEDED(rv)) - d->life = t; - else - d->life = 36000; - - rv = khc_read_int32(csp_ident, L"DefaultRenewLifetime", &t); - if (KHM_SUCCEEDED(rv)) - d->renew_life = t; - 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)) { - cb = sizeof(d->ccache); - if (KHM_FAILED(kcdb_identity_get_attr(d->ident, attr_id_krb5_ccname, - NULL, d->ccache, &cb))) - ZeroMemory(d->ccache, sizeof(d->ccache)); - } - - khui_tracker_initialize(&d->tc_life); - d->tc_life.current = d->life; - d->tc_life.min = 0; - d->tc_life.max = 3600 * 24 * 7; - - khui_tracker_initialize(&d->tc_renew); - d->tc_renew.current = d->renew_life; - d->tc_renew.min = 0; - d->tc_renew.max = 3600 * 24 * 30; - - if (csp_ident != csp_params) - khc_close_space(csp_ident); -} - -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 || - - (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; -} - -static void -k5_id_check_mod(HWND hw, k5_id_dlg_data * d) { - BOOL modified = k5_id_is_mod(hw, d); - - khui_cfg_set_flags_inst(&d->cfg, - (modified)?KHUI_CNFLAG_MODIFIED:0, - KHUI_CNFLAG_MODIFIED); -} - -static void -k5_id_write_params(HWND hw, k5_id_dlg_data * d) { - - khm_handle csp_idroot = NULL; - khm_handle csp_ident = NULL; - 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; - - rv = kcdb_identity_get_config(d->ident, KHM_FLAG_CREATE, &csp_idroot); - if (KHM_SUCCEEDED(rv)) { - khc_open_space(csp_idroot, CSNAME_KRB5CRED, - KHM_FLAG_CREATE, - &csp_ident); - } - - if (csp_idroot) - khc_close_space(csp_idroot); - - if (!csp_ident) - return; - - if (d->life != d->tc_life.current) { - d->life = d->tc_life.current; - khc_write_int32(csp_ident, L"DefaultLifetime", (khm_int32) d->life); - } - - if (d->renew_life != d->tc_renew.current) { - d->renew_life = d->tc_renew.current; - 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)) && - _wcsicmp(ccache, d->ccache)) { - khc_write_string(csp_ident, L"DefaultCCName", ccache); - StringCbCopy(d->ccache, sizeof(d->ccache), ccache); - } else { - khc_remove_value(csp_ident, L"DefaultCCName", KCONF_FLAG_USER); - } - - if (csp_ident) - khc_close_space(csp_ident); - - khui_cfg_set_flags_inst(&d->cfg, - KHUI_CNFLAG_APPLIED, - KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); -} - -INT_PTR CALLBACK -k5_id_tab_dlgproc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - - k5_id_dlg_data * d; - - switch(uMsg) { - case WM_INITDIALOG: - d = PMALLOC(sizeof(*d)); -#ifdef DEBUG - assert(d); -#endif - ZeroMemory(d, sizeof(*d)); - - d->cfg = *((khui_config_init_data *) lParam); - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); -#pragma warning(pop) - - k5_id_read_params(d); - - khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFLIFE), - &d->tc_life); - khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFRLIFE), - &d->tc_renew); - khui_tracker_refresh(&d->tc_life); - 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: - d = (k5_id_dlg_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (HIWORD(wParam) == EN_CHANGE || - HIWORD(wParam) == BN_CLICKED) - k5_id_check_mod(hwnd, d); - break; - - case KHUI_WM_CFG_NOTIFY: - d = (k5_id_dlg_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (HIWORD(wParam) == WMCFG_APPLY) { - k5_id_write_params(hwnd, d); - } - break; - - case WM_DESTROY: - d = (k5_id_dlg_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - khui_tracker_kill_controls(&d->tc_life); - khui_tracker_kill_controls(&d->tc_renew); - - if (d->ident) - kcdb_identity_release(d->ident); - - PFREE(d); - break; - } - return FALSE; -} +/* + * 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 +#include + +#include + +typedef struct tag_k5_id_dlg_data { + khui_config_init_data cfg; + + khm_handle ident; + + khui_tracker tc_life; + khui_tracker tc_renew; + + 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; + +static void +k5_id_read_params(k5_id_dlg_data * d) { + + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khm_int32 rv; + khm_int32 t; + khm_handle csp_ident; + khm_handle csp_idroot = NULL; + + cb = sizeof(idname); + rv = khui_cfg_get_name(d->cfg.ctx_node, idname, &cb); +#ifdef DEBUG + assert(KHM_SUCCEEDED(rv)); +#endif + + rv = kcdb_identity_create(idname, 0, &d->ident); +#ifdef DEBUG + assert(KHM_SUCCEEDED(rv)); +#endif + + rv = kcdb_identity_get_config(d->ident, 0, &csp_idroot); + if (KHM_SUCCEEDED(rv) && + KHM_SUCCEEDED(khc_open_space(csp_idroot, CSNAME_KRB5CRED, 0, + &csp_ident))) { + khc_shadow_space(csp_ident, csp_params); + } else { + csp_ident = csp_params; + } + + if (csp_idroot) + khc_close_space(csp_idroot); + + rv = khc_read_int32(csp_ident, L"DefaultLifetime", &t); + if (KHM_SUCCEEDED(rv)) + d->life = t; + else + d->life = 36000; + + rv = khc_read_int32(csp_ident, L"DefaultRenewLifetime", &t); + if (KHM_SUCCEEDED(rv)) + d->renew_life = t; + 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)) { + cb = sizeof(d->ccache); + if (KHM_FAILED(kcdb_identity_get_attr(d->ident, attr_id_krb5_ccname, + NULL, d->ccache, &cb))) + ZeroMemory(d->ccache, sizeof(d->ccache)); + } + + khui_tracker_initialize(&d->tc_life); + d->tc_life.current = d->life; + d->tc_life.min = 0; + d->tc_life.max = 3600 * 24 * 7; + + khui_tracker_initialize(&d->tc_renew); + d->tc_renew.current = d->renew_life; + d->tc_renew.min = 0; + d->tc_renew.max = 3600 * 24 * 30; + + if (csp_ident != csp_params) + khc_close_space(csp_ident); +} + +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 || + + (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; +} + +static void +k5_id_check_mod(HWND hw, k5_id_dlg_data * d) { + BOOL modified = k5_id_is_mod(hw, d); + + khui_cfg_set_flags_inst(&d->cfg, + (modified)?KHUI_CNFLAG_MODIFIED:0, + KHUI_CNFLAG_MODIFIED); +} + +static void +k5_id_write_params(HWND hw, k5_id_dlg_data * d) { + + khm_handle csp_idroot = NULL; + khm_handle csp_ident = NULL; + 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; + + rv = kcdb_identity_get_config(d->ident, KHM_FLAG_CREATE, &csp_idroot); + if (KHM_SUCCEEDED(rv)) { + khc_open_space(csp_idroot, CSNAME_KRB5CRED, + KHM_FLAG_CREATE, + &csp_ident); + } + + if (csp_idroot) + khc_close_space(csp_idroot); + + if (!csp_ident) + return; + + if (d->life != d->tc_life.current) { + d->life = d->tc_life.current; + khc_write_int32(csp_ident, L"DefaultLifetime", (khm_int32) d->life); + } + + if (d->renew_life != d->tc_renew.current) { + d->renew_life = d->tc_renew.current; + 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)) && + _wcsicmp(ccache, d->ccache)) { + khc_write_string(csp_ident, L"DefaultCCName", ccache); + StringCbCopy(d->ccache, sizeof(d->ccache), ccache); + } else { + khc_remove_value(csp_ident, L"DefaultCCName", KCONF_FLAG_USER); + } + + if (csp_ident) + khc_close_space(csp_ident); + + khui_cfg_set_flags_inst(&d->cfg, + KHUI_CNFLAG_APPLIED, + KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); +} + +INT_PTR CALLBACK +k5_id_tab_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + k5_id_dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + d = PMALLOC(sizeof(*d)); +#ifdef DEBUG + assert(d); +#endif + ZeroMemory(d, sizeof(*d)); + + d->cfg = *((khui_config_init_data *) lParam); + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + k5_id_read_params(d); + + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFLIFE), + &d->tc_life); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFRLIFE), + &d->tc_renew); + khui_tracker_refresh(&d->tc_life); + 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: + d = (k5_id_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == EN_CHANGE || + HIWORD(wParam) == BN_CLICKED) + k5_id_check_mod(hwnd, d); + break; + + case KHUI_WM_CFG_NOTIFY: + d = (k5_id_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == WMCFG_APPLY) { + k5_id_write_params(hwnd, d); + } + break; + + case WM_DESTROY: + d = (k5_id_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + khui_tracker_kill_controls(&d->tc_life); + khui_tracker_kill_controls(&d->tc_renew); + + if (d->ident) + kcdb_identity_release(d->ident); + + PFREE(d); + break; + } + return FALSE; +} diff --git a/src/windows/identity/plugins/krb5/krb5configids.c b/src/windows/identity/plugins/krb5/krb5configids.c index 5f4729253..8d6afd473 100644 --- a/src/windows/identity/plugins/krb5/krb5configids.c +++ b/src/windows/identity/plugins/krb5/krb5configids.c @@ -1,270 +1,270 @@ -/* - * 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 -#include - -typedef struct tag_k5_ids_opts { - khm_int32 renewable; - khm_int32 forwardable; - khm_int32 addressless; -} k5_ids_opts; - -typedef struct tag_k5_ids_dlg_data { - khui_config_init_data cfg; - - khui_tracker tc_life; - khui_tracker tc_renew; - khui_tracker tc_life_min; - khui_tracker tc_life_max; - khui_tracker tc_renew_min; - khui_tracker tc_renew_max; - - time_t life; - time_t renew_life; - time_t life_min; - time_t life_max; - time_t renew_min; - time_t renew_max; - - k5_ids_opts opt; - k5_ids_opts opt_saved; - -} k5_ids_dlg_data; - -static khm_boolean -k5_ids_is_mod(k5_ids_dlg_data * d) { - if (d->life != d->tc_life.current || - d->renew_life != d->tc_renew.current || - d->life_max != d->tc_life_max.current || - d->life_min != d->tc_life_min.current || - d->renew_max != d->tc_renew_max.current || - d->renew_min != d->tc_renew_min.current || - !!d->opt.renewable != !!d->opt_saved.renewable || - !!d->opt.forwardable != !!d->opt_saved.forwardable || - !!d->opt.addressless != !!d->opt_saved.addressless) - return TRUE; - return FALSE; -} - -static void -k5_ids_check_mod(k5_ids_dlg_data * d) { - BOOL modified = k5_ids_is_mod(d); - - khui_cfg_set_flags_inst(&d->cfg, - (modified)?KHUI_CNFLAG_MODIFIED:0, - KHUI_CNFLAG_MODIFIED); -} - -static void -k5_ids_write_params(k5_ids_dlg_data * d) { - - khm_int32 rv; - -#ifdef DEBUG - assert(csp_params); -#endif - - if (!k5_ids_is_mod(d)) - return; - -#define WRITEPARAM(po,pn,vn) \ - if (po != pn) { \ - po = pn; \ - rv = khc_write_int32(csp_params, vn, (khm_int32) po); \ - assert(KHM_SUCCEEDED(rv)); \ - } - - WRITEPARAM(d->life,d->tc_life.current, L"DefaultLifetime"); - WRITEPARAM(d->renew_life,d->tc_renew.current, L"DefaultRenewLifetime"); - WRITEPARAM(d->life_max,d->tc_life_max.current, L"MaxLifetime"); - WRITEPARAM(d->life_min,d->tc_life_min.current, L"MinLifetime"); - WRITEPARAM(d->renew_max,d->tc_renew_max.current, L"MaxRenewLifetime"); - WRITEPARAM(d->renew_min,d->tc_renew_min.current, L"MinRenewLifetime"); - WRITEPARAM(d->opt_saved.renewable, d->opt.renewable, L"Renewable"); - WRITEPARAM(d->opt_saved.forwardable, d->opt.forwardable, L"Forwardable"); - WRITEPARAM(d->opt_saved.addressless, d->opt.addressless, L"Addressless"); - -#undef WRITEPARAM - - khui_cfg_set_flags_inst(&d->cfg, - KHUI_CNFLAG_APPLIED, - KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); -} - -static void -k5_ids_read_params(k5_ids_dlg_data * d) { - k5_params p; - - khm_krb5_get_identity_params(NULL, &p); - - d->life = p.lifetime; - d->life_max = p.lifetime_max; - d->life_min = p.lifetime_min; - - d->renew_life = p.renew_life; - d->renew_max = p.renew_life_max; - d->renew_min = p.renew_life_min; - - d->opt_saved.forwardable = p.forwardable; - d->opt_saved.renewable = p.renewable; - d->opt_saved.addressless = p.addressless; - - d->opt = d->opt_saved; - - khui_tracker_initialize(&d->tc_life); - d->tc_life.current = d->life; - d->tc_life.min = 0; - d->tc_life.max = 3600 * 24 * 7; - - khui_tracker_initialize(&d->tc_renew); - d->tc_renew.current = d->renew_life; - d->tc_renew.min = 0; - d->tc_renew.max = 3600 * 24 * 30; - - khui_tracker_initialize(&d->tc_life_min); - d->tc_life_min.current = d->life_min; - d->tc_life_min.min = d->tc_life.min; - d->tc_life_min.max = d->tc_life.max; - - khui_tracker_initialize(&d->tc_life_max); - d->tc_life_max.current = d->life_max; - d->tc_life_max.min = d->tc_life.min; - d->tc_life_max.max = d->tc_life.max; - - khui_tracker_initialize(&d->tc_renew_min); - d->tc_renew_min.current = d->renew_min; - d->tc_renew_min.min = d->tc_renew.min; - d->tc_renew_min.max = d->tc_renew.max; - - khui_tracker_initialize(&d->tc_renew_max); - d->tc_renew_max.current = d->renew_max; - d->tc_renew_max.min = d->tc_renew.min; - d->tc_renew_max.max = d->tc_renew.max; -} - -INT_PTR CALLBACK -k5_ids_tab_dlgproc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - k5_ids_dlg_data * d; - - switch(uMsg) { - case WM_INITDIALOG: - d = PMALLOC(sizeof(*d)); -#ifdef DEBUG - assert(d); -#endif - ZeroMemory(d, sizeof(*d)); -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); -#pragma warning(pop) - - d->cfg = *((khui_config_init_data *) lParam); - - k5_ids_read_params(d); - - khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFLIFE), - &d->tc_life); - khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFRLIFE), - &d->tc_renew); - khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_LRNG_MIN), - &d->tc_life_min); - khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_LRNG_MAX), - &d->tc_life_max); - khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_RLRNG_MIN), - &d->tc_renew_min); - khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_RLRNG_MAX), - &d->tc_renew_max); - khui_tracker_refresh(&d->tc_life); - khui_tracker_refresh(&d->tc_life_min); - khui_tracker_refresh(&d->tc_life_max); - khui_tracker_refresh(&d->tc_renew); - khui_tracker_refresh(&d->tc_renew_min); - khui_tracker_refresh(&d->tc_renew_max); - - CheckDlgButton(hwnd, IDC_CFG_RENEW, (d->opt.renewable ? BST_CHECKED: BST_UNCHECKED)); - CheckDlgButton(hwnd, IDC_CFG_FORWARD, (d->opt.forwardable ? BST_CHECKED: BST_UNCHECKED)); - CheckDlgButton(hwnd, IDC_CFG_ADDRESSLESS, (d->opt.addressless ? BST_CHECKED: BST_UNCHECKED)); - break; - - case WM_COMMAND: - d = (k5_ids_dlg_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (HIWORD(wParam) == EN_CHANGE) { - k5_ids_check_mod(d); - } else if (HIWORD(wParam) == BN_CLICKED) { - switch (LOWORD(wParam)) { - case IDC_CFG_RENEW: - d->opt.renewable = (IsDlgButtonChecked(hwnd, IDC_CFG_RENEW) == BST_CHECKED); - break; - - case IDC_CFG_FORWARD: - d->opt.forwardable = (IsDlgButtonChecked(hwnd, IDC_CFG_FORWARD) == BST_CHECKED); - break; - - case IDC_CFG_ADDRESSLESS: - d->opt.addressless = (IsDlgButtonChecked(hwnd, IDC_CFG_ADDRESSLESS) == BST_CHECKED); - break; - } - - k5_ids_check_mod(d); - } - break; - - case KHUI_WM_CFG_NOTIFY: - d = (k5_ids_dlg_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - if (HIWORD(wParam) == WMCFG_APPLY) { - k5_ids_write_params(d); - } - break; - - case WM_DESTROY: - d = (k5_ids_dlg_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - khui_tracker_kill_controls(&d->tc_life); - khui_tracker_kill_controls(&d->tc_renew); - khui_tracker_kill_controls(&d->tc_life_min); - khui_tracker_kill_controls(&d->tc_life_max); - khui_tracker_kill_controls(&d->tc_renew_min); - khui_tracker_kill_controls(&d->tc_renew_max); - - PFREE(d); - break; - } - return FALSE; -} - - +/* + * 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 +#include + +typedef struct tag_k5_ids_opts { + khm_int32 renewable; + khm_int32 forwardable; + khm_int32 addressless; +} k5_ids_opts; + +typedef struct tag_k5_ids_dlg_data { + khui_config_init_data cfg; + + khui_tracker tc_life; + khui_tracker tc_renew; + khui_tracker tc_life_min; + khui_tracker tc_life_max; + khui_tracker tc_renew_min; + khui_tracker tc_renew_max; + + time_t life; + time_t renew_life; + time_t life_min; + time_t life_max; + time_t renew_min; + time_t renew_max; + + k5_ids_opts opt; + k5_ids_opts opt_saved; + +} k5_ids_dlg_data; + +static khm_boolean +k5_ids_is_mod(k5_ids_dlg_data * d) { + if (d->life != d->tc_life.current || + d->renew_life != d->tc_renew.current || + d->life_max != d->tc_life_max.current || + d->life_min != d->tc_life_min.current || + d->renew_max != d->tc_renew_max.current || + d->renew_min != d->tc_renew_min.current || + !!d->opt.renewable != !!d->opt_saved.renewable || + !!d->opt.forwardable != !!d->opt_saved.forwardable || + !!d->opt.addressless != !!d->opt_saved.addressless) + return TRUE; + return FALSE; +} + +static void +k5_ids_check_mod(k5_ids_dlg_data * d) { + BOOL modified = k5_ids_is_mod(d); + + khui_cfg_set_flags_inst(&d->cfg, + (modified)?KHUI_CNFLAG_MODIFIED:0, + KHUI_CNFLAG_MODIFIED); +} + +static void +k5_ids_write_params(k5_ids_dlg_data * d) { + + khm_int32 rv; + +#ifdef DEBUG + assert(csp_params); +#endif + + if (!k5_ids_is_mod(d)) + return; + +#define WRITEPARAM(po,pn,vn) \ + if (po != pn) { \ + po = pn; \ + rv = khc_write_int32(csp_params, vn, (khm_int32) po); \ + assert(KHM_SUCCEEDED(rv)); \ + } + + WRITEPARAM(d->life,d->tc_life.current, L"DefaultLifetime"); + WRITEPARAM(d->renew_life,d->tc_renew.current, L"DefaultRenewLifetime"); + WRITEPARAM(d->life_max,d->tc_life_max.current, L"MaxLifetime"); + WRITEPARAM(d->life_min,d->tc_life_min.current, L"MinLifetime"); + WRITEPARAM(d->renew_max,d->tc_renew_max.current, L"MaxRenewLifetime"); + WRITEPARAM(d->renew_min,d->tc_renew_min.current, L"MinRenewLifetime"); + WRITEPARAM(d->opt_saved.renewable, d->opt.renewable, L"Renewable"); + WRITEPARAM(d->opt_saved.forwardable, d->opt.forwardable, L"Forwardable"); + WRITEPARAM(d->opt_saved.addressless, d->opt.addressless, L"Addressless"); + +#undef WRITEPARAM + + khui_cfg_set_flags_inst(&d->cfg, + KHUI_CNFLAG_APPLIED, + KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); +} + +static void +k5_ids_read_params(k5_ids_dlg_data * d) { + k5_params p; + + khm_krb5_get_identity_params(NULL, &p); + + d->life = p.lifetime; + d->life_max = p.lifetime_max; + d->life_min = p.lifetime_min; + + d->renew_life = p.renew_life; + d->renew_max = p.renew_life_max; + d->renew_min = p.renew_life_min; + + d->opt_saved.forwardable = p.forwardable; + d->opt_saved.renewable = p.renewable; + d->opt_saved.addressless = p.addressless; + + d->opt = d->opt_saved; + + khui_tracker_initialize(&d->tc_life); + d->tc_life.current = d->life; + d->tc_life.min = 0; + d->tc_life.max = 3600 * 24 * 7; + + khui_tracker_initialize(&d->tc_renew); + d->tc_renew.current = d->renew_life; + d->tc_renew.min = 0; + d->tc_renew.max = 3600 * 24 * 30; + + khui_tracker_initialize(&d->tc_life_min); + d->tc_life_min.current = d->life_min; + d->tc_life_min.min = d->tc_life.min; + d->tc_life_min.max = d->tc_life.max; + + khui_tracker_initialize(&d->tc_life_max); + d->tc_life_max.current = d->life_max; + d->tc_life_max.min = d->tc_life.min; + d->tc_life_max.max = d->tc_life.max; + + khui_tracker_initialize(&d->tc_renew_min); + d->tc_renew_min.current = d->renew_min; + d->tc_renew_min.min = d->tc_renew.min; + d->tc_renew_min.max = d->tc_renew.max; + + khui_tracker_initialize(&d->tc_renew_max); + d->tc_renew_max.current = d->renew_max; + d->tc_renew_max.min = d->tc_renew.min; + d->tc_renew_max.max = d->tc_renew.max; +} + +INT_PTR CALLBACK +k5_ids_tab_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + k5_ids_dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + d = PMALLOC(sizeof(*d)); +#ifdef DEBUG + assert(d); +#endif + ZeroMemory(d, sizeof(*d)); +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + d->cfg = *((khui_config_init_data *) lParam); + + k5_ids_read_params(d); + + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFLIFE), + &d->tc_life); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFRLIFE), + &d->tc_renew); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_LRNG_MIN), + &d->tc_life_min); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_LRNG_MAX), + &d->tc_life_max); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_RLRNG_MIN), + &d->tc_renew_min); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_RLRNG_MAX), + &d->tc_renew_max); + khui_tracker_refresh(&d->tc_life); + khui_tracker_refresh(&d->tc_life_min); + khui_tracker_refresh(&d->tc_life_max); + khui_tracker_refresh(&d->tc_renew); + khui_tracker_refresh(&d->tc_renew_min); + khui_tracker_refresh(&d->tc_renew_max); + + CheckDlgButton(hwnd, IDC_CFG_RENEW, (d->opt.renewable ? BST_CHECKED: BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_FORWARD, (d->opt.forwardable ? BST_CHECKED: BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_ADDRESSLESS, (d->opt.addressless ? BST_CHECKED: BST_UNCHECKED)); + break; + + case WM_COMMAND: + d = (k5_ids_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == EN_CHANGE) { + k5_ids_check_mod(d); + } else if (HIWORD(wParam) == BN_CLICKED) { + switch (LOWORD(wParam)) { + case IDC_CFG_RENEW: + d->opt.renewable = (IsDlgButtonChecked(hwnd, IDC_CFG_RENEW) == BST_CHECKED); + break; + + case IDC_CFG_FORWARD: + d->opt.forwardable = (IsDlgButtonChecked(hwnd, IDC_CFG_FORWARD) == BST_CHECKED); + break; + + case IDC_CFG_ADDRESSLESS: + d->opt.addressless = (IsDlgButtonChecked(hwnd, IDC_CFG_ADDRESSLESS) == BST_CHECKED); + break; + } + + k5_ids_check_mod(d); + } + break; + + case KHUI_WM_CFG_NOTIFY: + d = (k5_ids_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + if (HIWORD(wParam) == WMCFG_APPLY) { + k5_ids_write_params(d); + } + break; + + case WM_DESTROY: + d = (k5_ids_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + khui_tracker_kill_controls(&d->tc_life); + khui_tracker_kill_controls(&d->tc_renew); + khui_tracker_kill_controls(&d->tc_life_min); + khui_tracker_kill_controls(&d->tc_life_max); + khui_tracker_kill_controls(&d->tc_renew_min); + khui_tracker_kill_controls(&d->tc_renew_max); + + PFREE(d); + break; + } + return FALSE; +} + + diff --git a/src/windows/identity/plugins/krb5/krb5funcs.c b/src/windows/identity/plugins/krb5/krb5funcs.c index e66e755a7..6f657e851 100644 --- a/src/windows/identity/plugins/krb5/krb5funcs.c +++ b/src/windows/identity/plugins/krb5/krb5funcs.c @@ -1,3487 +1,3487 @@ -/* -* Copyright (c) 2005 Massachusetts Institute of Technology -* Copyright (c) 2006,2007 Secure Endpoints Inc. -* -* Permission is hereby granted, free of charge, to any person -* obtaining a copy of this software and associated documentation -* files (the "Software"), to deal in the Software without -* restriction, including without limitation the rights to use, copy, -* modify, merge, publish, distribute, sublicense, and/or sell copies -* of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be -* included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -/* $Id$ */ - -/* Originally this was krb5routines.c in Leash sources. Subsequently - * modified and adapted for NetIDMgr */ - -#include -#include - -#define SECURITY_WIN32 -#include - -#include -#include -#include -#include -#include - -long -khm_convert524(krb5_context alt_ctx) -{ - krb5_context ctx = 0; - krb5_error_code code = 0; - int icode = 0; - krb5_principal me = 0; - krb5_principal server = 0; - krb5_creds *v5creds = 0; - krb5_creds increds; - krb5_ccache cc = 0; - CREDENTIALS * v4creds = NULL; - static int init_ets = 1; - - if (!pkrb5_init_context || - !pkrb_in_tkt || - !pkrb524_init_ets || - !pkrb524_convert_creds_kdc) - return 0; - - v4creds = (CREDENTIALS *) PMALLOC(sizeof(CREDENTIALS)); - memset((char *) v4creds, 0, sizeof(CREDENTIALS)); - - memset((char *) &increds, 0, sizeof(increds)); - /* - From this point on, we can goto cleanup because increds is - initialized. - */ - - if (alt_ctx) - { - ctx = alt_ctx; - } - else - { - code = pkrb5_init_context(&ctx); - if (code) goto cleanup; - } - - code = pkrb5_cc_default(ctx, &cc); - if (code) goto cleanup; - - if ( init_ets ) { - pkrb524_init_ets(ctx); - init_ets = 0; - } - - if (code = pkrb5_cc_get_principal(ctx, cc, &me)) - goto cleanup; - - if ((code = pkrb5_build_principal(ctx, - &server, - krb5_princ_realm(ctx, me)->length, - krb5_princ_realm(ctx, me)->data, - "krbtgt", - krb5_princ_realm(ctx, me)->data, - NULL))) - { - goto cleanup; - } - - increds.client = me; - increds.server = server; - increds.times.endtime = 0; - increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; - if ((code = pkrb5_get_credentials(ctx, 0, - cc, - &increds, - &v5creds))) - { - goto cleanup; - } - - if ((icode = pkrb524_convert_creds_kdc(ctx, - v5creds, - v4creds))) - { - goto cleanup; - } - - /* initialize ticket cache */ - if ((icode = pkrb_in_tkt(v4creds->pname, v4creds->pinst, v4creds->realm) - != KSUCCESS)) - { - goto cleanup; - } - /* stash ticket, session key, etc. for future use */ - if ((icode = pkrb_save_credentials(v4creds->service, - v4creds->instance, - v4creds->realm, - v4creds->session, - v4creds->lifetime, - v4creds->kvno, - &(v4creds->ticket_st), - v4creds->issue_date))) - { - goto cleanup; - } - -cleanup: - memset(v4creds, 0, sizeof(v4creds)); - PFREE(v4creds); - - if (v5creds) { - pkrb5_free_creds(ctx, v5creds); - } - if (increds.client == me) - me = 0; - if (increds.server == server) - server = 0; - pkrb5_free_cred_contents(ctx, &increds); - if (server) { - pkrb5_free_principal(ctx, server); - } - if (me) { - pkrb5_free_principal(ctx, me); - } - pkrb5_cc_close(ctx, cc); - - if (ctx && (ctx != alt_ctx)) { - pkrb5_free_context(ctx); - } - return !(code || icode); -} - -#ifdef DEPRECATED_REMOVABLE -int com_addr(void) -{ - long ipAddr; - char loc_addr[ADDR_SZ]; - CREDENTIALS cred; - char service[40]; - char instance[40]; - // char addr[40]; - char realm[40]; - struct in_addr LocAddr; - int k_errno; - - if (pkrb_get_cred == NULL) - return(KSUCCESS); - - k_errno = (*pkrb_get_cred)(service,instance,realm,&cred); - if (k_errno) - return KRBERR(k_errno); - - while(1) { - ipAddr = (*pLocalHostAddr)(); - LocAddr.s_addr = ipAddr; - StringCbCopyA(loc_addr, sizeof(loc_addr), inet_ntoa(LocAddr)); - if ( strcmp(cred.address, loc_addr) != 0) { - /* TODO: do something about this */ - //Leash_kdestroy (); - break; - } - break; - } // while() - return 0; -} -#endif - -/* we use these structures to keep track of identities that we find - while going through the API, FILE and MSLSA caches and enumerating - credentials. The only identities we want to keep track of are the - ones that have an initial ticket. We collect information for each - of the identities we find that we have initial tickets for and - then set the properties for the identities at once. */ - -typedef struct tag_ident_data { - khm_handle ident; /* handle to the identity */ - khm_int32 count; /* number of initial tickets we have - found for this identity. */ - wchar_t ccname[MAX_PATH]; - FILETIME ft_issue; - FILETIME ft_expire; - FILETIME ft_renewexpire; - khm_int32 krb5_flags; -} ident_data; - -typedef struct tag_identlist { - ident_data * list; - khm_size n_list; - khm_size nc_list; -} identlist; - -#define IDLIST_ALLOC_INCR 8 - -static void -tc_prep_idlist(identlist * idlist) { - khm_int32 rv; - khm_size cb_ids = 0; - khm_size n_ids = 0; - khm_size i; - wchar_t * ids = NULL; - wchar_t *thisid; - - idlist->list = NULL; - idlist->n_list = 0; - idlist->nc_list = 0; - - do { - - if (ids) { - PFREE(ids); - ids = NULL; - } - - rv = kcdb_identity_enum(KCDB_IDENT_FLAG_ACTIVE, - KCDB_IDENT_FLAG_ACTIVE, - NULL, - &cb_ids, - &n_ids); - - if (rv != KHM_ERROR_TOO_LONG) - break; /* something else is wrong */ - - if (n_ids == 0 || cb_ids == 0) - break; /* no identities to process */ - -#ifdef DEBUG - assert(cb_ids > 0); -#endif - - ids = PMALLOC(cb_ids); -#ifdef DEBUG - assert(ids != NULL); -#endif - if (ids == NULL) - break; - - rv = kcdb_identity_enum(KCDB_IDENT_FLAG_ACTIVE, - KCDB_IDENT_FLAG_ACTIVE, - ids, - &cb_ids, - &n_ids); - - if (KHM_SUCCEEDED(rv)) - break; - - } while (TRUE); - - if (ids == NULL) - return; - - if (KHM_FAILED(rv) || n_ids == 0) { - if (ids) - PFREE(ids); - return; - } - - idlist->nc_list = UBOUNDSS(n_ids, IDLIST_ALLOC_INCR, IDLIST_ALLOC_INCR); - - idlist->list = PCALLOC(idlist->nc_list, sizeof(idlist->list[0])); - - for (i = 0, thisid = ids; - thisid && thisid[0]; - thisid = multi_string_next(thisid)) { - - khm_handle ident; - - rv = kcdb_identity_create(thisid, 0, &ident); - - if (KHM_FAILED(rv)) - continue; - - idlist->list[i].ident = ident; - idlist->list[i].count = 0; - - i++; - } - - idlist->n_list = i; - - PFREE(ids); -} - -static ident_data * -tc_add_ident_to_list(identlist * idlist, khm_handle ident) { - khm_size i; - ident_data * d; - - for (i=0; i < idlist->n_list; i++) { - if (kcdb_identity_is_equal(ident, idlist->list[i].ident)) - break; - } - - if (i < idlist->n_list) { - /* we already have this identity on our list. Increment the - count */ - idlist->list[i].count++; - return &idlist->list[i]; - } - - /* it wasn't in our list. Add it */ - - if (idlist->n_list + 1 > idlist->nc_list) { - idlist->nc_list = UBOUNDSS(idlist->n_list + 1, - IDLIST_ALLOC_INCR, - IDLIST_ALLOC_INCR); -#ifdef DEBUG - assert(idlist->n_list + 1 <= idlist->nc_list); -#endif - idlist->list = PREALLOC(idlist->list, - sizeof(idlist->list[0]) * idlist->nc_list); -#ifdef DEBUG - assert(idlist->list); -#endif - ZeroMemory(&idlist->list[idlist->n_list], - sizeof(idlist->list[0]) * - (idlist->nc_list - idlist->n_list)); - } - - d = &idlist->list[idlist->n_list]; - - ZeroMemory(d, sizeof(*d)); - - d->ident = ident; - d->count = 1; - - idlist->n_list++; - - kcdb_identity_hold(ident); - - return d; -} - -static void -tc_set_ident_data(identlist * idlist) { - khm_size i; - wchar_t k5idtype[KCDB_MAXCCH_NAME]; - - k5idtype[0] = L'\0'; - LoadString(hResModule, IDS_KRB5_NC_NAME, - k5idtype, ARRAYLENGTH(k5idtype)); - - for (i=0; i < idlist->n_list; i++) { -#ifdef DEBUG - assert(idlist->list[i].ident); -#endif - - if (idlist->list[i].count > 0) { - khm_int32 t; - - t = credtype_id_krb5; - kcdb_identity_set_attr(idlist->list[i].ident, - KCDB_ATTR_TYPE, - &t, - sizeof(t)); - - /* We need to manually add the type name if we want the - name to show up in the property list for the identity. - The type name is only automatically calculated for - credentials. */ - kcdb_identity_set_attr(idlist->list[i].ident, - KCDB_ATTR_TYPE_NAME, - k5idtype, - KCDB_CBSIZE_AUTO); - - kcdb_identity_set_attr(idlist->list[i].ident, - attr_id_krb5_ccname, - idlist->list[i].ccname, - KCDB_CBSIZE_AUTO); - - kcdb_identity_set_attr(idlist->list[i].ident, - KCDB_ATTR_EXPIRE, - &idlist->list[i].ft_expire, - sizeof(idlist->list[i].ft_expire)); - - kcdb_identity_set_attr(idlist->list[i].ident, - KCDB_ATTR_ISSUE, - &idlist->list[i].ft_issue, - sizeof(idlist->list[i].ft_issue)); - - kcdb_identity_set_attr(idlist->list[i].ident, - attr_id_krb5_flags, - &idlist->list[i].krb5_flags, - sizeof(idlist->list[i].krb5_flags)); - - if (idlist->list[i].ft_renewexpire.dwLowDateTime == 0 && - idlist->list[i].ft_renewexpire.dwHighDateTime == 0) { - kcdb_identity_set_attr(idlist->list[i].ident, - KCDB_ATTR_RENEW_EXPIRE, - NULL, 0); - } else { - kcdb_identity_set_attr(idlist->list[i].ident, - KCDB_ATTR_RENEW_EXPIRE, - &idlist->list[i].ft_renewexpire, - sizeof(idlist->list[i].ft_renewexpire)); - } - - } else { - /* We didn't see any TGTs for this identity. We have to - remove all the Krb5 supplied properties. */ - - khm_int32 t; - khm_size cb; - - cb = sizeof(t); - if (KHM_SUCCEEDED(kcdb_identity_get_attr(idlist->list[i].ident, - KCDB_ATTR_TYPE, NULL, - &t, - &cb)) && - t == credtype_id_krb5) { - - /* disown this and remove all our properties. the - system will GC this identity if nobody claims it.*/ - - kcdb_identity_set_attr(idlist->list[i].ident, - KCDB_ATTR_TYPE, NULL, 0); - kcdb_identity_set_attr(idlist->list[i].ident, - KCDB_ATTR_TYPE_NAME, NULL, 0); - kcdb_identity_set_attr(idlist->list[i].ident, - attr_id_krb5_ccname, NULL, 0); - kcdb_identity_set_attr(idlist->list[i].ident, - KCDB_ATTR_EXPIRE, NULL, 0); - kcdb_identity_set_attr(idlist->list[i].ident, - KCDB_ATTR_ISSUE, NULL, 0); - kcdb_identity_set_attr(idlist->list[i].ident, - attr_id_krb5_flags, NULL, 0); - kcdb_identity_set_attr(idlist->list[i].ident, - KCDB_ATTR_RENEW_EXPIRE, NULL, 0); - } else { - /* otherwise, this identity doesn't belong to us. We - should leave it as is. */ - } - } - } -} - -static void -tc_free_idlist(identlist * idlist) { - khm_size i; - - for (i=0; i < idlist->n_list; i++) { - if (idlist->list[i].ident != NULL) { - kcdb_identity_release(idlist->list[i].ident); - idlist->list[i].ident = NULL; - } - } - - if (idlist->list) - PFREE(idlist->list); - idlist->list = NULL; - idlist->n_list = 0; - idlist->nc_list = 0; -} - -#ifndef ENCTYPE_LOCAL_RC4_MD4 -#define ENCTYPE_LOCAL_RC4_MD4 0xFFFFFF80 -#endif - -#define MAX_ADDRS 256 - -static long get_tickets_from_cache(krb5_context ctx, - krb5_ccache cache, - identlist * idlist) -{ - krb5_error_code code; - krb5_principal KRBv5Principal; - krb5_flags flags = 0; - krb5_cc_cursor KRBv5Cursor; - krb5_creds KRBv5Credentials; - krb5_ticket *tkt=NULL; - char *ClientName = NULL; - char *PrincipalName = NULL; - wchar_t wbuf[256]; /* temporary conversion buffer */ - wchar_t wcc_name[KRB5_MAXCCH_CCNAME]; /* credential cache name */ - char *sServerName = NULL; - khm_handle ident = NULL; - khm_handle cred = NULL; - time_t tt; - FILETIME ft, eft; - khm_int32 ti; - -#ifdef KRB5_TC_NOTICKET - flags = KRB5_TC_NOTICKET; -#else - flags = 0; -#endif - - { - const char * cc_name; - const char * cc_type; - - cc_name = (*pkrb5_cc_get_name)(ctx, cache); - if(cc_name) { - cc_type = (*pkrb5_cc_get_type)(ctx, cache); - if (cc_type) { - StringCbPrintf(wcc_name, sizeof(wcc_name), L"%S:%S", cc_type, cc_name); - } else { - AnsiStrToUnicode(wcc_name, sizeof(wcc_name), cc_name); - khm_krb5_canon_cc_name(wcc_name, sizeof(wcc_name)); - } - } else { - cc_type = (*pkrb5_cc_get_type)(ctx, cache); - if (cc_type) { - StringCbPrintf(wcc_name, sizeof(wcc_name), L"%S:", cc_type); - } else { -#ifdef DEBUG - assert(FALSE); -#endif - StringCbCopy(wcc_name, sizeof(wcc_name), L""); - } - } - } - - _reportf(L"Getting tickets from cache [%s]", wcc_name); - - if ((code = (*pkrb5_cc_set_flags)(ctx, cache, flags))) - { - if (code != KRB5_FCC_NOFILE && code != KRB5_CC_NOTFOUND) - khm_krb5_error(code, "krb5_cc_set_flags()", 0, &ctx, &cache); - - goto _exit; - } - - if ((code = (*pkrb5_cc_get_principal)(ctx, cache, &KRBv5Principal))) - { - if (code != KRB5_FCC_NOFILE && code != KRB5_CC_NOTFOUND) - khm_krb5_error(code, "krb5_cc_get_principal()", 0, &ctx, &cache); - - goto _exit; - } - - PrincipalName = NULL; - ClientName = NULL; - sServerName = NULL; - if ((code = (*pkrb5_unparse_name)(ctx, KRBv5Principal, - (char **)&PrincipalName))) - { - if (PrincipalName != NULL) - (*pkrb5_free_unparsed_name)(ctx, PrincipalName); - - (*pkrb5_free_principal)(ctx, KRBv5Principal); - - goto _exit; - } - - if (!strcspn(PrincipalName, "@" )) - { - if (PrincipalName != NULL) - (*pkrb5_free_unparsed_name)(ctx, PrincipalName); - - (*pkrb5_free_principal)(ctx, KRBv5Principal); - - goto _exit; - } - - AnsiStrToUnicode(wbuf, sizeof(wbuf), PrincipalName); - if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, - &ident))) { - /* something bad happened */ - code = 1; - goto _exit; - } - - _reportf(L"Found principal [%s]", wbuf); - - (*pkrb5_free_principal)(ctx, KRBv5Principal); - - if ((code = (*pkrb5_cc_start_seq_get)(ctx, cache, &KRBv5Cursor))) - { - goto _exit; - } - - memset(&KRBv5Credentials, '\0', sizeof(KRBv5Credentials)); - - ClientName = NULL; - sServerName = NULL; - cred = NULL; - - while (!(code = pkrb5_cc_next_cred(ctx, cache, &KRBv5Cursor, - &KRBv5Credentials))) - { - khm_handle tident = NULL; - khm_int32 cred_flags = 0; - - if(ClientName != NULL) - (*pkrb5_free_unparsed_name)(ctx, ClientName); - if(sServerName != NULL) - (*pkrb5_free_unparsed_name)(ctx, sServerName); - if(cred) - kcdb_cred_release(cred); - - ClientName = NULL; - sServerName = NULL; - cred = NULL; - - if ((*pkrb5_unparse_name)(ctx, KRBv5Credentials.client, &ClientName)) - { - (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); - khm_krb5_error(code, "krb5_free_cred_contents()", 0, &ctx, &cache); - continue; - } - - if ((*pkrb5_unparse_name)(ctx, KRBv5Credentials.server, &sServerName)) - { - (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); - khm_krb5_error(code, "krb5_free_cred_contents()", 0, &ctx, &cache); - continue; - } - - /* if the ClientName differs from PrincipalName for some - reason, we need to create a new identity */ - if(strcmp(ClientName, PrincipalName)) { - AnsiStrToUnicode(wbuf, sizeof(wbuf), ClientName); - if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, - &tident))) { - (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); - continue; - } - } else { - tident = ident; - } - - AnsiStrToUnicode(wbuf, sizeof(wbuf), sServerName); - if(KHM_FAILED(kcdb_cred_create(wbuf, tident, credtype_id_krb5, - &cred))) { - (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); - continue; - } - - if (!KRBv5Credentials.times.starttime) - KRBv5Credentials.times.starttime = KRBv5Credentials.times.authtime; - - tt = KRBv5Credentials.times.starttime; - TimetToFileTime(tt, &ft); - kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft)); - - tt = KRBv5Credentials.times.endtime; - TimetToFileTime(tt, &eft); - kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &eft, sizeof(eft)); - - { - FILETIME ftl; - - ftl = FtSub(&eft, &ft); - kcdb_cred_set_attr(cred, KCDB_ATTR_LIFETIME, &ftl, sizeof(ftl)); - } - - if (KRBv5Credentials.times.renew_till > 0) { - FILETIME ftl; - - tt = KRBv5Credentials.times.renew_till; - TimetToFileTime(tt, &eft); - kcdb_cred_set_attr(cred, KCDB_ATTR_RENEW_EXPIRE, &eft, - sizeof(eft)); - - - ftl = FtSub(&eft, &ft); - kcdb_cred_set_attr(cred, KCDB_ATTR_RENEW_LIFETIME, &ftl, - sizeof(ftl)); - } - - ti = KRBv5Credentials.ticket_flags; - kcdb_cred_set_attr(cred, attr_id_krb5_flags, &ti, sizeof(ti)); - - /* special flags understood by NetIDMgr */ - { - khm_int32 nflags = 0; - - if (ti & TKT_FLG_RENEWABLE) - nflags |= KCDB_CRED_FLAG_RENEWABLE; - if (ti & TKT_FLG_INITIAL) - nflags |= KCDB_CRED_FLAG_INITIAL; - else { - krb5_data * c0, *c1, *r; - - /* these are macros that do not allocate any memory */ - c0 = krb5_princ_component(ctx,KRBv5Credentials.server,0); - c1 = krb5_princ_component(ctx,KRBv5Credentials.server,1); - r = krb5_princ_realm(ctx,KRBv5Credentials.server); - - if ( c0 && c1 && r && c1->length == r->length && - !strncmp(c1->data,r->data,r->length) && - !strncmp("krbtgt",c0->data,c0->length) ) - nflags |= KCDB_CRED_FLAG_INITIAL; - } - - kcdb_cred_set_flags(cred, nflags, KCDB_CRED_FLAGMASK_EXT); - - cred_flags = nflags; - } - - if ( !pkrb5_decode_ticket(&KRBv5Credentials.ticket, &tkt)) { - ti = tkt->enc_part.enctype; - kcdb_cred_set_attr(cred, attr_id_tkt_enctype, &ti, sizeof(ti)); - ti = tkt->enc_part.kvno; - kcdb_cred_set_attr(cred, attr_id_kvno, &ti, sizeof(ti)); - pkrb5_free_ticket(ctx, tkt); - tkt = NULL; - } - - ti = KRBv5Credentials.keyblock.enctype; - kcdb_cred_set_attr(cred, attr_id_key_enctype, &ti, sizeof(ti)); - - kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION, wcc_name, - KCDB_CBSIZE_AUTO); - - if ( KRBv5Credentials.addresses && KRBv5Credentials.addresses[0] ) { - 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); - } - - if(cred_flags & KCDB_CRED_FLAG_INITIAL) { - FILETIME ft_issue_new; - FILETIME ft_expire_old; - FILETIME ft_expire_new; - ident_data * d; - - /* an initial ticket! Add it to the list of identities we - have seen so far with initial tickets. */ - d = tc_add_ident_to_list(idlist, ident); -#ifdef DEBUG - assert(d); - assert(d->count > 0); -#endif - - tt = KRBv5Credentials.times.endtime; - TimetToFileTime(tt, &ft_expire_new); - - tt = KRBv5Credentials.times.starttime; - TimetToFileTime(tt, &ft_issue_new); - - /* so now, we have to set the properties of the identity - based on the properties of this credential under the - following circumstances: - - - If this is the first time we are hitting this - identity. - - - If this is not the MSLSA: cache and the expiry time - for this credential is longer than the time already - found for this identity. - */ - - ft_expire_old = d->ft_expire; - - if(d->count == 1 - || (CompareFileTime(&ft_expire_new, &ft_expire_old) > 0 && - wcscmp(wcc_name, L"MSLSA:") != 0)) { - - _reportf(L"Setting properties for identity (count=%d)", d->count); - - StringCbCopy(d->ccname, sizeof(d->ccname), - wcc_name); - d->ft_expire = ft_expire_new; - d->ft_issue = ft_issue_new; - - if (KRBv5Credentials.times.renew_till > 0) { - tt = KRBv5Credentials.times.renew_till; - TimetToFileTime(tt, &ft); - d->ft_renewexpire = ft; - } else { - ZeroMemory(&d->ft_renewexpire, sizeof(d->ft_renewexpire)); - } - - d->krb5_flags = KRBv5Credentials.ticket_flags; - } - } - - kcdb_credset_add_cred(krb5_credset, cred, -1); - - (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); - - if(tident != ident) - kcdb_identity_release(tident); - } - - if (PrincipalName != NULL) - (*pkrb5_free_unparsed_name)(ctx, PrincipalName); - - if (ClientName != NULL) - (*pkrb5_free_unparsed_name)(ctx, ClientName); - - if (sServerName != NULL) - (*pkrb5_free_unparsed_name)(ctx, sServerName); - - if (cred) - kcdb_cred_release(cred); - - if ((code == KRB5_CC_END) || (code == KRB5_CC_NOTFOUND)) - { - if ((code = pkrb5_cc_end_seq_get(ctx, cache, &KRBv5Cursor))) - { - goto _exit; - } - - flags = KRB5_TC_OPENCLOSE; -#ifdef KRB5_TC_NOTICKET - flags |= KRB5_TC_NOTICKET; -#endif - if ((code = pkrb5_cc_set_flags(ctx, cache, flags))) - { - goto _exit; - } - } - else - { - goto _exit; - } - -_exit: - - return code; -} - -long -khm_krb5_list_tickets(krb5_context *krbv5Context) -{ - krb5_context ctx = NULL; - krb5_ccache cache = NULL; - krb5_error_code code = 0; - apiCB * cc_ctx = NULL; - struct _infoNC ** pNCi = NULL; - int i; - khm_int32 t; - wchar_t * ms = NULL; - khm_size cb; - identlist idl; - - kcdb_credset_flush(krb5_credset); - tc_prep_idlist(&idl); - - if((*krbv5Context == 0) && (code = (*pkrb5_init_context)(krbv5Context))) { - goto _exit; - } - - ctx = (*krbv5Context); - - if (!pcc_initialize || - !pcc_get_NC_info || - !pcc_free_NC_info || - !pcc_shutdown) - goto _skip_cc_iter; - - code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL); - if (code) - goto _exit; - - code = pcc_get_NC_info(cc_ctx, &pNCi); - if (code) - goto _exit; - - for(i=0; pNCi[i]; i++) { - char ccname[KRB5_MAXCCH_CCNAME]; - - if (pNCi[i]->vers != CC_CRED_V5) - continue; - - if (FAILED(StringCchPrintfA(ccname, sizeof(ccname), "API:%s", - pNCi[i]->name))) - continue; - - code = (*pkrb5_cc_resolve)(ctx, ccname, &cache); - - if (code) - continue; - - code = get_tickets_from_cache(ctx, cache, &idl); - - if(ctx != NULL && cache != NULL) - (*pkrb5_cc_close)(ctx, cache); - - cache = 0; - } - - _skip_cc_iter: - - if (khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb) - == KHM_ERROR_TOO_LONG && - cb > sizeof(wchar_t) * 2) { - wchar_t * t; - char ccname[MAX_PATH + 6]; - - ms = PMALLOC(cb); -#ifdef DEBUG - assert(ms); -#endif - khc_read_multi_string(csp_params, L"FileCCList", ms, &cb); - - for(t = ms; t && *t; t = multi_string_next(t)) { - StringCchPrintfA(ccname, ARRAYLENGTH(ccname), - "FILE:%S", t); - - code = (*pkrb5_cc_resolve)(ctx, ccname, &cache); - - if (code) - continue; - - code = get_tickets_from_cache(ctx, cache, &idl); - - if (ctx != NULL && cache != NULL) - (*pkrb5_cc_close)(ctx, cache); - cache = 0; - } - - PFREE(ms); - } - - if (KHM_SUCCEEDED(khc_read_int32(csp_params, L"MsLsaList", &t)) && t) { - code = (*pkrb5_cc_resolve)(ctx, "MSLSA:", &cache); - - if (code == 0 && cache) { - code = get_tickets_from_cache(ctx, cache, &idl); - } - - if (ctx != NULL && cache != NULL) - (*pkrb5_cc_close)(ctx, cache); - cache = 0; - } - -_exit: - if (pNCi) - (*pcc_free_NC_info)(cc_ctx, &pNCi); - if (cc_ctx) - (*pcc_shutdown)(&cc_ctx); - - kcdb_credset_collect(NULL, krb5_credset, NULL, credtype_id_krb5, NULL); - tc_set_ident_data(&idl); - tc_free_idlist(&idl); - - return(code); -} - -int -khm_krb5_renew_cred(khm_handle cred) -{ - khm_handle identity = NULL; - krb5_error_code code = 0; - krb5_context ctx = NULL; - krb5_ccache cc = NULL; - krb5_principal me = NULL, server = NULL; - krb5_creds in_creds, cc_creds; - krb5_creds * out_creds = NULL; - - wchar_t wname[512]; - khm_size cbname; - char name[512]; - khm_boolean brenewIdentity = FALSE; - khm_boolean istgt = FALSE; - - khm_int32 flags; - - cbname = sizeof(wname); - kcdb_cred_get_name(cred, wname, &cbname); - _reportf(L"Krb5 renew cred for %s", wname); - - kcdb_cred_get_flags(cred, &flags); - - if (!(flags & KCDB_CRED_FLAG_INITIAL)) { - _reportf(L"Krb5 skipping renewal because this is not an initial credential"); - return 0; - } - - memset(&in_creds, 0, sizeof(in_creds)); - memset(&cc_creds, 0, sizeof(cc_creds)); - - 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; - - code = pkrb5_cc_get_principal(ctx, cc, &me); - if (code) - goto cleanup; - - cbname = sizeof(wname); - if (KHM_FAILED(kcdb_cred_get_name(cred, wname, &cbname))) - goto cleanup; - - UnicodeStrToAnsi(name, sizeof(name), wname); - - code = pkrb5_parse_name(ctx, name, &server); - if (code) - goto cleanup; - - in_creds.client = me; - in_creds.server = server; - -#ifdef KRB5_TC_NOTICKET - pkrb5_cc_set_flags(ctx, cc, 0); -#endif - - if (strlen("krbtgt") != krb5_princ_name(ctx, server)->length || - strncmp("krbtgt", krb5_princ_name(ctx, server)->data, krb5_princ_name(ctx, server)->length)) - { - code = pkrb5_get_renewed_creds(ctx, &cc_creds, me, cc, name); - if (code) { - code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &in_creds, &cc_creds); - if (code == 0) { - code = pkrb5_cc_remove_cred(ctx, cc, 0, &cc_creds); - if (code) { - brenewIdentity = TRUE; - goto cleanup; - } - } - } - - code = pkrb5_get_credentials(ctx, 0, cc, &in_creds, &out_creds); - } else { - istgt = TRUE; - code = pkrb5_get_renewed_creds(ctx, &cc_creds, me, cc, NULL); - } - -#ifdef KRB5_TC_NOTICKET - pkrb5_cc_set_flags(ctx, cc, KRB5_TC_NOTICKET); -#endif - if (code) { - if ( code != KRB5KDC_ERR_ETYPE_NOSUPP || - code != KRB5_KDC_UNREACH) - khm_krb5_error(code, "krb5_get_renewed_creds()", 0, &ctx, &cc); - goto cleanup; - } - - if (istgt) { - code = pkrb5_cc_initialize(ctx, cc, me); - if (code) goto cleanup; - - } - - code = pkrb5_cc_store_cred(ctx, cc, istgt ? &cc_creds : out_creds); - if (code) goto cleanup; - - - cleanup: - - if (in_creds.client == me) - in_creds.client = NULL; - if (in_creds.server == server) - in_creds.server = NULL; - - if (me) - pkrb5_free_principal(ctx, me); - - if (server) - pkrb5_free_principal(ctx, server); - - pkrb5_free_cred_contents(ctx, &in_creds); - pkrb5_free_cred_contents(ctx, &cc_creds); - - if (out_creds) - pkrb5_free_creds(ctx, out_creds); - - if (cc && ctx) - pkrb5_cc_close(ctx, cc); - - if (ctx) - pkrb5_free_context(ctx); - - if (identity) { - if (brenewIdentity) - code = khm_krb5_renew_ident(identity); - kcdb_identity_release(identity); - } - - return code; -} - -int -khm_krb5_renew_ident(khm_handle identity) -{ - krb5_error_code code = 0; - krb5_context ctx = NULL; - krb5_ccache cc = NULL; - krb5_principal me = NULL; - krb5_principal server = NULL; - krb5_creds my_creds; - krb5_data *realm = NULL; - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - khm_int32 k5_flags; - - memset(&my_creds, 0, sizeof(krb5_creds)); - - if ( !pkrb5_init_context ) - goto cleanup; - - cb = sizeof(idname); - kcdb_identity_get_name(identity, idname, &cb); - - if (khm_krb5_get_identity_flags(identity) & K5IDFLAG_IMPORTED) { -#ifndef NO_REIMPORT_MSLSA_CREDS - /* we are trying to renew the identity that was imported from - MSLSA: */ - BOOL imported; - BOOL retry_import = FALSE; - char cidname[KCDB_IDENT_MAXCCH_NAME]; - khm_handle imported_id = NULL; - khm_size cb; - FILETIME ft_expire; - FILETIME ft_now; - FILETIME ft_threshold; - krb5_principal princ = NULL; - - UnicodeStrToAnsi(cidname, sizeof(cidname), idname); - - imported = khm_krb5_ms2mit(cidname, FALSE, TRUE, &imported_id); - - if (imported == 0) - goto import_failed; - - /* if the imported identity has already expired or will soon, - we clear the cache and try again. */ - khm_krb5_list_tickets(&ctx); - - cb = sizeof(ft_expire); - if (KHM_FAILED(kcdb_identity_get_attr(imported_id, KCDB_ATTR_EXPIRE, - NULL, &ft_expire, &cb))) - goto import_failed; - - GetSystemTimeAsFileTime(&ft_now); - TimetToFileTimeInterval(5 * 60, &ft_threshold); - - ft_now = FtAdd(&ft_now, &ft_threshold); - - if (CompareFileTime(&ft_expire, &ft_now) < 0) { - /* the ticket lifetime is not long enough */ - - code = 0; - - if (ctx == NULL) - code = pkrb5_init_context(&ctx); - if (code) - goto import_failed; - - code = pkrb5_cc_resolve(ctx, "MSLSA:", &cc); - if (code) - goto import_failed; - - code = pkrb5_cc_get_principal(ctx, cc, &princ); - if (code) - goto import_failed; - - pkrb5_cc_initialize(ctx, cc, princ); - - retry_import = TRUE; - } - - import_failed: - - if (imported_id) { - kcdb_identity_release(imported_id); - imported_id = NULL; - } - - if (ctx) { - if (cc) { - pkrb5_cc_close(ctx, cc); - cc = NULL; - } - - if (princ) { - pkrb5_free_principal(ctx, princ); - princ = NULL; - } - - /* leave ctx so we can use it later */ - } - - if (retry_import) - imported = khm_krb5_ms2mit(cidname, FALSE, TRUE, NULL); - - if (imported) - goto cleanup; - - /* if the import failed, then we try to renew the identity via - the usual procedure. */ - -#else - /* if we are suppressing further imports from MSLSA, we just - skip renewing this identity. */ - goto cleanup; -#endif - } - - cb = sizeof(k5_flags); - if (KHM_SUCCEEDED(kcdb_identity_get_attr(identity, - attr_id_krb5_flags, - NULL, - &k5_flags, - &cb)) && - !(k5_flags & TKT_FLG_RENEWABLE)) { - - code = KRB5KDC_ERR_BADOPTION; - goto cleanup; - } - - { - FILETIME ft_now; - FILETIME ft_exp; - - cb = sizeof(ft_exp); - GetSystemTimeAsFileTime(&ft_now); - if (KHM_SUCCEEDED(kcdb_identity_get_attr(identity, - KCDB_ATTR_EXPIRE, - NULL, - &ft_exp, - &cb)) && - CompareFileTime(&ft_exp, &ft_now) < 0) { - - code = KRB5KRB_AP_ERR_TKT_EXPIRED; - goto cleanup; - - } - } - - code = khm_krb5_initialize(identity, &ctx, &cc); - if (code) - goto cleanup; - - code = pkrb5_cc_get_principal(ctx, cc, &me); - if (code) - goto cleanup; - - realm = krb5_princ_realm(ctx, me); - - code = pkrb5_build_principal_ext(ctx, &server, - realm->length,realm->data, - KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, - realm->length,realm->data, - 0); - - if (code) - goto cleanup; - - my_creds.client = me; - my_creds.server = server; - -#ifdef KRB5_TC_NOTICKET - pkrb5_cc_set_flags(ctx, cc, 0); -#endif - code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL); -#ifdef KRB5_TC_NOTICKET - pkrb5_cc_set_flags(ctx, cc, KRB5_TC_NOTICKET); -#endif - if (code) { - if ( code != KRB5KDC_ERR_ETYPE_NOSUPP || - code != KRB5_KDC_UNREACH) - khm_krb5_error(code, "krb5_get_renewed_creds()", 0, &ctx, &cc); - goto cleanup; - } - - code = pkrb5_cc_initialize(ctx, cc, me); - if (code) goto cleanup; - - code = pkrb5_cc_store_cred(ctx, cc, &my_creds); - if (code) goto cleanup; - -cleanup: - if (my_creds.client == me) - my_creds.client = NULL; - if (my_creds.server == server) - my_creds.server = NULL; - - if (ctx) { - pkrb5_free_cred_contents(ctx, &my_creds); - - if (me) - pkrb5_free_principal(ctx, me); - if (server) - pkrb5_free_principal(ctx, server); - if (cc) - pkrb5_cc_close(ctx, cc); - pkrb5_free_context(ctx); - } - - return(code); -} - -int -khm_krb5_kinit(krb5_context alt_ctx, - char * principal_name, - char * password, - char * ccache, - krb5_deltat lifetime, - DWORD forwardable, - DWORD proxiable, - krb5_deltat renew_life, - DWORD addressless, - DWORD publicIP, - krb5_prompter_fct prompter, - void * p_data) -{ - krb5_error_code code = 0; - krb5_context ctx = NULL; - krb5_ccache cc = NULL; - krb5_principal me = NULL; - char* name = NULL; - krb5_creds my_creds; - krb5_get_init_creds_opt options; - krb5_address ** addrs = NULL; - int i = 0, addr_count = 0; - - if (!pkrb5_init_context) - return 0; - - _reportf(L"In khm_krb5_kinit"); - - pkrb5_get_init_creds_opt_init(&options); - pkrb5_get_init_creds_opt_set_change_password_prompt(&options, 0); - - memset(&my_creds, 0, sizeof(my_creds)); - - if (alt_ctx) { - ctx = alt_ctx; - } else { - code = pkrb5_init_context(&ctx); - if (code) - goto cleanup; - } - - if (ccache) { - _reportf(L"Using supplied ccache name %S", ccache); - code = pkrb5_cc_resolve(ctx, ccache, &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); - if (code) goto cleanup; - - code = pkrb5_unparse_name(ctx, me, &name); - if (code) goto cleanup; - - if (lifetime == 0) { - khc_read_int32(csp_params, L"DefaultLifetime", &lifetime); - } - - if (lifetime) - pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime); - - pkrb5_get_init_creds_opt_set_forwardable(&options, - forwardable ? 1 : 0); - pkrb5_get_init_creds_opt_set_proxiable(&options, - proxiable ? 1 : 0); - pkrb5_get_init_creds_opt_set_renew_life(&options, - renew_life); - - if (addressless) - pkrb5_get_init_creds_opt_set_address_list(&options,NULL); - else { - 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); - } - - 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); - - addrs[i]->magic = KV5M_ADDRESS; - addrs[i]->addrtype = AF_INET; - addrs[i]->length = 4; - addrs[i]->contents = (unsigned char *)PMALLOC(addrs[i]->length); - if (!addrs[i]->contents) - assert(0); - - netIPAddr = htonl(publicIP); - memcpy(addrs[i]->contents,&netIPAddr,4); - } - - pkrb5_get_init_creds_opt_set_address_list(&options,addrs); - } - - code = - pkrb5_get_init_creds_password(ctx, - &my_creds, - me, - password, // password - prompter, // prompter - p_data, // prompter data - 0, // start time - 0, // service name - &options); - _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: - if ( addrs ) { - for ( i=0;icontents ) - PFREE(addrs[i]->contents); - PFREE(addrs[i]); - } - } - } - if (my_creds.client == me) - my_creds.client = 0; - pkrb5_free_cred_contents(ctx, &my_creds); - if (name) - pkrb5_free_unparsed_name(ctx, name); - if (me) - pkrb5_free_principal(ctx, me); - if (cc) - pkrb5_cc_close(ctx, cc); - if (ctx && (ctx != alt_ctx)) - pkrb5_free_context(ctx); - return(code); -} - -long -khm_krb5_copy_ccache_by_name(krb5_context in_ctx, - wchar_t * wscc_dest, - wchar_t * wscc_src) { - krb5_context ctx = NULL; - krb5_error_code code = 0; - khm_boolean free_ctx; - krb5_ccache cc_src = NULL; - krb5_ccache cc_dest = NULL; - krb5_principal princ_src = NULL; - char scc_dest[KRB5_MAXCCH_CCNAME]; - char scc_src[KRB5_MAXCCH_CCNAME]; - int t; - - t = UnicodeStrToAnsi(scc_dest, sizeof(scc_dest), wscc_dest); - if (t == 0) - return KHM_ERROR_TOO_LONG; - t = UnicodeStrToAnsi(scc_src, sizeof(scc_src), wscc_src); - if (t == 0) - return KHM_ERROR_TOO_LONG; - - if (in_ctx) { - ctx = in_ctx; - free_ctx = FALSE; - } else { - code = pkrb5_init_context(&ctx); - if (code) { - if (ctx) - pkrb5_free_context(ctx); - return code; - } - free_ctx = TRUE; - } - - code = pkrb5_cc_resolve(ctx, scc_dest, &cc_dest); - if (code) - goto _cleanup; - - code = pkrb5_cc_resolve(ctx, scc_src, &cc_src); - if (code) - goto _cleanup; - - code = pkrb5_cc_get_principal(ctx, cc_src, &princ_src); - if (code) - goto _cleanup; - - code = pkrb5_cc_initialize(ctx, cc_dest, princ_src); - if (code) - goto _cleanup; - - code = pkrb5_cc_copy_creds(ctx, cc_src, cc_dest); - - _cleanup: - if (princ_src) - pkrb5_free_principal(ctx, princ_src); - - if (cc_dest) - pkrb5_cc_close(ctx, cc_dest); - - if (cc_src) - pkrb5_cc_close(ctx, cc_src); - - if (free_ctx && ctx) - pkrb5_free_context(ctx); - - return code; -} - -long -khm_krb5_canon_cc_name(wchar_t * wcc_name, - size_t cb_cc_name) { - size_t cb_len; - wchar_t * colon; - - if (FAILED(StringCbLength(wcc_name, - cb_cc_name, - &cb_len))) { -#ifdef DEBUG - assert(FALSE); -#else - return KHM_ERROR_TOO_LONG; -#endif - } - - cb_len += sizeof(wchar_t); - - colon = wcschr(wcc_name, L':'); - - if (colon) { - /* if the colon is just 1 character away from the beginning, - it's a FILE: cc */ - if (colon - wcc_name == 1) { - if (cb_len + 5 * sizeof(wchar_t) > cb_cc_name) - return KHM_ERROR_TOO_LONG; - - memmove(&wcc_name[5], &wcc_name[0], cb_len); - memmove(&wcc_name[0], L"FILE:", sizeof(wchar_t) * 5); - } - - return 0; - } - - if (cb_len + 4 * sizeof(wchar_t) > cb_cc_name) - return KHM_ERROR_TOO_LONG; - - memmove(&wcc_name[4], &wcc_name[0], cb_len); - memmove(&wcc_name[0], L"API:", sizeof(wchar_t) * 4); - - return 0; -} - -int -khm_krb5_cc_name_cmp(const wchar_t * cc_name_1, - const wchar_t * cc_name_2) { - if (!wcsncmp(cc_name_1, L"API:", 4)) - cc_name_1 += 4; - - if (!wcsncmp(cc_name_2, L"API:", 4)) - cc_name_2 += 4; - - return wcscmp(cc_name_1, cc_name_2); -} - -static khm_int32 KHMAPI -khmint_location_comp_func(khm_handle cred1, - khm_handle cred2, - void * rock) { - return kcdb_creds_comp_attr(cred1, cred2, KCDB_ATTR_LOCATION); -} - -struct khmint_location_check { - khm_handle credset; - khm_handle cred; - wchar_t * ccname; - khm_boolean success; -}; - -static khm_int32 KHMAPI -khmint_find_matching_cred_func(khm_handle cred, - void * rock) { - struct khmint_location_check * lc; - - lc = (struct khmint_location_check *) rock; - - if (!kcdb_creds_is_equal(cred, lc->cred)) - return KHM_ERROR_SUCCESS; - if (kcdb_creds_comp_attr(cred, lc->cred, KCDB_ATTR_LOCATION)) - return KHM_ERROR_SUCCESS; - - /* found it */ - lc->success = TRUE; - - /* break the search */ - return !KHM_ERROR_SUCCESS; -} - -static khm_int32 KHMAPI -khmint_location_check_func(khm_handle cred, - void * rock) { - khm_int32 t; - khm_size cb; - wchar_t ccname[KRB5_MAXCCH_CCNAME]; - struct khmint_location_check * lc; - - lc = (struct khmint_location_check *) rock; - - if (KHM_FAILED(kcdb_cred_get_type(cred, &t))) - return KHM_ERROR_SUCCESS; - - if (t != credtype_id_krb5) - return KHM_ERROR_SUCCESS; - - cb = sizeof(ccname); - if (KHM_FAILED(kcdb_cred_get_attr(cred, - KCDB_ATTR_LOCATION, - NULL, - ccname, - &cb))) - return KHM_ERROR_SUCCESS; - - if(wcscmp(ccname, lc->ccname)) - return KHM_ERROR_SUCCESS; - - lc->cred = cred; - - lc->success = FALSE; - - kcdb_credset_apply(lc->credset, - khmint_find_matching_cred_func, - (void *) lc); - - if (!lc->success) - return KHM_ERROR_NOT_FOUND; - else - return KHM_ERROR_SUCCESS; -} - -static khm_int32 KHMAPI -khmint_delete_location_func(khm_handle cred, - void * rock) { - wchar_t cc_cred[KRB5_MAXCCH_CCNAME]; - struct khmint_location_check * lc; - khm_size cb; - - lc = (struct khmint_location_check *) rock; - - cb = sizeof(cc_cred); - - if (KHM_FAILED(kcdb_cred_get_attr(cred, - KCDB_ATTR_LOCATION, - NULL, - cc_cred, - &cb))) - return KHM_ERROR_SUCCESS; - - if (wcscmp(cc_cred, lc->ccname)) - return KHM_ERROR_SUCCESS; - - kcdb_credset_del_cred_ref(lc->credset, - cred); - - return KHM_ERROR_SUCCESS; -} - -int -khm_krb5_destroy_by_credset(khm_handle p_cs) -{ - khm_handle d_cs = NULL; - khm_int32 rv = KHM_ERROR_SUCCESS; - khm_size s, cb; - krb5_context ctx = NULL; - krb5_error_code code = 0; - int i; - wchar_t ccname[KRB5_MAXCCH_CCNAME]; - struct khmint_location_check lc; - - rv = kcdb_credset_create(&d_cs); - - assert(KHM_SUCCEEDED(rv) && d_cs != NULL); - - kcdb_credset_extract(d_cs, p_cs, NULL, credtype_id_krb5); - - kcdb_credset_get_size(d_cs, &s); - - if (s == 0) { - _reportf(L"No tickets to delete"); - - kcdb_credset_delete(d_cs); - return 0; - } - - code = pkrb5_init_context(&ctx); - if (code != 0) { - rv = code; - goto _cleanup; - } - - /* we should synchronize the credential lists before we attempt to - make any assumptions on the state of the root credset */ - khm_krb5_list_tickets(&ctx); - - /* so, we need to make a decision about whether to destroy entire - ccaches or just individual credentials. Therefore we first - sort them by ccache. */ - kcdb_credset_sort(d_cs, - khmint_location_comp_func, - NULL); - - /* now, for each ccache we encounter, we check if we have all the - credentials from that ccache in the to-be-deleted list. */ - for (i=0; i < (int) s; i++) { - khm_handle cred; - - if (KHM_FAILED(kcdb_credset_get_cred(d_cs, - i, - &cred))) - continue; - - cb = sizeof(ccname); - rv = kcdb_cred_get_attr(cred, - KCDB_ATTR_LOCATION, - NULL, - ccname, - &cb); - -#ifdef DEBUG - assert(KHM_SUCCEEDED(rv)); -#endif - kcdb_cred_release(cred); - - lc.credset = d_cs; - lc.cred = NULL; - lc.ccname = ccname; - lc.success = FALSE; - - kcdb_credset_apply(NULL, - khmint_location_check_func, - (void *) &lc); - - if (lc.success) { - /* ok the destroy the ccache */ - char a_ccname[KRB5_MAXCCH_CCNAME]; - krb5_ccache cc = NULL; - - _reportf(L"Destroying ccache [%s]", ccname); - - UnicodeStrToAnsi(a_ccname, - sizeof(a_ccname), - ccname); - - code = pkrb5_cc_resolve(ctx, - a_ccname, - &cc); - if (code) - goto _delete_this_set; - - code = pkrb5_cc_destroy(ctx, cc); - - if (code) { - _reportf(L"krb5_cc_destroy returns code %d", code); - } - - _delete_this_set: - - lc.credset = d_cs; - lc.ccname = ccname; - - /* note that although we are deleting credentials off the - credential set, the size of the credential set does not - decrease since we are doing it from inside - kcdb_credset_apply(). The deleted creds will simply be - marked as deleted until kcdb_credset_purge() is - called. */ - - kcdb_credset_apply(d_cs, - khmint_delete_location_func, - (void *) &lc); - } - } - - kcdb_credset_purge(d_cs); - - /* the remainder need to be deleted one by one */ - - kcdb_credset_get_size(d_cs, &s); - - for (i=0; i < (int) s; ) { - khm_handle cred; - char a_ccname[KRB5_MAXCCH_CCNAME]; - char a_srvname[KCDB_CRED_MAXCCH_NAME]; - wchar_t srvname[KCDB_CRED_MAXCCH_NAME]; - krb5_ccache cc; - krb5_creds in_cred, out_cred; - krb5_principal princ; - khm_int32 etype; - - if (KHM_FAILED(kcdb_credset_get_cred(d_cs, - i, - &cred))) { - i++; - continue; - } - - cb = sizeof(ccname); - if (KHM_FAILED(kcdb_cred_get_attr(cred, - KCDB_ATTR_LOCATION, - NULL, - ccname, - &cb))) - goto _done_with_this_cred; - - _reportf(L"Looking at ccache [%s]", ccname); - - UnicodeStrToAnsi(a_ccname, - sizeof(a_ccname), - ccname); - - code = pkrb5_cc_resolve(ctx, - a_ccname, - &cc); - - if (code) - goto _skip_similar; - - code = pkrb5_cc_get_principal(ctx, cc, &princ); - - if (code) { - pkrb5_cc_close(ctx, cc); - goto _skip_similar; - } - - _del_this_cred: - - cb = sizeof(etype); - - if (KHM_FAILED(kcdb_cred_get_attr(cred, - attr_id_key_enctype, - NULL, - &etype, - &cb))) - goto _do_next_cred; - - cb = sizeof(srvname); - if (KHM_FAILED(kcdb_cred_get_name(cred, - srvname, - &cb))) - goto _do_next_cred; - - _reportf(L"Attempting to delete ticket %s", srvname); - - UnicodeStrToAnsi(a_srvname, sizeof(a_srvname), srvname); - - ZeroMemory(&in_cred, sizeof(in_cred)); - - code = pkrb5_parse_name(ctx, a_srvname, &in_cred.server); - if (code) - goto _do_next_cred; - in_cred.client = princ; - in_cred.keyblock.enctype = etype; - - code = pkrb5_cc_retrieve_cred(ctx, - cc, - KRB5_TC_MATCH_SRV_NAMEONLY | - KRB5_TC_SUPPORTED_KTYPES, - &in_cred, - &out_cred); - if (code) - goto _do_next_cred_0; - - code = pkrb5_cc_remove_cred(ctx, cc, - KRB5_TC_MATCH_SRV_NAMEONLY | - KRB5_TC_SUPPORTED_KTYPES | - KRB5_TC_MATCH_AUTHDATA, - &out_cred); - - pkrb5_free_cred_contents(ctx, &out_cred); - _do_next_cred_0: - pkrb5_free_principal(ctx, in_cred.server); - _do_next_cred: - - /* check if the next cred is also of the same ccache */ - kcdb_cred_release(cred); - - for (i++; i < (int) s; i++) { - if (KHM_FAILED(kcdb_credset_get_cred(d_cs, - i, - &cred))) - continue; - } - - if (i < (int) s) { - wchar_t newcc[KRB5_MAXCCH_CCNAME]; - - cb = sizeof(newcc); - if (KHM_FAILED(kcdb_cred_get_attr(cred, - KCDB_ATTR_LOCATION, - NULL, - newcc, - &cb)) || - wcscmp(newcc, ccname)) { - i--; /* we have to look at this again */ - goto _done_with_this_set; - } - goto _del_this_cred; - } - - - _done_with_this_set: - pkrb5_free_principal(ctx, princ); - - pkrb5_cc_close(ctx, cc); - - _done_with_this_cred: - kcdb_cred_release(cred); - i++; - continue; - - _skip_similar: - kcdb_cred_release(cred); - - for (++i; i < (int) s; i++) { - wchar_t newcc[KRB5_MAXCCH_CCNAME]; - - if (KHM_FAILED(kcdb_credset_get_cred(d_cs, - i, - &cred))) - continue; - - cb = sizeof(newcc); - if (KHM_FAILED(kcdb_cred_get_attr(cred, - KCDB_ATTR_LOCATION, - NULL, - &newcc, - &cb))) { - kcdb_cred_release(cred); - continue; - } - - if (wcscmp(newcc, ccname)) { - kcdb_cred_release(cred); - break; - } - } - } - - _cleanup: - - if (d_cs) - kcdb_credset_delete(&d_cs); - - if (ctx != NULL) - pkrb5_free_context(ctx); - - return rv; -} - -int -khm_krb5_destroy_identity(khm_handle identity) -{ - krb5_context ctx; - krb5_ccache cache; - krb5_error_code rc; - - ctx = NULL; - cache = NULL; - - if (rc = khm_krb5_initialize(identity, &ctx, &cache)) - return(rc); - - rc = pkrb5_cc_destroy(ctx, cache); - - if (ctx != NULL) - pkrb5_free_context(ctx); - - return(rc); -} - -static BOOL -GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData) -{ - NTSTATUS Status = 0; - HANDLE TokenHandle; - TOKEN_STATISTICS Stats; - DWORD ReqLen; - BOOL Success; - - if (!ppSessionData) - return FALSE; - *ppSessionData = NULL; - - Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle ); - if ( !Success ) - return FALSE; - - Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen ); - CloseHandle( TokenHandle ); - if ( !Success ) - return FALSE; - - Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData ); - if ( FAILED(Status) || !ppSessionData ) - return FALSE; - - return TRUE; -} - -// IsKerberosLogon() does not validate whether or not there are valid -// tickets in the cache. It validates whether or not it is reasonable -// to assume that if we attempted to retrieve valid tickets we could -// do so. Microsoft does not automatically renew expired tickets. -// Therefore, the cache could contain expired or invalid tickets. -// Microsoft also caches the user's password and will use it to -// retrieve new TGTs if the cache is empty and tickets are requested. - -static BOOL -IsKerberosLogon(VOID) -{ - PSECURITY_LOGON_SESSION_DATA pSessionData = NULL; - BOOL Success = FALSE; - - if ( GetSecurityLogonSessionData(&pSessionData) ) { - if ( pSessionData->AuthenticationPackage.Buffer ) { - WCHAR buffer[256]; - WCHAR *usBuffer; - int usLength; - - Success = FALSE; - usBuffer = (pSessionData->AuthenticationPackage).Buffer; - usLength = (pSessionData->AuthenticationPackage).Length; - if (usLength < 256) - { - lstrcpynW (buffer, usBuffer, usLength); - StringCbCatW (buffer, sizeof(buffer), L""); - if ( !lstrcmpW(L"Kerberos",buffer) ) - Success = TRUE; - } - } - pLsaFreeReturnBuffer(pSessionData); - } - return Success; -} - - -BOOL -khm_krb5_ms2mit(char * match_princ, BOOL match_realm, BOOL save_creds, - khm_handle * ret_ident) -{ -#ifdef NO_KRB5 - return(FALSE); -#else /* NO_KRB5 */ - krb5_context kcontext = 0; - krb5_error_code code = 0; - krb5_ccache ccache=0; - krb5_ccache mslsa_ccache=0; - krb5_creds creds; - krb5_cc_cursor cursor=0; - krb5_principal princ = 0; - khm_handle ident = NULL; - wchar_t wname[KCDB_IDENT_MAXCCH_NAME]; - char cname[KCDB_IDENT_MAXCCH_NAME]; - char *cache_name = NULL; - char *princ_name = NULL; - BOOL rc = FALSE; - - kherr_reportf(L"Begin : khm_krb5_ms2mit. save_cred=%d\n", (int) save_creds); - - if ( !pkrb5_init_context ) - goto cleanup; - - if (code = pkrb5_init_context(&kcontext)) - goto cleanup; - - kherr_reportf(L"Resolving MSLSA\n"); - - if (code = pkrb5_cc_resolve(kcontext, "MSLSA:", &mslsa_ccache)) - goto cleanup; - - if ( save_creds ) { - kherr_reportf(L"Getting principal\n"); - if (code = pkrb5_cc_get_principal(kcontext, mslsa_ccache, &princ)) - goto cleanup; - - kherr_reportf(L"Unparsing name\n"); - if (code = pkrb5_unparse_name(kcontext, princ, &princ_name)) - goto cleanup; - - AnsiStrToUnicode(wname, sizeof(wname), princ_name); - - kherr_reportf(L"Unparsed name [%s]", wname); - - /* see if we have to match a specific principal */ - if (match_princ != NULL) { - if (strcmp(princ_name, match_princ)) { - kherr_reportf(L"Principal mismatch. Wanted [%S], found [%S]", - match_princ, princ_name); - goto cleanup; - } - } else if (match_realm) { - wchar_t * wdefrealm; - char defrealm[256]; - krb5_data * princ_realm; - - wdefrealm = khm_krb5_get_default_realm(); - if (wdefrealm == NULL) { - kherr_reportf(L"Can't determine default realm"); - goto cleanup; - } - - princ_realm = krb5_princ_realm(kcontext, princ); - UnicodeStrToAnsi(defrealm, sizeof(defrealm), wdefrealm); - - if (strncmp(defrealm, princ_realm->data, princ_realm->length)) { - kherr_reportf(L"Realm mismatch. Wanted [%S], found [%*S]", - defrealm, princ_realm->length, princ_realm->data); - PFREE(wdefrealm); - goto cleanup; - } - - PFREE(wdefrealm); - } - - if (KHM_SUCCEEDED(kcdb_identity_create(wname, - KCDB_IDENT_FLAG_CREATE, - &ident))) { - khm_handle idconfig = NULL; - khm_handle k5config = NULL; - khm_size cb; - - wname[0] = L'\0'; - - kcdb_identity_get_config(ident, KHM_FLAG_CREATE, &idconfig); - if (idconfig == NULL) - goto _done_checking_config; - - khc_open_space(idconfig, CSNAME_KRB5CRED, KHM_FLAG_CREATE, &k5config); - if (k5config == NULL) - goto _done_checking_config; - - cb = sizeof(wname); - khc_read_string(k5config, - L"DefaultCCName", - wname, &cb); - - _done_checking_config: - - if (idconfig) - khc_close_space(idconfig); - if (k5config) - khc_close_space(k5config); - - if (wname[0]) { - UnicodeStrToAnsi(cname, sizeof(cname), wname); - } else { - StringCbPrintfA(cname, sizeof(cname), "API:%s", princ_name); - } - - cache_name = cname; - - } else { - /* the identity could not be created. we just use the - name of the principal as the ccache name. */ - StringCbPrintfA(cname, sizeof(cname), "API:%s", princ_name); - cache_name = cname; - } - - kherr_reportf(L"Resolving target cache [%S]\n", cache_name); - - if (code = pkrb5_cc_resolve(kcontext, cache_name, &ccache)) { - kherr_reportf(L"Cannot resolve cache [%S] with code=%d. Trying default.\n", cache_name, code); - - if (code = pkrb5_cc_default(kcontext, &ccache)) { - kherr_reportf(L"Failed to resolve default ccache. Code=%d", code); - goto cleanup; - } - } - - kherr_reportf(L"Initializing ccache\n"); - if (code = pkrb5_cc_initialize(kcontext, ccache, princ)) - goto cleanup; - - kherr_reportf(L"Copying credentials\n"); - if (code = pkrb5_cc_copy_creds(kcontext, mslsa_ccache, ccache)) - goto cleanup; - - /* and mark the identity as having been imported */ - if (ident) { - khm_krb5_set_identity_flags(ident, K5IDFLAG_IMPORTED, K5IDFLAG_IMPORTED); - - if (ret_ident) { - *ret_ident = ident; - kcdb_identity_hold(*ret_ident); - } - } - - rc = TRUE; - - } else { - /* Enumerate tickets from cache looking for an initial ticket */ - if ((code = pkrb5_cc_start_seq_get(kcontext, mslsa_ccache, &cursor))) - goto cleanup; - - while (!(code = pkrb5_cc_next_cred(kcontext, mslsa_ccache, - &cursor, &creds))) { - if ( creds.ticket_flags & TKT_FLG_INITIAL ) { - rc = TRUE; - pkrb5_free_cred_contents(kcontext, &creds); - break; - } - pkrb5_free_cred_contents(kcontext, &creds); - } - pkrb5_cc_end_seq_get(kcontext, mslsa_ccache, &cursor); - } - -cleanup: - kherr_reportf(L" Received code=%d", code); - - if (princ_name) - pkrb5_free_unparsed_name(kcontext, princ_name); - if (princ) - pkrb5_free_principal(kcontext, princ); - if (ccache) - pkrb5_cc_close(kcontext, ccache); - if (mslsa_ccache) - pkrb5_cc_close(kcontext, mslsa_ccache); - if (kcontext) - pkrb5_free_context(kcontext); - if (ident) - kcdb_identity_release(ident); - - return(rc); -#endif /* NO_KRB5 */ -} - -#define KRB_FILE "KRB.CON" -#define KRBREALM_FILE "KRBREALM.CON" -#define KRB5_FILE "KRB5.INI" -#define KRB5_TMP_FILE "KRB5.INI.TMP" - -BOOL -khm_krb5_get_temp_profile_file(LPSTR confname, UINT szConfname) -{ - GetTempPathA(szConfname, confname); - confname[szConfname-1] = '\0'; - StringCchCatA(confname, szConfname, KRB5_TMP_FILE); - confname[szConfname-1] = '\0'; - return FALSE; -} - -#ifdef NOT_QUITE_IMPLEMENTED_YET -BOOL -khm_krb5_set_profile_file(krb5_context ctx, LPSTR confname) -{ - char *conffiles[2]; - - if (confname == NULL || - pkrb5_set_config_files == NULL || - ctx == NULL) - return FALSE; - - conffiles[0] = confname; - conffiles[1] = NULL; - - if (pkrb5_set_config_files(ctx, conffiles)) - return FALSE; - else - return TRUE; -} -#endif - -BOOL -khm_krb5_get_profile_file(LPSTR confname, UINT szConfname) -{ - char **configFile = NULL; - if (pkrb5_get_default_config_files(&configFile)) - { - GetWindowsDirectoryA(confname,szConfname); - confname[szConfname-1] = '\0'; - - StringCchCatA(confname, szConfname, "\\"); - StringCchCatA(confname, szConfname, KRB5_FILE); - - return FALSE; - } - - *confname = 0; - - if (configFile) - { - StringCchCopyA(confname, szConfname, *configFile); - pkrb5_free_config_files(configFile); - } - - if (!*confname) - { - GetWindowsDirectoryA(confname,szConfname); - confname[szConfname-1] = '\0'; - StringCchCatA(confname, szConfname, "\\"); - StringCchCatA(confname, szConfname, KRB5_FILE); - } - - return FALSE; -} - -BOOL -khm_get_krb4_con_file(LPSTR confname, UINT szConfname) -{ - if (hKrb5 && !hKrb4) { // hold krb.con where krb5.ini is located - CHAR krbConFile[MAX_PATH]=""; - LPSTR pFind; - - //strcpy(krbConFile, CLeashApp::m_krbv5_profile->first_file->filename); - if (khm_krb5_get_profile_file(krbConFile, sizeof(krbConFile))) { - GetWindowsDirectoryA(krbConFile,sizeof(krbConFile)); - krbConFile[MAX_PATH-1] = '\0'; - StringCchCatA(confname, szConfname, "\\"); - } - - pFind = strrchr(krbConFile, '\\'); - if (pFind) { - *pFind = '\0'; - StringCchCatA(krbConFile, ARRAYLENGTH(krbConFile), "\\"); - StringCchCatA(krbConFile, ARRAYLENGTH(krbConFile), KRB_FILE); - } - else - krbConFile[0] = '\0'; - - StringCchCopyA(confname, szConfname, krbConFile); - } - else if (hKrb4) { - unsigned int size = szConfname; - memset(confname, '\0', szConfname); - if (!pkrb_get_krbconf2(confname, &size)) - { // Error has happened - GetWindowsDirectoryA(confname,szConfname); - confname[szConfname-1] = '\0'; - StringCchCatA(confname, szConfname, "\\"); - StringCchCatA(confname, szConfname, KRB_FILE); - } - } - return FALSE; -} - -int -readstring(FILE * file, char * buf, int len) -{ - int c,i; - memset(buf, '\0', sizeof(buf)); - for (i=0, c=fgetc(file); c != EOF ; c=fgetc(file), i++) { - if (i < sizeof(buf)) { - if (c == '\n') { - buf[i] = '\0'; - return i; - } else { - buf[i] = c; - } - } else { - if (c == '\n') { - buf[len-1] = '\0'; - return(i); - } - } - } - if (c == EOF) { - if (i > 0 && i < len) { - buf[i] = '\0'; - return(i); - } else { - buf[len-1] = '\0'; - return(-1); - } - } - return(-1); -} - -/*! \internal - \brief Return a list of configured realms - - The string that is returned is a set of null terminated unicode - strings, each of which denotes one realm. The set is terminated - by a zero length null terminated string. - - The caller should free the returned string using free() - - \return The string with the list of realms or NULL if the - operation fails. -*/ -wchar_t * -khm_krb5_get_realm_list(void) -{ - wchar_t * rlist = NULL; - - if (pprofile_get_subsection_names && pprofile_free_list) { - const char* rootSection[] = {"realms", NULL}; - const char** rootsec = rootSection; - char **sections = NULL, **cpp = NULL, *value = NULL; - - char krb5_conf[MAX_PATH+1]; - - if (!khm_krb5_get_profile_file(krb5_conf,sizeof(krb5_conf))) { - profile_t profile; - long retval; - const char *filenames[2]; - wchar_t * d; - size_t cbsize; - size_t t; - - filenames[0] = krb5_conf; - filenames[1] = NULL; - retval = pprofile_init(filenames, &profile); - if (!retval) { - retval = pprofile_get_subsection_names(profile, rootsec, - §ions); - - if (!retval) - { - /* first figure out how much space to allocate */ - cbsize = 0; - for (cpp = sections; *cpp; cpp++) - { - cbsize += sizeof(wchar_t) * (strlen(*cpp) + 1); - } - cbsize += sizeof(wchar_t); /* double null terminated */ - - rlist = PMALLOC(cbsize); - d = rlist; - for (cpp = sections; *cpp; cpp++) - { - AnsiStrToUnicode(d, cbsize, *cpp); - t = wcslen(d) + 1; - d += t; - cbsize -= sizeof(wchar_t) * t; - } - *d = L'\0'; - } - - pprofile_free_list(sections); - -#if 0 - retval = pprofile_get_string(profile, "libdefaults","noaddresses", 0, "true", &value); - if ( value ) { - disable_noaddresses = config_boolean_to_int(value); - pprofile_release_string(value); - } -#endif - pprofile_release(profile); - } - } - } else { - FILE * file; - char krb_conf[MAX_PATH+1]; - char * p; - size_t cbsize, t; - wchar_t * d; - - if (!khm_get_krb4_con_file(krb_conf,sizeof(krb_conf)) && -#if _MSC_VER >= 1400 - !fopen_s(&file, krb_conf, "rt") -#else - (file = fopen(krb_conf, "rt")) -#endif - ) - { - char lineBuf[256]; - - /*TODO: compute the actual required buffer size instead of hardcoding */ - cbsize = 16384; // arbitrary - rlist = PMALLOC(cbsize); - d = rlist; - - // Skip the default realm - readstring(file,lineBuf,sizeof(lineBuf)); - - // Read the defined realms - while (TRUE) - { - if (readstring(file,lineBuf,sizeof(lineBuf)) < 0) - break; - - if (*(lineBuf + strlen(lineBuf) - 1) == '\r') - *(lineBuf + strlen(lineBuf) - 1) = 0; - - for (p=lineBuf; *p ; p++) - { - if (isspace(*p)) { - *p = 0; - break; - } - } - - if ( strncmp(".KERBEROS.OPTION.",lineBuf,17) ) { - t = strlen(lineBuf) + 1; - if(cbsize > (1 + t*sizeof(wchar_t))) { - AnsiStrToUnicode(d, cbsize, lineBuf); - d += t; - cbsize -= t * sizeof(wchar_t); - } else - break; - } - } - - *d = L'\0'; - - fclose(file); - } - } - - return rlist; -} - -/*! \internal - \brief Get the default realm - - A string will be returned that specifies the default realm. The - caller should free the string using PFREE(). - - Returns NULL if the operation fails. -*/ -wchar_t * -khm_krb5_get_default_realm(void) -{ - wchar_t * realm; - size_t cch; - krb5_context ctx=0; - char * def = 0; - - pkrb5_init_context(&ctx); - - if (ctx == 0) - return NULL; - - pkrb5_get_default_realm(ctx,&def); - - if (def) { - cch = strlen(def) + 1; - realm = PMALLOC(sizeof(wchar_t) * cch); - AnsiStrToUnicode(realm, sizeof(wchar_t) * cch, def); - pkrb5_free_default_realm(ctx, def); - } else - realm = NULL; - - pkrb5_free_context(ctx); - - return realm; -} - -long -khm_krb5_set_default_realm(wchar_t * realm) { - krb5_context ctx=0; - char * def = 0; - long rv = 0; - char astr[K5_MAXCCH_REALM]; - - UnicodeStrToAnsi(astr, sizeof(astr), realm); - - pkrb5_init_context(&ctx); - pkrb5_get_default_realm(ctx,&def); - - if ((def && strcmp(def, astr)) || - !def) { - rv = pkrb5_set_default_realm(ctx, astr); - } - - if (def) { - pkrb5_free_default_realm(ctx, def); - } - - pkrb5_free_context(ctx); - - return rv; -} - -wchar_t * -khm_get_realm_from_princ(wchar_t * princ) { - wchar_t * t; - - if(!princ) - return NULL; - - for (t = princ; *t; t++) { - if(*t == L'\\') { /* escape */ - t++; - if(! *t) /* malformed */ - break; - } else if (*t == L'@') - break; - } - - if (*t == '@' && *(t+1) != L'\0') - return (t+1); - else - return NULL; -} - -long -khm_krb5_changepwd(char * principal, - char * password, - char * newpassword, - char** error_str) -{ - krb5_error_code rc = 0; - int result_code = 0; - krb5_data result_code_string, result_string; - krb5_context context = 0; - krb5_principal princ = 0; - krb5_get_init_creds_opt opts; - krb5_creds creds; - - result_string.data = 0; - result_code_string.data = 0; - - if ( !pkrb5_init_context ) - goto cleanup; - - if (rc = pkrb5_init_context(&context)) { - goto cleanup; - } - - if (rc = pkrb5_parse_name(context, principal, &princ)) { - goto cleanup; - } - - pkrb5_get_init_creds_opt_init(&opts); - pkrb5_get_init_creds_opt_set_tkt_life(&opts, 5*60); - pkrb5_get_init_creds_opt_set_renew_life(&opts, 0); - pkrb5_get_init_creds_opt_set_forwardable(&opts, 0); - pkrb5_get_init_creds_opt_set_proxiable(&opts, 0); - pkrb5_get_init_creds_opt_set_address_list(&opts,NULL); - - if (rc = pkrb5_get_init_creds_password(context, &creds, princ, - password, 0, 0, 0, - "kadmin/changepw", &opts)) { - if (rc == KRB5KRB_AP_ERR_BAD_INTEGRITY) { -#if 0 - com_err(argv[0], 0, - "Password incorrect while getting initial ticket"); -#endif - } else { -#if 0 - com_err(argv[0], ret, "getting initial ticket"); -#endif - } - goto cleanup; - } - - if (rc = pkrb5_change_password(context, &creds, newpassword, - &result_code, &result_code_string, - &result_string)) { -#if 0 - com_err(argv[0], ret, "changing password"); -#endif - goto cleanup; - } - - if (result_code) { - int len = result_code_string.length + - (result_string.length ? (sizeof(": ") - 1) : 0) + - result_string.length; - if (len && error_str) { - *error_str = PMALLOC(len + 1); - if (*error_str) - StringCchPrintfA(*error_str, len+1, - "%.*s%s%.*s", - result_code_string.length, - result_code_string.data, - result_string.length?": ":"", - result_string.length, - result_string.data); - } - rc = result_code; - goto cleanup; - } - - cleanup: - if (result_string.data) - pkrb5_free_data_contents(context, &result_string); - - if (result_code_string.data) - pkrb5_free_data_contents(context, &result_code_string); - - if (princ) - pkrb5_free_principal(context, princ); - - if (context) - pkrb5_free_context(context); - - return rc; -} - -khm_int32 KHMAPI -khm_krb5_creds_is_equal(khm_handle vcred1, khm_handle vcred2, void * dummy) { - if (kcdb_creds_comp_attr(vcred1, vcred2, KCDB_ATTR_LOCATION) || - kcdb_creds_comp_attr(vcred1, vcred2, attr_id_key_enctype) || - kcdb_creds_comp_attr(vcred1, vcred2, attr_id_tkt_enctype) || - kcdb_creds_comp_attr(vcred1, vcred2, attr_id_kvno)) - return 1; - else - return 0; -} - -void -khm_krb5_set_identity_flags(khm_handle identity, - khm_int32 flag_mask, - khm_int32 flag_value) { - - khm_int32 t = 0; - khm_size cb; - - cb = sizeof(t); - if (KHM_FAILED(kcdb_identity_get_attr(identity, - attr_id_krb5_idflags, - NULL, - &t, &cb))) { - t = 0; - } - - t &= ~flag_mask; - t |= (flag_value & flag_mask); - - kcdb_identity_set_attr(identity, - attr_id_krb5_idflags, - &t, sizeof(t)); -} - -khm_int32 -khm_krb5_get_identity_flags(khm_handle identity) { - khm_int32 t = 0; - khm_size cb; - - cb = sizeof(t); - kcdb_identity_get_attr(identity, - attr_id_krb5_idflags, - NULL, &t, &cb); - - return t; -} - -long -khm_krb5_get_temp_ccache(krb5_context ctx, - krb5_ccache * prcc) { - int rnd = rand(); - char ccname[MAX_PATH]; - long code = 0; - krb5_ccache cc = 0; - - StringCbPrintfA(ccname, sizeof(ccname), "MEMORY:TempCache%8x", rnd); - - code = pkrb5_cc_resolve(ctx, ccname, &cc); - - if (code == 0) - *prcc = cc; - - return code; -} - -/* - - The configuration information for each identity comes from a - multitude of layers organized as follows. The ordering is - decreasing in priority. When looking up a value, the value will be - looked up in each layer in turn starting at level 0. The first - instance of the value found will be the effective value. - - 0 : \Krb5Cred - - 0.1: per user - - 0.2: per machine - - 1 : \Parameters\Realms\ - - 1.1: per user - - 1.2: per machine - - 2 : \Parameters - - 2.1: per user - - 2.2: per machine - - 2.3: schema - - */ -khm_int32 -khm_krb5_get_identity_config(khm_handle ident, - khm_int32 flags, - khm_handle * ret_csp) { - - khm_int32 rv = KHM_ERROR_SUCCESS; - khm_handle csp_i = NULL; - khm_handle csp_ik5 = NULL; - khm_handle csp_realms = NULL; - khm_handle csp_realm = NULL; - khm_handle csp_plugins = NULL; - khm_handle csp_krbcfg = NULL; - khm_handle csp_rv = NULL; - wchar_t realm[KCDB_IDENT_MAXCCH_NAME]; - - realm[0] = L'\0'; - - if (ident) { - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - wchar_t * trealm; - khm_size cb_idname = sizeof(idname); - - rv = kcdb_identity_get_name(ident, idname, &cb_idname); - if (KHM_SUCCEEDED(rv) && - (trealm = khm_get_realm_from_princ(idname)) != NULL) { - StringCbCopy(realm, sizeof(realm), trealm); - } - } - - if (ident) { - rv = kcdb_identity_get_config(ident, flags, &csp_i); - if (KHM_FAILED(rv)) - goto try_realm; - - rv = khc_open_space(csp_i, CSNAME_KRB5CRED, flags, &csp_ik5); - if (KHM_FAILED(rv)) - goto try_realm; - - try_realm: - - if (realm[0] == L'\0') - goto done_shadow_realm; - - rv = khc_open_space(csp_params, CSNAME_REALMS, flags, &csp_realms); - if (KHM_FAILED(rv)) - goto done_shadow_realm; - - rv = khc_open_space(csp_realms, realm, flags, &csp_realm); - if (KHM_FAILED(rv)) - goto done_shadow_realm; - - rv = khc_shadow_space(csp_realm, csp_params); - - done_shadow_realm: - - if (csp_ik5) { - if (csp_realm) - rv = khc_shadow_space(csp_ik5, csp_realm); - else - rv = khc_shadow_space(csp_ik5, csp_params); - - csp_rv = csp_ik5; - } else { - if (csp_realm) - csp_rv = csp_realm; - } - } - - if (csp_rv == NULL) { - - /* No valid identity specified or the specified identity - doesn't have any configuration. We default to the - parameters key. */ - - /* we don't just return csp_params since that's a global - handle that we shouldn't close until the plugin is - unloaded. The caller is going to close the returned handle - when it is done. So we need to create a new csp_params - that can safely be closed. */ - - rv = kmm_get_plugins_config(0, &csp_plugins); - if (KHM_FAILED(rv)) - goto done; - - rv = khc_open_space(csp_plugins, CSNAME_KRB5CRED, flags, &csp_krbcfg); - if (KHM_FAILED(rv)) - goto done; - - rv = khc_open_space(csp_krbcfg, CSNAME_PARAMS, flags, &csp_rv); - } - - done: - - *ret_csp = csp_rv; - - /* leave csp_ik5. If it's non-NULL, then it's the return value */ - /* leave csp_rv. It's the return value. */ - if (csp_i) - khc_close_space(csp_i); - if (csp_realms) - khc_close_space(csp_realms); - - /* csp_realm can also be a return value if csp_ik5 was NULL */ - if (csp_realm && csp_realm != csp_rv) - khc_close_space(csp_realm); - - if (csp_plugins) - khc_close_space(csp_plugins); - if (csp_krbcfg) - khc_close_space(csp_krbcfg); - - return rv; -} - -/* from get_in_tkt.c */ -static krb5_error_code -get_libdefault_string(profile_t profile, const char * realm, - const char * option, char ** ret_val) { - char realmstr[K5_MAXCCH_REALM]; - char **nameval = NULL; - const char * names[4]; - krb5_error_code code = 0; - - names[0] = "libdefaults"; - - if (!realm || !realm[0]) - goto try_number_two; - - StringCbCopyA(realmstr, sizeof(realmstr), realm); - - /* - * Try number one: - * - * [libdefaults] - * REALM = { - * option = - * } - */ - - names[1] = realmstr; - names[2] = option; - names[3] = 0; - code = pprofile_get_values(profile, names, &nameval); - if (code == 0 && nameval && nameval[0]) - goto goodbye; - - try_number_two: - - /* - * Try number two: - * - * [libdefaults] - * option = - */ - - names[1] = option; - names[2] = 0; - code = pprofile_get_values(profile, names, &nameval); - if (code == 0 && nameval && nameval[0]) - goto goodbye; - - goodbye: - if (!nameval) - return(ENOENT); - - if (!nameval[0]) { - code = ENOENT; - } else { - size_t cb; - - if (FAILED(StringCbLengthA(nameval[0], K5_MAXCCH_REALM * sizeof(char), &cb))) { - code = ENOMEM; - } else { - cb += sizeof(char); - *ret_val = PMALLOC(cb); - - if (!*ret_val) - code = ENOMEM; - else { - StringCbCopyA(*ret_val, cb, nameval[0]); - code = 0; - } - } - } - - pprofile_free_list(nameval); - - return code; -} - -khm_int32 -khm_krb5_get_identity_params(khm_handle ident, k5_params * p) { - - khm_int32 rv = KHM_ERROR_SUCCESS; - khm_handle csp_id = NULL; - khm_int32 regf = 0; - khm_int32 proff = 0; - khm_int32 e; - khm_int32 v; - CHAR confname[MAX_PATH]; - CHAR realmname[K5_MAXCCH_REALM]; - - ZeroMemory(p, sizeof(*p)); - - rv = khm_krb5_get_identity_config(ident, 0, &csp_id); - if (KHM_FAILED(rv)) - goto done_reg; - - -#define GETVAL(vname, vfield, flag) \ - do { \ - e = khc_value_exists(csp_id, vname); \ - rv = khc_read_int32(csp_id, vname, &v); \ - if (KHM_FAILED(rv)) goto done_reg; \ - p->vfield = v; \ - if ((e & ~KCONF_FLAG_SCHEMA) != 0) regf |= flag; \ - } while(FALSE) - - /* Flags */ - GETVAL(L"Renewable", renewable, K5PARAM_F_RENEW); - GETVAL(L"Forwardable", forwardable, K5PARAM_F_FORW); - GETVAL(L"Proxiable", proxiable, K5PARAM_F_PROX); - GETVAL(L"Addressless", addressless, K5PARAM_F_ADDL); - GETVAL(L"PublicIP", publicIP, K5PARAM_F_PUBIP); - - /* Lifetime */ - GETVAL(L"DefaultLifetime", lifetime, K5PARAM_F_LIFE); - GETVAL(L"MaxLifetime", lifetime_max, K5PARAM_F_LIFE_H); - GETVAL(L"MinLifetime", lifetime_min, K5PARAM_F_LIFE_L); - - /* Renewable lifetime */ - GETVAL(L"DefaultRenewLifetime", renew_life, K5PARAM_F_RLIFE); - GETVAL(L"MaxRenewLifetime", renew_life_max, K5PARAM_F_RLIFE_H); - GETVAL(L"MinRenewLifetime", renew_life_min, K5PARAM_F_RLIFE_L); - -#undef GETVAL - - done_reg: - - if (csp_id) - khc_close_space(csp_id); - - /* if all the parameters were read from the registry, then we have - no reason to read from the profile file. */ - if (regf == K5PARAM_FM_ALL) { - p->source_reg = regf; - return KHM_ERROR_SUCCESS; - } - - if (rv) - return rv; - - /* we need to figure out the realm name, since there might be - per-realm configuration in the profile file. */ - - realmname[0] = '\0'; - - if (ident) { - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - - idname[0] = L'\0'; - cb = sizeof(idname); - rv = kcdb_identity_get_name(ident, idname, &cb); - if (KHM_SUCCEEDED(rv)) { - wchar_t * wrealm; - - wrealm = khm_get_realm_from_princ(idname); - if (wrealm) { - UnicodeStrToAnsi(realmname, sizeof(realmname), wrealm); - } - } - } - - /* If we get here, then some of the settings we read from the - configuration actually came from the schema. In other words, - the values weren't really defined for this identity. So we now - have to read the values from the krb5 configuration file. */ - - if (!khm_krb5_get_profile_file(confname, sizeof(confname))) { - profile_t profile; - const char * filenames[2]; - long retval; - - filenames[0] = confname; - filenames[1] = NULL; - - if (!pprofile_init(filenames, &profile)) { - - /* default ticket lifetime */ - if (!(regf & K5PARAM_F_LIFE)) { - char * value = NULL; - retval = get_libdefault_string(profile, realmname, - "ticket_lifetime", &value); - - if (retval == 0 && value) { - krb5_deltat d; - - retval = pkrb5_string_to_deltat(value, &d); - if (retval == KRB5_DELTAT_BADFORMAT) { - /* Historically some sites use relations of - the form 'ticket_lifetime = 24000' where - the unit is left out but is assumed to be - seconds. Then there are other sites which - use the form 'ticket_lifetime = 600' where - the unit is assumed to be minutes. While - these are technically wrong (a unit needs - to be specified), we try to accomodate for - this using the safe assumption that the - unit is seconds and tack an 's' to the end - and see if that works. */ - - size_t cch; - char tmpbuf[256]; - char * buf; - - do { - if (FAILED(StringCchLengthA(value, 1024 /* unresonably large size */, - &cch))) - break; - - cch += sizeof(char) * 2; /* NULL and new 's' */ - if (cch > ARRAYLENGTH(tmpbuf)) - buf = PMALLOC(cch * sizeof(char)); - else - buf = tmpbuf; - - StringCchCopyA(buf, cch, value); - StringCchCatA(buf, cch, "s"); - - retval = pkrb5_string_to_deltat(buf, &d); - if (retval == 0) { - p->lifetime = d; - proff |= K5PARAM_F_LIFE; - } - - if (buf != tmpbuf) - PFREE(buf); - - } while(0); - - } else if (retval == 0) { - p->lifetime = d; - proff |= K5PARAM_F_LIFE; - } - - PFREE(value); - } - } - - if (!(regf & K5PARAM_F_RLIFE)) { - char * value = NULL; - retval = get_libdefault_string(profile, realmname, - "renew_lifetime", &value); - if (retval == 0 && value) { - krb5_deltat d; - - retval = pkrb5_string_to_deltat(value, &d); - if (retval == 0) { - p->renew_life = d; - proff |= K5PARAM_F_RLIFE; - } - PFREE(value); - } - } - - if (!(regf & K5PARAM_F_FORW)) { - char * value = NULL; - retval = get_libdefault_string(profile, realmname, - "forwardable", &value); - if (retval == 0 && value) { - khm_boolean b; - - if (!khm_krb5_parse_boolean(value, &b)) - p->forwardable = b; - else - p->forwardable = FALSE; - PFREE(value); - proff |= K5PARAM_F_FORW; - } - } - - if (!(regf & K5PARAM_F_RENEW)) { - char * value = NULL; - retval = get_libdefault_string(profile, realmname, - "renewable", &value); - if (retval == 0 && value) { - khm_boolean b; - - if (!khm_krb5_parse_boolean(value, &b)) - p->renewable = b; - else - p->renewable = TRUE; - PFREE(value); - proff |= K5PARAM_F_RENEW; - } - } - - if (!(regf & K5PARAM_F_ADDL)) { - char * value = NULL; - retval = get_libdefault_string(profile, realmname, - "noaddresses", &value); - if (retval == 0 && value) { - khm_boolean b; - - if (!khm_krb5_parse_boolean(value, &b)) - p->addressless = b; - else - p->addressless = TRUE; - PFREE(value); - proff |= K5PARAM_F_ADDL; - } - } - - if (!(regf & K5PARAM_F_PROX)) { - char * value = NULL; - retval = get_libdefault_string(profile, realmname, - "proxiable", &value); - if (retval == 0 && value) { - khm_boolean b; - - if (!khm_krb5_parse_boolean(value, &b)) - p->proxiable = b; - else - p->proxiable = FALSE; - PFREE(value); - proff |= K5PARAM_F_PROX; - } - } - - pprofile_release(profile); - } - } - - p->source_reg = regf; - p->source_prof = proff; - - return rv; -} - -/* Note that p->source_reg and p->source_prof is used in special ways - here. All fields that are flagged in source_reg will be written to - the configuration (if they are different from what - khm_krb5_get_identity_params() reports). All fields that are - flagged in source_prof will be removed from the configuration - (thereby exposing the value defined in the profile file). */ -khm_int32 -khm_krb5_set_identity_params(khm_handle ident, const k5_params * p) { - khm_int32 rv = KHM_ERROR_SUCCESS; - khm_handle csp_id = NULL; - k5_params p_s; - khm_int32 source_reg = p->source_reg; - khm_int32 source_prof = p->source_prof; - - rv = khm_krb5_get_identity_config(ident, - KHM_PERM_WRITE | KHM_FLAG_CREATE | - KCONF_FLAG_WRITEIFMOD, - &csp_id); - if (KHM_FAILED(rv)) - goto done_reg; - - khm_krb5_get_identity_params(ident, &p_s); - - /* Remove any bits that don't make sense. Not all values can be - specified in the profile file. */ - source_prof &= K5PARAM_FM_PROF; - - /* if a flag appears in both source_prof and source_reg, remove - the flag from source_reg. */ - source_reg &= ~source_prof; - - /* we only write values that have changed, and that are flagged in - source_reg */ - - if ((source_reg & K5PARAM_F_RENEW) && - !!p_s.renewable != !!p->renewable) - khc_write_int32(csp_id, L"Renewable", !!p->renewable); - - if ((source_reg & K5PARAM_F_FORW) && - !!p_s.forwardable != !!p->forwardable) - khc_write_int32(csp_id, L"Forwardable", !!p->forwardable); - - if ((source_reg & K5PARAM_F_PROX) && - !!p_s.proxiable != !!p->proxiable) - khc_write_int32(csp_id, L"Proxiable", !!p->proxiable); - - if ((source_reg & K5PARAM_F_ADDL) && - !!p_s.addressless != !!p->addressless) - khc_write_int32(csp_id, L"Addressless", !!p->addressless); - - if ((source_reg & K5PARAM_F_PUBIP) && - p_s.publicIP != p->publicIP) - khc_write_int32(csp_id, L"PublicIP", p->publicIP); - - if ((source_reg & K5PARAM_F_LIFE) && - p_s.lifetime != p->lifetime) - khc_write_int32(csp_id, L"DefaultLifetime", p->lifetime); - - if ((source_reg & K5PARAM_F_LIFE_H) && - p_s.lifetime_max != p->lifetime_max) - khc_write_int32(csp_id, L"MaxLifetime", p->lifetime_max); - - if ((source_reg & K5PARAM_F_LIFE_L) && - p_s.lifetime_min != p->lifetime_min) - khc_write_int32(csp_id, L"MinLifetime", p->lifetime_min); - - if ((source_reg & K5PARAM_F_RLIFE) && - p_s.renew_life != p->renew_life) - khc_write_int32(csp_id, L"DefaultRenewLifetime", p->renew_life); - - if ((source_reg & K5PARAM_F_RLIFE_H) && - p_s.renew_life_max != p->renew_life_max) - khc_write_int32(csp_id, L"MaxRenewLifetime", p->renew_life_max); - - if ((source_reg & K5PARAM_F_RLIFE_L) && - p_s.renew_life_min != p->renew_life_min) - khc_write_int32(csp_id, L"MinRenewLifetime", p->renew_life_min); - - /* and now, remove the values that are present in source_prof. - Not all values are removed since not all values can be - specified in the profile file. */ - if (source_prof & K5PARAM_F_RENEW) - khc_remove_value(csp_id, L"Renewable", 0); - - if (source_prof & K5PARAM_F_FORW) - khc_remove_value(csp_id, L"Forwardable", 0); - - if (source_prof & K5PARAM_F_PROX) - khc_remove_value(csp_id, L"Proxiable", 0); - - if (source_prof & K5PARAM_F_ADDL) - khc_remove_value(csp_id, L"Addressless", 0); - - if (source_prof & K5PARAM_F_LIFE) - khc_remove_value(csp_id, L"DefaultLifetime", 0); - - if (source_prof & K5PARAM_F_RLIFE) - khc_remove_value(csp_id, L"DefaultRenewLifetime", 0); - - done_reg: - if (csp_id != NULL) - khc_close_space(csp_id); - - return rv; -} - -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 -khm_krb5_parse_boolean(const char *s, khm_boolean * b) -{ - const char *const *p; - - for(p=conf_yes; *p; p++) { - if (!_stricmp(*p,s)) { - *b = TRUE; - return 0; - } - } - - for(p=conf_no; *p; p++) { - if (!_stricmp(*p,s)) { - *b = FALSE; - return 0; - } - } - - /* Default to "no" */ - return KHM_ERROR_INVALID_PARAM; -} +/* +* Copyright (c) 2005 Massachusetts Institute of Technology +* Copyright (c) 2006,2007 Secure Endpoints Inc. +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* $Id$ */ + +/* Originally this was krb5routines.c in Leash sources. Subsequently + * modified and adapted for NetIDMgr */ + +#include +#include + +#define SECURITY_WIN32 +#include + +#include +#include +#include +#include +#include + +long +khm_convert524(krb5_context alt_ctx) +{ + krb5_context ctx = 0; + krb5_error_code code = 0; + int icode = 0; + krb5_principal me = 0; + krb5_principal server = 0; + krb5_creds *v5creds = 0; + krb5_creds increds; + krb5_ccache cc = 0; + CREDENTIALS * v4creds = NULL; + static int init_ets = 1; + + if (!pkrb5_init_context || + !pkrb_in_tkt || + !pkrb524_init_ets || + !pkrb524_convert_creds_kdc) + return 0; + + v4creds = (CREDENTIALS *) PMALLOC(sizeof(CREDENTIALS)); + memset((char *) v4creds, 0, sizeof(CREDENTIALS)); + + memset((char *) &increds, 0, sizeof(increds)); + /* + From this point on, we can goto cleanup because increds is + initialized. + */ + + if (alt_ctx) + { + ctx = alt_ctx; + } + else + { + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + } + + code = pkrb5_cc_default(ctx, &cc); + if (code) goto cleanup; + + if ( init_ets ) { + pkrb524_init_ets(ctx); + init_ets = 0; + } + + if (code = pkrb5_cc_get_principal(ctx, cc, &me)) + goto cleanup; + + if ((code = pkrb5_build_principal(ctx, + &server, + krb5_princ_realm(ctx, me)->length, + krb5_princ_realm(ctx, me)->data, + "krbtgt", + krb5_princ_realm(ctx, me)->data, + NULL))) + { + goto cleanup; + } + + increds.client = me; + increds.server = server; + increds.times.endtime = 0; + increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; + if ((code = pkrb5_get_credentials(ctx, 0, + cc, + &increds, + &v5creds))) + { + goto cleanup; + } + + if ((icode = pkrb524_convert_creds_kdc(ctx, + v5creds, + v4creds))) + { + goto cleanup; + } + + /* initialize ticket cache */ + if ((icode = pkrb_in_tkt(v4creds->pname, v4creds->pinst, v4creds->realm) + != KSUCCESS)) + { + goto cleanup; + } + /* stash ticket, session key, etc. for future use */ + if ((icode = pkrb_save_credentials(v4creds->service, + v4creds->instance, + v4creds->realm, + v4creds->session, + v4creds->lifetime, + v4creds->kvno, + &(v4creds->ticket_st), + v4creds->issue_date))) + { + goto cleanup; + } + +cleanup: + memset(v4creds, 0, sizeof(v4creds)); + PFREE(v4creds); + + if (v5creds) { + pkrb5_free_creds(ctx, v5creds); + } + if (increds.client == me) + me = 0; + if (increds.server == server) + server = 0; + pkrb5_free_cred_contents(ctx, &increds); + if (server) { + pkrb5_free_principal(ctx, server); + } + if (me) { + pkrb5_free_principal(ctx, me); + } + pkrb5_cc_close(ctx, cc); + + if (ctx && (ctx != alt_ctx)) { + pkrb5_free_context(ctx); + } + return !(code || icode); +} + +#ifdef DEPRECATED_REMOVABLE +int com_addr(void) +{ + long ipAddr; + char loc_addr[ADDR_SZ]; + CREDENTIALS cred; + char service[40]; + char instance[40]; + // char addr[40]; + char realm[40]; + struct in_addr LocAddr; + int k_errno; + + if (pkrb_get_cred == NULL) + return(KSUCCESS); + + k_errno = (*pkrb_get_cred)(service,instance,realm,&cred); + if (k_errno) + return KRBERR(k_errno); + + while(1) { + ipAddr = (*pLocalHostAddr)(); + LocAddr.s_addr = ipAddr; + StringCbCopyA(loc_addr, sizeof(loc_addr), inet_ntoa(LocAddr)); + if ( strcmp(cred.address, loc_addr) != 0) { + /* TODO: do something about this */ + //Leash_kdestroy (); + break; + } + break; + } // while() + return 0; +} +#endif + +/* we use these structures to keep track of identities that we find + while going through the API, FILE and MSLSA caches and enumerating + credentials. The only identities we want to keep track of are the + ones that have an initial ticket. We collect information for each + of the identities we find that we have initial tickets for and + then set the properties for the identities at once. */ + +typedef struct tag_ident_data { + khm_handle ident; /* handle to the identity */ + khm_int32 count; /* number of initial tickets we have + found for this identity. */ + wchar_t ccname[MAX_PATH]; + FILETIME ft_issue; + FILETIME ft_expire; + FILETIME ft_renewexpire; + khm_int32 krb5_flags; +} ident_data; + +typedef struct tag_identlist { + ident_data * list; + khm_size n_list; + khm_size nc_list; +} identlist; + +#define IDLIST_ALLOC_INCR 8 + +static void +tc_prep_idlist(identlist * idlist) { + khm_int32 rv; + khm_size cb_ids = 0; + khm_size n_ids = 0; + khm_size i; + wchar_t * ids = NULL; + wchar_t *thisid; + + idlist->list = NULL; + idlist->n_list = 0; + idlist->nc_list = 0; + + do { + + if (ids) { + PFREE(ids); + ids = NULL; + } + + rv = kcdb_identity_enum(KCDB_IDENT_FLAG_ACTIVE, + KCDB_IDENT_FLAG_ACTIVE, + NULL, + &cb_ids, + &n_ids); + + if (rv != KHM_ERROR_TOO_LONG) + break; /* something else is wrong */ + + if (n_ids == 0 || cb_ids == 0) + break; /* no identities to process */ + +#ifdef DEBUG + assert(cb_ids > 0); +#endif + + ids = PMALLOC(cb_ids); +#ifdef DEBUG + assert(ids != NULL); +#endif + if (ids == NULL) + break; + + rv = kcdb_identity_enum(KCDB_IDENT_FLAG_ACTIVE, + KCDB_IDENT_FLAG_ACTIVE, + ids, + &cb_ids, + &n_ids); + + if (KHM_SUCCEEDED(rv)) + break; + + } while (TRUE); + + if (ids == NULL) + return; + + if (KHM_FAILED(rv) || n_ids == 0) { + if (ids) + PFREE(ids); + return; + } + + idlist->nc_list = UBOUNDSS(n_ids, IDLIST_ALLOC_INCR, IDLIST_ALLOC_INCR); + + idlist->list = PCALLOC(idlist->nc_list, sizeof(idlist->list[0])); + + for (i = 0, thisid = ids; + thisid && thisid[0]; + thisid = multi_string_next(thisid)) { + + khm_handle ident; + + rv = kcdb_identity_create(thisid, 0, &ident); + + if (KHM_FAILED(rv)) + continue; + + idlist->list[i].ident = ident; + idlist->list[i].count = 0; + + i++; + } + + idlist->n_list = i; + + PFREE(ids); +} + +static ident_data * +tc_add_ident_to_list(identlist * idlist, khm_handle ident) { + khm_size i; + ident_data * d; + + for (i=0; i < idlist->n_list; i++) { + if (kcdb_identity_is_equal(ident, idlist->list[i].ident)) + break; + } + + if (i < idlist->n_list) { + /* we already have this identity on our list. Increment the + count */ + idlist->list[i].count++; + return &idlist->list[i]; + } + + /* it wasn't in our list. Add it */ + + if (idlist->n_list + 1 > idlist->nc_list) { + idlist->nc_list = UBOUNDSS(idlist->n_list + 1, + IDLIST_ALLOC_INCR, + IDLIST_ALLOC_INCR); +#ifdef DEBUG + assert(idlist->n_list + 1 <= idlist->nc_list); +#endif + idlist->list = PREALLOC(idlist->list, + sizeof(idlist->list[0]) * idlist->nc_list); +#ifdef DEBUG + assert(idlist->list); +#endif + ZeroMemory(&idlist->list[idlist->n_list], + sizeof(idlist->list[0]) * + (idlist->nc_list - idlist->n_list)); + } + + d = &idlist->list[idlist->n_list]; + + ZeroMemory(d, sizeof(*d)); + + d->ident = ident; + d->count = 1; + + idlist->n_list++; + + kcdb_identity_hold(ident); + + return d; +} + +static void +tc_set_ident_data(identlist * idlist) { + khm_size i; + wchar_t k5idtype[KCDB_MAXCCH_NAME]; + + k5idtype[0] = L'\0'; + LoadString(hResModule, IDS_KRB5_NC_NAME, + k5idtype, ARRAYLENGTH(k5idtype)); + + for (i=0; i < idlist->n_list; i++) { +#ifdef DEBUG + assert(idlist->list[i].ident); +#endif + + if (idlist->list[i].count > 0) { + khm_int32 t; + + t = credtype_id_krb5; + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_TYPE, + &t, + sizeof(t)); + + /* We need to manually add the type name if we want the + name to show up in the property list for the identity. + The type name is only automatically calculated for + credentials. */ + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_TYPE_NAME, + k5idtype, + KCDB_CBSIZE_AUTO); + + kcdb_identity_set_attr(idlist->list[i].ident, + attr_id_krb5_ccname, + idlist->list[i].ccname, + KCDB_CBSIZE_AUTO); + + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_EXPIRE, + &idlist->list[i].ft_expire, + sizeof(idlist->list[i].ft_expire)); + + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_ISSUE, + &idlist->list[i].ft_issue, + sizeof(idlist->list[i].ft_issue)); + + kcdb_identity_set_attr(idlist->list[i].ident, + attr_id_krb5_flags, + &idlist->list[i].krb5_flags, + sizeof(idlist->list[i].krb5_flags)); + + if (idlist->list[i].ft_renewexpire.dwLowDateTime == 0 && + idlist->list[i].ft_renewexpire.dwHighDateTime == 0) { + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_RENEW_EXPIRE, + NULL, 0); + } else { + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_RENEW_EXPIRE, + &idlist->list[i].ft_renewexpire, + sizeof(idlist->list[i].ft_renewexpire)); + } + + } else { + /* We didn't see any TGTs for this identity. We have to + remove all the Krb5 supplied properties. */ + + khm_int32 t; + khm_size cb; + + cb = sizeof(t); + if (KHM_SUCCEEDED(kcdb_identity_get_attr(idlist->list[i].ident, + KCDB_ATTR_TYPE, NULL, + &t, + &cb)) && + t == credtype_id_krb5) { + + /* disown this and remove all our properties. the + system will GC this identity if nobody claims it.*/ + + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_TYPE, NULL, 0); + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_TYPE_NAME, NULL, 0); + kcdb_identity_set_attr(idlist->list[i].ident, + attr_id_krb5_ccname, NULL, 0); + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_EXPIRE, NULL, 0); + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_ISSUE, NULL, 0); + kcdb_identity_set_attr(idlist->list[i].ident, + attr_id_krb5_flags, NULL, 0); + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_RENEW_EXPIRE, NULL, 0); + } else { + /* otherwise, this identity doesn't belong to us. We + should leave it as is. */ + } + } + } +} + +static void +tc_free_idlist(identlist * idlist) { + khm_size i; + + for (i=0; i < idlist->n_list; i++) { + if (idlist->list[i].ident != NULL) { + kcdb_identity_release(idlist->list[i].ident); + idlist->list[i].ident = NULL; + } + } + + if (idlist->list) + PFREE(idlist->list); + idlist->list = NULL; + idlist->n_list = 0; + idlist->nc_list = 0; +} + +#ifndef ENCTYPE_LOCAL_RC4_MD4 +#define ENCTYPE_LOCAL_RC4_MD4 0xFFFFFF80 +#endif + +#define MAX_ADDRS 256 + +static long get_tickets_from_cache(krb5_context ctx, + krb5_ccache cache, + identlist * idlist) +{ + krb5_error_code code; + krb5_principal KRBv5Principal; + krb5_flags flags = 0; + krb5_cc_cursor KRBv5Cursor; + krb5_creds KRBv5Credentials; + krb5_ticket *tkt=NULL; + char *ClientName = NULL; + char *PrincipalName = NULL; + wchar_t wbuf[256]; /* temporary conversion buffer */ + wchar_t wcc_name[KRB5_MAXCCH_CCNAME]; /* credential cache name */ + char *sServerName = NULL; + khm_handle ident = NULL; + khm_handle cred = NULL; + time_t tt; + FILETIME ft, eft; + khm_int32 ti; + +#ifdef KRB5_TC_NOTICKET + flags = KRB5_TC_NOTICKET; +#else + flags = 0; +#endif + + { + const char * cc_name; + const char * cc_type; + + cc_name = (*pkrb5_cc_get_name)(ctx, cache); + if(cc_name) { + cc_type = (*pkrb5_cc_get_type)(ctx, cache); + if (cc_type) { + StringCbPrintf(wcc_name, sizeof(wcc_name), L"%S:%S", cc_type, cc_name); + } else { + AnsiStrToUnicode(wcc_name, sizeof(wcc_name), cc_name); + khm_krb5_canon_cc_name(wcc_name, sizeof(wcc_name)); + } + } else { + cc_type = (*pkrb5_cc_get_type)(ctx, cache); + if (cc_type) { + StringCbPrintf(wcc_name, sizeof(wcc_name), L"%S:", cc_type); + } else { +#ifdef DEBUG + assert(FALSE); +#endif + StringCbCopy(wcc_name, sizeof(wcc_name), L""); + } + } + } + + _reportf(L"Getting tickets from cache [%s]", wcc_name); + + if ((code = (*pkrb5_cc_set_flags)(ctx, cache, flags))) + { + if (code != KRB5_FCC_NOFILE && code != KRB5_CC_NOTFOUND) + khm_krb5_error(code, "krb5_cc_set_flags()", 0, &ctx, &cache); + + goto _exit; + } + + if ((code = (*pkrb5_cc_get_principal)(ctx, cache, &KRBv5Principal))) + { + if (code != KRB5_FCC_NOFILE && code != KRB5_CC_NOTFOUND) + khm_krb5_error(code, "krb5_cc_get_principal()", 0, &ctx, &cache); + + goto _exit; + } + + PrincipalName = NULL; + ClientName = NULL; + sServerName = NULL; + if ((code = (*pkrb5_unparse_name)(ctx, KRBv5Principal, + (char **)&PrincipalName))) + { + if (PrincipalName != NULL) + (*pkrb5_free_unparsed_name)(ctx, PrincipalName); + + (*pkrb5_free_principal)(ctx, KRBv5Principal); + + goto _exit; + } + + if (!strcspn(PrincipalName, "@" )) + { + if (PrincipalName != NULL) + (*pkrb5_free_unparsed_name)(ctx, PrincipalName); + + (*pkrb5_free_principal)(ctx, KRBv5Principal); + + goto _exit; + } + + AnsiStrToUnicode(wbuf, sizeof(wbuf), PrincipalName); + if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, + &ident))) { + /* something bad happened */ + code = 1; + goto _exit; + } + + _reportf(L"Found principal [%s]", wbuf); + + (*pkrb5_free_principal)(ctx, KRBv5Principal); + + if ((code = (*pkrb5_cc_start_seq_get)(ctx, cache, &KRBv5Cursor))) + { + goto _exit; + } + + memset(&KRBv5Credentials, '\0', sizeof(KRBv5Credentials)); + + ClientName = NULL; + sServerName = NULL; + cred = NULL; + + while (!(code = pkrb5_cc_next_cred(ctx, cache, &KRBv5Cursor, + &KRBv5Credentials))) + { + khm_handle tident = NULL; + khm_int32 cred_flags = 0; + + if(ClientName != NULL) + (*pkrb5_free_unparsed_name)(ctx, ClientName); + if(sServerName != NULL) + (*pkrb5_free_unparsed_name)(ctx, sServerName); + if(cred) + kcdb_cred_release(cred); + + ClientName = NULL; + sServerName = NULL; + cred = NULL; + + if ((*pkrb5_unparse_name)(ctx, KRBv5Credentials.client, &ClientName)) + { + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + khm_krb5_error(code, "krb5_free_cred_contents()", 0, &ctx, &cache); + continue; + } + + if ((*pkrb5_unparse_name)(ctx, KRBv5Credentials.server, &sServerName)) + { + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + khm_krb5_error(code, "krb5_free_cred_contents()", 0, &ctx, &cache); + continue; + } + + /* if the ClientName differs from PrincipalName for some + reason, we need to create a new identity */ + if(strcmp(ClientName, PrincipalName)) { + AnsiStrToUnicode(wbuf, sizeof(wbuf), ClientName); + if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, + &tident))) { + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + continue; + } + } else { + tident = ident; + } + + AnsiStrToUnicode(wbuf, sizeof(wbuf), sServerName); + if(KHM_FAILED(kcdb_cred_create(wbuf, tident, credtype_id_krb5, + &cred))) { + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + continue; + } + + if (!KRBv5Credentials.times.starttime) + KRBv5Credentials.times.starttime = KRBv5Credentials.times.authtime; + + tt = KRBv5Credentials.times.starttime; + TimetToFileTime(tt, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft)); + + tt = KRBv5Credentials.times.endtime; + TimetToFileTime(tt, &eft); + kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &eft, sizeof(eft)); + + { + FILETIME ftl; + + ftl = FtSub(&eft, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_LIFETIME, &ftl, sizeof(ftl)); + } + + if (KRBv5Credentials.times.renew_till > 0) { + FILETIME ftl; + + tt = KRBv5Credentials.times.renew_till; + TimetToFileTime(tt, &eft); + kcdb_cred_set_attr(cred, KCDB_ATTR_RENEW_EXPIRE, &eft, + sizeof(eft)); + + + ftl = FtSub(&eft, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_RENEW_LIFETIME, &ftl, + sizeof(ftl)); + } + + ti = KRBv5Credentials.ticket_flags; + kcdb_cred_set_attr(cred, attr_id_krb5_flags, &ti, sizeof(ti)); + + /* special flags understood by NetIDMgr */ + { + khm_int32 nflags = 0; + + if (ti & TKT_FLG_RENEWABLE) + nflags |= KCDB_CRED_FLAG_RENEWABLE; + if (ti & TKT_FLG_INITIAL) + nflags |= KCDB_CRED_FLAG_INITIAL; + else { + krb5_data * c0, *c1, *r; + + /* these are macros that do not allocate any memory */ + c0 = krb5_princ_component(ctx,KRBv5Credentials.server,0); + c1 = krb5_princ_component(ctx,KRBv5Credentials.server,1); + r = krb5_princ_realm(ctx,KRBv5Credentials.server); + + if ( c0 && c1 && r && c1->length == r->length && + !strncmp(c1->data,r->data,r->length) && + !strncmp("krbtgt",c0->data,c0->length) ) + nflags |= KCDB_CRED_FLAG_INITIAL; + } + + kcdb_cred_set_flags(cred, nflags, KCDB_CRED_FLAGMASK_EXT); + + cred_flags = nflags; + } + + if ( !pkrb5_decode_ticket(&KRBv5Credentials.ticket, &tkt)) { + ti = tkt->enc_part.enctype; + kcdb_cred_set_attr(cred, attr_id_tkt_enctype, &ti, sizeof(ti)); + ti = tkt->enc_part.kvno; + kcdb_cred_set_attr(cred, attr_id_kvno, &ti, sizeof(ti)); + pkrb5_free_ticket(ctx, tkt); + tkt = NULL; + } + + ti = KRBv5Credentials.keyblock.enctype; + kcdb_cred_set_attr(cred, attr_id_key_enctype, &ti, sizeof(ti)); + + kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION, wcc_name, + KCDB_CBSIZE_AUTO); + + if ( KRBv5Credentials.addresses && KRBv5Credentials.addresses[0] ) { + 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); + } + + if(cred_flags & KCDB_CRED_FLAG_INITIAL) { + FILETIME ft_issue_new; + FILETIME ft_expire_old; + FILETIME ft_expire_new; + ident_data * d; + + /* an initial ticket! Add it to the list of identities we + have seen so far with initial tickets. */ + d = tc_add_ident_to_list(idlist, ident); +#ifdef DEBUG + assert(d); + assert(d->count > 0); +#endif + + tt = KRBv5Credentials.times.endtime; + TimetToFileTime(tt, &ft_expire_new); + + tt = KRBv5Credentials.times.starttime; + TimetToFileTime(tt, &ft_issue_new); + + /* so now, we have to set the properties of the identity + based on the properties of this credential under the + following circumstances: + + - If this is the first time we are hitting this + identity. + + - If this is not the MSLSA: cache and the expiry time + for this credential is longer than the time already + found for this identity. + */ + + ft_expire_old = d->ft_expire; + + if(d->count == 1 + || (CompareFileTime(&ft_expire_new, &ft_expire_old) > 0 && + wcscmp(wcc_name, L"MSLSA:") != 0)) { + + _reportf(L"Setting properties for identity (count=%d)", d->count); + + StringCbCopy(d->ccname, sizeof(d->ccname), + wcc_name); + d->ft_expire = ft_expire_new; + d->ft_issue = ft_issue_new; + + if (KRBv5Credentials.times.renew_till > 0) { + tt = KRBv5Credentials.times.renew_till; + TimetToFileTime(tt, &ft); + d->ft_renewexpire = ft; + } else { + ZeroMemory(&d->ft_renewexpire, sizeof(d->ft_renewexpire)); + } + + d->krb5_flags = KRBv5Credentials.ticket_flags; + } + } + + kcdb_credset_add_cred(krb5_credset, cred, -1); + + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + + if(tident != ident) + kcdb_identity_release(tident); + } + + if (PrincipalName != NULL) + (*pkrb5_free_unparsed_name)(ctx, PrincipalName); + + if (ClientName != NULL) + (*pkrb5_free_unparsed_name)(ctx, ClientName); + + if (sServerName != NULL) + (*pkrb5_free_unparsed_name)(ctx, sServerName); + + if (cred) + kcdb_cred_release(cred); + + if ((code == KRB5_CC_END) || (code == KRB5_CC_NOTFOUND)) + { + if ((code = pkrb5_cc_end_seq_get(ctx, cache, &KRBv5Cursor))) + { + goto _exit; + } + + flags = KRB5_TC_OPENCLOSE; +#ifdef KRB5_TC_NOTICKET + flags |= KRB5_TC_NOTICKET; +#endif + if ((code = pkrb5_cc_set_flags(ctx, cache, flags))) + { + goto _exit; + } + } + else + { + goto _exit; + } + +_exit: + + return code; +} + +long +khm_krb5_list_tickets(krb5_context *krbv5Context) +{ + krb5_context ctx = NULL; + krb5_ccache cache = NULL; + krb5_error_code code = 0; + apiCB * cc_ctx = NULL; + struct _infoNC ** pNCi = NULL; + int i; + khm_int32 t; + wchar_t * ms = NULL; + khm_size cb; + identlist idl; + + kcdb_credset_flush(krb5_credset); + tc_prep_idlist(&idl); + + if((*krbv5Context == 0) && (code = (*pkrb5_init_context)(krbv5Context))) { + goto _exit; + } + + ctx = (*krbv5Context); + + if (!pcc_initialize || + !pcc_get_NC_info || + !pcc_free_NC_info || + !pcc_shutdown) + goto _skip_cc_iter; + + code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL); + if (code) + goto _exit; + + code = pcc_get_NC_info(cc_ctx, &pNCi); + if (code) + goto _exit; + + for(i=0; pNCi[i]; i++) { + char ccname[KRB5_MAXCCH_CCNAME]; + + if (pNCi[i]->vers != CC_CRED_V5) + continue; + + if (FAILED(StringCchPrintfA(ccname, sizeof(ccname), "API:%s", + pNCi[i]->name))) + continue; + + code = (*pkrb5_cc_resolve)(ctx, ccname, &cache); + + if (code) + continue; + + code = get_tickets_from_cache(ctx, cache, &idl); + + if(ctx != NULL && cache != NULL) + (*pkrb5_cc_close)(ctx, cache); + + cache = 0; + } + + _skip_cc_iter: + + if (khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb) + == KHM_ERROR_TOO_LONG && + cb > sizeof(wchar_t) * 2) { + wchar_t * t; + char ccname[MAX_PATH + 6]; + + ms = PMALLOC(cb); +#ifdef DEBUG + assert(ms); +#endif + khc_read_multi_string(csp_params, L"FileCCList", ms, &cb); + + for(t = ms; t && *t; t = multi_string_next(t)) { + StringCchPrintfA(ccname, ARRAYLENGTH(ccname), + "FILE:%S", t); + + code = (*pkrb5_cc_resolve)(ctx, ccname, &cache); + + if (code) + continue; + + code = get_tickets_from_cache(ctx, cache, &idl); + + if (ctx != NULL && cache != NULL) + (*pkrb5_cc_close)(ctx, cache); + cache = 0; + } + + PFREE(ms); + } + + if (KHM_SUCCEEDED(khc_read_int32(csp_params, L"MsLsaList", &t)) && t) { + code = (*pkrb5_cc_resolve)(ctx, "MSLSA:", &cache); + + if (code == 0 && cache) { + code = get_tickets_from_cache(ctx, cache, &idl); + } + + if (ctx != NULL && cache != NULL) + (*pkrb5_cc_close)(ctx, cache); + cache = 0; + } + +_exit: + if (pNCi) + (*pcc_free_NC_info)(cc_ctx, &pNCi); + if (cc_ctx) + (*pcc_shutdown)(&cc_ctx); + + kcdb_credset_collect(NULL, krb5_credset, NULL, credtype_id_krb5, NULL); + tc_set_ident_data(&idl); + tc_free_idlist(&idl); + + return(code); +} + +int +khm_krb5_renew_cred(khm_handle cred) +{ + khm_handle identity = NULL; + krb5_error_code code = 0; + krb5_context ctx = NULL; + krb5_ccache cc = NULL; + krb5_principal me = NULL, server = NULL; + krb5_creds in_creds, cc_creds; + krb5_creds * out_creds = NULL; + + wchar_t wname[512]; + khm_size cbname; + char name[512]; + khm_boolean brenewIdentity = FALSE; + khm_boolean istgt = FALSE; + + khm_int32 flags; + + cbname = sizeof(wname); + kcdb_cred_get_name(cred, wname, &cbname); + _reportf(L"Krb5 renew cred for %s", wname); + + kcdb_cred_get_flags(cred, &flags); + + if (!(flags & KCDB_CRED_FLAG_INITIAL)) { + _reportf(L"Krb5 skipping renewal because this is not an initial credential"); + return 0; + } + + memset(&in_creds, 0, sizeof(in_creds)); + memset(&cc_creds, 0, sizeof(cc_creds)); + + 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; + + code = pkrb5_cc_get_principal(ctx, cc, &me); + if (code) + goto cleanup; + + cbname = sizeof(wname); + if (KHM_FAILED(kcdb_cred_get_name(cred, wname, &cbname))) + goto cleanup; + + UnicodeStrToAnsi(name, sizeof(name), wname); + + code = pkrb5_parse_name(ctx, name, &server); + if (code) + goto cleanup; + + in_creds.client = me; + in_creds.server = server; + +#ifdef KRB5_TC_NOTICKET + pkrb5_cc_set_flags(ctx, cc, 0); +#endif + + if (strlen("krbtgt") != krb5_princ_name(ctx, server)->length || + strncmp("krbtgt", krb5_princ_name(ctx, server)->data, krb5_princ_name(ctx, server)->length)) + { + code = pkrb5_get_renewed_creds(ctx, &cc_creds, me, cc, name); + if (code) { + code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &in_creds, &cc_creds); + if (code == 0) { + code = pkrb5_cc_remove_cred(ctx, cc, 0, &cc_creds); + if (code) { + brenewIdentity = TRUE; + goto cleanup; + } + } + } + + code = pkrb5_get_credentials(ctx, 0, cc, &in_creds, &out_creds); + } else { + istgt = TRUE; + code = pkrb5_get_renewed_creds(ctx, &cc_creds, me, cc, NULL); + } + +#ifdef KRB5_TC_NOTICKET + pkrb5_cc_set_flags(ctx, cc, KRB5_TC_NOTICKET); +#endif + if (code) { + if ( code != KRB5KDC_ERR_ETYPE_NOSUPP || + code != KRB5_KDC_UNREACH) + khm_krb5_error(code, "krb5_get_renewed_creds()", 0, &ctx, &cc); + goto cleanup; + } + + if (istgt) { + code = pkrb5_cc_initialize(ctx, cc, me); + if (code) goto cleanup; + + } + + code = pkrb5_cc_store_cred(ctx, cc, istgt ? &cc_creds : out_creds); + if (code) goto cleanup; + + + cleanup: + + if (in_creds.client == me) + in_creds.client = NULL; + if (in_creds.server == server) + in_creds.server = NULL; + + if (me) + pkrb5_free_principal(ctx, me); + + if (server) + pkrb5_free_principal(ctx, server); + + pkrb5_free_cred_contents(ctx, &in_creds); + pkrb5_free_cred_contents(ctx, &cc_creds); + + if (out_creds) + pkrb5_free_creds(ctx, out_creds); + + if (cc && ctx) + pkrb5_cc_close(ctx, cc); + + if (ctx) + pkrb5_free_context(ctx); + + if (identity) { + if (brenewIdentity) + code = khm_krb5_renew_ident(identity); + kcdb_identity_release(identity); + } + + return code; +} + +int +khm_krb5_renew_ident(khm_handle identity) +{ + krb5_error_code code = 0; + krb5_context ctx = NULL; + krb5_ccache cc = NULL; + krb5_principal me = NULL; + krb5_principal server = NULL; + krb5_creds my_creds; + krb5_data *realm = NULL; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khm_int32 k5_flags; + + memset(&my_creds, 0, sizeof(krb5_creds)); + + if ( !pkrb5_init_context ) + goto cleanup; + + cb = sizeof(idname); + kcdb_identity_get_name(identity, idname, &cb); + + if (khm_krb5_get_identity_flags(identity) & K5IDFLAG_IMPORTED) { +#ifndef NO_REIMPORT_MSLSA_CREDS + /* we are trying to renew the identity that was imported from + MSLSA: */ + BOOL imported; + BOOL retry_import = FALSE; + char cidname[KCDB_IDENT_MAXCCH_NAME]; + khm_handle imported_id = NULL; + khm_size cb; + FILETIME ft_expire; + FILETIME ft_now; + FILETIME ft_threshold; + krb5_principal princ = NULL; + + UnicodeStrToAnsi(cidname, sizeof(cidname), idname); + + imported = khm_krb5_ms2mit(cidname, FALSE, TRUE, &imported_id); + + if (imported == 0) + goto import_failed; + + /* if the imported identity has already expired or will soon, + we clear the cache and try again. */ + khm_krb5_list_tickets(&ctx); + + cb = sizeof(ft_expire); + if (KHM_FAILED(kcdb_identity_get_attr(imported_id, KCDB_ATTR_EXPIRE, + NULL, &ft_expire, &cb))) + goto import_failed; + + GetSystemTimeAsFileTime(&ft_now); + TimetToFileTimeInterval(5 * 60, &ft_threshold); + + ft_now = FtAdd(&ft_now, &ft_threshold); + + if (CompareFileTime(&ft_expire, &ft_now) < 0) { + /* the ticket lifetime is not long enough */ + + code = 0; + + if (ctx == NULL) + code = pkrb5_init_context(&ctx); + if (code) + goto import_failed; + + code = pkrb5_cc_resolve(ctx, "MSLSA:", &cc); + if (code) + goto import_failed; + + code = pkrb5_cc_get_principal(ctx, cc, &princ); + if (code) + goto import_failed; + + pkrb5_cc_initialize(ctx, cc, princ); + + retry_import = TRUE; + } + + import_failed: + + if (imported_id) { + kcdb_identity_release(imported_id); + imported_id = NULL; + } + + if (ctx) { + if (cc) { + pkrb5_cc_close(ctx, cc); + cc = NULL; + } + + if (princ) { + pkrb5_free_principal(ctx, princ); + princ = NULL; + } + + /* leave ctx so we can use it later */ + } + + if (retry_import) + imported = khm_krb5_ms2mit(cidname, FALSE, TRUE, NULL); + + if (imported) + goto cleanup; + + /* if the import failed, then we try to renew the identity via + the usual procedure. */ + +#else + /* if we are suppressing further imports from MSLSA, we just + skip renewing this identity. */ + goto cleanup; +#endif + } + + cb = sizeof(k5_flags); + if (KHM_SUCCEEDED(kcdb_identity_get_attr(identity, + attr_id_krb5_flags, + NULL, + &k5_flags, + &cb)) && + !(k5_flags & TKT_FLG_RENEWABLE)) { + + code = KRB5KDC_ERR_BADOPTION; + goto cleanup; + } + + { + FILETIME ft_now; + FILETIME ft_exp; + + cb = sizeof(ft_exp); + GetSystemTimeAsFileTime(&ft_now); + if (KHM_SUCCEEDED(kcdb_identity_get_attr(identity, + KCDB_ATTR_EXPIRE, + NULL, + &ft_exp, + &cb)) && + CompareFileTime(&ft_exp, &ft_now) < 0) { + + code = KRB5KRB_AP_ERR_TKT_EXPIRED; + goto cleanup; + + } + } + + code = khm_krb5_initialize(identity, &ctx, &cc); + if (code) + goto cleanup; + + code = pkrb5_cc_get_principal(ctx, cc, &me); + if (code) + goto cleanup; + + realm = krb5_princ_realm(ctx, me); + + code = pkrb5_build_principal_ext(ctx, &server, + realm->length,realm->data, + KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, + realm->length,realm->data, + 0); + + if (code) + goto cleanup; + + my_creds.client = me; + my_creds.server = server; + +#ifdef KRB5_TC_NOTICKET + pkrb5_cc_set_flags(ctx, cc, 0); +#endif + code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL); +#ifdef KRB5_TC_NOTICKET + pkrb5_cc_set_flags(ctx, cc, KRB5_TC_NOTICKET); +#endif + if (code) { + if ( code != KRB5KDC_ERR_ETYPE_NOSUPP || + code != KRB5_KDC_UNREACH) + khm_krb5_error(code, "krb5_get_renewed_creds()", 0, &ctx, &cc); + goto cleanup; + } + + code = pkrb5_cc_initialize(ctx, cc, me); + if (code) goto cleanup; + + code = pkrb5_cc_store_cred(ctx, cc, &my_creds); + if (code) goto cleanup; + +cleanup: + if (my_creds.client == me) + my_creds.client = NULL; + if (my_creds.server == server) + my_creds.server = NULL; + + if (ctx) { + pkrb5_free_cred_contents(ctx, &my_creds); + + if (me) + pkrb5_free_principal(ctx, me); + if (server) + pkrb5_free_principal(ctx, server); + if (cc) + pkrb5_cc_close(ctx, cc); + pkrb5_free_context(ctx); + } + + return(code); +} + +int +khm_krb5_kinit(krb5_context alt_ctx, + char * principal_name, + char * password, + char * ccache, + krb5_deltat lifetime, + DWORD forwardable, + DWORD proxiable, + krb5_deltat renew_life, + DWORD addressless, + DWORD publicIP, + krb5_prompter_fct prompter, + void * p_data) +{ + krb5_error_code code = 0; + krb5_context ctx = NULL; + krb5_ccache cc = NULL; + krb5_principal me = NULL; + char* name = NULL; + krb5_creds my_creds; + krb5_get_init_creds_opt options; + krb5_address ** addrs = NULL; + int i = 0, addr_count = 0; + + if (!pkrb5_init_context) + return 0; + + _reportf(L"In khm_krb5_kinit"); + + pkrb5_get_init_creds_opt_init(&options); + pkrb5_get_init_creds_opt_set_change_password_prompt(&options, 0); + + memset(&my_creds, 0, sizeof(my_creds)); + + if (alt_ctx) { + ctx = alt_ctx; + } else { + code = pkrb5_init_context(&ctx); + if (code) + goto cleanup; + } + + if (ccache) { + _reportf(L"Using supplied ccache name %S", ccache); + code = pkrb5_cc_resolve(ctx, ccache, &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); + if (code) goto cleanup; + + code = pkrb5_unparse_name(ctx, me, &name); + if (code) goto cleanup; + + if (lifetime == 0) { + khc_read_int32(csp_params, L"DefaultLifetime", &lifetime); + } + + if (lifetime) + pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime); + + pkrb5_get_init_creds_opt_set_forwardable(&options, + forwardable ? 1 : 0); + pkrb5_get_init_creds_opt_set_proxiable(&options, + proxiable ? 1 : 0); + pkrb5_get_init_creds_opt_set_renew_life(&options, + renew_life); + + if (addressless) + pkrb5_get_init_creds_opt_set_address_list(&options,NULL); + else { + 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); + } + + 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); + + addrs[i]->magic = KV5M_ADDRESS; + addrs[i]->addrtype = AF_INET; + addrs[i]->length = 4; + addrs[i]->contents = (unsigned char *)PMALLOC(addrs[i]->length); + if (!addrs[i]->contents) + assert(0); + + netIPAddr = htonl(publicIP); + memcpy(addrs[i]->contents,&netIPAddr,4); + } + + pkrb5_get_init_creds_opt_set_address_list(&options,addrs); + } + + code = + pkrb5_get_init_creds_password(ctx, + &my_creds, + me, + password, // password + prompter, // prompter + p_data, // prompter data + 0, // start time + 0, // service name + &options); + _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: + if ( addrs ) { + for ( i=0;icontents ) + PFREE(addrs[i]->contents); + PFREE(addrs[i]); + } + } + } + if (my_creds.client == me) + my_creds.client = 0; + pkrb5_free_cred_contents(ctx, &my_creds); + if (name) + pkrb5_free_unparsed_name(ctx, name); + if (me) + pkrb5_free_principal(ctx, me); + if (cc) + pkrb5_cc_close(ctx, cc); + if (ctx && (ctx != alt_ctx)) + pkrb5_free_context(ctx); + return(code); +} + +long +khm_krb5_copy_ccache_by_name(krb5_context in_ctx, + wchar_t * wscc_dest, + wchar_t * wscc_src) { + krb5_context ctx = NULL; + krb5_error_code code = 0; + khm_boolean free_ctx; + krb5_ccache cc_src = NULL; + krb5_ccache cc_dest = NULL; + krb5_principal princ_src = NULL; + char scc_dest[KRB5_MAXCCH_CCNAME]; + char scc_src[KRB5_MAXCCH_CCNAME]; + int t; + + t = UnicodeStrToAnsi(scc_dest, sizeof(scc_dest), wscc_dest); + if (t == 0) + return KHM_ERROR_TOO_LONG; + t = UnicodeStrToAnsi(scc_src, sizeof(scc_src), wscc_src); + if (t == 0) + return KHM_ERROR_TOO_LONG; + + if (in_ctx) { + ctx = in_ctx; + free_ctx = FALSE; + } else { + code = pkrb5_init_context(&ctx); + if (code) { + if (ctx) + pkrb5_free_context(ctx); + return code; + } + free_ctx = TRUE; + } + + code = pkrb5_cc_resolve(ctx, scc_dest, &cc_dest); + if (code) + goto _cleanup; + + code = pkrb5_cc_resolve(ctx, scc_src, &cc_src); + if (code) + goto _cleanup; + + code = pkrb5_cc_get_principal(ctx, cc_src, &princ_src); + if (code) + goto _cleanup; + + code = pkrb5_cc_initialize(ctx, cc_dest, princ_src); + if (code) + goto _cleanup; + + code = pkrb5_cc_copy_creds(ctx, cc_src, cc_dest); + + _cleanup: + if (princ_src) + pkrb5_free_principal(ctx, princ_src); + + if (cc_dest) + pkrb5_cc_close(ctx, cc_dest); + + if (cc_src) + pkrb5_cc_close(ctx, cc_src); + + if (free_ctx && ctx) + pkrb5_free_context(ctx); + + return code; +} + +long +khm_krb5_canon_cc_name(wchar_t * wcc_name, + size_t cb_cc_name) { + size_t cb_len; + wchar_t * colon; + + if (FAILED(StringCbLength(wcc_name, + cb_cc_name, + &cb_len))) { +#ifdef DEBUG + assert(FALSE); +#else + return KHM_ERROR_TOO_LONG; +#endif + } + + cb_len += sizeof(wchar_t); + + colon = wcschr(wcc_name, L':'); + + if (colon) { + /* if the colon is just 1 character away from the beginning, + it's a FILE: cc */ + if (colon - wcc_name == 1) { + if (cb_len + 5 * sizeof(wchar_t) > cb_cc_name) + return KHM_ERROR_TOO_LONG; + + memmove(&wcc_name[5], &wcc_name[0], cb_len); + memmove(&wcc_name[0], L"FILE:", sizeof(wchar_t) * 5); + } + + return 0; + } + + if (cb_len + 4 * sizeof(wchar_t) > cb_cc_name) + return KHM_ERROR_TOO_LONG; + + memmove(&wcc_name[4], &wcc_name[0], cb_len); + memmove(&wcc_name[0], L"API:", sizeof(wchar_t) * 4); + + return 0; +} + +int +khm_krb5_cc_name_cmp(const wchar_t * cc_name_1, + const wchar_t * cc_name_2) { + if (!wcsncmp(cc_name_1, L"API:", 4)) + cc_name_1 += 4; + + if (!wcsncmp(cc_name_2, L"API:", 4)) + cc_name_2 += 4; + + return wcscmp(cc_name_1, cc_name_2); +} + +static khm_int32 KHMAPI +khmint_location_comp_func(khm_handle cred1, + khm_handle cred2, + void * rock) { + return kcdb_creds_comp_attr(cred1, cred2, KCDB_ATTR_LOCATION); +} + +struct khmint_location_check { + khm_handle credset; + khm_handle cred; + wchar_t * ccname; + khm_boolean success; +}; + +static khm_int32 KHMAPI +khmint_find_matching_cred_func(khm_handle cred, + void * rock) { + struct khmint_location_check * lc; + + lc = (struct khmint_location_check *) rock; + + if (!kcdb_creds_is_equal(cred, lc->cred)) + return KHM_ERROR_SUCCESS; + if (kcdb_creds_comp_attr(cred, lc->cred, KCDB_ATTR_LOCATION)) + return KHM_ERROR_SUCCESS; + + /* found it */ + lc->success = TRUE; + + /* break the search */ + return !KHM_ERROR_SUCCESS; +} + +static khm_int32 KHMAPI +khmint_location_check_func(khm_handle cred, + void * rock) { + khm_int32 t; + khm_size cb; + wchar_t ccname[KRB5_MAXCCH_CCNAME]; + struct khmint_location_check * lc; + + lc = (struct khmint_location_check *) rock; + + if (KHM_FAILED(kcdb_cred_get_type(cred, &t))) + return KHM_ERROR_SUCCESS; + + if (t != credtype_id_krb5) + return KHM_ERROR_SUCCESS; + + cb = sizeof(ccname); + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + ccname, + &cb))) + return KHM_ERROR_SUCCESS; + + if(wcscmp(ccname, lc->ccname)) + return KHM_ERROR_SUCCESS; + + lc->cred = cred; + + lc->success = FALSE; + + kcdb_credset_apply(lc->credset, + khmint_find_matching_cred_func, + (void *) lc); + + if (!lc->success) + return KHM_ERROR_NOT_FOUND; + else + return KHM_ERROR_SUCCESS; +} + +static khm_int32 KHMAPI +khmint_delete_location_func(khm_handle cred, + void * rock) { + wchar_t cc_cred[KRB5_MAXCCH_CCNAME]; + struct khmint_location_check * lc; + khm_size cb; + + lc = (struct khmint_location_check *) rock; + + cb = sizeof(cc_cred); + + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + cc_cred, + &cb))) + return KHM_ERROR_SUCCESS; + + if (wcscmp(cc_cred, lc->ccname)) + return KHM_ERROR_SUCCESS; + + kcdb_credset_del_cred_ref(lc->credset, + cred); + + return KHM_ERROR_SUCCESS; +} + +int +khm_krb5_destroy_by_credset(khm_handle p_cs) +{ + khm_handle d_cs = NULL; + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_size s, cb; + krb5_context ctx = NULL; + krb5_error_code code = 0; + int i; + wchar_t ccname[KRB5_MAXCCH_CCNAME]; + struct khmint_location_check lc; + + rv = kcdb_credset_create(&d_cs); + + assert(KHM_SUCCEEDED(rv) && d_cs != NULL); + + kcdb_credset_extract(d_cs, p_cs, NULL, credtype_id_krb5); + + kcdb_credset_get_size(d_cs, &s); + + if (s == 0) { + _reportf(L"No tickets to delete"); + + kcdb_credset_delete(d_cs); + return 0; + } + + code = pkrb5_init_context(&ctx); + if (code != 0) { + rv = code; + goto _cleanup; + } + + /* we should synchronize the credential lists before we attempt to + make any assumptions on the state of the root credset */ + khm_krb5_list_tickets(&ctx); + + /* so, we need to make a decision about whether to destroy entire + ccaches or just individual credentials. Therefore we first + sort them by ccache. */ + kcdb_credset_sort(d_cs, + khmint_location_comp_func, + NULL); + + /* now, for each ccache we encounter, we check if we have all the + credentials from that ccache in the to-be-deleted list. */ + for (i=0; i < (int) s; i++) { + khm_handle cred; + + if (KHM_FAILED(kcdb_credset_get_cred(d_cs, + i, + &cred))) + continue; + + cb = sizeof(ccname); + rv = kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + ccname, + &cb); + +#ifdef DEBUG + assert(KHM_SUCCEEDED(rv)); +#endif + kcdb_cred_release(cred); + + lc.credset = d_cs; + lc.cred = NULL; + lc.ccname = ccname; + lc.success = FALSE; + + kcdb_credset_apply(NULL, + khmint_location_check_func, + (void *) &lc); + + if (lc.success) { + /* ok the destroy the ccache */ + char a_ccname[KRB5_MAXCCH_CCNAME]; + krb5_ccache cc = NULL; + + _reportf(L"Destroying ccache [%s]", ccname); + + UnicodeStrToAnsi(a_ccname, + sizeof(a_ccname), + ccname); + + code = pkrb5_cc_resolve(ctx, + a_ccname, + &cc); + if (code) + goto _delete_this_set; + + code = pkrb5_cc_destroy(ctx, cc); + + if (code) { + _reportf(L"krb5_cc_destroy returns code %d", code); + } + + _delete_this_set: + + lc.credset = d_cs; + lc.ccname = ccname; + + /* note that although we are deleting credentials off the + credential set, the size of the credential set does not + decrease since we are doing it from inside + kcdb_credset_apply(). The deleted creds will simply be + marked as deleted until kcdb_credset_purge() is + called. */ + + kcdb_credset_apply(d_cs, + khmint_delete_location_func, + (void *) &lc); + } + } + + kcdb_credset_purge(d_cs); + + /* the remainder need to be deleted one by one */ + + kcdb_credset_get_size(d_cs, &s); + + for (i=0; i < (int) s; ) { + khm_handle cred; + char a_ccname[KRB5_MAXCCH_CCNAME]; + char a_srvname[KCDB_CRED_MAXCCH_NAME]; + wchar_t srvname[KCDB_CRED_MAXCCH_NAME]; + krb5_ccache cc; + krb5_creds in_cred, out_cred; + krb5_principal princ; + khm_int32 etype; + + if (KHM_FAILED(kcdb_credset_get_cred(d_cs, + i, + &cred))) { + i++; + continue; + } + + cb = sizeof(ccname); + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + ccname, + &cb))) + goto _done_with_this_cred; + + _reportf(L"Looking at ccache [%s]", ccname); + + UnicodeStrToAnsi(a_ccname, + sizeof(a_ccname), + ccname); + + code = pkrb5_cc_resolve(ctx, + a_ccname, + &cc); + + if (code) + goto _skip_similar; + + code = pkrb5_cc_get_principal(ctx, cc, &princ); + + if (code) { + pkrb5_cc_close(ctx, cc); + goto _skip_similar; + } + + _del_this_cred: + + cb = sizeof(etype); + + if (KHM_FAILED(kcdb_cred_get_attr(cred, + attr_id_key_enctype, + NULL, + &etype, + &cb))) + goto _do_next_cred; + + cb = sizeof(srvname); + if (KHM_FAILED(kcdb_cred_get_name(cred, + srvname, + &cb))) + goto _do_next_cred; + + _reportf(L"Attempting to delete ticket %s", srvname); + + UnicodeStrToAnsi(a_srvname, sizeof(a_srvname), srvname); + + ZeroMemory(&in_cred, sizeof(in_cred)); + + code = pkrb5_parse_name(ctx, a_srvname, &in_cred.server); + if (code) + goto _do_next_cred; + in_cred.client = princ; + in_cred.keyblock.enctype = etype; + + code = pkrb5_cc_retrieve_cred(ctx, + cc, + KRB5_TC_MATCH_SRV_NAMEONLY | + KRB5_TC_SUPPORTED_KTYPES, + &in_cred, + &out_cred); + if (code) + goto _do_next_cred_0; + + code = pkrb5_cc_remove_cred(ctx, cc, + KRB5_TC_MATCH_SRV_NAMEONLY | + KRB5_TC_SUPPORTED_KTYPES | + KRB5_TC_MATCH_AUTHDATA, + &out_cred); + + pkrb5_free_cred_contents(ctx, &out_cred); + _do_next_cred_0: + pkrb5_free_principal(ctx, in_cred.server); + _do_next_cred: + + /* check if the next cred is also of the same ccache */ + kcdb_cred_release(cred); + + for (i++; i < (int) s; i++) { + if (KHM_FAILED(kcdb_credset_get_cred(d_cs, + i, + &cred))) + continue; + } + + if (i < (int) s) { + wchar_t newcc[KRB5_MAXCCH_CCNAME]; + + cb = sizeof(newcc); + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + newcc, + &cb)) || + wcscmp(newcc, ccname)) { + i--; /* we have to look at this again */ + goto _done_with_this_set; + } + goto _del_this_cred; + } + + + _done_with_this_set: + pkrb5_free_principal(ctx, princ); + + pkrb5_cc_close(ctx, cc); + + _done_with_this_cred: + kcdb_cred_release(cred); + i++; + continue; + + _skip_similar: + kcdb_cred_release(cred); + + for (++i; i < (int) s; i++) { + wchar_t newcc[KRB5_MAXCCH_CCNAME]; + + if (KHM_FAILED(kcdb_credset_get_cred(d_cs, + i, + &cred))) + continue; + + cb = sizeof(newcc); + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + &newcc, + &cb))) { + kcdb_cred_release(cred); + continue; + } + + if (wcscmp(newcc, ccname)) { + kcdb_cred_release(cred); + break; + } + } + } + + _cleanup: + + if (d_cs) + kcdb_credset_delete(&d_cs); + + if (ctx != NULL) + pkrb5_free_context(ctx); + + return rv; +} + +int +khm_krb5_destroy_identity(khm_handle identity) +{ + krb5_context ctx; + krb5_ccache cache; + krb5_error_code rc; + + ctx = NULL; + cache = NULL; + + if (rc = khm_krb5_initialize(identity, &ctx, &cache)) + return(rc); + + rc = pkrb5_cc_destroy(ctx, cache); + + if (ctx != NULL) + pkrb5_free_context(ctx); + + return(rc); +} + +static BOOL +GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData) +{ + NTSTATUS Status = 0; + HANDLE TokenHandle; + TOKEN_STATISTICS Stats; + DWORD ReqLen; + BOOL Success; + + if (!ppSessionData) + return FALSE; + *ppSessionData = NULL; + + Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle ); + if ( !Success ) + return FALSE; + + Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen ); + CloseHandle( TokenHandle ); + if ( !Success ) + return FALSE; + + Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData ); + if ( FAILED(Status) || !ppSessionData ) + return FALSE; + + return TRUE; +} + +// IsKerberosLogon() does not validate whether or not there are valid +// tickets in the cache. It validates whether or not it is reasonable +// to assume that if we attempted to retrieve valid tickets we could +// do so. Microsoft does not automatically renew expired tickets. +// Therefore, the cache could contain expired or invalid tickets. +// Microsoft also caches the user's password and will use it to +// retrieve new TGTs if the cache is empty and tickets are requested. + +static BOOL +IsKerberosLogon(VOID) +{ + PSECURITY_LOGON_SESSION_DATA pSessionData = NULL; + BOOL Success = FALSE; + + if ( GetSecurityLogonSessionData(&pSessionData) ) { + if ( pSessionData->AuthenticationPackage.Buffer ) { + WCHAR buffer[256]; + WCHAR *usBuffer; + int usLength; + + Success = FALSE; + usBuffer = (pSessionData->AuthenticationPackage).Buffer; + usLength = (pSessionData->AuthenticationPackage).Length; + if (usLength < 256) + { + lstrcpynW (buffer, usBuffer, usLength); + StringCbCatW (buffer, sizeof(buffer), L""); + if ( !lstrcmpW(L"Kerberos",buffer) ) + Success = TRUE; + } + } + pLsaFreeReturnBuffer(pSessionData); + } + return Success; +} + + +BOOL +khm_krb5_ms2mit(char * match_princ, BOOL match_realm, BOOL save_creds, + khm_handle * ret_ident) +{ +#ifdef NO_KRB5 + return(FALSE); +#else /* NO_KRB5 */ + krb5_context kcontext = 0; + krb5_error_code code = 0; + krb5_ccache ccache=0; + krb5_ccache mslsa_ccache=0; + krb5_creds creds; + krb5_cc_cursor cursor=0; + krb5_principal princ = 0; + khm_handle ident = NULL; + wchar_t wname[KCDB_IDENT_MAXCCH_NAME]; + char cname[KCDB_IDENT_MAXCCH_NAME]; + char *cache_name = NULL; + char *princ_name = NULL; + BOOL rc = FALSE; + + kherr_reportf(L"Begin : khm_krb5_ms2mit. save_cred=%d\n", (int) save_creds); + + if ( !pkrb5_init_context ) + goto cleanup; + + if (code = pkrb5_init_context(&kcontext)) + goto cleanup; + + kherr_reportf(L"Resolving MSLSA\n"); + + if (code = pkrb5_cc_resolve(kcontext, "MSLSA:", &mslsa_ccache)) + goto cleanup; + + if ( save_creds ) { + kherr_reportf(L"Getting principal\n"); + if (code = pkrb5_cc_get_principal(kcontext, mslsa_ccache, &princ)) + goto cleanup; + + kherr_reportf(L"Unparsing name\n"); + if (code = pkrb5_unparse_name(kcontext, princ, &princ_name)) + goto cleanup; + + AnsiStrToUnicode(wname, sizeof(wname), princ_name); + + kherr_reportf(L"Unparsed name [%s]", wname); + + /* see if we have to match a specific principal */ + if (match_princ != NULL) { + if (strcmp(princ_name, match_princ)) { + kherr_reportf(L"Principal mismatch. Wanted [%S], found [%S]", + match_princ, princ_name); + goto cleanup; + } + } else if (match_realm) { + wchar_t * wdefrealm; + char defrealm[256]; + krb5_data * princ_realm; + + wdefrealm = khm_krb5_get_default_realm(); + if (wdefrealm == NULL) { + kherr_reportf(L"Can't determine default realm"); + goto cleanup; + } + + princ_realm = krb5_princ_realm(kcontext, princ); + UnicodeStrToAnsi(defrealm, sizeof(defrealm), wdefrealm); + + if (strncmp(defrealm, princ_realm->data, princ_realm->length)) { + kherr_reportf(L"Realm mismatch. Wanted [%S], found [%*S]", + defrealm, princ_realm->length, princ_realm->data); + PFREE(wdefrealm); + goto cleanup; + } + + PFREE(wdefrealm); + } + + if (KHM_SUCCEEDED(kcdb_identity_create(wname, + KCDB_IDENT_FLAG_CREATE, + &ident))) { + khm_handle idconfig = NULL; + khm_handle k5config = NULL; + khm_size cb; + + wname[0] = L'\0'; + + kcdb_identity_get_config(ident, KHM_FLAG_CREATE, &idconfig); + if (idconfig == NULL) + goto _done_checking_config; + + khc_open_space(idconfig, CSNAME_KRB5CRED, KHM_FLAG_CREATE, &k5config); + if (k5config == NULL) + goto _done_checking_config; + + cb = sizeof(wname); + khc_read_string(k5config, + L"DefaultCCName", + wname, &cb); + + _done_checking_config: + + if (idconfig) + khc_close_space(idconfig); + if (k5config) + khc_close_space(k5config); + + if (wname[0]) { + UnicodeStrToAnsi(cname, sizeof(cname), wname); + } else { + StringCbPrintfA(cname, sizeof(cname), "API:%s", princ_name); + } + + cache_name = cname; + + } else { + /* the identity could not be created. we just use the + name of the principal as the ccache name. */ + StringCbPrintfA(cname, sizeof(cname), "API:%s", princ_name); + cache_name = cname; + } + + kherr_reportf(L"Resolving target cache [%S]\n", cache_name); + + if (code = pkrb5_cc_resolve(kcontext, cache_name, &ccache)) { + kherr_reportf(L"Cannot resolve cache [%S] with code=%d. Trying default.\n", cache_name, code); + + if (code = pkrb5_cc_default(kcontext, &ccache)) { + kherr_reportf(L"Failed to resolve default ccache. Code=%d", code); + goto cleanup; + } + } + + kherr_reportf(L"Initializing ccache\n"); + if (code = pkrb5_cc_initialize(kcontext, ccache, princ)) + goto cleanup; + + kherr_reportf(L"Copying credentials\n"); + if (code = pkrb5_cc_copy_creds(kcontext, mslsa_ccache, ccache)) + goto cleanup; + + /* and mark the identity as having been imported */ + if (ident) { + khm_krb5_set_identity_flags(ident, K5IDFLAG_IMPORTED, K5IDFLAG_IMPORTED); + + if (ret_ident) { + *ret_ident = ident; + kcdb_identity_hold(*ret_ident); + } + } + + rc = TRUE; + + } else { + /* Enumerate tickets from cache looking for an initial ticket */ + if ((code = pkrb5_cc_start_seq_get(kcontext, mslsa_ccache, &cursor))) + goto cleanup; + + while (!(code = pkrb5_cc_next_cred(kcontext, mslsa_ccache, + &cursor, &creds))) { + if ( creds.ticket_flags & TKT_FLG_INITIAL ) { + rc = TRUE; + pkrb5_free_cred_contents(kcontext, &creds); + break; + } + pkrb5_free_cred_contents(kcontext, &creds); + } + pkrb5_cc_end_seq_get(kcontext, mslsa_ccache, &cursor); + } + +cleanup: + kherr_reportf(L" Received code=%d", code); + + if (princ_name) + pkrb5_free_unparsed_name(kcontext, princ_name); + if (princ) + pkrb5_free_principal(kcontext, princ); + if (ccache) + pkrb5_cc_close(kcontext, ccache); + if (mslsa_ccache) + pkrb5_cc_close(kcontext, mslsa_ccache); + if (kcontext) + pkrb5_free_context(kcontext); + if (ident) + kcdb_identity_release(ident); + + return(rc); +#endif /* NO_KRB5 */ +} + +#define KRB_FILE "KRB.CON" +#define KRBREALM_FILE "KRBREALM.CON" +#define KRB5_FILE "KRB5.INI" +#define KRB5_TMP_FILE "KRB5.INI.TMP" + +BOOL +khm_krb5_get_temp_profile_file(LPSTR confname, UINT szConfname) +{ + GetTempPathA(szConfname, confname); + confname[szConfname-1] = '\0'; + StringCchCatA(confname, szConfname, KRB5_TMP_FILE); + confname[szConfname-1] = '\0'; + return FALSE; +} + +#ifdef NOT_QUITE_IMPLEMENTED_YET +BOOL +khm_krb5_set_profile_file(krb5_context ctx, LPSTR confname) +{ + char *conffiles[2]; + + if (confname == NULL || + pkrb5_set_config_files == NULL || + ctx == NULL) + return FALSE; + + conffiles[0] = confname; + conffiles[1] = NULL; + + if (pkrb5_set_config_files(ctx, conffiles)) + return FALSE; + else + return TRUE; +} +#endif + +BOOL +khm_krb5_get_profile_file(LPSTR confname, UINT szConfname) +{ + char **configFile = NULL; + if (pkrb5_get_default_config_files(&configFile)) + { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + + StringCchCatA(confname, szConfname, "\\"); + StringCchCatA(confname, szConfname, KRB5_FILE); + + return FALSE; + } + + *confname = 0; + + if (configFile) + { + StringCchCopyA(confname, szConfname, *configFile); + pkrb5_free_config_files(configFile); + } + + if (!*confname) + { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + StringCchCatA(confname, szConfname, "\\"); + StringCchCatA(confname, szConfname, KRB5_FILE); + } + + return FALSE; +} + +BOOL +khm_get_krb4_con_file(LPSTR confname, UINT szConfname) +{ + if (hKrb5 && !hKrb4) { // hold krb.con where krb5.ini is located + CHAR krbConFile[MAX_PATH]=""; + LPSTR pFind; + + //strcpy(krbConFile, CLeashApp::m_krbv5_profile->first_file->filename); + if (khm_krb5_get_profile_file(krbConFile, sizeof(krbConFile))) { + GetWindowsDirectoryA(krbConFile,sizeof(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + StringCchCatA(confname, szConfname, "\\"); + } + + pFind = strrchr(krbConFile, '\\'); + if (pFind) { + *pFind = '\0'; + StringCchCatA(krbConFile, ARRAYLENGTH(krbConFile), "\\"); + StringCchCatA(krbConFile, ARRAYLENGTH(krbConFile), KRB_FILE); + } + else + krbConFile[0] = '\0'; + + StringCchCopyA(confname, szConfname, krbConFile); + } + else if (hKrb4) { + unsigned int size = szConfname; + memset(confname, '\0', szConfname); + if (!pkrb_get_krbconf2(confname, &size)) + { // Error has happened + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + StringCchCatA(confname, szConfname, "\\"); + StringCchCatA(confname, szConfname, KRB_FILE); + } + } + return FALSE; +} + +int +readstring(FILE * file, char * buf, int len) +{ + int c,i; + memset(buf, '\0', sizeof(buf)); + for (i=0, c=fgetc(file); c != EOF ; c=fgetc(file), i++) { + if (i < sizeof(buf)) { + if (c == '\n') { + buf[i] = '\0'; + return i; + } else { + buf[i] = c; + } + } else { + if (c == '\n') { + buf[len-1] = '\0'; + return(i); + } + } + } + if (c == EOF) { + if (i > 0 && i < len) { + buf[i] = '\0'; + return(i); + } else { + buf[len-1] = '\0'; + return(-1); + } + } + return(-1); +} + +/*! \internal + \brief Return a list of configured realms + + The string that is returned is a set of null terminated unicode + strings, each of which denotes one realm. The set is terminated + by a zero length null terminated string. + + The caller should free the returned string using free() + + \return The string with the list of realms or NULL if the + operation fails. +*/ +wchar_t * +khm_krb5_get_realm_list(void) +{ + wchar_t * rlist = NULL; + + if (pprofile_get_subsection_names && pprofile_free_list) { + const char* rootSection[] = {"realms", NULL}; + const char** rootsec = rootSection; + char **sections = NULL, **cpp = NULL, *value = NULL; + + char krb5_conf[MAX_PATH+1]; + + if (!khm_krb5_get_profile_file(krb5_conf,sizeof(krb5_conf))) { + profile_t profile; + long retval; + const char *filenames[2]; + wchar_t * d; + size_t cbsize; + size_t t; + + filenames[0] = krb5_conf; + filenames[1] = NULL; + retval = pprofile_init(filenames, &profile); + if (!retval) { + retval = pprofile_get_subsection_names(profile, rootsec, + §ions); + + if (!retval) + { + /* first figure out how much space to allocate */ + cbsize = 0; + for (cpp = sections; *cpp; cpp++) + { + cbsize += sizeof(wchar_t) * (strlen(*cpp) + 1); + } + cbsize += sizeof(wchar_t); /* double null terminated */ + + rlist = PMALLOC(cbsize); + d = rlist; + for (cpp = sections; *cpp; cpp++) + { + AnsiStrToUnicode(d, cbsize, *cpp); + t = wcslen(d) + 1; + d += t; + cbsize -= sizeof(wchar_t) * t; + } + *d = L'\0'; + } + + pprofile_free_list(sections); + +#if 0 + retval = pprofile_get_string(profile, "libdefaults","noaddresses", 0, "true", &value); + if ( value ) { + disable_noaddresses = config_boolean_to_int(value); + pprofile_release_string(value); + } +#endif + pprofile_release(profile); + } + } + } else { + FILE * file; + char krb_conf[MAX_PATH+1]; + char * p; + size_t cbsize, t; + wchar_t * d; + + if (!khm_get_krb4_con_file(krb_conf,sizeof(krb_conf)) && +#if _MSC_VER >= 1400 + !fopen_s(&file, krb_conf, "rt") +#else + (file = fopen(krb_conf, "rt")) +#endif + ) + { + char lineBuf[256]; + + /*TODO: compute the actual required buffer size instead of hardcoding */ + cbsize = 16384; // arbitrary + rlist = PMALLOC(cbsize); + d = rlist; + + // Skip the default realm + readstring(file,lineBuf,sizeof(lineBuf)); + + // Read the defined realms + while (TRUE) + { + if (readstring(file,lineBuf,sizeof(lineBuf)) < 0) + break; + + if (*(lineBuf + strlen(lineBuf) - 1) == '\r') + *(lineBuf + strlen(lineBuf) - 1) = 0; + + for (p=lineBuf; *p ; p++) + { + if (isspace(*p)) { + *p = 0; + break; + } + } + + if ( strncmp(".KERBEROS.OPTION.",lineBuf,17) ) { + t = strlen(lineBuf) + 1; + if(cbsize > (1 + t*sizeof(wchar_t))) { + AnsiStrToUnicode(d, cbsize, lineBuf); + d += t; + cbsize -= t * sizeof(wchar_t); + } else + break; + } + } + + *d = L'\0'; + + fclose(file); + } + } + + return rlist; +} + +/*! \internal + \brief Get the default realm + + A string will be returned that specifies the default realm. The + caller should free the string using PFREE(). + + Returns NULL if the operation fails. +*/ +wchar_t * +khm_krb5_get_default_realm(void) +{ + wchar_t * realm; + size_t cch; + krb5_context ctx=0; + char * def = 0; + + pkrb5_init_context(&ctx); + + if (ctx == 0) + return NULL; + + pkrb5_get_default_realm(ctx,&def); + + if (def) { + cch = strlen(def) + 1; + realm = PMALLOC(sizeof(wchar_t) * cch); + AnsiStrToUnicode(realm, sizeof(wchar_t) * cch, def); + pkrb5_free_default_realm(ctx, def); + } else + realm = NULL; + + pkrb5_free_context(ctx); + + return realm; +} + +long +khm_krb5_set_default_realm(wchar_t * realm) { + krb5_context ctx=0; + char * def = 0; + long rv = 0; + char astr[K5_MAXCCH_REALM]; + + UnicodeStrToAnsi(astr, sizeof(astr), realm); + + pkrb5_init_context(&ctx); + pkrb5_get_default_realm(ctx,&def); + + if ((def && strcmp(def, astr)) || + !def) { + rv = pkrb5_set_default_realm(ctx, astr); + } + + if (def) { + pkrb5_free_default_realm(ctx, def); + } + + pkrb5_free_context(ctx); + + return rv; +} + +wchar_t * +khm_get_realm_from_princ(wchar_t * princ) { + wchar_t * t; + + if(!princ) + return NULL; + + for (t = princ; *t; t++) { + if(*t == L'\\') { /* escape */ + t++; + if(! *t) /* malformed */ + break; + } else if (*t == L'@') + break; + } + + if (*t == '@' && *(t+1) != L'\0') + return (t+1); + else + return NULL; +} + +long +khm_krb5_changepwd(char * principal, + char * password, + char * newpassword, + char** error_str) +{ + krb5_error_code rc = 0; + int result_code = 0; + krb5_data result_code_string, result_string; + krb5_context context = 0; + krb5_principal princ = 0; + krb5_get_init_creds_opt opts; + krb5_creds creds; + + result_string.data = 0; + result_code_string.data = 0; + + if ( !pkrb5_init_context ) + goto cleanup; + + if (rc = pkrb5_init_context(&context)) { + goto cleanup; + } + + if (rc = pkrb5_parse_name(context, principal, &princ)) { + goto cleanup; + } + + pkrb5_get_init_creds_opt_init(&opts); + pkrb5_get_init_creds_opt_set_tkt_life(&opts, 5*60); + pkrb5_get_init_creds_opt_set_renew_life(&opts, 0); + pkrb5_get_init_creds_opt_set_forwardable(&opts, 0); + pkrb5_get_init_creds_opt_set_proxiable(&opts, 0); + pkrb5_get_init_creds_opt_set_address_list(&opts,NULL); + + if (rc = pkrb5_get_init_creds_password(context, &creds, princ, + password, 0, 0, 0, + "kadmin/changepw", &opts)) { + if (rc == KRB5KRB_AP_ERR_BAD_INTEGRITY) { +#if 0 + com_err(argv[0], 0, + "Password incorrect while getting initial ticket"); +#endif + } else { +#if 0 + com_err(argv[0], ret, "getting initial ticket"); +#endif + } + goto cleanup; + } + + if (rc = pkrb5_change_password(context, &creds, newpassword, + &result_code, &result_code_string, + &result_string)) { +#if 0 + com_err(argv[0], ret, "changing password"); +#endif + goto cleanup; + } + + if (result_code) { + int len = result_code_string.length + + (result_string.length ? (sizeof(": ") - 1) : 0) + + result_string.length; + if (len && error_str) { + *error_str = PMALLOC(len + 1); + if (*error_str) + StringCchPrintfA(*error_str, len+1, + "%.*s%s%.*s", + result_code_string.length, + result_code_string.data, + result_string.length?": ":"", + result_string.length, + result_string.data); + } + rc = result_code; + goto cleanup; + } + + cleanup: + if (result_string.data) + pkrb5_free_data_contents(context, &result_string); + + if (result_code_string.data) + pkrb5_free_data_contents(context, &result_code_string); + + if (princ) + pkrb5_free_principal(context, princ); + + if (context) + pkrb5_free_context(context); + + return rc; +} + +khm_int32 KHMAPI +khm_krb5_creds_is_equal(khm_handle vcred1, khm_handle vcred2, void * dummy) { + if (kcdb_creds_comp_attr(vcred1, vcred2, KCDB_ATTR_LOCATION) || + kcdb_creds_comp_attr(vcred1, vcred2, attr_id_key_enctype) || + kcdb_creds_comp_attr(vcred1, vcred2, attr_id_tkt_enctype) || + kcdb_creds_comp_attr(vcred1, vcred2, attr_id_kvno)) + return 1; + else + return 0; +} + +void +khm_krb5_set_identity_flags(khm_handle identity, + khm_int32 flag_mask, + khm_int32 flag_value) { + + khm_int32 t = 0; + khm_size cb; + + cb = sizeof(t); + if (KHM_FAILED(kcdb_identity_get_attr(identity, + attr_id_krb5_idflags, + NULL, + &t, &cb))) { + t = 0; + } + + t &= ~flag_mask; + t |= (flag_value & flag_mask); + + kcdb_identity_set_attr(identity, + attr_id_krb5_idflags, + &t, sizeof(t)); +} + +khm_int32 +khm_krb5_get_identity_flags(khm_handle identity) { + khm_int32 t = 0; + khm_size cb; + + cb = sizeof(t); + kcdb_identity_get_attr(identity, + attr_id_krb5_idflags, + NULL, &t, &cb); + + return t; +} + +long +khm_krb5_get_temp_ccache(krb5_context ctx, + krb5_ccache * prcc) { + int rnd = rand(); + char ccname[MAX_PATH]; + long code = 0; + krb5_ccache cc = 0; + + StringCbPrintfA(ccname, sizeof(ccname), "MEMORY:TempCache%8x", rnd); + + code = pkrb5_cc_resolve(ctx, ccname, &cc); + + if (code == 0) + *prcc = cc; + + return code; +} + +/* + + The configuration information for each identity comes from a + multitude of layers organized as follows. The ordering is + decreasing in priority. When looking up a value, the value will be + looked up in each layer in turn starting at level 0. The first + instance of the value found will be the effective value. + + 0 : \Krb5Cred + + 0.1: per user + + 0.2: per machine + + 1 : \Parameters\Realms\ + + 1.1: per user + + 1.2: per machine + + 2 : \Parameters + + 2.1: per user + + 2.2: per machine + + 2.3: schema + + */ +khm_int32 +khm_krb5_get_identity_config(khm_handle ident, + khm_int32 flags, + khm_handle * ret_csp) { + + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_handle csp_i = NULL; + khm_handle csp_ik5 = NULL; + khm_handle csp_realms = NULL; + khm_handle csp_realm = NULL; + khm_handle csp_plugins = NULL; + khm_handle csp_krbcfg = NULL; + khm_handle csp_rv = NULL; + wchar_t realm[KCDB_IDENT_MAXCCH_NAME]; + + realm[0] = L'\0'; + + if (ident) { + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t * trealm; + khm_size cb_idname = sizeof(idname); + + rv = kcdb_identity_get_name(ident, idname, &cb_idname); + if (KHM_SUCCEEDED(rv) && + (trealm = khm_get_realm_from_princ(idname)) != NULL) { + StringCbCopy(realm, sizeof(realm), trealm); + } + } + + if (ident) { + rv = kcdb_identity_get_config(ident, flags, &csp_i); + if (KHM_FAILED(rv)) + goto try_realm; + + rv = khc_open_space(csp_i, CSNAME_KRB5CRED, flags, &csp_ik5); + if (KHM_FAILED(rv)) + goto try_realm; + + try_realm: + + if (realm[0] == L'\0') + goto done_shadow_realm; + + rv = khc_open_space(csp_params, CSNAME_REALMS, flags, &csp_realms); + if (KHM_FAILED(rv)) + goto done_shadow_realm; + + rv = khc_open_space(csp_realms, realm, flags, &csp_realm); + if (KHM_FAILED(rv)) + goto done_shadow_realm; + + rv = khc_shadow_space(csp_realm, csp_params); + + done_shadow_realm: + + if (csp_ik5) { + if (csp_realm) + rv = khc_shadow_space(csp_ik5, csp_realm); + else + rv = khc_shadow_space(csp_ik5, csp_params); + + csp_rv = csp_ik5; + } else { + if (csp_realm) + csp_rv = csp_realm; + } + } + + if (csp_rv == NULL) { + + /* No valid identity specified or the specified identity + doesn't have any configuration. We default to the + parameters key. */ + + /* we don't just return csp_params since that's a global + handle that we shouldn't close until the plugin is + unloaded. The caller is going to close the returned handle + when it is done. So we need to create a new csp_params + that can safely be closed. */ + + rv = kmm_get_plugins_config(0, &csp_plugins); + if (KHM_FAILED(rv)) + goto done; + + rv = khc_open_space(csp_plugins, CSNAME_KRB5CRED, flags, &csp_krbcfg); + if (KHM_FAILED(rv)) + goto done; + + rv = khc_open_space(csp_krbcfg, CSNAME_PARAMS, flags, &csp_rv); + } + + done: + + *ret_csp = csp_rv; + + /* leave csp_ik5. If it's non-NULL, then it's the return value */ + /* leave csp_rv. It's the return value. */ + if (csp_i) + khc_close_space(csp_i); + if (csp_realms) + khc_close_space(csp_realms); + + /* csp_realm can also be a return value if csp_ik5 was NULL */ + if (csp_realm && csp_realm != csp_rv) + khc_close_space(csp_realm); + + if (csp_plugins) + khc_close_space(csp_plugins); + if (csp_krbcfg) + khc_close_space(csp_krbcfg); + + return rv; +} + +/* from get_in_tkt.c */ +static krb5_error_code +get_libdefault_string(profile_t profile, const char * realm, + const char * option, char ** ret_val) { + char realmstr[K5_MAXCCH_REALM]; + char **nameval = NULL; + const char * names[4]; + krb5_error_code code = 0; + + names[0] = "libdefaults"; + + if (!realm || !realm[0]) + goto try_number_two; + + StringCbCopyA(realmstr, sizeof(realmstr), realm); + + /* + * Try number one: + * + * [libdefaults] + * REALM = { + * option = + * } + */ + + names[1] = realmstr; + names[2] = option; + names[3] = 0; + code = pprofile_get_values(profile, names, &nameval); + if (code == 0 && nameval && nameval[0]) + goto goodbye; + + try_number_two: + + /* + * Try number two: + * + * [libdefaults] + * option = + */ + + names[1] = option; + names[2] = 0; + code = pprofile_get_values(profile, names, &nameval); + if (code == 0 && nameval && nameval[0]) + goto goodbye; + + goodbye: + if (!nameval) + return(ENOENT); + + if (!nameval[0]) { + code = ENOENT; + } else { + size_t cb; + + if (FAILED(StringCbLengthA(nameval[0], K5_MAXCCH_REALM * sizeof(char), &cb))) { + code = ENOMEM; + } else { + cb += sizeof(char); + *ret_val = PMALLOC(cb); + + if (!*ret_val) + code = ENOMEM; + else { + StringCbCopyA(*ret_val, cb, nameval[0]); + code = 0; + } + } + } + + pprofile_free_list(nameval); + + return code; +} + +khm_int32 +khm_krb5_get_identity_params(khm_handle ident, k5_params * p) { + + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_handle csp_id = NULL; + khm_int32 regf = 0; + khm_int32 proff = 0; + khm_int32 e; + khm_int32 v; + CHAR confname[MAX_PATH]; + CHAR realmname[K5_MAXCCH_REALM]; + + ZeroMemory(p, sizeof(*p)); + + rv = khm_krb5_get_identity_config(ident, 0, &csp_id); + if (KHM_FAILED(rv)) + goto done_reg; + + +#define GETVAL(vname, vfield, flag) \ + do { \ + e = khc_value_exists(csp_id, vname); \ + rv = khc_read_int32(csp_id, vname, &v); \ + if (KHM_FAILED(rv)) goto done_reg; \ + p->vfield = v; \ + if ((e & ~KCONF_FLAG_SCHEMA) != 0) regf |= flag; \ + } while(FALSE) + + /* Flags */ + GETVAL(L"Renewable", renewable, K5PARAM_F_RENEW); + GETVAL(L"Forwardable", forwardable, K5PARAM_F_FORW); + GETVAL(L"Proxiable", proxiable, K5PARAM_F_PROX); + GETVAL(L"Addressless", addressless, K5PARAM_F_ADDL); + GETVAL(L"PublicIP", publicIP, K5PARAM_F_PUBIP); + + /* Lifetime */ + GETVAL(L"DefaultLifetime", lifetime, K5PARAM_F_LIFE); + GETVAL(L"MaxLifetime", lifetime_max, K5PARAM_F_LIFE_H); + GETVAL(L"MinLifetime", lifetime_min, K5PARAM_F_LIFE_L); + + /* Renewable lifetime */ + GETVAL(L"DefaultRenewLifetime", renew_life, K5PARAM_F_RLIFE); + GETVAL(L"MaxRenewLifetime", renew_life_max, K5PARAM_F_RLIFE_H); + GETVAL(L"MinRenewLifetime", renew_life_min, K5PARAM_F_RLIFE_L); + +#undef GETVAL + + done_reg: + + if (csp_id) + khc_close_space(csp_id); + + /* if all the parameters were read from the registry, then we have + no reason to read from the profile file. */ + if (regf == K5PARAM_FM_ALL) { + p->source_reg = regf; + return KHM_ERROR_SUCCESS; + } + + if (rv) + return rv; + + /* we need to figure out the realm name, since there might be + per-realm configuration in the profile file. */ + + realmname[0] = '\0'; + + if (ident) { + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + + idname[0] = L'\0'; + cb = sizeof(idname); + rv = kcdb_identity_get_name(ident, idname, &cb); + if (KHM_SUCCEEDED(rv)) { + wchar_t * wrealm; + + wrealm = khm_get_realm_from_princ(idname); + if (wrealm) { + UnicodeStrToAnsi(realmname, sizeof(realmname), wrealm); + } + } + } + + /* If we get here, then some of the settings we read from the + configuration actually came from the schema. In other words, + the values weren't really defined for this identity. So we now + have to read the values from the krb5 configuration file. */ + + if (!khm_krb5_get_profile_file(confname, sizeof(confname))) { + profile_t profile; + const char * filenames[2]; + long retval; + + filenames[0] = confname; + filenames[1] = NULL; + + if (!pprofile_init(filenames, &profile)) { + + /* default ticket lifetime */ + if (!(regf & K5PARAM_F_LIFE)) { + char * value = NULL; + retval = get_libdefault_string(profile, realmname, + "ticket_lifetime", &value); + + if (retval == 0 && value) { + krb5_deltat d; + + retval = pkrb5_string_to_deltat(value, &d); + if (retval == KRB5_DELTAT_BADFORMAT) { + /* Historically some sites use relations of + the form 'ticket_lifetime = 24000' where + the unit is left out but is assumed to be + seconds. Then there are other sites which + use the form 'ticket_lifetime = 600' where + the unit is assumed to be minutes. While + these are technically wrong (a unit needs + to be specified), we try to accomodate for + this using the safe assumption that the + unit is seconds and tack an 's' to the end + and see if that works. */ + + size_t cch; + char tmpbuf[256]; + char * buf; + + do { + if (FAILED(StringCchLengthA(value, 1024 /* unresonably large size */, + &cch))) + break; + + cch += sizeof(char) * 2; /* NULL and new 's' */ + if (cch > ARRAYLENGTH(tmpbuf)) + buf = PMALLOC(cch * sizeof(char)); + else + buf = tmpbuf; + + StringCchCopyA(buf, cch, value); + StringCchCatA(buf, cch, "s"); + + retval = pkrb5_string_to_deltat(buf, &d); + if (retval == 0) { + p->lifetime = d; + proff |= K5PARAM_F_LIFE; + } + + if (buf != tmpbuf) + PFREE(buf); + + } while(0); + + } else if (retval == 0) { + p->lifetime = d; + proff |= K5PARAM_F_LIFE; + } + + PFREE(value); + } + } + + if (!(regf & K5PARAM_F_RLIFE)) { + char * value = NULL; + retval = get_libdefault_string(profile, realmname, + "renew_lifetime", &value); + if (retval == 0 && value) { + krb5_deltat d; + + retval = pkrb5_string_to_deltat(value, &d); + if (retval == 0) { + p->renew_life = d; + proff |= K5PARAM_F_RLIFE; + } + PFREE(value); + } + } + + if (!(regf & K5PARAM_F_FORW)) { + char * value = NULL; + retval = get_libdefault_string(profile, realmname, + "forwardable", &value); + if (retval == 0 && value) { + khm_boolean b; + + if (!khm_krb5_parse_boolean(value, &b)) + p->forwardable = b; + else + p->forwardable = FALSE; + PFREE(value); + proff |= K5PARAM_F_FORW; + } + } + + if (!(regf & K5PARAM_F_RENEW)) { + char * value = NULL; + retval = get_libdefault_string(profile, realmname, + "renewable", &value); + if (retval == 0 && value) { + khm_boolean b; + + if (!khm_krb5_parse_boolean(value, &b)) + p->renewable = b; + else + p->renewable = TRUE; + PFREE(value); + proff |= K5PARAM_F_RENEW; + } + } + + if (!(regf & K5PARAM_F_ADDL)) { + char * value = NULL; + retval = get_libdefault_string(profile, realmname, + "noaddresses", &value); + if (retval == 0 && value) { + khm_boolean b; + + if (!khm_krb5_parse_boolean(value, &b)) + p->addressless = b; + else + p->addressless = TRUE; + PFREE(value); + proff |= K5PARAM_F_ADDL; + } + } + + if (!(regf & K5PARAM_F_PROX)) { + char * value = NULL; + retval = get_libdefault_string(profile, realmname, + "proxiable", &value); + if (retval == 0 && value) { + khm_boolean b; + + if (!khm_krb5_parse_boolean(value, &b)) + p->proxiable = b; + else + p->proxiable = FALSE; + PFREE(value); + proff |= K5PARAM_F_PROX; + } + } + + pprofile_release(profile); + } + } + + p->source_reg = regf; + p->source_prof = proff; + + return rv; +} + +/* Note that p->source_reg and p->source_prof is used in special ways + here. All fields that are flagged in source_reg will be written to + the configuration (if they are different from what + khm_krb5_get_identity_params() reports). All fields that are + flagged in source_prof will be removed from the configuration + (thereby exposing the value defined in the profile file). */ +khm_int32 +khm_krb5_set_identity_params(khm_handle ident, const k5_params * p) { + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_handle csp_id = NULL; + k5_params p_s; + khm_int32 source_reg = p->source_reg; + khm_int32 source_prof = p->source_prof; + + rv = khm_krb5_get_identity_config(ident, + KHM_PERM_WRITE | KHM_FLAG_CREATE | + KCONF_FLAG_WRITEIFMOD, + &csp_id); + if (KHM_FAILED(rv)) + goto done_reg; + + khm_krb5_get_identity_params(ident, &p_s); + + /* Remove any bits that don't make sense. Not all values can be + specified in the profile file. */ + source_prof &= K5PARAM_FM_PROF; + + /* if a flag appears in both source_prof and source_reg, remove + the flag from source_reg. */ + source_reg &= ~source_prof; + + /* we only write values that have changed, and that are flagged in + source_reg */ + + if ((source_reg & K5PARAM_F_RENEW) && + !!p_s.renewable != !!p->renewable) + khc_write_int32(csp_id, L"Renewable", !!p->renewable); + + if ((source_reg & K5PARAM_F_FORW) && + !!p_s.forwardable != !!p->forwardable) + khc_write_int32(csp_id, L"Forwardable", !!p->forwardable); + + if ((source_reg & K5PARAM_F_PROX) && + !!p_s.proxiable != !!p->proxiable) + khc_write_int32(csp_id, L"Proxiable", !!p->proxiable); + + if ((source_reg & K5PARAM_F_ADDL) && + !!p_s.addressless != !!p->addressless) + khc_write_int32(csp_id, L"Addressless", !!p->addressless); + + if ((source_reg & K5PARAM_F_PUBIP) && + p_s.publicIP != p->publicIP) + khc_write_int32(csp_id, L"PublicIP", p->publicIP); + + if ((source_reg & K5PARAM_F_LIFE) && + p_s.lifetime != p->lifetime) + khc_write_int32(csp_id, L"DefaultLifetime", p->lifetime); + + if ((source_reg & K5PARAM_F_LIFE_H) && + p_s.lifetime_max != p->lifetime_max) + khc_write_int32(csp_id, L"MaxLifetime", p->lifetime_max); + + if ((source_reg & K5PARAM_F_LIFE_L) && + p_s.lifetime_min != p->lifetime_min) + khc_write_int32(csp_id, L"MinLifetime", p->lifetime_min); + + if ((source_reg & K5PARAM_F_RLIFE) && + p_s.renew_life != p->renew_life) + khc_write_int32(csp_id, L"DefaultRenewLifetime", p->renew_life); + + if ((source_reg & K5PARAM_F_RLIFE_H) && + p_s.renew_life_max != p->renew_life_max) + khc_write_int32(csp_id, L"MaxRenewLifetime", p->renew_life_max); + + if ((source_reg & K5PARAM_F_RLIFE_L) && + p_s.renew_life_min != p->renew_life_min) + khc_write_int32(csp_id, L"MinRenewLifetime", p->renew_life_min); + + /* and now, remove the values that are present in source_prof. + Not all values are removed since not all values can be + specified in the profile file. */ + if (source_prof & K5PARAM_F_RENEW) + khc_remove_value(csp_id, L"Renewable", 0); + + if (source_prof & K5PARAM_F_FORW) + khc_remove_value(csp_id, L"Forwardable", 0); + + if (source_prof & K5PARAM_F_PROX) + khc_remove_value(csp_id, L"Proxiable", 0); + + if (source_prof & K5PARAM_F_ADDL) + khc_remove_value(csp_id, L"Addressless", 0); + + if (source_prof & K5PARAM_F_LIFE) + khc_remove_value(csp_id, L"DefaultLifetime", 0); + + if (source_prof & K5PARAM_F_RLIFE) + khc_remove_value(csp_id, L"DefaultRenewLifetime", 0); + + done_reg: + if (csp_id != NULL) + khc_close_space(csp_id); + + return rv; +} + +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 +khm_krb5_parse_boolean(const char *s, khm_boolean * b) +{ + const char *const *p; + + for(p=conf_yes; *p; p++) { + if (!_stricmp(*p,s)) { + *b = TRUE; + return 0; + } + } + + for(p=conf_no; *p; p++) { + if (!_stricmp(*p,s)) { + *b = FALSE; + return 0; + } + } + + /* Default to "no" */ + return KHM_ERROR_INVALID_PARAM; +} diff --git a/src/windows/identity/plugins/krb5/krb5funcs.h b/src/windows/identity/plugins/krb5/krb5funcs.h index b4ab452b3..d2ec28b47 100644 --- a/src/windows/identity/plugins/krb5/krb5funcs.h +++ b/src/windows/identity/plugins/krb5/krb5funcs.h @@ -1,217 +1,217 @@ -/* - * 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$ */ - -/* Adapted from multiple Leash header files */ - -#ifndef __KHIMAIRA_KRB5FUNCS_H -#define __KHIMAIRA_KRB5FUNCS_H - -#include -#include - -#include -#define SECURITY_WIN32 -#include - -#if _WIN32_WINNT < 0x0501 -#define KHM_SAVE_WIN32_WINNT _WIN32_WINNT -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif -#include -#ifdef KHM_SAVE_WIN32_WINNT -#undef _WIN32_WINNT -#define _WIN32_WINNT KHM_SAVE_WIN32_WINNT -#undef KHM_SAVE_WIN32_WINNT -#endif - -#include - -#define LEASH_DEBUG_CLASS_GENERIC 0 -#define LEASH_DEBUG_CLASS_KRB4 1 -#define LEASH_DEBUG_CLASS_KRB4_APP 2 - -#define LEASH_PRIORITY_LOW 0 -#define LEASH_PRIORITY_HIGH 1 - -#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ - -#define KRB5_MAXCCH_CCNAME 1024 - -#define KRB5_CONF_YES "yes" -#define KRB5_CONF_NO "no" - -typedef struct tag_k5params { - - khm_int32 source_reg; /* flags indicating which fields were - retrieved using the registry */ - khm_int32 source_prof; /* flags indicating which fields were - retrieved using krb5.ini */ - - khm_boolean renewable; - khm_boolean forwardable; - khm_boolean proxiable; - khm_boolean addressless; - - khm_ui_4 publicIP; - - krb5_deltat lifetime; - krb5_deltat lifetime_min; - krb5_deltat lifetime_max; - - krb5_deltat renew_life; - krb5_deltat renew_life_min; - krb5_deltat renew_life_max; - -} k5_params; - -#define K5PARAM_F_RENEW 0x00000001 -#define K5PARAM_F_FORW 0x00000002 -#define K5PARAM_F_PROX 0x00000004 -#define K5PARAM_F_ADDL 0x00000008 -#define K5PARAM_F_PUBIP 0x00000010 -#define K5PARAM_F_LIFE 0x00000020 -#define K5PARAM_F_RLIFE 0x00000040 -#define K5PARAM_F_LIFE_L 0x00000080 -#define K5PARAM_F_LIFE_H 0x00000100 -#define K5PARAM_F_RLIFE_L 0x00000200 -#define K5PARAM_F_RLIFE_H 0x00000400 - -#define K5PARAM_FM_ALL 0x000007ff -#define K5PARAM_FM_PROF 0x0000007f - -/* Credential and principal operations */ - -BOOL -khm_krb5_ms2mit(char * match_princ, - BOOL match_realm, - BOOL save_creds, - khm_handle * ret_ident); - -int -khm_krb5_kinit(krb5_context alt_ctx, - char * principal_name, - char * password, - char * ccache, - krb5_deltat lifetime, - DWORD forwardable, - DWORD proxiable, - krb5_deltat renew_life, - DWORD addressless, - DWORD publicIP, - krb5_prompter_fct prompter, - void * p_data); - -long -khm_krb5_changepwd(char * principal, - char * password, - char * newpassword, - char** error_str); - -int -khm_krb5_destroy_by_credset(khm_handle p_cs); - -int -khm_krb5_destroy_identity(khm_handle identity); - -long -khm_convert524(krb5_context ctx); - -int -khm_krb5_renew_cred(khm_handle cred); - -int -khm_krb5_renew_ident(khm_handle identity); - -long -khm_krb5_list_tickets(krb5_context *krbv5Context); - -long -khm_krb5_copy_ccache_by_name(krb5_context in_ctx, - wchar_t * wscc_dest, - wchar_t * wscc_src); - -long -khm_krb5_get_temp_ccache(krb5_context ctx, - krb5_ccache * cc); - -khm_int32 KHMAPI -khm_krb5_creds_is_equal(khm_handle vcred1, khm_handle vcred2, void * dummy); - - -/* Configuration */ - -BOOL -khm_krb5_get_profile_file(LPSTR confname, UINT szConfname); - -BOOL -khm_krb5_get_temp_profile_file(LPSTR confname, UINT szConfname); - -wchar_t * -khm_krb5_get_default_realm(void); - -long -khm_krb5_set_default_realm(wchar_t * realm); - -wchar_t * -khm_krb5_get_realm_list(void); - -khm_int32 -khm_krb5_get_identity_config(khm_handle ident, - khm_int32 flags, - khm_handle * ret_csp); - -void -khm_krb5_set_identity_flags(khm_handle identity, - khm_int32 flag_mask, - khm_int32 flag_value); - -khm_int32 -khm_krb5_get_identity_flags(khm_handle identity); - -khm_int32 -khm_krb5_set_identity_params(khm_handle ident, const k5_params * p); - -khm_int32 -khm_krb5_get_identity_params(khm_handle ident, k5_params * p); - -/* Utility */ - -wchar_t * -khm_get_realm_from_princ(wchar_t * princ); - -long -khm_krb5_canon_cc_name(wchar_t * wcc_name, - size_t cb_cc_name); - -int -khm_krb5_cc_name_cmp(const wchar_t * cc_name_1, - const wchar_t * cc_name_2); - -int -khm_krb5_parse_boolean(const char *s, khm_boolean * b); - -#endif +/* + * 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$ */ + +/* Adapted from multiple Leash header files */ + +#ifndef __KHIMAIRA_KRB5FUNCS_H +#define __KHIMAIRA_KRB5FUNCS_H + +#include +#include + +#include +#define SECURITY_WIN32 +#include + +#if _WIN32_WINNT < 0x0501 +#define KHM_SAVE_WIN32_WINNT _WIN32_WINNT +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#ifdef KHM_SAVE_WIN32_WINNT +#undef _WIN32_WINNT +#define _WIN32_WINNT KHM_SAVE_WIN32_WINNT +#undef KHM_SAVE_WIN32_WINNT +#endif + +#include + +#define LEASH_DEBUG_CLASS_GENERIC 0 +#define LEASH_DEBUG_CLASS_KRB4 1 +#define LEASH_DEBUG_CLASS_KRB4_APP 2 + +#define LEASH_PRIORITY_LOW 0 +#define LEASH_PRIORITY_HIGH 1 + +#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ + +#define KRB5_MAXCCH_CCNAME 1024 + +#define KRB5_CONF_YES "yes" +#define KRB5_CONF_NO "no" + +typedef struct tag_k5params { + + khm_int32 source_reg; /* flags indicating which fields were + retrieved using the registry */ + khm_int32 source_prof; /* flags indicating which fields were + retrieved using krb5.ini */ + + khm_boolean renewable; + khm_boolean forwardable; + khm_boolean proxiable; + khm_boolean addressless; + + khm_ui_4 publicIP; + + krb5_deltat lifetime; + krb5_deltat lifetime_min; + krb5_deltat lifetime_max; + + krb5_deltat renew_life; + krb5_deltat renew_life_min; + krb5_deltat renew_life_max; + +} k5_params; + +#define K5PARAM_F_RENEW 0x00000001 +#define K5PARAM_F_FORW 0x00000002 +#define K5PARAM_F_PROX 0x00000004 +#define K5PARAM_F_ADDL 0x00000008 +#define K5PARAM_F_PUBIP 0x00000010 +#define K5PARAM_F_LIFE 0x00000020 +#define K5PARAM_F_RLIFE 0x00000040 +#define K5PARAM_F_LIFE_L 0x00000080 +#define K5PARAM_F_LIFE_H 0x00000100 +#define K5PARAM_F_RLIFE_L 0x00000200 +#define K5PARAM_F_RLIFE_H 0x00000400 + +#define K5PARAM_FM_ALL 0x000007ff +#define K5PARAM_FM_PROF 0x0000007f + +/* Credential and principal operations */ + +BOOL +khm_krb5_ms2mit(char * match_princ, + BOOL match_realm, + BOOL save_creds, + khm_handle * ret_ident); + +int +khm_krb5_kinit(krb5_context alt_ctx, + char * principal_name, + char * password, + char * ccache, + krb5_deltat lifetime, + DWORD forwardable, + DWORD proxiable, + krb5_deltat renew_life, + DWORD addressless, + DWORD publicIP, + krb5_prompter_fct prompter, + void * p_data); + +long +khm_krb5_changepwd(char * principal, + char * password, + char * newpassword, + char** error_str); + +int +khm_krb5_destroy_by_credset(khm_handle p_cs); + +int +khm_krb5_destroy_identity(khm_handle identity); + +long +khm_convert524(krb5_context ctx); + +int +khm_krb5_renew_cred(khm_handle cred); + +int +khm_krb5_renew_ident(khm_handle identity); + +long +khm_krb5_list_tickets(krb5_context *krbv5Context); + +long +khm_krb5_copy_ccache_by_name(krb5_context in_ctx, + wchar_t * wscc_dest, + wchar_t * wscc_src); + +long +khm_krb5_get_temp_ccache(krb5_context ctx, + krb5_ccache * cc); + +khm_int32 KHMAPI +khm_krb5_creds_is_equal(khm_handle vcred1, khm_handle vcred2, void * dummy); + + +/* Configuration */ + +BOOL +khm_krb5_get_profile_file(LPSTR confname, UINT szConfname); + +BOOL +khm_krb5_get_temp_profile_file(LPSTR confname, UINT szConfname); + +wchar_t * +khm_krb5_get_default_realm(void); + +long +khm_krb5_set_default_realm(wchar_t * realm); + +wchar_t * +khm_krb5_get_realm_list(void); + +khm_int32 +khm_krb5_get_identity_config(khm_handle ident, + khm_int32 flags, + khm_handle * ret_csp); + +void +khm_krb5_set_identity_flags(khm_handle identity, + khm_int32 flag_mask, + khm_int32 flag_value); + +khm_int32 +khm_krb5_get_identity_flags(khm_handle identity); + +khm_int32 +khm_krb5_set_identity_params(khm_handle ident, const k5_params * p); + +khm_int32 +khm_krb5_get_identity_params(khm_handle ident, k5_params * p); + +/* Utility */ + +wchar_t * +khm_get_realm_from_princ(wchar_t * princ); + +long +khm_krb5_canon_cc_name(wchar_t * wcc_name, + size_t cb_cc_name); + +int +khm_krb5_cc_name_cmp(const wchar_t * cc_name_1, + const wchar_t * cc_name_2); + +int +khm_krb5_parse_boolean(const char *s, khm_boolean * b); + +#endif diff --git a/src/windows/identity/plugins/krb5/krb5identpro.c b/src/windows/identity/plugins/krb5/krb5identpro.c index 0072b967d..4d1120f39 100644 --- a/src/windows/identity/plugins/krb5/krb5identpro.c +++ b/src/windows/identity/plugins/krb5/krb5identpro.c @@ -1,1881 +1,1881 @@ -/* - * 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 -#include -#include - -#define K5_NCID_UN_LABEL (KHUI_CW_ID_MIN + 0) -#define K5_NCID_UN (KHUI_CW_ID_MIN + 1) -#define K5_NCID_REALM_LABEL (KHUI_CW_ID_MIN + 2) -#define K5_NCID_REALM (KHUI_CW_ID_MIN + 3) - -#define NC_UNCHANGE_TIMEOUT 3000 -#define NC_UNCHANGE_TIMER 2 -#define NC_REALMCHANGE_TIMEOUT NC_UNCHANGE_TIMEOUT -#define NC_REALMCHANGE_TIMER 3 - -typedef struct tag_k5_new_cred_data { - HWND hw_username_label; - HWND hw_username; - HWND hw_realm_label; - HWND hw_realm; -} k5_new_cred_data; - -static -void -trim_str(wchar_t * s, khm_size cch) { - wchar_t * c, * last_ws; - - for (c = s; *c && iswspace(*c) && ((khm_size)(c - s)) < cch; c++); - - if (((khm_size)(c - s)) >= cch) - return; - - if (c != s && ((khm_size)(c - s)) < cch) { -#if _MSC_VER >= 1400 - wmemmove_s(s, cch, c, cch - ((khm_size)(c - s))); -#else - memmove(s, c, (cch - ((khm_size)(c - s))) * sizeof(wchar_t)); -#endif - } - - last_ws = NULL; - for (c = s; *c && ((khm_size)(c - s)) < cch; c++) { - if (!iswspace(*c)) - last_ws = NULL; - else if (last_ws == NULL) - last_ws = c; - } - - if (last_ws) - *last_ws = L'\0'; -} - -/* Runs in the UI thread */ -int -k5_get_realm_from_nc(khui_new_creds * nc, - wchar_t * buf, - khm_size cch_buf) { - k5_new_cred_data * d; - khm_size s; - - d = (k5_new_cred_data *) nc->ident_aux; - buf[0] = L'\0'; - GetWindowText(d->hw_realm, buf, (int) cch_buf); - trim_str(buf, cch_buf); - - StringCchLength(buf, cch_buf, &s); - - return (int) s; -} - -/* set the primary identity of a new credentials dialog depending on - the selection of the username and realm - - Runs in the UI thread -*/ -static void -set_identity_from_ui(khui_new_creds * nc, - k5_new_cred_data * d) { - wchar_t un[KCDB_IDENT_MAXCCH_NAME]; - wchar_t * realm; - khm_size cch; - khm_size cch_left; - khm_handle ident; - LRESULT idx = CB_ERR; - khm_int32 rv = KHM_ERROR_SUCCESS; - - cch = GetWindowTextLength(d->hw_username); - - /* we already set the max length of the edit control to be this. - shouldn't exceed it unless the edit control is confused. */ - assert(cch < KCDB_IDENT_MAXCCH_NAME - 1); - - GetWindowText(d->hw_username, un, ARRAYLENGTH(un)); - trim_str(un, ARRAYLENGTH(un)); - - realm = khm_get_realm_from_princ(un); - if (realm) /* realm was specified */ - goto _set_ident; - - /* the cch we got from GetWindowTextLength can not be trusted to - be exact. For caveats see MSDN for GetWindowTextLength. */ - StringCchLength(un, KCDB_IDENT_MAXCCH_NAME, &cch); - - 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) { - rv = KHM_ERROR_INVALID_NAME; - goto _set_null_ident; - } - - GetWindowText(d->hw_realm, realm, (int) cch_left); - trim_str(realm, cch_left); - - _set_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); - - kcdb_identity_release(ident); - return; - - _set_null_ident: - { - 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; -} - -/* runs in the UI thread */ -static BOOL -update_crossfeed(khui_new_creds * nc, - k5_new_cred_data * d, - int ctrl_id_src) { - wchar_t un[KCDB_IDENT_MAXCCH_NAME]; - wchar_t * un_realm; - wchar_t realm[KCDB_IDENT_MAXCCH_NAME]; - khm_size cch; - khm_size cch_left; - int idx; - - cch = (khm_size) GetWindowTextLength(d->hw_username); -#ifdef DEBUG - assert(cch < KCDB_IDENT_MAXCCH_NAME); -#endif - if (cch == 0) - return FALSE; - - GetWindowText(d->hw_username, - un, - ARRAYLENGTH(un)); - trim_str(un, ARRAYLENGTH(un)); - - un_realm = khm_get_realm_from_princ(un); - - if (un_realm == NULL) { - EnableWindow(d->hw_realm, TRUE); - return FALSE; - } - - if (ctrl_id_src == K5_NCID_UN) { - - idx = (int)SendMessage(d->hw_realm, - CB_FINDSTRINGEXACT, - (WPARAM) -1, - (LPARAM) un_realm); - - if (idx != CB_ERR) { - wchar_t srealm[KCDB_IDENT_MAXCCH_NAME]; - - cch = SendMessage(d->hw_realm, - CB_GETLBTEXTLEN, - (WPARAM) idx, - 0); - -#ifdef DEBUG - assert(cch < ARRAYLENGTH(srealm) - 1); -#endif - SendMessage(d->hw_realm, - CB_GETLBTEXT, - (WPARAM) idx, - (LPARAM) srealm); - - if (!_wcsicmp(srealm, un_realm) && wcscmp(srealm, un_realm)) { - /* differ only by case */ - - StringCchCopy(un_realm, ARRAYLENGTH(un) - (un_realm - un), - srealm); - - SetWindowText(d->hw_username, un); - } - } - - SendMessage(d->hw_realm, - CB_SELECTSTRING, - (WPARAM) -1, - (LPARAM) un_realm); - - SetWindowText(d->hw_realm, - un_realm); - - if (GetFocus() == d->hw_realm) { - HWND hw_next = GetNextDlgTabItem(nc->hwnd, d->hw_realm, - FALSE); - if (hw_next) - SetFocus(hw_next); - } - - EnableWindow(d->hw_realm, FALSE); - - return TRUE; - } - /* else... */ - - cch_left = KCDB_IDENT_MAXCCH_NAME - (un_realm - un); - - cch = (khm_size) GetWindowTextLength(d->hw_realm); - -#ifdef DEBUG - assert(cch < KCDB_IDENT_MAXCCH_NAME); -#endif - if (cch == 0) - return FALSE; - - GetWindowText(d->hw_realm, realm, - ARRAYLENGTH(realm)); - trim_str(realm, ARRAYLENGTH(realm)); - - idx = (int)SendMessage(d->hw_realm, - CB_FINDSTRINGEXACT, - (WPARAM) -1, - (LPARAM) realm); - - if (idx != CB_ERR) { - wchar_t srealm[KCDB_IDENT_MAXCCH_NAME]; - - SendMessage(d->hw_realm, - CB_GETLBTEXT, - (WPARAM) idx, - (LPARAM) srealm); - - if (!_wcsicmp(srealm, realm) && wcscmp(srealm, realm)) { - StringCbCopy(realm, sizeof(realm), srealm); - - SetWindowText(d->hw_realm, srealm); - } - } - - StringCchCopy(un_realm, cch_left, realm); - - SendMessage(d->hw_username, - CB_SELECTSTRING, - (WPARAM) -1, - (LPARAM) un); - - SetWindowText(d->hw_username, un); - - return TRUE; -} - -/* Handle window messages for the identity specifiers - - runs in UI thread */ -static LRESULT -handle_wnd_msg(khui_new_creds * nc, - HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - k5_new_cred_data * d; - - d = (k5_new_cred_data *) nc->ident_aux; - - switch(uMsg) { - case WM_COMMAND: - switch(wParam) { - case MAKEWPARAM(K5_NCID_UN, CBN_EDITCHANGE): - /* the username has changed. Instead of handling this - for every keystroke, set a timer that elapses some - time afterwards and then handle the event. */ - SetTimer(hwnd, NC_UNCHANGE_TIMER, - NC_UNCHANGE_TIMEOUT, NULL); - return TRUE; - - case MAKEWPARAM(K5_NCID_UN, CBN_KILLFOCUS): - case MAKEWPARAM(K5_NCID_UN, CBN_CLOSEUP): - KillTimer(hwnd, NC_UNCHANGE_TIMER); - - update_crossfeed(nc,d,K5_NCID_UN); - set_identity_from_ui(nc,d); - return TRUE; - - case MAKEWPARAM(K5_NCID_REALM,CBN_EDITCHANGE): - SetTimer(hwnd, NC_REALMCHANGE_TIMER, - NC_REALMCHANGE_TIMEOUT, NULL); - return TRUE; - - case MAKEWPARAM(K5_NCID_REALM,CBN_KILLFOCUS): - case MAKEWPARAM(K5_NCID_REALM,CBN_CLOSEUP): - KillTimer(hwnd, NC_REALMCHANGE_TIMER); - - update_crossfeed(nc,d,K5_NCID_REALM); - set_identity_from_ui(nc, d); - return TRUE; - } - break; - - case WM_TIMER: - if(wParam == NC_UNCHANGE_TIMER) { - KillTimer(hwnd, NC_UNCHANGE_TIMER); - - update_crossfeed(nc, d, K5_NCID_UN); - set_identity_from_ui(nc,d); - return TRUE; - } else if (wParam == NC_REALMCHANGE_TIMER) { - KillTimer(hwnd, NC_REALMCHANGE_TIMER); - - update_crossfeed(nc, d, K5_NCID_REALM); - set_identity_from_ui(nc, d); - return TRUE; - } - break; - } - return FALSE; -} - -/* UI Callback - - runs in UI thread */ -static LRESULT KHMAPI -ui_cb(khui_new_creds * nc, - UINT cmd, - HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - - k5_new_cred_data * d; - - d = (k5_new_cred_data *) nc->ident_aux; - - switch(cmd) { - case WMNC_IDENT_INIT: - { - wchar_t defident[KCDB_IDENT_MAXCCH_NAME]; - wchar_t wbuf[1024]; - wchar_t * ms = NULL; - wchar_t * t; - wchar_t * defrealm = NULL; - LRESULT lr; - khm_size cb_ms; - khm_size cb; - HWND hw_parent; - khm_int32 rv; - khm_handle hident; - - hw_parent = (HWND) lParam; - defident[0] = L'\0'; - -#ifdef DEBUG - assert(d == NULL); - assert(hw_parent != NULL); -#endif - - d = PMALLOC(sizeof(*d)); - assert(d); - ZeroMemory(d, sizeof(*d)); - - khui_cw_lock_nc(nc); - nc->ident_aux = (LPARAM) d; - khui_cw_unlock_nc(nc); - - LoadString(hResModule, IDS_NC_USERNAME, - wbuf, ARRAYLENGTH(wbuf)); - - d->hw_username_label = CreateWindow - (L"STATIC", - wbuf, - SS_SIMPLE | WS_CHILD | WS_VISIBLE, - 0, 0, 100, 100, /* bogus values */ - hw_parent, - (HMENU) K5_NCID_UN_LABEL, - hInstance, - NULL); - assert(d->hw_username_label != NULL); - - d->hw_username = CreateWindow - (L"COMBOBOX", - L"", - CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | - WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL, - 0, 0, 100, 100, /* bogus values */ - hw_parent, - (HMENU) K5_NCID_UN, - hInstance, - NULL); - assert(d->hw_username != NULL); - - SendMessage(d->hw_username, - CB_LIMITTEXT, - (WPARAM)(KCDB_IDENT_MAXCCH_NAME - 1), - 0); - - SendMessage(d->hw_username, - CB_SETEXTENDEDUI, - (WPARAM) TRUE, - 0); - - khui_cw_add_control_row(nc, - d->hw_username_label, - d->hw_username, - KHUI_CTRLSIZE_SMALL); - - LoadString(hResModule, IDS_NC_REALM, - wbuf, ARRAYLENGTH(wbuf)); - - d->hw_realm_label = CreateWindow - (L"STATIC", - wbuf, - SS_SIMPLE | WS_CHILD | WS_VISIBLE, - 0, 0, 100, 100, /* bogus */ - hw_parent, - (HMENU) K5_NCID_REALM_LABEL, - hInstance, - NULL); - assert(d->hw_realm_label != NULL); - - d->hw_realm = CreateWindow - (L"COMBOBOX", - L"", - CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | - WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL, - 0, 0, 100, 100, /* bogus */ - hw_parent, - (HMENU) K5_NCID_REALM, - hInstance, - NULL); - assert(d->hw_realm != NULL); - - SendMessage(d->hw_realm, - CB_LIMITTEXT, - (WPARAM) (KCDB_IDENT_MAXCCH_NAME - 1), - 0); - - SendMessage(d->hw_realm, - CB_SETEXTENDEDUI, - (WPARAM) TRUE, - 0); - - khui_cw_add_control_row(nc, - d->hw_realm_label, - d->hw_realm, - KHUI_CTRLSIZE_SMALL); - - /* add the LRU realms and principals to the dropdown - lists */ - rv = khc_read_multi_string(csp_params, - L"LRUPrincipals", - NULL, - &cb_ms); - - if (rv != KHM_ERROR_TOO_LONG || cb_ms <= sizeof(wchar_t) * 2) - goto _add_lru_realms; - - ms = PMALLOC(cb_ms); - assert(ms != NULL); - - cb = cb_ms; - rv = khc_read_multi_string(csp_params, - L"LRUPrincipals", - ms, - &cb); - - assert(KHM_SUCCEEDED(rv)); - - /* the first of these is considered the default identity - if no other default is known */ - StringCbCopy(defident, sizeof(defident), ms); - - t = ms; - while(t && *t) { - SendMessage(d->hw_username, - CB_ADDSTRING, - 0, - (LPARAM) t); - - t = multi_string_next(t); - } - - _add_lru_realms: - /* add the default realm first */ - defrealm = khm_krb5_get_default_realm(); - if (defrealm) { - SendMessage(d->hw_realm, - CB_ADDSTRING, - 0, - (LPARAM) defrealm); - } - - rv = khc_read_multi_string(csp_params, - L"LRURealms", - NULL, - &cb); - - if (rv != KHM_ERROR_TOO_LONG) - goto _done_adding_lru; - - if (ms != NULL) { - if (cb_ms < cb) { - PFREE(ms); - ms = PMALLOC(cb); - assert(ms); - cb_ms = cb; - } - } else { - ms = PMALLOC(cb); - cb_ms = cb; - } - - rv = khc_read_multi_string(csp_params, - L"LRURealms", - ms, - &cb); - - assert(KHM_SUCCEEDED(rv)); - - for (t = ms; t && *t; t = multi_string_next(t)) { - lr = SendMessage(d->hw_realm, - CB_FINDSTRINGEXACT, - (WPARAM) -1, - (LPARAM) t); - if (lr != CB_ERR) - continue; - - SendMessage(d->hw_realm, - CB_ADDSTRING, - 0, - (LPARAM) t); - } - _done_adding_lru: - - { - khm_int32 inc_realms = 0; - - if (KHM_FAILED(khc_read_int32(csp_params, - L"UseFullRealmList", - &inc_realms)) || - !inc_realms) - goto _done_adding_all_realms; - } - - if(ms) - PFREE(ms); - - ms = khm_krb5_get_realm_list(); - if(ms) { - for (t = ms; t && *t; t = multi_string_next(t)) { - lr = SendMessage(d->hw_realm, - CB_FINDSTRINGEXACT, - (WPARAM) -1, - (LPARAM) t); - if (lr != CB_ERR) - continue; - - SendMessage(d->hw_realm, - CB_ADDSTRING, - 0, - (LPARAM) t); - } - } - _done_adding_all_realms: - - /* set the current selection of the realms list */ - if (defrealm) { - SendMessage(d->hw_realm, - CB_SELECTSTRING, - (WPARAM) -1, - (LPARAM) defrealm); - } else { - SendMessage(d->hw_realm, - CB_SETCURSEL, - (WPARAM) 0, - (LPARAM) 0); - } - - if (defrealm) - PFREE(defrealm); - - if (ms) - PFREE(ms); - - /* now see about that default identity */ - if (nc->ctx.identity) { - cb = sizeof(defident); - kcdb_identity_get_name(nc->ctx.identity, - defident, - &cb); - } - - if (defident[0] == L'\0' && - KHM_SUCCEEDED(kcdb_identity_get_default(&hident))) { - cb = sizeof(defident); - kcdb_identity_get_name(hident, defident, &cb); - kcdb_identity_release(hident); - } - - if (defident[0] == L'\0') { - DWORD dw; - - dw = ARRAYLENGTH(defident); - GetUserName(defident, &dw); - } - - t = khm_get_realm_from_princ(defident); - if (t) { - /* there is a realm */ - assert(t != defident); - *--t = L'\0'; - t++; - - SendMessage(d->hw_realm, - CB_SELECTSTRING, - (WPARAM) -1, - (LPARAM) t); - - SendMessage(d->hw_realm, - WM_SETTEXT, - 0, - (LPARAM) t); - } - - if (defident[0] != L'\0') { - /* there is a username */ - SendMessage(d->hw_username, - CB_SELECTSTRING, - (WPARAM) -1, - (LPARAM) defident); - - SendMessage(d->hw_username, - WM_SETTEXT, - 0, - (LPARAM) defident); - } - - set_identity_from_ui(nc, d); - } - return TRUE; - - case WMNC_IDENT_WMSG: - return handle_wnd_msg(nc, hwnd, uMsg, wParam, lParam); - - case WMNC_IDENT_EXIT: - { -#ifdef DEBUG - assert(d != NULL); -#endif - khui_cw_lock_nc(nc); - nc->ident_aux = 0; - khui_cw_unlock_nc(nc); - - /* since we created all the windows as child windows of - the new creds window, they will be destroyed when that - window is destroyed. */ - PFREE(d); - } - return TRUE; - } - return FALSE; -} - -static khm_int32 -k5_ident_validate_name(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam) { - krb5_principal princ = NULL; - char princ_name[KCDB_IDENT_MAXCCH_NAME]; - kcdb_ident_name_xfer * nx; - krb5_error_code code; - wchar_t * atsign; - - nx = (kcdb_ident_name_xfer *) vparam; - - if(UnicodeStrToAnsi(princ_name, sizeof(princ_name), - nx->name_src) == 0) { - nx->result = KHM_ERROR_INVALID_NAME; - return KHM_ERROR_SUCCESS; - } - - assert(k5_identpro_ctx != NULL); - - code = pkrb5_parse_name(k5_identpro_ctx, - princ_name, - &princ); - - if (code) { - nx->result = KHM_ERROR_INVALID_NAME; - return KHM_ERROR_SUCCESS; - } - - if (princ != NULL) - pkrb5_free_principal(k5_identpro_ctx, - princ); - - /* krb5_parse_name() accepts principal names with no realm or an - empty realm. We don't. */ - atsign = wcschr(nx->name_src, L'@'); - if (atsign == NULL || atsign[1] == L'\0') { - nx->result = KHM_ERROR_INVALID_NAME; - } else { - nx->result = KHM_ERROR_SUCCESS; - } - - return KHM_ERROR_SUCCESS; -} - -static void -k5_update_last_default_identity(khm_handle ident) { - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - - cb = sizeof(idname); - if (KHM_FAILED(kcdb_identity_get_name(ident, idname, &cb))) - return; - - assert(csp_params); - - khc_write_string(csp_params, L"LastDefaultIdent", idname); -} - -static khm_int32 -k5_ident_set_default_int(khm_handle def_ident) { - wchar_t id_ccname[KRB5_MAXCCH_CCNAME]; - khm_size cb; - DWORD dw; - LONG l; - HKEY hk_ccname; - DWORD dwType; - DWORD dwSize; - wchar_t reg_ccname[KRB5_MAXCCH_CCNAME]; - -#ifdef DEBUG - assert(def_ident != NULL); -#endif - - cb = sizeof(id_ccname); - if (KHM_FAILED(kcdb_identity_get_attr(def_ident, attr_id_krb5_ccname, NULL, - id_ccname, &cb))) { - khm_handle csp_ident = NULL; - khm_handle csp_k5 = NULL; - - _reportf(L"The specified identity does not have the Krb5CCName property"); - - cb = sizeof(id_ccname); - if (KHM_SUCCEEDED(kcdb_identity_get_config(def_ident, 0, &csp_ident)) && - KHM_SUCCEEDED(khc_open_space(csp_ident, CSNAME_KRB5CRED, 0, &csp_k5)) && - KHM_SUCCEEDED(khc_read_string(csp_k5, L"DefaultCCName", - id_ccname, &cb))) { - - _reportf(L"Found CC name in configuration [%s]", id_ccname); - } else { - /* last resort, use the name of the identity as the cc - name */ - cb = sizeof(id_ccname); - if (KHM_FAILED(kcdb_identity_get_name(def_ident, id_ccname, &cb))) { - _reportf(L"Can't use name of identity as CCName"); - _end_task(); - - id_ccname[0] = L'\0'; - } - } - - if (csp_k5) - khc_close_space(csp_k5); - if (csp_ident) - khc_close_space(csp_ident); - - if (id_ccname[0] == L'\0') - return KHM_ERROR_INVALID_PARAM; - } - - khm_krb5_canon_cc_name(id_ccname, sizeof(id_ccname)); - - _reportf(L"Found Krb5CCName property : %s", id_ccname); - - StringCbLength(id_ccname, sizeof(id_ccname), &cb); - cb += sizeof(wchar_t); - - _reportf(L"Setting default CC name in the registry"); - - l = RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\MIT\\kerberos5", 0, - KEY_READ | KEY_WRITE, &hk_ccname); - - if (l != ERROR_SUCCESS) - l = RegCreateKeyEx(HKEY_CURRENT_USER, L"Software\\MIT\\kerberos5", 0, - NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, - NULL, &hk_ccname, &dw); - - if (l != ERROR_SUCCESS) { - _reportf(L"Can't create registry key : %d", l); - _end_task(); - return KHM_ERROR_UNKNOWN; - } - - dwSize = sizeof(reg_ccname); - - l = RegQueryValueEx(hk_ccname, L"ccname", NULL, &dwType, (LPBYTE) reg_ccname, - &dwSize); - - if (l != ERROR_SUCCESS || - dwType != REG_SZ || - khm_krb5_cc_name_cmp(reg_ccname, id_ccname)) { - - /* we have to write the new value in */ - - l = RegSetValueEx(hk_ccname, L"ccname", 0, REG_SZ, (BYTE *) id_ccname, - (DWORD) cb); - } - - RegCloseKey(hk_ccname); - - if (l == ERROR_SUCCESS) { - _reportf(L"Successfully set the default ccache"); - k5_update_last_default_identity(def_ident); - return KHM_ERROR_SUCCESS; - } else { - _reportf(L"Can't set the registry value : %d", l); - return KHM_ERROR_UNKNOWN; - } -} - -static khm_int32 -k5_ident_set_default(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam) { - - /* - Currently, setting the default identity simply sets the - "ccname" registry value at "Software\MIT\kerberos5". - */ - - if (uparam) { - /* an identity is being made default */ - khm_handle def_ident = (khm_handle) vparam; - khm_int32 rv; - -#ifdef DEBUG - assert(def_ident != NULL); -#endif - - { - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - - cb = sizeof(idname); - kcdb_identity_get_name(def_ident, idname, &cb); - - _begin_task(0); - _report_cs1(KHERR_DEBUG_1, L"Setting default identity [%1!s!]", _cstr(idname)); - _describe(); - } - - rv = k5_ident_set_default_int(def_ident); - - _end_task(); - - return rv; - - } else { - /* the default identity is being forgotten */ - - /* we don't really do anything about this case */ - } - - return KHM_ERROR_SUCCESS; -} - -static khm_int32 -k5_ident_get_ui_cb(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam) { - khui_ident_new_creds_cb * cb; - - cb = (khui_ident_new_creds_cb *) vparam; - - *cb = ui_cb; - - return KHM_ERROR_SUCCESS; -} - -static khm_int32 -k5_ident_notify_create(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam) { - - /* a new identity has been created. What we want to do at - this point is to check if the identity belongs to krb5 - and to see if it is the default. */ - - krb5_ccache cc = NULL; - krb5_error_code code; - krb5_principal princ = NULL; - char * princ_nameA = NULL; - wchar_t princ_nameW[KCDB_IDENT_MAXCCH_NAME]; - wchar_t id_nameW[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - khm_handle ident; - - /* if there is a default identity already, we assume we don't need - to check this one. */ - - khm_handle def_ident; - - if (KHM_SUCCEEDED(kcdb_identity_get_default(&def_ident))) { - kcdb_identity_release(def_ident); - - return KHM_ERROR_SUCCESS; - } - - ident = (khm_handle) vparam; - - assert(k5_identpro_ctx != NULL); - - code = pkrb5_cc_default(k5_identpro_ctx, &cc); - if (code) - goto _nc_cleanup; - - code = pkrb5_cc_get_principal(k5_identpro_ctx, - cc, - &princ); - if (code) - goto _nc_cleanup; - - code = pkrb5_unparse_name(k5_identpro_ctx, - princ, - &princ_nameA); - if (code) - goto _nc_cleanup; - - AnsiStrToUnicode(princ_nameW, - sizeof(princ_nameW), - princ_nameA); - - cb = sizeof(id_nameW); - - if (KHM_FAILED(kcdb_identity_get_name(ident, - id_nameW, - &cb))) - goto _nc_cleanup; - - if (!wcscmp(id_nameW, princ_nameW)) { - kcdb_identity_set_default_int(ident); - } - - _nc_cleanup: - if (princ_nameA) - pkrb5_free_unparsed_name(k5_identpro_ctx, - princ_nameA); - if (princ) - pkrb5_free_principal(k5_identpro_ctx, - princ); - if (cc) - pkrb5_cc_close(k5_identpro_ctx, cc); - - return KHM_ERROR_SUCCESS; -} - -struct k5_ident_update_data { - khm_handle identity; - - FILETIME ft_expire; /* expiration */ - FILETIME ft_issue; /* issue */ - FILETIME ft_rexpire; /* renew expiration */ - wchar_t ccname[KRB5_MAXCCH_CCNAME]; - khm_int32 k5_flags; -}; - -/* The logic here has to reflect the logic in khm_krb5_list_tickets(). - We use this to handle an identity update request because some other - plug-in or maybe NetIDMgr itself is about to do something - important(tm) with the identity and needs to make sure that the - properties of the identity are up-to-date. */ -static khm_int32 KHMAPI -k5_ident_update_apply_proc(khm_handle cred, - void * rock) { - struct k5_ident_update_data * d = (struct k5_ident_update_data *) rock; - khm_handle ident = NULL; - khm_int32 t; - khm_int32 flags; - FILETIME t_cexpire; - FILETIME t_rexpire; - khm_size cb; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if (KHM_FAILED(kcdb_cred_get_type(cred, &t)) || - t != credtype_id_krb5 || - KHM_FAILED(kcdb_cred_get_identity(cred, &ident))) - - return KHM_ERROR_SUCCESS; - - if (!kcdb_identity_is_equal(ident,d->identity)) - - goto _cleanup; - - if (KHM_FAILED(kcdb_cred_get_flags(cred, &flags))) - - flags = 0; - - if (flags & KCDB_CRED_FLAG_INITIAL) { - cb = sizeof(t_cexpire); - if (KHM_SUCCEEDED(kcdb_cred_get_attr(cred, - KCDB_ATTR_EXPIRE, - NULL, - &t_cexpire, - &cb))) { - if ((d->ft_expire.dwLowDateTime == 0 && - d->ft_expire.dwHighDateTime == 0) || - CompareFileTime(&t_cexpire, &d->ft_expire) > 0) { - goto update_identity; - } - } - } - - goto _cleanup; - - update_identity: - - d->ft_expire = t_cexpire; - - cb = sizeof(d->ccname); - if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_LOCATION, NULL, d->ccname, &cb))) { - d->ccname[0] = L'\0'; - } - - cb = sizeof(d->k5_flags); - if (KHM_FAILED(kcdb_cred_get_attr(cred, attr_id_krb5_flags, NULL, - &d->k5_flags, &cb))) { - d->k5_flags = 0; - } - - cb = sizeof(d->ft_issue); - if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_ISSUE, NULL, &d->ft_issue, &cb))) { - ZeroMemory(&d->ft_issue, sizeof(d->ft_issue)); - } - - cb = sizeof(t_rexpire); - if ((d->k5_flags & TKT_FLG_RENEWABLE) && - KHM_SUCCEEDED(kcdb_cred_get_attr(cred, - KCDB_ATTR_RENEW_EXPIRE, - NULL, - &t_rexpire, - &cb))) { - d->ft_rexpire = t_rexpire; - } else { - ZeroMemory(&d->ft_rexpire, sizeof(d->ft_rexpire)); - } - - _cleanup: - if (ident) - kcdb_identity_release(ident); - - return rv; -} - -static khm_int32 -k5_ident_update(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam) { - -#if 0 - struct k5_ident_update_data d; -#endif - khm_handle ident; - khm_handle tident; - krb5_ccache cc = NULL; - char * ccname; - krb5_error_code code; - khm_size cb; - wchar_t wid_ccname[MAX_PATH]; - wchar_t w_ccname[MAX_PATH]; - - ident = (khm_handle) vparam; - if (ident == NULL) - return KHM_ERROR_SUCCESS; - -#if 0 - /* we are going to skip doing this here since - khm_krb5_list_tickets() performs this function for us each time - we enumerate tickets. Since it also gets run each time our - list of tickets changes and since we are basing this operation - on existing tickets, we are unlikely to find anything new - here. */ - ZeroMemory(&d, sizeof(d)); - d.identity = ident; - - kcdb_credset_apply(NULL, - k5_ident_update_apply_proc, - (void *) &d); - - if (d.ft_expire.dwLowDateTime != 0 || - d.ft_expire.dwHighDateTime != 0) { - - /* we found a TGT */ - - kcdb_identity_set_attr(ident, KCDB_ATTR_EXPIRE, - &d.ft_expire, sizeof(d.ft_expire)); - if (d.ft_issue.dwLowDateTime != 0 || - d.ft_issue.dwHighDateTime != 0) - kcdb_identity_set_attr(ident, KCDB_ATTR_ISSUE, - &d.ft_issue, sizeof(d.ft_issue)); - else - kcdb_identity_set_attr(ident, KCDB_ATTR_ISSUE, NULL, 0); - - if (d.ft_rexpire.dwLowDateTime != 0 || - d.ft_rexpire.dwHighDateTime != 0) - kcdb_identity_set_attr(ident, KCDB_ATTR_RENEW_EXPIRE, - &d.ft_rexpire, sizeof(d.ft_rexpire)); - else - kcdb_identity_set_attr(ident, KCDB_ATTR_RENEW_EXPIRE, NULL, 0); - - kcdb_identity_set_attr(ident, attr_id_krb5_flags, - &d.k5_flags, sizeof(d.k5_flags)); - - if (d.ccname[0]) - kcdb_identity_set_attr(ident, attr_id_krb5_ccname, - d.ccname, KCDB_CBSIZE_AUTO); - else - kcdb_identity_set_attr(ident, attr_id_krb5_ccname, NULL, 0); - - } else { - /* Clear out the attributes. We don't have any information - about this identity */ - kcdb_identity_set_attr(ident, KCDB_ATTR_EXPIRE, NULL, 0); - kcdb_identity_set_attr(ident, KCDB_ATTR_ISSUE, NULL, 0); - kcdb_identity_set_attr(ident, KCDB_ATTR_RENEW_EXPIRE, NULL, 0); - kcdb_identity_set_attr(ident, attr_id_krb5_flags, NULL, 0); - kcdb_identity_set_attr(ident, attr_id_krb5_ccname, NULL, 0); - } -#endif - - if (KHM_SUCCEEDED(kcdb_identity_get_default(&tident))) { - kcdb_identity_release(tident); - goto _iu_cleanup; - } - - cb = sizeof(wid_ccname); - if (KHM_FAILED(kcdb_identity_get_attr(ident, - attr_id_krb5_ccname, - NULL, - wid_ccname, - &cb))) - goto _iu_cleanup; - - if(k5_identpro_ctx == NULL) - goto _iu_cleanup; - - code = pkrb5_cc_default(k5_identpro_ctx, &cc); - if (code) - goto _iu_cleanup; - - ccname = pkrb5_cc_get_name(k5_identpro_ctx, cc); - if (ccname == NULL) - goto _iu_cleanup; - - AnsiStrToUnicode(w_ccname, sizeof(w_ccname), ccname); - - khm_krb5_canon_cc_name(w_ccname, sizeof(w_ccname)); - khm_krb5_canon_cc_name(wid_ccname, sizeof(wid_ccname)); - - if (!_wcsicmp(w_ccname, wid_ccname)) - kcdb_identity_set_default_int(ident); - - _iu_cleanup: - if (cc && k5_identpro_ctx) - pkrb5_cc_close(k5_identpro_ctx, cc); - - return KHM_ERROR_SUCCESS; -} - -static khm_boolean -k5_refresh_default_identity(krb5_context ctx) { - /* just like notify_create, except now we set the default identity - based on what we find in the configuration */ - krb5_ccache cc = NULL; - krb5_error_code code; - krb5_principal princ = NULL; - char * princ_nameA = NULL; - wchar_t princ_nameW[KCDB_IDENT_MAXCCH_NAME]; - char * ccname = NULL; - khm_handle ident = NULL; - khm_boolean found_default = FALSE; - - assert(ctx != NULL); - - _begin_task(0); - _report_cs0(KHERR_DEBUG_1, L"Refreshing default identity"); - _describe(); - - code = pkrb5_cc_default(ctx, &cc); - if (code) { - _reportf(L"Can't open default ccache. code=%d", code); - goto _nc_cleanup; - } - - code = pkrb5_cc_get_principal(ctx, cc, &princ); - if (code) { - /* try to determine the identity from the ccache name */ - ccname = pkrb5_cc_get_name(ctx, cc); - - if (ccname) { - char * namepart = strchr(ccname, ':'); - - _reportf(L"CC name is [%S]", ccname); - - if (namepart == NULL) - namepart = ccname; - else - namepart++; - - _reportf(L"Checking if [%S] is a valid identity name", namepart); - - AnsiStrToUnicode(princ_nameW, sizeof(princ_nameW), namepart); - if (kcdb_identity_is_valid_name(princ_nameW)) { - kcdb_identity_create(princ_nameW, KCDB_IDENT_FLAG_CREATE, &ident); - if (ident) { - _reportf(L"Setting [%S] as the default identity", namepart); - kcdb_identity_set_default_int(ident); - found_default = TRUE; - } - } - } else { - _reportf(L"Can't determine ccache name"); - } - - goto _nc_cleanup; - } - - code = pkrb5_unparse_name(ctx, princ, &princ_nameA); - if (code) - goto _nc_cleanup; - - AnsiStrToUnicode(princ_nameW, sizeof(princ_nameW), princ_nameA); - - _reportf(L"Found principal [%s]", princ_nameW); - - if (KHM_FAILED(kcdb_identity_create(princ_nameW, KCDB_IDENT_FLAG_CREATE, &ident))) { - _reportf(L"Failed to create identity"); - goto _nc_cleanup; - } - - _reportf(L"Setting default identity to [%s]", princ_nameW); - kcdb_identity_set_default_int(ident); - - found_default = TRUE; - - _nc_cleanup: - - _end_task(); - - if (princ_nameA) - pkrb5_free_unparsed_name(ctx, princ_nameA); - - if (princ) - pkrb5_free_principal(ctx, princ); - - if (cc) - pkrb5_cc_close(ctx, cc); - - if (ident) - kcdb_identity_release(ident); - - return found_default; -} - -static khm_int32 -k5_ident_init(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam) { - - khm_boolean found_default; - khm_handle ident; - - found_default = k5_refresh_default_identity(k5_identpro_ctx); - - if (!found_default) { - wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - - cb = sizeof(widname); - - assert(csp_params); - - if (KHM_SUCCEEDED(khc_read_string(csp_params, L"LastDefaultIdent", - widname, &cb))) { - ident = NULL; - kcdb_identity_create(widname, KCDB_IDENT_FLAG_CREATE, &ident); - if (ident) { - kcdb_identity_set_default_int(ident); - kcdb_identity_release(ident); - - found_default = TRUE; - } - } - } - - if (!found_default) { - - /* There was no default ccache and we don't have a - "LastDefaultIdent" value. Next we see if there are any - identities that have credentials which have a Krb5CCName - property (i.e. an identity that has a Kerberos 5 TGT), and - make it the default. - - Note that since the Krb5Ident plug-in has a dependency on - Krb5Cred, by the time this code runs, we already have a - listing of Kerberos 5 tickets and identities. */ - - wchar_t * idlist = NULL; - wchar_t * thisid; - khm_size cb = 0; - khm_size n_idents = 0; - khm_int32 rv; - wchar_t ccname[KRB5_MAXCCH_CCNAME]; - FILETIME ft_expire; - FILETIME ft_now; - FILETIME ft_threshold; - BOOL match_all = FALSE; - - rv = kcdb_identity_enum(0, 0, NULL, &cb, &n_idents); - - TimetToFileTimeInterval(5 * 60, &ft_threshold); - GetSystemTimeAsFileTime(&ft_now); - ft_now = FtAdd(&ft_now, &ft_threshold); - - while (rv == KHM_ERROR_TOO_LONG && n_idents > 0) { - if (idlist) { - PFREE(idlist); - idlist = NULL; - } - - idlist = PMALLOC(cb); - - if (idlist == NULL) - break; - - rv = kcdb_identity_enum(0, 0, idlist, &cb, &n_idents); - } - - if (KHM_SUCCEEDED(rv)) { - - /* first we try to find an identity that has a valid TGT. - If that fails, then we try to find an identity with - *any* TGT. */ - - try_again: - - for (thisid = idlist; - thisid && *thisid && !found_default; - thisid = multi_string_next(thisid)) { - - if (KHM_SUCCEEDED(kcdb_identity_create(thisid, 0, &ident))) { - khm_size cb_ft = sizeof(FILETIME); - cb = sizeof(ccname); - - if (KHM_SUCCEEDED(kcdb_identity_get_attr(ident, attr_id_krb5_ccname, - NULL, ccname, &cb)) && - (match_all || - (KHM_SUCCEEDED(kcdb_identity_get_attr(ident, KCDB_ATTR_EXPIRE, - NULL, &ft_expire, &cb_ft)) && - CompareFileTime(&ft_expire, &ft_now) > 0))) { - - /* found one */ - k5_ident_set_default_int(ident); - kcdb_identity_set_default_int(ident); - found_default = TRUE; - - } - - kcdb_identity_release(ident); - ident = NULL; - } - } - - if (!found_default && !match_all) { - match_all = TRUE; - goto try_again; - } - } - - if (idlist) { - PFREE(idlist); - idlist = NULL; - } - } - - return KHM_ERROR_SUCCESS; -} - -static khm_int32 -k5_ident_exit(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam) { - /* don't really do anything */ - return KHM_ERROR_SUCCESS; -} - -/* forward dcl */ -khm_int32 KHMAPI -k5_ident_name_comp_func(const void * dl, khm_size cb_dl, - const void * dr, khm_size cb_dr); - -static khm_int32 -k5_ident_compare_name(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam) { - kcdb_ident_name_xfer *px; - - px = (kcdb_ident_name_xfer *) vparam; - - /* note that k5_ident_name_comp_func() ignores the size - specifiers. So we can just pass in 0's. */ - px->result = k5_ident_name_comp_func(px->name_src, 0, - px->name_alt, 0); - - return KHM_ERROR_SUCCESS; -} - -#if 0 -/* copy and paste template for ident provider messages */ -static khm_int32 -k5_ident_(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam) { -} -#endif - -khm_int32 KHMAPI -k5_msg_ident(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam) -{ - switch(msg_subtype) { - case KMSG_IDENT_INIT: - return k5_ident_init(msg_type, - msg_subtype, - uparam, - vparam); - - case KMSG_IDENT_EXIT: - return k5_ident_exit(msg_type, - msg_subtype, - uparam, - vparam); - - case KMSG_IDENT_VALIDATE_NAME: - return k5_ident_validate_name(msg_type, - msg_subtype, - uparam, - vparam); - - case KMSG_IDENT_VALIDATE_IDENTITY: - /* TODO: handle KMSG_IDENT_VALIDATE_IDENTITY */ - break; - - case KMSG_IDENT_CANON_NAME: - /* TODO: handle KMSG_IDENT_CANON_NAME */ - break; - - case KMSG_IDENT_COMPARE_NAME: - return k5_ident_compare_name(msg_type, - msg_subtype, - uparam, - vparam); - - case KMSG_IDENT_SET_DEFAULT: - return k5_ident_set_default(msg_type, - msg_subtype, - uparam, - vparam); - - case KMSG_IDENT_SET_SEARCHABLE: - /* TODO: handle KMSG_IDENT_SET_SEARCHABLE */ - break; - - case KMSG_IDENT_GET_INFO: - /* TODO: handle KMSG_IDENT_GET_INFO */ - break; - - case KMSG_IDENT_UPDATE: - return k5_ident_update(msg_type, - msg_subtype, - uparam, - vparam); - - case KMSG_IDENT_ENUM_KNOWN: - /* TODO: handle KMSG_IDENT_ENUM_KNOWN */ - break; - - case KMSG_IDENT_GET_UI_CALLBACK: - return k5_ident_get_ui_cb(msg_type, - msg_subtype, - uparam, - vparam); - - case KMSG_IDENT_NOTIFY_CREATE: - return k5_ident_notify_create(msg_type, - msg_subtype, - uparam, - vparam); - } - - return KHM_ERROR_SUCCESS; -} - -/* note that we are ignoring the size specifiers. We can do that - because we are guaranteed that dl and dr point to NULL terminated - unicode strings when used with credential data buffers. We also - use the fact that we are ignoring the size specifiers when we call - this function from k5_ident_compare_name() to avoid calculating the - length of the string. */ -khm_int32 KHMAPI -k5_ident_name_comp_func(const void * dl, khm_size cb_dl, - const void * dr, khm_size cb_dr) { - wchar_t * idl = (wchar_t *) dl; - wchar_t * idr = (wchar_t *) dr; - wchar_t * rl; - wchar_t * rr; - khm_int32 r; - - rl = khm_get_realm_from_princ(idl); - rr = khm_get_realm_from_princ(idr); - - if (rl == NULL && rr == NULL) - return wcscmp(idl, idr); - else if (rl == NULL) - return 1; - else if (rr == NULL) - return -1; - - r = wcscmp(rl, rr); - if (r == 0) - return wcscmp(idl, idr); - else - return r; -} - - -/* Identity change notification thread */ - -HANDLE h_ccname_exit_event; -HANDLE h_ccname_thread; - -DWORD WINAPI k5_ccname_monitor_thread(LPVOID lpParameter) { - krb5_context ctx = 0; - - HKEY hk_ccname; - HANDLE h_notify; - HANDLE h_waits[2]; - - khm_int32 rv = KHM_ERROR_SUCCESS; - DWORD dwType; - DWORD dwSize; - DWORD dwDisp; - wchar_t reg_ccname[KRB5_MAXCCH_CCNAME]; - LONG l; - - PDESCTHREAD(L"Krb5 CCName Monitor", L"Krb5"); - - l = RegOpenKeyEx(HKEY_CURRENT_USER, - L"Software\\MIT\\kerberos5", - 0, - KEY_READ | KEY_WRITE, - &hk_ccname); - - if (l != ERROR_SUCCESS) - l = RegCreateKeyEx(HKEY_CURRENT_USER, - L"Software\\MIT\\kerberos5", - 0, - NULL, - REG_OPTION_NON_VOLATILE, - KEY_READ | KEY_WRITE, - NULL, - &hk_ccname, - &dwDisp); - - if (l != ERROR_SUCCESS) { - rv = KHM_ERROR_UNKNOWN; - goto _exit; - } - - dwSize = sizeof(reg_ccname); - - l = RegQueryValueEx(hk_ccname, - L"ccname", - NULL, - &dwType, - (LPBYTE) reg_ccname, - &dwSize); - - if (l != ERROR_SUCCESS || - dwType != REG_SZ) { - - reg_ccname[0] = L'\0'; - } - - l = pkrb5_init_context(&ctx); - - if (l) - goto _exit_0; - - h_notify = CreateEvent(NULL, FALSE, FALSE, L"Local\\Krb5CCNameChangeNotifier"); - - if (h_notify == NULL) - goto _exit_0; - - /* begin wait loop */ - - h_waits[0] = h_ccname_exit_event; - h_waits[1] = h_notify; - - do { - DWORD dwrv; - - l = RegNotifyChangeKeyValue(hk_ccname, FALSE, - REG_NOTIFY_CHANGE_LAST_SET, - h_notify, TRUE); - - if (l != ERROR_SUCCESS) { - rv = KHM_ERROR_UNKNOWN; - break; - } - - dwrv = WaitForMultipleObjects(2, h_waits, FALSE, INFINITE); - - if (dwrv == WAIT_OBJECT_0) { - /* exit! */ - break; - - } else if (dwrv == WAIT_OBJECT_0 + 1) { - /* change notify! */ - wchar_t new_ccname[KRB5_MAXCCH_CCNAME]; - - dwSize = sizeof(new_ccname); - - l = RegQueryValueEx(hk_ccname, - L"ccname", - NULL, - &dwType, - (LPBYTE) new_ccname, - &dwSize); - - if (l != ERROR_SUCCESS || - dwType != REG_SZ) { - new_ccname[0] = L'\0'; - } - - if (_wcsicmp(new_ccname, reg_ccname)) { - k5_refresh_default_identity(ctx); - StringCbCopy(reg_ccname, sizeof(reg_ccname), new_ccname); - } - - } else { - /* something went wrong */ - rv = KHM_ERROR_UNKNOWN; - break; - } - - } while (TRUE); - - CloseHandle(h_notify); - - _exit_0: - - RegCloseKey(hk_ccname); - - if (ctx) - pkrb5_free_context(ctx); - - _exit: - ExitThread(rv); - - /* not reached */ - return rv; -} - -khm_int32 -k5_msg_system_idpro(khm_int32 msg_type, khm_int32 msg_subtype, - khm_ui_4 uparam, void * vparam) { - - switch(msg_subtype) { - case KMSG_SYSTEM_INIT: - { - - pkrb5_init_context(&k5_identpro_ctx); - kcdb_identity_set_type(credtype_id_krb5); - - if (KHM_FAILED(kcdb_type_get_id(TYPENAME_KRB5_PRINC, - &type_id_krb5_princ))) { - kcdb_type dt; - kcdb_type * pstr; - - kcdb_type_get_info(KCDB_TYPE_STRING, &pstr); - - ZeroMemory(&dt, sizeof(dt)); - dt.name = TYPENAME_KRB5_PRINC; - dt.id = KCDB_TYPE_INVALID; - dt.flags = KCDB_TYPE_FLAG_CB_AUTO; - dt.cb_min = pstr->cb_min; - dt.cb_max = pstr->cb_max; - dt.toString = pstr->toString; - dt.isValid = pstr->isValid; - dt.comp = k5_ident_name_comp_func; - dt.dup = pstr->dup; - - kcdb_type_register(&dt, &type_id_krb5_princ); - - type_regd_krb5_princ = TRUE; - - kcdb_type_release_info(pstr); - } - - if (type_id_krb5_princ != -1) { - kcdb_attrib * attr; - - kcdb_attrib_get_info(KCDB_ATTR_ID_NAME, &attr); - - attr->type = type_id_krb5_princ; - - kcdb_attrib_release_info(attr); - } - - h_ccname_exit_event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (h_ccname_exit_event) { - h_ccname_thread = CreateThread(NULL, - 200 * 1024, - k5_ccname_monitor_thread, - NULL, - 0, - NULL); - } else { - h_ccname_thread = NULL; - } - } - break; - - case KMSG_SYSTEM_EXIT: - { - - if (h_ccname_thread) { - SetEvent(h_ccname_exit_event); - WaitForSingleObject(h_ccname_thread, INFINITE); - CloseHandle(h_ccname_thread); - CloseHandle(h_ccname_exit_event); - - h_ccname_exit_event = NULL; - h_ccname_thread = NULL; - } - - if (k5_identpro_ctx) { - pkrb5_free_context(k5_identpro_ctx); - k5_identpro_ctx = NULL; - } - - if (type_id_krb5_princ != -1) { - kcdb_attrib * attr; - - kcdb_attrib_get_info(KCDB_ATTR_ID_NAME, &attr); - - attr->type = KCDB_TYPE_STRING; - - kcdb_attrib_release_info(attr); - } - - /* allow a brief moment for any stale references to die */ - Sleep(100); - - if (type_regd_krb5_princ) { - kcdb_type_unregister(type_id_krb5_princ); - } - } - break; - } - - return KHM_ERROR_SUCCESS; -} - -khm_int32 KHMAPI -k5_ident_callback(khm_int32 msg_type, khm_int32 msg_subtype, - khm_ui_4 uparam, void * vparam) { - switch(msg_type) { - case KMSG_SYSTEM: - return k5_msg_system_idpro(msg_type, msg_subtype, uparam, vparam); - - case KMSG_IDENT: - return k5_msg_ident(msg_type, msg_subtype, uparam, vparam); - } - - return KHM_ERROR_SUCCESS; -} +/* + * 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 +#include +#include + +#define K5_NCID_UN_LABEL (KHUI_CW_ID_MIN + 0) +#define K5_NCID_UN (KHUI_CW_ID_MIN + 1) +#define K5_NCID_REALM_LABEL (KHUI_CW_ID_MIN + 2) +#define K5_NCID_REALM (KHUI_CW_ID_MIN + 3) + +#define NC_UNCHANGE_TIMEOUT 3000 +#define NC_UNCHANGE_TIMER 2 +#define NC_REALMCHANGE_TIMEOUT NC_UNCHANGE_TIMEOUT +#define NC_REALMCHANGE_TIMER 3 + +typedef struct tag_k5_new_cred_data { + HWND hw_username_label; + HWND hw_username; + HWND hw_realm_label; + HWND hw_realm; +} k5_new_cred_data; + +static +void +trim_str(wchar_t * s, khm_size cch) { + wchar_t * c, * last_ws; + + for (c = s; *c && iswspace(*c) && ((khm_size)(c - s)) < cch; c++); + + if (((khm_size)(c - s)) >= cch) + return; + + if (c != s && ((khm_size)(c - s)) < cch) { +#if _MSC_VER >= 1400 + wmemmove_s(s, cch, c, cch - ((khm_size)(c - s))); +#else + memmove(s, c, (cch - ((khm_size)(c - s))) * sizeof(wchar_t)); +#endif + } + + last_ws = NULL; + for (c = s; *c && ((khm_size)(c - s)) < cch; c++) { + if (!iswspace(*c)) + last_ws = NULL; + else if (last_ws == NULL) + last_ws = c; + } + + if (last_ws) + *last_ws = L'\0'; +} + +/* Runs in the UI thread */ +int +k5_get_realm_from_nc(khui_new_creds * nc, + wchar_t * buf, + khm_size cch_buf) { + k5_new_cred_data * d; + khm_size s; + + d = (k5_new_cred_data *) nc->ident_aux; + buf[0] = L'\0'; + GetWindowText(d->hw_realm, buf, (int) cch_buf); + trim_str(buf, cch_buf); + + StringCchLength(buf, cch_buf, &s); + + return (int) s; +} + +/* set the primary identity of a new credentials dialog depending on + the selection of the username and realm + + Runs in the UI thread +*/ +static void +set_identity_from_ui(khui_new_creds * nc, + k5_new_cred_data * d) { + wchar_t un[KCDB_IDENT_MAXCCH_NAME]; + wchar_t * realm; + khm_size cch; + khm_size cch_left; + khm_handle ident; + LRESULT idx = CB_ERR; + khm_int32 rv = KHM_ERROR_SUCCESS; + + cch = GetWindowTextLength(d->hw_username); + + /* we already set the max length of the edit control to be this. + shouldn't exceed it unless the edit control is confused. */ + assert(cch < KCDB_IDENT_MAXCCH_NAME - 1); + + GetWindowText(d->hw_username, un, ARRAYLENGTH(un)); + trim_str(un, ARRAYLENGTH(un)); + + realm = khm_get_realm_from_princ(un); + if (realm) /* realm was specified */ + goto _set_ident; + + /* the cch we got from GetWindowTextLength can not be trusted to + be exact. For caveats see MSDN for GetWindowTextLength. */ + StringCchLength(un, KCDB_IDENT_MAXCCH_NAME, &cch); + + 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) { + rv = KHM_ERROR_INVALID_NAME; + goto _set_null_ident; + } + + GetWindowText(d->hw_realm, realm, (int) cch_left); + trim_str(realm, cch_left); + + _set_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); + + kcdb_identity_release(ident); + return; + + _set_null_ident: + { + 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; +} + +/* runs in the UI thread */ +static BOOL +update_crossfeed(khui_new_creds * nc, + k5_new_cred_data * d, + int ctrl_id_src) { + wchar_t un[KCDB_IDENT_MAXCCH_NAME]; + wchar_t * un_realm; + wchar_t realm[KCDB_IDENT_MAXCCH_NAME]; + khm_size cch; + khm_size cch_left; + int idx; + + cch = (khm_size) GetWindowTextLength(d->hw_username); +#ifdef DEBUG + assert(cch < KCDB_IDENT_MAXCCH_NAME); +#endif + if (cch == 0) + return FALSE; + + GetWindowText(d->hw_username, + un, + ARRAYLENGTH(un)); + trim_str(un, ARRAYLENGTH(un)); + + un_realm = khm_get_realm_from_princ(un); + + if (un_realm == NULL) { + EnableWindow(d->hw_realm, TRUE); + return FALSE; + } + + if (ctrl_id_src == K5_NCID_UN) { + + idx = (int)SendMessage(d->hw_realm, + CB_FINDSTRINGEXACT, + (WPARAM) -1, + (LPARAM) un_realm); + + if (idx != CB_ERR) { + wchar_t srealm[KCDB_IDENT_MAXCCH_NAME]; + + cch = SendMessage(d->hw_realm, + CB_GETLBTEXTLEN, + (WPARAM) idx, + 0); + +#ifdef DEBUG + assert(cch < ARRAYLENGTH(srealm) - 1); +#endif + SendMessage(d->hw_realm, + CB_GETLBTEXT, + (WPARAM) idx, + (LPARAM) srealm); + + if (!_wcsicmp(srealm, un_realm) && wcscmp(srealm, un_realm)) { + /* differ only by case */ + + StringCchCopy(un_realm, ARRAYLENGTH(un) - (un_realm - un), + srealm); + + SetWindowText(d->hw_username, un); + } + } + + SendMessage(d->hw_realm, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) un_realm); + + SetWindowText(d->hw_realm, + un_realm); + + if (GetFocus() == d->hw_realm) { + HWND hw_next = GetNextDlgTabItem(nc->hwnd, d->hw_realm, + FALSE); + if (hw_next) + SetFocus(hw_next); + } + + EnableWindow(d->hw_realm, FALSE); + + return TRUE; + } + /* else... */ + + cch_left = KCDB_IDENT_MAXCCH_NAME - (un_realm - un); + + cch = (khm_size) GetWindowTextLength(d->hw_realm); + +#ifdef DEBUG + assert(cch < KCDB_IDENT_MAXCCH_NAME); +#endif + if (cch == 0) + return FALSE; + + GetWindowText(d->hw_realm, realm, + ARRAYLENGTH(realm)); + trim_str(realm, ARRAYLENGTH(realm)); + + idx = (int)SendMessage(d->hw_realm, + CB_FINDSTRINGEXACT, + (WPARAM) -1, + (LPARAM) realm); + + if (idx != CB_ERR) { + wchar_t srealm[KCDB_IDENT_MAXCCH_NAME]; + + SendMessage(d->hw_realm, + CB_GETLBTEXT, + (WPARAM) idx, + (LPARAM) srealm); + + if (!_wcsicmp(srealm, realm) && wcscmp(srealm, realm)) { + StringCbCopy(realm, sizeof(realm), srealm); + + SetWindowText(d->hw_realm, srealm); + } + } + + StringCchCopy(un_realm, cch_left, realm); + + SendMessage(d->hw_username, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) un); + + SetWindowText(d->hw_username, un); + + return TRUE; +} + +/* Handle window messages for the identity specifiers + + runs in UI thread */ +static LRESULT +handle_wnd_msg(khui_new_creds * nc, + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + k5_new_cred_data * d; + + d = (k5_new_cred_data *) nc->ident_aux; + + switch(uMsg) { + case WM_COMMAND: + switch(wParam) { + case MAKEWPARAM(K5_NCID_UN, CBN_EDITCHANGE): + /* the username has changed. Instead of handling this + for every keystroke, set a timer that elapses some + time afterwards and then handle the event. */ + SetTimer(hwnd, NC_UNCHANGE_TIMER, + NC_UNCHANGE_TIMEOUT, NULL); + return TRUE; + + case MAKEWPARAM(K5_NCID_UN, CBN_KILLFOCUS): + case MAKEWPARAM(K5_NCID_UN, CBN_CLOSEUP): + KillTimer(hwnd, NC_UNCHANGE_TIMER); + + update_crossfeed(nc,d,K5_NCID_UN); + set_identity_from_ui(nc,d); + return TRUE; + + case MAKEWPARAM(K5_NCID_REALM,CBN_EDITCHANGE): + SetTimer(hwnd, NC_REALMCHANGE_TIMER, + NC_REALMCHANGE_TIMEOUT, NULL); + return TRUE; + + case MAKEWPARAM(K5_NCID_REALM,CBN_KILLFOCUS): + case MAKEWPARAM(K5_NCID_REALM,CBN_CLOSEUP): + KillTimer(hwnd, NC_REALMCHANGE_TIMER); + + update_crossfeed(nc,d,K5_NCID_REALM); + set_identity_from_ui(nc, d); + return TRUE; + } + break; + + case WM_TIMER: + if(wParam == NC_UNCHANGE_TIMER) { + KillTimer(hwnd, NC_UNCHANGE_TIMER); + + update_crossfeed(nc, d, K5_NCID_UN); + set_identity_from_ui(nc,d); + return TRUE; + } else if (wParam == NC_REALMCHANGE_TIMER) { + KillTimer(hwnd, NC_REALMCHANGE_TIMER); + + update_crossfeed(nc, d, K5_NCID_REALM); + set_identity_from_ui(nc, d); + return TRUE; + } + break; + } + return FALSE; +} + +/* UI Callback + + runs in UI thread */ +static LRESULT KHMAPI +ui_cb(khui_new_creds * nc, + UINT cmd, + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + k5_new_cred_data * d; + + d = (k5_new_cred_data *) nc->ident_aux; + + switch(cmd) { + case WMNC_IDENT_INIT: + { + wchar_t defident[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wbuf[1024]; + wchar_t * ms = NULL; + wchar_t * t; + wchar_t * defrealm = NULL; + LRESULT lr; + khm_size cb_ms; + khm_size cb; + HWND hw_parent; + khm_int32 rv; + khm_handle hident; + + hw_parent = (HWND) lParam; + defident[0] = L'\0'; + +#ifdef DEBUG + assert(d == NULL); + assert(hw_parent != NULL); +#endif + + d = PMALLOC(sizeof(*d)); + assert(d); + ZeroMemory(d, sizeof(*d)); + + khui_cw_lock_nc(nc); + nc->ident_aux = (LPARAM) d; + khui_cw_unlock_nc(nc); + + LoadString(hResModule, IDS_NC_USERNAME, + wbuf, ARRAYLENGTH(wbuf)); + + d->hw_username_label = CreateWindow + (L"STATIC", + wbuf, + SS_SIMPLE | WS_CHILD | WS_VISIBLE, + 0, 0, 100, 100, /* bogus values */ + hw_parent, + (HMENU) K5_NCID_UN_LABEL, + hInstance, + NULL); + assert(d->hw_username_label != NULL); + + d->hw_username = CreateWindow + (L"COMBOBOX", + L"", + CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | + WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL, + 0, 0, 100, 100, /* bogus values */ + hw_parent, + (HMENU) K5_NCID_UN, + hInstance, + NULL); + assert(d->hw_username != NULL); + + SendMessage(d->hw_username, + CB_LIMITTEXT, + (WPARAM)(KCDB_IDENT_MAXCCH_NAME - 1), + 0); + + SendMessage(d->hw_username, + CB_SETEXTENDEDUI, + (WPARAM) TRUE, + 0); + + khui_cw_add_control_row(nc, + d->hw_username_label, + d->hw_username, + KHUI_CTRLSIZE_SMALL); + + LoadString(hResModule, IDS_NC_REALM, + wbuf, ARRAYLENGTH(wbuf)); + + d->hw_realm_label = CreateWindow + (L"STATIC", + wbuf, + SS_SIMPLE | WS_CHILD | WS_VISIBLE, + 0, 0, 100, 100, /* bogus */ + hw_parent, + (HMENU) K5_NCID_REALM_LABEL, + hInstance, + NULL); + assert(d->hw_realm_label != NULL); + + d->hw_realm = CreateWindow + (L"COMBOBOX", + L"", + CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | + WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL, + 0, 0, 100, 100, /* bogus */ + hw_parent, + (HMENU) K5_NCID_REALM, + hInstance, + NULL); + assert(d->hw_realm != NULL); + + SendMessage(d->hw_realm, + CB_LIMITTEXT, + (WPARAM) (KCDB_IDENT_MAXCCH_NAME - 1), + 0); + + SendMessage(d->hw_realm, + CB_SETEXTENDEDUI, + (WPARAM) TRUE, + 0); + + khui_cw_add_control_row(nc, + d->hw_realm_label, + d->hw_realm, + KHUI_CTRLSIZE_SMALL); + + /* add the LRU realms and principals to the dropdown + lists */ + rv = khc_read_multi_string(csp_params, + L"LRUPrincipals", + NULL, + &cb_ms); + + if (rv != KHM_ERROR_TOO_LONG || cb_ms <= sizeof(wchar_t) * 2) + goto _add_lru_realms; + + ms = PMALLOC(cb_ms); + assert(ms != NULL); + + cb = cb_ms; + rv = khc_read_multi_string(csp_params, + L"LRUPrincipals", + ms, + &cb); + + assert(KHM_SUCCEEDED(rv)); + + /* the first of these is considered the default identity + if no other default is known */ + StringCbCopy(defident, sizeof(defident), ms); + + t = ms; + while(t && *t) { + SendMessage(d->hw_username, + CB_ADDSTRING, + 0, + (LPARAM) t); + + t = multi_string_next(t); + } + + _add_lru_realms: + /* add the default realm first */ + defrealm = khm_krb5_get_default_realm(); + if (defrealm) { + SendMessage(d->hw_realm, + CB_ADDSTRING, + 0, + (LPARAM) defrealm); + } + + rv = khc_read_multi_string(csp_params, + L"LRURealms", + NULL, + &cb); + + if (rv != KHM_ERROR_TOO_LONG) + goto _done_adding_lru; + + if (ms != NULL) { + if (cb_ms < cb) { + PFREE(ms); + ms = PMALLOC(cb); + assert(ms); + cb_ms = cb; + } + } else { + ms = PMALLOC(cb); + cb_ms = cb; + } + + rv = khc_read_multi_string(csp_params, + L"LRURealms", + ms, + &cb); + + assert(KHM_SUCCEEDED(rv)); + + for (t = ms; t && *t; t = multi_string_next(t)) { + lr = SendMessage(d->hw_realm, + CB_FINDSTRINGEXACT, + (WPARAM) -1, + (LPARAM) t); + if (lr != CB_ERR) + continue; + + SendMessage(d->hw_realm, + CB_ADDSTRING, + 0, + (LPARAM) t); + } + _done_adding_lru: + + { + khm_int32 inc_realms = 0; + + if (KHM_FAILED(khc_read_int32(csp_params, + L"UseFullRealmList", + &inc_realms)) || + !inc_realms) + goto _done_adding_all_realms; + } + + if(ms) + PFREE(ms); + + ms = khm_krb5_get_realm_list(); + if(ms) { + for (t = ms; t && *t; t = multi_string_next(t)) { + lr = SendMessage(d->hw_realm, + CB_FINDSTRINGEXACT, + (WPARAM) -1, + (LPARAM) t); + if (lr != CB_ERR) + continue; + + SendMessage(d->hw_realm, + CB_ADDSTRING, + 0, + (LPARAM) t); + } + } + _done_adding_all_realms: + + /* set the current selection of the realms list */ + if (defrealm) { + SendMessage(d->hw_realm, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) defrealm); + } else { + SendMessage(d->hw_realm, + CB_SETCURSEL, + (WPARAM) 0, + (LPARAM) 0); + } + + if (defrealm) + PFREE(defrealm); + + if (ms) + PFREE(ms); + + /* now see about that default identity */ + if (nc->ctx.identity) { + cb = sizeof(defident); + kcdb_identity_get_name(nc->ctx.identity, + defident, + &cb); + } + + if (defident[0] == L'\0' && + KHM_SUCCEEDED(kcdb_identity_get_default(&hident))) { + cb = sizeof(defident); + kcdb_identity_get_name(hident, defident, &cb); + kcdb_identity_release(hident); + } + + if (defident[0] == L'\0') { + DWORD dw; + + dw = ARRAYLENGTH(defident); + GetUserName(defident, &dw); + } + + t = khm_get_realm_from_princ(defident); + if (t) { + /* there is a realm */ + assert(t != defident); + *--t = L'\0'; + t++; + + SendMessage(d->hw_realm, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) t); + + SendMessage(d->hw_realm, + WM_SETTEXT, + 0, + (LPARAM) t); + } + + if (defident[0] != L'\0') { + /* there is a username */ + SendMessage(d->hw_username, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) defident); + + SendMessage(d->hw_username, + WM_SETTEXT, + 0, + (LPARAM) defident); + } + + set_identity_from_ui(nc, d); + } + return TRUE; + + case WMNC_IDENT_WMSG: + return handle_wnd_msg(nc, hwnd, uMsg, wParam, lParam); + + case WMNC_IDENT_EXIT: + { +#ifdef DEBUG + assert(d != NULL); +#endif + khui_cw_lock_nc(nc); + nc->ident_aux = 0; + khui_cw_unlock_nc(nc); + + /* since we created all the windows as child windows of + the new creds window, they will be destroyed when that + window is destroyed. */ + PFREE(d); + } + return TRUE; + } + return FALSE; +} + +static khm_int32 +k5_ident_validate_name(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + krb5_principal princ = NULL; + char princ_name[KCDB_IDENT_MAXCCH_NAME]; + kcdb_ident_name_xfer * nx; + krb5_error_code code; + wchar_t * atsign; + + nx = (kcdb_ident_name_xfer *) vparam; + + if(UnicodeStrToAnsi(princ_name, sizeof(princ_name), + nx->name_src) == 0) { + nx->result = KHM_ERROR_INVALID_NAME; + return KHM_ERROR_SUCCESS; + } + + assert(k5_identpro_ctx != NULL); + + code = pkrb5_parse_name(k5_identpro_ctx, + princ_name, + &princ); + + if (code) { + nx->result = KHM_ERROR_INVALID_NAME; + return KHM_ERROR_SUCCESS; + } + + if (princ != NULL) + pkrb5_free_principal(k5_identpro_ctx, + princ); + + /* krb5_parse_name() accepts principal names with no realm or an + empty realm. We don't. */ + atsign = wcschr(nx->name_src, L'@'); + if (atsign == NULL || atsign[1] == L'\0') { + nx->result = KHM_ERROR_INVALID_NAME; + } else { + nx->result = KHM_ERROR_SUCCESS; + } + + return KHM_ERROR_SUCCESS; +} + +static void +k5_update_last_default_identity(khm_handle ident) { + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + + cb = sizeof(idname); + if (KHM_FAILED(kcdb_identity_get_name(ident, idname, &cb))) + return; + + assert(csp_params); + + khc_write_string(csp_params, L"LastDefaultIdent", idname); +} + +static khm_int32 +k5_ident_set_default_int(khm_handle def_ident) { + wchar_t id_ccname[KRB5_MAXCCH_CCNAME]; + khm_size cb; + DWORD dw; + LONG l; + HKEY hk_ccname; + DWORD dwType; + DWORD dwSize; + wchar_t reg_ccname[KRB5_MAXCCH_CCNAME]; + +#ifdef DEBUG + assert(def_ident != NULL); +#endif + + cb = sizeof(id_ccname); + if (KHM_FAILED(kcdb_identity_get_attr(def_ident, attr_id_krb5_ccname, NULL, + id_ccname, &cb))) { + khm_handle csp_ident = NULL; + khm_handle csp_k5 = NULL; + + _reportf(L"The specified identity does not have the Krb5CCName property"); + + cb = sizeof(id_ccname); + if (KHM_SUCCEEDED(kcdb_identity_get_config(def_ident, 0, &csp_ident)) && + KHM_SUCCEEDED(khc_open_space(csp_ident, CSNAME_KRB5CRED, 0, &csp_k5)) && + KHM_SUCCEEDED(khc_read_string(csp_k5, L"DefaultCCName", + id_ccname, &cb))) { + + _reportf(L"Found CC name in configuration [%s]", id_ccname); + } else { + /* last resort, use the name of the identity as the cc + name */ + cb = sizeof(id_ccname); + if (KHM_FAILED(kcdb_identity_get_name(def_ident, id_ccname, &cb))) { + _reportf(L"Can't use name of identity as CCName"); + _end_task(); + + id_ccname[0] = L'\0'; + } + } + + if (csp_k5) + khc_close_space(csp_k5); + if (csp_ident) + khc_close_space(csp_ident); + + if (id_ccname[0] == L'\0') + return KHM_ERROR_INVALID_PARAM; + } + + khm_krb5_canon_cc_name(id_ccname, sizeof(id_ccname)); + + _reportf(L"Found Krb5CCName property : %s", id_ccname); + + StringCbLength(id_ccname, sizeof(id_ccname), &cb); + cb += sizeof(wchar_t); + + _reportf(L"Setting default CC name in the registry"); + + l = RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\MIT\\kerberos5", 0, + KEY_READ | KEY_WRITE, &hk_ccname); + + if (l != ERROR_SUCCESS) + l = RegCreateKeyEx(HKEY_CURRENT_USER, L"Software\\MIT\\kerberos5", 0, + NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, + NULL, &hk_ccname, &dw); + + if (l != ERROR_SUCCESS) { + _reportf(L"Can't create registry key : %d", l); + _end_task(); + return KHM_ERROR_UNKNOWN; + } + + dwSize = sizeof(reg_ccname); + + l = RegQueryValueEx(hk_ccname, L"ccname", NULL, &dwType, (LPBYTE) reg_ccname, + &dwSize); + + if (l != ERROR_SUCCESS || + dwType != REG_SZ || + khm_krb5_cc_name_cmp(reg_ccname, id_ccname)) { + + /* we have to write the new value in */ + + l = RegSetValueEx(hk_ccname, L"ccname", 0, REG_SZ, (BYTE *) id_ccname, + (DWORD) cb); + } + + RegCloseKey(hk_ccname); + + if (l == ERROR_SUCCESS) { + _reportf(L"Successfully set the default ccache"); + k5_update_last_default_identity(def_ident); + return KHM_ERROR_SUCCESS; + } else { + _reportf(L"Can't set the registry value : %d", l); + return KHM_ERROR_UNKNOWN; + } +} + +static khm_int32 +k5_ident_set_default(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + + /* + Currently, setting the default identity simply sets the + "ccname" registry value at "Software\MIT\kerberos5". + */ + + if (uparam) { + /* an identity is being made default */ + khm_handle def_ident = (khm_handle) vparam; + khm_int32 rv; + +#ifdef DEBUG + assert(def_ident != NULL); +#endif + + { + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + + cb = sizeof(idname); + kcdb_identity_get_name(def_ident, idname, &cb); + + _begin_task(0); + _report_cs1(KHERR_DEBUG_1, L"Setting default identity [%1!s!]", _cstr(idname)); + _describe(); + } + + rv = k5_ident_set_default_int(def_ident); + + _end_task(); + + return rv; + + } else { + /* the default identity is being forgotten */ + + /* we don't really do anything about this case */ + } + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +k5_ident_get_ui_cb(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + khui_ident_new_creds_cb * cb; + + cb = (khui_ident_new_creds_cb *) vparam; + + *cb = ui_cb; + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +k5_ident_notify_create(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + + /* a new identity has been created. What we want to do at + this point is to check if the identity belongs to krb5 + and to see if it is the default. */ + + krb5_ccache cc = NULL; + krb5_error_code code; + krb5_principal princ = NULL; + char * princ_nameA = NULL; + wchar_t princ_nameW[KCDB_IDENT_MAXCCH_NAME]; + wchar_t id_nameW[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khm_handle ident; + + /* if there is a default identity already, we assume we don't need + to check this one. */ + + khm_handle def_ident; + + if (KHM_SUCCEEDED(kcdb_identity_get_default(&def_ident))) { + kcdb_identity_release(def_ident); + + return KHM_ERROR_SUCCESS; + } + + ident = (khm_handle) vparam; + + assert(k5_identpro_ctx != NULL); + + code = pkrb5_cc_default(k5_identpro_ctx, &cc); + if (code) + goto _nc_cleanup; + + code = pkrb5_cc_get_principal(k5_identpro_ctx, + cc, + &princ); + if (code) + goto _nc_cleanup; + + code = pkrb5_unparse_name(k5_identpro_ctx, + princ, + &princ_nameA); + if (code) + goto _nc_cleanup; + + AnsiStrToUnicode(princ_nameW, + sizeof(princ_nameW), + princ_nameA); + + cb = sizeof(id_nameW); + + if (KHM_FAILED(kcdb_identity_get_name(ident, + id_nameW, + &cb))) + goto _nc_cleanup; + + if (!wcscmp(id_nameW, princ_nameW)) { + kcdb_identity_set_default_int(ident); + } + + _nc_cleanup: + if (princ_nameA) + pkrb5_free_unparsed_name(k5_identpro_ctx, + princ_nameA); + if (princ) + pkrb5_free_principal(k5_identpro_ctx, + princ); + if (cc) + pkrb5_cc_close(k5_identpro_ctx, cc); + + return KHM_ERROR_SUCCESS; +} + +struct k5_ident_update_data { + khm_handle identity; + + FILETIME ft_expire; /* expiration */ + FILETIME ft_issue; /* issue */ + FILETIME ft_rexpire; /* renew expiration */ + wchar_t ccname[KRB5_MAXCCH_CCNAME]; + khm_int32 k5_flags; +}; + +/* The logic here has to reflect the logic in khm_krb5_list_tickets(). + We use this to handle an identity update request because some other + plug-in or maybe NetIDMgr itself is about to do something + important(tm) with the identity and needs to make sure that the + properties of the identity are up-to-date. */ +static khm_int32 KHMAPI +k5_ident_update_apply_proc(khm_handle cred, + void * rock) { + struct k5_ident_update_data * d = (struct k5_ident_update_data *) rock; + khm_handle ident = NULL; + khm_int32 t; + khm_int32 flags; + FILETIME t_cexpire; + FILETIME t_rexpire; + khm_size cb; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if (KHM_FAILED(kcdb_cred_get_type(cred, &t)) || + t != credtype_id_krb5 || + KHM_FAILED(kcdb_cred_get_identity(cred, &ident))) + + return KHM_ERROR_SUCCESS; + + if (!kcdb_identity_is_equal(ident,d->identity)) + + goto _cleanup; + + if (KHM_FAILED(kcdb_cred_get_flags(cred, &flags))) + + flags = 0; + + if (flags & KCDB_CRED_FLAG_INITIAL) { + cb = sizeof(t_cexpire); + if (KHM_SUCCEEDED(kcdb_cred_get_attr(cred, + KCDB_ATTR_EXPIRE, + NULL, + &t_cexpire, + &cb))) { + if ((d->ft_expire.dwLowDateTime == 0 && + d->ft_expire.dwHighDateTime == 0) || + CompareFileTime(&t_cexpire, &d->ft_expire) > 0) { + goto update_identity; + } + } + } + + goto _cleanup; + + update_identity: + + d->ft_expire = t_cexpire; + + cb = sizeof(d->ccname); + if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_LOCATION, NULL, d->ccname, &cb))) { + d->ccname[0] = L'\0'; + } + + cb = sizeof(d->k5_flags); + if (KHM_FAILED(kcdb_cred_get_attr(cred, attr_id_krb5_flags, NULL, + &d->k5_flags, &cb))) { + d->k5_flags = 0; + } + + cb = sizeof(d->ft_issue); + if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_ISSUE, NULL, &d->ft_issue, &cb))) { + ZeroMemory(&d->ft_issue, sizeof(d->ft_issue)); + } + + cb = sizeof(t_rexpire); + if ((d->k5_flags & TKT_FLG_RENEWABLE) && + KHM_SUCCEEDED(kcdb_cred_get_attr(cred, + KCDB_ATTR_RENEW_EXPIRE, + NULL, + &t_rexpire, + &cb))) { + d->ft_rexpire = t_rexpire; + } else { + ZeroMemory(&d->ft_rexpire, sizeof(d->ft_rexpire)); + } + + _cleanup: + if (ident) + kcdb_identity_release(ident); + + return rv; +} + +static khm_int32 +k5_ident_update(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + +#if 0 + struct k5_ident_update_data d; +#endif + khm_handle ident; + khm_handle tident; + krb5_ccache cc = NULL; + char * ccname; + krb5_error_code code; + khm_size cb; + wchar_t wid_ccname[MAX_PATH]; + wchar_t w_ccname[MAX_PATH]; + + ident = (khm_handle) vparam; + if (ident == NULL) + return KHM_ERROR_SUCCESS; + +#if 0 + /* we are going to skip doing this here since + khm_krb5_list_tickets() performs this function for us each time + we enumerate tickets. Since it also gets run each time our + list of tickets changes and since we are basing this operation + on existing tickets, we are unlikely to find anything new + here. */ + ZeroMemory(&d, sizeof(d)); + d.identity = ident; + + kcdb_credset_apply(NULL, + k5_ident_update_apply_proc, + (void *) &d); + + if (d.ft_expire.dwLowDateTime != 0 || + d.ft_expire.dwHighDateTime != 0) { + + /* we found a TGT */ + + kcdb_identity_set_attr(ident, KCDB_ATTR_EXPIRE, + &d.ft_expire, sizeof(d.ft_expire)); + if (d.ft_issue.dwLowDateTime != 0 || + d.ft_issue.dwHighDateTime != 0) + kcdb_identity_set_attr(ident, KCDB_ATTR_ISSUE, + &d.ft_issue, sizeof(d.ft_issue)); + else + kcdb_identity_set_attr(ident, KCDB_ATTR_ISSUE, NULL, 0); + + if (d.ft_rexpire.dwLowDateTime != 0 || + d.ft_rexpire.dwHighDateTime != 0) + kcdb_identity_set_attr(ident, KCDB_ATTR_RENEW_EXPIRE, + &d.ft_rexpire, sizeof(d.ft_rexpire)); + else + kcdb_identity_set_attr(ident, KCDB_ATTR_RENEW_EXPIRE, NULL, 0); + + kcdb_identity_set_attr(ident, attr_id_krb5_flags, + &d.k5_flags, sizeof(d.k5_flags)); + + if (d.ccname[0]) + kcdb_identity_set_attr(ident, attr_id_krb5_ccname, + d.ccname, KCDB_CBSIZE_AUTO); + else + kcdb_identity_set_attr(ident, attr_id_krb5_ccname, NULL, 0); + + } else { + /* Clear out the attributes. We don't have any information + about this identity */ + kcdb_identity_set_attr(ident, KCDB_ATTR_EXPIRE, NULL, 0); + kcdb_identity_set_attr(ident, KCDB_ATTR_ISSUE, NULL, 0); + kcdb_identity_set_attr(ident, KCDB_ATTR_RENEW_EXPIRE, NULL, 0); + kcdb_identity_set_attr(ident, attr_id_krb5_flags, NULL, 0); + kcdb_identity_set_attr(ident, attr_id_krb5_ccname, NULL, 0); + } +#endif + + if (KHM_SUCCEEDED(kcdb_identity_get_default(&tident))) { + kcdb_identity_release(tident); + goto _iu_cleanup; + } + + cb = sizeof(wid_ccname); + if (KHM_FAILED(kcdb_identity_get_attr(ident, + attr_id_krb5_ccname, + NULL, + wid_ccname, + &cb))) + goto _iu_cleanup; + + if(k5_identpro_ctx == NULL) + goto _iu_cleanup; + + code = pkrb5_cc_default(k5_identpro_ctx, &cc); + if (code) + goto _iu_cleanup; + + ccname = pkrb5_cc_get_name(k5_identpro_ctx, cc); + if (ccname == NULL) + goto _iu_cleanup; + + AnsiStrToUnicode(w_ccname, sizeof(w_ccname), ccname); + + khm_krb5_canon_cc_name(w_ccname, sizeof(w_ccname)); + khm_krb5_canon_cc_name(wid_ccname, sizeof(wid_ccname)); + + if (!_wcsicmp(w_ccname, wid_ccname)) + kcdb_identity_set_default_int(ident); + + _iu_cleanup: + if (cc && k5_identpro_ctx) + pkrb5_cc_close(k5_identpro_ctx, cc); + + return KHM_ERROR_SUCCESS; +} + +static khm_boolean +k5_refresh_default_identity(krb5_context ctx) { + /* just like notify_create, except now we set the default identity + based on what we find in the configuration */ + krb5_ccache cc = NULL; + krb5_error_code code; + krb5_principal princ = NULL; + char * princ_nameA = NULL; + wchar_t princ_nameW[KCDB_IDENT_MAXCCH_NAME]; + char * ccname = NULL; + khm_handle ident = NULL; + khm_boolean found_default = FALSE; + + assert(ctx != NULL); + + _begin_task(0); + _report_cs0(KHERR_DEBUG_1, L"Refreshing default identity"); + _describe(); + + code = pkrb5_cc_default(ctx, &cc); + if (code) { + _reportf(L"Can't open default ccache. code=%d", code); + goto _nc_cleanup; + } + + code = pkrb5_cc_get_principal(ctx, cc, &princ); + if (code) { + /* try to determine the identity from the ccache name */ + ccname = pkrb5_cc_get_name(ctx, cc); + + if (ccname) { + char * namepart = strchr(ccname, ':'); + + _reportf(L"CC name is [%S]", ccname); + + if (namepart == NULL) + namepart = ccname; + else + namepart++; + + _reportf(L"Checking if [%S] is a valid identity name", namepart); + + AnsiStrToUnicode(princ_nameW, sizeof(princ_nameW), namepart); + if (kcdb_identity_is_valid_name(princ_nameW)) { + kcdb_identity_create(princ_nameW, KCDB_IDENT_FLAG_CREATE, &ident); + if (ident) { + _reportf(L"Setting [%S] as the default identity", namepart); + kcdb_identity_set_default_int(ident); + found_default = TRUE; + } + } + } else { + _reportf(L"Can't determine ccache name"); + } + + goto _nc_cleanup; + } + + code = pkrb5_unparse_name(ctx, princ, &princ_nameA); + if (code) + goto _nc_cleanup; + + AnsiStrToUnicode(princ_nameW, sizeof(princ_nameW), princ_nameA); + + _reportf(L"Found principal [%s]", princ_nameW); + + if (KHM_FAILED(kcdb_identity_create(princ_nameW, KCDB_IDENT_FLAG_CREATE, &ident))) { + _reportf(L"Failed to create identity"); + goto _nc_cleanup; + } + + _reportf(L"Setting default identity to [%s]", princ_nameW); + kcdb_identity_set_default_int(ident); + + found_default = TRUE; + + _nc_cleanup: + + _end_task(); + + if (princ_nameA) + pkrb5_free_unparsed_name(ctx, princ_nameA); + + if (princ) + pkrb5_free_principal(ctx, princ); + + if (cc) + pkrb5_cc_close(ctx, cc); + + if (ident) + kcdb_identity_release(ident); + + return found_default; +} + +static khm_int32 +k5_ident_init(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + + khm_boolean found_default; + khm_handle ident; + + found_default = k5_refresh_default_identity(k5_identpro_ctx); + + if (!found_default) { + wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + + cb = sizeof(widname); + + assert(csp_params); + + if (KHM_SUCCEEDED(khc_read_string(csp_params, L"LastDefaultIdent", + widname, &cb))) { + ident = NULL; + kcdb_identity_create(widname, KCDB_IDENT_FLAG_CREATE, &ident); + if (ident) { + kcdb_identity_set_default_int(ident); + kcdb_identity_release(ident); + + found_default = TRUE; + } + } + } + + if (!found_default) { + + /* There was no default ccache and we don't have a + "LastDefaultIdent" value. Next we see if there are any + identities that have credentials which have a Krb5CCName + property (i.e. an identity that has a Kerberos 5 TGT), and + make it the default. + + Note that since the Krb5Ident plug-in has a dependency on + Krb5Cred, by the time this code runs, we already have a + listing of Kerberos 5 tickets and identities. */ + + wchar_t * idlist = NULL; + wchar_t * thisid; + khm_size cb = 0; + khm_size n_idents = 0; + khm_int32 rv; + wchar_t ccname[KRB5_MAXCCH_CCNAME]; + FILETIME ft_expire; + FILETIME ft_now; + FILETIME ft_threshold; + BOOL match_all = FALSE; + + rv = kcdb_identity_enum(0, 0, NULL, &cb, &n_idents); + + TimetToFileTimeInterval(5 * 60, &ft_threshold); + GetSystemTimeAsFileTime(&ft_now); + ft_now = FtAdd(&ft_now, &ft_threshold); + + while (rv == KHM_ERROR_TOO_LONG && n_idents > 0) { + if (idlist) { + PFREE(idlist); + idlist = NULL; + } + + idlist = PMALLOC(cb); + + if (idlist == NULL) + break; + + rv = kcdb_identity_enum(0, 0, idlist, &cb, &n_idents); + } + + if (KHM_SUCCEEDED(rv)) { + + /* first we try to find an identity that has a valid TGT. + If that fails, then we try to find an identity with + *any* TGT. */ + + try_again: + + for (thisid = idlist; + thisid && *thisid && !found_default; + thisid = multi_string_next(thisid)) { + + if (KHM_SUCCEEDED(kcdb_identity_create(thisid, 0, &ident))) { + khm_size cb_ft = sizeof(FILETIME); + cb = sizeof(ccname); + + if (KHM_SUCCEEDED(kcdb_identity_get_attr(ident, attr_id_krb5_ccname, + NULL, ccname, &cb)) && + (match_all || + (KHM_SUCCEEDED(kcdb_identity_get_attr(ident, KCDB_ATTR_EXPIRE, + NULL, &ft_expire, &cb_ft)) && + CompareFileTime(&ft_expire, &ft_now) > 0))) { + + /* found one */ + k5_ident_set_default_int(ident); + kcdb_identity_set_default_int(ident); + found_default = TRUE; + + } + + kcdb_identity_release(ident); + ident = NULL; + } + } + + if (!found_default && !match_all) { + match_all = TRUE; + goto try_again; + } + } + + if (idlist) { + PFREE(idlist); + idlist = NULL; + } + } + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +k5_ident_exit(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + /* don't really do anything */ + return KHM_ERROR_SUCCESS; +} + +/* forward dcl */ +khm_int32 KHMAPI +k5_ident_name_comp_func(const void * dl, khm_size cb_dl, + const void * dr, khm_size cb_dr); + +static khm_int32 +k5_ident_compare_name(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + kcdb_ident_name_xfer *px; + + px = (kcdb_ident_name_xfer *) vparam; + + /* note that k5_ident_name_comp_func() ignores the size + specifiers. So we can just pass in 0's. */ + px->result = k5_ident_name_comp_func(px->name_src, 0, + px->name_alt, 0); + + return KHM_ERROR_SUCCESS; +} + +#if 0 +/* copy and paste template for ident provider messages */ +static khm_int32 +k5_ident_(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { +} +#endif + +khm_int32 KHMAPI +k5_msg_ident(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) +{ + switch(msg_subtype) { + case KMSG_IDENT_INIT: + return k5_ident_init(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_EXIT: + return k5_ident_exit(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_VALIDATE_NAME: + return k5_ident_validate_name(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_VALIDATE_IDENTITY: + /* TODO: handle KMSG_IDENT_VALIDATE_IDENTITY */ + break; + + case KMSG_IDENT_CANON_NAME: + /* TODO: handle KMSG_IDENT_CANON_NAME */ + break; + + case KMSG_IDENT_COMPARE_NAME: + return k5_ident_compare_name(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_SET_DEFAULT: + return k5_ident_set_default(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_SET_SEARCHABLE: + /* TODO: handle KMSG_IDENT_SET_SEARCHABLE */ + break; + + case KMSG_IDENT_GET_INFO: + /* TODO: handle KMSG_IDENT_GET_INFO */ + break; + + case KMSG_IDENT_UPDATE: + return k5_ident_update(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_ENUM_KNOWN: + /* TODO: handle KMSG_IDENT_ENUM_KNOWN */ + break; + + case KMSG_IDENT_GET_UI_CALLBACK: + return k5_ident_get_ui_cb(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_NOTIFY_CREATE: + return k5_ident_notify_create(msg_type, + msg_subtype, + uparam, + vparam); + } + + return KHM_ERROR_SUCCESS; +} + +/* note that we are ignoring the size specifiers. We can do that + because we are guaranteed that dl and dr point to NULL terminated + unicode strings when used with credential data buffers. We also + use the fact that we are ignoring the size specifiers when we call + this function from k5_ident_compare_name() to avoid calculating the + length of the string. */ +khm_int32 KHMAPI +k5_ident_name_comp_func(const void * dl, khm_size cb_dl, + const void * dr, khm_size cb_dr) { + wchar_t * idl = (wchar_t *) dl; + wchar_t * idr = (wchar_t *) dr; + wchar_t * rl; + wchar_t * rr; + khm_int32 r; + + rl = khm_get_realm_from_princ(idl); + rr = khm_get_realm_from_princ(idr); + + if (rl == NULL && rr == NULL) + return wcscmp(idl, idr); + else if (rl == NULL) + return 1; + else if (rr == NULL) + return -1; + + r = wcscmp(rl, rr); + if (r == 0) + return wcscmp(idl, idr); + else + return r; +} + + +/* Identity change notification thread */ + +HANDLE h_ccname_exit_event; +HANDLE h_ccname_thread; + +DWORD WINAPI k5_ccname_monitor_thread(LPVOID lpParameter) { + krb5_context ctx = 0; + + HKEY hk_ccname; + HANDLE h_notify; + HANDLE h_waits[2]; + + khm_int32 rv = KHM_ERROR_SUCCESS; + DWORD dwType; + DWORD dwSize; + DWORD dwDisp; + wchar_t reg_ccname[KRB5_MAXCCH_CCNAME]; + LONG l; + + PDESCTHREAD(L"Krb5 CCName Monitor", L"Krb5"); + + l = RegOpenKeyEx(HKEY_CURRENT_USER, + L"Software\\MIT\\kerberos5", + 0, + KEY_READ | KEY_WRITE, + &hk_ccname); + + if (l != ERROR_SUCCESS) + l = RegCreateKeyEx(HKEY_CURRENT_USER, + L"Software\\MIT\\kerberos5", + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, + &hk_ccname, + &dwDisp); + + if (l != ERROR_SUCCESS) { + rv = KHM_ERROR_UNKNOWN; + goto _exit; + } + + dwSize = sizeof(reg_ccname); + + l = RegQueryValueEx(hk_ccname, + L"ccname", + NULL, + &dwType, + (LPBYTE) reg_ccname, + &dwSize); + + if (l != ERROR_SUCCESS || + dwType != REG_SZ) { + + reg_ccname[0] = L'\0'; + } + + l = pkrb5_init_context(&ctx); + + if (l) + goto _exit_0; + + h_notify = CreateEvent(NULL, FALSE, FALSE, L"Local\\Krb5CCNameChangeNotifier"); + + if (h_notify == NULL) + goto _exit_0; + + /* begin wait loop */ + + h_waits[0] = h_ccname_exit_event; + h_waits[1] = h_notify; + + do { + DWORD dwrv; + + l = RegNotifyChangeKeyValue(hk_ccname, FALSE, + REG_NOTIFY_CHANGE_LAST_SET, + h_notify, TRUE); + + if (l != ERROR_SUCCESS) { + rv = KHM_ERROR_UNKNOWN; + break; + } + + dwrv = WaitForMultipleObjects(2, h_waits, FALSE, INFINITE); + + if (dwrv == WAIT_OBJECT_0) { + /* exit! */ + break; + + } else if (dwrv == WAIT_OBJECT_0 + 1) { + /* change notify! */ + wchar_t new_ccname[KRB5_MAXCCH_CCNAME]; + + dwSize = sizeof(new_ccname); + + l = RegQueryValueEx(hk_ccname, + L"ccname", + NULL, + &dwType, + (LPBYTE) new_ccname, + &dwSize); + + if (l != ERROR_SUCCESS || + dwType != REG_SZ) { + new_ccname[0] = L'\0'; + } + + if (_wcsicmp(new_ccname, reg_ccname)) { + k5_refresh_default_identity(ctx); + StringCbCopy(reg_ccname, sizeof(reg_ccname), new_ccname); + } + + } else { + /* something went wrong */ + rv = KHM_ERROR_UNKNOWN; + break; + } + + } while (TRUE); + + CloseHandle(h_notify); + + _exit_0: + + RegCloseKey(hk_ccname); + + if (ctx) + pkrb5_free_context(ctx); + + _exit: + ExitThread(rv); + + /* not reached */ + return rv; +} + +khm_int32 +k5_msg_system_idpro(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) { + + switch(msg_subtype) { + case KMSG_SYSTEM_INIT: + { + + pkrb5_init_context(&k5_identpro_ctx); + kcdb_identity_set_type(credtype_id_krb5); + + if (KHM_FAILED(kcdb_type_get_id(TYPENAME_KRB5_PRINC, + &type_id_krb5_princ))) { + kcdb_type dt; + kcdb_type * pstr; + + kcdb_type_get_info(KCDB_TYPE_STRING, &pstr); + + ZeroMemory(&dt, sizeof(dt)); + dt.name = TYPENAME_KRB5_PRINC; + dt.id = KCDB_TYPE_INVALID; + dt.flags = KCDB_TYPE_FLAG_CB_AUTO; + dt.cb_min = pstr->cb_min; + dt.cb_max = pstr->cb_max; + dt.toString = pstr->toString; + dt.isValid = pstr->isValid; + dt.comp = k5_ident_name_comp_func; + dt.dup = pstr->dup; + + kcdb_type_register(&dt, &type_id_krb5_princ); + + type_regd_krb5_princ = TRUE; + + kcdb_type_release_info(pstr); + } + + if (type_id_krb5_princ != -1) { + kcdb_attrib * attr; + + kcdb_attrib_get_info(KCDB_ATTR_ID_NAME, &attr); + + attr->type = type_id_krb5_princ; + + kcdb_attrib_release_info(attr); + } + + h_ccname_exit_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (h_ccname_exit_event) { + h_ccname_thread = CreateThread(NULL, + 200 * 1024, + k5_ccname_monitor_thread, + NULL, + 0, + NULL); + } else { + h_ccname_thread = NULL; + } + } + break; + + case KMSG_SYSTEM_EXIT: + { + + if (h_ccname_thread) { + SetEvent(h_ccname_exit_event); + WaitForSingleObject(h_ccname_thread, INFINITE); + CloseHandle(h_ccname_thread); + CloseHandle(h_ccname_exit_event); + + h_ccname_exit_event = NULL; + h_ccname_thread = NULL; + } + + if (k5_identpro_ctx) { + pkrb5_free_context(k5_identpro_ctx); + k5_identpro_ctx = NULL; + } + + if (type_id_krb5_princ != -1) { + kcdb_attrib * attr; + + kcdb_attrib_get_info(KCDB_ATTR_ID_NAME, &attr); + + attr->type = KCDB_TYPE_STRING; + + kcdb_attrib_release_info(attr); + } + + /* allow a brief moment for any stale references to die */ + Sleep(100); + + if (type_regd_krb5_princ) { + kcdb_type_unregister(type_id_krb5_princ); + } + } + break; + } + + return KHM_ERROR_SUCCESS; +} + +khm_int32 KHMAPI +k5_ident_callback(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) { + switch(msg_type) { + case KMSG_SYSTEM: + return k5_msg_system_idpro(msg_type, msg_subtype, uparam, vparam); + + case KMSG_IDENT: + return k5_msg_ident(msg_type, msg_subtype, uparam, vparam); + } + + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/plugins/krb5/krb5main.c b/src/windows/identity/plugins/krb5/krb5main.c index 3d2f2c0e9..befa7a980 100644 --- a/src/windows/identity/plugins/krb5/krb5main.c +++ b/src/windows/identity/plugins/krb5/krb5main.c @@ -1,497 +1,497 @@ -/* - * 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 - -kmm_module h_khModule; /* KMM's handle to this module */ -HINSTANCE hInstance; -HMODULE hResModule; /* HMODULE to the resource library */ -const wchar_t * k5_facility = L"Krb5Cred"; - -khm_int32 type_id_enctype = -1; -khm_int32 type_id_addr_list = -1; -khm_int32 type_id_krb5_flags = -1; -khm_int32 type_id_krb5_princ = -1; -khm_int32 type_id_kvno = -1; - -BOOL type_regd_enctype = FALSE; -BOOL type_regd_addr_list = FALSE; -BOOL type_regd_krb5_flags = FALSE; -BOOL type_regd_krb5_princ = FALSE; -BOOL type_regd_kvno = FALSE; - -khm_int32 attr_id_key_enctype = -1; -khm_int32 attr_id_tkt_enctype = -1; -khm_int32 attr_id_addr_list = -1; -khm_int32 attr_id_krb5_flags = -1; -khm_int32 attr_id_krb5_ccname = -1; -khm_int32 attr_id_kvno = -1; -khm_int32 attr_id_krb5_idflags = -1; - -BOOL attr_regd_key_enctype = FALSE; -BOOL attr_regd_tkt_enctype = FALSE; -BOOL attr_regd_addr_list = FALSE; -BOOL attr_regd_krb5_flags = FALSE; -BOOL attr_regd_krb5_ccname = FALSE; -BOOL attr_regd_kvno = FALSE; -BOOL attr_regd_krb5_idflags = FALSE; - -khm_handle csp_plugins = NULL; -khm_handle csp_krbcred = NULL; -khm_handle csp_params = NULL; - -BOOL is_k5_identpro = TRUE; - -khm_ui_4 k5_commctl_version; - -kmm_module_locale locales[] = { - LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), L"krb5cred_en_us.dll", KMM_MLOC_FLAG_DEFAULT) -}; -int n_locales = ARRAYLENGTH(locales); - -/* These two should not do anything */ -void init_krb() { -} - -void exit_krb() { -} - -/* called by the NetIDMgr module manager */ -KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { - khm_int32 rv = KHM_ERROR_SUCCESS; - kmm_plugin_reg pi; - wchar_t buf[256]; - - h_khModule = h_module; - - rv = kmm_set_locale_info(h_module, locales, n_locales); - if(KHM_SUCCEEDED(rv)) { - hResModule = kmm_get_resource_hmodule(h_module); - } else - goto _exit; - - k5_commctl_version = khm_get_commctl_version(NULL); - - /* register the plugin */ - ZeroMemory(&pi, sizeof(pi)); - pi.name = KRB5_PLUGIN_NAME; - pi.type = KHM_PITYPE_CRED; - 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); - - ZeroMemory(&pi, sizeof(pi)); - pi.name = KRB5_IDENTPRO_NAME; - pi.type = KHM_PITYPE_IDENT; - 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; - pi.dependencies = KRB5_PLUGIN_NAME L"\0"; - LoadString(hResModule, IDS_IDENTPRO_DESC, - buf, ARRAYLENGTH(buf)); - kmm_provide_plugin(h_module, &pi); - - if(KHM_FAILED(rv = init_imports())) - goto _exit; - - if(KHM_FAILED(rv = init_error_funcs())) - goto _exit; - - /* Register common data types */ - if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ENCTYPE, &type_id_enctype))) { - kcdb_type type; - kcdb_type *t32; - - kcdb_type_get_info(KCDB_TYPE_INT32, &t32); - - type.id = KCDB_TYPE_INVALID; - type.name = TYPENAME_ENCTYPE; - type.flags = KCDB_TYPE_FLAG_CB_FIXED; - type.cb_max = t32->cb_max; - type.cb_min = t32->cb_min; - type.isValid = t32->isValid; - type.comp = t32->comp; - type.dup = t32->dup; - type.toString = enctype_toString; - - rv = kcdb_type_register(&type, &type_id_enctype); - kcdb_type_release_info(t32); - - if(KHM_FAILED(rv)) - goto _exit; - type_regd_enctype = TRUE; - } - - if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ADDR_LIST, &type_id_addr_list))) { - kcdb_type type; - kcdb_type *tdata; - - kcdb_type_get_info(KCDB_TYPE_DATA, &tdata); - - type.id = KCDB_TYPE_INVALID; - type.name = TYPENAME_ADDR_LIST; - type.flags = KCDB_TYPE_FLAG_CB_MIN; - type.cb_min = 0; - type.cb_max = 0; - type.isValid = tdata->isValid; - type.comp = addr_list_comp; - type.dup = tdata->dup; - type.toString = addr_list_toString; - - rv = kcdb_type_register(&type, &type_id_addr_list); - kcdb_type_release_info(tdata); - - if(KHM_FAILED(rv)) - goto _exit; - type_regd_addr_list = TRUE; - } - - if(KHM_FAILED(kcdb_type_get_id(TYPENAME_KRB5_FLAGS, &type_id_krb5_flags))) { - kcdb_type type; - kcdb_type *t32; - - kcdb_type_get_info(KCDB_TYPE_INT32, &t32); - - type.id = KCDB_TYPE_INVALID; - type.name = TYPENAME_KRB5_FLAGS; - type.flags = KCDB_TYPE_FLAG_CB_FIXED; - type.cb_max = t32->cb_max; - type.cb_min = t32->cb_min; - type.isValid = t32->isValid; - type.comp = t32->comp; - type.dup = t32->dup; - type.toString = krb5flags_toString; - - rv = kcdb_type_register(&type, &type_id_krb5_flags); - kcdb_type_release_info(t32); - - if(KHM_FAILED(rv)) - goto _exit; - type_regd_krb5_flags = TRUE; - } - - if (KHM_FAILED(kcdb_type_get_id(TYPENAME_KVNO, &type_id_kvno))) { - kcdb_type type; - kcdb_type *t32; - - kcdb_type_get_info(KCDB_TYPE_INT32, &t32); - - type.id = KCDB_TYPE_INVALID; - type.name = TYPENAME_KVNO; - type.flags = KCDB_TYPE_FLAG_CB_FIXED; - type.cb_max = t32->cb_max; - type.cb_min = t32->cb_min; - type.isValid = t32->isValid; - type.comp = t32->comp; - type.dup = t32->dup; - type.toString = kvno_toString; - - rv = kcdb_type_register(&type, &type_id_kvno); - kcdb_type_release_info(t32); - - if (KHM_FAILED(rv)) - goto _exit; - - type_regd_kvno = TRUE; - } - - /* Register common attributes */ - if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KEY_ENCTYPE, &attr_id_key_enctype))) { - kcdb_attrib attrib; - wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; - wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; - /* although we are loading a long descriptoin, it still fits - in the short descriptoin buffer */ - - ZeroMemory(&attrib, sizeof(attrib)); - - attrib.name = ATTRNAME_KEY_ENCTYPE; - attrib.id = KCDB_ATTR_INVALID; - attrib.type = type_id_enctype; - attrib.flags = 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; - attrib.long_desc = lbuf; - - rv = kcdb_attrib_register(&attrib, &attr_id_key_enctype); - - if(KHM_FAILED(rv)) - goto _exit; - - attr_regd_key_enctype = TRUE; - } - - if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_TKT_ENCTYPE, &attr_id_tkt_enctype))) { - kcdb_attrib attrib; - wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; - wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; - /* although we are loading a long descriptoin, it still fits - in the short descriptoin buffer */ - - ZeroMemory(&attrib, sizeof(attrib)); - - attrib.name = ATTRNAME_TKT_ENCTYPE; - attrib.id = KCDB_ATTR_INVALID; - attrib.type = type_id_enctype; - attrib.flags = 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; - attrib.long_desc = lbuf; - - rv = kcdb_attrib_register(&attrib, &attr_id_tkt_enctype); - - if(KHM_FAILED(rv)) - goto _exit; - - attr_regd_tkt_enctype = TRUE; - } - - if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_ADDR_LIST, &attr_id_addr_list))) { - kcdb_attrib attrib; - wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; - wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; - /* although we are loading a long descriptoin, it still fits - in the short descriptoin buffer */ - - ZeroMemory(&attrib, sizeof(attrib)); - - attrib.name = ATTRNAME_ADDR_LIST; - attrib.id = KCDB_ATTR_INVALID; - attrib.type = type_id_addr_list; - attrib.flags = 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; - attrib.long_desc = lbuf; - - rv = kcdb_attrib_register(&attrib, &attr_id_addr_list); - - if(KHM_FAILED(rv)) - goto _exit; - - attr_regd_addr_list = TRUE; - } - - if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_FLAGS, &attr_id_krb5_flags))) { - kcdb_attrib attrib; - wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; - - /* although we are loading a long descriptoin, it still fits - in the short descriptoin buffer */ - - ZeroMemory(&attrib, sizeof(attrib)); - - attrib.name = ATTRNAME_KRB5_FLAGS; - attrib.id = KCDB_ATTR_INVALID; - attrib.type = type_id_krb5_flags; - attrib.flags = KCDB_ATTR_FLAG_TRANSIENT; - LoadString(hResModule, IDS_KRB5_FLAGS_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = NULL; - - rv = kcdb_attrib_register(&attrib, &attr_id_krb5_flags); - - if(KHM_FAILED(rv)) - goto _exit; - - attr_regd_krb5_flags = TRUE; - } - - if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_CCNAME, &attr_id_krb5_ccname))) { - kcdb_attrib attrib; - wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; - wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; - /* although we are loading a long descriptoin, it still fits - in the short descriptoin buffer */ - - ZeroMemory(&attrib, sizeof(attrib)); - - attrib.name = ATTRNAME_KRB5_CCNAME; - attrib.id = KCDB_ATTR_INVALID; - attrib.type = KCDB_TYPE_STRING; - attrib.flags = - KCDB_ATTR_FLAG_PROPERTY | - 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; - attrib.long_desc = lbuf; - - rv = kcdb_attrib_register(&attrib, &attr_id_krb5_ccname); - - if(KHM_FAILED(rv)) - goto _exit; - - attr_regd_krb5_ccname = TRUE; - } - - if (KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KVNO, &attr_id_kvno))) { - kcdb_attrib attrib; - wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; - wchar_t lbuf[KCDB_MAXCCH_LONG_DESC]; - /* although we are loading a long description, it still fits - in the short description buffer */ - - ZeroMemory(&attrib, sizeof(attrib)); - - attrib.name = ATTRNAME_KVNO; - attrib.id = KCDB_ATTR_INVALID; - attrib.type = type_id_kvno; - attrib.flags = KCDB_ATTR_FLAG_TRANSIENT; - LoadString(hResModule, IDS_KVNO_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); - LoadString(hResModule, IDS_KVNO_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); - attrib.short_desc = sbuf; - attrib.long_desc = lbuf; - - rv = kcdb_attrib_register(&attrib, &attr_id_kvno); - - if (KHM_FAILED(rv)) - goto _exit; - - attr_regd_kvno = TRUE; - } - - if (KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_IDFLAGS, &attr_id_krb5_idflags))) { - kcdb_attrib attrib; - - ZeroMemory(&attrib, sizeof(attrib)); - - attrib.name = ATTRNAME_KRB5_IDFLAGS; - attrib.id = KCDB_ATTR_INVALID; - attrib.type = KCDB_TYPE_INT32; - attrib.flags = KCDB_ATTR_FLAG_PROPERTY | - KCDB_ATTR_FLAG_HIDDEN; - /* we don't bother localizing these strings since the - attribute is hidden. The user will not see these - descriptions anyway. */ - attrib.short_desc = L"Krb5 ID flags"; - attrib.long_desc = L"Kerberos 5 Identity Flags"; - - rv = kcdb_attrib_register(&attrib, &attr_id_krb5_idflags); - - if (KHM_FAILED(rv)) - goto _exit; - - attr_regd_krb5_idflags = TRUE; - } - - rv = kmm_get_plugins_config(0, &csp_plugins); - if(KHM_FAILED(rv)) goto _exit; - - rv = khc_load_schema(csp_plugins, schema_krbconfig); - if(KHM_FAILED(rv)) goto _exit; - - rv = khc_open_space(csp_plugins, CSNAME_KRB5CRED, 0, &csp_krbcred); - if(KHM_FAILED(rv)) goto _exit; - - rv = khc_open_space(csp_krbcred, CSNAME_PARAMS, 0, &csp_params); - if(KHM_FAILED(rv)) goto _exit; - -_exit: - return rv; -} - -/* called by the NetIDMgr module manager */ -KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module) { - exit_imports(); - exit_error_funcs(); - - if(attr_regd_key_enctype) - kcdb_attrib_unregister(attr_id_key_enctype); - if(attr_regd_tkt_enctype) - kcdb_attrib_unregister(attr_id_tkt_enctype); - if(attr_regd_addr_list) - kcdb_attrib_unregister(attr_id_addr_list); - if(attr_regd_krb5_flags) - kcdb_attrib_unregister(attr_id_krb5_flags); - if(attr_regd_krb5_ccname) - kcdb_attrib_unregister(attr_id_krb5_ccname); - if(attr_regd_kvno) - kcdb_attrib_unregister(attr_id_kvno); - if(attr_regd_krb5_idflags) - kcdb_attrib_unregister(attr_id_krb5_idflags); - - if(type_regd_enctype) - kcdb_type_unregister(type_id_enctype); - if(type_regd_addr_list) - kcdb_type_unregister(type_id_addr_list); - if(type_regd_krb5_flags) - kcdb_type_unregister(type_id_krb5_flags); - if(type_regd_kvno) - kcdb_type_unregister(type_id_kvno); - - if(csp_params) { - khc_close_space(csp_params); - csp_params = NULL; - } - - if(csp_krbcred) { - khc_close_space(csp_krbcred); - csp_krbcred = NULL; - } - - if(csp_plugins) { - khc_unload_schema(csp_plugins, schema_krbconfig); - khc_close_space(csp_plugins); - csp_plugins = NULL; - } - - return KHM_ERROR_SUCCESS; /* the return code is ignored */ -} - -BOOL WINAPI DllMain( - HINSTANCE hinstDLL, - DWORD fdwReason, - LPVOID lpvReserved -) -{ - switch(fdwReason) { - case DLL_PROCESS_ATTACH: - hInstance = hinstDLL; - init_krb(); - break; - case DLL_PROCESS_DETACH: - exit_krb(); - break; - case DLL_THREAD_ATTACH: - break; - case DLL_THREAD_DETACH: - break; - } - - return TRUE; -} +/* + * 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 + +kmm_module h_khModule; /* KMM's handle to this module */ +HINSTANCE hInstance; +HMODULE hResModule; /* HMODULE to the resource library */ +const wchar_t * k5_facility = L"Krb5Cred"; + +khm_int32 type_id_enctype = -1; +khm_int32 type_id_addr_list = -1; +khm_int32 type_id_krb5_flags = -1; +khm_int32 type_id_krb5_princ = -1; +khm_int32 type_id_kvno = -1; + +BOOL type_regd_enctype = FALSE; +BOOL type_regd_addr_list = FALSE; +BOOL type_regd_krb5_flags = FALSE; +BOOL type_regd_krb5_princ = FALSE; +BOOL type_regd_kvno = FALSE; + +khm_int32 attr_id_key_enctype = -1; +khm_int32 attr_id_tkt_enctype = -1; +khm_int32 attr_id_addr_list = -1; +khm_int32 attr_id_krb5_flags = -1; +khm_int32 attr_id_krb5_ccname = -1; +khm_int32 attr_id_kvno = -1; +khm_int32 attr_id_krb5_idflags = -1; + +BOOL attr_regd_key_enctype = FALSE; +BOOL attr_regd_tkt_enctype = FALSE; +BOOL attr_regd_addr_list = FALSE; +BOOL attr_regd_krb5_flags = FALSE; +BOOL attr_regd_krb5_ccname = FALSE; +BOOL attr_regd_kvno = FALSE; +BOOL attr_regd_krb5_idflags = FALSE; + +khm_handle csp_plugins = NULL; +khm_handle csp_krbcred = NULL; +khm_handle csp_params = NULL; + +BOOL is_k5_identpro = TRUE; + +khm_ui_4 k5_commctl_version; + +kmm_module_locale locales[] = { + LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), L"krb5cred_en_us.dll", KMM_MLOC_FLAG_DEFAULT) +}; +int n_locales = ARRAYLENGTH(locales); + +/* These two should not do anything */ +void init_krb() { +} + +void exit_krb() { +} + +/* called by the NetIDMgr module manager */ +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { + khm_int32 rv = KHM_ERROR_SUCCESS; + kmm_plugin_reg pi; + wchar_t buf[256]; + + h_khModule = h_module; + + rv = kmm_set_locale_info(h_module, locales, n_locales); + if(KHM_SUCCEEDED(rv)) { + hResModule = kmm_get_resource_hmodule(h_module); + } else + goto _exit; + + k5_commctl_version = khm_get_commctl_version(NULL); + + /* register the plugin */ + ZeroMemory(&pi, sizeof(pi)); + pi.name = KRB5_PLUGIN_NAME; + pi.type = KHM_PITYPE_CRED; + 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); + + ZeroMemory(&pi, sizeof(pi)); + pi.name = KRB5_IDENTPRO_NAME; + pi.type = KHM_PITYPE_IDENT; + 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; + pi.dependencies = KRB5_PLUGIN_NAME L"\0"; + LoadString(hResModule, IDS_IDENTPRO_DESC, + buf, ARRAYLENGTH(buf)); + kmm_provide_plugin(h_module, &pi); + + if(KHM_FAILED(rv = init_imports())) + goto _exit; + + if(KHM_FAILED(rv = init_error_funcs())) + goto _exit; + + /* Register common data types */ + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ENCTYPE, &type_id_enctype))) { + kcdb_type type; + kcdb_type *t32; + + kcdb_type_get_info(KCDB_TYPE_INT32, &t32); + + type.id = KCDB_TYPE_INVALID; + type.name = TYPENAME_ENCTYPE; + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + type.cb_max = t32->cb_max; + type.cb_min = t32->cb_min; + type.isValid = t32->isValid; + type.comp = t32->comp; + type.dup = t32->dup; + type.toString = enctype_toString; + + rv = kcdb_type_register(&type, &type_id_enctype); + kcdb_type_release_info(t32); + + if(KHM_FAILED(rv)) + goto _exit; + type_regd_enctype = TRUE; + } + + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ADDR_LIST, &type_id_addr_list))) { + kcdb_type type; + kcdb_type *tdata; + + kcdb_type_get_info(KCDB_TYPE_DATA, &tdata); + + type.id = KCDB_TYPE_INVALID; + type.name = TYPENAME_ADDR_LIST; + type.flags = KCDB_TYPE_FLAG_CB_MIN; + type.cb_min = 0; + type.cb_max = 0; + type.isValid = tdata->isValid; + type.comp = addr_list_comp; + type.dup = tdata->dup; + type.toString = addr_list_toString; + + rv = kcdb_type_register(&type, &type_id_addr_list); + kcdb_type_release_info(tdata); + + if(KHM_FAILED(rv)) + goto _exit; + type_regd_addr_list = TRUE; + } + + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_KRB5_FLAGS, &type_id_krb5_flags))) { + kcdb_type type; + kcdb_type *t32; + + kcdb_type_get_info(KCDB_TYPE_INT32, &t32); + + type.id = KCDB_TYPE_INVALID; + type.name = TYPENAME_KRB5_FLAGS; + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + type.cb_max = t32->cb_max; + type.cb_min = t32->cb_min; + type.isValid = t32->isValid; + type.comp = t32->comp; + type.dup = t32->dup; + type.toString = krb5flags_toString; + + rv = kcdb_type_register(&type, &type_id_krb5_flags); + kcdb_type_release_info(t32); + + if(KHM_FAILED(rv)) + goto _exit; + type_regd_krb5_flags = TRUE; + } + + if (KHM_FAILED(kcdb_type_get_id(TYPENAME_KVNO, &type_id_kvno))) { + kcdb_type type; + kcdb_type *t32; + + kcdb_type_get_info(KCDB_TYPE_INT32, &t32); + + type.id = KCDB_TYPE_INVALID; + type.name = TYPENAME_KVNO; + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + type.cb_max = t32->cb_max; + type.cb_min = t32->cb_min; + type.isValid = t32->isValid; + type.comp = t32->comp; + type.dup = t32->dup; + type.toString = kvno_toString; + + rv = kcdb_type_register(&type, &type_id_kvno); + kcdb_type_release_info(t32); + + if (KHM_FAILED(rv)) + goto _exit; + + type_regd_kvno = TRUE; + } + + /* Register common attributes */ + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KEY_ENCTYPE, &attr_id_key_enctype))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_KEY_ENCTYPE; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_enctype; + attrib.flags = 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; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_key_enctype); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_key_enctype = TRUE; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_TKT_ENCTYPE, &attr_id_tkt_enctype))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_TKT_ENCTYPE; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_enctype; + attrib.flags = 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; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_tkt_enctype); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_tkt_enctype = TRUE; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_ADDR_LIST, &attr_id_addr_list))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_ADDR_LIST; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_addr_list; + attrib.flags = 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; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_addr_list); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_addr_list = TRUE; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_FLAGS, &attr_id_krb5_flags))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_KRB5_FLAGS; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_krb5_flags; + attrib.flags = KCDB_ATTR_FLAG_TRANSIENT; + LoadString(hResModule, IDS_KRB5_FLAGS_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + + rv = kcdb_attrib_register(&attrib, &attr_id_krb5_flags); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_krb5_flags = TRUE; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_CCNAME, &attr_id_krb5_ccname))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_KRB5_CCNAME; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = KCDB_TYPE_STRING; + attrib.flags = + KCDB_ATTR_FLAG_PROPERTY | + 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; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_krb5_ccname); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_krb5_ccname = TRUE; + } + + if (KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KVNO, &attr_id_kvno))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_LONG_DESC]; + /* although we are loading a long description, it still fits + in the short description buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_KVNO; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_kvno; + attrib.flags = KCDB_ATTR_FLAG_TRANSIENT; + LoadString(hResModule, IDS_KVNO_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + LoadString(hResModule, IDS_KVNO_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_kvno); + + if (KHM_FAILED(rv)) + goto _exit; + + attr_regd_kvno = TRUE; + } + + if (KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_IDFLAGS, &attr_id_krb5_idflags))) { + kcdb_attrib attrib; + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_KRB5_IDFLAGS; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = KCDB_TYPE_INT32; + attrib.flags = KCDB_ATTR_FLAG_PROPERTY | + KCDB_ATTR_FLAG_HIDDEN; + /* we don't bother localizing these strings since the + attribute is hidden. The user will not see these + descriptions anyway. */ + attrib.short_desc = L"Krb5 ID flags"; + attrib.long_desc = L"Kerberos 5 Identity Flags"; + + rv = kcdb_attrib_register(&attrib, &attr_id_krb5_idflags); + + if (KHM_FAILED(rv)) + goto _exit; + + attr_regd_krb5_idflags = TRUE; + } + + rv = kmm_get_plugins_config(0, &csp_plugins); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_load_schema(csp_plugins, schema_krbconfig); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_open_space(csp_plugins, CSNAME_KRB5CRED, 0, &csp_krbcred); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_open_space(csp_krbcred, CSNAME_PARAMS, 0, &csp_params); + if(KHM_FAILED(rv)) goto _exit; + +_exit: + return rv; +} + +/* called by the NetIDMgr module manager */ +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module) { + exit_imports(); + exit_error_funcs(); + + if(attr_regd_key_enctype) + kcdb_attrib_unregister(attr_id_key_enctype); + if(attr_regd_tkt_enctype) + kcdb_attrib_unregister(attr_id_tkt_enctype); + if(attr_regd_addr_list) + kcdb_attrib_unregister(attr_id_addr_list); + if(attr_regd_krb5_flags) + kcdb_attrib_unregister(attr_id_krb5_flags); + if(attr_regd_krb5_ccname) + kcdb_attrib_unregister(attr_id_krb5_ccname); + if(attr_regd_kvno) + kcdb_attrib_unregister(attr_id_kvno); + if(attr_regd_krb5_idflags) + kcdb_attrib_unregister(attr_id_krb5_idflags); + + if(type_regd_enctype) + kcdb_type_unregister(type_id_enctype); + if(type_regd_addr_list) + kcdb_type_unregister(type_id_addr_list); + if(type_regd_krb5_flags) + kcdb_type_unregister(type_id_krb5_flags); + if(type_regd_kvno) + kcdb_type_unregister(type_id_kvno); + + if(csp_params) { + khc_close_space(csp_params); + csp_params = NULL; + } + + if(csp_krbcred) { + khc_close_space(csp_krbcred); + csp_krbcred = NULL; + } + + if(csp_plugins) { + khc_unload_schema(csp_plugins, schema_krbconfig); + khc_close_space(csp_plugins); + csp_plugins = NULL; + } + + return KHM_ERROR_SUCCESS; /* the return code is ignored */ +} + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved +) +{ + switch(fdwReason) { + case DLL_PROCESS_ATTACH: + hInstance = hinstDLL; + init_krb(); + break; + case DLL_PROCESS_DETACH: + exit_krb(); + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + } + + return TRUE; +} diff --git a/src/windows/identity/plugins/krb5/krb5newcreds.c b/src/windows/identity/plugins/krb5/krb5newcreds.c index edd64725d..d2458fe50 100644 --- a/src/windows/identity/plugins/krb5/krb5newcreds.c +++ b/src/windows/identity/plugins/krb5/krb5newcreds.c @@ -1,2747 +1,2747 @@ -/* - * Copyright (c) 2006 Secure Endpoints Inc. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* $Id$ */ - -#include -#include -#include -#include -#include - -#include - -#include - -extern LPVOID k5_main_fiber; -extern LPVOID k5_kinit_fiber; - -typedef struct k5_dlg_data_t { - khui_new_creds * nc; - - khui_tracker tc_lifetime; - khui_tracker tc_renew; - - BOOL dirty; /* 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; - DWORD addressless; - DWORD publicIP; - - wchar_t * cred_message; /* overrides the credential text, if - non-NULL */ - BOOL pwd_change; /* force a password change */ -} k5_dlg_data; - - -INT_PTR -k5_handle_wm_initdialog(HWND hwnd, - WPARAM wParam, - LPARAM lParam) -{ - HWND hw; - k5_dlg_data * d; - khui_new_creds_by_type * nct; - - d = PMALLOC(sizeof(*d)); - ZeroMemory(d, sizeof(*d)); - /* lParam is a pointer to a khui_new_creds structure */ - d->nc = (khui_new_creds *) lParam; - khui_cw_find_type(d->nc, credtype_id_krb5, &nct); - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM) d); -#pragma warning(pop) - - nct->aux = (LPARAM) d; - - if (d->nc->subtype == KMSG_CRED_NEW_CREDS) { - khui_tracker_initialize(&d->tc_lifetime); - khui_tracker_initialize(&d->tc_renew); - - hw = GetDlgItem(hwnd, IDC_NCK5_LIFETIME_EDIT); - khui_tracker_install(hw, &d->tc_lifetime); - - hw = GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT); - khui_tracker_install(hw, &d->tc_renew); - } - return TRUE; -} - -INT_PTR -k5_handle_wm_destroy(HWND hwnd, - WPARAM wParam, - LPARAM lParam) -{ - k5_dlg_data * d; - khui_new_creds_by_type * nct = NULL; - - d = (k5_dlg_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (!d) - return TRUE; - - khui_cw_find_type(d->nc, credtype_id_krb5, &nct); - -#ifdef DEBUG - assert(nct); -#endif - - nct->aux = 0; - - if (d->nc->subtype == KMSG_CRED_NEW_CREDS) { - khui_tracker_kill_controls(&d->tc_renew); - khui_tracker_kill_controls(&d->tc_lifetime); - } - - PFREE(d); - - return TRUE; -} - -LRESULT -k5_force_password_change(k5_dlg_data * d) { - /* we are turning this dialog into a change password dialog... */ - wchar_t wbuf[KHUI_MAXCCH_BANNER]; - - khui_cw_clear_prompts(d->nc); - - LoadString(hResModule, IDS_NC_PWD_BANNER, - wbuf, ARRAYLENGTH(wbuf)); - khui_cw_begin_custom_prompts(d->nc, 3, NULL, wbuf); - - LoadString(hResModule, IDS_NC_PWD_PWD, - wbuf, ARRAYLENGTH(wbuf)); - khui_cw_add_prompt(d->nc, KHUI_NCPROMPT_TYPE_PASSWORD, - wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); - - LoadString(hResModule, IDS_NC_PWD_NPWD, - wbuf, ARRAYLENGTH(wbuf)); - khui_cw_add_prompt(d->nc, KHUI_NCPROMPT_TYPE_NEW_PASSWORD, - wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); - - LoadString(hResModule, IDS_NC_PWD_NPWD_AGAIN, - wbuf, ARRAYLENGTH(wbuf)); - khui_cw_add_prompt(d->nc, KHUI_NCPROMPT_TYPE_NEW_PASSWORD_AGAIN, - wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); - - d->pwd_change = TRUE; - - if (is_k5_identpro && - d->nc->n_identities > 0 && - d->nc->identities[0]) { - - kcdb_identity_set_flags(d->nc->identities[0], - KCDB_IDENT_FLAG_VALID, - KCDB_IDENT_FLAG_VALID); - - } - - PostMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, - MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), - (LPARAM) d->nc); - - return TRUE; -} - -INT_PTR -k5_handle_wmnc_notify(HWND hwnd, - WPARAM wParam, - LPARAM lParam) -{ - switch(HIWORD(wParam)) { - case WMNC_DIALOG_MOVE: - { - k5_dlg_data * d; - - d = (k5_dlg_data *)(LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (d->nc->subtype == KMSG_CRED_NEW_CREDS) { - khui_tracker_reposition(&d->tc_lifetime); - khui_tracker_reposition(&d->tc_renew); - } - - return TRUE; - } - break; - - case WMNC_DIALOG_SETUP: - { - k5_dlg_data * d; - BOOL old_sync; - - d = (k5_dlg_data *)(LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (d->nc->subtype == KMSG_CRED_PASSWORD) - return TRUE; - - /* we save the value of the 'sync' field here because some - of the notifications that are generated while setting - the controls overwrite the field. */ - old_sync = d->sync; - - /* need to update the controls with d->* */ - 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); - - 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); - - d->sync = old_sync; - } - break; - - case WMNC_CREDTEXT_LINK: - { - k5_dlg_data * d; - khui_htwnd_link * l; - khui_new_creds * nc; - wchar_t linktext[128]; - - d = (k5_dlg_data *)(LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - nc = d->nc; - l = (khui_htwnd_link *) lParam; - - if (!l) - break; - - StringCchCopyN(linktext, ARRAYLENGTH(linktext), - l->id, l->id_len); - - if (!wcscmp(linktext, L"Krb5Cred:!Passwd")) { - return k5_force_password_change(d); - } - } - break; - - case WMNC_UPDATE_CREDTEXT: - { - k5_dlg_data * d; - khui_new_creds * nc; - khui_new_creds_by_type * nct; - wchar_t sbuf[1024]; - wchar_t fbuf[256]; - wchar_t tbuf[256]; - size_t cbsize; - khm_int32 flags; - - d = (k5_dlg_data *)(LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - nc = d->nc; - khui_cw_find_type(nc, credtype_id_krb5, &nct); - - if(nct == NULL) - break; - - if(nct->credtext) - PFREE(nct->credtext); - nct->credtext = NULL; - - tbuf[0] = L'\0'; - - if (nc->n_identities > 0 && - KHM_SUCCEEDED(kcdb_identity_get_flags(nc->identities[0], - &flags)) && - (flags & KCDB_IDENT_FLAG_VALID) && - nc->subtype == KMSG_CRED_NEW_CREDS && - !d->pwd_change) { - - if (is_k5_identpro) - k5_get_realm_from_nc(nc, tbuf, ARRAYLENGTH(tbuf)); - else - GetDlgItemText(hwnd, IDC_NCK5_REALM, tbuf, - ARRAYLENGTH(tbuf)); - - /*TODO: if additional realms were specified, then those - must be listed as well */ - LoadString(hResModule, IDS_KRB5_CREDTEXT_0, - fbuf, ARRAYLENGTH(fbuf)); - StringCbPrintf(sbuf, sizeof(sbuf), fbuf, - tbuf); - - StringCbLength(sbuf, sizeof(sbuf), &cbsize); - cbsize += sizeof(wchar_t); - - nct->credtext = PMALLOC(cbsize); - - StringCbCopy(nct->credtext, cbsize, sbuf); - } else if (nc->n_identities > 0 && - (nc->subtype == KMSG_CRED_PASSWORD || - (nc->subtype == KMSG_CRED_NEW_CREDS && d->pwd_change))) { - cbsize = sizeof(tbuf); - kcdb_identity_get_name(nc->identities[0], tbuf, &cbsize); - - LoadString(hResModule, IDS_KRB5_CREDTEXT_P0, - fbuf, ARRAYLENGTH(fbuf)); - StringCbPrintf(sbuf, sizeof(sbuf), fbuf, tbuf); - - StringCbLength(sbuf, sizeof(sbuf), &cbsize); - cbsize += sizeof(wchar_t); - - nct->credtext = PMALLOC(cbsize); - - StringCbCopy(nct->credtext, cbsize, sbuf); - } else { - if (d->cred_message) { - StringCbLength(d->cred_message, KHUI_MAXCB_BANNER, - &cbsize); - cbsize += sizeof(wchar_t); - - nct->credtext = PMALLOC(cbsize); - - StringCbCopy(nct->credtext, cbsize, d->cred_message); - } - } - } - break; - - case WMNC_IDENTITY_CHANGE: - { - /* There has been a change of identity */ - k5_dlg_data * d; - - d = (k5_dlg_data *)(LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - kmq_post_sub_msg(k5_sub, KMSG_CRED, - KMSG_CRED_DIALOG_NEW_IDENTITY, - 0, (void *) d->nc); - } - break; - - case WMNC_DIALOG_PREPROCESS: - { - k5_dlg_data * d; - - d = (k5_dlg_data *)(LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if(!d->sync && d->nc->result == KHUI_NC_RESULT_PROCESS) { - kmq_post_sub_msg(k5_sub, KMSG_CRED, - KMSG_CRED_DIALOG_NEW_OPTIONS, - 0, (void *) d->nc); - } - } - 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; - } - - 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, - LPARAM lParam) -{ - int cid; - int notif; - k5_dlg_data * d; - - d = (k5_dlg_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); - - cid = LOWORD(wParam); - notif = HIWORD(wParam); - - if(notif == BN_CLICKED && cid == IDC_NCK5_RENEWABLE) { - int c; - c = (int) SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, - BM_GETCHECK, 0, 0); - if(c==BST_CHECKED) { - EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), TRUE); - d->renewable = TRUE; - } else { - EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), FALSE); - d->renewable = FALSE; - } - d->dirty = TRUE; - d->sync = FALSE; - } else if(notif == BN_CLICKED && cid == IDC_NCK5_FORWARDABLE) { - int c; - c = (int) SendDlgItemMessage(hwnd, IDC_NCK5_FORWARDABLE, - BM_GETCHECK, 0, 0); - if(c==BST_CHECKED) { - d->forwardable = TRUE; - } else { - 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 && - !is_k5_identpro) { - /* find out what the realm of the current identity - is, and if they are the same, then we don't do - anything */ - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - wchar_t realm[KCDB_IDENT_MAXCCH_NAME]; - wchar_t *r; - khm_size cbsize; - khm_handle ident; - int idx; - - if(d->nc->n_identities > 0) { - if(notif == CBN_SELCHANGE) { - idx = (int) SendDlgItemMessage(hwnd, IDC_NCK5_REALM, - CB_GETCURSEL, 0, 0); - SendDlgItemMessage(hwnd, IDC_NCK5_REALM, - CB_GETLBTEXT, idx, (LPARAM) realm); - } else { - GetDlgItemText(hwnd, IDC_NCK5_REALM, - realm, ARRAYLENGTH(realm)); - } - cbsize = sizeof(idname); - if(KHM_SUCCEEDED(kcdb_identity_get_name(d->nc->identities[0], - idname, &cbsize))) { - r = wcschr(idname, L'@'); - if(r && !wcscmp(realm, r+1)) - return 0; /* nothing to do */ - - if(!r) { - r = idname + wcslen(idname); - *r++ = L'@'; - *r++ = 0; - } - - /* if we get here, we have a new user */ - StringCchCopy(r+1, - ARRAYLENGTH(idname) - ((r+1) - idname), - realm); - if(KHM_SUCCEEDED(kcdb_identity_create(idname, - KCDB_IDENT_FLAG_CREATE, - &ident))) { - khui_cw_set_primary_id(d->nc, ident); - kcdb_identity_release(ident); - } - return 0; - } - } - - /* if we get here, we have a new realm, but there is no - identity */ - PostMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, - MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0); - } - - return 0; -} - - -/* Dialog procedure for the Krb5 credentials type panel. - - NOTE: Runs in the context of the UI thread -*/ -INT_PTR CALLBACK -k5_nc_dlg_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - switch(uMsg) { - case WM_INITDIALOG: - return k5_handle_wm_initdialog(hwnd, wParam, lParam); - - case WM_COMMAND: - return k5_handle_wm_command(hwnd, wParam, lParam); - - case KHUI_WM_NC_NOTIFY: - return k5_handle_wmnc_notify(hwnd, wParam, lParam); - - case WM_NOTIFY: - return k5_handle_wm_notify(hwnd, wParam, lParam); - - case WM_DESTROY: - return k5_handle_wm_destroy(hwnd, wParam, lParam); - } - return FALSE; -} - -/* forward dcl */ -krb5_error_code KRB5_CALLCONV -k5_kinit_prompter(krb5_context context, - void *data, - const char *name, - const char *banner, - int num_prompts, - krb5_prompt prompts[]); - - - -fiber_job g_fjob; /* global fiber job object */ - -static BOOL -k5_cached_kinit_prompter(void); - -static BOOL -k5_cp_check_continue(void); - -/* - Runs in the context of the krb5 plugin's slave fiber -*/ -VOID CALLBACK -k5_kinit_fiber_proc(PVOID lpParameter) -{ - while(TRUE) - { - if(g_fjob.command == FIBER_CMD_KINIT) { - g_fjob.state = FIBER_STATE_KINIT; - - g_fjob.prompt_set = 0; - - if (k5_cached_kinit_prompter()) { - SwitchToFiber(k5_main_fiber); - - if (g_fjob.command != FIBER_CMD_CONTINUE) - goto _switch_to_main; - - if (!k5_cp_check_continue()) { - g_fjob.code = KRB5KRB_AP_ERR_BAD_INTEGRITY; - goto _switch_to_main; - } - } - -#ifdef DEBUG - /* log the state of g_fjob.* */ - _reportf(L"g_fjob state prior to calling khm_krb5_kinit() :"); - _reportf(L" g_fjob.principal = [%S]", g_fjob.principal); - _reportf(L" g_fjob.code = %d", g_fjob.code); - _reportf(L" g_fjob.state = %d", g_fjob.state); - _reportf(L" g_fjob.prompt_set= %d", g_fjob.prompt_set); - _reportf(L" g_fjob.valid_principal = %d", (int) g_fjob.valid_principal); -#endif - - /* If we don't know if we have a valid principal, we - restrict the options that are set when we call kinit. - This way we will be able to use the response from the - KDC to verify the principal. */ - - g_fjob.retry_if_valid_principal = (g_fjob.forwardable || - g_fjob.proxiable || - g_fjob.renewable); - - retry_kinit: - g_fjob.code = - khm_krb5_kinit(0, - g_fjob.principal, - g_fjob.password, - g_fjob.ccache, - g_fjob.lifetime, - g_fjob.valid_principal ? g_fjob.forwardable : 0, - g_fjob.valid_principal ? g_fjob.proxiable : 0, - (g_fjob.valid_principal && g_fjob.renewable ? g_fjob.renew_life : 0), - g_fjob.addressless, - g_fjob.publicIP, - k5_kinit_prompter, - &g_fjob); - - /* If the principal was found to be valid, and if we - restricted the options that were being passed to kinit, - then we need to retry the kinit call. This time we use - the real options. */ - if (g_fjob.state == FIBER_STATE_RETRY_KINIT) { -#ifdef DEBUG - assert(g_fjob.valid_principal); -#endif - g_fjob.state = FIBER_STATE_KINIT; - goto retry_kinit; - } - } - - _switch_to_main: - g_fjob.state = FIBER_STATE_NONE; - - SwitchToFiber(k5_main_fiber); - } -} - -/* return TRUE if we should go ahead with creds acquisition */ -static BOOL -k5_cp_check_continue(void) { - khm_size i; - khm_size n_p; - khui_new_creds_prompt * p; - size_t cch; - -#ifdef DEBUG - assert(g_fjob.nc); -#endif - - if (KHM_FAILED(khui_cw_get_prompt_count(g_fjob.nc, &n_p))) { -#ifdef DEBUG - assert(FALSE); -#endif - return TRUE; - } - - khui_cw_sync_prompt_values(g_fjob.nc); - - g_fjob.null_password = FALSE; - - /* we are just checking whether there was a password field that - was left empty, in which case we can't continue with the - credentials acquisition. */ - for (i=0; i < n_p; i++) { - if(KHM_FAILED(khui_cw_get_prompt(g_fjob.nc, - (int) i, - &p))) - continue; - if(p->type == KHUI_NCPROMPT_TYPE_PASSWORD) { - if (p->value == NULL || - FAILED(StringCchLength(p->value, KHUI_MAXCCH_PROMPT, - &cch)) || - cch == 0) { - g_fjob.null_password = TRUE; - return FALSE; - } else - break; - } - } - - return TRUE; -} - -/* returns true if we find cached prompts */ -static BOOL -k5_cached_kinit_prompter(void) { - BOOL rv = FALSE; - khm_handle ident; - khm_handle csp_idconfig = NULL; - khm_handle csp_k5config = NULL; - khm_handle csp_prcache = NULL; - khm_size cb; - khm_size n_cur_prompts; - khm_int32 n_prompts; - khm_int32 i; - khm_int64 iexpiry; - FILETIME expiry; - FILETIME current; - -#ifdef DEBUG - assert(g_fjob.nc); -#endif - - ident = g_fjob.identity; - if (!ident) - return FALSE; - - /* don't need to hold ident, since it is already held in g_fjob - and it doesn't change until we return */ - - if (KHM_FAILED(kcdb_identity_get_config(ident, 0, &csp_idconfig)) || - - KHM_FAILED(khc_open_space(csp_idconfig, CSNAME_KRB5CRED, - 0, &csp_k5config)) || - - KHM_FAILED(khc_open_space(csp_k5config, CSNAME_PROMPTCACHE, - 0, &csp_prcache)) || - - KHM_FAILED(khc_read_int32(csp_prcache, L"PromptCount", - &n_prompts)) || - n_prompts == 0) - - goto _cleanup; - - if (KHM_SUCCEEDED(khc_read_int64(csp_prcache, L"ExpiresOn", &iexpiry))) { - /* has the cache expired? */ - expiry = IntToFt(iexpiry); - GetSystemTimeAsFileTime(¤t); - - if (CompareFileTime(&expiry, ¤t) < 0) - /* already expired */ - goto _cleanup; - } else { - /* if there is no value for ExpiresOn, we assume the prompts - have already expired. */ - goto _cleanup; - } - - /* we found a prompt cache. We take this to imply that the - principal is valid. */ - g_fjob.valid_principal = TRUE; - - /* check if there are any prompts currently showing. If there are - we check if they are the same as the ones we are going to show. - In which case we just reuse the exisitng prompts */ - if (KHM_FAILED(khui_cw_get_prompt_count(g_fjob.nc, - &n_cur_prompts)) || - n_prompts != (khm_int32) n_cur_prompts) - goto _show_new_prompts; - - for(i = 0; i < n_prompts; i++) { - wchar_t wsname[8]; - wchar_t wprompt[KHUI_MAXCCH_PROMPT]; - khm_handle csp_p = NULL; - khm_int32 p_type; - khm_int32 p_flags; - khui_new_creds_prompt * p; - - if (KHM_FAILED(khui_cw_get_prompt(g_fjob.nc, i, &p))) - break; - - StringCbPrintf(wsname, sizeof(wsname), L"%d", i); - - if (KHM_FAILED(khc_open_space(csp_prcache, wsname, 0, &csp_p))) - break; - - cb = sizeof(wprompt); - if (KHM_FAILED(khc_read_string(csp_p, L"Prompt", - wprompt, &cb))) { - khc_close_space(csp_p); - break; - } - - if (KHM_FAILED(khc_read_int32(csp_p, L"Type", &p_type))) - p_type = 0; - - if (KHM_FAILED(khc_read_int32(csp_p, L"Flags", &p_flags))) - p_flags = 0; - - if ( /* if we received a prompt string, - then it should be the same as the - one that is displayed */ - (wprompt[0] && - (p->prompt == NULL || - wcscmp(wprompt, p->prompt))) || - - /* if we didn't receive one, then - there shouldn't be one displayed. - This case really shouldn't happen - in reality, but we check anyway. */ - (!wprompt[0] && - p->prompt != NULL) || - - /* the type should match */ - (p_type != p->type) || - - /* if this prompt should be hidden, - then it must also be so */ - (p_flags != p->flags) - ) { - - khc_close_space(csp_p); - break; - - } - - - khc_close_space(csp_p); - } - - if (i == n_prompts) { - rv = TRUE; - goto _cleanup; - } - - _show_new_prompts: - - khui_cw_clear_prompts(g_fjob.nc); - - { - wchar_t wbanner[KHUI_MAXCCH_BANNER]; - wchar_t wpname[KHUI_MAXCCH_PNAME]; - - cb = sizeof(wbanner); - if (KHM_FAILED(khc_read_string(csp_prcache, L"Banner", - wbanner, &cb))) - wbanner[0] = 0; - - cb = sizeof(wpname); - if (KHM_FAILED(khc_read_string(csp_prcache, L"Name", - wpname, &cb))) - wpname[0] = 0; - - khui_cw_begin_custom_prompts(g_fjob.nc, - n_prompts, - (wbanner[0]? wbanner: NULL), - (wpname[0]? wpname: NULL)); - } - - for(i = 0; i < n_prompts; i++) { - wchar_t wsname[8]; - wchar_t wprompt[KHUI_MAXCCH_PROMPT]; - khm_handle csp_p = NULL; - khm_int32 p_type; - khm_int32 p_flags; - - StringCbPrintf(wsname, sizeof(wsname), L"%d", i); - - if (KHM_FAILED(khc_open_space(csp_prcache, wsname, 0, &csp_p))) - break; - - cb = sizeof(wprompt); - if (KHM_FAILED(khc_read_string(csp_p, L"Prompt", - wprompt, &cb))) { - khc_close_space(csp_p); - break; - } - - if (KHM_FAILED(khc_read_int32(csp_p, L"Type", &p_type))) - p_type = 0; - - if (KHM_FAILED(khc_read_int32(csp_p, L"Flags", &p_flags))) - p_flags = 0; - - khui_cw_add_prompt(g_fjob.nc, p_type, wprompt, NULL, p_flags); - - khc_close_space(csp_p); - } - - if (i < n_prompts) { - khui_cw_clear_prompts(g_fjob.nc); - } else { - rv = TRUE; - } - - _cleanup: - - if (csp_prcache) - khc_close_space(csp_prcache); - - if (csp_k5config) - khc_close_space(csp_k5config); - - if (csp_idconfig) - khc_close_space(csp_idconfig); - - return rv; -} - -/* Runs in the context of the Krb5 plugin's slave fiber */ -krb5_error_code KRB5_CALLCONV -k5_kinit_prompter(krb5_context context, - void *data, - const char *name, - const char *banner, - int num_prompts, - krb5_prompt prompts[]) -{ - int i; - khui_new_creds * nc; - krb5_prompt_type * ptypes; - khm_size ncp; - krb5_error_code code = 0; - BOOL new_prompts = TRUE; - khm_handle csp_prcache = NULL; - -#ifdef DEBUG - _reportf(L"k5_kinit_prompter() received %d prompts with name=[%S] banner=[%S]", - num_prompts, - name, banner); - for (i=0; i < num_prompts; i++) { - _reportf(L"Prompt[%d]: string[%S]", i, prompts[i].prompt); - } -#endif - - /* we got prompts? Then we assume that the principal is valid */ - - if (!g_fjob.valid_principal) { - g_fjob.valid_principal = TRUE; - - /* if the flags that were used to call kinit were restricted - because we didn't know the validity of the principal, then - we need to go back and retry the call with the correct - flags. */ - if (g_fjob.retry_if_valid_principal) { - _reportf(L"Retrying kinit call due to restricted flags on first call."); - g_fjob.state = FIBER_STATE_RETRY_KINIT; - return KRB5_LIBOS_PWDINTR; - } - } - - nc = g_fjob.nc; - - if(pkrb5_get_prompt_types) - ptypes = pkrb5_get_prompt_types(context); - else - ptypes = NULL; - - /* check if we are already showing the right prompts */ - khui_cw_get_prompt_count(nc, &ncp); - - if (num_prompts != (int) ncp) - goto _show_new_prompts; - - for (i=0; i < num_prompts; i++) { - wchar_t wprompt[KHUI_MAXCCH_PROMPT]; - khui_new_creds_prompt * p; - - if(prompts[i].prompt) { - AnsiStrToUnicode(wprompt, sizeof(wprompt), - prompts[i].prompt); - } else { - wprompt[0] = 0; - } - - if (KHM_FAILED(khui_cw_get_prompt(nc, i, &p))) - break; - - if ( /* if we received a prompt string, - then it should be the same as the - one that is displayed */ - (wprompt[0] && - (p->prompt == NULL || - wcscmp(wprompt, p->prompt))) || - /* if we didn't receive one, then - there shouldn't be one displayed. - This case really shouldn't happen - in reality, but we check anyway. */ - (!wprompt[0] && - p->prompt != NULL) || - /* the type should match */ - (ptypes && - ptypes[i] != p->type) || - (!ptypes && - p->type != 0) || - /* if this prompt should be hidden, - then it must also be so */ - (prompts[i].hidden && - !(p->flags & KHUI_NCPROMPT_FLAG_HIDDEN)) || - (!prompts[i].hidden && - (p->flags & KHUI_NCPROMPT_FLAG_HIDDEN)) - ) - break; - } - - if (i < num_prompts) - goto _show_new_prompts; - - new_prompts = FALSE; - - /* ok. looks like we are already showing the same set of prompts - that we were supposed to show. Sync up the values and go - ahead. */ - khui_cw_sync_prompt_values(nc); - goto _process_prompts; - - _show_new_prompts: - /* special case. if there are no actual input controls involved, - then we have to show an alerter window and pass through */ - if (num_prompts == 0) { - wchar_t wbanner[KHUI_MAXCCH_BANNER]; - wchar_t wname[KHUI_MAXCCH_PNAME]; - wchar_t wident[KCDB_IDENT_MAXCCH_NAME]; - wchar_t wmsg[KHUI_MAXCCH_MESSAGE]; - wchar_t wfmt[KHUI_MAXCCH_BANNER]; - khm_size cb; - - if (!banner) { - code = 0; - g_fjob.null_password = FALSE; - goto _exit; - } else { - AnsiStrToUnicode(wbanner, sizeof(wbanner), banner); - } - - if (name) { - AnsiStrToUnicode(wname, sizeof(wname), name); - } else { - LoadString(hResModule, - IDS_KRB5_WARNING, - wname, - ARRAYLENGTH(wname)); - } - - cb = sizeof(wident); - if (KHM_FAILED(kcdb_identity_get_name(g_fjob.identity, wident, &cb))) - wident[0] = L'\0'; - - LoadString(hResModule, - IDS_KRB5_WARN_FMT, - wfmt, - ARRAYLENGTH(wfmt)); - - StringCbPrintf(wmsg, sizeof(wmsg), wfmt, wident, wbanner); - - khui_alert_show_simple(wname, wmsg, KHERR_WARNING); - - code = 0; - g_fjob.null_password = FALSE; - goto _exit; - } - - /* in addition to showing new prompts, we also cache the set of - prompts. */ - if(g_fjob.prompt_set == 0) { - khm_handle csp_idconfig = NULL; - khm_handle csp_idk5 = NULL; - - kcdb_identity_get_config(g_fjob.identity, - KHM_FLAG_CREATE, - &csp_idconfig); - - if (csp_idconfig != NULL) - khc_open_space(csp_idconfig, - CSNAME_KRB5CRED, - KHM_FLAG_CREATE, - &csp_idk5); - - if (csp_idk5 != NULL) - khc_open_space(csp_idk5, - CSNAME_PROMPTCACHE, - KHM_FLAG_CREATE, - &csp_prcache); - - khc_close_space(csp_idconfig); - khc_close_space(csp_idk5); - } - - { - wchar_t wbanner[KHUI_MAXCCH_BANNER]; - wchar_t wname[KHUI_MAXCCH_PNAME]; - FILETIME current; - FILETIME lifetime; - FILETIME expiry; - khm_int64 iexpiry; - khm_int32 t = 0; - - if(banner) - AnsiStrToUnicode(wbanner, sizeof(wbanner), banner); - if(name) - AnsiStrToUnicode(wname, sizeof(wname), name); - - khui_cw_clear_prompts(nc); - - khui_cw_begin_custom_prompts( - nc, - num_prompts, - (banner)?wbanner:NULL, - (name)?wname:NULL); - - if (csp_prcache) { - - if (banner) - khc_write_string(csp_prcache, - L"Banner", - wbanner); - else - khc_write_string(csp_prcache, - L"Banner", - L""); - - if (name) - khc_write_string(csp_prcache, - L"Name", - wname); - else if (csp_prcache) - khc_write_string(csp_prcache, - L"Name", - L""); - - khc_write_int32(csp_prcache, - L"PromptCount", - (khm_int32) num_prompts); - - GetSystemTimeAsFileTime(¤t); -#ifdef USE_PROMPT_CACHE_LIFETIME - khc_read_int32(csp_params, L"PromptCacheLifetime", &t); - if (t == 0) - t = 172800; /* 48 hours */ -#else - khc_read_int32(csp_params, L"MaxRenewLifetime", &t); - if (t == 0) - t = 2592000; /* 30 days */ - t += 604800; /* + 7 days */ -#endif - TimetToFileTimeInterval(t, &lifetime); - expiry = FtAdd(¤t, &lifetime); - iexpiry = FtToInt(&expiry); - - khc_write_int64(csp_prcache, L"ExpiresOn", iexpiry); - } - } - - for(i=0; i < num_prompts; i++) { - wchar_t wprompt[KHUI_MAXCCH_PROMPT]; - - if(prompts[i].prompt) { - AnsiStrToUnicode(wprompt, sizeof(wprompt), - prompts[i].prompt); - } else { - wprompt[0] = 0; - } - - khui_cw_add_prompt( - nc, - (ptypes?ptypes[i]:0), - wprompt, - NULL, - (prompts[i].hidden?KHUI_NCPROMPT_FLAG_HIDDEN:0)); - - if (csp_prcache) { - khm_handle csp_p = NULL; - wchar_t wnum[8]; /* should be enough for 10 - million prompts */ - - wnum[0] = 0; - StringCbPrintf(wnum, sizeof(wnum), L"%d", i); - - khc_open_space(csp_prcache, wnum, - KHM_FLAG_CREATE, &csp_p); - - if (csp_p) { - khc_write_string(csp_p, L"Prompt", wprompt); - khc_write_int32(csp_p, L"Type", (ptypes?ptypes[i]:0)); - khc_write_int32(csp_p, L"Flags", - (prompts[i].hidden? - KHUI_NCPROMPT_FLAG_HIDDEN:0)); - - khc_close_space(csp_p); - } - } - } - - if (csp_prcache) { - khc_close_space(csp_prcache); - csp_prcache = NULL; - } - - _process_prompts: - /* switch back to main thread if we showed new prompts */ - if (new_prompts) - SwitchToFiber(k5_main_fiber); - - /* we get here after the user selects an action that either - cancles the credentials acquisition operation or triggers the - actual acquisition of credentials. */ - if(g_fjob.command != FIBER_CMD_CONTINUE && - g_fjob.command != FIBER_CMD_KINIT) { - code = KRB5_LIBOS_PWDINTR; - goto _exit; - } - - g_fjob.null_password = FALSE; - - /* otherwise, we need to get the data back from the UI and - return 0 */ - for(i=0; idata, d->length, wbuf); - if(SUCCEEDED(StringCchLengthA(d->data, d->length, &cch))) - d->length = (unsigned int) cch; - else - d->length = 0; - } else { -#ifdef DEBUG - assert(FALSE); -#endif - d->length = 0; - } - - if (ptypes && - ptypes[i] == KRB5_PROMPT_TYPE_PASSWORD && - d->length == 0) - - g_fjob.null_password = TRUE; - } - - _exit: - - g_fjob.prompt_set++; - - /* entering a NULL password is equivalent to cancelling out */ - if (g_fjob.null_password) - return KRB5_LIBOS_PWDINTR; - else - return code; -} - - -void -k5_read_dlg_params(k5_dlg_data * d, khm_handle identity) -{ - k5_params p; - - khm_krb5_get_identity_params(identity, &p); - - d->renewable = p.renewable; - d->forwardable = p.forwardable; - d->proxiable = p.proxiable; - d->addressless = p.addressless; - d->publicIP = p.publicIP; - - d->tc_lifetime.current = p.lifetime; - d->tc_lifetime.max = p.lifetime_max; - d->tc_lifetime.min = p.lifetime_min; - - d->tc_renew.current = p.renew_life; - d->tc_renew.max = p.renew_life_max; - d->tc_renew.min = p.renew_life_min; - - /* however, if this has externally supplied defaults, we have to - use them too. */ - if (d->nc && d->nc->ctx.vparam && - d->nc->ctx.cb_vparam == sizeof(NETID_DLGINFO)) { - LPNETID_DLGINFO pdlginfo; - - pdlginfo = (LPNETID_DLGINFO) d->nc->ctx.vparam; - if (pdlginfo->size == NETID_DLGINFO_V1_SZ && - pdlginfo->in.use_defaults == 0) { - d->forwardable = pdlginfo->in.forwardable; - d->addressless = pdlginfo->in.noaddresses; - d->tc_lifetime.current = pdlginfo->in.lifetime; - d->tc_renew.current = pdlginfo->in.renew_till; - - if (pdlginfo->in.renew_till == 0) - d->renewable = FALSE; - else - d->renewable = TRUE; - - d->proxiable = pdlginfo->in.proxiable; - d->publicIP = pdlginfo->in.publicip; - } - } - - /* once we read the new data, in, it is no longer considered - dirty */ - d->dirty = FALSE; - d->sync = FALSE; -} - -void -k5_write_dlg_params(k5_dlg_data * d, khm_handle identity) -{ - - k5_params p; - - ZeroMemory(&p, sizeof(p)); - - p.source_reg = K5PARAM_FM_ALL; /* we want to write all the - settings to the registry, if - necessary. */ - - p.renewable = d->renewable; - p.forwardable = d->forwardable; - p.proxiable = d->proxiable; - p.addressless = d->addressless; - p.publicIP = d->publicIP; - - p.lifetime = (krb5_deltat) d->tc_lifetime.current; - p.lifetime_max = (krb5_deltat) d->tc_lifetime.max; - p.lifetime_min = (krb5_deltat) d->tc_lifetime.min; - - p.renew_life = (krb5_deltat) d->tc_renew.current; - p.renew_life_max = (krb5_deltat) d->tc_renew.max; - p.renew_life_min = (krb5_deltat) d->tc_renew.min; - - khm_krb5_set_identity_params(identity, &p); - - /* as in k5_read_dlg_params, once we write the data in, the local - data is no longer dirty */ - d->dirty = FALSE; -} - -void -k5_free_kinit_job(void) -{ - if (g_fjob.principal) - PFREE(g_fjob.principal); - - if (g_fjob.password) - PFREE(g_fjob.password); - - if (g_fjob.identity) - kcdb_identity_release(g_fjob.identity); - - if (g_fjob.ccache) - PFREE(g_fjob.ccache); - - ZeroMemory(&g_fjob, sizeof(g_fjob)); -} - -void -k5_prep_kinit_job(khui_new_creds * nc) -{ - khui_new_creds_by_type * nct; - k5_dlg_data * d; - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - khm_size cbbuf; - size_t size; - khm_handle ident; - LPNETID_DLGINFO pdlginfo; - - khui_cw_find_type(nc, credtype_id_krb5, &nct); - if (!nct) - return; - - d = (k5_dlg_data *)(LONG_PTR) - GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); - - if (!d) - return; - - khui_cw_lock_nc(nc); - ident = nc->identities[0]; - kcdb_identity_hold(ident); - khui_cw_unlock_nc(nc); - - cbbuf = sizeof(idname); - kcdb_identity_get_name(ident, idname, &cbbuf); - StringCchLength(idname, ARRAYLENGTH(idname), &size); - size++; - - k5_free_kinit_job(); - - g_fjob.command = FIBER_CMD_KINIT; - g_fjob.nc = nc; - g_fjob.nct = nct; - g_fjob.dialog = nct->hwnd_panel; - g_fjob.principal = PMALLOC(size); - UnicodeStrToAnsi(g_fjob.principal, size, idname); - g_fjob.password = NULL; - g_fjob.lifetime = (krb5_deltat) d->tc_lifetime.current; - g_fjob.forwardable = d->forwardable; - g_fjob.proxiable = d->proxiable; - g_fjob.renewable = d->renewable; - g_fjob.renew_life = (krb5_deltat) d->tc_renew.current; - g_fjob.addressless = d->addressless; - g_fjob.publicIP = d->publicIP; - g_fjob.code = 0; - g_fjob.identity = ident; - g_fjob.prompt_set = 0; - g_fjob.valid_principal = FALSE; - g_fjob.retry_if_valid_principal = FALSE; - - /* the value for - retry_if_valid_principal is not - necessarily the correct value here, - but the correct value will be - assigned k5_kinit_fiber_proc(). */ - - /* if we have external parameters, we should use them as well */ - if (nc->ctx.cb_vparam == sizeof(NETID_DLGINFO) && - (pdlginfo = nc->ctx.vparam) && - pdlginfo->size == NETID_DLGINFO_V1_SZ) { - wchar_t * t; - - if (pdlginfo->in.ccache[0] && - SUCCEEDED(StringCchLength(pdlginfo->in.ccache, - NETID_CCACHE_NAME_SZ, - &size))) { - g_fjob.ccache = PMALLOC(sizeof(char) * (size + 1)); -#ifdef DEBUG - assert(g_fjob.ccache); -#endif - UnicodeStrToAnsi(g_fjob.ccache, size + 1, - pdlginfo->in.ccache); - - /* this is the same as the output cache */ - - StringCbCopy(pdlginfo->out.ccache, sizeof(pdlginfo->out.ccache), - pdlginfo->in.ccache); - } else { - g_fjob.ccache = NULL; - - StringCbCopy(pdlginfo->out.ccache, sizeof(pdlginfo->out.ccache), - idname); - - khm_krb5_canon_cc_name(pdlginfo->out.ccache, - sizeof(pdlginfo->out.ccache)); - } - - t = khm_get_realm_from_princ(idname); - - if (t) { - StringCbCopy(pdlginfo->out.realm, - sizeof(pdlginfo->out.realm), - t); - - if ((t - idname) > 1) { - StringCchCopyN(pdlginfo->out.username, - ARRAYLENGTH(pdlginfo->out.username), - idname, - (t - idname) - 1); - } else { - StringCbCopy(pdlginfo->out.username, - sizeof(pdlginfo->out.username), - L""); - } - } else { - StringCbCopy(pdlginfo->out.username, - sizeof(pdlginfo->out.username), - idname); - StringCbCopy(pdlginfo->out.realm, - sizeof(pdlginfo->out.realm), - L""); - } - } - - /* leave identity held, since we added a reference above */ -} - -static khm_int32 KHMAPI -k5_find_tgt_filter(khm_handle cred, - khm_int32 flags, - void * rock) { - khm_handle ident = (khm_handle) rock; - khm_handle cident = NULL; - khm_int32 f; - khm_int32 rv; - - if (KHM_SUCCEEDED(kcdb_cred_get_identity(cred, - &cident)) && - cident == ident && - KHM_SUCCEEDED(kcdb_cred_get_flags(cred, &f)) && - (f & KCDB_CRED_FLAG_INITIAL) && - !(f & KCDB_CRED_FLAG_EXPIRED)) - rv = 1; - else - rv = 0; - - if (cident) - kcdb_identity_release(cident); - - return rv; -} - -khm_int32 -k5_remove_from_LRU(khm_handle identity) -{ - wchar_t * wbuf = NULL; - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - khm_size cb_ms; - khm_int32 rv = KHM_ERROR_SUCCESS; - - cb = sizeof(idname); - rv = kcdb_identity_get_name(identity, idname, &cb); - assert(rv == KHM_ERROR_SUCCESS); - - rv = khc_read_multi_string(csp_params, L"LRUPrincipals", NULL, &cb_ms); - if (rv != KHM_ERROR_TOO_LONG) - cb_ms = sizeof(wchar_t) * 2; - - wbuf = PMALLOC(cb_ms); - assert(wbuf); - - cb = cb_ms; - - if (rv == KHM_ERROR_TOO_LONG) { - rv = khc_read_multi_string(csp_params, L"LRUPrincipals", wbuf, &cb); - assert(KHM_SUCCEEDED(rv)); - - if (multi_string_find(wbuf, idname, KHM_CASE_SENSITIVE) != NULL) { - multi_string_delete(wbuf, idname, KHM_CASE_SENSITIVE); - } - } else { - multi_string_init(wbuf, cb_ms); - } - - rv = khc_write_multi_string(csp_params, L"LRUPrincipals", wbuf); - - if (wbuf) - PFREE(wbuf); - - return rv; -} - -khm_int32 -k5_update_LRU(khm_handle identity) -{ - wchar_t * wbuf = NULL; - wchar_t * idname = NULL; - wchar_t * realm = NULL; - khm_size cb; - khm_size cb_ms; - khm_int32 rv = KHM_ERROR_SUCCESS; - - rv = kcdb_identity_get_name(identity, NULL, &cb); - assert(rv == KHM_ERROR_TOO_LONG); - - idname = PMALLOC(cb); - assert(idname); - - rv = kcdb_identity_get_name(identity, idname, &cb); - assert(KHM_SUCCEEDED(rv)); - - rv = khc_read_multi_string(csp_params, L"LRUPrincipals", NULL, &cb_ms); - if (rv != KHM_ERROR_TOO_LONG) - cb_ms = cb + sizeof(wchar_t); - else - cb_ms += cb + sizeof(wchar_t); - - wbuf = PMALLOC(cb_ms); - assert(wbuf); - - cb = cb_ms; - - if (rv == KHM_ERROR_TOO_LONG) { - rv = khc_read_multi_string(csp_params, L"LRUPrincipals", wbuf, &cb); - assert(KHM_SUCCEEDED(rv)); - - if (multi_string_find(wbuf, idname, KHM_CASE_SENSITIVE) != NULL) { - /* it's already there. We remove it here and add it at - the top of the LRU list. */ - multi_string_delete(wbuf, idname, KHM_CASE_SENSITIVE); - } - } else { - multi_string_init(wbuf, cb_ms); - } - - cb = cb_ms; - rv = multi_string_prepend(wbuf, &cb, idname); - assert(KHM_SUCCEEDED(rv)); - - rv = khc_write_multi_string(csp_params, L"LRUPrincipals", wbuf); - - realm = khm_get_realm_from_princ(idname); - if (realm == NULL || *realm == L'\0') - goto _done_with_LRU; - - cb = cb_ms; - rv = khc_read_multi_string(csp_params, L"LRURealms", wbuf, &cb); - - if (rv == KHM_ERROR_TOO_LONG) { - PFREE(wbuf); - wbuf = PMALLOC(cb); - assert(wbuf); - - cb_ms = cb; - - rv = khc_read_multi_string(csp_params, L"LRURealms", wbuf, &cb); - - assert(KHM_SUCCEEDED(rv)); - } else if (rv == KHM_ERROR_SUCCESS) { - if (multi_string_find(wbuf, realm, KHM_CASE_SENSITIVE) != NULL) { - /* remove the realm and add it at the top later. */ - multi_string_delete(wbuf, realm, KHM_CASE_SENSITIVE); - } - } else { - multi_string_init(wbuf, cb_ms); - } - - cb = cb_ms; - rv = multi_string_prepend(wbuf, &cb, realm); - - if (rv == KHM_ERROR_TOO_LONG) { - wbuf = PREALLOC(wbuf, cb); - - rv = multi_string_prepend(wbuf, &cb, realm); - - assert(KHM_SUCCEEDED(rv)); - } - - rv = khc_write_multi_string(csp_params, L"LRURealms", wbuf); - - assert(KHM_SUCCEEDED(rv)); - - _done_with_LRU: - - if (wbuf) - PFREE(wbuf); - if (idname) - PFREE(idname); - - return rv; -} - -/* Handler for CRED type messages - - Runs in the context of the Krb5 plugin -*/ -khm_int32 KHMAPI -k5_msg_cred_dialog(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - - switch(msg_subtype) { - - case KMSG_CRED_PASSWORD: - case KMSG_CRED_NEW_CREDS: - { - khui_new_creds * nc; - khui_new_creds_by_type * nct; - wchar_t wbuf[256]; - size_t cbsize; - - nc = (khui_new_creds *) vparam; - - nct = PMALLOC(sizeof(*nct)); - ZeroMemory(nct, sizeof(*nct)); - - nct->type = credtype_id_krb5; - nct->ordinal = 1; - - LoadString(hResModule, IDS_KRB5_NC_NAME, - wbuf, ARRAYLENGTH(wbuf)); - StringCbLength(wbuf, sizeof(wbuf), &cbsize); - cbsize += sizeof(wchar_t); - - nct->name = PMALLOC(cbsize); - StringCbCopy(nct->name, cbsize, wbuf); - - nct->h_module = hResModule; - nct->dlg_proc = k5_nc_dlg_proc; - if (nc->subtype == KMSG_CRED_PASSWORD) - nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB5_PASSWORD); - else - nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB5); - - khui_cw_add_type(nc, nct); - } - break; - - case KMSG_CRED_RENEW_CREDS: - { - khui_new_creds * nc; - khui_new_creds_by_type * nct; - - nc = (khui_new_creds *) vparam; - - nct = PMALLOC(sizeof(*nct)); - ZeroMemory(nct, sizeof(*nct)); - - nct->type = credtype_id_krb5; - - khui_cw_add_type(nc, nct); - } - break; - - case KMSG_CRED_DIALOG_PRESTART: - { - khui_new_creds * nc; - khui_new_creds_by_type * nct; - k5_dlg_data * d; - HWND hwnd; - wchar_t * realms; - wchar_t * t; - wchar_t * defrealm; - - nc = (khui_new_creds *) vparam; - - khui_cw_find_type(nc, credtype_id_krb5, &nct); - - if(!nct) - break; - - hwnd = nct->hwnd_panel; - d = (k5_dlg_data *)(LONG_PTR) - GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); - - /* this can be NULL if the dialog was closed while the - plug-in thread was processing. */ - if (d == NULL) - break; - - if (!is_k5_identpro) { - - /* enumerate all realms and place in realms combo box */ - SendDlgItemMessage(hwnd, IDC_NCK5_REALM, - CB_RESETCONTENT, - 0, 0); - - realms = khm_krb5_get_realm_list(); - if(realms) { - for (t = realms; t && *t; t = multi_string_next(t)) { - SendDlgItemMessage(hwnd, IDC_NCK5_REALM, - CB_ADDSTRING, - 0, (LPARAM) t); - } - PFREE(realms); - } - - /* and set the default realm */ - defrealm = khm_krb5_get_default_realm(); - if(defrealm) { - SendDlgItemMessage(hwnd, IDC_NCK5_REALM, - CB_SELECTSTRING, - (WPARAM) -1, - (LPARAM) defrealm); - - SendDlgItemMessage(hwnd, IDC_NCK5_REALM, - WM_SETTEXT, - 0, (LPARAM) defrealm); - PFREE(defrealm); - } - } else { /* if krb5 is the identity provider */ - HWND hw_realms; - - /* in this case, the realm selection is done by the - identity provider prompts. */ - - hw_realms = GetDlgItem(hwnd, IDC_NCK5_REALM); -#ifdef DEBUG - assert(hw_realms); -#endif - EnableWindow(hw_realms, FALSE); - } - - if (nc->subtype == KMSG_CRED_NEW_CREDS) { - k5_read_dlg_params(d, NULL); - } - - PostMessage(hwnd, KHUI_WM_NC_NOTIFY, - MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0); - } - break; - - case KMSG_CRED_DIALOG_NEW_IDENTITY: - { - khui_new_creds * nc; - khui_new_creds_by_type * nct; - k5_dlg_data * d; - - nc = (khui_new_creds *) vparam; - - khui_cw_find_type(nc, credtype_id_krb5, &nct); - if (!nct) - break; - - d = (k5_dlg_data *)(LONG_PTR) - GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); - - if (d == NULL) - break; - - /* we only load the identity specific defaults if the user - hasn't changed the options */ - khui_cw_lock_nc(nc); - - /* ?: 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) { - - k5_read_dlg_params(d, nc->identities[0]); - - PostMessage(nct->hwnd_panel, KHUI_WM_NC_NOTIFY, - MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0); - } - - khui_cw_unlock_nc(nc); - - /* reset the force-password-change flag if this is a new - identity. */ - d->pwd_change = FALSE; - } - - /* fallthrough */ - case KMSG_CRED_DIALOG_NEW_OPTIONS: - { - khui_new_creds * nc; - khui_new_creds_by_type * nct; - k5_dlg_data * d; - - nc = (khui_new_creds *) vparam; - - khui_cw_find_type(nc, credtype_id_krb5, &nct); - if (!nct) - break; - - d = (k5_dlg_data *)(LONG_PTR) - GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); - if (d == NULL) - break; - - if (nc->subtype == KMSG_CRED_PASSWORD) { - khm_size n_prompts = 0; - - khui_cw_get_prompt_count(nc, &n_prompts); - - if (nc->n_identities == 0) { - if (n_prompts) - khui_cw_clear_prompts(nc); - } else if (n_prompts != 3) { - wchar_t wbuf[KHUI_MAXCCH_BANNER]; - - khui_cw_clear_prompts(nc); - - LoadString(hResModule, IDS_NC_PWD_BANNER, - wbuf, ARRAYLENGTH(wbuf)); - khui_cw_begin_custom_prompts(nc, 3, NULL, wbuf); - - LoadString(hResModule, IDS_NC_PWD_PWD, - wbuf, ARRAYLENGTH(wbuf)); - khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_PASSWORD, - wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); - - LoadString(hResModule, IDS_NC_PWD_NPWD, - wbuf, ARRAYLENGTH(wbuf)); - khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_NEW_PASSWORD, - wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); - - LoadString(hResModule, IDS_NC_PWD_NPWD_AGAIN, - wbuf, ARRAYLENGTH(wbuf)); - khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_NEW_PASSWORD_AGAIN, - wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); - } - - return KHM_ERROR_SUCCESS; - } - /* else; nc->subtype == KMSG_CRED_NEW_CREDS */ - - assert(nc->subtype == KMSG_CRED_NEW_CREDS); - - /* If we are forcing a password change, then we don't do - anything here. Note that if the identity changed, then - this field would have been reset, so we would proceed - as usual. */ - if (d->pwd_change) - return KHM_ERROR_SUCCESS; - -#if 0 - /* Clearing the prompts at this point is a bad idea since - the prompter depends on the prompts to know if this set - of prompts is the same as the new set and if so, use - the values entered in the old prompts as responses to - the new one. */ - khui_cw_clear_prompts(nc); -#endif - - /* if the fiber is already in a kinit, cancel it */ - if(g_fjob.state == FIBER_STATE_KINIT) { - g_fjob.command = FIBER_CMD_CANCEL; - SwitchToFiber(k5_kinit_fiber); - /* we get here when the cancel operation completes */ - k5_free_kinit_job(); - } - - khui_cw_lock_nc(nc); - - if(nc->n_identities > 0) { - khm_handle ident = nc->identities[0]; - - kcdb_identity_hold(ident); - - k5_prep_kinit_job(nc); - - /* after the switch to the fiber, the dialog will be - back in sync with the kinit thread. */ - d->sync = TRUE; - - khui_cw_unlock_nc(nc); - - SwitchToFiber(k5_kinit_fiber); - /* we get here when the fiber switches back */ - if(g_fjob.state == FIBER_STATE_NONE) { - wchar_t msg[KHUI_MAXCCH_BANNER]; - khm_size cb; - - /* Special case. If the users' password has - expired, we force a password change dialog on - top of the new credentials dialog using a set - of custom prompts, but only if we are the - identity provider. */ - if (g_fjob.code == KRB5KDC_ERR_KEY_EXP && - is_k5_identpro) { - - k5_force_password_change(d); - goto done_with_bad_princ; - - } - - /* we can't possibly have succeeded without a - password */ - if(g_fjob.code == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN && - is_k5_identpro) { - kcdb_identity_set_flags(ident, - KCDB_IDENT_FLAG_INVALID, - KCDB_IDENT_FLAG_INVALID); - - khui_cw_clear_prompts(nc); - } - - if (d->cred_message) { - PFREE(d->cred_message); - d->cred_message = NULL; - } - - msg[0] = L'\0'; - - switch(g_fjob.code) { - case KRB5KDC_ERR_NAME_EXP: - /* principal expired */ - LoadString(hResModule, IDS_K5ERR_NAME_EXPIRED, - msg, ARRAYLENGTH(msg)); - break; - - case KRB5KDC_ERR_KEY_EXP: - { - /* password needs changing. */ - LoadString(hResModule, IDS_K5ERR_KEY_EXPIRED, - msg, ARRAYLENGTH(msg)); - } - break; - - default: - { - DWORD dw_dummy; - kherr_suggestion sug_dummy; - wchar_t fmt[KHUI_MAXCCH_BANNER]; - wchar_t desc[KHUI_MAXCCH_BANNER]; - - LoadString(hResModule, IDS_K5ERR_FMT, - fmt, ARRAYLENGTH(fmt)); - - khm_err_describe(g_fjob.code, - desc, - sizeof(desc), - &dw_dummy, - &sug_dummy); - - StringCbPrintf(msg, sizeof(msg), fmt, desc); - } - } - - if (msg[0]) { - StringCbLength(msg, sizeof(msg), &cb); - cb += sizeof(wchar_t); - - d->cred_message = PMALLOC(cb); - StringCbCopy(d->cred_message, cb, msg); - } - - done_with_bad_princ: - - k5_free_kinit_job(); - - if (is_k5_identpro) - kcdb_identity_set_flags(ident, - KCDB_IDENT_FLAG_UNKNOWN, - KCDB_IDENT_FLAG_UNKNOWN); - - - } else if(g_fjob.state == FIBER_STATE_KINIT) { - /* this is what we want. Leave the fiber there. */ - - if(is_k5_identpro) - kcdb_identity_set_flags(ident, - KCDB_IDENT_FLAG_VALID, - KCDB_IDENT_FLAG_VALID); - } else { - /* huh?? */ -#ifdef DEBUG - assert(FALSE); -#endif - } - - /* since the attributes of the identity have changed, - we should update the cred text as well */ - kcdb_identity_release(ident); - khui_cw_lock_nc(nc); - PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, - MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0); - } else { - khui_cw_unlock_nc(nc); - khui_cw_clear_prompts(nc); - khui_cw_lock_nc(nc); - } - - khui_cw_unlock_nc(nc); - } - break; - - case KMSG_CRED_PROCESS: - { - khui_new_creds * nc; - khui_new_creds_by_type * nct; - k5_dlg_data * d; - - khm_int32 r = 0; - - nc = (khui_new_creds *) vparam; - - khui_cw_find_type(nc, credtype_id_krb5, &nct); - - if(!nct) - break; - - /* reset the null_password flag, just in case */ - g_fjob.null_password = FALSE; - - if (nc->subtype == KMSG_CRED_NEW_CREDS) { - d = (k5_dlg_data *) nct->aux; - if (d == NULL) - break; - - if (d->pwd_change) { - /* we are forcing a password change */ - goto change_password; - } - - _begin_task(0); - _report_mr0(KHERR_NONE, MSG_CTX_INITAL_CREDS); - _describe(); - - if (g_fjob.state == FIBER_STATE_KINIT) { - if(nc->result == KHUI_NC_RESULT_CANCEL) { - g_fjob.command = FIBER_CMD_CANCEL; - SwitchToFiber(k5_kinit_fiber); - - /* if we cancelled out, then we shouldn't care - about the return code. */ -#ifdef DEBUG - assert(g_fjob.state == FIBER_STATE_NONE); -#endif - g_fjob.code = 0; - - _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); - - /* We get back here once the fiber finishes - processing */ - } -#ifdef DEBUG - else { - assert(FALSE); - } -#endif - } else { - /* we weren't in a KINIT state */ - if (nc->result == KHUI_NC_RESULT_CANCEL) { - /* nothing to report */ - g_fjob.code = 0; - } else if (nc->result == KHUI_NC_RESULT_PROCESS) { - /* g_fjob.code should have the result of the - last kinit attempt. We should leave it - as-is */ - } -#ifdef DEBUG - else { - /* unknown result */ - assert(FALSE); - } -#endif - } - - /* special case: if there was no password entered, and - if there is a valid TGT we allow the credential - acquisition to go through */ - if (g_fjob.state == FIBER_STATE_NONE && - g_fjob.code && - g_fjob.null_password && - - (nc->n_identities == 0 || - nc->identities[0] == NULL || - KHM_SUCCEEDED(kcdb_credset_find_filtered - (NULL, - -1, - k5_find_tgt_filter, - nc->identities[0], - NULL, - NULL)))) { - _reportf(L"No password entered, but a valid TGT exists. Continuing"); - g_fjob.code = 0; - } else if (g_fjob.state == FIBER_STATE_NONE && - g_fjob.code == 0 && - nc->n_identities > 0 && - nc->identities[0] != NULL) { - - /* we had a password and we used it to get - tickets. We should reset the IMPORTED flag now - since the tickets are not imported. */ - - khm_krb5_set_identity_flags(nc->identities[0], - K5IDFLAG_IMPORTED, - 0); - } - - if(g_fjob.code != 0) { - wchar_t tbuf[1024]; - DWORD suggestion; - kherr_suggestion suggest_code; - - khm_err_describe(g_fjob.code, tbuf, sizeof(tbuf), - &suggestion, &suggest_code); - - _report_cs0(KHERR_ERROR, tbuf); - if (suggestion != 0) - _suggest_mr(suggestion, suggest_code); - - _resolve(); - - r = KHUI_NC_RESPONSE_FAILED; - - if (suggest_code == KHERR_SUGGEST_RETRY) { - r |= KHUI_NC_RESPONSE_NOEXIT | - KHUI_NC_RESPONSE_PENDING; - } - -#ifdef DEBUG - assert(g_fjob.state == FIBER_STATE_NONE); -#endif - - if (g_fjob.valid_principal && - nc->n_identities > 0 && - nc->identities[0]) { - /* the principal was valid, so we can go ahead - and update the LRU */ - k5_update_LRU(nc->identities[0]); - } - - } else if (nc->result == KHUI_NC_RESULT_PROCESS && - g_fjob.state == FIBER_STATE_NONE) { - krb5_context ctx = NULL; - - _reportf(L"Tickets successfully acquired"); - - r = KHUI_NC_RESPONSE_SUCCESS | - KHUI_NC_RESPONSE_EXIT; - - /* if we successfully obtained credentials, we - should save the current settings in the - identity config space */ - - assert(nc->n_identities > 0); - assert(nc->identities[0]); - - k5_write_dlg_params(d, nc->identities[0]); - - /* We should also quickly refresh the credentials - so that the identity flags and ccache - properties reflect the current state of - affairs. This has to be done here so that - other credentials providers which depend on - Krb5 can properly find the initial creds to - obtain their respective creds. */ - - khm_krb5_list_tickets(&ctx); - - if (nc->set_default) { - _reportf(L"Setting default identity"); - kcdb_identity_set_default(nc->identities[0]); - } - - /* If there is no default identity, then make this the default */ - kcdb_identity_refresh(nc->identities[0]); - { - khm_handle tdefault = NULL; - - 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]); - } - } - - /* and update the LRU */ - k5_update_LRU(nc->identities[0]); - - if (ctx != NULL) - pkrb5_free_context(ctx); - } else if (g_fjob.state == FIBER_STATE_NONE) { - /* the user cancelled the operation */ - r = KHUI_NC_RESPONSE_EXIT | - KHUI_NC_RESPONSE_SUCCESS; - } - - if(g_fjob.state == FIBER_STATE_NONE) { - khui_cw_set_response(nc, credtype_id_krb5, r); - - if (r & KHUI_NC_RESPONSE_NOEXIT) { - /* if we are retrying the call, we should - restart the kinit fiber */ -#ifdef DEBUG - assert(r & KHUI_NC_RESPONSE_PENDING); -#endif - - k5_prep_kinit_job(nc); - SwitchToFiber(k5_kinit_fiber); - } else { - /* free up the fiber data fields. */ - k5_free_kinit_job(); - } - } else { - khui_cw_set_response(nc, credtype_id_krb5, - KHUI_NC_RESPONSE_NOEXIT | - KHUI_NC_RESPONSE_PENDING | r); - } - - _end_task(); - } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { - - FILETIME ftidexp = {0,0}; - FILETIME ftcurrent; - khm_size cb; - - GetSystemTimeAsFileTime(&ftcurrent); - - _begin_task(0); - _report_mr0(KHERR_NONE, MSG_CTX_RENEW_CREDS); - _describe(); - - if (nc->ctx.scope == KHUI_SCOPE_IDENT || - (nc->ctx.scope == KHUI_SCOPE_CREDTYPE && - nc->ctx.cred_type == credtype_id_krb5) || - (nc->ctx.scope == KHUI_SCOPE_CRED && - nc->ctx.cred_type == credtype_id_krb5)) { - int code; - - 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); - - kcdb_identity_get_attr(nc->ctx.identity, - KCDB_ATTR_EXPIRE, - NULL, - &ftidexp, - &cb); - - 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); - } else if (nc->ctx.identity == 0) { - - _report_mr0(KHERR_ERROR, MSG_ERR_NO_IDENTITY); - - khui_cw_set_response(nc, credtype_id_krb5, - KHUI_NC_RESPONSE_EXIT | - KHUI_NC_RESPONSE_FAILED); - } else if (CompareFileTime(&ftcurrent, &ftidexp) < 0) { - wchar_t tbuf[1024]; - DWORD suggestion; - kherr_suggestion sug_id; - - /* if we failed to get new tickets, but the - identity is still valid, then we assume that - the current tickets are still good enough - for other credential types to obtain their - credentials. */ - - khm_err_describe(code, tbuf, sizeof(tbuf), - &suggestion, &sug_id); - - _report_cs0(KHERR_WARNING, tbuf); - if (suggestion) - _suggest_mr(suggestion, sug_id); - - _resolve(); - - khui_cw_set_response(nc, credtype_id_krb5, - KHUI_NC_RESPONSE_EXIT | - KHUI_NC_RESPONSE_SUCCESS); - } else { - wchar_t tbuf[1024]; - DWORD suggestion; - kherr_suggestion sug_id; - - khm_err_describe(code, tbuf, sizeof(tbuf), - &suggestion, &sug_id); - - _report_cs0(KHERR_ERROR, tbuf); - if (suggestion) - _suggest_mr(suggestion, sug_id); - - _resolve(); - - khui_cw_set_response(nc, credtype_id_krb5, - ((sug_id == KHERR_SUGGEST_RETRY)?KHUI_NC_RESPONSE_NOEXIT:KHUI_NC_RESPONSE_EXIT) | - KHUI_NC_RESPONSE_FAILED); - } - } else { - khui_cw_set_response(nc, credtype_id_krb5, - KHUI_NC_RESPONSE_EXIT | - KHUI_NC_RESPONSE_SUCCESS); - } - - _end_task(); - } else if (nc->subtype == KMSG_CRED_PASSWORD && - nc->result == KHUI_NC_RESULT_PROCESS) { - - change_password: - /* we jump here if there was a password change forced */ - - _begin_task(0); - _report_mr0(KHERR_NONE, MSG_CTX_PASSWD); - _describe(); - - khui_cw_lock_nc(nc); - - if (nc->result == KHUI_NC_RESULT_CANCEL) { - - khui_cw_set_response(nc, credtype_id_krb5, - KHUI_NC_RESPONSE_SUCCESS | - KHUI_NC_RESPONSE_EXIT); - - } else if (nc->n_identities == 0 || - nc->identities[0] == NULL) { - _report_mr0(KHERR_ERROR, MSG_PWD_NO_IDENTITY); - _suggest_mr(MSG_PWD_S_NO_IDENTITY, KHERR_SUGGEST_RETRY); - - khui_cw_set_response(nc, credtype_id_krb5, - KHUI_NC_RESPONSE_FAILED | - KHUI_NC_RESPONSE_NOEXIT); - - } else { - wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; - char idname[KCDB_IDENT_MAXCCH_NAME]; - wchar_t wpwd[KHUI_MAXCCH_PASSWORD]; - char pwd[KHUI_MAXCCH_PASSWORD]; - wchar_t wnpwd[KHUI_MAXCCH_PASSWORD]; - char npwd[KHUI_MAXCCH_PASSWORD]; - wchar_t wnpwd2[KHUI_MAXCCH_PASSWORD]; - wchar_t * wresult; - char * result; - khm_size n_prompts = 0; - khm_size cb; - khm_int32 rv = KHM_ERROR_SUCCESS; - long code = 0; - khm_handle ident; - - khui_cw_get_prompt_count(nc, &n_prompts); - assert(n_prompts == 3); - - ident = nc->identities[0]; - cb = sizeof(widname); - rv = kcdb_identity_get_name(ident, widname, &cb); - if (KHM_FAILED(rv)) { -#ifdef DEBUG - assert(FALSE); -#endif - _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); - goto _pwd_exit; - } - - cb = sizeof(wpwd); - rv = khui_cw_get_prompt_value(nc, 0, wpwd, &cb); - if (KHM_FAILED(rv)) { -#ifdef DEBUG - assert(FALSE); -#endif - _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); - goto _pwd_exit; - } - - cb = sizeof(wnpwd); - rv = khui_cw_get_prompt_value(nc, 1, wnpwd, &cb); - if (KHM_FAILED(rv)) { -#ifdef DEBUG - assert(FALSE); -#endif - _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); - goto _pwd_exit; - } - - cb = sizeof(wnpwd2); - rv = khui_cw_get_prompt_value(nc, 2, wnpwd2, &cb); - if (KHM_FAILED(rv)) { -#ifdef DEBUG - assert(FALSE); -#endif - _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); - goto _pwd_exit; - } - - if (wcscmp(wnpwd, wnpwd2)) { - rv = KHM_ERROR_INVALID_PARAM; - _report_mr0(KHERR_ERROR, MSG_PWD_NOT_SAME); - _suggest_mr(MSG_PWD_S_NOT_SAME, KHERR_SUGGEST_INTERACT); - goto _pwd_exit; - } - - if (!wcscmp(wpwd, wnpwd)) { - rv = KHM_ERROR_INVALID_PARAM; - _report_mr0(KHERR_ERROR, MSG_PWD_SAME); - _suggest_mr(MSG_PWD_S_SAME, KHERR_SUGGEST_INTERACT); - goto _pwd_exit; - } - - UnicodeStrToAnsi(idname, sizeof(idname), widname); - UnicodeStrToAnsi(pwd, sizeof(pwd), wpwd); - UnicodeStrToAnsi(npwd, sizeof(npwd), wnpwd); - - result = NULL; - - code = khm_krb5_changepwd(idname, - pwd, - npwd, - &result); - - if (code) - rv = KHM_ERROR_UNKNOWN; - else { - khm_handle csp_idcfg = NULL; - krb5_context ctx = NULL; - - /* we set a new password. now we need to get - initial credentials. */ - - d = (k5_dlg_data *) nct->aux; - - if (d == NULL) { - rv = KHM_ERROR_UNKNOWN; - goto _pwd_exit; - } - - if (nc->subtype == KMSG_CRED_PASSWORD) { - /* since this was just a password change, - we need to load new credentials options - from the configuration store. */ - - k5_read_dlg_params(d, nc->identities[0]); - } - - /* the password change phase is now done */ - d->pwd_change = FALSE; - -#ifdef DEBUG - _reportf(L"Calling khm_krb5_kinit()"); -#endif - code = khm_krb5_kinit(NULL, /* context (create one) */ - idname, /* principal_name */ - npwd, /* new password */ - NULL, /* ccache name (figure out the identity cc)*/ - (krb5_deltat) d->tc_lifetime.current, - d->forwardable, - d->proxiable, - (krb5_deltat)((d->renewable)?d->tc_renew.current:0), - d->addressless, /* addressless */ - d->publicIP, /* public IP */ - NULL, /* prompter */ - NULL /* prompter data */); - - if (code) { - rv = KHM_ERROR_UNKNOWN; - goto _pwd_exit; - } - - /* save the settings that we used for - obtaining the ticket. */ - if (nc->subtype == KMSG_CRED_NEW_CREDS) { - - k5_write_dlg_params(d, nc->identities[0]); - - /* and then update the LRU too */ - k5_update_LRU(nc->identities[0]); - } - - /* and do a quick refresh of the krb5 tickets - so that other plug-ins that depend on krb5 - can look up tickets inside NetIDMgr */ - khm_krb5_list_tickets(&ctx); - - /* if there was no default identity, we make - this one the default. */ - kcdb_identity_refresh(nc->identities[0]); - { - khm_handle tdefault = NULL; - - if (KHM_SUCCEEDED(kcdb_identity_get_default(&tdefault))) { - kcdb_identity_release(tdefault); - } else { - _reportf(L"There was no default identity. Setting defualt"); - kcdb_identity_set_default(nc->identities[0]); - } - } - - if (ctx != NULL) - pkrb5_free_context(ctx); - - if (nc->subtype == KMSG_CRED_PASSWORD) { - /* if we obtained new credentials as a - result of successfully changing the - password, we also schedule an identity - renewal for this identity. This allows - the other credential types to obtain - credentials for this identity. */ - khui_action_context ctx; - - _reportf(L"Scheduling renewal of [%s] after password change", - widname); - - khui_context_create(&ctx, - KHUI_SCOPE_IDENT, - nc->identities[0], - KCDB_CREDTYPE_INVALID, - NULL); - khui_action_trigger(KHUI_ACTION_RENEW_CRED, - &ctx); - - khui_context_release(&ctx); - } - } - - /* result is only set when code != 0 */ - if (code && result) { - size_t len; - - StringCchLengthA(result, KHERR_MAXCCH_STRING, - &len); - wresult = PMALLOC((len + 1) * sizeof(wchar_t)); -#ifdef DEBUG - assert(wresult); -#endif - AnsiStrToUnicode(wresult, (len + 1) * sizeof(wchar_t), - result); - - _report_cs1(KHERR_ERROR, L"%1!s!", _cstr(wresult)); - _resolve(); - - PFREE(result); - PFREE(wresult); - - /* we don't need to report anything more */ - code = 0; - } - - _pwd_exit: - if (KHM_FAILED(rv)) { - if (code) { - wchar_t tbuf[1024]; - DWORD suggestion; - kherr_suggestion sug_id; - - khm_err_describe(code, tbuf, sizeof(tbuf), - &suggestion, &sug_id); - _report_cs0(KHERR_ERROR, tbuf); - - if (suggestion) - _suggest_mr(suggestion, sug_id); - - _resolve(); - } - - khui_cw_set_response(nc, credtype_id_krb5, - KHUI_NC_RESPONSE_NOEXIT| - KHUI_NC_RESPONSE_FAILED); - } else { - khui_cw_set_response(nc, credtype_id_krb5, - KHUI_NC_RESPONSE_SUCCESS | - KHUI_NC_RESPONSE_EXIT); - } - } - - khui_cw_unlock_nc(nc); - - _end_task(); - } /* KMSG_CRED_PASSWORD */ - } - break; - - case KMSG_CRED_END: - { - khui_new_creds * nc; - khui_new_creds_by_type * nct; - - nc = (khui_new_creds *) vparam; - khui_cw_find_type(nc, credtype_id_krb5, &nct); - - if(!nct) - break; - - khui_cw_del_type(nc, credtype_id_krb5); - - if (nct->name) - PFREE(nct->name); - if (nct->credtext) - PFREE(nct->credtext); - - PFREE(nct); - - k5_free_kinit_job(); - } - break; - - case KMSG_CRED_IMPORT: - { - khm_int32 t = 0; - -#ifdef DEBUG - assert(csp_params); -#endif - khc_read_int32(csp_params, L"MsLsaImport", &t); - - if (t != K5_LSAIMPORT_NEVER) { - krb5_context ctx = NULL; - khm_handle id_default = NULL; - khm_handle id_imported = NULL; - BOOL imported; - - imported = khm_krb5_ms2mit(NULL, (t == K5_LSAIMPORT_MATCH), TRUE, - &id_imported); - if (imported) { - khm_krb5_list_tickets(&ctx); - - if (ctx) - pkrb5_free_context(ctx); - - kcdb_identity_refresh(id_imported); - - if (KHM_SUCCEEDED(kcdb_identity_get_default(&id_default))) { - kcdb_identity_release(id_default); - id_default = NULL; - } else { - _reportf(L"There was no default identity. Setting default"); - kcdb_identity_set_default(id_imported); - } - - /* and update the LRU */ - k5_update_LRU(id_imported); - } - - if (id_imported) - kcdb_identity_release(id_imported); - } - } - break; - } - - return rv; -} +/* + * Copyright (c) 2006 Secure Endpoints Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include + +#include + +#include + +extern LPVOID k5_main_fiber; +extern LPVOID k5_kinit_fiber; + +typedef struct k5_dlg_data_t { + khui_new_creds * nc; + + khui_tracker tc_lifetime; + khui_tracker tc_renew; + + BOOL dirty; /* 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; + DWORD addressless; + DWORD publicIP; + + wchar_t * cred_message; /* overrides the credential text, if + non-NULL */ + BOOL pwd_change; /* force a password change */ +} k5_dlg_data; + + +INT_PTR +k5_handle_wm_initdialog(HWND hwnd, + WPARAM wParam, + LPARAM lParam) +{ + HWND hw; + k5_dlg_data * d; + khui_new_creds_by_type * nct; + + d = PMALLOC(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + /* lParam is a pointer to a khui_new_creds structure */ + d->nc = (khui_new_creds *) lParam; + khui_cw_find_type(d->nc, credtype_id_krb5, &nct); + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM) d); +#pragma warning(pop) + + nct->aux = (LPARAM) d; + + if (d->nc->subtype == KMSG_CRED_NEW_CREDS) { + khui_tracker_initialize(&d->tc_lifetime); + khui_tracker_initialize(&d->tc_renew); + + hw = GetDlgItem(hwnd, IDC_NCK5_LIFETIME_EDIT); + khui_tracker_install(hw, &d->tc_lifetime); + + hw = GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT); + khui_tracker_install(hw, &d->tc_renew); + } + return TRUE; +} + +INT_PTR +k5_handle_wm_destroy(HWND hwnd, + WPARAM wParam, + LPARAM lParam) +{ + k5_dlg_data * d; + khui_new_creds_by_type * nct = NULL; + + d = (k5_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (!d) + return TRUE; + + khui_cw_find_type(d->nc, credtype_id_krb5, &nct); + +#ifdef DEBUG + assert(nct); +#endif + + nct->aux = 0; + + if (d->nc->subtype == KMSG_CRED_NEW_CREDS) { + khui_tracker_kill_controls(&d->tc_renew); + khui_tracker_kill_controls(&d->tc_lifetime); + } + + PFREE(d); + + return TRUE; +} + +LRESULT +k5_force_password_change(k5_dlg_data * d) { + /* we are turning this dialog into a change password dialog... */ + wchar_t wbuf[KHUI_MAXCCH_BANNER]; + + khui_cw_clear_prompts(d->nc); + + LoadString(hResModule, IDS_NC_PWD_BANNER, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_begin_custom_prompts(d->nc, 3, NULL, wbuf); + + LoadString(hResModule, IDS_NC_PWD_PWD, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_add_prompt(d->nc, KHUI_NCPROMPT_TYPE_PASSWORD, + wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); + + LoadString(hResModule, IDS_NC_PWD_NPWD, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_add_prompt(d->nc, KHUI_NCPROMPT_TYPE_NEW_PASSWORD, + wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); + + LoadString(hResModule, IDS_NC_PWD_NPWD_AGAIN, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_add_prompt(d->nc, KHUI_NCPROMPT_TYPE_NEW_PASSWORD_AGAIN, + wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); + + d->pwd_change = TRUE; + + if (is_k5_identpro && + d->nc->n_identities > 0 && + d->nc->identities[0]) { + + kcdb_identity_set_flags(d->nc->identities[0], + KCDB_IDENT_FLAG_VALID, + KCDB_IDENT_FLAG_VALID); + + } + + PostMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), + (LPARAM) d->nc); + + return TRUE; +} + +INT_PTR +k5_handle_wmnc_notify(HWND hwnd, + WPARAM wParam, + LPARAM lParam) +{ + switch(HIWORD(wParam)) { + case WMNC_DIALOG_MOVE: + { + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (d->nc->subtype == KMSG_CRED_NEW_CREDS) { + khui_tracker_reposition(&d->tc_lifetime); + khui_tracker_reposition(&d->tc_renew); + } + + return TRUE; + } + break; + + case WMNC_DIALOG_SETUP: + { + k5_dlg_data * d; + BOOL old_sync; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (d->nc->subtype == KMSG_CRED_PASSWORD) + return TRUE; + + /* we save the value of the 'sync' field here because some + of the notifications that are generated while setting + the controls overwrite the field. */ + old_sync = d->sync; + + /* need to update the controls with d->* */ + 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); + + 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); + + d->sync = old_sync; + } + break; + + case WMNC_CREDTEXT_LINK: + { + k5_dlg_data * d; + khui_htwnd_link * l; + khui_new_creds * nc; + wchar_t linktext[128]; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + nc = d->nc; + l = (khui_htwnd_link *) lParam; + + if (!l) + break; + + StringCchCopyN(linktext, ARRAYLENGTH(linktext), + l->id, l->id_len); + + if (!wcscmp(linktext, L"Krb5Cred:!Passwd")) { + return k5_force_password_change(d); + } + } + break; + + case WMNC_UPDATE_CREDTEXT: + { + k5_dlg_data * d; + khui_new_creds * nc; + khui_new_creds_by_type * nct; + wchar_t sbuf[1024]; + wchar_t fbuf[256]; + wchar_t tbuf[256]; + size_t cbsize; + khm_int32 flags; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + nc = d->nc; + khui_cw_find_type(nc, credtype_id_krb5, &nct); + + if(nct == NULL) + break; + + if(nct->credtext) + PFREE(nct->credtext); + nct->credtext = NULL; + + tbuf[0] = L'\0'; + + if (nc->n_identities > 0 && + KHM_SUCCEEDED(kcdb_identity_get_flags(nc->identities[0], + &flags)) && + (flags & KCDB_IDENT_FLAG_VALID) && + nc->subtype == KMSG_CRED_NEW_CREDS && + !d->pwd_change) { + + if (is_k5_identpro) + k5_get_realm_from_nc(nc, tbuf, ARRAYLENGTH(tbuf)); + else + GetDlgItemText(hwnd, IDC_NCK5_REALM, tbuf, + ARRAYLENGTH(tbuf)); + + /*TODO: if additional realms were specified, then those + must be listed as well */ + LoadString(hResModule, IDS_KRB5_CREDTEXT_0, + fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(sbuf, sizeof(sbuf), fbuf, + tbuf); + + StringCbLength(sbuf, sizeof(sbuf), &cbsize); + cbsize += sizeof(wchar_t); + + nct->credtext = PMALLOC(cbsize); + + StringCbCopy(nct->credtext, cbsize, sbuf); + } else if (nc->n_identities > 0 && + (nc->subtype == KMSG_CRED_PASSWORD || + (nc->subtype == KMSG_CRED_NEW_CREDS && d->pwd_change))) { + cbsize = sizeof(tbuf); + kcdb_identity_get_name(nc->identities[0], tbuf, &cbsize); + + LoadString(hResModule, IDS_KRB5_CREDTEXT_P0, + fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(sbuf, sizeof(sbuf), fbuf, tbuf); + + StringCbLength(sbuf, sizeof(sbuf), &cbsize); + cbsize += sizeof(wchar_t); + + nct->credtext = PMALLOC(cbsize); + + StringCbCopy(nct->credtext, cbsize, sbuf); + } else { + if (d->cred_message) { + StringCbLength(d->cred_message, KHUI_MAXCB_BANNER, + &cbsize); + cbsize += sizeof(wchar_t); + + nct->credtext = PMALLOC(cbsize); + + StringCbCopy(nct->credtext, cbsize, d->cred_message); + } + } + } + break; + + case WMNC_IDENTITY_CHANGE: + { + /* There has been a change of identity */ + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + kmq_post_sub_msg(k5_sub, KMSG_CRED, + KMSG_CRED_DIALOG_NEW_IDENTITY, + 0, (void *) d->nc); + } + break; + + case WMNC_DIALOG_PREPROCESS: + { + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if(!d->sync && d->nc->result == KHUI_NC_RESULT_PROCESS) { + kmq_post_sub_msg(k5_sub, KMSG_CRED, + KMSG_CRED_DIALOG_NEW_OPTIONS, + 0, (void *) d->nc); + } + } + 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; + } + + 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, + LPARAM lParam) +{ + int cid; + int notif; + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + cid = LOWORD(wParam); + notif = HIWORD(wParam); + + if(notif == BN_CLICKED && cid == IDC_NCK5_RENEWABLE) { + int c; + c = (int) SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, + BM_GETCHECK, 0, 0); + if(c==BST_CHECKED) { + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), TRUE); + d->renewable = TRUE; + } else { + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), FALSE); + d->renewable = FALSE; + } + d->dirty = TRUE; + d->sync = FALSE; + } else if(notif == BN_CLICKED && cid == IDC_NCK5_FORWARDABLE) { + int c; + c = (int) SendDlgItemMessage(hwnd, IDC_NCK5_FORWARDABLE, + BM_GETCHECK, 0, 0); + if(c==BST_CHECKED) { + d->forwardable = TRUE; + } else { + 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 && + !is_k5_identpro) { + /* find out what the realm of the current identity + is, and if they are the same, then we don't do + anything */ + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t realm[KCDB_IDENT_MAXCCH_NAME]; + wchar_t *r; + khm_size cbsize; + khm_handle ident; + int idx; + + if(d->nc->n_identities > 0) { + if(notif == CBN_SELCHANGE) { + idx = (int) SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_GETCURSEL, 0, 0); + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_GETLBTEXT, idx, (LPARAM) realm); + } else { + GetDlgItemText(hwnd, IDC_NCK5_REALM, + realm, ARRAYLENGTH(realm)); + } + cbsize = sizeof(idname); + if(KHM_SUCCEEDED(kcdb_identity_get_name(d->nc->identities[0], + idname, &cbsize))) { + r = wcschr(idname, L'@'); + if(r && !wcscmp(realm, r+1)) + return 0; /* nothing to do */ + + if(!r) { + r = idname + wcslen(idname); + *r++ = L'@'; + *r++ = 0; + } + + /* if we get here, we have a new user */ + StringCchCopy(r+1, + ARRAYLENGTH(idname) - ((r+1) - idname), + realm); + if(KHM_SUCCEEDED(kcdb_identity_create(idname, + KCDB_IDENT_FLAG_CREATE, + &ident))) { + khui_cw_set_primary_id(d->nc, ident); + kcdb_identity_release(ident); + } + return 0; + } + } + + /* if we get here, we have a new realm, but there is no + identity */ + PostMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0); + } + + return 0; +} + + +/* Dialog procedure for the Krb5 credentials type panel. + + NOTE: Runs in the context of the UI thread +*/ +INT_PTR CALLBACK +k5_nc_dlg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) { + case WM_INITDIALOG: + return k5_handle_wm_initdialog(hwnd, wParam, lParam); + + case WM_COMMAND: + return k5_handle_wm_command(hwnd, wParam, lParam); + + case KHUI_WM_NC_NOTIFY: + return k5_handle_wmnc_notify(hwnd, wParam, lParam); + + case WM_NOTIFY: + return k5_handle_wm_notify(hwnd, wParam, lParam); + + case WM_DESTROY: + return k5_handle_wm_destroy(hwnd, wParam, lParam); + } + return FALSE; +} + +/* forward dcl */ +krb5_error_code KRB5_CALLCONV +k5_kinit_prompter(krb5_context context, + void *data, + const char *name, + const char *banner, + int num_prompts, + krb5_prompt prompts[]); + + + +fiber_job g_fjob; /* global fiber job object */ + +static BOOL +k5_cached_kinit_prompter(void); + +static BOOL +k5_cp_check_continue(void); + +/* + Runs in the context of the krb5 plugin's slave fiber +*/ +VOID CALLBACK +k5_kinit_fiber_proc(PVOID lpParameter) +{ + while(TRUE) + { + if(g_fjob.command == FIBER_CMD_KINIT) { + g_fjob.state = FIBER_STATE_KINIT; + + g_fjob.prompt_set = 0; + + if (k5_cached_kinit_prompter()) { + SwitchToFiber(k5_main_fiber); + + if (g_fjob.command != FIBER_CMD_CONTINUE) + goto _switch_to_main; + + if (!k5_cp_check_continue()) { + g_fjob.code = KRB5KRB_AP_ERR_BAD_INTEGRITY; + goto _switch_to_main; + } + } + +#ifdef DEBUG + /* log the state of g_fjob.* */ + _reportf(L"g_fjob state prior to calling khm_krb5_kinit() :"); + _reportf(L" g_fjob.principal = [%S]", g_fjob.principal); + _reportf(L" g_fjob.code = %d", g_fjob.code); + _reportf(L" g_fjob.state = %d", g_fjob.state); + _reportf(L" g_fjob.prompt_set= %d", g_fjob.prompt_set); + _reportf(L" g_fjob.valid_principal = %d", (int) g_fjob.valid_principal); +#endif + + /* If we don't know if we have a valid principal, we + restrict the options that are set when we call kinit. + This way we will be able to use the response from the + KDC to verify the principal. */ + + g_fjob.retry_if_valid_principal = (g_fjob.forwardable || + g_fjob.proxiable || + g_fjob.renewable); + + retry_kinit: + g_fjob.code = + khm_krb5_kinit(0, + g_fjob.principal, + g_fjob.password, + g_fjob.ccache, + g_fjob.lifetime, + g_fjob.valid_principal ? g_fjob.forwardable : 0, + g_fjob.valid_principal ? g_fjob.proxiable : 0, + (g_fjob.valid_principal && g_fjob.renewable ? g_fjob.renew_life : 0), + g_fjob.addressless, + g_fjob.publicIP, + k5_kinit_prompter, + &g_fjob); + + /* If the principal was found to be valid, and if we + restricted the options that were being passed to kinit, + then we need to retry the kinit call. This time we use + the real options. */ + if (g_fjob.state == FIBER_STATE_RETRY_KINIT) { +#ifdef DEBUG + assert(g_fjob.valid_principal); +#endif + g_fjob.state = FIBER_STATE_KINIT; + goto retry_kinit; + } + } + + _switch_to_main: + g_fjob.state = FIBER_STATE_NONE; + + SwitchToFiber(k5_main_fiber); + } +} + +/* return TRUE if we should go ahead with creds acquisition */ +static BOOL +k5_cp_check_continue(void) { + khm_size i; + khm_size n_p; + khui_new_creds_prompt * p; + size_t cch; + +#ifdef DEBUG + assert(g_fjob.nc); +#endif + + if (KHM_FAILED(khui_cw_get_prompt_count(g_fjob.nc, &n_p))) { +#ifdef DEBUG + assert(FALSE); +#endif + return TRUE; + } + + khui_cw_sync_prompt_values(g_fjob.nc); + + g_fjob.null_password = FALSE; + + /* we are just checking whether there was a password field that + was left empty, in which case we can't continue with the + credentials acquisition. */ + for (i=0; i < n_p; i++) { + if(KHM_FAILED(khui_cw_get_prompt(g_fjob.nc, + (int) i, + &p))) + continue; + if(p->type == KHUI_NCPROMPT_TYPE_PASSWORD) { + if (p->value == NULL || + FAILED(StringCchLength(p->value, KHUI_MAXCCH_PROMPT, + &cch)) || + cch == 0) { + g_fjob.null_password = TRUE; + return FALSE; + } else + break; + } + } + + return TRUE; +} + +/* returns true if we find cached prompts */ +static BOOL +k5_cached_kinit_prompter(void) { + BOOL rv = FALSE; + khm_handle ident; + khm_handle csp_idconfig = NULL; + khm_handle csp_k5config = NULL; + khm_handle csp_prcache = NULL; + khm_size cb; + khm_size n_cur_prompts; + khm_int32 n_prompts; + khm_int32 i; + khm_int64 iexpiry; + FILETIME expiry; + FILETIME current; + +#ifdef DEBUG + assert(g_fjob.nc); +#endif + + ident = g_fjob.identity; + if (!ident) + return FALSE; + + /* don't need to hold ident, since it is already held in g_fjob + and it doesn't change until we return */ + + if (KHM_FAILED(kcdb_identity_get_config(ident, 0, &csp_idconfig)) || + + KHM_FAILED(khc_open_space(csp_idconfig, CSNAME_KRB5CRED, + 0, &csp_k5config)) || + + KHM_FAILED(khc_open_space(csp_k5config, CSNAME_PROMPTCACHE, + 0, &csp_prcache)) || + + KHM_FAILED(khc_read_int32(csp_prcache, L"PromptCount", + &n_prompts)) || + n_prompts == 0) + + goto _cleanup; + + if (KHM_SUCCEEDED(khc_read_int64(csp_prcache, L"ExpiresOn", &iexpiry))) { + /* has the cache expired? */ + expiry = IntToFt(iexpiry); + GetSystemTimeAsFileTime(¤t); + + if (CompareFileTime(&expiry, ¤t) < 0) + /* already expired */ + goto _cleanup; + } else { + /* if there is no value for ExpiresOn, we assume the prompts + have already expired. */ + goto _cleanup; + } + + /* we found a prompt cache. We take this to imply that the + principal is valid. */ + g_fjob.valid_principal = TRUE; + + /* check if there are any prompts currently showing. If there are + we check if they are the same as the ones we are going to show. + In which case we just reuse the exisitng prompts */ + if (KHM_FAILED(khui_cw_get_prompt_count(g_fjob.nc, + &n_cur_prompts)) || + n_prompts != (khm_int32) n_cur_prompts) + goto _show_new_prompts; + + for(i = 0; i < n_prompts; i++) { + wchar_t wsname[8]; + wchar_t wprompt[KHUI_MAXCCH_PROMPT]; + khm_handle csp_p = NULL; + khm_int32 p_type; + khm_int32 p_flags; + khui_new_creds_prompt * p; + + if (KHM_FAILED(khui_cw_get_prompt(g_fjob.nc, i, &p))) + break; + + StringCbPrintf(wsname, sizeof(wsname), L"%d", i); + + if (KHM_FAILED(khc_open_space(csp_prcache, wsname, 0, &csp_p))) + break; + + cb = sizeof(wprompt); + if (KHM_FAILED(khc_read_string(csp_p, L"Prompt", + wprompt, &cb))) { + khc_close_space(csp_p); + break; + } + + if (KHM_FAILED(khc_read_int32(csp_p, L"Type", &p_type))) + p_type = 0; + + if (KHM_FAILED(khc_read_int32(csp_p, L"Flags", &p_flags))) + p_flags = 0; + + if ( /* if we received a prompt string, + then it should be the same as the + one that is displayed */ + (wprompt[0] && + (p->prompt == NULL || + wcscmp(wprompt, p->prompt))) || + + /* if we didn't receive one, then + there shouldn't be one displayed. + This case really shouldn't happen + in reality, but we check anyway. */ + (!wprompt[0] && + p->prompt != NULL) || + + /* the type should match */ + (p_type != p->type) || + + /* if this prompt should be hidden, + then it must also be so */ + (p_flags != p->flags) + ) { + + khc_close_space(csp_p); + break; + + } + + + khc_close_space(csp_p); + } + + if (i == n_prompts) { + rv = TRUE; + goto _cleanup; + } + + _show_new_prompts: + + khui_cw_clear_prompts(g_fjob.nc); + + { + wchar_t wbanner[KHUI_MAXCCH_BANNER]; + wchar_t wpname[KHUI_MAXCCH_PNAME]; + + cb = sizeof(wbanner); + if (KHM_FAILED(khc_read_string(csp_prcache, L"Banner", + wbanner, &cb))) + wbanner[0] = 0; + + cb = sizeof(wpname); + if (KHM_FAILED(khc_read_string(csp_prcache, L"Name", + wpname, &cb))) + wpname[0] = 0; + + khui_cw_begin_custom_prompts(g_fjob.nc, + n_prompts, + (wbanner[0]? wbanner: NULL), + (wpname[0]? wpname: NULL)); + } + + for(i = 0; i < n_prompts; i++) { + wchar_t wsname[8]; + wchar_t wprompt[KHUI_MAXCCH_PROMPT]; + khm_handle csp_p = NULL; + khm_int32 p_type; + khm_int32 p_flags; + + StringCbPrintf(wsname, sizeof(wsname), L"%d", i); + + if (KHM_FAILED(khc_open_space(csp_prcache, wsname, 0, &csp_p))) + break; + + cb = sizeof(wprompt); + if (KHM_FAILED(khc_read_string(csp_p, L"Prompt", + wprompt, &cb))) { + khc_close_space(csp_p); + break; + } + + if (KHM_FAILED(khc_read_int32(csp_p, L"Type", &p_type))) + p_type = 0; + + if (KHM_FAILED(khc_read_int32(csp_p, L"Flags", &p_flags))) + p_flags = 0; + + khui_cw_add_prompt(g_fjob.nc, p_type, wprompt, NULL, p_flags); + + khc_close_space(csp_p); + } + + if (i < n_prompts) { + khui_cw_clear_prompts(g_fjob.nc); + } else { + rv = TRUE; + } + + _cleanup: + + if (csp_prcache) + khc_close_space(csp_prcache); + + if (csp_k5config) + khc_close_space(csp_k5config); + + if (csp_idconfig) + khc_close_space(csp_idconfig); + + return rv; +} + +/* Runs in the context of the Krb5 plugin's slave fiber */ +krb5_error_code KRB5_CALLCONV +k5_kinit_prompter(krb5_context context, + void *data, + const char *name, + const char *banner, + int num_prompts, + krb5_prompt prompts[]) +{ + int i; + khui_new_creds * nc; + krb5_prompt_type * ptypes; + khm_size ncp; + krb5_error_code code = 0; + BOOL new_prompts = TRUE; + khm_handle csp_prcache = NULL; + +#ifdef DEBUG + _reportf(L"k5_kinit_prompter() received %d prompts with name=[%S] banner=[%S]", + num_prompts, + name, banner); + for (i=0; i < num_prompts; i++) { + _reportf(L"Prompt[%d]: string[%S]", i, prompts[i].prompt); + } +#endif + + /* we got prompts? Then we assume that the principal is valid */ + + if (!g_fjob.valid_principal) { + g_fjob.valid_principal = TRUE; + + /* if the flags that were used to call kinit were restricted + because we didn't know the validity of the principal, then + we need to go back and retry the call with the correct + flags. */ + if (g_fjob.retry_if_valid_principal) { + _reportf(L"Retrying kinit call due to restricted flags on first call."); + g_fjob.state = FIBER_STATE_RETRY_KINIT; + return KRB5_LIBOS_PWDINTR; + } + } + + nc = g_fjob.nc; + + if(pkrb5_get_prompt_types) + ptypes = pkrb5_get_prompt_types(context); + else + ptypes = NULL; + + /* check if we are already showing the right prompts */ + khui_cw_get_prompt_count(nc, &ncp); + + if (num_prompts != (int) ncp) + goto _show_new_prompts; + + for (i=0; i < num_prompts; i++) { + wchar_t wprompt[KHUI_MAXCCH_PROMPT]; + khui_new_creds_prompt * p; + + if(prompts[i].prompt) { + AnsiStrToUnicode(wprompt, sizeof(wprompt), + prompts[i].prompt); + } else { + wprompt[0] = 0; + } + + if (KHM_FAILED(khui_cw_get_prompt(nc, i, &p))) + break; + + if ( /* if we received a prompt string, + then it should be the same as the + one that is displayed */ + (wprompt[0] && + (p->prompt == NULL || + wcscmp(wprompt, p->prompt))) || + /* if we didn't receive one, then + there shouldn't be one displayed. + This case really shouldn't happen + in reality, but we check anyway. */ + (!wprompt[0] && + p->prompt != NULL) || + /* the type should match */ + (ptypes && + ptypes[i] != p->type) || + (!ptypes && + p->type != 0) || + /* if this prompt should be hidden, + then it must also be so */ + (prompts[i].hidden && + !(p->flags & KHUI_NCPROMPT_FLAG_HIDDEN)) || + (!prompts[i].hidden && + (p->flags & KHUI_NCPROMPT_FLAG_HIDDEN)) + ) + break; + } + + if (i < num_prompts) + goto _show_new_prompts; + + new_prompts = FALSE; + + /* ok. looks like we are already showing the same set of prompts + that we were supposed to show. Sync up the values and go + ahead. */ + khui_cw_sync_prompt_values(nc); + goto _process_prompts; + + _show_new_prompts: + /* special case. if there are no actual input controls involved, + then we have to show an alerter window and pass through */ + if (num_prompts == 0) { + wchar_t wbanner[KHUI_MAXCCH_BANNER]; + wchar_t wname[KHUI_MAXCCH_PNAME]; + wchar_t wident[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wmsg[KHUI_MAXCCH_MESSAGE]; + wchar_t wfmt[KHUI_MAXCCH_BANNER]; + khm_size cb; + + if (!banner) { + code = 0; + g_fjob.null_password = FALSE; + goto _exit; + } else { + AnsiStrToUnicode(wbanner, sizeof(wbanner), banner); + } + + if (name) { + AnsiStrToUnicode(wname, sizeof(wname), name); + } else { + LoadString(hResModule, + IDS_KRB5_WARNING, + wname, + ARRAYLENGTH(wname)); + } + + cb = sizeof(wident); + if (KHM_FAILED(kcdb_identity_get_name(g_fjob.identity, wident, &cb))) + wident[0] = L'\0'; + + LoadString(hResModule, + IDS_KRB5_WARN_FMT, + wfmt, + ARRAYLENGTH(wfmt)); + + StringCbPrintf(wmsg, sizeof(wmsg), wfmt, wident, wbanner); + + khui_alert_show_simple(wname, wmsg, KHERR_WARNING); + + code = 0; + g_fjob.null_password = FALSE; + goto _exit; + } + + /* in addition to showing new prompts, we also cache the set of + prompts. */ + if(g_fjob.prompt_set == 0) { + khm_handle csp_idconfig = NULL; + khm_handle csp_idk5 = NULL; + + kcdb_identity_get_config(g_fjob.identity, + KHM_FLAG_CREATE, + &csp_idconfig); + + if (csp_idconfig != NULL) + khc_open_space(csp_idconfig, + CSNAME_KRB5CRED, + KHM_FLAG_CREATE, + &csp_idk5); + + if (csp_idk5 != NULL) + khc_open_space(csp_idk5, + CSNAME_PROMPTCACHE, + KHM_FLAG_CREATE, + &csp_prcache); + + khc_close_space(csp_idconfig); + khc_close_space(csp_idk5); + } + + { + wchar_t wbanner[KHUI_MAXCCH_BANNER]; + wchar_t wname[KHUI_MAXCCH_PNAME]; + FILETIME current; + FILETIME lifetime; + FILETIME expiry; + khm_int64 iexpiry; + khm_int32 t = 0; + + if(banner) + AnsiStrToUnicode(wbanner, sizeof(wbanner), banner); + if(name) + AnsiStrToUnicode(wname, sizeof(wname), name); + + khui_cw_clear_prompts(nc); + + khui_cw_begin_custom_prompts( + nc, + num_prompts, + (banner)?wbanner:NULL, + (name)?wname:NULL); + + if (csp_prcache) { + + if (banner) + khc_write_string(csp_prcache, + L"Banner", + wbanner); + else + khc_write_string(csp_prcache, + L"Banner", + L""); + + if (name) + khc_write_string(csp_prcache, + L"Name", + wname); + else if (csp_prcache) + khc_write_string(csp_prcache, + L"Name", + L""); + + khc_write_int32(csp_prcache, + L"PromptCount", + (khm_int32) num_prompts); + + GetSystemTimeAsFileTime(¤t); +#ifdef USE_PROMPT_CACHE_LIFETIME + khc_read_int32(csp_params, L"PromptCacheLifetime", &t); + if (t == 0) + t = 172800; /* 48 hours */ +#else + khc_read_int32(csp_params, L"MaxRenewLifetime", &t); + if (t == 0) + t = 2592000; /* 30 days */ + t += 604800; /* + 7 days */ +#endif + TimetToFileTimeInterval(t, &lifetime); + expiry = FtAdd(¤t, &lifetime); + iexpiry = FtToInt(&expiry); + + khc_write_int64(csp_prcache, L"ExpiresOn", iexpiry); + } + } + + for(i=0; i < num_prompts; i++) { + wchar_t wprompt[KHUI_MAXCCH_PROMPT]; + + if(prompts[i].prompt) { + AnsiStrToUnicode(wprompt, sizeof(wprompt), + prompts[i].prompt); + } else { + wprompt[0] = 0; + } + + khui_cw_add_prompt( + nc, + (ptypes?ptypes[i]:0), + wprompt, + NULL, + (prompts[i].hidden?KHUI_NCPROMPT_FLAG_HIDDEN:0)); + + if (csp_prcache) { + khm_handle csp_p = NULL; + wchar_t wnum[8]; /* should be enough for 10 + million prompts */ + + wnum[0] = 0; + StringCbPrintf(wnum, sizeof(wnum), L"%d", i); + + khc_open_space(csp_prcache, wnum, + KHM_FLAG_CREATE, &csp_p); + + if (csp_p) { + khc_write_string(csp_p, L"Prompt", wprompt); + khc_write_int32(csp_p, L"Type", (ptypes?ptypes[i]:0)); + khc_write_int32(csp_p, L"Flags", + (prompts[i].hidden? + KHUI_NCPROMPT_FLAG_HIDDEN:0)); + + khc_close_space(csp_p); + } + } + } + + if (csp_prcache) { + khc_close_space(csp_prcache); + csp_prcache = NULL; + } + + _process_prompts: + /* switch back to main thread if we showed new prompts */ + if (new_prompts) + SwitchToFiber(k5_main_fiber); + + /* we get here after the user selects an action that either + cancles the credentials acquisition operation or triggers the + actual acquisition of credentials. */ + if(g_fjob.command != FIBER_CMD_CONTINUE && + g_fjob.command != FIBER_CMD_KINIT) { + code = KRB5_LIBOS_PWDINTR; + goto _exit; + } + + g_fjob.null_password = FALSE; + + /* otherwise, we need to get the data back from the UI and + return 0 */ + for(i=0; idata, d->length, wbuf); + if(SUCCEEDED(StringCchLengthA(d->data, d->length, &cch))) + d->length = (unsigned int) cch; + else + d->length = 0; + } else { +#ifdef DEBUG + assert(FALSE); +#endif + d->length = 0; + } + + if (ptypes && + ptypes[i] == KRB5_PROMPT_TYPE_PASSWORD && + d->length == 0) + + g_fjob.null_password = TRUE; + } + + _exit: + + g_fjob.prompt_set++; + + /* entering a NULL password is equivalent to cancelling out */ + if (g_fjob.null_password) + return KRB5_LIBOS_PWDINTR; + else + return code; +} + + +void +k5_read_dlg_params(k5_dlg_data * d, khm_handle identity) +{ + k5_params p; + + khm_krb5_get_identity_params(identity, &p); + + d->renewable = p.renewable; + d->forwardable = p.forwardable; + d->proxiable = p.proxiable; + d->addressless = p.addressless; + d->publicIP = p.publicIP; + + d->tc_lifetime.current = p.lifetime; + d->tc_lifetime.max = p.lifetime_max; + d->tc_lifetime.min = p.lifetime_min; + + d->tc_renew.current = p.renew_life; + d->tc_renew.max = p.renew_life_max; + d->tc_renew.min = p.renew_life_min; + + /* however, if this has externally supplied defaults, we have to + use them too. */ + if (d->nc && d->nc->ctx.vparam && + d->nc->ctx.cb_vparam == sizeof(NETID_DLGINFO)) { + LPNETID_DLGINFO pdlginfo; + + pdlginfo = (LPNETID_DLGINFO) d->nc->ctx.vparam; + if (pdlginfo->size == NETID_DLGINFO_V1_SZ && + pdlginfo->in.use_defaults == 0) { + d->forwardable = pdlginfo->in.forwardable; + d->addressless = pdlginfo->in.noaddresses; + d->tc_lifetime.current = pdlginfo->in.lifetime; + d->tc_renew.current = pdlginfo->in.renew_till; + + if (pdlginfo->in.renew_till == 0) + d->renewable = FALSE; + else + d->renewable = TRUE; + + d->proxiable = pdlginfo->in.proxiable; + d->publicIP = pdlginfo->in.publicip; + } + } + + /* once we read the new data, in, it is no longer considered + dirty */ + d->dirty = FALSE; + d->sync = FALSE; +} + +void +k5_write_dlg_params(k5_dlg_data * d, khm_handle identity) +{ + + k5_params p; + + ZeroMemory(&p, sizeof(p)); + + p.source_reg = K5PARAM_FM_ALL; /* we want to write all the + settings to the registry, if + necessary. */ + + p.renewable = d->renewable; + p.forwardable = d->forwardable; + p.proxiable = d->proxiable; + p.addressless = d->addressless; + p.publicIP = d->publicIP; + + p.lifetime = (krb5_deltat) d->tc_lifetime.current; + p.lifetime_max = (krb5_deltat) d->tc_lifetime.max; + p.lifetime_min = (krb5_deltat) d->tc_lifetime.min; + + p.renew_life = (krb5_deltat) d->tc_renew.current; + p.renew_life_max = (krb5_deltat) d->tc_renew.max; + p.renew_life_min = (krb5_deltat) d->tc_renew.min; + + khm_krb5_set_identity_params(identity, &p); + + /* as in k5_read_dlg_params, once we write the data in, the local + data is no longer dirty */ + d->dirty = FALSE; +} + +void +k5_free_kinit_job(void) +{ + if (g_fjob.principal) + PFREE(g_fjob.principal); + + if (g_fjob.password) + PFREE(g_fjob.password); + + if (g_fjob.identity) + kcdb_identity_release(g_fjob.identity); + + if (g_fjob.ccache) + PFREE(g_fjob.ccache); + + ZeroMemory(&g_fjob, sizeof(g_fjob)); +} + +void +k5_prep_kinit_job(khui_new_creds * nc) +{ + khui_new_creds_by_type * nct; + k5_dlg_data * d; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cbbuf; + size_t size; + khm_handle ident; + LPNETID_DLGINFO pdlginfo; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + if (!nct) + return; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + + if (!d) + return; + + khui_cw_lock_nc(nc); + ident = nc->identities[0]; + kcdb_identity_hold(ident); + khui_cw_unlock_nc(nc); + + cbbuf = sizeof(idname); + kcdb_identity_get_name(ident, idname, &cbbuf); + StringCchLength(idname, ARRAYLENGTH(idname), &size); + size++; + + k5_free_kinit_job(); + + g_fjob.command = FIBER_CMD_KINIT; + g_fjob.nc = nc; + g_fjob.nct = nct; + g_fjob.dialog = nct->hwnd_panel; + g_fjob.principal = PMALLOC(size); + UnicodeStrToAnsi(g_fjob.principal, size, idname); + g_fjob.password = NULL; + g_fjob.lifetime = (krb5_deltat) d->tc_lifetime.current; + g_fjob.forwardable = d->forwardable; + g_fjob.proxiable = d->proxiable; + g_fjob.renewable = d->renewable; + g_fjob.renew_life = (krb5_deltat) d->tc_renew.current; + g_fjob.addressless = d->addressless; + g_fjob.publicIP = d->publicIP; + g_fjob.code = 0; + g_fjob.identity = ident; + g_fjob.prompt_set = 0; + g_fjob.valid_principal = FALSE; + g_fjob.retry_if_valid_principal = FALSE; + + /* the value for + retry_if_valid_principal is not + necessarily the correct value here, + but the correct value will be + assigned k5_kinit_fiber_proc(). */ + + /* if we have external parameters, we should use them as well */ + if (nc->ctx.cb_vparam == sizeof(NETID_DLGINFO) && + (pdlginfo = nc->ctx.vparam) && + pdlginfo->size == NETID_DLGINFO_V1_SZ) { + wchar_t * t; + + if (pdlginfo->in.ccache[0] && + SUCCEEDED(StringCchLength(pdlginfo->in.ccache, + NETID_CCACHE_NAME_SZ, + &size))) { + g_fjob.ccache = PMALLOC(sizeof(char) * (size + 1)); +#ifdef DEBUG + assert(g_fjob.ccache); +#endif + UnicodeStrToAnsi(g_fjob.ccache, size + 1, + pdlginfo->in.ccache); + + /* this is the same as the output cache */ + + StringCbCopy(pdlginfo->out.ccache, sizeof(pdlginfo->out.ccache), + pdlginfo->in.ccache); + } else { + g_fjob.ccache = NULL; + + StringCbCopy(pdlginfo->out.ccache, sizeof(pdlginfo->out.ccache), + idname); + + khm_krb5_canon_cc_name(pdlginfo->out.ccache, + sizeof(pdlginfo->out.ccache)); + } + + t = khm_get_realm_from_princ(idname); + + if (t) { + StringCbCopy(pdlginfo->out.realm, + sizeof(pdlginfo->out.realm), + t); + + if ((t - idname) > 1) { + StringCchCopyN(pdlginfo->out.username, + ARRAYLENGTH(pdlginfo->out.username), + idname, + (t - idname) - 1); + } else { + StringCbCopy(pdlginfo->out.username, + sizeof(pdlginfo->out.username), + L""); + } + } else { + StringCbCopy(pdlginfo->out.username, + sizeof(pdlginfo->out.username), + idname); + StringCbCopy(pdlginfo->out.realm, + sizeof(pdlginfo->out.realm), + L""); + } + } + + /* leave identity held, since we added a reference above */ +} + +static khm_int32 KHMAPI +k5_find_tgt_filter(khm_handle cred, + khm_int32 flags, + void * rock) { + khm_handle ident = (khm_handle) rock; + khm_handle cident = NULL; + khm_int32 f; + khm_int32 rv; + + if (KHM_SUCCEEDED(kcdb_cred_get_identity(cred, + &cident)) && + cident == ident && + KHM_SUCCEEDED(kcdb_cred_get_flags(cred, &f)) && + (f & KCDB_CRED_FLAG_INITIAL) && + !(f & KCDB_CRED_FLAG_EXPIRED)) + rv = 1; + else + rv = 0; + + if (cident) + kcdb_identity_release(cident); + + return rv; +} + +khm_int32 +k5_remove_from_LRU(khm_handle identity) +{ + wchar_t * wbuf = NULL; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khm_size cb_ms; + khm_int32 rv = KHM_ERROR_SUCCESS; + + cb = sizeof(idname); + rv = kcdb_identity_get_name(identity, idname, &cb); + assert(rv == KHM_ERROR_SUCCESS); + + rv = khc_read_multi_string(csp_params, L"LRUPrincipals", NULL, &cb_ms); + if (rv != KHM_ERROR_TOO_LONG) + cb_ms = sizeof(wchar_t) * 2; + + wbuf = PMALLOC(cb_ms); + assert(wbuf); + + cb = cb_ms; + + if (rv == KHM_ERROR_TOO_LONG) { + rv = khc_read_multi_string(csp_params, L"LRUPrincipals", wbuf, &cb); + assert(KHM_SUCCEEDED(rv)); + + if (multi_string_find(wbuf, idname, KHM_CASE_SENSITIVE) != NULL) { + multi_string_delete(wbuf, idname, KHM_CASE_SENSITIVE); + } + } else { + multi_string_init(wbuf, cb_ms); + } + + rv = khc_write_multi_string(csp_params, L"LRUPrincipals", wbuf); + + if (wbuf) + PFREE(wbuf); + + return rv; +} + +khm_int32 +k5_update_LRU(khm_handle identity) +{ + wchar_t * wbuf = NULL; + wchar_t * idname = NULL; + wchar_t * realm = NULL; + khm_size cb; + khm_size cb_ms; + khm_int32 rv = KHM_ERROR_SUCCESS; + + rv = kcdb_identity_get_name(identity, NULL, &cb); + assert(rv == KHM_ERROR_TOO_LONG); + + idname = PMALLOC(cb); + assert(idname); + + rv = kcdb_identity_get_name(identity, idname, &cb); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_read_multi_string(csp_params, L"LRUPrincipals", NULL, &cb_ms); + if (rv != KHM_ERROR_TOO_LONG) + cb_ms = cb + sizeof(wchar_t); + else + cb_ms += cb + sizeof(wchar_t); + + wbuf = PMALLOC(cb_ms); + assert(wbuf); + + cb = cb_ms; + + if (rv == KHM_ERROR_TOO_LONG) { + rv = khc_read_multi_string(csp_params, L"LRUPrincipals", wbuf, &cb); + assert(KHM_SUCCEEDED(rv)); + + if (multi_string_find(wbuf, idname, KHM_CASE_SENSITIVE) != NULL) { + /* it's already there. We remove it here and add it at + the top of the LRU list. */ + multi_string_delete(wbuf, idname, KHM_CASE_SENSITIVE); + } + } else { + multi_string_init(wbuf, cb_ms); + } + + cb = cb_ms; + rv = multi_string_prepend(wbuf, &cb, idname); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_write_multi_string(csp_params, L"LRUPrincipals", wbuf); + + realm = khm_get_realm_from_princ(idname); + if (realm == NULL || *realm == L'\0') + goto _done_with_LRU; + + cb = cb_ms; + rv = khc_read_multi_string(csp_params, L"LRURealms", wbuf, &cb); + + if (rv == KHM_ERROR_TOO_LONG) { + PFREE(wbuf); + wbuf = PMALLOC(cb); + assert(wbuf); + + cb_ms = cb; + + rv = khc_read_multi_string(csp_params, L"LRURealms", wbuf, &cb); + + assert(KHM_SUCCEEDED(rv)); + } else if (rv == KHM_ERROR_SUCCESS) { + if (multi_string_find(wbuf, realm, KHM_CASE_SENSITIVE) != NULL) { + /* remove the realm and add it at the top later. */ + multi_string_delete(wbuf, realm, KHM_CASE_SENSITIVE); + } + } else { + multi_string_init(wbuf, cb_ms); + } + + cb = cb_ms; + rv = multi_string_prepend(wbuf, &cb, realm); + + if (rv == KHM_ERROR_TOO_LONG) { + wbuf = PREALLOC(wbuf, cb); + + rv = multi_string_prepend(wbuf, &cb, realm); + + assert(KHM_SUCCEEDED(rv)); + } + + rv = khc_write_multi_string(csp_params, L"LRURealms", wbuf); + + assert(KHM_SUCCEEDED(rv)); + + _done_with_LRU: + + if (wbuf) + PFREE(wbuf); + if (idname) + PFREE(idname); + + return rv; +} + +/* Handler for CRED type messages + + Runs in the context of the Krb5 plugin +*/ +khm_int32 KHMAPI +k5_msg_cred_dialog(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + + case KMSG_CRED_PASSWORD: + case KMSG_CRED_NEW_CREDS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + wchar_t wbuf[256]; + size_t cbsize; + + nc = (khui_new_creds *) vparam; + + nct = PMALLOC(sizeof(*nct)); + ZeroMemory(nct, sizeof(*nct)); + + nct->type = credtype_id_krb5; + nct->ordinal = 1; + + LoadString(hResModule, IDS_KRB5_NC_NAME, + wbuf, ARRAYLENGTH(wbuf)); + StringCbLength(wbuf, sizeof(wbuf), &cbsize); + cbsize += sizeof(wchar_t); + + nct->name = PMALLOC(cbsize); + StringCbCopy(nct->name, cbsize, wbuf); + + nct->h_module = hResModule; + nct->dlg_proc = k5_nc_dlg_proc; + if (nc->subtype == KMSG_CRED_PASSWORD) + nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB5_PASSWORD); + else + nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB5); + + khui_cw_add_type(nc, nct); + } + break; + + case KMSG_CRED_RENEW_CREDS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + + nc = (khui_new_creds *) vparam; + + nct = PMALLOC(sizeof(*nct)); + ZeroMemory(nct, sizeof(*nct)); + + nct->type = credtype_id_krb5; + + khui_cw_add_type(nc, nct); + } + break; + + case KMSG_CRED_DIALOG_PRESTART: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + k5_dlg_data * d; + HWND hwnd; + wchar_t * realms; + wchar_t * t; + wchar_t * defrealm; + + nc = (khui_new_creds *) vparam; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + + if(!nct) + break; + + hwnd = nct->hwnd_panel; + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + + /* this can be NULL if the dialog was closed while the + plug-in thread was processing. */ + if (d == NULL) + break; + + if (!is_k5_identpro) { + + /* enumerate all realms and place in realms combo box */ + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_RESETCONTENT, + 0, 0); + + realms = khm_krb5_get_realm_list(); + if(realms) { + for (t = realms; t && *t; t = multi_string_next(t)) { + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_ADDSTRING, + 0, (LPARAM) t); + } + PFREE(realms); + } + + /* and set the default realm */ + defrealm = khm_krb5_get_default_realm(); + if(defrealm) { + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) defrealm); + + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + WM_SETTEXT, + 0, (LPARAM) defrealm); + PFREE(defrealm); + } + } else { /* if krb5 is the identity provider */ + HWND hw_realms; + + /* in this case, the realm selection is done by the + identity provider prompts. */ + + hw_realms = GetDlgItem(hwnd, IDC_NCK5_REALM); +#ifdef DEBUG + assert(hw_realms); +#endif + EnableWindow(hw_realms, FALSE); + } + + if (nc->subtype == KMSG_CRED_NEW_CREDS) { + k5_read_dlg_params(d, NULL); + } + + PostMessage(hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0); + } + break; + + case KMSG_CRED_DIALOG_NEW_IDENTITY: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + k5_dlg_data * d; + + nc = (khui_new_creds *) vparam; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + if (!nct) + break; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + + if (d == NULL) + break; + + /* we only load the identity specific defaults if the user + hasn't changed the options */ + khui_cw_lock_nc(nc); + + /* ?: 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) { + + k5_read_dlg_params(d, nc->identities[0]); + + PostMessage(nct->hwnd_panel, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0); + } + + khui_cw_unlock_nc(nc); + + /* reset the force-password-change flag if this is a new + identity. */ + d->pwd_change = FALSE; + } + + /* fallthrough */ + case KMSG_CRED_DIALOG_NEW_OPTIONS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + k5_dlg_data * d; + + nc = (khui_new_creds *) vparam; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + if (!nct) + break; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + if (d == NULL) + break; + + if (nc->subtype == KMSG_CRED_PASSWORD) { + khm_size n_prompts = 0; + + khui_cw_get_prompt_count(nc, &n_prompts); + + if (nc->n_identities == 0) { + if (n_prompts) + khui_cw_clear_prompts(nc); + } else if (n_prompts != 3) { + wchar_t wbuf[KHUI_MAXCCH_BANNER]; + + khui_cw_clear_prompts(nc); + + LoadString(hResModule, IDS_NC_PWD_BANNER, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_begin_custom_prompts(nc, 3, NULL, wbuf); + + LoadString(hResModule, IDS_NC_PWD_PWD, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_PASSWORD, + wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); + + LoadString(hResModule, IDS_NC_PWD_NPWD, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_NEW_PASSWORD, + wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); + + LoadString(hResModule, IDS_NC_PWD_NPWD_AGAIN, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_NEW_PASSWORD_AGAIN, + wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); + } + + return KHM_ERROR_SUCCESS; + } + /* else; nc->subtype == KMSG_CRED_NEW_CREDS */ + + assert(nc->subtype == KMSG_CRED_NEW_CREDS); + + /* If we are forcing a password change, then we don't do + anything here. Note that if the identity changed, then + this field would have been reset, so we would proceed + as usual. */ + if (d->pwd_change) + return KHM_ERROR_SUCCESS; + +#if 0 + /* Clearing the prompts at this point is a bad idea since + the prompter depends on the prompts to know if this set + of prompts is the same as the new set and if so, use + the values entered in the old prompts as responses to + the new one. */ + khui_cw_clear_prompts(nc); +#endif + + /* if the fiber is already in a kinit, cancel it */ + if(g_fjob.state == FIBER_STATE_KINIT) { + g_fjob.command = FIBER_CMD_CANCEL; + SwitchToFiber(k5_kinit_fiber); + /* we get here when the cancel operation completes */ + k5_free_kinit_job(); + } + + khui_cw_lock_nc(nc); + + if(nc->n_identities > 0) { + khm_handle ident = nc->identities[0]; + + kcdb_identity_hold(ident); + + k5_prep_kinit_job(nc); + + /* after the switch to the fiber, the dialog will be + back in sync with the kinit thread. */ + d->sync = TRUE; + + khui_cw_unlock_nc(nc); + + SwitchToFiber(k5_kinit_fiber); + /* we get here when the fiber switches back */ + if(g_fjob.state == FIBER_STATE_NONE) { + wchar_t msg[KHUI_MAXCCH_BANNER]; + khm_size cb; + + /* Special case. If the users' password has + expired, we force a password change dialog on + top of the new credentials dialog using a set + of custom prompts, but only if we are the + identity provider. */ + if (g_fjob.code == KRB5KDC_ERR_KEY_EXP && + is_k5_identpro) { + + k5_force_password_change(d); + goto done_with_bad_princ; + + } + + /* we can't possibly have succeeded without a + password */ + if(g_fjob.code == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN && + is_k5_identpro) { + kcdb_identity_set_flags(ident, + KCDB_IDENT_FLAG_INVALID, + KCDB_IDENT_FLAG_INVALID); + + khui_cw_clear_prompts(nc); + } + + if (d->cred_message) { + PFREE(d->cred_message); + d->cred_message = NULL; + } + + msg[0] = L'\0'; + + switch(g_fjob.code) { + case KRB5KDC_ERR_NAME_EXP: + /* principal expired */ + LoadString(hResModule, IDS_K5ERR_NAME_EXPIRED, + msg, ARRAYLENGTH(msg)); + break; + + case KRB5KDC_ERR_KEY_EXP: + { + /* password needs changing. */ + LoadString(hResModule, IDS_K5ERR_KEY_EXPIRED, + msg, ARRAYLENGTH(msg)); + } + break; + + default: + { + DWORD dw_dummy; + kherr_suggestion sug_dummy; + wchar_t fmt[KHUI_MAXCCH_BANNER]; + wchar_t desc[KHUI_MAXCCH_BANNER]; + + LoadString(hResModule, IDS_K5ERR_FMT, + fmt, ARRAYLENGTH(fmt)); + + khm_err_describe(g_fjob.code, + desc, + sizeof(desc), + &dw_dummy, + &sug_dummy); + + StringCbPrintf(msg, sizeof(msg), fmt, desc); + } + } + + if (msg[0]) { + StringCbLength(msg, sizeof(msg), &cb); + cb += sizeof(wchar_t); + + d->cred_message = PMALLOC(cb); + StringCbCopy(d->cred_message, cb, msg); + } + + done_with_bad_princ: + + k5_free_kinit_job(); + + if (is_k5_identpro) + kcdb_identity_set_flags(ident, + KCDB_IDENT_FLAG_UNKNOWN, + KCDB_IDENT_FLAG_UNKNOWN); + + + } else if(g_fjob.state == FIBER_STATE_KINIT) { + /* this is what we want. Leave the fiber there. */ + + if(is_k5_identpro) + kcdb_identity_set_flags(ident, + KCDB_IDENT_FLAG_VALID, + KCDB_IDENT_FLAG_VALID); + } else { + /* huh?? */ +#ifdef DEBUG + assert(FALSE); +#endif + } + + /* since the attributes of the identity have changed, + we should update the cred text as well */ + kcdb_identity_release(ident); + khui_cw_lock_nc(nc); + PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0); + } else { + khui_cw_unlock_nc(nc); + khui_cw_clear_prompts(nc); + khui_cw_lock_nc(nc); + } + + khui_cw_unlock_nc(nc); + } + break; + + case KMSG_CRED_PROCESS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + k5_dlg_data * d; + + khm_int32 r = 0; + + nc = (khui_new_creds *) vparam; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + + if(!nct) + break; + + /* reset the null_password flag, just in case */ + g_fjob.null_password = FALSE; + + if (nc->subtype == KMSG_CRED_NEW_CREDS) { + d = (k5_dlg_data *) nct->aux; + if (d == NULL) + break; + + if (d->pwd_change) { + /* we are forcing a password change */ + goto change_password; + } + + _begin_task(0); + _report_mr0(KHERR_NONE, MSG_CTX_INITAL_CREDS); + _describe(); + + if (g_fjob.state == FIBER_STATE_KINIT) { + if(nc->result == KHUI_NC_RESULT_CANCEL) { + g_fjob.command = FIBER_CMD_CANCEL; + SwitchToFiber(k5_kinit_fiber); + + /* if we cancelled out, then we shouldn't care + about the return code. */ +#ifdef DEBUG + assert(g_fjob.state == FIBER_STATE_NONE); +#endif + g_fjob.code = 0; + + _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); + + /* We get back here once the fiber finishes + processing */ + } +#ifdef DEBUG + else { + assert(FALSE); + } +#endif + } else { + /* we weren't in a KINIT state */ + if (nc->result == KHUI_NC_RESULT_CANCEL) { + /* nothing to report */ + g_fjob.code = 0; + } else if (nc->result == KHUI_NC_RESULT_PROCESS) { + /* g_fjob.code should have the result of the + last kinit attempt. We should leave it + as-is */ + } +#ifdef DEBUG + else { + /* unknown result */ + assert(FALSE); + } +#endif + } + + /* special case: if there was no password entered, and + if there is a valid TGT we allow the credential + acquisition to go through */ + if (g_fjob.state == FIBER_STATE_NONE && + g_fjob.code && + g_fjob.null_password && + + (nc->n_identities == 0 || + nc->identities[0] == NULL || + KHM_SUCCEEDED(kcdb_credset_find_filtered + (NULL, + -1, + k5_find_tgt_filter, + nc->identities[0], + NULL, + NULL)))) { + _reportf(L"No password entered, but a valid TGT exists. Continuing"); + g_fjob.code = 0; + } else if (g_fjob.state == FIBER_STATE_NONE && + g_fjob.code == 0 && + nc->n_identities > 0 && + nc->identities[0] != NULL) { + + /* we had a password and we used it to get + tickets. We should reset the IMPORTED flag now + since the tickets are not imported. */ + + khm_krb5_set_identity_flags(nc->identities[0], + K5IDFLAG_IMPORTED, + 0); + } + + if(g_fjob.code != 0) { + wchar_t tbuf[1024]; + DWORD suggestion; + kherr_suggestion suggest_code; + + khm_err_describe(g_fjob.code, tbuf, sizeof(tbuf), + &suggestion, &suggest_code); + + _report_cs0(KHERR_ERROR, tbuf); + if (suggestion != 0) + _suggest_mr(suggestion, suggest_code); + + _resolve(); + + r = KHUI_NC_RESPONSE_FAILED; + + if (suggest_code == KHERR_SUGGEST_RETRY) { + r |= KHUI_NC_RESPONSE_NOEXIT | + KHUI_NC_RESPONSE_PENDING; + } + +#ifdef DEBUG + assert(g_fjob.state == FIBER_STATE_NONE); +#endif + + if (g_fjob.valid_principal && + nc->n_identities > 0 && + nc->identities[0]) { + /* the principal was valid, so we can go ahead + and update the LRU */ + k5_update_LRU(nc->identities[0]); + } + + } else if (nc->result == KHUI_NC_RESULT_PROCESS && + g_fjob.state == FIBER_STATE_NONE) { + krb5_context ctx = NULL; + + _reportf(L"Tickets successfully acquired"); + + r = KHUI_NC_RESPONSE_SUCCESS | + KHUI_NC_RESPONSE_EXIT; + + /* if we successfully obtained credentials, we + should save the current settings in the + identity config space */ + + assert(nc->n_identities > 0); + assert(nc->identities[0]); + + k5_write_dlg_params(d, nc->identities[0]); + + /* We should also quickly refresh the credentials + so that the identity flags and ccache + properties reflect the current state of + affairs. This has to be done here so that + other credentials providers which depend on + Krb5 can properly find the initial creds to + obtain their respective creds. */ + + khm_krb5_list_tickets(&ctx); + + if (nc->set_default) { + _reportf(L"Setting default identity"); + kcdb_identity_set_default(nc->identities[0]); + } + + /* If there is no default identity, then make this the default */ + kcdb_identity_refresh(nc->identities[0]); + { + khm_handle tdefault = NULL; + + 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]); + } + } + + /* and update the LRU */ + k5_update_LRU(nc->identities[0]); + + if (ctx != NULL) + pkrb5_free_context(ctx); + } else if (g_fjob.state == FIBER_STATE_NONE) { + /* the user cancelled the operation */ + r = KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_SUCCESS; + } + + if(g_fjob.state == FIBER_STATE_NONE) { + khui_cw_set_response(nc, credtype_id_krb5, r); + + if (r & KHUI_NC_RESPONSE_NOEXIT) { + /* if we are retrying the call, we should + restart the kinit fiber */ +#ifdef DEBUG + assert(r & KHUI_NC_RESPONSE_PENDING); +#endif + + k5_prep_kinit_job(nc); + SwitchToFiber(k5_kinit_fiber); + } else { + /* free up the fiber data fields. */ + k5_free_kinit_job(); + } + } else { + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_NOEXIT | + KHUI_NC_RESPONSE_PENDING | r); + } + + _end_task(); + } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { + + FILETIME ftidexp = {0,0}; + FILETIME ftcurrent; + khm_size cb; + + GetSystemTimeAsFileTime(&ftcurrent); + + _begin_task(0); + _report_mr0(KHERR_NONE, MSG_CTX_RENEW_CREDS); + _describe(); + + if (nc->ctx.scope == KHUI_SCOPE_IDENT || + (nc->ctx.scope == KHUI_SCOPE_CREDTYPE && + nc->ctx.cred_type == credtype_id_krb5) || + (nc->ctx.scope == KHUI_SCOPE_CRED && + nc->ctx.cred_type == credtype_id_krb5)) { + int code; + + 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); + + kcdb_identity_get_attr(nc->ctx.identity, + KCDB_ATTR_EXPIRE, + NULL, + &ftidexp, + &cb); + + 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); + } else if (nc->ctx.identity == 0) { + + _report_mr0(KHERR_ERROR, MSG_ERR_NO_IDENTITY); + + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_FAILED); + } else if (CompareFileTime(&ftcurrent, &ftidexp) < 0) { + wchar_t tbuf[1024]; + DWORD suggestion; + kherr_suggestion sug_id; + + /* if we failed to get new tickets, but the + identity is still valid, then we assume that + the current tickets are still good enough + for other credential types to obtain their + credentials. */ + + khm_err_describe(code, tbuf, sizeof(tbuf), + &suggestion, &sug_id); + + _report_cs0(KHERR_WARNING, tbuf); + if (suggestion) + _suggest_mr(suggestion, sug_id); + + _resolve(); + + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_SUCCESS); + } else { + wchar_t tbuf[1024]; + DWORD suggestion; + kherr_suggestion sug_id; + + khm_err_describe(code, tbuf, sizeof(tbuf), + &suggestion, &sug_id); + + _report_cs0(KHERR_ERROR, tbuf); + if (suggestion) + _suggest_mr(suggestion, sug_id); + + _resolve(); + + khui_cw_set_response(nc, credtype_id_krb5, + ((sug_id == KHERR_SUGGEST_RETRY)?KHUI_NC_RESPONSE_NOEXIT:KHUI_NC_RESPONSE_EXIT) | + KHUI_NC_RESPONSE_FAILED); + } + } else { + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_SUCCESS); + } + + _end_task(); + } else if (nc->subtype == KMSG_CRED_PASSWORD && + nc->result == KHUI_NC_RESULT_PROCESS) { + + change_password: + /* we jump here if there was a password change forced */ + + _begin_task(0); + _report_mr0(KHERR_NONE, MSG_CTX_PASSWD); + _describe(); + + khui_cw_lock_nc(nc); + + if (nc->result == KHUI_NC_RESULT_CANCEL) { + + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_SUCCESS | + KHUI_NC_RESPONSE_EXIT); + + } else if (nc->n_identities == 0 || + nc->identities[0] == NULL) { + _report_mr0(KHERR_ERROR, MSG_PWD_NO_IDENTITY); + _suggest_mr(MSG_PWD_S_NO_IDENTITY, KHERR_SUGGEST_RETRY); + + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_FAILED | + KHUI_NC_RESPONSE_NOEXIT); + + } else { + wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; + char idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wpwd[KHUI_MAXCCH_PASSWORD]; + char pwd[KHUI_MAXCCH_PASSWORD]; + wchar_t wnpwd[KHUI_MAXCCH_PASSWORD]; + char npwd[KHUI_MAXCCH_PASSWORD]; + wchar_t wnpwd2[KHUI_MAXCCH_PASSWORD]; + wchar_t * wresult; + char * result; + khm_size n_prompts = 0; + khm_size cb; + khm_int32 rv = KHM_ERROR_SUCCESS; + long code = 0; + khm_handle ident; + + khui_cw_get_prompt_count(nc, &n_prompts); + assert(n_prompts == 3); + + ident = nc->identities[0]; + cb = sizeof(widname); + rv = kcdb_identity_get_name(ident, widname, &cb); + if (KHM_FAILED(rv)) { +#ifdef DEBUG + assert(FALSE); +#endif + _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); + goto _pwd_exit; + } + + cb = sizeof(wpwd); + rv = khui_cw_get_prompt_value(nc, 0, wpwd, &cb); + if (KHM_FAILED(rv)) { +#ifdef DEBUG + assert(FALSE); +#endif + _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); + goto _pwd_exit; + } + + cb = sizeof(wnpwd); + rv = khui_cw_get_prompt_value(nc, 1, wnpwd, &cb); + if (KHM_FAILED(rv)) { +#ifdef DEBUG + assert(FALSE); +#endif + _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); + goto _pwd_exit; + } + + cb = sizeof(wnpwd2); + rv = khui_cw_get_prompt_value(nc, 2, wnpwd2, &cb); + if (KHM_FAILED(rv)) { +#ifdef DEBUG + assert(FALSE); +#endif + _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); + goto _pwd_exit; + } + + if (wcscmp(wnpwd, wnpwd2)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr0(KHERR_ERROR, MSG_PWD_NOT_SAME); + _suggest_mr(MSG_PWD_S_NOT_SAME, KHERR_SUGGEST_INTERACT); + goto _pwd_exit; + } + + if (!wcscmp(wpwd, wnpwd)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr0(KHERR_ERROR, MSG_PWD_SAME); + _suggest_mr(MSG_PWD_S_SAME, KHERR_SUGGEST_INTERACT); + goto _pwd_exit; + } + + UnicodeStrToAnsi(idname, sizeof(idname), widname); + UnicodeStrToAnsi(pwd, sizeof(pwd), wpwd); + UnicodeStrToAnsi(npwd, sizeof(npwd), wnpwd); + + result = NULL; + + code = khm_krb5_changepwd(idname, + pwd, + npwd, + &result); + + if (code) + rv = KHM_ERROR_UNKNOWN; + else { + khm_handle csp_idcfg = NULL; + krb5_context ctx = NULL; + + /* we set a new password. now we need to get + initial credentials. */ + + d = (k5_dlg_data *) nct->aux; + + if (d == NULL) { + rv = KHM_ERROR_UNKNOWN; + goto _pwd_exit; + } + + if (nc->subtype == KMSG_CRED_PASSWORD) { + /* since this was just a password change, + we need to load new credentials options + from the configuration store. */ + + k5_read_dlg_params(d, nc->identities[0]); + } + + /* the password change phase is now done */ + d->pwd_change = FALSE; + +#ifdef DEBUG + _reportf(L"Calling khm_krb5_kinit()"); +#endif + code = khm_krb5_kinit(NULL, /* context (create one) */ + idname, /* principal_name */ + npwd, /* new password */ + NULL, /* ccache name (figure out the identity cc)*/ + (krb5_deltat) d->tc_lifetime.current, + d->forwardable, + d->proxiable, + (krb5_deltat)((d->renewable)?d->tc_renew.current:0), + d->addressless, /* addressless */ + d->publicIP, /* public IP */ + NULL, /* prompter */ + NULL /* prompter data */); + + if (code) { + rv = KHM_ERROR_UNKNOWN; + goto _pwd_exit; + } + + /* save the settings that we used for + obtaining the ticket. */ + if (nc->subtype == KMSG_CRED_NEW_CREDS) { + + k5_write_dlg_params(d, nc->identities[0]); + + /* and then update the LRU too */ + k5_update_LRU(nc->identities[0]); + } + + /* and do a quick refresh of the krb5 tickets + so that other plug-ins that depend on krb5 + can look up tickets inside NetIDMgr */ + khm_krb5_list_tickets(&ctx); + + /* if there was no default identity, we make + this one the default. */ + kcdb_identity_refresh(nc->identities[0]); + { + khm_handle tdefault = NULL; + + if (KHM_SUCCEEDED(kcdb_identity_get_default(&tdefault))) { + kcdb_identity_release(tdefault); + } else { + _reportf(L"There was no default identity. Setting defualt"); + kcdb_identity_set_default(nc->identities[0]); + } + } + + if (ctx != NULL) + pkrb5_free_context(ctx); + + if (nc->subtype == KMSG_CRED_PASSWORD) { + /* if we obtained new credentials as a + result of successfully changing the + password, we also schedule an identity + renewal for this identity. This allows + the other credential types to obtain + credentials for this identity. */ + khui_action_context ctx; + + _reportf(L"Scheduling renewal of [%s] after password change", + widname); + + khui_context_create(&ctx, + KHUI_SCOPE_IDENT, + nc->identities[0], + KCDB_CREDTYPE_INVALID, + NULL); + khui_action_trigger(KHUI_ACTION_RENEW_CRED, + &ctx); + + khui_context_release(&ctx); + } + } + + /* result is only set when code != 0 */ + if (code && result) { + size_t len; + + StringCchLengthA(result, KHERR_MAXCCH_STRING, + &len); + wresult = PMALLOC((len + 1) * sizeof(wchar_t)); +#ifdef DEBUG + assert(wresult); +#endif + AnsiStrToUnicode(wresult, (len + 1) * sizeof(wchar_t), + result); + + _report_cs1(KHERR_ERROR, L"%1!s!", _cstr(wresult)); + _resolve(); + + PFREE(result); + PFREE(wresult); + + /* we don't need to report anything more */ + code = 0; + } + + _pwd_exit: + if (KHM_FAILED(rv)) { + if (code) { + wchar_t tbuf[1024]; + DWORD suggestion; + kherr_suggestion sug_id; + + khm_err_describe(code, tbuf, sizeof(tbuf), + &suggestion, &sug_id); + _report_cs0(KHERR_ERROR, tbuf); + + if (suggestion) + _suggest_mr(suggestion, sug_id); + + _resolve(); + } + + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_NOEXIT| + KHUI_NC_RESPONSE_FAILED); + } else { + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_SUCCESS | + KHUI_NC_RESPONSE_EXIT); + } + } + + khui_cw_unlock_nc(nc); + + _end_task(); + } /* KMSG_CRED_PASSWORD */ + } + break; + + case KMSG_CRED_END: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + + nc = (khui_new_creds *) vparam; + khui_cw_find_type(nc, credtype_id_krb5, &nct); + + if(!nct) + break; + + khui_cw_del_type(nc, credtype_id_krb5); + + if (nct->name) + PFREE(nct->name); + if (nct->credtext) + PFREE(nct->credtext); + + PFREE(nct); + + k5_free_kinit_job(); + } + break; + + case KMSG_CRED_IMPORT: + { + khm_int32 t = 0; + +#ifdef DEBUG + assert(csp_params); +#endif + khc_read_int32(csp_params, L"MsLsaImport", &t); + + if (t != K5_LSAIMPORT_NEVER) { + krb5_context ctx = NULL; + khm_handle id_default = NULL; + khm_handle id_imported = NULL; + BOOL imported; + + imported = khm_krb5_ms2mit(NULL, (t == K5_LSAIMPORT_MATCH), TRUE, + &id_imported); + if (imported) { + khm_krb5_list_tickets(&ctx); + + if (ctx) + pkrb5_free_context(ctx); + + kcdb_identity_refresh(id_imported); + + if (KHM_SUCCEEDED(kcdb_identity_get_default(&id_default))) { + kcdb_identity_release(id_default); + id_default = NULL; + } else { + _reportf(L"There was no default identity. Setting default"); + kcdb_identity_set_default(id_imported); + } + + /* and update the LRU */ + k5_update_LRU(id_imported); + } + + if (id_imported) + kcdb_identity_release(id_imported); + } + } + break; + } + + return rv; +} diff --git a/src/windows/identity/plugins/krb5/krb5plugin.c b/src/windows/identity/plugins/krb5/krb5plugin.c index bb481e0fb..61331f384 100644 --- a/src/windows/identity/plugins/krb5/krb5plugin.c +++ b/src/windows/identity/plugins/krb5/krb5plugin.c @@ -1,265 +1,265 @@ -/* - * 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 -#include - -#ifdef DEBUG -#include -#endif - -khm_int32 credtype_id_krb5 = KCDB_CREDTYPE_INVALID; -khm_boolean krb5_initialized = FALSE; -khm_handle krb5_credset = NULL; - -khm_handle k5_sub = NULL; - -LPVOID k5_main_fiber = NULL; -LPVOID k5_kinit_fiber = NULL; - -VOID CALLBACK k5_kinit_fiber_proc(PVOID lpParameter); - -krb5_context k5_identpro_ctx = NULL; - -/* The system message handler. - - Runs in the context of the plugin thread */ -khm_int32 KHMAPI -k5_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, - khm_ui_4 uparam, void * vparam) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - - switch(msg_subtype) { - case KMSG_SYSTEM_INIT: - { - kcdb_credtype ct; - wchar_t buf[KCDB_MAXCCH_SHORT_DESC]; - size_t cbsize; - - /* perform critical registrations and initialization - stuff */ - ZeroMemory(&ct, sizeof(ct)); - ct.id = KCDB_CREDTYPE_AUTO; - ct.name = KRB5_CREDTYPE_NAME; - - if(LoadString(hResModule, IDS_KRB5_SHORT_DESC, - buf, ARRAYLENGTH(buf))) { - StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); - cbsize += sizeof(wchar_t); - ct.short_desc = PMALLOC(cbsize); - StringCbCopy(ct.short_desc, cbsize, buf); - } - - /* even though ideally we should be setting limits - based KCDB_MAXCB_LONG_DESC, our long description - actually fits nicely in KCDB_MAXCB_SHORT_DESC */ - if(LoadString(hResModule, IDS_KRB5_LONG_DESC, - buf, ARRAYLENGTH(buf))) { - StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); - cbsize += sizeof(wchar_t); - ct.long_desc = PMALLOC(cbsize); - StringCbCopy(ct.long_desc, cbsize, buf); - } - - ct.icon = NULL; /* TODO: set a proper icon */ - - kmq_create_subscription(k5_msg_callback, &ct.sub); - - ct.is_equal = khm_krb5_creds_is_equal; - - rv = kcdb_credtype_register(&ct, &credtype_id_krb5); - - if(KHM_SUCCEEDED(rv)) - rv = kcdb_credset_create(&krb5_credset); - - if(ct.short_desc) - PFREE(ct.short_desc); - - if(ct.long_desc) - PFREE(ct.long_desc); - - if(KHM_SUCCEEDED(rv)) { - krb5_context ctx = NULL; - - krb5_initialized = TRUE; - - /* now convert this thread to a fiber and create a - separate fiber to do kinit stuff */ - k5_main_fiber = ConvertThreadToFiber(NULL); - k5_kinit_fiber = CreateFiber(0,k5_kinit_fiber_proc,NULL); - - ZeroMemory(&g_fjob, sizeof(g_fjob)); - - kmq_create_subscription(k5_msg_callback, &k5_sub); - - k5_register_config_panels(); - - khm_krb5_list_tickets(&ctx); - - if(ctx != NULL) - pkrb5_free_context(ctx); - } - } - break; - - case KMSG_SYSTEM_EXIT: - - k5_unregister_config_panels(); - - if(credtype_id_krb5 >= 0) { - /* basically just unregister the credential type */ - kcdb_credtype_unregister(credtype_id_krb5); - - /* kcdb knows how to deal with bad handles */ - kcdb_credset_delete(krb5_credset); - krb5_credset = NULL; - } - - if(k5_main_fiber != NULL) { - if (k5_kinit_fiber) { -#ifdef DEBUG - assert(k5_kinit_fiber != GetCurrentFiber()); -#endif -#ifdef CLEANUP_FIBERS_ON_EXIT - DeleteFiber(k5_kinit_fiber); - CloseHandle(k5_kinit_fiber); -#endif - k5_kinit_fiber = NULL; - } - - k5_main_fiber = NULL; - } - - if(k5_sub != NULL) { - kmq_delete_subscription(k5_sub); - k5_sub = NULL; - } - - break; - } - - return rv; -} - -khm_int32 KHMAPI -k5_msg_kcdb(khm_int32 msg_type, khm_int32 msg_subtype, - khm_ui_4 uparam, void * vparam) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - - switch(msg_subtype) { - case KMSG_KCDB_IDENT: - if (uparam == KCDB_OP_DELCONFIG) { - k5_remove_from_LRU((khm_handle) vparam); - } - break; - } - - return rv; -} - - -/* Handler for CRED type messages - - Runs in the context of the Krb5 plugin -*/ -khm_int32 KHMAPI -k5_msg_cred(khm_int32 msg_type, khm_int32 msg_subtype, - khm_ui_4 uparam, void * vparam) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - - switch(msg_subtype) { - case KMSG_CRED_REFRESH: - { - krb5_context ctx = NULL; - - khm_krb5_list_tickets(&ctx); - - if(ctx != NULL) - pkrb5_free_context(ctx); - } - break; - - case KMSG_CRED_DESTROY_CREDS: - { - khui_action_context * ctx; - - ctx = (khui_action_context *) vparam; - - if (ctx->credset) { - _begin_task(0); - _report_mr0(KHERR_INFO, MSG_ERR_CTX_DESTROY_CREDS); - _describe(); - - khm_krb5_destroy_by_credset(ctx->credset); - - _end_task(); - } - } - break; - - case KMSG_CRED_PP_BEGIN: - k5_pp_begin((khui_property_sheet *) vparam); - break; - - case KMSG_CRED_PP_END: - k5_pp_end((khui_property_sheet *) vparam); - break; - - default: - if(IS_CRED_ACQ_MSG(msg_subtype)) - return k5_msg_cred_dialog(msg_type, msg_subtype, - uparam, vparam); - } - - return rv; -} - -/* The main message handler. We don't do much here, except delegate - to other message handlers - - Runs in the context of the Krb5 plugin -*/ -khm_int32 KHMAPI -k5_msg_callback(khm_int32 msg_type, khm_int32 msg_subtype, - khm_ui_4 uparam, void * vparam) -{ - switch(msg_type) { - case KMSG_SYSTEM: - return k5_msg_system(msg_type, msg_subtype, uparam, vparam); - case KMSG_CRED: - return k5_msg_cred(msg_type, msg_subtype, uparam, vparam); - case KMSG_KCDB: - return k5_msg_kcdb(msg_type, msg_subtype, uparam, vparam); - } - return KHM_ERROR_SUCCESS; -} +/* + * 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 +#include + +#ifdef DEBUG +#include +#endif + +khm_int32 credtype_id_krb5 = KCDB_CREDTYPE_INVALID; +khm_boolean krb5_initialized = FALSE; +khm_handle krb5_credset = NULL; + +khm_handle k5_sub = NULL; + +LPVOID k5_main_fiber = NULL; +LPVOID k5_kinit_fiber = NULL; + +VOID CALLBACK k5_kinit_fiber_proc(PVOID lpParameter); + +krb5_context k5_identpro_ctx = NULL; + +/* The system message handler. + + Runs in the context of the plugin thread */ +khm_int32 KHMAPI +k5_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_SYSTEM_INIT: + { + kcdb_credtype ct; + wchar_t buf[KCDB_MAXCCH_SHORT_DESC]; + size_t cbsize; + + /* perform critical registrations and initialization + stuff */ + ZeroMemory(&ct, sizeof(ct)); + ct.id = KCDB_CREDTYPE_AUTO; + ct.name = KRB5_CREDTYPE_NAME; + + if(LoadString(hResModule, IDS_KRB5_SHORT_DESC, + buf, ARRAYLENGTH(buf))) { + StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); + cbsize += sizeof(wchar_t); + ct.short_desc = PMALLOC(cbsize); + StringCbCopy(ct.short_desc, cbsize, buf); + } + + /* even though ideally we should be setting limits + based KCDB_MAXCB_LONG_DESC, our long description + actually fits nicely in KCDB_MAXCB_SHORT_DESC */ + if(LoadString(hResModule, IDS_KRB5_LONG_DESC, + buf, ARRAYLENGTH(buf))) { + StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); + cbsize += sizeof(wchar_t); + ct.long_desc = PMALLOC(cbsize); + StringCbCopy(ct.long_desc, cbsize, buf); + } + + ct.icon = NULL; /* TODO: set a proper icon */ + + kmq_create_subscription(k5_msg_callback, &ct.sub); + + ct.is_equal = khm_krb5_creds_is_equal; + + rv = kcdb_credtype_register(&ct, &credtype_id_krb5); + + if(KHM_SUCCEEDED(rv)) + rv = kcdb_credset_create(&krb5_credset); + + if(ct.short_desc) + PFREE(ct.short_desc); + + if(ct.long_desc) + PFREE(ct.long_desc); + + if(KHM_SUCCEEDED(rv)) { + krb5_context ctx = NULL; + + krb5_initialized = TRUE; + + /* now convert this thread to a fiber and create a + separate fiber to do kinit stuff */ + k5_main_fiber = ConvertThreadToFiber(NULL); + k5_kinit_fiber = CreateFiber(0,k5_kinit_fiber_proc,NULL); + + ZeroMemory(&g_fjob, sizeof(g_fjob)); + + kmq_create_subscription(k5_msg_callback, &k5_sub); + + k5_register_config_panels(); + + khm_krb5_list_tickets(&ctx); + + if(ctx != NULL) + pkrb5_free_context(ctx); + } + } + break; + + case KMSG_SYSTEM_EXIT: + + k5_unregister_config_panels(); + + if(credtype_id_krb5 >= 0) { + /* basically just unregister the credential type */ + kcdb_credtype_unregister(credtype_id_krb5); + + /* kcdb knows how to deal with bad handles */ + kcdb_credset_delete(krb5_credset); + krb5_credset = NULL; + } + + if(k5_main_fiber != NULL) { + if (k5_kinit_fiber) { +#ifdef DEBUG + assert(k5_kinit_fiber != GetCurrentFiber()); +#endif +#ifdef CLEANUP_FIBERS_ON_EXIT + DeleteFiber(k5_kinit_fiber); + CloseHandle(k5_kinit_fiber); +#endif + k5_kinit_fiber = NULL; + } + + k5_main_fiber = NULL; + } + + if(k5_sub != NULL) { + kmq_delete_subscription(k5_sub); + k5_sub = NULL; + } + + break; + } + + return rv; +} + +khm_int32 KHMAPI +k5_msg_kcdb(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_KCDB_IDENT: + if (uparam == KCDB_OP_DELCONFIG) { + k5_remove_from_LRU((khm_handle) vparam); + } + break; + } + + return rv; +} + + +/* Handler for CRED type messages + + Runs in the context of the Krb5 plugin +*/ +khm_int32 KHMAPI +k5_msg_cred(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_CRED_REFRESH: + { + krb5_context ctx = NULL; + + khm_krb5_list_tickets(&ctx); + + if(ctx != NULL) + pkrb5_free_context(ctx); + } + break; + + case KMSG_CRED_DESTROY_CREDS: + { + khui_action_context * ctx; + + ctx = (khui_action_context *) vparam; + + if (ctx->credset) { + _begin_task(0); + _report_mr0(KHERR_INFO, MSG_ERR_CTX_DESTROY_CREDS); + _describe(); + + khm_krb5_destroy_by_credset(ctx->credset); + + _end_task(); + } + } + break; + + case KMSG_CRED_PP_BEGIN: + k5_pp_begin((khui_property_sheet *) vparam); + break; + + case KMSG_CRED_PP_END: + k5_pp_end((khui_property_sheet *) vparam); + break; + + default: + if(IS_CRED_ACQ_MSG(msg_subtype)) + return k5_msg_cred_dialog(msg_type, msg_subtype, + uparam, vparam); + } + + return rv; +} + +/* The main message handler. We don't do much here, except delegate + to other message handlers + + Runs in the context of the Krb5 plugin +*/ +khm_int32 KHMAPI +k5_msg_callback(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + switch(msg_type) { + case KMSG_SYSTEM: + return k5_msg_system(msg_type, msg_subtype, uparam, vparam); + case KMSG_CRED: + return k5_msg_cred(msg_type, msg_subtype, uparam, vparam); + case KMSG_KCDB: + return k5_msg_kcdb(msg_type, msg_subtype, uparam, vparam); + } + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/plugins/krb5/krb5props.c b/src/windows/identity/plugins/krb5/krb5props.c index 0d8d27276..312b576fd 100644 --- a/src/windows/identity/plugins/krb5/krb5props.c +++ b/src/windows/identity/plugins/krb5/krb5props.c @@ -1,176 +1,176 @@ -/* - * 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 -#include -#ifdef DEBUG -#include -#endif - -/* Property page - - Runs in the context of the UI thread. - */ -INT_PTR CALLBACK krb5_pp_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam - ) -{ - switch(uMsg) { - case WM_INITDIALOG: - { - khui_property_sheet * s; - PROPSHEETPAGE * p; - wchar_t buf[512]; - wchar_t unavailable[64]; - khm_size cbsize; - khm_int32 rv; - khm_int32 tflags; - - p = (PROPSHEETPAGE *) lParam; - s = (khui_property_sheet *) p->lParam; - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) s); -#pragma warning(pop) - - LoadString(hResModule, IDS_UNAVAILABLE, - unavailable, ARRAYLENGTH(unavailable)); - - if(s->cred) { - cbsize = sizeof(buf); - kcdb_cred_get_name(s->cred, buf, &cbsize); - SetDlgItemText(hwnd, IDC_PPK5_NAME, buf); - - cbsize = sizeof(buf); - rv = kcdb_cred_get_attr_string(s->cred, - KCDB_ATTR_ISSUE, - buf, &cbsize, 0); - if (KHM_SUCCEEDED(rv)) - SetDlgItemText(hwnd, IDC_PPK5_ISSUE, buf); - else - SetDlgItemText(hwnd, IDC_PPK5_ISSUE, unavailable); - - cbsize = sizeof(buf); - rv = kcdb_cred_get_attr_string(s->cred, - KCDB_ATTR_EXPIRE, - buf, &cbsize, 0); - if (KHM_SUCCEEDED(rv)) - SetDlgItemText(hwnd, IDC_PPK5_VALID, buf); - else - SetDlgItemText(hwnd, IDC_PPK5_VALID, unavailable); - - cbsize = sizeof(buf); - rv = kcdb_cred_get_attr_string(s->cred, - KCDB_ATTR_RENEW_EXPIRE, - buf, &cbsize, 0); - if (KHM_SUCCEEDED(rv)) - SetDlgItemText(hwnd, IDC_PPK5_RENEW, buf); - else - SetDlgItemText(hwnd, IDC_PPK5_RENEW, unavailable); - - tflags = 0; - cbsize = sizeof(tflags); - rv = kcdb_cred_get_attr(s->cred, - attr_id_krb5_flags, - NULL, - &tflags, - &cbsize); - if (KHM_SUCCEEDED(rv)) { - -#define ADDBITFLAG(f,s) \ - if (tflags & f) { \ - LoadString(hResModule, s, buf, ARRAYLENGTH(buf)); \ - SendDlgItemMessage(hwnd, IDC_PPK5_FLAGS, LB_ADDSTRING, 0, (LPARAM) buf); \ - } - - ADDBITFLAG(TKT_FLG_FORWARDABLE, IDS_FLG_FORWARDABLE); - ADDBITFLAG(TKT_FLG_FORWARDED, IDS_FLG_FORWARDED); - ADDBITFLAG(TKT_FLG_PROXIABLE, IDS_FLG_PROXIABLE); - ADDBITFLAG(TKT_FLG_PROXY, IDS_FLG_PROXY); - ADDBITFLAG(TKT_FLG_MAY_POSTDATE, IDS_FLG_MAY_POSTDATE); - ADDBITFLAG(TKT_FLG_POSTDATED, IDS_FLG_POSTDATED); - ADDBITFLAG(TKT_FLG_INVALID, IDS_FLG_INVALID); - ADDBITFLAG(TKT_FLG_RENEWABLE, IDS_FLG_RENEWABLE); - ADDBITFLAG(TKT_FLG_INITIAL, IDS_FLG_INITIAL); - ADDBITFLAG(TKT_FLG_PRE_AUTH, IDS_FLG_PRE_AUTH); - ADDBITFLAG(TKT_FLG_HW_AUTH, IDS_FLG_HW_AUTH); - ADDBITFLAG(TKT_FLG_TRANSIT_POLICY_CHECKED, IDS_FLG_TRANSIT_POL); - ADDBITFLAG(TKT_FLG_OK_AS_DELEGATE, IDS_FLG_OK_DELEGATE); - ADDBITFLAG(TKT_FLG_ANONYMOUS, IDS_FLG_ANONYMOUS); - -#undef ADDBITFLAG - - } - } else { -#ifdef DEBUG - assert(FALSE); -#endif - } - } - return FALSE; - } - - return FALSE; -} - -void k5_pp_begin(khui_property_sheet * s) -{ - PROPSHEETPAGE *p; - - if(s->credtype == credtype_id_krb5 && - s->cred) { - p = PMALLOC(sizeof(*p)); - ZeroMemory(p, sizeof(*p)); - - p->dwSize = sizeof(*p); - p->dwFlags = 0; - p->hInstance = hResModule; - p->pszTemplate = MAKEINTRESOURCE(IDD_PP_KRB5C); - p->pfnDlgProc = krb5_pp_proc; - p->lParam = (LPARAM) s; - khui_ps_add_page(s, credtype_id_krb5, 0, p, NULL); - } -} - -void k5_pp_end(khui_property_sheet * s) -{ - khui_property_page * p = NULL; - - khui_ps_find_page(s, credtype_id_krb5, &p); - if(p) { - if(p->p_page) - PFREE(p->p_page); - p->p_page = NULL; - } -} - +/* + * 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 +#include +#ifdef DEBUG +#include +#endif + +/* Property page + + Runs in the context of the UI thread. + */ +INT_PTR CALLBACK krb5_pp_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ) +{ + switch(uMsg) { + case WM_INITDIALOG: + { + khui_property_sheet * s; + PROPSHEETPAGE * p; + wchar_t buf[512]; + wchar_t unavailable[64]; + khm_size cbsize; + khm_int32 rv; + khm_int32 tflags; + + p = (PROPSHEETPAGE *) lParam; + s = (khui_property_sheet *) p->lParam; + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) s); +#pragma warning(pop) + + LoadString(hResModule, IDS_UNAVAILABLE, + unavailable, ARRAYLENGTH(unavailable)); + + if(s->cred) { + cbsize = sizeof(buf); + kcdb_cred_get_name(s->cred, buf, &cbsize); + SetDlgItemText(hwnd, IDC_PPK5_NAME, buf); + + cbsize = sizeof(buf); + rv = kcdb_cred_get_attr_string(s->cred, + KCDB_ATTR_ISSUE, + buf, &cbsize, 0); + if (KHM_SUCCEEDED(rv)) + SetDlgItemText(hwnd, IDC_PPK5_ISSUE, buf); + else + SetDlgItemText(hwnd, IDC_PPK5_ISSUE, unavailable); + + cbsize = sizeof(buf); + rv = kcdb_cred_get_attr_string(s->cred, + KCDB_ATTR_EXPIRE, + buf, &cbsize, 0); + if (KHM_SUCCEEDED(rv)) + SetDlgItemText(hwnd, IDC_PPK5_VALID, buf); + else + SetDlgItemText(hwnd, IDC_PPK5_VALID, unavailable); + + cbsize = sizeof(buf); + rv = kcdb_cred_get_attr_string(s->cred, + KCDB_ATTR_RENEW_EXPIRE, + buf, &cbsize, 0); + if (KHM_SUCCEEDED(rv)) + SetDlgItemText(hwnd, IDC_PPK5_RENEW, buf); + else + SetDlgItemText(hwnd, IDC_PPK5_RENEW, unavailable); + + tflags = 0; + cbsize = sizeof(tflags); + rv = kcdb_cred_get_attr(s->cred, + attr_id_krb5_flags, + NULL, + &tflags, + &cbsize); + if (KHM_SUCCEEDED(rv)) { + +#define ADDBITFLAG(f,s) \ + if (tflags & f) { \ + LoadString(hResModule, s, buf, ARRAYLENGTH(buf)); \ + SendDlgItemMessage(hwnd, IDC_PPK5_FLAGS, LB_ADDSTRING, 0, (LPARAM) buf); \ + } + + ADDBITFLAG(TKT_FLG_FORWARDABLE, IDS_FLG_FORWARDABLE); + ADDBITFLAG(TKT_FLG_FORWARDED, IDS_FLG_FORWARDED); + ADDBITFLAG(TKT_FLG_PROXIABLE, IDS_FLG_PROXIABLE); + ADDBITFLAG(TKT_FLG_PROXY, IDS_FLG_PROXY); + ADDBITFLAG(TKT_FLG_MAY_POSTDATE, IDS_FLG_MAY_POSTDATE); + ADDBITFLAG(TKT_FLG_POSTDATED, IDS_FLG_POSTDATED); + ADDBITFLAG(TKT_FLG_INVALID, IDS_FLG_INVALID); + ADDBITFLAG(TKT_FLG_RENEWABLE, IDS_FLG_RENEWABLE); + ADDBITFLAG(TKT_FLG_INITIAL, IDS_FLG_INITIAL); + ADDBITFLAG(TKT_FLG_PRE_AUTH, IDS_FLG_PRE_AUTH); + ADDBITFLAG(TKT_FLG_HW_AUTH, IDS_FLG_HW_AUTH); + ADDBITFLAG(TKT_FLG_TRANSIT_POLICY_CHECKED, IDS_FLG_TRANSIT_POL); + ADDBITFLAG(TKT_FLG_OK_AS_DELEGATE, IDS_FLG_OK_DELEGATE); + ADDBITFLAG(TKT_FLG_ANONYMOUS, IDS_FLG_ANONYMOUS); + +#undef ADDBITFLAG + + } + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + } + return FALSE; + } + + return FALSE; +} + +void k5_pp_begin(khui_property_sheet * s) +{ + PROPSHEETPAGE *p; + + if(s->credtype == credtype_id_krb5 && + s->cred) { + p = PMALLOC(sizeof(*p)); + ZeroMemory(p, sizeof(*p)); + + p->dwSize = sizeof(*p); + p->dwFlags = 0; + p->hInstance = hResModule; + p->pszTemplate = MAKEINTRESOURCE(IDD_PP_KRB5C); + p->pfnDlgProc = krb5_pp_proc; + p->lParam = (LPARAM) s; + khui_ps_add_page(s, credtype_id_krb5, 0, p, NULL); + } +} + +void k5_pp_end(khui_property_sheet * s) +{ + khui_property_page * p = NULL; + + khui_ps_find_page(s, credtype_id_krb5, &p); + if(p) { + if(p->p_page) + PFREE(p->p_page); + p->p_page = NULL; + } +} + diff --git a/src/windows/identity/plugins/krb5/krbcred.h b/src/windows/identity/plugins/krb5/krbcred.h index d552fd0c8..0048f7185 100644 --- a/src/windows/identity/plugins/krb5/krbcred.h +++ b/src/windows/identity/plugins/krb5/krbcred.h @@ -1,244 +1,244 @@ -/* - * 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_KRBAFSCRED_H -#define __KHIMAIRA_KRBAFSCRED_H - -#include - -/* While we generally pull resources out of hResModule, the message - strings for all the languages are kept in the main DLL. */ -#define KHERR_HMODULE hInstance -#define KHERR_FACILITY k5_facility -#define KHERR_FACILITY_ID 64 - -#include - -#include -#include -#include -#include - -#include -#include -#include - -typedef enum tag_k5_lsa_import { - K5_LSAIMPORT_NEVER = 0, - K5_LSAIMPORT_ALWAYS = 1, - K5_LSAIMPORT_MATCH = 2, /* only when the principal name matches */ -} k5_lsa_import; - -#define TYPENAME_ENCTYPE L"EncType" -#define TYPENAME_ADDR_LIST L"AddrList" -#define TYPENAME_KRB5_FLAGS L"Krb5Flags" -#define TYPENAME_KRB5_PRINC L"Krb5Principal" -#define TYPENAME_KVNO L"Kvno" - -#define ATTRNAME_KEY_ENCTYPE L"KeyEncType" -#define ATTRNAME_TKT_ENCTYPE L"TktEncType" -#define ATTRNAME_ADDR_LIST L"AddrList" -#define ATTRNAME_KRB5_FLAGS L"Krb5Flags" -#define ATTRNAME_KRB5_CCNAME L"Krb5CCName" -#define ATTRNAME_KVNO L"Kvno" -#define ATTRNAME_KRB5_IDFLAGS L"Krb5IDFlags" - -/* Flag bits for Krb5IDFlags property */ - -/* identity was imported from MSLSA: */ -#define K5IDFLAG_IMPORTED 0x00000001 - -void init_krb(); -void exit_krb(); -KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module); -KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module); - -/* globals */ -extern kmm_module h_khModule; -extern HMODULE hResModule; -extern HINSTANCE hInstance; -extern const wchar_t * k5_facility; - -extern khm_int32 type_id_enctype; -extern khm_int32 type_id_addr_list; -extern khm_int32 type_id_krb5_flags; -extern khm_int32 type_id_krb5_princ; -extern khm_int32 type_id_kvno; - -extern BOOL type_regd_krb5_princ; - -extern khm_int32 attr_id_key_enctype; -extern khm_int32 attr_id_tkt_enctype; -extern khm_int32 attr_id_addr_list; -extern khm_int32 attr_id_krb5_flags; -extern khm_int32 attr_id_krb5_ccname; -extern khm_int32 attr_id_kvno; -extern khm_int32 attr_id_krb5_idflags; - -extern khm_ui_4 k5_commctl_version; - -#define IS_COMMCTL6() (k5_commctl_version >= 0x60000) - -/* Configuration spaces */ -#define CSNAME_KRB5CRED L"Krb5Cred" -#define CSNAME_PARAMS L"Parameters" -#define CSNAME_PROMPTCACHE L"PromptCache" -#define CSNAME_REALMS L"Realms" - -/* plugin constants */ -#define KRB5_PLUGIN_NAME L"Krb5Cred" -#define KRB5_IDENTPRO_NAME L"Krb5Ident" - -#define KRB5_CREDTYPE_NAME L"Krb5Cred" - -/* limits */ -/* maximum number of characters in a realm name */ -#define K5_MAXCCH_REALM 256 - -/* maximum number of characters in a host name */ -#define K5_MAXCCH_HOST 128 - -/* maximum number of KDC's per realm */ -#define K5_MAX_KDC 64 - -/* maximum number of domains that map to a realm */ -#define K5_MAX_DOMAIN_MAPPINGS 32 - -extern khm_handle csp_plugins; -extern khm_handle csp_krbcred; -extern khm_handle csp_params; - -extern kconf_schema schema_krbconfig[]; - -/* other globals */ -extern khm_int32 credtype_id_krb5; - -extern khm_boolean krb5_initialized; - -extern khm_handle krb5_credset; - -extern khm_handle k5_sub; - -extern krb5_context k5_identpro_ctx; - -extern BOOL is_k5_identpro; - -/* plugin callbacks */ -khm_int32 KHMAPI k5_msg_callback(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam); -khm_int32 KHMAPI k5_ident_callback(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam); - -/* kinit fiber */ -typedef struct _fiber_job_t { - int command; - - khui_new_creds * nc; - khui_new_creds_by_type * nct; - HWND dialog; - - khm_handle identity; - char * principal; - char * password; - char * ccache; - krb5_deltat lifetime; - DWORD forwardable; - DWORD proxiable; - DWORD renewable; - krb5_deltat renew_life; - DWORD addressless; - DWORD publicIP; - - int code; - int state; - int prompt_set; - - BOOL null_password; - BOOL valid_principal; - BOOL retry_if_valid_principal; -} fiber_job; - -extern fiber_job g_fjob; /* global fiber job object */ - -#define FIBER_CMD_KINIT 1 -#define FIBER_CMD_CANCEL 2 -#define FIBER_CMD_CONTINUE 3 - -#define FIBER_STATE_NONE 0 -#define FIBER_STATE_KINIT 1 -#define FIBER_STATE_RETRY_KINIT 2 - -#define K5_SET_CRED_MSG WMNC_USER - -void -k5_pp_begin(khui_property_sheet * s); - -void -k5_pp_end(khui_property_sheet * s); - -khm_int32 KHMAPI -k5_msg_cred_dialog(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam); - -khm_int32 KHMAPI -k5_msg_ident(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam); - -khm_int32 -k5_remove_from_LRU(khm_handle identity); - -int -k5_get_realm_from_nc(khui_new_creds * nc, - wchar_t * buf, - khm_size cch_buf); - -void -k5_register_config_panels(void); - -void -k5_unregister_config_panels(void); - -INT_PTR CALLBACK -k5_ccconfig_dlgproc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -INT_PTR CALLBACK -k5_id_tab_dlgproc(HWND hwndDlg, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -INT_PTR CALLBACK -k5_ids_tab_dlgproc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -#endif +/* + * 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_KRBAFSCRED_H +#define __KHIMAIRA_KRBAFSCRED_H + +#include + +/* While we generally pull resources out of hResModule, the message + strings for all the languages are kept in the main DLL. */ +#define KHERR_HMODULE hInstance +#define KHERR_FACILITY k5_facility +#define KHERR_FACILITY_ID 64 + +#include + +#include +#include +#include +#include + +#include +#include +#include + +typedef enum tag_k5_lsa_import { + K5_LSAIMPORT_NEVER = 0, + K5_LSAIMPORT_ALWAYS = 1, + K5_LSAIMPORT_MATCH = 2, /* only when the principal name matches */ +} k5_lsa_import; + +#define TYPENAME_ENCTYPE L"EncType" +#define TYPENAME_ADDR_LIST L"AddrList" +#define TYPENAME_KRB5_FLAGS L"Krb5Flags" +#define TYPENAME_KRB5_PRINC L"Krb5Principal" +#define TYPENAME_KVNO L"Kvno" + +#define ATTRNAME_KEY_ENCTYPE L"KeyEncType" +#define ATTRNAME_TKT_ENCTYPE L"TktEncType" +#define ATTRNAME_ADDR_LIST L"AddrList" +#define ATTRNAME_KRB5_FLAGS L"Krb5Flags" +#define ATTRNAME_KRB5_CCNAME L"Krb5CCName" +#define ATTRNAME_KVNO L"Kvno" +#define ATTRNAME_KRB5_IDFLAGS L"Krb5IDFlags" + +/* Flag bits for Krb5IDFlags property */ + +/* identity was imported from MSLSA: */ +#define K5IDFLAG_IMPORTED 0x00000001 + +void init_krb(); +void exit_krb(); +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module); +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module); + +/* globals */ +extern kmm_module h_khModule; +extern HMODULE hResModule; +extern HINSTANCE hInstance; +extern const wchar_t * k5_facility; + +extern khm_int32 type_id_enctype; +extern khm_int32 type_id_addr_list; +extern khm_int32 type_id_krb5_flags; +extern khm_int32 type_id_krb5_princ; +extern khm_int32 type_id_kvno; + +extern BOOL type_regd_krb5_princ; + +extern khm_int32 attr_id_key_enctype; +extern khm_int32 attr_id_tkt_enctype; +extern khm_int32 attr_id_addr_list; +extern khm_int32 attr_id_krb5_flags; +extern khm_int32 attr_id_krb5_ccname; +extern khm_int32 attr_id_kvno; +extern khm_int32 attr_id_krb5_idflags; + +extern khm_ui_4 k5_commctl_version; + +#define IS_COMMCTL6() (k5_commctl_version >= 0x60000) + +/* Configuration spaces */ +#define CSNAME_KRB5CRED L"Krb5Cred" +#define CSNAME_PARAMS L"Parameters" +#define CSNAME_PROMPTCACHE L"PromptCache" +#define CSNAME_REALMS L"Realms" + +/* plugin constants */ +#define KRB5_PLUGIN_NAME L"Krb5Cred" +#define KRB5_IDENTPRO_NAME L"Krb5Ident" + +#define KRB5_CREDTYPE_NAME L"Krb5Cred" + +/* limits */ +/* maximum number of characters in a realm name */ +#define K5_MAXCCH_REALM 256 + +/* maximum number of characters in a host name */ +#define K5_MAXCCH_HOST 128 + +/* maximum number of KDC's per realm */ +#define K5_MAX_KDC 64 + +/* maximum number of domains that map to a realm */ +#define K5_MAX_DOMAIN_MAPPINGS 32 + +extern khm_handle csp_plugins; +extern khm_handle csp_krbcred; +extern khm_handle csp_params; + +extern kconf_schema schema_krbconfig[]; + +/* other globals */ +extern khm_int32 credtype_id_krb5; + +extern khm_boolean krb5_initialized; + +extern khm_handle krb5_credset; + +extern khm_handle k5_sub; + +extern krb5_context k5_identpro_ctx; + +extern BOOL is_k5_identpro; + +/* plugin callbacks */ +khm_int32 KHMAPI k5_msg_callback(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam); +khm_int32 KHMAPI k5_ident_callback(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam); + +/* kinit fiber */ +typedef struct _fiber_job_t { + int command; + + khui_new_creds * nc; + khui_new_creds_by_type * nct; + HWND dialog; + + khm_handle identity; + char * principal; + char * password; + char * ccache; + krb5_deltat lifetime; + DWORD forwardable; + DWORD proxiable; + DWORD renewable; + krb5_deltat renew_life; + DWORD addressless; + DWORD publicIP; + + int code; + int state; + int prompt_set; + + BOOL null_password; + BOOL valid_principal; + BOOL retry_if_valid_principal; +} fiber_job; + +extern fiber_job g_fjob; /* global fiber job object */ + +#define FIBER_CMD_KINIT 1 +#define FIBER_CMD_CANCEL 2 +#define FIBER_CMD_CONTINUE 3 + +#define FIBER_STATE_NONE 0 +#define FIBER_STATE_KINIT 1 +#define FIBER_STATE_RETRY_KINIT 2 + +#define K5_SET_CRED_MSG WMNC_USER + +void +k5_pp_begin(khui_property_sheet * s); + +void +k5_pp_end(khui_property_sheet * s); + +khm_int32 KHMAPI +k5_msg_cred_dialog(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam); + +khm_int32 KHMAPI +k5_msg_ident(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam); + +khm_int32 +k5_remove_from_LRU(khm_handle identity); + +int +k5_get_realm_from_nc(khui_new_creds * nc, + wchar_t * buf, + khm_size cch_buf); + +void +k5_register_config_panels(void); + +void +k5_unregister_config_panels(void); + +INT_PTR CALLBACK +k5_ccconfig_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +k5_id_tab_dlgproc(HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +k5_ids_tab_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +#endif diff --git a/src/windows/identity/plugins/krb5/langres.h b/src/windows/identity/plugins/krb5/langres.h index 0e62ecda1..117754b3e 100644 --- a/src/windows/identity/plugins/krb5/langres.h +++ b/src/windows/identity/plugins/krb5/langres.h @@ -1,216 +1,216 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// 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 -#define IDS_KRB5_CREDTEXT_0 102 -#define IDS_KRB5_CCNAME_SHORT_DESC 103 -#define IDS_KEY_ENCTYPE_SHORT_DESC 104 -#define IDD_CONFIG 104 -#define IDS_TKT_ENCTYPE_SHORT_DESC 105 -#define IDD_CFG_REALMS 105 -#define IDS_KEY_ENCTYPE_LONG_DESC 106 -#define IDD_CFG_IDS_TAB 106 -#define IDS_TKT_ENCTYPE_LONG_DESC 107 -#define IDD_PP_KRB5C 107 -#define IDS_ADDR_LIST_SHORT_DESC 108 -#define IDD_PP_KRB5 108 -#define IDS_ADDR_LIST_LONG_DESC 109 -#define IDD_CFG_ID_TAB 109 -#define IDS_ETYPE_NULL 110 -#define IDD_NC_KRB5_PASSWORD 110 -#define IDS_ETYPE_DES_CBC_CRC 111 -#define IDD_CFG_CACHES 111 -#define IDS_ETYPE_DES_CBC_MD4 112 -#define IDI_PLUGIN 112 -#define IDS_ETYPE_DES_CBC_MD5 113 -#define IDI_DELETED 113 -#define IDS_ETYPE_DES_CBC_RAW 114 -#define IDI_NEW 114 -#define IDS_ETYPE_DES3_CBC_SHA 115 -#define IDI_NORMAL 115 -#define IDS_ETYPE_DES3_CBC_RAW 116 -#define IDI_MODIFIED 116 -#define IDS_ETYPE_DES_HMAC_SHA1 117 -#define IDS_ETYPE_DES3_CBC_SHA1 118 -#define IDS_ETYPE_AES128_CTS_HMAC_SHA1_96 119 -#define IDS_ETYPE_AES256_CTS_HMAC_SHA1_96 120 -#define IDS_ETYPE_ARCFOUR_HMAC 121 -#define IDS_ETYPE_ARCFOUR_HMAC_EXP 122 -#define IDS_ETYPE_UNKNOWN 123 -#define IDS_ETYPE_LOCAL_DES3_HMAC_SHA1 124 -#define IDS_ETYPE_LOCAL_RC4_MD4 125 -#define IDS_KRB5_SHORT_DESC 126 -#define IDS_KRB5_LONG_DESC 127 -#define IDS_KRB4_SHORT_DESC 128 -#define IDS_KRB4_LONG_DESC 129 -#define IDS_KRB5_FLAGS_SHORT_DESC 130 -#define IDS_RENEW_TILL_SHORT_DESC 131 -#define IDS_RENEW_TILL_LONG_DESC 132 -#define IDS_RENEW_FOR_SHORT_DESC 133 -#define IDS_RENEW_FOR_LONG_DESC 134 -#define IDS_KRB5_CCNAME_LONG_DESC 135 -#define IDS_NC_USERNAME 136 -#define IDS_NC_REALM 137 -#define IDS_KRB5_WARNING 138 -#define IDS_K5ERR_NAME_EXPIRED 139 -#define IDS_K5ERR_KEY_EXPIRED 140 -#define IDS_KRB5_WARN_FMT 141 -#define IDS_K5ERR_FMT 142 -#define IDS_K5CFG_SHORT_DESC 143 -#define IDS_K5CFG_LONG_DESC 144 -#define IDS_K5RLM_SHORT_DESC 145 -#define IDS_K5RLM_LONG_DESC 146 -#define IDS_K5CFG_IDS_SHORT_DESC 147 -#define IDS_K5CFG_IDS_LONG_DESC 148 -#define IDS_K5CFG_ID_SHORT_DESC 149 -#define IDS_K5CFG_ID_LONG_DESC 150 -#define IDS_PLUGIN_DESC 151 -#define IDS_NC_PWD_BANNER 152 -#define IDS_NC_PWD_PWD 153 -#define IDS_NC_PWD_NPWD 154 -#define IDS_NC_PWD_NPWD_AGAIN 155 -#define IDS_KRB5_CREDTEXT_P0 156 -#define IDS_K5CFG_IMPORT_OPTIONS 157 -#define IDS_IDENTPRO_DESC 158 -#define IDS_K5CCC_SHORT_DESC 159 -#define IDS_K5CCC_LONG_DESC 160 -#define IDS_CFG_FCTITLE 161 -#define IDS_CFG_FCN_WARNING 162 -#define IDS_CFG_FCN_W_NOTFOUND 163 -#define IDS_CFG_FCN_W_RELATIVE 164 -#define IDS_CFG_FCOPENTITLE 165 -#define IDS_UNAVAILABLE 166 -#define IDS_FLG_FORWARDABLE 167 -#define IDS_FLG_FORWARDED 168 -#define IDS_FLG_PROXIABLE 169 -#define IDS_FLG_PROXY 170 -#define IDS_FLG_MAY_POSTDATE 171 -#define IDS_FLG_POSTDATED 172 -#define IDS_FLG_INVALID 173 -#define IDS_FLG_RENEWABLE 174 -#define IDS_FLG_INITIAL 175 -#define IDS_FLG_PRE_AUTH 176 -#define IDS_FLG_HW_AUTH 177 -#define IDS_FLG_TRANSIT_POL 178 -#define IDS_FLG_OK_DELEGATE 179 -#define IDS_FLG_ANONYMOUS 180 -#define IDS_K5ERR_CANTWRITEPROFILE 181 -#define IDS_K5ERR_PROFNOWRITE 182 -#define IDS_K5ERR_PROFUSETEMP 183 -#define IDS_K5ERR_PROFSUGGEST 184 -#define IDS_CFG_RE_REALMS 185 -#define IDS_CFG_RE_KDCS 186 -#define IDS_CFG_RE_DMAPS 187 -#define IDS_CFG_RE_KDCS_R 188 -#define IDS_CFG_RE_DMAPS_R 189 -#define IDS_CFG_RE_HEAD_SVR 190 -#define IDS_CFG_RE_HEAD_ADMIN 191 -#define IDS_CFG_RE_HEAD_MASTER 192 -#define IDS_CFG_RE_HEAD_DOMAIN 193 -#define IDS_CFG_RE_NEWREALM 194 -#define IDS_YES 195 -#define IDS_NO 196 -#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 IDS_KVNO_SHORT_DESC 217 -#define IDS_KVNO_LONG_DESC 218 -#define IDC_NCK5_RENEWABLE 1002 -#define IDC_NCK5_FORWARDABLE 1004 -#define IDC_NCK5_REALM 1005 -#define IDC_NCK5_ADD_REALMS 1006 -#define IDC_NCK5_LIFETIME_EDIT 1008 -#define IDC_NCK5_RENEW_EDIT 1009 -#define IDC_PPK5_CRENEW 1014 -#define IDC_PPK5_CFORWARD 1015 -#define IDC_PPK5_CPROXY 1016 -#define IDC_PPK5_NAME 1017 -#define IDC_PPK5_ISSUE 1018 -#define IDC_PPK5_VALID 1019 -#define IDC_PPK5_RENEW 1020 -#define IDC_CHECK2 1022 -#define IDC_CHECK4 1024 -#define IDC_PPK5_LIFETIME 1024 -#define IDC_CHECK5 1025 -#define IDC_CFG_LBL_REALM 1025 -#define IDC_CFG_DEFREALM 1026 -#define IDC_CFG_LBL_CFGFILE 1029 -#define IDC_CFG_CFGFILE 1030 -#define IDC_CFG_WINGRP 1031 -#define IDC_LBL_IMPORT 1032 -#define IDC_CFG_IMPORT 1033 -#define IDC_CFG_LBL_HOSTNAME 1034 -#define IDC_CFG_HOSTNAME 1035 -#define IDC_CFG_LBL_DOMAIN 1036 -#define IDC_CFG_DOMAIN 1037 -#define IDC_CFG_CREATECONFIG 1038 -#define IDC_CFG_BROWSE 1039 -#define IDC_CFG_CFGFILEGRP 1040 -#define IDC_CFG_CFGREALMS 1041 -#define IDC_CFG_BROWSE2 1042 -#define IDC_CFG_REALMS 1044 -#define IDC_CFG_DOMAINGRP 1045 -#define IDC_CFG_SERVERSGRP 1046 -#define IDC_LIST3 1047 -#define IDC_CFG_KDC 1047 -#define IDC_LIST4 1048 -#define IDC_CFG_DMAP 1048 -#define IDC_CFG_LBL_DEFLIFE 1049 -#define IDC_CFG_DEFLIFE 1050 -#define IDC_CFG_LBL_DEFRLIFE 1051 -#define IDC_CFG_DEFRLIFE 1052 -#define IDC_CFG_LIFEGRP 1053 -#define IDC_CFG_LRNG_MIN 1054 -#define IDC_CFG_LRNG_MAX 1055 -#define IDC_CFG_RLRNG_MIN 1056 -#define IDC_CFG_RLRNG_MAX 1057 -#define IDC_CFG_CCACHE 1058 -#define IDC_CFG_FCGRP 1059 -#define IDC_CFG_FCLIST 1060 -#define IDC_CFG_FCNAME 1062 -#define IDC_CFG_ADD 1064 -#define IDC_CFG_REMOVE 1065 -#define IDC_CFG_INCAPI 1066 -#define IDC_CFG_INCMSLSA 1067 -#define IDC_PPK5_FLAGS 1072 -#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 IDC_CHECK1 1079 -#define ID_FOO_BAR 40001 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 219 -#define _APS_NEXT_COMMAND_VALUE 40002 -#define _APS_NEXT_CONTROL_VALUE 1080 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// 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 +#define IDS_KRB5_CREDTEXT_0 102 +#define IDS_KRB5_CCNAME_SHORT_DESC 103 +#define IDS_KEY_ENCTYPE_SHORT_DESC 104 +#define IDD_CONFIG 104 +#define IDS_TKT_ENCTYPE_SHORT_DESC 105 +#define IDD_CFG_REALMS 105 +#define IDS_KEY_ENCTYPE_LONG_DESC 106 +#define IDD_CFG_IDS_TAB 106 +#define IDS_TKT_ENCTYPE_LONG_DESC 107 +#define IDD_PP_KRB5C 107 +#define IDS_ADDR_LIST_SHORT_DESC 108 +#define IDD_PP_KRB5 108 +#define IDS_ADDR_LIST_LONG_DESC 109 +#define IDD_CFG_ID_TAB 109 +#define IDS_ETYPE_NULL 110 +#define IDD_NC_KRB5_PASSWORD 110 +#define IDS_ETYPE_DES_CBC_CRC 111 +#define IDD_CFG_CACHES 111 +#define IDS_ETYPE_DES_CBC_MD4 112 +#define IDI_PLUGIN 112 +#define IDS_ETYPE_DES_CBC_MD5 113 +#define IDI_DELETED 113 +#define IDS_ETYPE_DES_CBC_RAW 114 +#define IDI_NEW 114 +#define IDS_ETYPE_DES3_CBC_SHA 115 +#define IDI_NORMAL 115 +#define IDS_ETYPE_DES3_CBC_RAW 116 +#define IDI_MODIFIED 116 +#define IDS_ETYPE_DES_HMAC_SHA1 117 +#define IDS_ETYPE_DES3_CBC_SHA1 118 +#define IDS_ETYPE_AES128_CTS_HMAC_SHA1_96 119 +#define IDS_ETYPE_AES256_CTS_HMAC_SHA1_96 120 +#define IDS_ETYPE_ARCFOUR_HMAC 121 +#define IDS_ETYPE_ARCFOUR_HMAC_EXP 122 +#define IDS_ETYPE_UNKNOWN 123 +#define IDS_ETYPE_LOCAL_DES3_HMAC_SHA1 124 +#define IDS_ETYPE_LOCAL_RC4_MD4 125 +#define IDS_KRB5_SHORT_DESC 126 +#define IDS_KRB5_LONG_DESC 127 +#define IDS_KRB4_SHORT_DESC 128 +#define IDS_KRB4_LONG_DESC 129 +#define IDS_KRB5_FLAGS_SHORT_DESC 130 +#define IDS_RENEW_TILL_SHORT_DESC 131 +#define IDS_RENEW_TILL_LONG_DESC 132 +#define IDS_RENEW_FOR_SHORT_DESC 133 +#define IDS_RENEW_FOR_LONG_DESC 134 +#define IDS_KRB5_CCNAME_LONG_DESC 135 +#define IDS_NC_USERNAME 136 +#define IDS_NC_REALM 137 +#define IDS_KRB5_WARNING 138 +#define IDS_K5ERR_NAME_EXPIRED 139 +#define IDS_K5ERR_KEY_EXPIRED 140 +#define IDS_KRB5_WARN_FMT 141 +#define IDS_K5ERR_FMT 142 +#define IDS_K5CFG_SHORT_DESC 143 +#define IDS_K5CFG_LONG_DESC 144 +#define IDS_K5RLM_SHORT_DESC 145 +#define IDS_K5RLM_LONG_DESC 146 +#define IDS_K5CFG_IDS_SHORT_DESC 147 +#define IDS_K5CFG_IDS_LONG_DESC 148 +#define IDS_K5CFG_ID_SHORT_DESC 149 +#define IDS_K5CFG_ID_LONG_DESC 150 +#define IDS_PLUGIN_DESC 151 +#define IDS_NC_PWD_BANNER 152 +#define IDS_NC_PWD_PWD 153 +#define IDS_NC_PWD_NPWD 154 +#define IDS_NC_PWD_NPWD_AGAIN 155 +#define IDS_KRB5_CREDTEXT_P0 156 +#define IDS_K5CFG_IMPORT_OPTIONS 157 +#define IDS_IDENTPRO_DESC 158 +#define IDS_K5CCC_SHORT_DESC 159 +#define IDS_K5CCC_LONG_DESC 160 +#define IDS_CFG_FCTITLE 161 +#define IDS_CFG_FCN_WARNING 162 +#define IDS_CFG_FCN_W_NOTFOUND 163 +#define IDS_CFG_FCN_W_RELATIVE 164 +#define IDS_CFG_FCOPENTITLE 165 +#define IDS_UNAVAILABLE 166 +#define IDS_FLG_FORWARDABLE 167 +#define IDS_FLG_FORWARDED 168 +#define IDS_FLG_PROXIABLE 169 +#define IDS_FLG_PROXY 170 +#define IDS_FLG_MAY_POSTDATE 171 +#define IDS_FLG_POSTDATED 172 +#define IDS_FLG_INVALID 173 +#define IDS_FLG_RENEWABLE 174 +#define IDS_FLG_INITIAL 175 +#define IDS_FLG_PRE_AUTH 176 +#define IDS_FLG_HW_AUTH 177 +#define IDS_FLG_TRANSIT_POL 178 +#define IDS_FLG_OK_DELEGATE 179 +#define IDS_FLG_ANONYMOUS 180 +#define IDS_K5ERR_CANTWRITEPROFILE 181 +#define IDS_K5ERR_PROFNOWRITE 182 +#define IDS_K5ERR_PROFUSETEMP 183 +#define IDS_K5ERR_PROFSUGGEST 184 +#define IDS_CFG_RE_REALMS 185 +#define IDS_CFG_RE_KDCS 186 +#define IDS_CFG_RE_DMAPS 187 +#define IDS_CFG_RE_KDCS_R 188 +#define IDS_CFG_RE_DMAPS_R 189 +#define IDS_CFG_RE_HEAD_SVR 190 +#define IDS_CFG_RE_HEAD_ADMIN 191 +#define IDS_CFG_RE_HEAD_MASTER 192 +#define IDS_CFG_RE_HEAD_DOMAIN 193 +#define IDS_CFG_RE_NEWREALM 194 +#define IDS_YES 195 +#define IDS_NO 196 +#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 IDS_KVNO_SHORT_DESC 217 +#define IDS_KVNO_LONG_DESC 218 +#define IDC_NCK5_RENEWABLE 1002 +#define IDC_NCK5_FORWARDABLE 1004 +#define IDC_NCK5_REALM 1005 +#define IDC_NCK5_ADD_REALMS 1006 +#define IDC_NCK5_LIFETIME_EDIT 1008 +#define IDC_NCK5_RENEW_EDIT 1009 +#define IDC_PPK5_CRENEW 1014 +#define IDC_PPK5_CFORWARD 1015 +#define IDC_PPK5_CPROXY 1016 +#define IDC_PPK5_NAME 1017 +#define IDC_PPK5_ISSUE 1018 +#define IDC_PPK5_VALID 1019 +#define IDC_PPK5_RENEW 1020 +#define IDC_CHECK2 1022 +#define IDC_CHECK4 1024 +#define IDC_PPK5_LIFETIME 1024 +#define IDC_CHECK5 1025 +#define IDC_CFG_LBL_REALM 1025 +#define IDC_CFG_DEFREALM 1026 +#define IDC_CFG_LBL_CFGFILE 1029 +#define IDC_CFG_CFGFILE 1030 +#define IDC_CFG_WINGRP 1031 +#define IDC_LBL_IMPORT 1032 +#define IDC_CFG_IMPORT 1033 +#define IDC_CFG_LBL_HOSTNAME 1034 +#define IDC_CFG_HOSTNAME 1035 +#define IDC_CFG_LBL_DOMAIN 1036 +#define IDC_CFG_DOMAIN 1037 +#define IDC_CFG_CREATECONFIG 1038 +#define IDC_CFG_BROWSE 1039 +#define IDC_CFG_CFGFILEGRP 1040 +#define IDC_CFG_CFGREALMS 1041 +#define IDC_CFG_BROWSE2 1042 +#define IDC_CFG_REALMS 1044 +#define IDC_CFG_DOMAINGRP 1045 +#define IDC_CFG_SERVERSGRP 1046 +#define IDC_LIST3 1047 +#define IDC_CFG_KDC 1047 +#define IDC_LIST4 1048 +#define IDC_CFG_DMAP 1048 +#define IDC_CFG_LBL_DEFLIFE 1049 +#define IDC_CFG_DEFLIFE 1050 +#define IDC_CFG_LBL_DEFRLIFE 1051 +#define IDC_CFG_DEFRLIFE 1052 +#define IDC_CFG_LIFEGRP 1053 +#define IDC_CFG_LRNG_MIN 1054 +#define IDC_CFG_LRNG_MAX 1055 +#define IDC_CFG_RLRNG_MIN 1056 +#define IDC_CFG_RLRNG_MAX 1057 +#define IDC_CFG_CCACHE 1058 +#define IDC_CFG_FCGRP 1059 +#define IDC_CFG_FCLIST 1060 +#define IDC_CFG_FCNAME 1062 +#define IDC_CFG_ADD 1064 +#define IDC_CFG_REMOVE 1065 +#define IDC_CFG_INCAPI 1066 +#define IDC_CFG_INCMSLSA 1067 +#define IDC_PPK5_FLAGS 1072 +#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 IDC_CHECK1 1079 +#define ID_FOO_BAR 40001 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 219 +#define _APS_NEXT_COMMAND_VALUE 40002 +#define _APS_NEXT_CONTROL_VALUE 1080 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/windows/identity/sample/templates/credprov/config_id.c b/src/windows/identity/sample/templates/credprov/config_id.c index ed5b3e4c3..850016266 100644 --- a/src/windows/identity/sample/templates/credprov/config_id.c +++ b/src/windows/identity/sample/templates/credprov/config_id.c @@ -1,118 +1,118 @@ -/* - * Copyright (c) 2006 Secure Endpoints Inc. - * - * 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 "credprov.h" -#include - -/* Dialog procedures and support functions for handling configuration - dialogs for per-identity configuration. When the configuration - dialog is activated, an instance of this dialog will be created for - each identity that the user touches. */ - -/* The structure that we use to hold state information for the - dialog. */ -typedef struct tag_config_id_dlg_data { - khui_config_init_data cfg; /* instance information for this - dialog */ - - khm_handle ident; /* handle to the identity for this - dialog */ - - /* TODO: Add any fields for holding state here */ -} config_id_dlg_data; - -INT_PTR CALLBACK -config_id_dlgproc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - - config_id_dlg_data * d; - - switch (uMsg) { - case WM_INITDIALOG: - { - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - khm_int32 rv; - - d = malloc(sizeof(*d)); - assert(d); - ZeroMemory(d, sizeof(*d)); - - /* for subpanels, lParam is a pointer to a - khui_config_init_data strucutre that provides the - instance and context information. It's not a - persistent strucutre, so we have to make a copy. */ - d->cfg = *((khui_config_init_data *) lParam); - - cb = sizeof(idname); - rv = khui_cfg_get_name(d->cfg.ctx_node, idname, &cb); - assert(KHM_SUCCEEDED(rv)); - - rv = kcdb_identity_create(idname, 0, &d->ident); - assert(KHM_SUCCEEDED(rv)); - - /* TODO: perform any other required initialization */ - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); -#pragma warning(pop) - } - break; - - case KHUI_WM_CFG_NOTIFY: - d = (config_id_dlg_data *) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (HIWORD(wParam) == WMCFG_APPLY) { - /* TODO: apply changes */ - - return TRUE; - } - break; - - case WM_DESTROY: - { - d = (config_id_dlg_data *) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (d) { - if (d->ident) - kcdb_identity_release(d->ident); - - /* TODO: perform any other required uninitialization */ - - free(d); - } - } - break; - } - - return FALSE; - -} +/* + * Copyright (c) 2006 Secure Endpoints Inc. + * + * 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 "credprov.h" +#include + +/* Dialog procedures and support functions for handling configuration + dialogs for per-identity configuration. When the configuration + dialog is activated, an instance of this dialog will be created for + each identity that the user touches. */ + +/* The structure that we use to hold state information for the + dialog. */ +typedef struct tag_config_id_dlg_data { + khui_config_init_data cfg; /* instance information for this + dialog */ + + khm_handle ident; /* handle to the identity for this + dialog */ + + /* TODO: Add any fields for holding state here */ +} config_id_dlg_data; + +INT_PTR CALLBACK +config_id_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + config_id_dlg_data * d; + + switch (uMsg) { + case WM_INITDIALOG: + { + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khm_int32 rv; + + d = malloc(sizeof(*d)); + assert(d); + ZeroMemory(d, sizeof(*d)); + + /* for subpanels, lParam is a pointer to a + khui_config_init_data strucutre that provides the + instance and context information. It's not a + persistent strucutre, so we have to make a copy. */ + d->cfg = *((khui_config_init_data *) lParam); + + cb = sizeof(idname); + rv = khui_cfg_get_name(d->cfg.ctx_node, idname, &cb); + assert(KHM_SUCCEEDED(rv)); + + rv = kcdb_identity_create(idname, 0, &d->ident); + assert(KHM_SUCCEEDED(rv)); + + /* TODO: perform any other required initialization */ + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + } + break; + + case KHUI_WM_CFG_NOTIFY: + d = (config_id_dlg_data *) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == WMCFG_APPLY) { + /* TODO: apply changes */ + + return TRUE; + } + break; + + case WM_DESTROY: + { + d = (config_id_dlg_data *) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (d) { + if (d->ident) + kcdb_identity_release(d->ident); + + /* TODO: perform any other required uninitialization */ + + free(d); + } + } + break; + } + + return FALSE; + +} diff --git a/src/windows/identity/sample/templates/credprov/config_ids.c b/src/windows/identity/sample/templates/credprov/config_ids.c index 413951207..8d6f0081a 100644 --- a/src/windows/identity/sample/templates/credprov/config_ids.c +++ b/src/windows/identity/sample/templates/credprov/config_ids.c @@ -1,96 +1,96 @@ -/* - * Copyright (c) 2006 Secure Endpoints Inc. - * - * 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 "credprov.h" -#include - -/* Dialog procedures and support functions for handling configuration - dialogs for all identities. */ - -/* The structure that we use to hold state information for the - dialog. */ -typedef struct tag_config_ids_dlg_data { - khui_config_init_data cfg; /* instance information for this - dialog */ - - /* TODO: Add any fields for holding state here */ -} config_ids_dlg_data; - -INT_PTR CALLBACK -config_ids_dlgproc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - - config_ids_dlg_data * d; - - switch (uMsg) { - case WM_INITDIALOG: - { - d = malloc(sizeof(*d)); - assert(d); - ZeroMemory(d, sizeof(*d)); - - /* for subpanels, lParam is a pointer to a - khui_config_init_data strucutre that provides the - instance and context information. It's not a - persistent strucutre, so we have to make a copy. */ - d->cfg = *((khui_config_init_data *) lParam); - - /* TODO: perform any additional initialization */ - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); -#pragma warning(pop) - } - break; - - case KHUI_WM_CFG_NOTIFY: - d = (config_ids_dlg_data *) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (HIWORD(wParam) == WMCFG_APPLY) { - /* TODO: apply changes */ - - return TRUE; - } - break; - - case WM_DESTROY: - d = (config_ids_dlg_data *) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (d) { - /* TODO: Perform any additional uninitialization */ - - free (d); - } - break; - } - - return FALSE; -} +/* + * Copyright (c) 2006 Secure Endpoints Inc. + * + * 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 "credprov.h" +#include + +/* Dialog procedures and support functions for handling configuration + dialogs for all identities. */ + +/* The structure that we use to hold state information for the + dialog. */ +typedef struct tag_config_ids_dlg_data { + khui_config_init_data cfg; /* instance information for this + dialog */ + + /* TODO: Add any fields for holding state here */ +} config_ids_dlg_data; + +INT_PTR CALLBACK +config_ids_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + config_ids_dlg_data * d; + + switch (uMsg) { + case WM_INITDIALOG: + { + d = malloc(sizeof(*d)); + assert(d); + ZeroMemory(d, sizeof(*d)); + + /* for subpanels, lParam is a pointer to a + khui_config_init_data strucutre that provides the + instance and context information. It's not a + persistent strucutre, so we have to make a copy. */ + d->cfg = *((khui_config_init_data *) lParam); + + /* TODO: perform any additional initialization */ + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + } + break; + + case KHUI_WM_CFG_NOTIFY: + d = (config_ids_dlg_data *) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == WMCFG_APPLY) { + /* TODO: apply changes */ + + return TRUE; + } + break; + + case WM_DESTROY: + d = (config_ids_dlg_data *) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (d) { + /* TODO: Perform any additional uninitialization */ + + free (d); + } + break; + } + + return FALSE; +} diff --git a/src/windows/identity/sample/templates/credprov/config_main.c b/src/windows/identity/sample/templates/credprov/config_main.c index 3461ac0cc..87a2a15fc 100644 --- a/src/windows/identity/sample/templates/credprov/config_main.c +++ b/src/windows/identity/sample/templates/credprov/config_main.c @@ -1,99 +1,99 @@ -/* - * Copyright (c) 2006 Secure Endpoints Inc. - * - * 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 "credprov.h" -#include - -/* Dialog procedures and support functions for handling configuration - dialogs for general plug-in configuration. */ - -/* Structure for holding dialog data for the configuration window. */ -typedef struct tag_config_main_dlg_data { - khui_config_node cnode; - - /* TODO: add fields as needed */ -} config_main_dlg_data; - -INT_PTR CALLBACK -config_dlgproc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - - config_main_dlg_data * d; - - switch (uMsg) { - case WM_INITDIALOG: - d = malloc(sizeof(*d)); - assert(d); - ZeroMemory(d, sizeof(*d)); - - /* for configuration panels that are not subpanels, lParam is - a held handle to the configuration node. The handle will - be held for the lifetime of the window. */ - - d->cnode = (khui_config_node) lParam; - - /* TODO: perform any other required initialization stuff - here */ - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); -#pragma warning(pop) - - break; - - case KHUI_WM_CFG_NOTIFY: - { - d = (config_main_dlg_data *) - GetWindowLongPtr(hwnd, DWLP_USER); - - /* WMCFG_APPLY is the only notification we care about */ - - if (HIWORD(wParam) == WMCFG_APPLY) { - /* TODO: Apply changes and update the state */ - - return TRUE; - } - } - break; - - case WM_DESTROY: - d = (config_main_dlg_data *) - GetWindowLongPtr(hwnd, DWLP_USER); - - /* TODO: perform any other required uninitialization here */ - - if (d) - free(d); - - break; - } - - return FALSE; - -} +/* + * Copyright (c) 2006 Secure Endpoints Inc. + * + * 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 "credprov.h" +#include + +/* Dialog procedures and support functions for handling configuration + dialogs for general plug-in configuration. */ + +/* Structure for holding dialog data for the configuration window. */ +typedef struct tag_config_main_dlg_data { + khui_config_node cnode; + + /* TODO: add fields as needed */ +} config_main_dlg_data; + +INT_PTR CALLBACK +config_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + config_main_dlg_data * d; + + switch (uMsg) { + case WM_INITDIALOG: + d = malloc(sizeof(*d)); + assert(d); + ZeroMemory(d, sizeof(*d)); + + /* for configuration panels that are not subpanels, lParam is + a held handle to the configuration node. The handle will + be held for the lifetime of the window. */ + + d->cnode = (khui_config_node) lParam; + + /* TODO: perform any other required initialization stuff + here */ + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + break; + + case KHUI_WM_CFG_NOTIFY: + { + d = (config_main_dlg_data *) + GetWindowLongPtr(hwnd, DWLP_USER); + + /* WMCFG_APPLY is the only notification we care about */ + + if (HIWORD(wParam) == WMCFG_APPLY) { + /* TODO: Apply changes and update the state */ + + return TRUE; + } + } + break; + + case WM_DESTROY: + d = (config_main_dlg_data *) + GetWindowLongPtr(hwnd, DWLP_USER); + + /* TODO: perform any other required uninitialization here */ + + if (d) + free(d); + + break; + } + + return FALSE; + +} diff --git a/src/windows/identity/sample/templates/credprov/credacq.c b/src/windows/identity/sample/templates/credprov/credacq.c index da07756da..cd8db44ee 100644 --- a/src/windows/identity/sample/templates/credprov/credacq.c +++ b/src/windows/identity/sample/templates/credprov/credacq.c @@ -1,405 +1,405 @@ -/* - * Copyright (c) 2006 Secure Endpoints Inc. - * - * 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 "credprov.h" -#include - -/* This file provides handlers for the credentials acquisition - messages including handling the user interface for the new - credentials dialogs. */ - -/********************************************************************* - -These are stubs for the Window message for the dialog panel. This -dialog panel is the one that is added to the new credentials window -for obtaining new credentials. - -Note that all the UI callbacks run under the UI thread. - - *********************************************************************/ - -/* This structure will hold all the state information we will need to - access from the new credentials panel for our credentials type. */ -struct nc_dialog_data { - khui_new_creds * nc; - khui_new_creds_by_type * nct; - - /* TODO: add any other state information here */ -}; - -/* Note: This callback runs under the UI thread */ -INT_PTR -handle_wm_initdialog(HWND hwnd, WPARAM wParam, LPARAM lParam) { - khui_new_creds * nc = NULL; - khui_new_creds_by_type * nct = NULL; - struct nc_dialog_data * d = NULL; - - nc = (khui_new_creds *) lParam; - khui_cw_find_type(nc, credtype_id, &nct); - - assert(nct); - - d = malloc(sizeof(*d)); - ZeroMemory(d, sizeof(*d)); - - d->nc = nc; - d->nct = nct; - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM) d); -#pragma warning(pop) - - nct->aux = (LPARAM) d; /* we can use the auxiliary field to - hold a pointer to d */ - - /* TODO: Perform any additional initialization here */ - - return FALSE; -} - -/* Note: This callback runs under the UI thread */ -INT_PTR -handle_khui_wm_nc_notify(HWND hwnd, WPARAM wParam, LPARAM lParam) { - - struct nc_dialog_data * d; - - /* Refer to the khui_wm_nc_notifications enumeration in the - NetIDMgr SDK for the full list of notification messages that - can be sent. */ - - d = (struct nc_dialog_data *) GetWindowLongPtr(hwnd, DWLP_USER); - - if (!d) - return TRUE; - - /* these should be set by now */ - assert(d->nc); - assert(d->nct); - - switch (HIWORD(wParam)) { - case WMNC_UPDATE_CREDTEXT: - { - wchar_t fmt[KHUI_MAXCCH_LONG_DESC]; - wchar_t tbuf[256]; - - /* we are being requested to update the credentials - text. We already allocated a buffer when we created the - nct structure. So we can just set the text here.*/ - - /* TODO: The credtext should reflect the credentials that - will be obtained when the new credentials operation - completes. */ - - LoadString(hResModule, IDS_NC_CT_TEMPLATE, - fmt, ARRAYLENGTH(fmt)); - - LoadString(hResModule, IDS_GEN_NONE, - tbuf, ARRAYLENGTH(tbuf)); - - assert(d->nct->credtext); - - StringCbPrintf(d->nct->credtext, KHUI_MAXCB_LONG_DESC, - fmt, tbuf); - } - break; - - case WMNC_CREDTEXT_LINK: - break; - - case WMNC_IDENTITY_CHANGE: - break; - - case WMNC_DIALOG_PREPROCESS: - break; - } - - return TRUE; -} - -/* Note: This callback runs under the UI thread */ -INT_PTR -handle_wm_command(HWND hwnd, WPARAM wParam, LPARAM lParam) { - - struct nc_dialog_data * d; - - d = (struct nc_dialog_data *) GetWindowLongPtr(hwnd, DWLP_USER); - - /* TODO: handle WM_COMMAND */ - return FALSE; -} - -/* Note: This callback runs under the UI thread */ -INT_PTR -handle_wm_destroy(HWND hwnd, WPARAM wParam, LPARAM lParam) { - - struct nc_dialog_data * d; - - d = (struct nc_dialog_data *) GetWindowLongPtr(hwnd, DWLP_USER); - - if (d) { - d->nc = NULL; - d->nct = NULL; - - free(d); - } - - /* TODO: Perform any additional uninitialization */ - - return FALSE; -} - -/* Dialog procedure for the new credentials panel for our credentials - type. We just dispatch messages here to other functions here. - - Note that this procedure runs under the UI thread. - */ -INT_PTR CALLBACK -nc_dlg_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - - switch (uMsg) { - case WM_INITDIALOG: - return handle_wm_initdialog(hwnd, wParam, lParam); - - case WM_COMMAND: - return handle_wm_command(hwnd, wParam, lParam); - - case KHUI_WM_NC_NOTIFY: - return handle_khui_wm_nc_notify(hwnd, wParam, lParam); - - case WM_DESTROY: - return handle_wm_destroy(hwnd, wParam, lParam); - - /* TODO: add code for handling other windows messages here. */ - } - - return FALSE; -} - -/******************************************************************* - -The following section contains function stubs for each of the -credentials messages that a credentials provider is likely to want to -handle. It doesn't include a few messages, but they should be easy to -add. Please see the documentation for each of the KMSG_CRED_* -messages for documentation on how to handle each of the messages. - -********************************************************************/ - - -/* Handler for KMSG_CRED_NEW_CREDS */ -khm_int32 -handle_kmsg_cred_new_creds(khui_new_creds * nc) { - - wchar_t wshortdesc[KHUI_MAXCCH_SHORT_DESC]; - size_t cb = 0; - khui_new_creds_by_type * nct = NULL; - - /* This is a minimal handler that just adds a dialog pane to the - new credentials window to handle new credentials acquisition - for this credentials type. */ - - /* TODO: add additional initialization etc. as needed */ - - nct = malloc(sizeof(*nct)); - ZeroMemory(nct, sizeof(*nct)); - - nct->type = credtype_id; - nct->ordinal = -1; - - LoadString(hResModule, IDS_CT_SHORT_DESC, - wshortdesc, ARRAYLENGTH(wshortdesc)); - StringCbLength(wshortdesc, sizeof(wshortdesc), &cb); -#ifdef DEBUG - assert(cb > 0); -#endif - cb += sizeof(wchar_t); - - nct->name = malloc(cb); - StringCbCopy(nct->name, cb, wshortdesc); - - /* while we are at it, we should also allocate space for the - credential text. */ - nct->credtext = malloc(KHUI_MAXCB_LONG_DESC); - ZeroMemory(nct->credtext, KHUI_MAXCB_LONG_DESC); - - nct->h_module = hResModule; - nct->dlg_proc = nc_dlg_proc; - nct->dlg_template = MAKEINTRESOURCE(IDD_NEW_CREDS); - - khui_cw_add_type(nc, nct); - - return KHM_ERROR_SUCCESS; -} - -/* Handler for KMSG_CRED_RENEW_CREDS */ -khm_int32 -handle_kmsg_cred_renew_creds(khui_new_creds * nc) { - - khui_new_creds_by_type * nct; - - /* This is a minimal handler that just adds this credential type - to the list of credential types that are participating in this - renewal operation. */ - - /* TODO: add additional initialization etc. as needed */ - - nct = malloc(sizeof(*nct)); - ZeroMemory(nct, sizeof(*nct)); - - nct->type = credtype_id; - - khui_cw_add_type(nc, nct); - - return KHM_ERROR_SUCCESS; -} - -/* Handler for KMSG_CRED_DIALOG_PRESTART */ -khm_int32 -handle_kmsg_cred_dialog_prestart(khui_new_creds * nc) { - /* TODO: Handle this message */ - - /* The message is sent after the dialog has been created. The - window handle for the created dialog can be accessed through - the hwnd_panel member of the khui_new_creds_by_type structure - that was added for this credentials type. */ - return KHM_ERROR_SUCCESS; -} - -/* Handler for KMSG_CRED_DIALOG_NEW_IDENTITY */ -/* Not a message sent out by NetIDMgr. See documentation of - KMSG_CRED_DIALOG_NEW_IDENTITY */ -khm_int32 -handle_kmsg_cred_dialog_new_identity(khm_ui_4 uparam, - void * vparam) { - /* TODO: Handle this message */ - return KHM_ERROR_SUCCESS; -} - -/* Handler for KMSG_CRED_DIALOG_NEW_OPTIONS */ -/* Not a message sent out by NetIDMgr. See documentation of - KMSG_CRED_DIALOG_NEW_OPTIONS */ -khm_int32 -handle_kmsg_cred_dialog_new_options(khm_ui_4 uparam, - void * vparam) { - /* TODO: Handle this message */ - return KHM_ERROR_SUCCESS; -} - -/* Handler for KMSG_CRED_PROCESS */ -khm_int32 -handle_kmsg_cred_process(khui_new_creds * nc) { - /* TODO: Handle this message */ - - /* This is where the credentials acquisition should be performed - as determined by the UI. Note that this message is sent even - when the user clicks 'cancel'. The value of nc->result should - be checked before performing any credentials acquisition. If - the value is KHUI_NC_RESULT_CANCEL, then no credentials should - be acquired. Otherwise, the value would be - KHUI_NC_RESULT_PROCESS. */ - - return KHM_ERROR_SUCCESS; -} - -/* Handler for KMSG_CRED_END */ -khm_int32 -handle_kmsg_cred_end(khui_new_creds * nc) { - - khui_new_creds_by_type * nct = NULL; - - /* TODO: Perform any additional uninitialization as needed. */ - - khui_cw_find_type(nc, credtype_id, &nct); - - if (nct) { - - khui_cw_del_type(nc, credtype_id); - - if (nct->name) - free(nct->name); - if (nct->credtext) - free(nct->credtext); - - free(nct); - - } - - return KHM_ERROR_SUCCESS; -} - -/* Handler for KMSG_CRED_IMPORT */ -khm_int32 -handle_kmsg_cred_import(void) { - - /* TODO: Handle this message */ - - return KHM_ERROR_SUCCESS; -} - - -/****************************************************** - Dispatch each message to individual handlers above. - */ -khm_int32 KHMAPI -handle_cred_acq_msg(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam) { - - khm_int32 rv = KHM_ERROR_SUCCESS; - - switch(msg_subtype) { - case KMSG_CRED_NEW_CREDS: - return handle_kmsg_cred_new_creds((khui_new_creds *) vparam); - - case KMSG_CRED_RENEW_CREDS: - return handle_kmsg_cred_renew_creds((khui_new_creds *) vparam); - - case KMSG_CRED_DIALOG_PRESTART: - return handle_kmsg_cred_dialog_prestart((khui_new_creds *) vparam); - - case KMSG_CRED_PROCESS: - return handle_kmsg_cred_process((khui_new_creds *) vparam); - - case KMSG_CRED_DIALOG_NEW_IDENTITY: - return handle_kmsg_cred_dialog_new_identity(uparam, vparam); - - case KMSG_CRED_DIALOG_NEW_OPTIONS: - return handle_kmsg_cred_dialog_new_options(uparam, vparam); - - case KMSG_CRED_END: - return handle_kmsg_cred_end((khui_new_creds *) vparam); - - case KMSG_CRED_IMPORT: - return handle_kmsg_cred_import(); - } - - return rv; -} +/* + * Copyright (c) 2006 Secure Endpoints Inc. + * + * 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 "credprov.h" +#include + +/* This file provides handlers for the credentials acquisition + messages including handling the user interface for the new + credentials dialogs. */ + +/********************************************************************* + +These are stubs for the Window message for the dialog panel. This +dialog panel is the one that is added to the new credentials window +for obtaining new credentials. + +Note that all the UI callbacks run under the UI thread. + + *********************************************************************/ + +/* This structure will hold all the state information we will need to + access from the new credentials panel for our credentials type. */ +struct nc_dialog_data { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + + /* TODO: add any other state information here */ +}; + +/* Note: This callback runs under the UI thread */ +INT_PTR +handle_wm_initdialog(HWND hwnd, WPARAM wParam, LPARAM lParam) { + khui_new_creds * nc = NULL; + khui_new_creds_by_type * nct = NULL; + struct nc_dialog_data * d = NULL; + + nc = (khui_new_creds *) lParam; + khui_cw_find_type(nc, credtype_id, &nct); + + assert(nct); + + d = malloc(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + + d->nc = nc; + d->nct = nct; + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM) d); +#pragma warning(pop) + + nct->aux = (LPARAM) d; /* we can use the auxiliary field to + hold a pointer to d */ + + /* TODO: Perform any additional initialization here */ + + return FALSE; +} + +/* Note: This callback runs under the UI thread */ +INT_PTR +handle_khui_wm_nc_notify(HWND hwnd, WPARAM wParam, LPARAM lParam) { + + struct nc_dialog_data * d; + + /* Refer to the khui_wm_nc_notifications enumeration in the + NetIDMgr SDK for the full list of notification messages that + can be sent. */ + + d = (struct nc_dialog_data *) GetWindowLongPtr(hwnd, DWLP_USER); + + if (!d) + return TRUE; + + /* these should be set by now */ + assert(d->nc); + assert(d->nct); + + switch (HIWORD(wParam)) { + case WMNC_UPDATE_CREDTEXT: + { + wchar_t fmt[KHUI_MAXCCH_LONG_DESC]; + wchar_t tbuf[256]; + + /* we are being requested to update the credentials + text. We already allocated a buffer when we created the + nct structure. So we can just set the text here.*/ + + /* TODO: The credtext should reflect the credentials that + will be obtained when the new credentials operation + completes. */ + + LoadString(hResModule, IDS_NC_CT_TEMPLATE, + fmt, ARRAYLENGTH(fmt)); + + LoadString(hResModule, IDS_GEN_NONE, + tbuf, ARRAYLENGTH(tbuf)); + + assert(d->nct->credtext); + + StringCbPrintf(d->nct->credtext, KHUI_MAXCB_LONG_DESC, + fmt, tbuf); + } + break; + + case WMNC_CREDTEXT_LINK: + break; + + case WMNC_IDENTITY_CHANGE: + break; + + case WMNC_DIALOG_PREPROCESS: + break; + } + + return TRUE; +} + +/* Note: This callback runs under the UI thread */ +INT_PTR +handle_wm_command(HWND hwnd, WPARAM wParam, LPARAM lParam) { + + struct nc_dialog_data * d; + + d = (struct nc_dialog_data *) GetWindowLongPtr(hwnd, DWLP_USER); + + /* TODO: handle WM_COMMAND */ + return FALSE; +} + +/* Note: This callback runs under the UI thread */ +INT_PTR +handle_wm_destroy(HWND hwnd, WPARAM wParam, LPARAM lParam) { + + struct nc_dialog_data * d; + + d = (struct nc_dialog_data *) GetWindowLongPtr(hwnd, DWLP_USER); + + if (d) { + d->nc = NULL; + d->nct = NULL; + + free(d); + } + + /* TODO: Perform any additional uninitialization */ + + return FALSE; +} + +/* Dialog procedure for the new credentials panel for our credentials + type. We just dispatch messages here to other functions here. + + Note that this procedure runs under the UI thread. + */ +INT_PTR CALLBACK +nc_dlg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + switch (uMsg) { + case WM_INITDIALOG: + return handle_wm_initdialog(hwnd, wParam, lParam); + + case WM_COMMAND: + return handle_wm_command(hwnd, wParam, lParam); + + case KHUI_WM_NC_NOTIFY: + return handle_khui_wm_nc_notify(hwnd, wParam, lParam); + + case WM_DESTROY: + return handle_wm_destroy(hwnd, wParam, lParam); + + /* TODO: add code for handling other windows messages here. */ + } + + return FALSE; +} + +/******************************************************************* + +The following section contains function stubs for each of the +credentials messages that a credentials provider is likely to want to +handle. It doesn't include a few messages, but they should be easy to +add. Please see the documentation for each of the KMSG_CRED_* +messages for documentation on how to handle each of the messages. + +********************************************************************/ + + +/* Handler for KMSG_CRED_NEW_CREDS */ +khm_int32 +handle_kmsg_cred_new_creds(khui_new_creds * nc) { + + wchar_t wshortdesc[KHUI_MAXCCH_SHORT_DESC]; + size_t cb = 0; + khui_new_creds_by_type * nct = NULL; + + /* This is a minimal handler that just adds a dialog pane to the + new credentials window to handle new credentials acquisition + for this credentials type. */ + + /* TODO: add additional initialization etc. as needed */ + + nct = malloc(sizeof(*nct)); + ZeroMemory(nct, sizeof(*nct)); + + nct->type = credtype_id; + nct->ordinal = -1; + + LoadString(hResModule, IDS_CT_SHORT_DESC, + wshortdesc, ARRAYLENGTH(wshortdesc)); + StringCbLength(wshortdesc, sizeof(wshortdesc), &cb); +#ifdef DEBUG + assert(cb > 0); +#endif + cb += sizeof(wchar_t); + + nct->name = malloc(cb); + StringCbCopy(nct->name, cb, wshortdesc); + + /* while we are at it, we should also allocate space for the + credential text. */ + nct->credtext = malloc(KHUI_MAXCB_LONG_DESC); + ZeroMemory(nct->credtext, KHUI_MAXCB_LONG_DESC); + + nct->h_module = hResModule; + nct->dlg_proc = nc_dlg_proc; + nct->dlg_template = MAKEINTRESOURCE(IDD_NEW_CREDS); + + khui_cw_add_type(nc, nct); + + return KHM_ERROR_SUCCESS; +} + +/* Handler for KMSG_CRED_RENEW_CREDS */ +khm_int32 +handle_kmsg_cred_renew_creds(khui_new_creds * nc) { + + khui_new_creds_by_type * nct; + + /* This is a minimal handler that just adds this credential type + to the list of credential types that are participating in this + renewal operation. */ + + /* TODO: add additional initialization etc. as needed */ + + nct = malloc(sizeof(*nct)); + ZeroMemory(nct, sizeof(*nct)); + + nct->type = credtype_id; + + khui_cw_add_type(nc, nct); + + return KHM_ERROR_SUCCESS; +} + +/* Handler for KMSG_CRED_DIALOG_PRESTART */ +khm_int32 +handle_kmsg_cred_dialog_prestart(khui_new_creds * nc) { + /* TODO: Handle this message */ + + /* The message is sent after the dialog has been created. The + window handle for the created dialog can be accessed through + the hwnd_panel member of the khui_new_creds_by_type structure + that was added for this credentials type. */ + return KHM_ERROR_SUCCESS; +} + +/* Handler for KMSG_CRED_DIALOG_NEW_IDENTITY */ +/* Not a message sent out by NetIDMgr. See documentation of + KMSG_CRED_DIALOG_NEW_IDENTITY */ +khm_int32 +handle_kmsg_cred_dialog_new_identity(khm_ui_4 uparam, + void * vparam) { + /* TODO: Handle this message */ + return KHM_ERROR_SUCCESS; +} + +/* Handler for KMSG_CRED_DIALOG_NEW_OPTIONS */ +/* Not a message sent out by NetIDMgr. See documentation of + KMSG_CRED_DIALOG_NEW_OPTIONS */ +khm_int32 +handle_kmsg_cred_dialog_new_options(khm_ui_4 uparam, + void * vparam) { + /* TODO: Handle this message */ + return KHM_ERROR_SUCCESS; +} + +/* Handler for KMSG_CRED_PROCESS */ +khm_int32 +handle_kmsg_cred_process(khui_new_creds * nc) { + /* TODO: Handle this message */ + + /* This is where the credentials acquisition should be performed + as determined by the UI. Note that this message is sent even + when the user clicks 'cancel'. The value of nc->result should + be checked before performing any credentials acquisition. If + the value is KHUI_NC_RESULT_CANCEL, then no credentials should + be acquired. Otherwise, the value would be + KHUI_NC_RESULT_PROCESS. */ + + return KHM_ERROR_SUCCESS; +} + +/* Handler for KMSG_CRED_END */ +khm_int32 +handle_kmsg_cred_end(khui_new_creds * nc) { + + khui_new_creds_by_type * nct = NULL; + + /* TODO: Perform any additional uninitialization as needed. */ + + khui_cw_find_type(nc, credtype_id, &nct); + + if (nct) { + + khui_cw_del_type(nc, credtype_id); + + if (nct->name) + free(nct->name); + if (nct->credtext) + free(nct->credtext); + + free(nct); + + } + + return KHM_ERROR_SUCCESS; +} + +/* Handler for KMSG_CRED_IMPORT */ +khm_int32 +handle_kmsg_cred_import(void) { + + /* TODO: Handle this message */ + + return KHM_ERROR_SUCCESS; +} + + +/****************************************************** + Dispatch each message to individual handlers above. + */ +khm_int32 KHMAPI +handle_cred_acq_msg(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_CRED_NEW_CREDS: + return handle_kmsg_cred_new_creds((khui_new_creds *) vparam); + + case KMSG_CRED_RENEW_CREDS: + return handle_kmsg_cred_renew_creds((khui_new_creds *) vparam); + + case KMSG_CRED_DIALOG_PRESTART: + return handle_kmsg_cred_dialog_prestart((khui_new_creds *) vparam); + + case KMSG_CRED_PROCESS: + return handle_kmsg_cred_process((khui_new_creds *) vparam); + + case KMSG_CRED_DIALOG_NEW_IDENTITY: + return handle_kmsg_cred_dialog_new_identity(uparam, vparam); + + case KMSG_CRED_DIALOG_NEW_OPTIONS: + return handle_kmsg_cred_dialog_new_options(uparam, vparam); + + case KMSG_CRED_END: + return handle_kmsg_cred_end((khui_new_creds *) vparam); + + case KMSG_CRED_IMPORT: + return handle_kmsg_cred_import(); + } + + return rv; +} diff --git a/src/windows/identity/sample/templates/credprov/credprov.h b/src/windows/identity/sample/templates/credprov/credprov.h index 1851eaa4b..14670934d 100644 --- a/src/windows/identity/sample/templates/credprov/credprov.h +++ b/src/windows/identity/sample/templates/credprov/credprov.h @@ -1,176 +1,176 @@ -/* - * Copyright (c) 2006 Secure Endpoints Inc. - * - * 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$ */ - -/* only include this header file once */ -#pragma once - -#ifndef _UNICODE -#ifndef RC_INVOKED -/* This template relies on _UNICODE being defined to call the correct - APIs. */ -#error This template needs to be compiled with _UNICODE -#endif -#endif - -/* Pull in configuration macros from the Makefile */ -#include "credacq_config.h" - -/* declare a few macros about our plugin */ - -/* The following macro will be used throughout the template to refer - to the name of the plugin. The macro is actually defined the - Makefile generated configuration header file. Modify the - PLUGINNAME Makefile macro.*/ -#ifndef MYPLUGIN_NAME -#error MYPLUGIN_NAME not defined -#endif - -/* Also define the unicde equivalent of the name. In general strings - in NetIDMgr are unicode. */ -#define MYPLUGIN_NAMEW _T(MYPLUGIN_NAME) - -/* The name of the module. This is distinct from the name of the - plugin for several reasons. One of which is that a single module - can provide multiple plugins. Also, having a module name distinct - from a plugin name allows multiple vendors to provide the same - plugin. For example, the module name for the MIT Kerberos 5 plugin - is MITKrb5 while the plugin name is Krb5Cred. The macro is - actually defined in the Makefile generated configuration header - file. Modify the MODULENAME Makefile macro.*/ -#ifndef MYMODULE_NAME -#error MYMODULE_NAME not defined -#endif - -#define MYMODULE_NAMEW _T(MYMODULE_NAME) - -/* When logging events from our plugin, the event logging API can - optionally take a facility name to provide a friendly label to - identify where each event came from. We will default to the plugin - name, although it can be anything. */ -#define MYPLUGIN_FACILITYW MYPLUGIN_NAMEW - -/* Base name of the DLL that will be providing the plugin. We use it - to construct names of the DLLs that will contain localized - resources. This is defined in the Makefile and fed in to the build - through there. The macro to change in the Makefile is - DLLBASENAME. */ -#ifndef MYPLUGIN_DLLBASE -#error MYPLUGIN_DLLBASE Not defined! -#endif - -#define MYPLUGIN_DLLBASEW _T(MYPLUGIN_DLLBASE) - -/* Name of the credentials type that will be registered by the plugin. - This macro is actually defined in the Makefile generated - configuration header file. Change the CREDTYPENAME macro in the - Makefile. */ -#ifndef MYCREDTYPE_NAME -#error MYCREDTYPE_NAME not defined -#endif - -#define MYCREDTYPE_NAMEW _T(MYCREDTYPE_NAME) - -/* Configuration node names. We just concatenate a few strings - together, although you should feel free to completely define your - own. */ - -#define CONFIGNODE_MAIN MYCREDTYPE_NAMEW L"Config" -#define CONFIGNODE_ALL_ID MYCREDTYPE_NAMEW L"AllIdents" -#define CONFIGNODE_PER_ID MYCREDTYPE_NAMEW L"PerIdent" - -#include -/* include the standard NetIDMgr header files */ -#include -#include - -/* declarations for language resources */ -#include "langres.h" - -#ifndef NOSTRSAFE -#include -#endif - -/*************************************************** - Externals -***************************************************/ - -extern kmm_module h_khModule; -extern HINSTANCE hInstance; -extern HMODULE hResModule; - -extern const wchar_t * my_facility; - -extern khm_int32 credtype_id; - -/* Function declarations */ - -/* in plugin.c */ -khm_int32 KHMAPI -plugin_msg_proc(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam); - -/* in credtype.c */ -khm_int32 KHMAPI -cred_is_equal(khm_handle cred1, - khm_handle cred2, - void * rock); - -/* in credacq.c */ -khm_int32 KHMAPI -handle_cred_acq_msg(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam); - -/* in proppage.c */ -INT_PTR CALLBACK -pp_cred_dlg_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -/* in config_id.c */ -INT_PTR CALLBACK -config_id_dlgproc(HWND hwndDlg, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -/* in config_ids.c */ -INT_PTR CALLBACK -config_ids_dlgproc(HWND hwndDlg, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -/* in config_main.c */ -INT_PTR CALLBACK -config_dlgproc(HWND hwndDlg, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); +/* + * Copyright (c) 2006 Secure Endpoints Inc. + * + * 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$ */ + +/* only include this header file once */ +#pragma once + +#ifndef _UNICODE +#ifndef RC_INVOKED +/* This template relies on _UNICODE being defined to call the correct + APIs. */ +#error This template needs to be compiled with _UNICODE +#endif +#endif + +/* Pull in configuration macros from the Makefile */ +#include "credacq_config.h" + +/* declare a few macros about our plugin */ + +/* The following macro will be used throughout the template to refer + to the name of the plugin. The macro is actually defined the + Makefile generated configuration header file. Modify the + PLUGINNAME Makefile macro.*/ +#ifndef MYPLUGIN_NAME +#error MYPLUGIN_NAME not defined +#endif + +/* Also define the unicde equivalent of the name. In general strings + in NetIDMgr are unicode. */ +#define MYPLUGIN_NAMEW _T(MYPLUGIN_NAME) + +/* The name of the module. This is distinct from the name of the + plugin for several reasons. One of which is that a single module + can provide multiple plugins. Also, having a module name distinct + from a plugin name allows multiple vendors to provide the same + plugin. For example, the module name for the MIT Kerberos 5 plugin + is MITKrb5 while the plugin name is Krb5Cred. The macro is + actually defined in the Makefile generated configuration header + file. Modify the MODULENAME Makefile macro.*/ +#ifndef MYMODULE_NAME +#error MYMODULE_NAME not defined +#endif + +#define MYMODULE_NAMEW _T(MYMODULE_NAME) + +/* When logging events from our plugin, the event logging API can + optionally take a facility name to provide a friendly label to + identify where each event came from. We will default to the plugin + name, although it can be anything. */ +#define MYPLUGIN_FACILITYW MYPLUGIN_NAMEW + +/* Base name of the DLL that will be providing the plugin. We use it + to construct names of the DLLs that will contain localized + resources. This is defined in the Makefile and fed in to the build + through there. The macro to change in the Makefile is + DLLBASENAME. */ +#ifndef MYPLUGIN_DLLBASE +#error MYPLUGIN_DLLBASE Not defined! +#endif + +#define MYPLUGIN_DLLBASEW _T(MYPLUGIN_DLLBASE) + +/* Name of the credentials type that will be registered by the plugin. + This macro is actually defined in the Makefile generated + configuration header file. Change the CREDTYPENAME macro in the + Makefile. */ +#ifndef MYCREDTYPE_NAME +#error MYCREDTYPE_NAME not defined +#endif + +#define MYCREDTYPE_NAMEW _T(MYCREDTYPE_NAME) + +/* Configuration node names. We just concatenate a few strings + together, although you should feel free to completely define your + own. */ + +#define CONFIGNODE_MAIN MYCREDTYPE_NAMEW L"Config" +#define CONFIGNODE_ALL_ID MYCREDTYPE_NAMEW L"AllIdents" +#define CONFIGNODE_PER_ID MYCREDTYPE_NAMEW L"PerIdent" + +#include +/* include the standard NetIDMgr header files */ +#include +#include + +/* declarations for language resources */ +#include "langres.h" + +#ifndef NOSTRSAFE +#include +#endif + +/*************************************************** + Externals +***************************************************/ + +extern kmm_module h_khModule; +extern HINSTANCE hInstance; +extern HMODULE hResModule; + +extern const wchar_t * my_facility; + +extern khm_int32 credtype_id; + +/* Function declarations */ + +/* in plugin.c */ +khm_int32 KHMAPI +plugin_msg_proc(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam); + +/* in credtype.c */ +khm_int32 KHMAPI +cred_is_equal(khm_handle cred1, + khm_handle cred2, + void * rock); + +/* in credacq.c */ +khm_int32 KHMAPI +handle_cred_acq_msg(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam); + +/* in proppage.c */ +INT_PTR CALLBACK +pp_cred_dlg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +/* in config_id.c */ +INT_PTR CALLBACK +config_id_dlgproc(HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +/* in config_ids.c */ +INT_PTR CALLBACK +config_ids_dlgproc(HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +/* in config_main.c */ +INT_PTR CALLBACK +config_dlgproc(HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); diff --git a/src/windows/identity/sample/templates/credprov/credtype.c b/src/windows/identity/sample/templates/credprov/credtype.c index 039c64454..cee7df19a 100644 --- a/src/windows/identity/sample/templates/credprov/credtype.c +++ b/src/windows/identity/sample/templates/credprov/credtype.c @@ -1,52 +1,52 @@ -/* - * Copyright (c) 2006 Secure Endpoints Inc. - * - * 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 AND - * 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 "credprov.h" - -/* Functions for handling our credentials type. -*/ - -khm_int32 KHMAPI -cred_is_equal(khm_handle cred1, - khm_handle cred2, - void * rock) { - - khm_int32 result; - - /* TODO: Check any additional fields to determine if the two - credentials are equal or not. */ - - /* Note that this is actually a comparison function. It should - return 0 if the credentials are found to be equal, and non-zero - if they are not. We just set this to 0 if we don't need to - check any additional fields and accept the two credentials as - being equal. By the time this function is called, the - identity, name and type of the credentials have already been - found to be equal. */ - result = 0; - - return result; -} +/* + * Copyright (c) 2006 Secure Endpoints Inc. + * + * 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 AND + * 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 "credprov.h" + +/* Functions for handling our credentials type. +*/ + +khm_int32 KHMAPI +cred_is_equal(khm_handle cred1, + khm_handle cred2, + void * rock) { + + khm_int32 result; + + /* TODO: Check any additional fields to determine if the two + credentials are equal or not. */ + + /* Note that this is actually a comparison function. It should + return 0 if the credentials are found to be equal, and non-zero + if they are not. We just set this to 0 if we don't need to + check any additional fields and accept the two credentials as + being equal. By the time this function is called, the + identity, name and type of the credentials have already been + found to be equal. */ + result = 0; + + return result; +} diff --git a/src/windows/identity/sample/templates/credprov/langres.h b/src/windows/identity/sample/templates/credprov/langres.h index 2b81c554d..962c4cb22 100644 --- a/src/windows/identity/sample/templates/credprov/langres.h +++ b/src/windows/identity/sample/templates/credprov/langres.h @@ -1,34 +1,34 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by C:\work\pismere\athena\auth\krb5\src\windows\identity\sample\templates\credprov\lang\en_us\langres.rc -// -#define IDD_PP_CRED 106 -#define IDD_PP_IDENT 107 -#define IDS_PLUGIN_DESC 109 -#define IDS_CT_SHORT_DESC 110 -#define IDI_PLUGIN 110 -#define IDS_CT_LONG_DESC 111 -#define IDD_NEW_CREDS 112 -#define IDS_NC_CT_TEMPLATE 112 -#define IDS_NC_CT_TEMPLATE_NL 113 -#define IDD_CONFIG 113 -#define IDS_GEN_NONE 114 -#define IDD_CONFIG_ID 114 -#define IDS_CFG_SHORT_DESC 115 -#define IDD_CONFIG_IDS 115 -#define IDS_CFG_LONG_DESC 116 -#define IDS_CFG_IDS_SHORT_DESC 117 -#define IDS_CFG_IDS_LONG_DESC 118 -#define IDS_CFG_ID_SHORT_DESC 119 -#define IDS_CFG_ID_LONG_DESC 120 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 116 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1039 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by C:\work\pismere\athena\auth\krb5\src\windows\identity\sample\templates\credprov\lang\en_us\langres.rc +// +#define IDD_PP_CRED 106 +#define IDD_PP_IDENT 107 +#define IDS_PLUGIN_DESC 109 +#define IDS_CT_SHORT_DESC 110 +#define IDI_PLUGIN 110 +#define IDS_CT_LONG_DESC 111 +#define IDD_NEW_CREDS 112 +#define IDS_NC_CT_TEMPLATE 112 +#define IDS_NC_CT_TEMPLATE_NL 113 +#define IDD_CONFIG 113 +#define IDS_GEN_NONE 114 +#define IDD_CONFIG_ID 114 +#define IDS_CFG_SHORT_DESC 115 +#define IDD_CONFIG_IDS 115 +#define IDS_CFG_LONG_DESC 116 +#define IDS_CFG_IDS_SHORT_DESC 117 +#define IDS_CFG_IDS_LONG_DESC 118 +#define IDS_CFG_ID_SHORT_DESC 119 +#define IDS_CFG_ID_LONG_DESC 120 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 116 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1039 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/windows/identity/sample/templates/credprov/main.c b/src/windows/identity/sample/templates/credprov/main.c index 7a5020573..07da40d57 100644 --- a/src/windows/identity/sample/templates/credprov/main.c +++ b/src/windows/identity/sample/templates/credprov/main.c @@ -1,171 +1,171 @@ -/* - * Copyright (c) 2006 Secure Endpoints Inc. - * - * 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 "credprov.h" - -/* This file provides the entry points for the module. The purpose of - each entry point is explained below. -*/ - -kmm_module h_khModule; /* KMM's handle to this module */ -HINSTANCE hInstance; /* handle to our DLL */ -HMODULE hResModule; /* handle to DLL containing language specific resources */ - -const wchar_t * my_facility = MYPLUGIN_FACILITYW; - -/* locales and n_locales are used to provide information to NetIDMgr - about the locales that we support. Each locale that is supported - is represented by a single line below. NetIDMgr will pick a - suitable locale from this list as described in the documentation - for kmm_set_locale_info(). */ -kmm_module_locale locales[] = { - - /* there needs to be at least one language that is supported. - Here we declare that to be US English, and make it the - default. */ - LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), - MYPLUGIN_DLLBASEW L"_en_us.dll", /* this is the name of - the DLL. We paste a - trailer to basename - of the DLL. This - DLL should reside in - the same directory - as the plugin - DLL. */ - KMM_MLOC_FLAG_DEFAULT) -}; -int n_locales = ARRAYLENGTH(locales); - -/******************************************************************* - init_module - ***************************************************************** - - This is the entry point for the module. Each module can provide - multiple plugins and each plugin will need a separate entry point. - Generally, the module entry point will set up localized resources - and register the plugins. - -*/ -KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { - - khm_int32 rv = KHM_ERROR_SUCCESS; - kmm_plugin_reg pi; - wchar_t description[KMM_MAXCCH_DESC]; - int t; - - h_khModule = h_module; - - rv = kmm_set_locale_info(h_module, locales, n_locales); - if(KHM_SUCCEEDED(rv)) { - /* if the call succeeded, then NetIDMgr has picked a localized - resource DLL for us to use. */ - hResModule = kmm_get_resource_hmodule(h_module); - } else - goto _exit; - - /* TODO: Perform any other required initialization operations. */ - - /* register our plugin */ - ZeroMemory(&pi, sizeof(pi)); - - pi.name = MYPLUGIN_NAMEW; /* name of the plugin */ - pi.type = KHM_PITYPE_CRED; /* type. This is a credentials - provider. Setting this type has - the effect of having the plugin - entrypoint being automatically - subscribed to credentials provider - messages. */ - - /* An icon is optional, but we provide one anyway. */ - pi.icon = LoadImage(hResModule, MAKEINTRESOURCE(IDI_PLUGIN), - IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE); - pi.flags = 0; - pi.msg_proc = plugin_msg_proc; - pi.description = description; - pi.dependencies = NULL; - t = LoadString(hResModule, IDS_PLUGIN_DESC, - description, ARRAYLENGTH(description)); - if (!t) - description[0] = L'\0'; - else - description[ARRAYLENGTH(description) - 1] = L'\0'; - - rv = kmm_provide_plugin(h_module, &pi); - - /* TODO: register any additional plugins */ - - /* Returning a successful code (KHM_ERROR_SUCCESS) will cause the - plugins to be initialized. If no plugin is successfully - registered while processing init_module or if a code other than - KHM_ERROR_SUCCESS is returned, the module will be immediately - unloaded. */ - - _exit: - return rv; -} - -/********************************************************** - Exit module - ******************************************************** - - Called by the NetIDMgr module manager when unloading the module. - This will get called even if the module is being unloaded due to an - error code returned by init_module(). This callback is required. */ -KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module) { - - /* Unregistering the plugin is not required at this point. */ - - /* TODO: Perform any other required cleanup here. */ - - return KHM_ERROR_SUCCESS; /* the return code is ignored */ -} - -/* General DLL initialization. It is advisable to not do anything - here and also keep in mind that the plugin will be loaded at a time - where some threads have already started. So DLL_THREAD_ATTACH will - not fire for every thread. In addition, the plugin will be - unloaded before the application and all the threads terminate. */ -BOOL WINAPI DllMain(HINSTANCE hinstDLL, - DWORD fdwReason, - LPVOID lpvReserved) -{ - switch(fdwReason) { - case DLL_PROCESS_ATTACH: - hInstance = hinstDLL; - break; - - case DLL_PROCESS_DETACH: - break; - - case DLL_THREAD_ATTACH: - break; - - case DLL_THREAD_DETACH: - break; - } - - return TRUE; -} +/* + * Copyright (c) 2006 Secure Endpoints Inc. + * + * 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 "credprov.h" + +/* This file provides the entry points for the module. The purpose of + each entry point is explained below. +*/ + +kmm_module h_khModule; /* KMM's handle to this module */ +HINSTANCE hInstance; /* handle to our DLL */ +HMODULE hResModule; /* handle to DLL containing language specific resources */ + +const wchar_t * my_facility = MYPLUGIN_FACILITYW; + +/* locales and n_locales are used to provide information to NetIDMgr + about the locales that we support. Each locale that is supported + is represented by a single line below. NetIDMgr will pick a + suitable locale from this list as described in the documentation + for kmm_set_locale_info(). */ +kmm_module_locale locales[] = { + + /* there needs to be at least one language that is supported. + Here we declare that to be US English, and make it the + default. */ + LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), + MYPLUGIN_DLLBASEW L"_en_us.dll", /* this is the name of + the DLL. We paste a + trailer to basename + of the DLL. This + DLL should reside in + the same directory + as the plugin + DLL. */ + KMM_MLOC_FLAG_DEFAULT) +}; +int n_locales = ARRAYLENGTH(locales); + +/******************************************************************* + init_module + ***************************************************************** + + This is the entry point for the module. Each module can provide + multiple plugins and each plugin will need a separate entry point. + Generally, the module entry point will set up localized resources + and register the plugins. + +*/ +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { + + khm_int32 rv = KHM_ERROR_SUCCESS; + kmm_plugin_reg pi; + wchar_t description[KMM_MAXCCH_DESC]; + int t; + + h_khModule = h_module; + + rv = kmm_set_locale_info(h_module, locales, n_locales); + if(KHM_SUCCEEDED(rv)) { + /* if the call succeeded, then NetIDMgr has picked a localized + resource DLL for us to use. */ + hResModule = kmm_get_resource_hmodule(h_module); + } else + goto _exit; + + /* TODO: Perform any other required initialization operations. */ + + /* register our plugin */ + ZeroMemory(&pi, sizeof(pi)); + + pi.name = MYPLUGIN_NAMEW; /* name of the plugin */ + pi.type = KHM_PITYPE_CRED; /* type. This is a credentials + provider. Setting this type has + the effect of having the plugin + entrypoint being automatically + subscribed to credentials provider + messages. */ + + /* An icon is optional, but we provide one anyway. */ + pi.icon = LoadImage(hResModule, MAKEINTRESOURCE(IDI_PLUGIN), + IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE); + pi.flags = 0; + pi.msg_proc = plugin_msg_proc; + pi.description = description; + pi.dependencies = NULL; + t = LoadString(hResModule, IDS_PLUGIN_DESC, + description, ARRAYLENGTH(description)); + if (!t) + description[0] = L'\0'; + else + description[ARRAYLENGTH(description) - 1] = L'\0'; + + rv = kmm_provide_plugin(h_module, &pi); + + /* TODO: register any additional plugins */ + + /* Returning a successful code (KHM_ERROR_SUCCESS) will cause the + plugins to be initialized. If no plugin is successfully + registered while processing init_module or if a code other than + KHM_ERROR_SUCCESS is returned, the module will be immediately + unloaded. */ + + _exit: + return rv; +} + +/********************************************************** + Exit module + ******************************************************** + + Called by the NetIDMgr module manager when unloading the module. + This will get called even if the module is being unloaded due to an + error code returned by init_module(). This callback is required. */ +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module) { + + /* Unregistering the plugin is not required at this point. */ + + /* TODO: Perform any other required cleanup here. */ + + return KHM_ERROR_SUCCESS; /* the return code is ignored */ +} + +/* General DLL initialization. It is advisable to not do anything + here and also keep in mind that the plugin will be loaded at a time + where some threads have already started. So DLL_THREAD_ATTACH will + not fire for every thread. In addition, the plugin will be + unloaded before the application and all the threads terminate. */ +BOOL WINAPI DllMain(HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ + switch(fdwReason) { + case DLL_PROCESS_ATTACH: + hInstance = hinstDLL; + break; + + case DLL_PROCESS_DETACH: + break; + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + break; + } + + return TRUE; +} diff --git a/src/windows/identity/sample/templates/credprov/plugin.c b/src/windows/identity/sample/templates/credprov/plugin.c index 31c9626a5..9b1b0ce94 100644 --- a/src/windows/identity/sample/templates/credprov/plugin.c +++ b/src/windows/identity/sample/templates/credprov/plugin.c @@ -1,382 +1,382 @@ -/* - * Copyright (c) 2006 Secure Endpoints Inc. - * - * 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 "credprov.h" -#include - -/* This file provides the message processing function and the support - routines for implementing our plugin. Note that some of the - message processing routines have been moved to other source files - based on their use. -*/ - -khm_int32 credtype_id = KCDB_CREDTYPE_INVALID; -khm_handle g_credset = NULL; - -/* Handler for system messages. The only two we handle are - KMSG_SYSTEM_INIT and KMSG_SYSTEM_EXIT. */ -khm_int32 KHMAPI -handle_kmsg_system(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam) { - khm_int32 rv = KHM_ERROR_SUCCESS; - - switch (msg_subtype) { - - /* This is the first message that will be received by a - plugin. We use it to perform initialization operations - such as registering any credential types, data types and - attributes. */ - case KMSG_SYSTEM_INIT: - { - kcdb_credtype ct; - wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC]; - wchar_t long_desc[KCDB_MAXCCH_LONG_DESC]; - khui_config_node cnode; - khui_config_node_reg creg; - - /* First and foremost, we need to register a credential - type. */ - ZeroMemory(&ct, sizeof(ct)); - ct.id = KCDB_CREDTYPE_AUTO; - ct.name = MYCREDTYPE_NAMEW; - - short_desc[0] = L'\0'; - LoadString(hResModule, IDS_CT_SHORT_DESC, - short_desc, ARRAYLENGTH(short_desc)); - - long_desc[0] = L'\0'; - LoadString(hResModule, IDS_CT_LONG_DESC, - long_desc, ARRAYLENGTH(long_desc)); - - ct.icon = NULL; /* We skip the icon for now, but you - can assign a handle to an icon - here. The icon will be used to - represent the credentials type.*/ - - kmq_create_subscription(plugin_msg_proc, &ct.sub); - - ct.is_equal = cred_is_equal; - - rv = kcdb_credtype_register(&ct, &credtype_id); - - /* We create a global credential set that we use in the - plug-in thread. This alleviates the need to create one - everytime we need one. Keep in mind that this should - only be used in the plug-in thread and should not be - touched from the UI thread or any other thread. */ - kcdb_credset_create(&g_credset); - - /* TODO: Perform additional initialization operations. */ - - /* TODO: Also list out the credentials of this type that - already exist. */ - - /* Now we register our configuration panels. */ - - - /* This configuration panel is the one that controls - general options. We leave the identity specific and - identity defaults for other configuration panels. */ - - ZeroMemory(&creg, sizeof(creg)); - - short_desc[0] = L'\0'; - - LoadString(hResModule, IDS_CFG_SHORT_DESC, - short_desc, ARRAYLENGTH(short_desc)); - - long_desc[0] = L'\0'; - - LoadString(hResModule, IDS_CFG_LONG_DESC, - long_desc, ARRAYLENGTH(long_desc)); - - creg.name = CONFIGNODE_MAIN; - creg.short_desc = short_desc; - creg.long_desc = long_desc; - creg.h_module = hResModule; - creg.dlg_template = MAKEINTRESOURCE(IDD_CONFIG); - creg.dlg_proc = config_dlgproc; - creg.flags = 0; - - khui_cfg_register(NULL, &creg); - - /* Now we do the identity specific and identity default - configuration panels. "KhmIdentities" is a predefined - configuration node under which all the identity spcific - configuration is managed. */ - - if (KHM_FAILED(khui_cfg_open(NULL, L"KhmIdentities", &cnode))) { - /* this should always work */ - assert(FALSE); - rv = KHM_ERROR_NOT_FOUND; - break; - } - - /* First the tab panel for defaults for all identities */ - - ZeroMemory(&creg, sizeof(creg)); - - short_desc[0] = L'\0'; - LoadString(hResModule, IDS_CFG_IDS_SHORT_DESC, - short_desc, ARRAYLENGTH(short_desc)); - long_desc[0] = L'\0'; - LoadString(hResModule, IDS_CFG_IDS_LONG_DESC, - long_desc, ARRAYLENGTH(long_desc)); - - creg.name = CONFIGNODE_ALL_ID; - creg.short_desc = short_desc; - creg.long_desc = long_desc; - creg.h_module = hResModule; - creg.dlg_template = MAKEINTRESOURCE(IDD_CONFIG_IDS); - creg.dlg_proc = config_ids_dlgproc; - creg.flags = KHUI_CNFLAG_SUBPANEL; - - khui_cfg_register(cnode, &creg); - - /* Now the panel for per identity configuration */ - - ZeroMemory(&creg, sizeof(creg)); - - short_desc[0] = L'\0'; - LoadString(hResModule, IDS_CFG_ID_SHORT_DESC, - short_desc, ARRAYLENGTH(short_desc)); - long_desc[0] = L'\0'; - LoadString(hResModule, IDS_CFG_ID_LONG_DESC, - long_desc, ARRAYLENGTH(long_desc)); - - creg.name = CONFIGNODE_PER_ID; - creg.short_desc = short_desc; - creg.long_desc = long_desc; - creg.h_module = hResModule; - creg.dlg_template = MAKEINTRESOURCE(IDD_CONFIG_ID); - creg.dlg_proc = config_id_dlgproc; - creg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_PLURAL; - - khui_cfg_register(cnode, &creg); - - khui_cfg_release(cnode); - } - break; - - /* This is the last message that will be received by the - plugin. */ - case KMSG_SYSTEM_EXIT: - { - khui_config_node cnode; - khui_config_node cn_idents; - - /* It should not be assumed that initialization of the - plugin went well at this point since we receive a - KMSG_SYSTEM_EXIT even if the initialization failed. */ - - if (credtype_id != KCDB_CREDTYPE_INVALID) { - kcdb_credtype_unregister(credtype_id); - credtype_id = KCDB_CREDTYPE_INVALID; - } - - if (g_credset) { - kcdb_credset_delete(g_credset); - g_credset = NULL; - } - - /* Now unregister any configuration nodes we registered. */ - - if (KHM_SUCCEEDED(khui_cfg_open(NULL, CONFIGNODE_MAIN, &cnode))) { - khui_cfg_remove(cnode); - khui_cfg_release(cnode); - } - - if (KHM_SUCCEEDED(khui_cfg_open(NULL, L"KhmIdentities", &cn_idents))) { - if (KHM_SUCCEEDED(khui_cfg_open(cn_idents, - CONFIGNODE_ALL_ID, - &cnode))) { - khui_cfg_remove(cnode); - khui_cfg_release(cnode); - } - - if (KHM_SUCCEEDED(khui_cfg_open(cn_idents, - CONFIGNODE_PER_ID, - &cnode))) { - khui_cfg_remove(cnode); - khui_cfg_release(cnode); - } - - khui_cfg_release(cn_idents); - } - - /* TODO: Perform additional uninitialization - operations. */ - } - break; - } - - return rv; -} - -/* Handler for credentials the refresh message. */ -khm_int32 -handle_kmsg_cred_refresh(void) { - /* TODO: Re-enumerate the credentials of our credentials type */ - - /* - Re-enumerating credentials would look something like this: - - - flush all credentials from g_credset (kcdb_credset_flush()) - - - list out the credentials and add them to g_credset - - - collect the credentials from g_credset to the root credentials - set. (kcdb_credset_collect()) - - Note that when listing credentials, each credential must be - populated with enough information to locate the actual - credential at a later time. - */ - - return KHM_ERROR_SUCCESS; -} - -/* Handler for destroying credentials */ -khm_int32 -handle_kmsg_cred_destroy_creds(khui_action_context * ctx) { - /* TODO: Destroy credentials of our type as specified by the - action context passed in through vparam. */ - - /* The credential set in ctx->credset contains the credentials - that are to be destroyed. */ - - return KHM_ERROR_SUCCESS; -} - -/* Begin a property sheet */ -khm_int32 -handle_kmsg_cred_pp_begin(khui_property_sheet * ps) { - - /* TODO: Provide the information necessary to show a property - page for a credentials belonging to our credential type. */ - - PROPSHEETPAGE *p; - - if (ps->credtype == credtype_id && - ps->cred) { - /* We have been requested to show a property sheet for one of - our credentials. */ - p = malloc(sizeof(*p)); - ZeroMemory(p, sizeof(*p)); - - p->dwSize = sizeof(*p); - p->dwFlags = 0; - p->hInstance = hResModule; - p->pszTemplate = MAKEINTRESOURCE(IDD_PP_CRED); - p->pfnDlgProc = pp_cred_dlg_proc; - p->lParam = (LPARAM) ps; - khui_ps_add_page(ps, credtype_id, 0, p, NULL); - } - - return KHM_ERROR_SUCCESS; -} - -/* End a property sheet */ -khm_int32 -handle_kmsg_cred_pp_end(khui_property_sheet * ps) { - /* TODO: Handle the end of a property sheet. */ - - khui_property_page * p = NULL; - - khui_ps_find_page(ps, credtype_id, &p); - if (p) { - if (p->p_page) - free(p->p_page); - p->p_page = NULL; - } - - return KHM_ERROR_SUCCESS; -} - -/* IP address change notification */ -khm_int32 -handle_kmsg_cred_addr_change(void) { - /* TODO: Handle this message. */ - - return KHM_ERROR_SUCCESS; -} - -/* Message dispatcher for credentials messages. */ -khm_int32 KHMAPI -handle_kmsg_cred(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam) { - khm_int32 rv = KHM_ERROR_SUCCESS; - - switch(msg_subtype) { - case KMSG_CRED_REFRESH: - return handle_kmsg_cred_refresh(); - - case KMSG_CRED_DESTROY_CREDS: - return handle_kmsg_cred_destroy_creds((khui_action_context *) vparam); - - case KMSG_CRED_PP_BEGIN: - return handle_kmsg_cred_pp_begin((khui_property_sheet *) vparam); - - case KMSG_CRED_PP_END: - return handle_kmsg_cred_pp_end((khui_property_sheet *) vparam); - - case KMSG_CRED_ADDR_CHANGE: - return handle_kmsg_cred_addr_change(); - - default: - /* Credentials acquisition messages are all handled in a - different source file. */ - if (IS_CRED_ACQ_MSG(msg_subtype)) - return handle_cred_acq_msg(msg_type, msg_subtype, - uparam, vparam); - } - - return rv; -} - - -/* This is the main message handler for our plugin. All the plugin - messages end up here where we either handle it directly or dispatch - it to other handlers. */ -khm_int32 KHMAPI plugin_msg_proc(khm_int32 msg_type, - khm_int32 msg_subtype, - khm_ui_4 uparam, - void * vparam) { - - switch(msg_type) { - case KMSG_SYSTEM: - return handle_kmsg_system(msg_type, msg_subtype, uparam, vparam); - - case KMSG_CRED: - return handle_kmsg_cred(msg_type, msg_subtype, uparam, vparam); - } - - return KHM_ERROR_SUCCESS; -} +/* + * Copyright (c) 2006 Secure Endpoints Inc. + * + * 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 "credprov.h" +#include + +/* This file provides the message processing function and the support + routines for implementing our plugin. Note that some of the + message processing routines have been moved to other source files + based on their use. +*/ + +khm_int32 credtype_id = KCDB_CREDTYPE_INVALID; +khm_handle g_credset = NULL; + +/* Handler for system messages. The only two we handle are + KMSG_SYSTEM_INIT and KMSG_SYSTEM_EXIT. */ +khm_int32 KHMAPI +handle_kmsg_system(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch (msg_subtype) { + + /* This is the first message that will be received by a + plugin. We use it to perform initialization operations + such as registering any credential types, data types and + attributes. */ + case KMSG_SYSTEM_INIT: + { + kcdb_credtype ct; + wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC]; + wchar_t long_desc[KCDB_MAXCCH_LONG_DESC]; + khui_config_node cnode; + khui_config_node_reg creg; + + /* First and foremost, we need to register a credential + type. */ + ZeroMemory(&ct, sizeof(ct)); + ct.id = KCDB_CREDTYPE_AUTO; + ct.name = MYCREDTYPE_NAMEW; + + short_desc[0] = L'\0'; + LoadString(hResModule, IDS_CT_SHORT_DESC, + short_desc, ARRAYLENGTH(short_desc)); + + long_desc[0] = L'\0'; + LoadString(hResModule, IDS_CT_LONG_DESC, + long_desc, ARRAYLENGTH(long_desc)); + + ct.icon = NULL; /* We skip the icon for now, but you + can assign a handle to an icon + here. The icon will be used to + represent the credentials type.*/ + + kmq_create_subscription(plugin_msg_proc, &ct.sub); + + ct.is_equal = cred_is_equal; + + rv = kcdb_credtype_register(&ct, &credtype_id); + + /* We create a global credential set that we use in the + plug-in thread. This alleviates the need to create one + everytime we need one. Keep in mind that this should + only be used in the plug-in thread and should not be + touched from the UI thread or any other thread. */ + kcdb_credset_create(&g_credset); + + /* TODO: Perform additional initialization operations. */ + + /* TODO: Also list out the credentials of this type that + already exist. */ + + /* Now we register our configuration panels. */ + + + /* This configuration panel is the one that controls + general options. We leave the identity specific and + identity defaults for other configuration panels. */ + + ZeroMemory(&creg, sizeof(creg)); + + short_desc[0] = L'\0'; + + LoadString(hResModule, IDS_CFG_SHORT_DESC, + short_desc, ARRAYLENGTH(short_desc)); + + long_desc[0] = L'\0'; + + LoadString(hResModule, IDS_CFG_LONG_DESC, + long_desc, ARRAYLENGTH(long_desc)); + + creg.name = CONFIGNODE_MAIN; + creg.short_desc = short_desc; + creg.long_desc = long_desc; + creg.h_module = hResModule; + creg.dlg_template = MAKEINTRESOURCE(IDD_CONFIG); + creg.dlg_proc = config_dlgproc; + creg.flags = 0; + + khui_cfg_register(NULL, &creg); + + /* Now we do the identity specific and identity default + configuration panels. "KhmIdentities" is a predefined + configuration node under which all the identity spcific + configuration is managed. */ + + if (KHM_FAILED(khui_cfg_open(NULL, L"KhmIdentities", &cnode))) { + /* this should always work */ + assert(FALSE); + rv = KHM_ERROR_NOT_FOUND; + break; + } + + /* First the tab panel for defaults for all identities */ + + ZeroMemory(&creg, sizeof(creg)); + + short_desc[0] = L'\0'; + LoadString(hResModule, IDS_CFG_IDS_SHORT_DESC, + short_desc, ARRAYLENGTH(short_desc)); + long_desc[0] = L'\0'; + LoadString(hResModule, IDS_CFG_IDS_LONG_DESC, + long_desc, ARRAYLENGTH(long_desc)); + + creg.name = CONFIGNODE_ALL_ID; + creg.short_desc = short_desc; + creg.long_desc = long_desc; + creg.h_module = hResModule; + creg.dlg_template = MAKEINTRESOURCE(IDD_CONFIG_IDS); + creg.dlg_proc = config_ids_dlgproc; + creg.flags = KHUI_CNFLAG_SUBPANEL; + + khui_cfg_register(cnode, &creg); + + /* Now the panel for per identity configuration */ + + ZeroMemory(&creg, sizeof(creg)); + + short_desc[0] = L'\0'; + LoadString(hResModule, IDS_CFG_ID_SHORT_DESC, + short_desc, ARRAYLENGTH(short_desc)); + long_desc[0] = L'\0'; + LoadString(hResModule, IDS_CFG_ID_LONG_DESC, + long_desc, ARRAYLENGTH(long_desc)); + + creg.name = CONFIGNODE_PER_ID; + creg.short_desc = short_desc; + creg.long_desc = long_desc; + creg.h_module = hResModule; + creg.dlg_template = MAKEINTRESOURCE(IDD_CONFIG_ID); + creg.dlg_proc = config_id_dlgproc; + creg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_PLURAL; + + khui_cfg_register(cnode, &creg); + + khui_cfg_release(cnode); + } + break; + + /* This is the last message that will be received by the + plugin. */ + case KMSG_SYSTEM_EXIT: + { + khui_config_node cnode; + khui_config_node cn_idents; + + /* It should not be assumed that initialization of the + plugin went well at this point since we receive a + KMSG_SYSTEM_EXIT even if the initialization failed. */ + + if (credtype_id != KCDB_CREDTYPE_INVALID) { + kcdb_credtype_unregister(credtype_id); + credtype_id = KCDB_CREDTYPE_INVALID; + } + + if (g_credset) { + kcdb_credset_delete(g_credset); + g_credset = NULL; + } + + /* Now unregister any configuration nodes we registered. */ + + if (KHM_SUCCEEDED(khui_cfg_open(NULL, CONFIGNODE_MAIN, &cnode))) { + khui_cfg_remove(cnode); + khui_cfg_release(cnode); + } + + if (KHM_SUCCEEDED(khui_cfg_open(NULL, L"KhmIdentities", &cn_idents))) { + if (KHM_SUCCEEDED(khui_cfg_open(cn_idents, + CONFIGNODE_ALL_ID, + &cnode))) { + khui_cfg_remove(cnode); + khui_cfg_release(cnode); + } + + if (KHM_SUCCEEDED(khui_cfg_open(cn_idents, + CONFIGNODE_PER_ID, + &cnode))) { + khui_cfg_remove(cnode); + khui_cfg_release(cnode); + } + + khui_cfg_release(cn_idents); + } + + /* TODO: Perform additional uninitialization + operations. */ + } + break; + } + + return rv; +} + +/* Handler for credentials the refresh message. */ +khm_int32 +handle_kmsg_cred_refresh(void) { + /* TODO: Re-enumerate the credentials of our credentials type */ + + /* + Re-enumerating credentials would look something like this: + + - flush all credentials from g_credset (kcdb_credset_flush()) + + - list out the credentials and add them to g_credset + + - collect the credentials from g_credset to the root credentials + set. (kcdb_credset_collect()) + + Note that when listing credentials, each credential must be + populated with enough information to locate the actual + credential at a later time. + */ + + return KHM_ERROR_SUCCESS; +} + +/* Handler for destroying credentials */ +khm_int32 +handle_kmsg_cred_destroy_creds(khui_action_context * ctx) { + /* TODO: Destroy credentials of our type as specified by the + action context passed in through vparam. */ + + /* The credential set in ctx->credset contains the credentials + that are to be destroyed. */ + + return KHM_ERROR_SUCCESS; +} + +/* Begin a property sheet */ +khm_int32 +handle_kmsg_cred_pp_begin(khui_property_sheet * ps) { + + /* TODO: Provide the information necessary to show a property + page for a credentials belonging to our credential type. */ + + PROPSHEETPAGE *p; + + if (ps->credtype == credtype_id && + ps->cred) { + /* We have been requested to show a property sheet for one of + our credentials. */ + p = malloc(sizeof(*p)); + ZeroMemory(p, sizeof(*p)); + + p->dwSize = sizeof(*p); + p->dwFlags = 0; + p->hInstance = hResModule; + p->pszTemplate = MAKEINTRESOURCE(IDD_PP_CRED); + p->pfnDlgProc = pp_cred_dlg_proc; + p->lParam = (LPARAM) ps; + khui_ps_add_page(ps, credtype_id, 0, p, NULL); + } + + return KHM_ERROR_SUCCESS; +} + +/* End a property sheet */ +khm_int32 +handle_kmsg_cred_pp_end(khui_property_sheet * ps) { + /* TODO: Handle the end of a property sheet. */ + + khui_property_page * p = NULL; + + khui_ps_find_page(ps, credtype_id, &p); + if (p) { + if (p->p_page) + free(p->p_page); + p->p_page = NULL; + } + + return KHM_ERROR_SUCCESS; +} + +/* IP address change notification */ +khm_int32 +handle_kmsg_cred_addr_change(void) { + /* TODO: Handle this message. */ + + return KHM_ERROR_SUCCESS; +} + +/* Message dispatcher for credentials messages. */ +khm_int32 KHMAPI +handle_kmsg_cred(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_CRED_REFRESH: + return handle_kmsg_cred_refresh(); + + case KMSG_CRED_DESTROY_CREDS: + return handle_kmsg_cred_destroy_creds((khui_action_context *) vparam); + + case KMSG_CRED_PP_BEGIN: + return handle_kmsg_cred_pp_begin((khui_property_sheet *) vparam); + + case KMSG_CRED_PP_END: + return handle_kmsg_cred_pp_end((khui_property_sheet *) vparam); + + case KMSG_CRED_ADDR_CHANGE: + return handle_kmsg_cred_addr_change(); + + default: + /* Credentials acquisition messages are all handled in a + different source file. */ + if (IS_CRED_ACQ_MSG(msg_subtype)) + return handle_cred_acq_msg(msg_type, msg_subtype, + uparam, vparam); + } + + return rv; +} + + +/* This is the main message handler for our plugin. All the plugin + messages end up here where we either handle it directly or dispatch + it to other handlers. */ +khm_int32 KHMAPI plugin_msg_proc(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + + switch(msg_type) { + case KMSG_SYSTEM: + return handle_kmsg_system(msg_type, msg_subtype, uparam, vparam); + + case KMSG_CRED: + return handle_kmsg_cred(msg_type, msg_subtype, uparam, vparam); + } + + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/sample/templates/credprov/proppage.c b/src/windows/identity/sample/templates/credprov/proppage.c index 734a58ee4..eaffde23e 100644 --- a/src/windows/identity/sample/templates/credprov/proppage.c +++ b/src/windows/identity/sample/templates/credprov/proppage.c @@ -1,59 +1,59 @@ -/* - * Copyright (c) 2006 Secure Endpoints Inc. - * - * 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 "credprov.h" - -/* Dialog procedure and support code for displaying property sheets - for credentials of type MyCred. */ - -/* Dialog procedure for the property sheet. This will run under the - UI thread when a property sheet is being displayed for one of our - credentials.. */ -INT_PTR CALLBACK -pp_cred_dlg_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - - switch (uMsg) { - case WM_INITDIALOG: - { - khui_property_sheet * ps; - PROPSHEETPAGE * p; - - p = (PROPSHEETPAGE *) lParam; - ps = (khui_property_sheet *) p->lParam; - - /* TODO: Populate the property sheet controls with values - extracted from the credential. (ps->cred) */ - - return FALSE; - } - } - - return FALSE; -} - +/* + * Copyright (c) 2006 Secure Endpoints Inc. + * + * 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 "credprov.h" + +/* Dialog procedure and support code for displaying property sheets + for credentials of type MyCred. */ + +/* Dialog procedure for the property sheet. This will run under the + UI thread when a property sheet is being displayed for one of our + credentials.. */ +INT_PTR CALLBACK +pp_cred_dlg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + switch (uMsg) { + case WM_INITDIALOG: + { + khui_property_sheet * ps; + PROPSHEETPAGE * p; + + p = (PROPSHEETPAGE *) lParam; + ps = (khui_property_sheet *) p->lParam; + + /* TODO: Populate the property sheet controls with values + extracted from the credential. (ps->cred) */ + + return FALSE; + } + } + + return FALSE; +} + diff --git a/src/windows/identity/ui/aboutwnd.c b/src/windows/identity/ui/aboutwnd.c index 68aef0277..cc88705d7 100644 --- a/src/windows/identity/ui/aboutwnd.c +++ b/src/windows/identity/ui/aboutwnd.c @@ -1,154 +1,154 @@ -/* - * 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 - -#if DEBUG -#include -#endif - -INT_PTR CALLBACK -about_dlg_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - - switch(uMsg) { - case WM_INITDIALOG: - { - HANDLE hsnap; - HWND hw; - - SetDlgItemText(hwnd, IDC_PRODUCT, - TEXT(KH_VERSTR_PRODUCT_1033)); - /* retain the original copyright strings */ -#ifdef OVERRIDE_COPYRIGHT - SetDlgItemText(hwnd, IDC_COPYRIGHT, - TEXT(KH_VERSTR_COPYRIGHT_1033)); -#endif - SetDlgItemText(hwnd, IDC_BUILDINFO, - TEXT(KH_VERSTR_BUILDINFO_1033)); - - hsnap = - CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, - 0); - - if (hsnap != INVALID_HANDLE_VALUE) { - LVCOLUMN lvc; - MODULEENTRY32 mod; - RECT r; - - hw = GetDlgItem(hwnd, IDC_MODULES); -#ifdef DEBUG - assert(hw != NULL); -#endif - - GetWindowRect(hw, &r); - OffsetRect(&r, -r.left, -r.top); - - ZeroMemory(&lvc, sizeof(lvc)); - lvc.mask = LVCF_TEXT | LVCF_WIDTH; - - lvc.pszText = L"Name"; - lvc.cx = r.right / 4; - - ListView_InsertColumn(hw, 0, &lvc); - - lvc.pszText = L"Path"; - lvc.cx = (r.right * 3) / 4; - ListView_InsertColumn(hw, 1, &lvc); - - ZeroMemory(&mod, sizeof(mod)); - mod.dwSize = sizeof(mod); - - /* done with columns, now for the actual data */ - if (!Module32First(hsnap, &mod)) - goto _done_with_modules; - - do { - - LVITEM lvi; - int idx; - - ZeroMemory(&lvi, sizeof(lvi)); - - lvi.mask = LVIF_TEXT; - lvi.pszText = mod.szModule; - idx = ListView_InsertItem(hw, &lvi); - - lvi.mask = LVIF_TEXT; - lvi.iItem = idx; - lvi.iSubItem = 1; - lvi.pszText = mod.szExePath; - ListView_SetItem(hw, &lvi); - - ZeroMemory(&mod, sizeof(mod)); - mod.dwSize = sizeof(mod); - } while(Module32Next(hsnap, &mod)); - - _done_with_modules: - CloseHandle(hsnap); - } - - khm_add_dialog(hwnd); - khm_enter_modal(hwnd); - } - return FALSE; - - case WM_DESTROY: - khm_del_dialog(hwnd); - return TRUE; - - case WM_CLOSE: - khm_leave_modal(); - DestroyWindow(hwnd); - return TRUE; - - case WM_COMMAND: - if (wParam == MAKEWPARAM(IDOK, BN_CLICKED)) { - khm_leave_modal(); - DestroyWindow(hwnd); - } - return TRUE; - } - - return FALSE; -} - -void -khm_create_about_window(void) { - HWND hwnd; - hwnd = CreateDialog(khm_hInstance, - MAKEINTRESOURCE(IDD_ABOUT), - khm_hwnd_main, - about_dlg_proc); - - ShowWindow(hwnd, SW_SHOW); - /* no need to keep track of the hwnd, since we add it to the - dialog chain in the dialog procedure */ -} +/* + * 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 + +#if DEBUG +#include +#endif + +INT_PTR CALLBACK +about_dlg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + { + HANDLE hsnap; + HWND hw; + + SetDlgItemText(hwnd, IDC_PRODUCT, + TEXT(KH_VERSTR_PRODUCT_1033)); + /* retain the original copyright strings */ +#ifdef OVERRIDE_COPYRIGHT + SetDlgItemText(hwnd, IDC_COPYRIGHT, + TEXT(KH_VERSTR_COPYRIGHT_1033)); +#endif + SetDlgItemText(hwnd, IDC_BUILDINFO, + TEXT(KH_VERSTR_BUILDINFO_1033)); + + hsnap = + CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, + 0); + + if (hsnap != INVALID_HANDLE_VALUE) { + LVCOLUMN lvc; + MODULEENTRY32 mod; + RECT r; + + hw = GetDlgItem(hwnd, IDC_MODULES); +#ifdef DEBUG + assert(hw != NULL); +#endif + + GetWindowRect(hw, &r); + OffsetRect(&r, -r.left, -r.top); + + ZeroMemory(&lvc, sizeof(lvc)); + lvc.mask = LVCF_TEXT | LVCF_WIDTH; + + lvc.pszText = L"Name"; + lvc.cx = r.right / 4; + + ListView_InsertColumn(hw, 0, &lvc); + + lvc.pszText = L"Path"; + lvc.cx = (r.right * 3) / 4; + ListView_InsertColumn(hw, 1, &lvc); + + ZeroMemory(&mod, sizeof(mod)); + mod.dwSize = sizeof(mod); + + /* done with columns, now for the actual data */ + if (!Module32First(hsnap, &mod)) + goto _done_with_modules; + + do { + + LVITEM lvi; + int idx; + + ZeroMemory(&lvi, sizeof(lvi)); + + lvi.mask = LVIF_TEXT; + lvi.pszText = mod.szModule; + idx = ListView_InsertItem(hw, &lvi); + + lvi.mask = LVIF_TEXT; + lvi.iItem = idx; + lvi.iSubItem = 1; + lvi.pszText = mod.szExePath; + ListView_SetItem(hw, &lvi); + + ZeroMemory(&mod, sizeof(mod)); + mod.dwSize = sizeof(mod); + } while(Module32Next(hsnap, &mod)); + + _done_with_modules: + CloseHandle(hsnap); + } + + khm_add_dialog(hwnd); + khm_enter_modal(hwnd); + } + return FALSE; + + case WM_DESTROY: + khm_del_dialog(hwnd); + return TRUE; + + case WM_CLOSE: + khm_leave_modal(); + DestroyWindow(hwnd); + return TRUE; + + case WM_COMMAND: + if (wParam == MAKEWPARAM(IDOK, BN_CLICKED)) { + khm_leave_modal(); + DestroyWindow(hwnd); + } + return TRUE; + } + + return FALSE; +} + +void +khm_create_about_window(void) { + HWND hwnd; + hwnd = CreateDialog(khm_hInstance, + MAKEINTRESOURCE(IDD_ABOUT), + khm_hwnd_main, + about_dlg_proc); + + ShowWindow(hwnd, SW_SHOW); + /* no need to keep track of the hwnd, since we add it to the + dialog chain in the dialog procedure */ +} diff --git a/src/windows/identity/ui/aboutwnd.h b/src/windows/identity/ui/aboutwnd.h index 81b7e9047..7da709d93 100644 --- a/src/windows/identity/ui/aboutwnd.h +++ b/src/windows/identity/ui/aboutwnd.h @@ -1,33 +1,33 @@ -/* - * 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_ABOUTWND_H -#define __KHIMAIRA_ABOUTWND_H - -void -khm_create_about_window(void); - -#endif +/* + * 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_ABOUTWND_H +#define __KHIMAIRA_ABOUTWND_H + +void +khm_create_about_window(void); + +#endif diff --git a/src/windows/identity/ui/addrchange.c b/src/windows/identity/ui/addrchange.c index b37fca534..36ef2beee 100644 --- a/src/windows/identity/ui/addrchange.c +++ b/src/windows/identity/ui/addrchange.c @@ -1,94 +1,94 @@ -/* - * 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 - -static HANDLE evt_terminate = NULL; -static HANDLE h_thread = NULL; - -DWORD WINAPI -addr_change_thread(LPVOID dummy) { - - HANDLE h_waits[2]; - HANDLE h_notify; - - OVERLAPPED overlap; - DWORD ret; - - PDESCTHREAD(L"Address change waiter", L"App"); - - ZeroMemory(&overlap, sizeof(overlap)); - - h_notify = NULL; - overlap.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - - do { - ret = NotifyAddrChange(&h_notify, &overlap); - - if (ret != ERROR_IO_PENDING) { - goto _end_thread; /* some error */ - } - - h_waits[0] = overlap.hEvent; - h_waits[1] = evt_terminate; - - ret = WaitForMultipleObjects(2, h_waits, FALSE, INFINITE); - - if ( ret == WAIT_OBJECT_0 ) { - Sleep(3000); /* wait for things to settle down */ - kmq_post_message(KMSG_CRED, KMSG_CRED_ADDR_CHANGE, 0, 0); - } else { - goto _end_thread; - } - } while(TRUE); - - _end_thread: - ExitThread(0); - return 0; /* unreachable */ -} - -void -khm_addr_change_notifier_init(void) { - evt_terminate = CreateEvent(NULL, FALSE, FALSE, NULL); - h_thread = CreateThread(NULL, - 64 * 4096, - addr_change_thread, - NULL, - 0, - NULL); -} - -void -khm_addr_change_notifier_exit(void) { - if (h_thread && evt_terminate) { - SetEvent(evt_terminate); - WaitForSingleObject(h_thread, INFINITE); - - CloseHandle(h_thread); - CloseHandle(evt_terminate); - } -} +/* + * 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 + +static HANDLE evt_terminate = NULL; +static HANDLE h_thread = NULL; + +DWORD WINAPI +addr_change_thread(LPVOID dummy) { + + HANDLE h_waits[2]; + HANDLE h_notify; + + OVERLAPPED overlap; + DWORD ret; + + PDESCTHREAD(L"Address change waiter", L"App"); + + ZeroMemory(&overlap, sizeof(overlap)); + + h_notify = NULL; + overlap.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + do { + ret = NotifyAddrChange(&h_notify, &overlap); + + if (ret != ERROR_IO_PENDING) { + goto _end_thread; /* some error */ + } + + h_waits[0] = overlap.hEvent; + h_waits[1] = evt_terminate; + + ret = WaitForMultipleObjects(2, h_waits, FALSE, INFINITE); + + if ( ret == WAIT_OBJECT_0 ) { + Sleep(3000); /* wait for things to settle down */ + kmq_post_message(KMSG_CRED, KMSG_CRED_ADDR_CHANGE, 0, 0); + } else { + goto _end_thread; + } + } while(TRUE); + + _end_thread: + ExitThread(0); + return 0; /* unreachable */ +} + +void +khm_addr_change_notifier_init(void) { + evt_terminate = CreateEvent(NULL, FALSE, FALSE, NULL); + h_thread = CreateThread(NULL, + 64 * 4096, + addr_change_thread, + NULL, + 0, + NULL); +} + +void +khm_addr_change_notifier_exit(void) { + if (h_thread && evt_terminate) { + SetEvent(evt_terminate); + WaitForSingleObject(h_thread, INFINITE); + + CloseHandle(h_thread); + CloseHandle(evt_terminate); + } +} diff --git a/src/windows/identity/ui/addrchange.h b/src/windows/identity/ui/addrchange.h index 08c15041f..2f605af8c 100644 --- a/src/windows/identity/ui/addrchange.h +++ b/src/windows/identity/ui/addrchange.h @@ -1,36 +1,36 @@ -/* - * 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_ADDRCHANGE_H -#define __NETIDMGR_ADDRCHANGE_H - -void -khm_addr_change_notifier_init(void); - -void -khm_addr_change_notifier_exit(void); - -#endif +/* + * 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_ADDRCHANGE_H +#define __NETIDMGR_ADDRCHANGE_H + +void +khm_addr_change_notifier_init(void); + +void +khm_addr_change_notifier_exit(void); + +#endif diff --git a/src/windows/identity/ui/appglobal.h b/src/windows/identity/ui/appglobal.h index 3e44282d1..46e2d0dc9 100644 --- a/src/windows/identity/ui/appglobal.h +++ b/src/windows/identity/ui/appglobal.h @@ -1,143 +1,143 @@ -/* - * 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_APPGLOBAL_H -#define __KHIMAIRA_APPGLOBAL_H - -/* Helpfile */ -#define NIDM_HELPFILE L"netidmgr.chm" - -/* global data */ -extern HINSTANCE khm_hInstance; -extern int khm_nCmdShow; -extern const wchar_t * khm_facility; -extern kconf_schema schema_uiconfig[]; -extern khm_ui_4 khm_commctl_version; -extern const khm_version app_version; - -#define IS_COMMCTL6() (khm_commctl_version >= 0x60000) - -/* The structure used to send command-line options to a remote - NetIDMgr session for versions prior to 1.2. */ -struct tag_khm_startup_options_v1 { - BOOL seen; - BOOL processing; - - BOOL init; - BOOL import; - BOOL renew; - BOOL destroy; - - BOOL autoinit; - BOOL exit; - BOOL error_exit; - - BOOL no_main_window; -}; - -/* Used on NetIDMgr versions 1.2 and later */ -struct tag_khm_startup_options_v2 { - khm_int32 magic; - DWORD cb_size; - - BOOL init; - BOOL import; - BOOL renew; - BOOL destroy; - - BOOL autoinit; - BOOL remote_exit; - - khm_int32 code; -} khm_startup_options_xfer; - -#define STARTUP_OPTIONS_MAGIC 0x1f280e41 - -/* Used internally. */ -typedef struct tag_khm_startup_options_int { - BOOL seen; - BOOL processing; - BOOL remote; - - BOOL init; - BOOL import; - BOOL renew; - BOOL destroy; - - BOOL autoinit; - BOOL exit; - BOOL remote_exit; - - BOOL error_exit; - - BOOL no_main_window; - - LONG pending_renewals; -} khm_startup_options; - -extern khm_startup_options khm_startup; - -/* Used to query a remote instance of NetIDMgr for the version. */ -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); - -void khm_enter_modal(HWND hwnd); -void khm_leave_modal(void); - -void khm_add_property_sheet(khui_property_sheet * s); -void khm_del_property_sheet(khui_property_sheet * s); - -void khm_init_gui(void); -void khm_exit_gui(void); - -void khm_parse_commandline(); -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); - -int khm_compare_version(const khm_version * v1, const khm_version * v2); - -#define MAX_RES_STRING 1024 - -#define ELLIPSIS L"..." - -#endif +/* + * 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_APPGLOBAL_H +#define __KHIMAIRA_APPGLOBAL_H + +/* Helpfile */ +#define NIDM_HELPFILE L"netidmgr.chm" + +/* global data */ +extern HINSTANCE khm_hInstance; +extern int khm_nCmdShow; +extern const wchar_t * khm_facility; +extern kconf_schema schema_uiconfig[]; +extern khm_ui_4 khm_commctl_version; +extern const khm_version app_version; + +#define IS_COMMCTL6() (khm_commctl_version >= 0x60000) + +/* The structure used to send command-line options to a remote + NetIDMgr session for versions prior to 1.2. */ +struct tag_khm_startup_options_v1 { + BOOL seen; + BOOL processing; + + BOOL init; + BOOL import; + BOOL renew; + BOOL destroy; + + BOOL autoinit; + BOOL exit; + BOOL error_exit; + + BOOL no_main_window; +}; + +/* Used on NetIDMgr versions 1.2 and later */ +struct tag_khm_startup_options_v2 { + khm_int32 magic; + DWORD cb_size; + + BOOL init; + BOOL import; + BOOL renew; + BOOL destroy; + + BOOL autoinit; + BOOL remote_exit; + + khm_int32 code; +} khm_startup_options_xfer; + +#define STARTUP_OPTIONS_MAGIC 0x1f280e41 + +/* Used internally. */ +typedef struct tag_khm_startup_options_int { + BOOL seen; + BOOL processing; + BOOL remote; + + BOOL init; + BOOL import; + BOOL renew; + BOOL destroy; + + BOOL autoinit; + BOOL exit; + BOOL remote_exit; + + BOOL error_exit; + + BOOL no_main_window; + + LONG pending_renewals; +} khm_startup_options; + +extern khm_startup_options khm_startup; + +/* Used to query a remote instance of NetIDMgr for the version. */ +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); + +void khm_enter_modal(HWND hwnd); +void khm_leave_modal(void); + +void khm_add_property_sheet(khui_property_sheet * s); +void khm_del_property_sheet(khui_property_sheet * s); + +void khm_init_gui(void); +void khm_exit_gui(void); + +void khm_parse_commandline(); +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); + +int khm_compare_version(const khm_version * v1, const khm_version * v2); + +#define MAX_RES_STRING 1024 + +#define ELLIPSIS L"..." + +#endif diff --git a/src/windows/identity/ui/cfg_appear_wnd.c b/src/windows/identity/ui/cfg_appear_wnd.c index bca270979..c7e9abc25 100644 --- a/src/windows/identity/ui/cfg_appear_wnd.c +++ b/src/windows/identity/ui/cfg_appear_wnd.c @@ -1,435 +1,435 @@ -/* - * 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 - -static int text_sizes[] = { - 4,6,8,9,10,12,14,16,18 -}; - -typedef struct tag_dlg_data { - khui_config_node node; - HWND hwnd; - LOGFONT lf_base; - LOGFONT lf_work; - HFONT c_font_normal; - HFONT c_font_bold; - int size_idx[ARRAYLENGTH(text_sizes)]; -} dlg_data; - -static void -read_params(HWND hwnd, dlg_data * d) { - - HDC hdc; - - hdc = GetWindowDC(hwnd); - - khm_get_cw_element_font(hdc, - NULL, - FALSE, - &d->lf_base); - - d->lf_work = d->lf_base; - - ReleaseDC(hwnd, hdc); -} - - -static void -write_params(dlg_data * d) { - khm_boolean applied = FALSE; - - if (memcmp(&d->lf_work, &d->lf_base, sizeof(LOGFONT))) { - khm_set_cw_element_font(NULL, &d->lf_work); - d->lf_base = d->lf_work; - applied = TRUE; - } - - khui_cfg_set_flags(d->node, - (applied)? KHUI_CNFLAG_APPLIED: 0, - KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); -} - -static void -check_for_modification(dlg_data * d) { - - khui_cfg_set_flags(d->node, - ((memcmp(&d->lf_work, &d->lf_base, sizeof(LOGFONT)))? - KHUI_CNFLAG_MODIFIED: 0), - KHUI_CNFLAG_MODIFIED); -} - -static void -refresh_view(HWND hwnd, dlg_data * d) { - wchar_t sample[256]; - HFONT hf; - LOGFONT lf; - - LoadString(khm_hInstance, IDS_APR_SAMPLE_TEXT_NORMAL, - sample, ARRAYLENGTH(sample)); - - SetDlgItemText(hwnd, IDC_CFG_SAMPLE_NORMAL, sample); - - LoadString(khm_hInstance, IDS_APR_SAMPLE_TEXT_SEL, - sample, ARRAYLENGTH(sample)); - - SetDlgItemText(hwnd, IDC_CFG_SAMPLE_BOLD, sample); - - lf = d->lf_work; - hf = CreateFontIndirect(&lf); - if (hf == NULL) - return; - - SendDlgItemMessage(hwnd, IDC_CFG_SAMPLE_NORMAL, WM_SETFONT, (WPARAM) hf, TRUE); - - if (d->c_font_normal) - DeleteObject(d->c_font_normal); - - d->c_font_normal = hf; - - lf.lfWeight = FW_BOLD; - - hf = CreateFontIndirect(&lf); - if (hf == NULL) - return; - - SendDlgItemMessage(hwnd, IDC_CFG_SAMPLE_BOLD, WM_SETFONT, (WPARAM) hf, TRUE); - - if (d->c_font_bold) - DeleteObject(d->c_font_bold); - - d->c_font_bold = hf; -} - -struct sel_update_blob { - dlg_data * d; - HDC hdc; -}; - -static int CALLBACK -enum_font_proc(ENUMLOGFONTEXDV * plfe, - ENUMTEXTMETRIC * pntm, - DWORD font_type, - LPARAM lParam) { - struct sel_update_blob * blob = (struct sel_update_blob *) lParam; - LOGFONT * plf = &plfe->elfEnumLogfontEx.elfLogFont; - LRESULT lr; - - lr = SendDlgItemMessage(blob->d->hwnd, - IDC_CFG_FONTS, - CB_SELECTSTRING, - (WPARAM) -1, - (LPARAM) plf->lfFaceName); - - if (lr == CB_ERR) { - SendDlgItemMessage(blob->d->hwnd, - IDC_CFG_FONTS, - CB_SELECTSTRING, - (WPARAM) -1, - (LPARAM) plfe->elfEnumLogfontEx.elfFullName); - } - - return FALSE; -} - -static void -update_selection(dlg_data * d, BOOL update_fonts, BOOL update_effects) { - LOGFONT lf; - struct sel_update_blob blob; - HDC hdc; - - if (update_fonts) { - - ZeroMemory(&lf, sizeof(lf)); - - lf.lfCharSet = ANSI_CHARSET; - StringCbCopy(lf.lfFaceName, sizeof(lf.lfFaceName), - d->lf_work.lfFaceName); - - hdc = GetWindowDC(d->hwnd); - - blob.d = d; - blob.hdc = hdc; - - EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC) enum_font_proc, - (LPARAM) &blob, 0); - - ReleaseDC(d->hwnd, hdc); - } - - if (update_effects) { - int i; - HDC hdc; - int pt_height; - - if (d->lf_work.lfWeight >= FW_BOLD) - CheckDlgButton(d->hwnd, IDC_CFG_BOLD, BST_CHECKED); - else - CheckDlgButton(d->hwnd, IDC_CFG_BOLD, BST_UNCHECKED); - - if (d->lf_work.lfItalic) - CheckDlgButton(d->hwnd, IDC_CFG_ITALICS, BST_CHECKED); - else - CheckDlgButton(d->hwnd, IDC_CFG_ITALICS, BST_UNCHECKED); - - hdc = GetWindowDC(d->hwnd); - - pt_height = MulDiv(d->lf_work.lfHeight, 72, - GetDeviceCaps(hdc, LOGPIXELSY)); - - - ReleaseDC(d->hwnd, hdc); - - if (pt_height < 0) - pt_height = - pt_height; - - for (i=0; i < ARRAYLENGTH(text_sizes); i++) { - if (text_sizes[i] >= pt_height) - break; - } - - if (i >= ARRAYLENGTH(text_sizes)) - i = ARRAYLENGTH(text_sizes) - 1; - - SendDlgItemMessage(d->hwnd, IDC_CFG_SIZE, CB_SETCURSEL, - d->size_idx[i], 0); - } -} - -static int CALLBACK -enum_font_families_proc(ENUMLOGFONTEXDV * plfe, - ENUMTEXTMETRIC * pntm, - DWORD font_type, - LPARAM lParam) { - - dlg_data * d = (dlg_data *) lParam; - - SendDlgItemMessage(d->hwnd, IDC_CFG_FONTS, - CB_ADDSTRING, 0, - (LPARAM) plfe->elfEnumLogfontEx.elfLogFont.lfFaceName); - - return TRUE; -} - -INT_PTR CALLBACK -khm_cfg_appearance_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - - dlg_data * d; - - switch(uMsg) { - case WM_INITDIALOG: - { - HWND hw_cb; - LOGFONT lf; - HDC hdc; - int i; - wchar_t buf[4]; - - d = PMALLOC(sizeof(*d)); -#ifdef DEBUG - assert(d != NULL); -#endif - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); -#pragma warning(pop) - - ZeroMemory(d, sizeof(*d)); - - d->node = (khui_config_node) lParam; - d->hwnd = hwnd; - - read_params(hwnd, d); - - hw_cb = GetDlgItem(hwnd, IDC_CFG_FONTS); -#ifdef DEBUG - assert(hw_cb); -#endif - SendMessage(hw_cb, CB_RESETCONTENT, 0, 0); - - ZeroMemory(&lf, sizeof(lf)); - lf.lfCharSet = ANSI_CHARSET; - - hdc = GetWindowDC(hwnd); - - EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC) enum_font_families_proc, - (LPARAM) d, 0); - - ReleaseDC(hwnd, hdc); - - - for (i=0; i < ARRAYLENGTH(text_sizes); i++) { - LRESULT idx; - - StringCbPrintf(buf, sizeof(buf), L"%d", text_sizes[i]); - - idx = SendDlgItemMessage(hwnd, IDC_CFG_SIZE, - CB_ADDSTRING, 0, (LPARAM) buf); - - SendDlgItemMessage(hwnd, IDC_CFG_SIZE, - CB_SETITEMDATA, idx, text_sizes[i]); - - d->size_idx[i] = (int) idx; - } - - update_selection(d, TRUE, TRUE); - - refresh_view(hwnd, d); - } - return FALSE; - - case WM_COMMAND: - d = (dlg_data *) (LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); - - if (wParam == MAKEWPARAM(IDC_CFG_FONTS, CBN_SELCHANGE)) { - LRESULT idx; - wchar_t facename[LF_FACESIZE]; - - idx = SendDlgItemMessage(hwnd, IDC_CFG_FONTS, - CB_GETCURSEL, - 0, 0); - - if (idx == CB_ERR) - return TRUE; - - if (SendDlgItemMessage(hwnd, IDC_CFG_FONTS, - CB_GETLBTEXTLEN, idx, 0) - >= ARRAYLENGTH(facename)) - return TRUE; - - SendDlgItemMessage(hwnd, IDC_CFG_FONTS, - CB_GETLBTEXT, idx, - (LPARAM) facename); - - ZeroMemory(d->lf_work.lfFaceName, - sizeof(d->lf_work.lfFaceName)); - - StringCbCopy(d->lf_work.lfFaceName, - sizeof(d->lf_work.lfFaceName), - facename); - - update_selection(d, FALSE, FALSE); - - refresh_view(hwnd, d); - - check_for_modification(d); - - } else if (wParam == MAKEWPARAM(IDC_CFG_BOLD, BN_CLICKED)) { - - if (IsDlgButtonChecked(hwnd, IDC_CFG_BOLD) == BST_CHECKED) { - d->lf_work.lfWeight = FW_BOLD; - } else { - d->lf_work.lfWeight = 0; - } - - refresh_view(hwnd, d); - - check_for_modification(d); - - } else if (wParam == MAKEWPARAM(IDC_CFG_ITALICS, BN_CLICKED)) { - - d->lf_work.lfItalic = - (IsDlgButtonChecked(hwnd, IDC_CFG_ITALICS) == BST_CHECKED); - - refresh_view(hwnd, d); - - check_for_modification(d); - - } else if (wParam == MAKEWPARAM(IDC_CFG_REVERT, BN_CLICKED)) { - HDC hdc; - - hdc = GetWindowDC(hwnd); - - khm_get_cw_element_font(hdc, NULL, TRUE, &d->lf_work); - - ReleaseDC(hwnd, hdc); - - update_selection(d, TRUE, TRUE); - - refresh_view(hwnd, d); - - check_for_modification(d); - - } else if (wParam == MAKEWPARAM(IDC_CFG_SIZE, CBN_SELCHANGE)) { - HDC hdc; - LPARAM idx; - int points; - - idx = SendDlgItemMessage(hwnd, IDC_CFG_SIZE, - CB_GETCURSEL, 0, 0); - if (idx == CB_ERR) - return TRUE; - - points = (int) SendDlgItemMessage(hwnd, IDC_CFG_SIZE, - CB_GETITEMDATA, idx, 0); - - hdc = GetWindowDC(hwnd); - - d->lf_work.lfHeight = -MulDiv(points, - GetDeviceCaps(hdc, LOGPIXELSY), - 72); - - ReleaseDC(hwnd, hdc); - - refresh_view(hwnd, d); - - check_for_modification(d); - } - - return TRUE; - - case WM_DESTROY: - d = (dlg_data *) (LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); - - if (d) { - if (d->c_font_bold) - DeleteObject(d->c_font_bold); - - if (d->c_font_normal) - DeleteObject(d->c_font_normal); - - PFREE(d); - } - return TRUE; - - case KHUI_WM_CFG_NOTIFY: - d = (dlg_data *) (LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); - - if (HIWORD(wParam) == WMCFG_APPLY) { - write_params(d); - khui_action_trigger(KHUI_ACTION_LAYOUT_RELOAD, NULL); - } - - return TRUE; - } - - return FALSE; -} +/* + * 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 + +static int text_sizes[] = { + 4,6,8,9,10,12,14,16,18 +}; + +typedef struct tag_dlg_data { + khui_config_node node; + HWND hwnd; + LOGFONT lf_base; + LOGFONT lf_work; + HFONT c_font_normal; + HFONT c_font_bold; + int size_idx[ARRAYLENGTH(text_sizes)]; +} dlg_data; + +static void +read_params(HWND hwnd, dlg_data * d) { + + HDC hdc; + + hdc = GetWindowDC(hwnd); + + khm_get_cw_element_font(hdc, + NULL, + FALSE, + &d->lf_base); + + d->lf_work = d->lf_base; + + ReleaseDC(hwnd, hdc); +} + + +static void +write_params(dlg_data * d) { + khm_boolean applied = FALSE; + + if (memcmp(&d->lf_work, &d->lf_base, sizeof(LOGFONT))) { + khm_set_cw_element_font(NULL, &d->lf_work); + d->lf_base = d->lf_work; + applied = TRUE; + } + + khui_cfg_set_flags(d->node, + (applied)? KHUI_CNFLAG_APPLIED: 0, + KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); +} + +static void +check_for_modification(dlg_data * d) { + + khui_cfg_set_flags(d->node, + ((memcmp(&d->lf_work, &d->lf_base, sizeof(LOGFONT)))? + KHUI_CNFLAG_MODIFIED: 0), + KHUI_CNFLAG_MODIFIED); +} + +static void +refresh_view(HWND hwnd, dlg_data * d) { + wchar_t sample[256]; + HFONT hf; + LOGFONT lf; + + LoadString(khm_hInstance, IDS_APR_SAMPLE_TEXT_NORMAL, + sample, ARRAYLENGTH(sample)); + + SetDlgItemText(hwnd, IDC_CFG_SAMPLE_NORMAL, sample); + + LoadString(khm_hInstance, IDS_APR_SAMPLE_TEXT_SEL, + sample, ARRAYLENGTH(sample)); + + SetDlgItemText(hwnd, IDC_CFG_SAMPLE_BOLD, sample); + + lf = d->lf_work; + hf = CreateFontIndirect(&lf); + if (hf == NULL) + return; + + SendDlgItemMessage(hwnd, IDC_CFG_SAMPLE_NORMAL, WM_SETFONT, (WPARAM) hf, TRUE); + + if (d->c_font_normal) + DeleteObject(d->c_font_normal); + + d->c_font_normal = hf; + + lf.lfWeight = FW_BOLD; + + hf = CreateFontIndirect(&lf); + if (hf == NULL) + return; + + SendDlgItemMessage(hwnd, IDC_CFG_SAMPLE_BOLD, WM_SETFONT, (WPARAM) hf, TRUE); + + if (d->c_font_bold) + DeleteObject(d->c_font_bold); + + d->c_font_bold = hf; +} + +struct sel_update_blob { + dlg_data * d; + HDC hdc; +}; + +static int CALLBACK +enum_font_proc(ENUMLOGFONTEXDV * plfe, + ENUMTEXTMETRIC * pntm, + DWORD font_type, + LPARAM lParam) { + struct sel_update_blob * blob = (struct sel_update_blob *) lParam; + LOGFONT * plf = &plfe->elfEnumLogfontEx.elfLogFont; + LRESULT lr; + + lr = SendDlgItemMessage(blob->d->hwnd, + IDC_CFG_FONTS, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) plf->lfFaceName); + + if (lr == CB_ERR) { + SendDlgItemMessage(blob->d->hwnd, + IDC_CFG_FONTS, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) plfe->elfEnumLogfontEx.elfFullName); + } + + return FALSE; +} + +static void +update_selection(dlg_data * d, BOOL update_fonts, BOOL update_effects) { + LOGFONT lf; + struct sel_update_blob blob; + HDC hdc; + + if (update_fonts) { + + ZeroMemory(&lf, sizeof(lf)); + + lf.lfCharSet = ANSI_CHARSET; + StringCbCopy(lf.lfFaceName, sizeof(lf.lfFaceName), + d->lf_work.lfFaceName); + + hdc = GetWindowDC(d->hwnd); + + blob.d = d; + blob.hdc = hdc; + + EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC) enum_font_proc, + (LPARAM) &blob, 0); + + ReleaseDC(d->hwnd, hdc); + } + + if (update_effects) { + int i; + HDC hdc; + int pt_height; + + if (d->lf_work.lfWeight >= FW_BOLD) + CheckDlgButton(d->hwnd, IDC_CFG_BOLD, BST_CHECKED); + else + CheckDlgButton(d->hwnd, IDC_CFG_BOLD, BST_UNCHECKED); + + if (d->lf_work.lfItalic) + CheckDlgButton(d->hwnd, IDC_CFG_ITALICS, BST_CHECKED); + else + CheckDlgButton(d->hwnd, IDC_CFG_ITALICS, BST_UNCHECKED); + + hdc = GetWindowDC(d->hwnd); + + pt_height = MulDiv(d->lf_work.lfHeight, 72, + GetDeviceCaps(hdc, LOGPIXELSY)); + + + ReleaseDC(d->hwnd, hdc); + + if (pt_height < 0) + pt_height = - pt_height; + + for (i=0; i < ARRAYLENGTH(text_sizes); i++) { + if (text_sizes[i] >= pt_height) + break; + } + + if (i >= ARRAYLENGTH(text_sizes)) + i = ARRAYLENGTH(text_sizes) - 1; + + SendDlgItemMessage(d->hwnd, IDC_CFG_SIZE, CB_SETCURSEL, + d->size_idx[i], 0); + } +} + +static int CALLBACK +enum_font_families_proc(ENUMLOGFONTEXDV * plfe, + ENUMTEXTMETRIC * pntm, + DWORD font_type, + LPARAM lParam) { + + dlg_data * d = (dlg_data *) lParam; + + SendDlgItemMessage(d->hwnd, IDC_CFG_FONTS, + CB_ADDSTRING, 0, + (LPARAM) plfe->elfEnumLogfontEx.elfLogFont.lfFaceName); + + return TRUE; +} + +INT_PTR CALLBACK +khm_cfg_appearance_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + { + HWND hw_cb; + LOGFONT lf; + HDC hdc; + int i; + wchar_t buf[4]; + + d = PMALLOC(sizeof(*d)); +#ifdef DEBUG + assert(d != NULL); +#endif + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + ZeroMemory(d, sizeof(*d)); + + d->node = (khui_config_node) lParam; + d->hwnd = hwnd; + + read_params(hwnd, d); + + hw_cb = GetDlgItem(hwnd, IDC_CFG_FONTS); +#ifdef DEBUG + assert(hw_cb); +#endif + SendMessage(hw_cb, CB_RESETCONTENT, 0, 0); + + ZeroMemory(&lf, sizeof(lf)); + lf.lfCharSet = ANSI_CHARSET; + + hdc = GetWindowDC(hwnd); + + EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC) enum_font_families_proc, + (LPARAM) d, 0); + + ReleaseDC(hwnd, hdc); + + + for (i=0; i < ARRAYLENGTH(text_sizes); i++) { + LRESULT idx; + + StringCbPrintf(buf, sizeof(buf), L"%d", text_sizes[i]); + + idx = SendDlgItemMessage(hwnd, IDC_CFG_SIZE, + CB_ADDSTRING, 0, (LPARAM) buf); + + SendDlgItemMessage(hwnd, IDC_CFG_SIZE, + CB_SETITEMDATA, idx, text_sizes[i]); + + d->size_idx[i] = (int) idx; + } + + update_selection(d, TRUE, TRUE); + + refresh_view(hwnd, d); + } + return FALSE; + + case WM_COMMAND: + d = (dlg_data *) (LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + if (wParam == MAKEWPARAM(IDC_CFG_FONTS, CBN_SELCHANGE)) { + LRESULT idx; + wchar_t facename[LF_FACESIZE]; + + idx = SendDlgItemMessage(hwnd, IDC_CFG_FONTS, + CB_GETCURSEL, + 0, 0); + + if (idx == CB_ERR) + return TRUE; + + if (SendDlgItemMessage(hwnd, IDC_CFG_FONTS, + CB_GETLBTEXTLEN, idx, 0) + >= ARRAYLENGTH(facename)) + return TRUE; + + SendDlgItemMessage(hwnd, IDC_CFG_FONTS, + CB_GETLBTEXT, idx, + (LPARAM) facename); + + ZeroMemory(d->lf_work.lfFaceName, + sizeof(d->lf_work.lfFaceName)); + + StringCbCopy(d->lf_work.lfFaceName, + sizeof(d->lf_work.lfFaceName), + facename); + + update_selection(d, FALSE, FALSE); + + refresh_view(hwnd, d); + + check_for_modification(d); + + } else if (wParam == MAKEWPARAM(IDC_CFG_BOLD, BN_CLICKED)) { + + if (IsDlgButtonChecked(hwnd, IDC_CFG_BOLD) == BST_CHECKED) { + d->lf_work.lfWeight = FW_BOLD; + } else { + d->lf_work.lfWeight = 0; + } + + refresh_view(hwnd, d); + + check_for_modification(d); + + } else if (wParam == MAKEWPARAM(IDC_CFG_ITALICS, BN_CLICKED)) { + + d->lf_work.lfItalic = + (IsDlgButtonChecked(hwnd, IDC_CFG_ITALICS) == BST_CHECKED); + + refresh_view(hwnd, d); + + check_for_modification(d); + + } else if (wParam == MAKEWPARAM(IDC_CFG_REVERT, BN_CLICKED)) { + HDC hdc; + + hdc = GetWindowDC(hwnd); + + khm_get_cw_element_font(hdc, NULL, TRUE, &d->lf_work); + + ReleaseDC(hwnd, hdc); + + update_selection(d, TRUE, TRUE); + + refresh_view(hwnd, d); + + check_for_modification(d); + + } else if (wParam == MAKEWPARAM(IDC_CFG_SIZE, CBN_SELCHANGE)) { + HDC hdc; + LPARAM idx; + int points; + + idx = SendDlgItemMessage(hwnd, IDC_CFG_SIZE, + CB_GETCURSEL, 0, 0); + if (idx == CB_ERR) + return TRUE; + + points = (int) SendDlgItemMessage(hwnd, IDC_CFG_SIZE, + CB_GETITEMDATA, idx, 0); + + hdc = GetWindowDC(hwnd); + + d->lf_work.lfHeight = -MulDiv(points, + GetDeviceCaps(hdc, LOGPIXELSY), + 72); + + ReleaseDC(hwnd, hdc); + + refresh_view(hwnd, d); + + check_for_modification(d); + } + + return TRUE; + + case WM_DESTROY: + d = (dlg_data *) (LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + if (d) { + if (d->c_font_bold) + DeleteObject(d->c_font_bold); + + if (d->c_font_normal) + DeleteObject(d->c_font_normal); + + PFREE(d); + } + return TRUE; + + case KHUI_WM_CFG_NOTIFY: + d = (dlg_data *) (LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == WMCFG_APPLY) { + write_params(d); + khui_action_trigger(KHUI_ACTION_LAYOUT_RELOAD, NULL); + } + + return TRUE; + } + + return FALSE; +} diff --git a/src/windows/identity/ui/cfg_general_wnd.c b/src/windows/identity/ui/cfg_general_wnd.c index fa7ac6fd4..1e92947f0 100644 --- a/src/windows/identity/ui/cfg_general_wnd.c +++ b/src/windows/identity/ui/cfg_general_wnd.c @@ -1,419 +1,419 @@ -/* - * 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 - -typedef struct tag_cfg_data { - BOOL auto_init; - BOOL auto_start; - BOOL auto_import; - BOOL keep_running; - BOOL auto_detect_net; - BOOL log_to_file; - BOOL destroy_creds; - khm_int32 notif_action; -} cfg_data; - -typedef struct tag_dlg_data { - khui_config_node node; - cfg_data saved; - cfg_data work; -} dlg_data; - -static void -read_params(dlg_data * dd) { - cfg_data * d; - khm_handle csp_cw; - khm_int32 t; - - d = &dd->saved; - - if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, - &csp_cw))) { -#ifdef DEBUG - assert(FALSE); -#endif - return; - } - - khc_read_int32(csp_cw, L"AutoInit", &t); - d->auto_init = !!t; - - khc_read_int32(csp_cw, L"AutoStart", &t); - d->auto_start = !!t; - - khc_read_int32(csp_cw, L"AutoImport", &t); - d->auto_import = !!t; - - khc_read_int32(csp_cw, L"KeepRunning", &t); - d->keep_running = !!t; - - 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_read_int32(csp_cw, L"NotificationAction", &t); - d->notif_action = t; - - khc_close_space(csp_cw); - - dd->work = *d; -} - -static void -write_params(dlg_data * dd) { - cfg_data * d, * s; - khm_handle csp_cw; - BOOL applied = FALSE; - - d = &dd->work; - s = &dd->saved; - - if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_WRITE, - &csp_cw))) { -#ifdef DEBUG - assert(FALSE); -#endif - return; - } - - if (!!d->auto_init != !!s->auto_init) { - khc_write_int32(csp_cw, L"AutoInit", d->auto_init); - applied = TRUE; - } - - if (!!d->auto_start != !!s->auto_start) { - khc_write_int32(csp_cw, L"AutoStart", d->auto_start); - applied = TRUE; - } - - if (!!d->auto_import != !!s->auto_import) { - khc_write_int32(csp_cw, L"AutoImport", d->auto_import); - applied = TRUE; - } - - if (!!d->keep_running != !!s->keep_running) { - khc_write_int32(csp_cw, L"KeepRunning", d->keep_running); - applied = TRUE; - } - - if (!!d->auto_detect_net != !!s->auto_detect_net) { - khc_write_int32(csp_cw, L"AutoDetectNet", d->auto_detect_net); - 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; - } - - if (d->notif_action != s->notif_action) { - khc_write_int32(csp_cw, L"NotificationAction", d->notif_action); - applied = TRUE; - } - - khc_close_space(csp_cw); - - khui_cfg_set_flags(dd->node, - (applied) ? KHUI_CNFLAG_APPLIED : 0, - KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); - - *s = *d; -} - -static void -check_for_modification(dlg_data * dd) { - cfg_data * d, * s; - d = &dd->work; - s = &dd->saved; - - if (!!d->auto_init != !!s->auto_init || - !!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->log_to_file != !!s->log_to_file || - !!d->destroy_creds != !!s->destroy_creds || - d->notif_action != s->notif_action) { - - khui_cfg_set_flags(dd->node, - KHUI_CNFLAG_MODIFIED, - KHUI_CNFLAG_MODIFIED); - - } else { - - khui_cfg_set_flags(dd->node, - 0, - KHUI_CNFLAG_MODIFIED); - - } -} - - -static void -strip_ampersands(wchar_t * str) { - wchar_t *f, *t; - - for(f = t = str; *f; f++) - if (*f != L'&') - *t++ = *f; - - *t = L'\0'; -} - -static void -refresh_view(HWND hwnd, dlg_data * d) { - wchar_t buf[512]; - khm_size i; - - CheckDlgButton(hwnd, IDC_CFG_AUTOINIT, - (d->work.auto_init?BST_CHECKED:BST_UNCHECKED)); - CheckDlgButton(hwnd, IDC_CFG_AUTOSTART, - (d->work.auto_start?BST_CHECKED:BST_UNCHECKED)); - CheckDlgButton(hwnd, IDC_CFG_AUTOIMPORT, - (d->work.auto_import?BST_CHECKED:BST_UNCHECKED)); - CheckDlgButton(hwnd, IDC_CFG_KEEPRUNNING, - (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)); - - /* we need populate the notification action combo box control and - set the current selection to match the default action. */ - - if (n_khm_notifier_actions != SendDlgItemMessage(hwnd, IDC_CFG_NOTACTION, - CB_GETCOUNT, 0, 0)) { - - for (i=0; i < n_khm_notifier_actions; i++) { - int idx; - - khm_get_action_caption(khm_notifier_actions[i], - buf, sizeof(buf)); - - strip_ampersands(buf); - - idx = (int) SendDlgItemMessage(hwnd, IDC_CFG_NOTACTION, - CB_INSERTSTRING, i, - (LPARAM) buf); - -#ifdef DEBUG - if (idx != (int) i) { - assert(FALSE); - } -#endif - } - } - - for (i=0; i < n_khm_notifier_actions; i++) { - if (khm_notifier_actions[i] == d->work.notif_action) - break; - } - - if (i >= n_khm_notifier_actions) { - d->work.notif_action = khm_notifier_actions[0]; - i = 0; - } - - SendDlgItemMessage(hwnd, IDC_CFG_NOTACTION, CB_SETCURSEL, i, 0); - - /* 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 -refresh_data(HWND hwnd, dlg_data * d) { - int idx; - - d->work.auto_init = (IsDlgButtonChecked(hwnd, IDC_CFG_AUTOINIT) - == BST_CHECKED); - d->work.auto_start = (IsDlgButtonChecked(hwnd, IDC_CFG_AUTOSTART) - == BST_CHECKED); - d->work.auto_import = (IsDlgButtonChecked(hwnd, IDC_CFG_AUTOIMPORT) - == BST_CHECKED); - d->work.keep_running = (IsDlgButtonChecked(hwnd, IDC_CFG_KEEPRUNNING) - == 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); - - idx = (int) SendDlgItemMessage(hwnd, IDC_CFG_NOTACTION, CB_GETCURSEL, 0, 0); - if (idx < 0) - idx = 0; - else if (idx >= (int) n_khm_notifier_actions) - idx = (int) n_khm_notifier_actions - 1; - - d->work.notif_action = khm_notifier_actions[idx]; -} - -INT_PTR CALLBACK -khm_cfg_general_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - dlg_data * d; - - switch(uMsg) { - case WM_INITDIALOG: - d = PMALLOC(sizeof(*d)); -#ifdef DEBUG - assert(d != NULL); -#endif - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); -#pragma warning(pop) - - ZeroMemory(d, sizeof(*d)); - - d->node = (khui_config_node) lParam; - - read_params(d); - - refresh_view(hwnd, d); - - return FALSE; - - case WM_DESTROY: - d = (dlg_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); - if (d) { - PFREE(d); - } - return TRUE; - - case WM_COMMAND: - d = (dlg_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); - - if (HIWORD(wParam) == BN_CLICKED) { - if (LOWORD(wParam) == IDC_CFG_SHOWLOG) { - /* we need to display the logfile */ - wchar_t buf[512]; - - buf[0] = L'\0'; - khm_get_file_log_path(sizeof(buf), buf); - - if (!buf[0] || - !PathFileExists(buf)) { - - wchar_t title[256]; - wchar_t msg[550]; - wchar_t fmt[256]; - - LoadString(khm_hInstance, IDS_CFG_LOGF_CS, - title, ARRAYLENGTH(title)); - LoadString(khm_hInstance, IDS_CFG_LOGF_CSR, - fmt, ARRAYLENGTH(fmt)); - - StringCbPrintf(msg, sizeof(msg), fmt, buf); - - MessageBox(hwnd, title, msg, MB_OK); - - } else { - wchar_t cmdline[550]; - STARTUPINFO si; - PROCESS_INFORMATION pi; - - StringCbCopy(cmdline, sizeof(cmdline), L"notepad.exe "); - StringCbCat(cmdline, sizeof(cmdline), L"\""); - StringCbCat(cmdline, sizeof(cmdline), buf); - StringCbCat(cmdline, sizeof(cmdline), L"\""); - - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - ZeroMemory(&pi, sizeof(pi)); - - CreateProcess(NULL, - cmdline, - NULL, NULL, - FALSE, - 0, NULL, NULL, - &si, - &pi); - - if (pi.hProcess) - CloseHandle(pi.hProcess); - if (pi.hThread) - CloseHandle(pi.hThread); - - } - } else { - refresh_data(hwnd, d); - check_for_modification(d); - } - } else if (HIWORD(wParam) == CBN_SELCHANGE) { - refresh_data(hwnd, d); - check_for_modification(d); - } - - khm_set_dialog_result(hwnd, 0); - - return TRUE; - - case KHUI_WM_CFG_NOTIFY: - d = (dlg_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); - - if (HIWORD(wParam) == WMCFG_APPLY) { - write_params(d); - } - - khm_set_dialog_result(hwnd, 0); - - return TRUE; - } - - return FALSE; -} +/* + * 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 + +typedef struct tag_cfg_data { + BOOL auto_init; + BOOL auto_start; + BOOL auto_import; + BOOL keep_running; + BOOL auto_detect_net; + BOOL log_to_file; + BOOL destroy_creds; + khm_int32 notif_action; +} cfg_data; + +typedef struct tag_dlg_data { + khui_config_node node; + cfg_data saved; + cfg_data work; +} dlg_data; + +static void +read_params(dlg_data * dd) { + cfg_data * d; + khm_handle csp_cw; + khm_int32 t; + + d = &dd->saved; + + if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, + &csp_cw))) { +#ifdef DEBUG + assert(FALSE); +#endif + return; + } + + khc_read_int32(csp_cw, L"AutoInit", &t); + d->auto_init = !!t; + + khc_read_int32(csp_cw, L"AutoStart", &t); + d->auto_start = !!t; + + khc_read_int32(csp_cw, L"AutoImport", &t); + d->auto_import = !!t; + + khc_read_int32(csp_cw, L"KeepRunning", &t); + d->keep_running = !!t; + + 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_read_int32(csp_cw, L"NotificationAction", &t); + d->notif_action = t; + + khc_close_space(csp_cw); + + dd->work = *d; +} + +static void +write_params(dlg_data * dd) { + cfg_data * d, * s; + khm_handle csp_cw; + BOOL applied = FALSE; + + d = &dd->work; + s = &dd->saved; + + if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_WRITE, + &csp_cw))) { +#ifdef DEBUG + assert(FALSE); +#endif + return; + } + + if (!!d->auto_init != !!s->auto_init) { + khc_write_int32(csp_cw, L"AutoInit", d->auto_init); + applied = TRUE; + } + + if (!!d->auto_start != !!s->auto_start) { + khc_write_int32(csp_cw, L"AutoStart", d->auto_start); + applied = TRUE; + } + + if (!!d->auto_import != !!s->auto_import) { + khc_write_int32(csp_cw, L"AutoImport", d->auto_import); + applied = TRUE; + } + + if (!!d->keep_running != !!s->keep_running) { + khc_write_int32(csp_cw, L"KeepRunning", d->keep_running); + applied = TRUE; + } + + if (!!d->auto_detect_net != !!s->auto_detect_net) { + khc_write_int32(csp_cw, L"AutoDetectNet", d->auto_detect_net); + 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; + } + + if (d->notif_action != s->notif_action) { + khc_write_int32(csp_cw, L"NotificationAction", d->notif_action); + applied = TRUE; + } + + khc_close_space(csp_cw); + + khui_cfg_set_flags(dd->node, + (applied) ? KHUI_CNFLAG_APPLIED : 0, + KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); + + *s = *d; +} + +static void +check_for_modification(dlg_data * dd) { + cfg_data * d, * s; + d = &dd->work; + s = &dd->saved; + + if (!!d->auto_init != !!s->auto_init || + !!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->log_to_file != !!s->log_to_file || + !!d->destroy_creds != !!s->destroy_creds || + d->notif_action != s->notif_action) { + + khui_cfg_set_flags(dd->node, + KHUI_CNFLAG_MODIFIED, + KHUI_CNFLAG_MODIFIED); + + } else { + + khui_cfg_set_flags(dd->node, + 0, + KHUI_CNFLAG_MODIFIED); + + } +} + + +static void +strip_ampersands(wchar_t * str) { + wchar_t *f, *t; + + for(f = t = str; *f; f++) + if (*f != L'&') + *t++ = *f; + + *t = L'\0'; +} + +static void +refresh_view(HWND hwnd, dlg_data * d) { + wchar_t buf[512]; + khm_size i; + + CheckDlgButton(hwnd, IDC_CFG_AUTOINIT, + (d->work.auto_init?BST_CHECKED:BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_AUTOSTART, + (d->work.auto_start?BST_CHECKED:BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_AUTOIMPORT, + (d->work.auto_import?BST_CHECKED:BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_KEEPRUNNING, + (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)); + + /* we need populate the notification action combo box control and + set the current selection to match the default action. */ + + if (n_khm_notifier_actions != SendDlgItemMessage(hwnd, IDC_CFG_NOTACTION, + CB_GETCOUNT, 0, 0)) { + + for (i=0; i < n_khm_notifier_actions; i++) { + int idx; + + khm_get_action_caption(khm_notifier_actions[i], + buf, sizeof(buf)); + + strip_ampersands(buf); + + idx = (int) SendDlgItemMessage(hwnd, IDC_CFG_NOTACTION, + CB_INSERTSTRING, i, + (LPARAM) buf); + +#ifdef DEBUG + if (idx != (int) i) { + assert(FALSE); + } +#endif + } + } + + for (i=0; i < n_khm_notifier_actions; i++) { + if (khm_notifier_actions[i] == d->work.notif_action) + break; + } + + if (i >= n_khm_notifier_actions) { + d->work.notif_action = khm_notifier_actions[0]; + i = 0; + } + + SendDlgItemMessage(hwnd, IDC_CFG_NOTACTION, CB_SETCURSEL, i, 0); + + /* 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 +refresh_data(HWND hwnd, dlg_data * d) { + int idx; + + d->work.auto_init = (IsDlgButtonChecked(hwnd, IDC_CFG_AUTOINIT) + == BST_CHECKED); + d->work.auto_start = (IsDlgButtonChecked(hwnd, IDC_CFG_AUTOSTART) + == BST_CHECKED); + d->work.auto_import = (IsDlgButtonChecked(hwnd, IDC_CFG_AUTOIMPORT) + == BST_CHECKED); + d->work.keep_running = (IsDlgButtonChecked(hwnd, IDC_CFG_KEEPRUNNING) + == 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); + + idx = (int) SendDlgItemMessage(hwnd, IDC_CFG_NOTACTION, CB_GETCURSEL, 0, 0); + if (idx < 0) + idx = 0; + else if (idx >= (int) n_khm_notifier_actions) + idx = (int) n_khm_notifier_actions - 1; + + d->work.notif_action = khm_notifier_actions[idx]; +} + +INT_PTR CALLBACK +khm_cfg_general_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + d = PMALLOC(sizeof(*d)); +#ifdef DEBUG + assert(d != NULL); +#endif + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + ZeroMemory(d, sizeof(*d)); + + d->node = (khui_config_node) lParam; + + read_params(d); + + refresh_view(hwnd, d); + + return FALSE; + + case WM_DESTROY: + d = (dlg_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + if (d) { + PFREE(d); + } + return TRUE; + + case WM_COMMAND: + d = (dlg_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == BN_CLICKED) { + if (LOWORD(wParam) == IDC_CFG_SHOWLOG) { + /* we need to display the logfile */ + wchar_t buf[512]; + + buf[0] = L'\0'; + khm_get_file_log_path(sizeof(buf), buf); + + if (!buf[0] || + !PathFileExists(buf)) { + + wchar_t title[256]; + wchar_t msg[550]; + wchar_t fmt[256]; + + LoadString(khm_hInstance, IDS_CFG_LOGF_CS, + title, ARRAYLENGTH(title)); + LoadString(khm_hInstance, IDS_CFG_LOGF_CSR, + fmt, ARRAYLENGTH(fmt)); + + StringCbPrintf(msg, sizeof(msg), fmt, buf); + + MessageBox(hwnd, title, msg, MB_OK); + + } else { + wchar_t cmdline[550]; + STARTUPINFO si; + PROCESS_INFORMATION pi; + + StringCbCopy(cmdline, sizeof(cmdline), L"notepad.exe "); + StringCbCat(cmdline, sizeof(cmdline), L"\""); + StringCbCat(cmdline, sizeof(cmdline), buf); + StringCbCat(cmdline, sizeof(cmdline), L"\""); + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); + + CreateProcess(NULL, + cmdline, + NULL, NULL, + FALSE, + 0, NULL, NULL, + &si, + &pi); + + if (pi.hProcess) + CloseHandle(pi.hProcess); + if (pi.hThread) + CloseHandle(pi.hThread); + + } + } else { + refresh_data(hwnd, d); + check_for_modification(d); + } + } else if (HIWORD(wParam) == CBN_SELCHANGE) { + refresh_data(hwnd, d); + check_for_modification(d); + } + + khm_set_dialog_result(hwnd, 0); + + return TRUE; + + case KHUI_WM_CFG_NOTIFY: + d = (dlg_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == WMCFG_APPLY) { + write_params(d); + } + + khm_set_dialog_result(hwnd, 0); + + return TRUE; + } + + return FALSE; +} diff --git a/src/windows/identity/ui/cfg_identities_wnd.c b/src/windows/identity/ui/cfg_identities_wnd.c index a8813d116..d45288a3a 100644 --- a/src/windows/identity/ui/cfg_identities_wnd.c +++ b/src/windows/identity/ui/cfg_identities_wnd.c @@ -1,1523 +1,1523 @@ -/* - * 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 - -static khui_config_node -get_window_node(HWND hwnd) { - return (khui_config_node) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); -} - -static void -set_window_node(HWND hwnd, khui_config_node node) { -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, - (LONG_PTR) node); -#pragma warning(pop) -} - -static void -add_subpanels(HWND hwnd, - khui_config_node ctx_node, - khui_config_node ref_node) { - - HWND hw_tab; - HWND hw_target; - khui_config_node sub; - khui_config_node_reg reg; - khui_config_init_data idata; - int idx; - - hw_tab = GetDlgItem(hwnd, IDC_CFG_TAB); - hw_target = GetDlgItem(hwnd, IDC_CFG_TARGET); -#ifdef DEBUG - assert(hw_tab); - assert(hw_target); -#endif - - if (KHM_FAILED(khui_cfg_get_first_subpanel(ref_node, &sub))) { -#ifdef DEBUG - assert(FALSE); -#endif - return; - } - - idx = 0; - while(sub) { - HWND hwnd_panel; - TCITEM tci; - int iid; - - khui_cfg_get_reg(sub, ®); - - if ((ctx_node == ref_node && (reg.flags & KHUI_CNFLAG_PLURAL)) || - (ctx_node != ref_node && !(reg.flags & KHUI_CNFLAG_PLURAL))) - goto _next_node; - - idata.ctx_node = ctx_node; - idata.this_node = sub; - idata.ref_node = ref_node; - - hwnd_panel = CreateDialogParam(reg.h_module, - reg.dlg_template, - hwnd, - reg.dlg_proc, - (LPARAM) &idata); - -#ifdef DEBUG - assert(hwnd_panel); -#endif - - ShowWindow(hwnd_panel, SW_HIDE); - - ZeroMemory(&tci, sizeof(tci)); - - tci.mask = TCIF_PARAM | TCIF_TEXT; - tci.lParam = (LPARAM) sub; - tci.pszText = (LPWSTR) reg.short_desc; - - iid = TabCtrl_InsertItem(hw_tab, 0, &tci); - idx++; - - if (reg.flags & KHUI_CNFLAG_PLURAL) { - khui_cfg_set_param_inst(sub, ctx_node, iid); - khui_cfg_set_hwnd_inst(sub, ctx_node, hwnd_panel); - } else { - khui_cfg_set_param(sub, iid); - khui_cfg_set_hwnd(sub, hwnd_panel); - } - - _next_node: - - khui_cfg_get_next_release(&sub); - } - - TabCtrl_SetCurSel(hw_tab, 0); -} - -static void -apply_all(HWND hwnd, - HWND hw_tab, - khui_config_node noderef) { - TCITEM tci; - HWND hw; - khui_config_node_reg reg; - int idx; - int count; - BOOL cont = TRUE; - - count = TabCtrl_GetItemCount(hw_tab); - - for (idx = 0; idx < count && cont; idx++) { - - ZeroMemory(&tci, sizeof(tci)); - - tci.mask = TCIF_PARAM; - TabCtrl_GetItem(hw_tab, - idx, - &tci); - -#ifdef DEBUG - assert(tci.lParam); -#endif - khui_cfg_get_reg((khui_config_node) tci.lParam, ®); - if (reg.flags & KHUI_CNFLAG_PLURAL) - hw = khui_cfg_get_hwnd_inst((khui_config_node) tci.lParam, - noderef); - else - hw = khui_cfg_get_hwnd((khui_config_node) tci.lParam); -#ifdef DEBUG - assert(hw); -#endif - - SendMessage(hw, KHUI_WM_CFG_NOTIFY, - MAKEWPARAM(0, WMCFG_APPLY), (LPARAM) &cont); - } -} - -static void -show_tab_panel(HWND hwnd, - khui_config_node node, - HWND hw_tab, - int idx, - BOOL show) { - TCITEM tci; - HWND hw; - HWND hw_target; - HWND hw_firstctl; - RECT r; - RECT rref; - khui_config_node_reg reg; - - ZeroMemory(&tci, sizeof(tci)); - - tci.mask = TCIF_PARAM; - TabCtrl_GetItem(hw_tab, - idx, - &tci); - -#ifdef DEBUG - assert(tci.lParam); -#endif - khui_cfg_get_reg((khui_config_node) tci.lParam, ®); - if (reg.flags & KHUI_CNFLAG_PLURAL) - hw = khui_cfg_get_hwnd_inst((khui_config_node) tci.lParam, - node); - else - hw = khui_cfg_get_hwnd((khui_config_node) tci.lParam); -#ifdef DEBUG - assert(hw); -#endif - - if (!show) { - ShowWindow(hw, SW_HIDE); - return; - } - - hw_target = GetDlgItem(hwnd, IDC_CFG_TARGET); -#ifdef DEBUG - assert(hw_target); -#endif - GetWindowRect(hwnd, &rref); - GetWindowRect(hw_target, &r); - - OffsetRect(&r, -rref.left, -rref.top); - - SetWindowPos(hw, - hw_tab, - r.left, r.top, - 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 -handle_cfg_notify(HWND hwnd, - WPARAM wParam, - LPARAM lParam) { - khui_config_node node; - HWND hw; - - node = get_window_node(hwnd); - - if (HIWORD(wParam) == WMCFG_APPLY) { - - hw = GetDlgItem(hwnd, IDC_CFG_TAB); - - apply_all(hwnd, - hw, - node); - } - - return TRUE; -} - -static INT_PTR -handle_notify(HWND hwnd, - WPARAM wParam, - LPARAM lParam) { - LPNMHDR lpnm; - int i; - - - khui_config_node node; - - lpnm = (LPNMHDR) lParam; - node = get_window_node(hwnd); - - if (lpnm->idFrom == IDC_CFG_TAB) { - switch(lpnm->code) { - case TCN_SELCHANGING: - i = TabCtrl_GetCurSel(lpnm->hwndFrom); - - show_tab_panel(hwnd, - node, - lpnm->hwndFrom, - i, - FALSE); - break; - - case TCN_SELCHANGE: - i = TabCtrl_GetCurSel(lpnm->hwndFrom); - - show_tab_panel(hwnd, - node, - lpnm->hwndFrom, - i, - TRUE); - break; - } - return TRUE; - } else { - return FALSE; - } -} - -typedef struct tag_ident_props { - BOOL monitor; - BOOL auto_renew; - BOOL sticky; -} ident_props; - -typedef struct tag_ident_data { - khm_handle ident; - wchar_t * idname; - int lv_idx; - - BOOL removed; - BOOL applied; - - khm_int32 flags; - - ident_props saved; - ident_props work; - - HWND hwnd; -} ident_data; - -typedef struct tag_global_props { - BOOL monitor; - BOOL auto_renew; - BOOL sticky; -} global_props; - -typedef struct tag_idents_data { - BOOL valid; - - ident_data * idents; - khm_size n_idents; - khm_size nc_idents; -#define IDENTS_DATA_ALLOC_INCR 8 - - /* global options */ - global_props saved; - global_props work; - BOOL applied; - - int refcount; - - HIMAGELIST hi_status; - int idx_id; - int idx_default; - int idx_modified; - int idx_applied; - int idx_deleted; - - HWND hwnd; - khui_config_init_data cfg; -} idents_data; - -static idents_data cfg_idents = {FALSE, NULL, 0, 0, - {0, 0, 0}, - {0, 0, 0}, - FALSE, - - 0, NULL }; - -static void -read_params_ident(ident_data * d) { - khm_handle csp_ident; - khm_handle csp_cw; - khm_int32 t; - - if (KHM_FAILED(kcdb_identity_get_config(d->ident, - KHM_PERM_READ, - &csp_ident))) { - csp_ident = NULL; - } - - if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, - &csp_cw))) { - if (csp_ident) { - khc_shadow_space(csp_ident, - csp_cw); - khc_close_space(csp_cw); - } else { - csp_ident = csp_cw; - } - csp_cw = NULL; - } else { -#ifdef DEBUG - assert(FALSE); -#endif - d->saved.monitor = TRUE; - d->saved.auto_renew = TRUE; - d->saved.sticky = FALSE; - d->work = d->saved; - - if (csp_ident) - khc_close_space(csp_ident); - - return; - } - - if (KHM_FAILED(khc_read_int32(csp_ident, L"Monitor", &t))) { -#ifdef DEBUG - assert(FALSE); -#endif - d->saved.monitor = TRUE; - } else { - d->saved.monitor = !!t; - } - - if (KHM_FAILED(khc_read_int32(csp_ident, L"AllowAutoRenew", &t))) { -#ifdef DEBUG - assert(FALSE); -#endif - d->saved.auto_renew = TRUE; - } else { - d->saved.auto_renew = !!t; - } - - if (KHM_FAILED(khc_read_int32(csp_ident, L"Sticky", &t))) { - d->saved.sticky = FALSE; - } else { - d->saved.sticky = !!t; - } - - khc_close_space(csp_ident); - - d->work = d->saved; - d->applied = FALSE; -} - -static void -write_params_ident(ident_data * d) { - khm_handle csp_ident; - - if (d->saved.monitor == d->work.monitor && - d->saved.auto_renew == d->work.auto_renew && - d->saved.sticky == d->work.sticky && - !d->removed) - return; - - if (KHM_FAILED(kcdb_identity_get_config(d->ident, KHM_PERM_WRITE, - &csp_ident))) { -#ifdef DEBUG - assert(FALSE); -#endif - return; - } - - if (d->removed) { - khm_handle h = NULL; - khm_int32 flags = 0; - - khc_remove_space(csp_ident); - - /* calling kcdb_identity_get_config() will update the - KCDB_IDENT_FLAG_CONFIG flag for the identity to reflect the - fact that it nolonger has a configuration. */ - kcdb_identity_get_config(d->ident, 0, &h); - if (h) { - /* what the ? */ -#ifdef DEBUG - assert(FALSE); -#endif - khc_close_space(h); - } -#ifdef DEBUG - kcdb_identity_get_flags(d->ident, &flags); - assert(!(flags & KCDB_IDENT_FLAG_CONFIG)); -#endif - - } else { - - if (d->saved.monitor != d->work.monitor) - khc_write_int32(csp_ident, L"Monitor", !!d->work.monitor); - - if (d->saved.auto_renew != d->work.auto_renew) - khc_write_int32(csp_ident, L"AllowAutoRenew", - !!d->work.auto_renew); - - if (d->saved.sticky != d->work.sticky) { - kcdb_identity_set_flags(d->ident, - (d->work.sticky)?KCDB_IDENT_FLAG_STICKY:0, - KCDB_IDENT_FLAG_STICKY); - } - } - - khc_close_space(csp_ident); - - d->saved = d->work; - - d->applied = TRUE; - - if (d->hwnd) - PostMessage(d->hwnd, KHUI_WM_CFG_NOTIFY, - MAKEWPARAM(0, WMCFG_UPDATE_STATE), 0); - - khm_refresh_config(); -} - -static void -write_params_idents(void) { - khm_handle csp_cw = NULL; - - if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", - KHM_FLAG_CREATE, &csp_cw))) { - if (cfg_idents.work.monitor != cfg_idents.saved.monitor) { - khc_write_int32(csp_cw, L"DefaultMonitor", - !!cfg_idents.work.monitor); - cfg_idents.work.monitor = cfg_idents.saved.monitor; - cfg_idents.applied = TRUE; - } - if (cfg_idents.work.auto_renew != cfg_idents.saved.auto_renew) { - khc_write_int32(csp_cw, L"DefaultAllowAutoRenew", - !!cfg_idents.work.auto_renew); - cfg_idents.work.auto_renew = cfg_idents.saved.auto_renew; - cfg_idents.applied = TRUE; - } - if (cfg_idents.work.sticky != cfg_idents.saved.sticky) { - khc_write_int32(csp_cw, L"DefaultSticky", - !!cfg_idents.work.sticky); - cfg_idents.work.sticky = cfg_idents.saved.sticky; - cfg_idents.applied = TRUE; - } - - khc_close_space(csp_cw); - csp_cw = NULL; - } - -#if 0 - for (i=0; i < (int)cfg_idents.n_idents; i++) { - write_params_ident(&cfg_idents.idents[i]); - } -#endif - - if (cfg_idents.hwnd) - PostMessage(cfg_idents.hwnd, KHUI_WM_CFG_NOTIFY, - MAKEWPARAM(0, WMCFG_UPDATE_STATE), 0); -} - -static void -init_idents_data(void) { - khm_int32 rv; - wchar_t * t; - wchar_t * widnames = NULL; - khm_size cb; - int n_tries = 0; - int i; - khm_handle csp_cw = NULL; - - if (cfg_idents.valid) - return; - -#ifdef DEBUG - assert(cfg_idents.idents == NULL); - assert(cfg_idents.n_idents == 0); - assert(cfg_idents.nc_idents == 0); -#endif - - if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", 0, &csp_cw))) { - khm_int32 t; - - if (KHM_SUCCEEDED(khc_read_int32(csp_cw, L"DefaultMonitor", &t))) - cfg_idents.saved.monitor = !!t; - else - cfg_idents.saved.monitor = TRUE; - - if (KHM_SUCCEEDED(khc_read_int32(csp_cw, L"DefaultAllowAutoRenew", &t))) - cfg_idents.saved.auto_renew = !!t; - else - cfg_idents.saved.auto_renew = TRUE; - - if (KHM_SUCCEEDED(khc_read_int32(csp_cw, L"DefaultSticky", &t))) - cfg_idents.saved.sticky = !!t; - else - cfg_idents.saved.sticky = FALSE; - - khc_close_space(csp_cw); - csp_cw = NULL; - - } else { - - cfg_idents.saved.monitor = TRUE; - cfg_idents.saved.auto_renew = TRUE; - cfg_idents.saved.sticky = FALSE; - - } - - cfg_idents.work = cfg_idents.saved; - cfg_idents.applied = FALSE; - - do { - rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG, - KCDB_IDENT_FLAG_CONFIG, - NULL, - &cb, - &cfg_idents.n_idents); - - if (rv != KHM_ERROR_TOO_LONG || - cfg_idents.n_idents == 0 || - cb == 0) - break; - - if (widnames) - PFREE(widnames); - widnames = PMALLOC(cb); -#ifdef DEBUG - assert(widnames); -#endif - - rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG, - KCDB_IDENT_FLAG_CONFIG, - widnames, - &cb, - &cfg_idents.n_idents); - n_tries++; - } while(KHM_FAILED(rv) && - n_tries < 5); - - if (KHM_FAILED(rv) || - cfg_idents.n_idents == 0) { - cfg_idents.n_idents = 0; - goto _cleanup; - } - - cfg_idents.idents = PMALLOC(sizeof(*cfg_idents.idents) * - cfg_idents.n_idents); -#ifdef DEBUG - assert(cfg_idents.idents); -#endif - ZeroMemory(cfg_idents.idents, - sizeof(*cfg_idents.idents) * cfg_idents.n_idents); - cfg_idents.nc_idents = cfg_idents.n_idents; - - i = 0; - for (t = widnames; t && *t; t = multi_string_next(t)) { - khm_handle ident; - - if (KHM_FAILED(kcdb_identity_create(t, 0, &ident))) { - cfg_idents.n_idents--; - continue; - } - - StringCbLength(t, KCDB_IDENT_MAXCB_NAME, &cb); - cb += sizeof(wchar_t); - - cfg_idents.idents[i].idname = PMALLOC(cb); -#ifdef DEBUG - assert(cfg_idents.idents[i].idname); -#endif - StringCbCopy(cfg_idents.idents[i].idname, cb, t); - - cfg_idents.idents[i].ident = ident; - cfg_idents.idents[i].removed = FALSE; - - kcdb_identity_get_flags(ident, &cfg_idents.idents[i].flags); -#ifdef DEBUG - assert(cfg_idents.idents[i].flags & KCDB_IDENT_FLAG_CONFIG); -#endif - - read_params_ident(&cfg_idents.idents[i]); - - i++; - /* leave identity held */ - } - - _cleanup: - - cfg_idents.valid = TRUE; - - if (widnames) - PFREE(widnames); -} - -static void -free_idents_data(void) { - int i; - - if (!cfg_idents.valid) - return; - - for (i=0; i< (int) cfg_idents.n_idents; i++) { - if (cfg_idents.idents[i].ident) - kcdb_identity_release(cfg_idents.idents[i].ident); - if (cfg_idents.idents[i].idname) - PFREE(cfg_idents.idents[i].idname); - } - - if (cfg_idents.idents) - PFREE(cfg_idents.idents); - - cfg_idents.idents = NULL; - cfg_idents.n_idents = 0; - cfg_idents.nc_idents = 0; - cfg_idents.valid = FALSE; -} - -static void -hold_idents_data(void) { - if (!cfg_idents.valid) - init_idents_data(); -#ifdef DEBUG - assert(cfg_idents.valid); -#endif - cfg_idents.refcount++; -} - -static void -release_idents_data(void) { -#ifdef DEBUG - assert(cfg_idents.valid); -#endif - cfg_idents.refcount--; - - if (cfg_idents.refcount == 0) - free_idents_data(); -} - - -static void -refresh_data_idents(HWND hwnd) { - cfg_idents.work.monitor = - (IsDlgButtonChecked(hwnd, IDC_CFG_MONITOR) == BST_CHECKED); - cfg_idents.work.auto_renew = - (IsDlgButtonChecked(hwnd, IDC_CFG_RENEW) == BST_CHECKED); - cfg_idents.work.sticky = - (IsDlgButtonChecked(hwnd, IDC_CFG_STICKY) == BST_CHECKED); -} - -static void -refresh_view_idents_state(HWND hwnd) { - BOOL modified; - BOOL applied; - khm_int32 flags = 0; - - applied = cfg_idents.applied; - modified = (cfg_idents.work.monitor != cfg_idents.saved.monitor || - cfg_idents.work.auto_renew != cfg_idents.saved.auto_renew || - cfg_idents.work.sticky != cfg_idents.saved.sticky); - - if (modified) - flags |= KHUI_CNFLAG_MODIFIED; - if (applied) - flags |= KHUI_CNFLAG_APPLIED; - - khui_cfg_set_flags_inst(&cfg_idents.cfg, flags, - KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); -} - -struct ctrl_row_dimensions { - RECT enclosure; - RECT label; - RECT control; -}; - -typedef struct tag_add_ident_data { - khui_new_creds * nc; - - struct ctrl_row_dimensions dim_small; - struct ctrl_row_dimensions dim_medium; - struct ctrl_row_dimensions dim_large; - int row_gap; - - int current_y; - int current_x; - - HWND hwnd_last_ctrl; -} add_ident_data; - -void -get_ctrl_row_metrics(struct ctrl_row_dimensions * dim, HWND hw_lbl, HWND hw_ctl) { - - assert(hw_lbl); - assert(hw_ctl); - - GetWindowRect(hw_lbl, &dim->label); - GetWindowRect(hw_ctl, &dim->control); - - UnionRect(&dim->enclosure, &dim->label, &dim->control); - OffsetRect(&dim->label, - -dim->enclosure.left, - -dim->enclosure.top); - OffsetRect(&dim->control, - -dim->enclosure.left, - -dim->enclosure.top); - OffsetRect(&dim->enclosure, - -dim->enclosure.left, - -dim->enclosure.top); -} - -/* dialog box procedure for the "Add new identity" dialog */ -INT_PTR CALLBACK -khm_cfg_add_ident_proc(HWND hwnd, - UINT umsg, - WPARAM wParam, - LPARAM lParam) { - add_ident_data * d; - - switch(umsg) { - case WM_INITDIALOG: - /* we create a new credentials blob and pull in the identity - selectors from the identity provider. */ - d = PMALLOC(sizeof(*d)); - ZeroMemory(d, sizeof(*d)); - - khui_cw_create_cred_blob(&d->nc); -#ifdef DEBUG - assert(d->nc != NULL); -#endif - if (d->nc == NULL) { - PFREE(d); - break; - } - - if (KHM_FAILED(kcdb_identpro_get_ui_cb(&d->nc->ident_cb))) { - /* this should have worked. The only reason it would fail - is if there is no identity provider or if the identity - provider does not support providing idnetity - selectors. */ - khui_cw_destroy_cred_blob(d->nc); - PFREE(d); - break; - } - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); -#pragma warning(pop) - - /* get metrics for dynamic controls */ - get_ctrl_row_metrics(&d->dim_small, - GetDlgItem(hwnd, IDC_SM_LBL), - GetDlgItem(hwnd, IDC_SM_CTL)); - get_ctrl_row_metrics(&d->dim_medium, - GetDlgItem(hwnd, IDC_MED_LBL), - GetDlgItem(hwnd, IDC_MED_CTL)); - get_ctrl_row_metrics(&d->dim_large, - GetDlgItem(hwnd, IDC_LG_LBL), - GetDlgItem(hwnd, IDC_LG_CTL)); - - { - RECT rlbl; - RECT rctl; - RECT rwnd; - - GetWindowRect(GetDlgItem(hwnd, IDC_SM_LBL), - &rlbl); - GetWindowRect(GetDlgItem(hwnd, IDC_SM_CTL), - &rctl); - GetWindowRect(hwnd, &rwnd); - - OffsetRect(&rlbl, -rwnd.left, -rwnd.top); - OffsetRect(&rctl, -rwnd.left, -rwnd.top); - - d->current_x = rlbl.left; - d->current_y = rctl.top - GetSystemMetrics(SM_CYCAPTION); - - GetWindowRect(GetDlgItem(hwnd, IDC_MED_CTL), - &rlbl); - OffsetRect(&rlbl, -rwnd.left, -rwnd.top); - - d->row_gap = rlbl.top - rctl.bottom; - } - - d->nc->hwnd = hwnd; - - /* now call the UI callback and make it create the - controls. */ - d->nc->ident_cb(d->nc, WMNC_IDENT_INIT, NULL, 0, 0, - (LPARAM) hwnd); - - break; - - case WM_DESTROY: - d = (add_ident_data *)(LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - if (d == NULL) - break; - - d->nc->ident_cb(d->nc, WMNC_IDENT_EXIT, NULL, 0, 0, 0); - - khui_cw_destroy_cred_blob(d->nc); - PFREE(d); - break; - - case KHUI_WM_NC_NOTIFY: - d = (add_ident_data *)(LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - switch(HIWORD(wParam)) { - case WMNC_ADD_CONTROL_ROW: - { - khui_control_row * row; - RECT r_lbl, r_inp, r_enc; - struct ctrl_row_dimensions * dim; - HFONT hf; - - row = (khui_control_row *) lParam; - -#ifdef DEBUG - assert(row->label); - assert(row->input); - assert(d); -#endif - - if (row->size == KHUI_CTRLSIZE_SMALL) { - dim = &d->dim_small; - } else if (row->size == KHUI_CTRLSIZE_HALF) { - dim = &d->dim_medium; - } else { - dim = &d->dim_large; -#ifdef DEBUG - assert(row->size == KHUI_CTRLSIZE_FULL); -#endif - } - - CopyRect(&r_enc, &dim->enclosure); - CopyRect(&r_lbl, &dim->label); - CopyRect(&r_inp, &dim->control); - - OffsetRect(&r_enc, d->current_x, d->current_y); - OffsetRect(&r_lbl, r_enc.left, r_enc.top); - OffsetRect(&r_inp, r_enc.left, r_enc.top); - - d->current_y += r_enc.bottom - r_enc.top; - - hf = (HFONT) SendDlgItemMessage(hwnd, IDOK, WM_GETFONT, 0, 0); - - if (row->label) { - SetWindowPos(row->label, - ((d->hwnd_last_ctrl != NULL)? - d->hwnd_last_ctrl : - HWND_TOP), - r_lbl.left, r_lbl.top, - r_lbl.right - r_lbl.left, - r_lbl.bottom - r_lbl.top, - SWP_DEFERERASE | SWP_NOACTIVATE | - SWP_NOOWNERZORDER); - if (hf) - SendMessage(row->label, WM_SETFONT, - (WPARAM) hf, - TRUE); - d->hwnd_last_ctrl = row->label; - } - - if (row->input) { - SetWindowPos(row->input, - ((d->hwnd_last_ctrl != NULL)? - d->hwnd_last_ctrl : - HWND_TOP), - r_inp.left, r_inp.top, - r_inp.right - r_inp.left, - r_inp.bottom - r_inp.top, - SWP_DEFERERASE | SWP_NOACTIVATE | - SWP_NOOWNERZORDER); - if (hf) - SendMessage(row->input, WM_SETFONT, - (WPARAM) hf, - TRUE); - d->hwnd_last_ctrl = row->input; - } - } - break; - - case WMNC_IDENTITY_CHANGE: - break; - } - return TRUE; - - case WM_COMMAND: - if (LOWORD(wParam) == IDOK) { - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - wchar_t err_msg[1024]; - khm_handle ident = NULL; - khm_handle csp_ident = NULL; - khm_size cb; - khm_int32 rv = KHM_ERROR_SUCCESS; - - d = (add_ident_data *)(LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (!d || !d->nc) - break; - - /* check if there was an identity selected */ - if (d->nc->n_identities == 0 || - d->nc->identities[0] == NULL) { - - StringCbCopy(idname, sizeof(idname), L""); - - LoadString(khm_hInstance, IDS_CFG_IDNAME_NON, - err_msg, ARRAYLENGTH(err_msg)); - - goto show_failure; - } - - ident = d->nc->identities[0]; - kcdb_identity_hold(ident); - - cb = sizeof(idname); - kcdb_identity_get_name(ident, idname, &cb); - - /* now we have to create the identity configuration. */ - if (KHM_FAILED(rv = kcdb_identity_get_config(ident, - KHM_FLAG_CREATE, - &csp_ident))) { - wchar_t fmt[256]; - - LoadString(khm_hInstance, IDS_CFG_IDNAME_CCC, - fmt, ARRAYLENGTH(fmt)); - StringCbPrintf(err_msg, sizeof(err_msg), fmt, rv); - - kcdb_identity_release(ident); - - goto show_failure; - } - - /* create a value so that the configuration space will - actually be created in the registry. We don't want - this new identity to be sticky. */ - khc_write_int32(csp_ident, L"Sticky", 0); - - khm_refresh_config(); - - kcdb_identity_release(ident); - khc_close_space(csp_ident); - - EndDialog(hwnd, 0); - break; - - show_failure: - { - wchar_t title[512]; - wchar_t fmt[256]; - - if (!err_msg[0]) - break; - - LoadString(khm_hInstance, IDS_CFG_IDNAME_PRB, - fmt, ARRAYLENGTH(fmt)); - StringCbPrintf(title, sizeof(title), fmt, idname); - - MessageBox(hwnd, err_msg, title, MB_OK | MB_ICONSTOP); - - /* don't end the dialog yet */ - break; - } - break; - - } else if (LOWORD(wParam) == IDCANCEL) { - EndDialog(hwnd, 1); - } else { - d = (add_ident_data *)(LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (d && d->nc && d->nc->ident_cb) { - return d->nc->ident_cb(d->nc, WMNC_IDENT_WMSG, - hwnd, umsg, wParam, lParam); - } - } - break; - } - - return FALSE; -} - -/* dialog procedure for the "general" pane of the "identities" - configuration node. */ -INT_PTR CALLBACK -khm_cfg_ids_tab_proc(HWND hwnd, - UINT umsg, - WPARAM wParam, - LPARAM lParam) { - - switch(umsg) { - case WM_INITDIALOG: - { - HICON hicon; - - hold_idents_data(); - - cfg_idents.hwnd = hwnd; - cfg_idents.cfg = *((khui_config_init_data *) lParam); - - /* add the status icons */ - if (cfg_idents.hi_status) - goto _done_with_icons; - - cfg_idents.hi_status = - ImageList_Create(GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), - ILC_COLOR8 | ILC_MASK, - 4,4); - - hicon = - LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_ID), - IMAGE_ICON, - GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); - - cfg_idents.idx_id = ImageList_AddIcon(cfg_idents.hi_status, - hicon); - - DestroyIcon(hicon); - - hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_DEFAULT), - IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); - - cfg_idents.idx_default = ImageList_AddIcon(cfg_idents.hi_status, - hicon) + 1; - - DestroyIcon(hicon); - - hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_MODIFIED), - IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); - - cfg_idents.idx_modified = ImageList_AddIcon(cfg_idents.hi_status, - hicon) + 1; - - DestroyIcon(hicon); - - hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_APPLIED), - IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); - - cfg_idents.idx_applied = ImageList_AddIcon(cfg_idents.hi_status, - hicon) + 1; - - DestroyIcon(hicon); - - hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_DELETED), - IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); - - cfg_idents.idx_deleted = ImageList_AddIcon(cfg_idents.hi_status, - hicon) + 1; - - DestroyIcon(hicon); - - _done_with_icons: - - CheckDlgButton(hwnd, IDC_CFG_MONITOR, - (cfg_idents.work.monitor)?BST_CHECKED:BST_UNCHECKED); - CheckDlgButton(hwnd, IDC_CFG_RENEW, - (cfg_idents.work.auto_renew)?BST_CHECKED:BST_UNCHECKED); - CheckDlgButton(hwnd, IDC_CFG_STICKY, - (cfg_idents.work.sticky)?BST_CHECKED:BST_UNCHECKED); - - } - return FALSE; - - case WM_COMMAND: - - if (HIWORD(wParam) == BN_CLICKED) { - UINT ctrl = LOWORD(wParam); - - switch(ctrl) { - case IDC_CFG_MONITOR: - case IDC_CFG_RENEW: - case IDC_CFG_STICKY: - refresh_data_idents(hwnd); - break; - - case IDC_CFG_ADDIDENT: - DialogBoxParam(khm_hInstance, - MAKEINTRESOURCE(IDD_CFG_ADDIDENT), - hwnd, - khm_cfg_add_ident_proc, - (LPARAM) hwnd); - break; - } - - refresh_view_idents_state(hwnd); - } - - khm_set_dialog_result(hwnd, 0); - return TRUE; - - case KHUI_WM_CFG_NOTIFY: - { - switch(HIWORD(wParam)) { - case WMCFG_APPLY: - write_params_idents(); - break; - - case WMCFG_UPDATE_STATE: - refresh_view_idents_state(hwnd); - break; - } - } - return TRUE; - - case WM_DESTROY: - cfg_idents.hwnd = NULL; - - if (cfg_idents.hi_status != NULL) { - ImageList_Destroy(cfg_idents.hi_status); - cfg_idents.hi_status = NULL; - } - release_idents_data(); - - khm_set_dialog_result(hwnd, 0); - - return TRUE; - } - - return FALSE; -} - -/* dialog procedure for the "Identities" configuration node */ -INT_PTR CALLBACK -khm_cfg_identities_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - HWND hw; - switch(uMsg) { - case WM_INITDIALOG: - set_window_node(hwnd, (khui_config_node) lParam); - add_subpanels(hwnd, (khui_config_node) lParam, - (khui_config_node) lParam); - hw = GetDlgItem(hwnd, IDC_CFG_TAB); - show_tab_panel(hwnd, - (khui_config_node) lParam, - hw, - TabCtrl_GetCurSel(hw), - TRUE); - return FALSE; - - case WM_DESTROY: - return 0; - - case KHUI_WM_CFG_NOTIFY: - return handle_cfg_notify(hwnd, wParam, lParam); - - case WM_NOTIFY: - return handle_notify(hwnd, wParam, lParam); - } - - return FALSE; -} - -static ident_data * -find_ident_by_node(khui_config_node node) { - khm_size cb; - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - int i; - khm_handle ident = NULL; - - cb = sizeof(idname); - khui_cfg_get_name(node, idname, &cb); - - for (i=0; i < (int)cfg_idents.n_idents; i++) { - if (!wcscmp(cfg_idents.idents[i].idname, idname)) - break; - } - - if (i < (int)cfg_idents.n_idents) - return &cfg_idents.idents[i]; - - /* there is no identity data for this configuration node. We try - to create it. */ - if (KHM_FAILED(kcdb_identity_create(idname, 0, &ident))) - return NULL; - - if (cfg_idents.n_idents >= cfg_idents.nc_idents) { - cfg_idents.nc_idents = UBOUNDSS(cfg_idents.n_idents + 1, - IDENTS_DATA_ALLOC_INCR, - IDENTS_DATA_ALLOC_INCR); -#ifdef DEBUG - assert(cfg_idents.nc_idents > cfg_idents.n_idents); -#endif - cfg_idents.idents = PREALLOC(cfg_idents.idents, - sizeof(*cfg_idents.idents) * - cfg_idents.nc_idents); -#ifdef DEBUG - assert(cfg_idents.idents); -#endif - ZeroMemory(&(cfg_idents.idents[cfg_idents.n_idents]), - sizeof(*cfg_idents.idents) * - (cfg_idents.nc_idents - cfg_idents.n_idents)); - } - - i = (int) cfg_idents.n_idents; - - StringCbLength(idname, KCDB_IDENT_MAXCB_NAME, &cb); - cb += sizeof(wchar_t); - - cfg_idents.idents[i].idname = PMALLOC(cb); -#ifdef DEBUG - assert(cfg_idents.idents[i].idname); -#endif - StringCbCopy(cfg_idents.idents[i].idname, cb, idname); - - cfg_idents.idents[i].ident = ident; - cfg_idents.idents[i].removed = FALSE; - - kcdb_identity_get_flags(ident, &cfg_idents.idents[i].flags); -#ifdef DEBUG - assert(cfg_idents.idents[i].flags & KCDB_IDENT_FLAG_CONFIG); -#endif - - read_params_ident(&cfg_idents.idents[i]); - - cfg_idents.n_idents++; - - /* leave ident held. */ - - return &cfg_idents.idents[i]; -} - -static void -refresh_view_ident(HWND hwnd, khui_config_node node) { - ident_data * d; - - d = find_ident_by_node(node); -#ifdef DEBUG - assert(d); -#endif - - CheckDlgButton(hwnd, IDC_CFG_MONITOR, - (d->work.monitor? BST_CHECKED: BST_UNCHECKED)); - CheckDlgButton(hwnd, IDC_CFG_RENEW, - (d->work.auto_renew? BST_CHECKED: BST_UNCHECKED)); - CheckDlgButton(hwnd, IDC_CFG_STICKY, - (d->work.sticky? BST_CHECKED: BST_UNCHECKED)); -} - -static void -mark_remove_ident(HWND hwnd, khui_config_init_data * idata) { - ident_data * d; - - d = find_ident_by_node(idata->ctx_node); -#ifdef DEBUG - assert(d); -#endif - - if (d->removed) - return; - - d->removed = TRUE; - - khui_cfg_set_flags_inst(idata, KHUI_CNFLAG_MODIFIED, - KHUI_CNFLAG_MODIFIED); - - EnableWindow(GetDlgItem(hwnd, IDC_CFG_REMOVE), FALSE); -} - -static void -refresh_data_ident(HWND hwnd, khui_config_init_data * idata) { - ident_data * d; - - d = find_ident_by_node(idata->ctx_node); -#ifdef DEBUG - assert(d); -#endif - - if (IsDlgButtonChecked(hwnd, IDC_CFG_MONITOR) == BST_CHECKED) - d->work.monitor = TRUE; - else - d->work.monitor = FALSE; - - if (IsDlgButtonChecked(hwnd, IDC_CFG_RENEW) == BST_CHECKED) - d->work.auto_renew = TRUE; - else - d->work.auto_renew = FALSE; - - if (IsDlgButtonChecked(hwnd, IDC_CFG_STICKY) == BST_CHECKED) - d->work.sticky = TRUE; - else - d->work.sticky = FALSE; - - if (d->work.monitor != d->saved.monitor || - d->work.auto_renew != d->saved.auto_renew || - d->work.sticky != d->saved.sticky) { - - khui_cfg_set_flags_inst(idata, KHUI_CNFLAG_MODIFIED, - KHUI_CNFLAG_MODIFIED); - - } else { - khui_cfg_set_flags_inst(idata, 0, - KHUI_CNFLAG_MODIFIED); - } -} - -/* dialog procedure for the "general" pane of individual identity - configuration nodes. */ -INT_PTR CALLBACK -khm_cfg_id_tab_proc(HWND hwnd, - UINT umsg, - WPARAM wParam, - LPARAM lParam) { - - khui_config_init_data * idata; - - switch(umsg) { - case WM_INITDIALOG: - { - ident_data * d; - - hold_idents_data(); - - idata = (khui_config_init_data *) lParam; - - khui_cfg_init_dialog_data(hwnd, idata, 0, NULL, NULL); - - refresh_view_ident(hwnd, idata->ctx_node); - - d = find_ident_by_node(idata->ctx_node); - if (d) - d->hwnd = hwnd; -#ifdef DEBUG - else - assert(FALSE); -#endif - } - return FALSE; - - case WM_COMMAND: - khui_cfg_get_dialog_data(hwnd, &idata, NULL); - - if (HIWORD(wParam) == BN_CLICKED) { - switch(LOWORD(wParam)) { - case IDC_CFG_MONITOR: - case IDC_CFG_RENEW: - case IDC_CFG_STICKY: - - refresh_data_ident(hwnd, idata); - if (cfg_idents.hwnd) - PostMessage(cfg_idents.hwnd, KHUI_WM_CFG_NOTIFY, - MAKEWPARAM(1, WMCFG_UPDATE_STATE), 0); - break; - - case IDC_CFG_REMOVE: - mark_remove_ident(hwnd, idata); - if (cfg_idents.hwnd) - PostMessage(cfg_idents.hwnd, KHUI_WM_CFG_NOTIFY, - MAKEWPARAM(1, WMCFG_UPDATE_STATE), 0); - break; - } - } - - khm_set_dialog_result(hwnd, 0); - return TRUE; - - case WM_DESTROY: - { - ident_data * d; - - khui_cfg_get_dialog_data(hwnd, &idata, NULL); - - d = find_ident_by_node(idata->ctx_node); - if (d) - d->hwnd = NULL; - - release_idents_data(); - khui_cfg_free_dialog_data(hwnd); - khm_set_dialog_result(hwnd, 0); - } - return TRUE; - - case KHUI_WM_CFG_NOTIFY: - { - ident_data * d; - BOOL * cont; - - khui_cfg_get_dialog_data(hwnd, &idata, NULL); - - switch (HIWORD(wParam)) { - case WMCFG_APPLY: - cont = (BOOL *) lParam; - d = find_ident_by_node(idata->ctx_node); - write_params_ident(d); - if (d->removed && cont) - *cont = FALSE; - khui_cfg_set_flags_inst(idata, KHUI_CNFLAG_APPLIED, - KHUI_CNFLAG_APPLIED | - KHUI_CNFLAG_MODIFIED); - break; - - case WMCFG_UPDATE_STATE: - refresh_view_ident(hwnd, idata->ctx_node); - refresh_data_ident(hwnd, idata); - break; - } - } - return TRUE; - } - - return FALSE; -} - -/* dialog procedure for individual identity configuration nodes */ -INT_PTR CALLBACK -khm_cfg_identity_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - HWND hw; - - switch(uMsg) { - case WM_INITDIALOG: - { - khui_config_node refnode = NULL; - - set_window_node(hwnd, (khui_config_node) lParam); - - khui_cfg_open(NULL, L"KhmIdentities", &refnode); -#ifdef DEBUG - assert(refnode != NULL); -#endif - add_subpanels(hwnd, - (khui_config_node) lParam, - refnode); - - hw = GetDlgItem(hwnd, IDC_CFG_TAB); - - show_tab_panel(hwnd, - (khui_config_node) lParam, - hw, - TabCtrl_GetCurSel(hw), - TRUE); - - khui_cfg_release(refnode); - } - return FALSE; - - case WM_DESTROY: - return 0; - - case KHUI_WM_CFG_NOTIFY: - return handle_cfg_notify(hwnd, wParam, lParam); - - case WM_NOTIFY: - return handle_notify(hwnd, wParam, lParam); - } - return FALSE; -} +/* + * 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 + +static khui_config_node +get_window_node(HWND hwnd) { + return (khui_config_node) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); +} + +static void +set_window_node(HWND hwnd, khui_config_node node) { +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, + (LONG_PTR) node); +#pragma warning(pop) +} + +static void +add_subpanels(HWND hwnd, + khui_config_node ctx_node, + khui_config_node ref_node) { + + HWND hw_tab; + HWND hw_target; + khui_config_node sub; + khui_config_node_reg reg; + khui_config_init_data idata; + int idx; + + hw_tab = GetDlgItem(hwnd, IDC_CFG_TAB); + hw_target = GetDlgItem(hwnd, IDC_CFG_TARGET); +#ifdef DEBUG + assert(hw_tab); + assert(hw_target); +#endif + + if (KHM_FAILED(khui_cfg_get_first_subpanel(ref_node, &sub))) { +#ifdef DEBUG + assert(FALSE); +#endif + return; + } + + idx = 0; + while(sub) { + HWND hwnd_panel; + TCITEM tci; + int iid; + + khui_cfg_get_reg(sub, ®); + + if ((ctx_node == ref_node && (reg.flags & KHUI_CNFLAG_PLURAL)) || + (ctx_node != ref_node && !(reg.flags & KHUI_CNFLAG_PLURAL))) + goto _next_node; + + idata.ctx_node = ctx_node; + idata.this_node = sub; + idata.ref_node = ref_node; + + hwnd_panel = CreateDialogParam(reg.h_module, + reg.dlg_template, + hwnd, + reg.dlg_proc, + (LPARAM) &idata); + +#ifdef DEBUG + assert(hwnd_panel); +#endif + + ShowWindow(hwnd_panel, SW_HIDE); + + ZeroMemory(&tci, sizeof(tci)); + + tci.mask = TCIF_PARAM | TCIF_TEXT; + tci.lParam = (LPARAM) sub; + tci.pszText = (LPWSTR) reg.short_desc; + + iid = TabCtrl_InsertItem(hw_tab, 0, &tci); + idx++; + + if (reg.flags & KHUI_CNFLAG_PLURAL) { + khui_cfg_set_param_inst(sub, ctx_node, iid); + khui_cfg_set_hwnd_inst(sub, ctx_node, hwnd_panel); + } else { + khui_cfg_set_param(sub, iid); + khui_cfg_set_hwnd(sub, hwnd_panel); + } + + _next_node: + + khui_cfg_get_next_release(&sub); + } + + TabCtrl_SetCurSel(hw_tab, 0); +} + +static void +apply_all(HWND hwnd, + HWND hw_tab, + khui_config_node noderef) { + TCITEM tci; + HWND hw; + khui_config_node_reg reg; + int idx; + int count; + BOOL cont = TRUE; + + count = TabCtrl_GetItemCount(hw_tab); + + for (idx = 0; idx < count && cont; idx++) { + + ZeroMemory(&tci, sizeof(tci)); + + tci.mask = TCIF_PARAM; + TabCtrl_GetItem(hw_tab, + idx, + &tci); + +#ifdef DEBUG + assert(tci.lParam); +#endif + khui_cfg_get_reg((khui_config_node) tci.lParam, ®); + if (reg.flags & KHUI_CNFLAG_PLURAL) + hw = khui_cfg_get_hwnd_inst((khui_config_node) tci.lParam, + noderef); + else + hw = khui_cfg_get_hwnd((khui_config_node) tci.lParam); +#ifdef DEBUG + assert(hw); +#endif + + SendMessage(hw, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(0, WMCFG_APPLY), (LPARAM) &cont); + } +} + +static void +show_tab_panel(HWND hwnd, + khui_config_node node, + HWND hw_tab, + int idx, + BOOL show) { + TCITEM tci; + HWND hw; + HWND hw_target; + HWND hw_firstctl; + RECT r; + RECT rref; + khui_config_node_reg reg; + + ZeroMemory(&tci, sizeof(tci)); + + tci.mask = TCIF_PARAM; + TabCtrl_GetItem(hw_tab, + idx, + &tci); + +#ifdef DEBUG + assert(tci.lParam); +#endif + khui_cfg_get_reg((khui_config_node) tci.lParam, ®); + if (reg.flags & KHUI_CNFLAG_PLURAL) + hw = khui_cfg_get_hwnd_inst((khui_config_node) tci.lParam, + node); + else + hw = khui_cfg_get_hwnd((khui_config_node) tci.lParam); +#ifdef DEBUG + assert(hw); +#endif + + if (!show) { + ShowWindow(hw, SW_HIDE); + return; + } + + hw_target = GetDlgItem(hwnd, IDC_CFG_TARGET); +#ifdef DEBUG + assert(hw_target); +#endif + GetWindowRect(hwnd, &rref); + GetWindowRect(hw_target, &r); + + OffsetRect(&r, -rref.left, -rref.top); + + SetWindowPos(hw, + hw_tab, + r.left, r.top, + 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 +handle_cfg_notify(HWND hwnd, + WPARAM wParam, + LPARAM lParam) { + khui_config_node node; + HWND hw; + + node = get_window_node(hwnd); + + if (HIWORD(wParam) == WMCFG_APPLY) { + + hw = GetDlgItem(hwnd, IDC_CFG_TAB); + + apply_all(hwnd, + hw, + node); + } + + return TRUE; +} + +static INT_PTR +handle_notify(HWND hwnd, + WPARAM wParam, + LPARAM lParam) { + LPNMHDR lpnm; + int i; + + + khui_config_node node; + + lpnm = (LPNMHDR) lParam; + node = get_window_node(hwnd); + + if (lpnm->idFrom == IDC_CFG_TAB) { + switch(lpnm->code) { + case TCN_SELCHANGING: + i = TabCtrl_GetCurSel(lpnm->hwndFrom); + + show_tab_panel(hwnd, + node, + lpnm->hwndFrom, + i, + FALSE); + break; + + case TCN_SELCHANGE: + i = TabCtrl_GetCurSel(lpnm->hwndFrom); + + show_tab_panel(hwnd, + node, + lpnm->hwndFrom, + i, + TRUE); + break; + } + return TRUE; + } else { + return FALSE; + } +} + +typedef struct tag_ident_props { + BOOL monitor; + BOOL auto_renew; + BOOL sticky; +} ident_props; + +typedef struct tag_ident_data { + khm_handle ident; + wchar_t * idname; + int lv_idx; + + BOOL removed; + BOOL applied; + + khm_int32 flags; + + ident_props saved; + ident_props work; + + HWND hwnd; +} ident_data; + +typedef struct tag_global_props { + BOOL monitor; + BOOL auto_renew; + BOOL sticky; +} global_props; + +typedef struct tag_idents_data { + BOOL valid; + + ident_data * idents; + khm_size n_idents; + khm_size nc_idents; +#define IDENTS_DATA_ALLOC_INCR 8 + + /* global options */ + global_props saved; + global_props work; + BOOL applied; + + int refcount; + + HIMAGELIST hi_status; + int idx_id; + int idx_default; + int idx_modified; + int idx_applied; + int idx_deleted; + + HWND hwnd; + khui_config_init_data cfg; +} idents_data; + +static idents_data cfg_idents = {FALSE, NULL, 0, 0, + {0, 0, 0}, + {0, 0, 0}, + FALSE, + + 0, NULL }; + +static void +read_params_ident(ident_data * d) { + khm_handle csp_ident; + khm_handle csp_cw; + khm_int32 t; + + if (KHM_FAILED(kcdb_identity_get_config(d->ident, + KHM_PERM_READ, + &csp_ident))) { + csp_ident = NULL; + } + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, + &csp_cw))) { + if (csp_ident) { + khc_shadow_space(csp_ident, + csp_cw); + khc_close_space(csp_cw); + } else { + csp_ident = csp_cw; + } + csp_cw = NULL; + } else { +#ifdef DEBUG + assert(FALSE); +#endif + d->saved.monitor = TRUE; + d->saved.auto_renew = TRUE; + d->saved.sticky = FALSE; + d->work = d->saved; + + if (csp_ident) + khc_close_space(csp_ident); + + return; + } + + if (KHM_FAILED(khc_read_int32(csp_ident, L"Monitor", &t))) { +#ifdef DEBUG + assert(FALSE); +#endif + d->saved.monitor = TRUE; + } else { + d->saved.monitor = !!t; + } + + if (KHM_FAILED(khc_read_int32(csp_ident, L"AllowAutoRenew", &t))) { +#ifdef DEBUG + assert(FALSE); +#endif + d->saved.auto_renew = TRUE; + } else { + d->saved.auto_renew = !!t; + } + + if (KHM_FAILED(khc_read_int32(csp_ident, L"Sticky", &t))) { + d->saved.sticky = FALSE; + } else { + d->saved.sticky = !!t; + } + + khc_close_space(csp_ident); + + d->work = d->saved; + d->applied = FALSE; +} + +static void +write_params_ident(ident_data * d) { + khm_handle csp_ident; + + if (d->saved.monitor == d->work.monitor && + d->saved.auto_renew == d->work.auto_renew && + d->saved.sticky == d->work.sticky && + !d->removed) + return; + + if (KHM_FAILED(kcdb_identity_get_config(d->ident, KHM_PERM_WRITE, + &csp_ident))) { +#ifdef DEBUG + assert(FALSE); +#endif + return; + } + + if (d->removed) { + khm_handle h = NULL; + khm_int32 flags = 0; + + khc_remove_space(csp_ident); + + /* calling kcdb_identity_get_config() will update the + KCDB_IDENT_FLAG_CONFIG flag for the identity to reflect the + fact that it nolonger has a configuration. */ + kcdb_identity_get_config(d->ident, 0, &h); + if (h) { + /* what the ? */ +#ifdef DEBUG + assert(FALSE); +#endif + khc_close_space(h); + } +#ifdef DEBUG + kcdb_identity_get_flags(d->ident, &flags); + assert(!(flags & KCDB_IDENT_FLAG_CONFIG)); +#endif + + } else { + + if (d->saved.monitor != d->work.monitor) + khc_write_int32(csp_ident, L"Monitor", !!d->work.monitor); + + if (d->saved.auto_renew != d->work.auto_renew) + khc_write_int32(csp_ident, L"AllowAutoRenew", + !!d->work.auto_renew); + + if (d->saved.sticky != d->work.sticky) { + kcdb_identity_set_flags(d->ident, + (d->work.sticky)?KCDB_IDENT_FLAG_STICKY:0, + KCDB_IDENT_FLAG_STICKY); + } + } + + khc_close_space(csp_ident); + + d->saved = d->work; + + d->applied = TRUE; + + if (d->hwnd) + PostMessage(d->hwnd, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(0, WMCFG_UPDATE_STATE), 0); + + khm_refresh_config(); +} + +static void +write_params_idents(void) { + khm_handle csp_cw = NULL; + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", + KHM_FLAG_CREATE, &csp_cw))) { + if (cfg_idents.work.monitor != cfg_idents.saved.monitor) { + khc_write_int32(csp_cw, L"DefaultMonitor", + !!cfg_idents.work.monitor); + cfg_idents.work.monitor = cfg_idents.saved.monitor; + cfg_idents.applied = TRUE; + } + if (cfg_idents.work.auto_renew != cfg_idents.saved.auto_renew) { + khc_write_int32(csp_cw, L"DefaultAllowAutoRenew", + !!cfg_idents.work.auto_renew); + cfg_idents.work.auto_renew = cfg_idents.saved.auto_renew; + cfg_idents.applied = TRUE; + } + if (cfg_idents.work.sticky != cfg_idents.saved.sticky) { + khc_write_int32(csp_cw, L"DefaultSticky", + !!cfg_idents.work.sticky); + cfg_idents.work.sticky = cfg_idents.saved.sticky; + cfg_idents.applied = TRUE; + } + + khc_close_space(csp_cw); + csp_cw = NULL; + } + +#if 0 + for (i=0; i < (int)cfg_idents.n_idents; i++) { + write_params_ident(&cfg_idents.idents[i]); + } +#endif + + if (cfg_idents.hwnd) + PostMessage(cfg_idents.hwnd, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(0, WMCFG_UPDATE_STATE), 0); +} + +static void +init_idents_data(void) { + khm_int32 rv; + wchar_t * t; + wchar_t * widnames = NULL; + khm_size cb; + int n_tries = 0; + int i; + khm_handle csp_cw = NULL; + + if (cfg_idents.valid) + return; + +#ifdef DEBUG + assert(cfg_idents.idents == NULL); + assert(cfg_idents.n_idents == 0); + assert(cfg_idents.nc_idents == 0); +#endif + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", 0, &csp_cw))) { + khm_int32 t; + + if (KHM_SUCCEEDED(khc_read_int32(csp_cw, L"DefaultMonitor", &t))) + cfg_idents.saved.monitor = !!t; + else + cfg_idents.saved.monitor = TRUE; + + if (KHM_SUCCEEDED(khc_read_int32(csp_cw, L"DefaultAllowAutoRenew", &t))) + cfg_idents.saved.auto_renew = !!t; + else + cfg_idents.saved.auto_renew = TRUE; + + if (KHM_SUCCEEDED(khc_read_int32(csp_cw, L"DefaultSticky", &t))) + cfg_idents.saved.sticky = !!t; + else + cfg_idents.saved.sticky = FALSE; + + khc_close_space(csp_cw); + csp_cw = NULL; + + } else { + + cfg_idents.saved.monitor = TRUE; + cfg_idents.saved.auto_renew = TRUE; + cfg_idents.saved.sticky = FALSE; + + } + + cfg_idents.work = cfg_idents.saved; + cfg_idents.applied = FALSE; + + do { + rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG, + KCDB_IDENT_FLAG_CONFIG, + NULL, + &cb, + &cfg_idents.n_idents); + + if (rv != KHM_ERROR_TOO_LONG || + cfg_idents.n_idents == 0 || + cb == 0) + break; + + if (widnames) + PFREE(widnames); + widnames = PMALLOC(cb); +#ifdef DEBUG + assert(widnames); +#endif + + rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG, + KCDB_IDENT_FLAG_CONFIG, + widnames, + &cb, + &cfg_idents.n_idents); + n_tries++; + } while(KHM_FAILED(rv) && + n_tries < 5); + + if (KHM_FAILED(rv) || + cfg_idents.n_idents == 0) { + cfg_idents.n_idents = 0; + goto _cleanup; + } + + cfg_idents.idents = PMALLOC(sizeof(*cfg_idents.idents) * + cfg_idents.n_idents); +#ifdef DEBUG + assert(cfg_idents.idents); +#endif + ZeroMemory(cfg_idents.idents, + sizeof(*cfg_idents.idents) * cfg_idents.n_idents); + cfg_idents.nc_idents = cfg_idents.n_idents; + + i = 0; + for (t = widnames; t && *t; t = multi_string_next(t)) { + khm_handle ident; + + if (KHM_FAILED(kcdb_identity_create(t, 0, &ident))) { + cfg_idents.n_idents--; + continue; + } + + StringCbLength(t, KCDB_IDENT_MAXCB_NAME, &cb); + cb += sizeof(wchar_t); + + cfg_idents.idents[i].idname = PMALLOC(cb); +#ifdef DEBUG + assert(cfg_idents.idents[i].idname); +#endif + StringCbCopy(cfg_idents.idents[i].idname, cb, t); + + cfg_idents.idents[i].ident = ident; + cfg_idents.idents[i].removed = FALSE; + + kcdb_identity_get_flags(ident, &cfg_idents.idents[i].flags); +#ifdef DEBUG + assert(cfg_idents.idents[i].flags & KCDB_IDENT_FLAG_CONFIG); +#endif + + read_params_ident(&cfg_idents.idents[i]); + + i++; + /* leave identity held */ + } + + _cleanup: + + cfg_idents.valid = TRUE; + + if (widnames) + PFREE(widnames); +} + +static void +free_idents_data(void) { + int i; + + if (!cfg_idents.valid) + return; + + for (i=0; i< (int) cfg_idents.n_idents; i++) { + if (cfg_idents.idents[i].ident) + kcdb_identity_release(cfg_idents.idents[i].ident); + if (cfg_idents.idents[i].idname) + PFREE(cfg_idents.idents[i].idname); + } + + if (cfg_idents.idents) + PFREE(cfg_idents.idents); + + cfg_idents.idents = NULL; + cfg_idents.n_idents = 0; + cfg_idents.nc_idents = 0; + cfg_idents.valid = FALSE; +} + +static void +hold_idents_data(void) { + if (!cfg_idents.valid) + init_idents_data(); +#ifdef DEBUG + assert(cfg_idents.valid); +#endif + cfg_idents.refcount++; +} + +static void +release_idents_data(void) { +#ifdef DEBUG + assert(cfg_idents.valid); +#endif + cfg_idents.refcount--; + + if (cfg_idents.refcount == 0) + free_idents_data(); +} + + +static void +refresh_data_idents(HWND hwnd) { + cfg_idents.work.monitor = + (IsDlgButtonChecked(hwnd, IDC_CFG_MONITOR) == BST_CHECKED); + cfg_idents.work.auto_renew = + (IsDlgButtonChecked(hwnd, IDC_CFG_RENEW) == BST_CHECKED); + cfg_idents.work.sticky = + (IsDlgButtonChecked(hwnd, IDC_CFG_STICKY) == BST_CHECKED); +} + +static void +refresh_view_idents_state(HWND hwnd) { + BOOL modified; + BOOL applied; + khm_int32 flags = 0; + + applied = cfg_idents.applied; + modified = (cfg_idents.work.monitor != cfg_idents.saved.monitor || + cfg_idents.work.auto_renew != cfg_idents.saved.auto_renew || + cfg_idents.work.sticky != cfg_idents.saved.sticky); + + if (modified) + flags |= KHUI_CNFLAG_MODIFIED; + if (applied) + flags |= KHUI_CNFLAG_APPLIED; + + khui_cfg_set_flags_inst(&cfg_idents.cfg, flags, + KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); +} + +struct ctrl_row_dimensions { + RECT enclosure; + RECT label; + RECT control; +}; + +typedef struct tag_add_ident_data { + khui_new_creds * nc; + + struct ctrl_row_dimensions dim_small; + struct ctrl_row_dimensions dim_medium; + struct ctrl_row_dimensions dim_large; + int row_gap; + + int current_y; + int current_x; + + HWND hwnd_last_ctrl; +} add_ident_data; + +void +get_ctrl_row_metrics(struct ctrl_row_dimensions * dim, HWND hw_lbl, HWND hw_ctl) { + + assert(hw_lbl); + assert(hw_ctl); + + GetWindowRect(hw_lbl, &dim->label); + GetWindowRect(hw_ctl, &dim->control); + + UnionRect(&dim->enclosure, &dim->label, &dim->control); + OffsetRect(&dim->label, + -dim->enclosure.left, + -dim->enclosure.top); + OffsetRect(&dim->control, + -dim->enclosure.left, + -dim->enclosure.top); + OffsetRect(&dim->enclosure, + -dim->enclosure.left, + -dim->enclosure.top); +} + +/* dialog box procedure for the "Add new identity" dialog */ +INT_PTR CALLBACK +khm_cfg_add_ident_proc(HWND hwnd, + UINT umsg, + WPARAM wParam, + LPARAM lParam) { + add_ident_data * d; + + switch(umsg) { + case WM_INITDIALOG: + /* we create a new credentials blob and pull in the identity + selectors from the identity provider. */ + d = PMALLOC(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + + khui_cw_create_cred_blob(&d->nc); +#ifdef DEBUG + assert(d->nc != NULL); +#endif + if (d->nc == NULL) { + PFREE(d); + break; + } + + if (KHM_FAILED(kcdb_identpro_get_ui_cb(&d->nc->ident_cb))) { + /* this should have worked. The only reason it would fail + is if there is no identity provider or if the identity + provider does not support providing idnetity + selectors. */ + khui_cw_destroy_cred_blob(d->nc); + PFREE(d); + break; + } + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + /* get metrics for dynamic controls */ + get_ctrl_row_metrics(&d->dim_small, + GetDlgItem(hwnd, IDC_SM_LBL), + GetDlgItem(hwnd, IDC_SM_CTL)); + get_ctrl_row_metrics(&d->dim_medium, + GetDlgItem(hwnd, IDC_MED_LBL), + GetDlgItem(hwnd, IDC_MED_CTL)); + get_ctrl_row_metrics(&d->dim_large, + GetDlgItem(hwnd, IDC_LG_LBL), + GetDlgItem(hwnd, IDC_LG_CTL)); + + { + RECT rlbl; + RECT rctl; + RECT rwnd; + + GetWindowRect(GetDlgItem(hwnd, IDC_SM_LBL), + &rlbl); + GetWindowRect(GetDlgItem(hwnd, IDC_SM_CTL), + &rctl); + GetWindowRect(hwnd, &rwnd); + + OffsetRect(&rlbl, -rwnd.left, -rwnd.top); + OffsetRect(&rctl, -rwnd.left, -rwnd.top); + + d->current_x = rlbl.left; + d->current_y = rctl.top - GetSystemMetrics(SM_CYCAPTION); + + GetWindowRect(GetDlgItem(hwnd, IDC_MED_CTL), + &rlbl); + OffsetRect(&rlbl, -rwnd.left, -rwnd.top); + + d->row_gap = rlbl.top - rctl.bottom; + } + + d->nc->hwnd = hwnd; + + /* now call the UI callback and make it create the + controls. */ + d->nc->ident_cb(d->nc, WMNC_IDENT_INIT, NULL, 0, 0, + (LPARAM) hwnd); + + break; + + case WM_DESTROY: + d = (add_ident_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + if (d == NULL) + break; + + d->nc->ident_cb(d->nc, WMNC_IDENT_EXIT, NULL, 0, 0, 0); + + khui_cw_destroy_cred_blob(d->nc); + PFREE(d); + break; + + case KHUI_WM_NC_NOTIFY: + d = (add_ident_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + switch(HIWORD(wParam)) { + case WMNC_ADD_CONTROL_ROW: + { + khui_control_row * row; + RECT r_lbl, r_inp, r_enc; + struct ctrl_row_dimensions * dim; + HFONT hf; + + row = (khui_control_row *) lParam; + +#ifdef DEBUG + assert(row->label); + assert(row->input); + assert(d); +#endif + + if (row->size == KHUI_CTRLSIZE_SMALL) { + dim = &d->dim_small; + } else if (row->size == KHUI_CTRLSIZE_HALF) { + dim = &d->dim_medium; + } else { + dim = &d->dim_large; +#ifdef DEBUG + assert(row->size == KHUI_CTRLSIZE_FULL); +#endif + } + + CopyRect(&r_enc, &dim->enclosure); + CopyRect(&r_lbl, &dim->label); + CopyRect(&r_inp, &dim->control); + + OffsetRect(&r_enc, d->current_x, d->current_y); + OffsetRect(&r_lbl, r_enc.left, r_enc.top); + OffsetRect(&r_inp, r_enc.left, r_enc.top); + + d->current_y += r_enc.bottom - r_enc.top; + + hf = (HFONT) SendDlgItemMessage(hwnd, IDOK, WM_GETFONT, 0, 0); + + if (row->label) { + SetWindowPos(row->label, + ((d->hwnd_last_ctrl != NULL)? + d->hwnd_last_ctrl : + HWND_TOP), + r_lbl.left, r_lbl.top, + r_lbl.right - r_lbl.left, + r_lbl.bottom - r_lbl.top, + SWP_DEFERERASE | SWP_NOACTIVATE | + SWP_NOOWNERZORDER); + if (hf) + SendMessage(row->label, WM_SETFONT, + (WPARAM) hf, + TRUE); + d->hwnd_last_ctrl = row->label; + } + + if (row->input) { + SetWindowPos(row->input, + ((d->hwnd_last_ctrl != NULL)? + d->hwnd_last_ctrl : + HWND_TOP), + r_inp.left, r_inp.top, + r_inp.right - r_inp.left, + r_inp.bottom - r_inp.top, + SWP_DEFERERASE | SWP_NOACTIVATE | + SWP_NOOWNERZORDER); + if (hf) + SendMessage(row->input, WM_SETFONT, + (WPARAM) hf, + TRUE); + d->hwnd_last_ctrl = row->input; + } + } + break; + + case WMNC_IDENTITY_CHANGE: + break; + } + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) { + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t err_msg[1024]; + khm_handle ident = NULL; + khm_handle csp_ident = NULL; + khm_size cb; + khm_int32 rv = KHM_ERROR_SUCCESS; + + d = (add_ident_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (!d || !d->nc) + break; + + /* check if there was an identity selected */ + if (d->nc->n_identities == 0 || + d->nc->identities[0] == NULL) { + + StringCbCopy(idname, sizeof(idname), L""); + + LoadString(khm_hInstance, IDS_CFG_IDNAME_NON, + err_msg, ARRAYLENGTH(err_msg)); + + goto show_failure; + } + + ident = d->nc->identities[0]; + kcdb_identity_hold(ident); + + cb = sizeof(idname); + kcdb_identity_get_name(ident, idname, &cb); + + /* now we have to create the identity configuration. */ + if (KHM_FAILED(rv = kcdb_identity_get_config(ident, + KHM_FLAG_CREATE, + &csp_ident))) { + wchar_t fmt[256]; + + LoadString(khm_hInstance, IDS_CFG_IDNAME_CCC, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(err_msg, sizeof(err_msg), fmt, rv); + + kcdb_identity_release(ident); + + goto show_failure; + } + + /* create a value so that the configuration space will + actually be created in the registry. We don't want + this new identity to be sticky. */ + khc_write_int32(csp_ident, L"Sticky", 0); + + khm_refresh_config(); + + kcdb_identity_release(ident); + khc_close_space(csp_ident); + + EndDialog(hwnd, 0); + break; + + show_failure: + { + wchar_t title[512]; + wchar_t fmt[256]; + + if (!err_msg[0]) + break; + + LoadString(khm_hInstance, IDS_CFG_IDNAME_PRB, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(title, sizeof(title), fmt, idname); + + MessageBox(hwnd, err_msg, title, MB_OK | MB_ICONSTOP); + + /* don't end the dialog yet */ + break; + } + break; + + } else if (LOWORD(wParam) == IDCANCEL) { + EndDialog(hwnd, 1); + } else { + d = (add_ident_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (d && d->nc && d->nc->ident_cb) { + return d->nc->ident_cb(d->nc, WMNC_IDENT_WMSG, + hwnd, umsg, wParam, lParam); + } + } + break; + } + + return FALSE; +} + +/* dialog procedure for the "general" pane of the "identities" + configuration node. */ +INT_PTR CALLBACK +khm_cfg_ids_tab_proc(HWND hwnd, + UINT umsg, + WPARAM wParam, + LPARAM lParam) { + + switch(umsg) { + case WM_INITDIALOG: + { + HICON hicon; + + hold_idents_data(); + + cfg_idents.hwnd = hwnd; + cfg_idents.cfg = *((khui_config_init_data *) lParam); + + /* add the status icons */ + if (cfg_idents.hi_status) + goto _done_with_icons; + + cfg_idents.hi_status = + ImageList_Create(GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + ILC_COLOR8 | ILC_MASK, + 4,4); + + hicon = + LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_ID), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + cfg_idents.idx_id = ImageList_AddIcon(cfg_idents.hi_status, + hicon); + + DestroyIcon(hicon); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_DEFAULT), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + cfg_idents.idx_default = ImageList_AddIcon(cfg_idents.hi_status, + hicon) + 1; + + DestroyIcon(hicon); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_MODIFIED), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + cfg_idents.idx_modified = ImageList_AddIcon(cfg_idents.hi_status, + hicon) + 1; + + DestroyIcon(hicon); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_APPLIED), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + cfg_idents.idx_applied = ImageList_AddIcon(cfg_idents.hi_status, + hicon) + 1; + + DestroyIcon(hicon); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_DELETED), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + cfg_idents.idx_deleted = ImageList_AddIcon(cfg_idents.hi_status, + hicon) + 1; + + DestroyIcon(hicon); + + _done_with_icons: + + CheckDlgButton(hwnd, IDC_CFG_MONITOR, + (cfg_idents.work.monitor)?BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwnd, IDC_CFG_RENEW, + (cfg_idents.work.auto_renew)?BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwnd, IDC_CFG_STICKY, + (cfg_idents.work.sticky)?BST_CHECKED:BST_UNCHECKED); + + } + return FALSE; + + case WM_COMMAND: + + if (HIWORD(wParam) == BN_CLICKED) { + UINT ctrl = LOWORD(wParam); + + switch(ctrl) { + case IDC_CFG_MONITOR: + case IDC_CFG_RENEW: + case IDC_CFG_STICKY: + refresh_data_idents(hwnd); + break; + + case IDC_CFG_ADDIDENT: + DialogBoxParam(khm_hInstance, + MAKEINTRESOURCE(IDD_CFG_ADDIDENT), + hwnd, + khm_cfg_add_ident_proc, + (LPARAM) hwnd); + break; + } + + refresh_view_idents_state(hwnd); + } + + khm_set_dialog_result(hwnd, 0); + return TRUE; + + case KHUI_WM_CFG_NOTIFY: + { + switch(HIWORD(wParam)) { + case WMCFG_APPLY: + write_params_idents(); + break; + + case WMCFG_UPDATE_STATE: + refresh_view_idents_state(hwnd); + break; + } + } + return TRUE; + + case WM_DESTROY: + cfg_idents.hwnd = NULL; + + if (cfg_idents.hi_status != NULL) { + ImageList_Destroy(cfg_idents.hi_status); + cfg_idents.hi_status = NULL; + } + release_idents_data(); + + khm_set_dialog_result(hwnd, 0); + + return TRUE; + } + + return FALSE; +} + +/* dialog procedure for the "Identities" configuration node */ +INT_PTR CALLBACK +khm_cfg_identities_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + HWND hw; + switch(uMsg) { + case WM_INITDIALOG: + set_window_node(hwnd, (khui_config_node) lParam); + add_subpanels(hwnd, (khui_config_node) lParam, + (khui_config_node) lParam); + hw = GetDlgItem(hwnd, IDC_CFG_TAB); + show_tab_panel(hwnd, + (khui_config_node) lParam, + hw, + TabCtrl_GetCurSel(hw), + TRUE); + return FALSE; + + case WM_DESTROY: + return 0; + + case KHUI_WM_CFG_NOTIFY: + return handle_cfg_notify(hwnd, wParam, lParam); + + case WM_NOTIFY: + return handle_notify(hwnd, wParam, lParam); + } + + return FALSE; +} + +static ident_data * +find_ident_by_node(khui_config_node node) { + khm_size cb; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + int i; + khm_handle ident = NULL; + + cb = sizeof(idname); + khui_cfg_get_name(node, idname, &cb); + + for (i=0; i < (int)cfg_idents.n_idents; i++) { + if (!wcscmp(cfg_idents.idents[i].idname, idname)) + break; + } + + if (i < (int)cfg_idents.n_idents) + return &cfg_idents.idents[i]; + + /* there is no identity data for this configuration node. We try + to create it. */ + if (KHM_FAILED(kcdb_identity_create(idname, 0, &ident))) + return NULL; + + if (cfg_idents.n_idents >= cfg_idents.nc_idents) { + cfg_idents.nc_idents = UBOUNDSS(cfg_idents.n_idents + 1, + IDENTS_DATA_ALLOC_INCR, + IDENTS_DATA_ALLOC_INCR); +#ifdef DEBUG + assert(cfg_idents.nc_idents > cfg_idents.n_idents); +#endif + cfg_idents.idents = PREALLOC(cfg_idents.idents, + sizeof(*cfg_idents.idents) * + cfg_idents.nc_idents); +#ifdef DEBUG + assert(cfg_idents.idents); +#endif + ZeroMemory(&(cfg_idents.idents[cfg_idents.n_idents]), + sizeof(*cfg_idents.idents) * + (cfg_idents.nc_idents - cfg_idents.n_idents)); + } + + i = (int) cfg_idents.n_idents; + + StringCbLength(idname, KCDB_IDENT_MAXCB_NAME, &cb); + cb += sizeof(wchar_t); + + cfg_idents.idents[i].idname = PMALLOC(cb); +#ifdef DEBUG + assert(cfg_idents.idents[i].idname); +#endif + StringCbCopy(cfg_idents.idents[i].idname, cb, idname); + + cfg_idents.idents[i].ident = ident; + cfg_idents.idents[i].removed = FALSE; + + kcdb_identity_get_flags(ident, &cfg_idents.idents[i].flags); +#ifdef DEBUG + assert(cfg_idents.idents[i].flags & KCDB_IDENT_FLAG_CONFIG); +#endif + + read_params_ident(&cfg_idents.idents[i]); + + cfg_idents.n_idents++; + + /* leave ident held. */ + + return &cfg_idents.idents[i]; +} + +static void +refresh_view_ident(HWND hwnd, khui_config_node node) { + ident_data * d; + + d = find_ident_by_node(node); +#ifdef DEBUG + assert(d); +#endif + + CheckDlgButton(hwnd, IDC_CFG_MONITOR, + (d->work.monitor? BST_CHECKED: BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_RENEW, + (d->work.auto_renew? BST_CHECKED: BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_STICKY, + (d->work.sticky? BST_CHECKED: BST_UNCHECKED)); +} + +static void +mark_remove_ident(HWND hwnd, khui_config_init_data * idata) { + ident_data * d; + + d = find_ident_by_node(idata->ctx_node); +#ifdef DEBUG + assert(d); +#endif + + if (d->removed) + return; + + d->removed = TRUE; + + khui_cfg_set_flags_inst(idata, KHUI_CNFLAG_MODIFIED, + KHUI_CNFLAG_MODIFIED); + + EnableWindow(GetDlgItem(hwnd, IDC_CFG_REMOVE), FALSE); +} + +static void +refresh_data_ident(HWND hwnd, khui_config_init_data * idata) { + ident_data * d; + + d = find_ident_by_node(idata->ctx_node); +#ifdef DEBUG + assert(d); +#endif + + if (IsDlgButtonChecked(hwnd, IDC_CFG_MONITOR) == BST_CHECKED) + d->work.monitor = TRUE; + else + d->work.monitor = FALSE; + + if (IsDlgButtonChecked(hwnd, IDC_CFG_RENEW) == BST_CHECKED) + d->work.auto_renew = TRUE; + else + d->work.auto_renew = FALSE; + + if (IsDlgButtonChecked(hwnd, IDC_CFG_STICKY) == BST_CHECKED) + d->work.sticky = TRUE; + else + d->work.sticky = FALSE; + + if (d->work.monitor != d->saved.monitor || + d->work.auto_renew != d->saved.auto_renew || + d->work.sticky != d->saved.sticky) { + + khui_cfg_set_flags_inst(idata, KHUI_CNFLAG_MODIFIED, + KHUI_CNFLAG_MODIFIED); + + } else { + khui_cfg_set_flags_inst(idata, 0, + KHUI_CNFLAG_MODIFIED); + } +} + +/* dialog procedure for the "general" pane of individual identity + configuration nodes. */ +INT_PTR CALLBACK +khm_cfg_id_tab_proc(HWND hwnd, + UINT umsg, + WPARAM wParam, + LPARAM lParam) { + + khui_config_init_data * idata; + + switch(umsg) { + case WM_INITDIALOG: + { + ident_data * d; + + hold_idents_data(); + + idata = (khui_config_init_data *) lParam; + + khui_cfg_init_dialog_data(hwnd, idata, 0, NULL, NULL); + + refresh_view_ident(hwnd, idata->ctx_node); + + d = find_ident_by_node(idata->ctx_node); + if (d) + d->hwnd = hwnd; +#ifdef DEBUG + else + assert(FALSE); +#endif + } + return FALSE; + + case WM_COMMAND: + khui_cfg_get_dialog_data(hwnd, &idata, NULL); + + if (HIWORD(wParam) == BN_CLICKED) { + switch(LOWORD(wParam)) { + case IDC_CFG_MONITOR: + case IDC_CFG_RENEW: + case IDC_CFG_STICKY: + + refresh_data_ident(hwnd, idata); + if (cfg_idents.hwnd) + PostMessage(cfg_idents.hwnd, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(1, WMCFG_UPDATE_STATE), 0); + break; + + case IDC_CFG_REMOVE: + mark_remove_ident(hwnd, idata); + if (cfg_idents.hwnd) + PostMessage(cfg_idents.hwnd, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(1, WMCFG_UPDATE_STATE), 0); + break; + } + } + + khm_set_dialog_result(hwnd, 0); + return TRUE; + + case WM_DESTROY: + { + ident_data * d; + + khui_cfg_get_dialog_data(hwnd, &idata, NULL); + + d = find_ident_by_node(idata->ctx_node); + if (d) + d->hwnd = NULL; + + release_idents_data(); + khui_cfg_free_dialog_data(hwnd); + khm_set_dialog_result(hwnd, 0); + } + return TRUE; + + case KHUI_WM_CFG_NOTIFY: + { + ident_data * d; + BOOL * cont; + + khui_cfg_get_dialog_data(hwnd, &idata, NULL); + + switch (HIWORD(wParam)) { + case WMCFG_APPLY: + cont = (BOOL *) lParam; + d = find_ident_by_node(idata->ctx_node); + write_params_ident(d); + if (d->removed && cont) + *cont = FALSE; + khui_cfg_set_flags_inst(idata, KHUI_CNFLAG_APPLIED, + KHUI_CNFLAG_APPLIED | + KHUI_CNFLAG_MODIFIED); + break; + + case WMCFG_UPDATE_STATE: + refresh_view_ident(hwnd, idata->ctx_node); + refresh_data_ident(hwnd, idata); + break; + } + } + return TRUE; + } + + return FALSE; +} + +/* dialog procedure for individual identity configuration nodes */ +INT_PTR CALLBACK +khm_cfg_identity_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + HWND hw; + + switch(uMsg) { + case WM_INITDIALOG: + { + khui_config_node refnode = NULL; + + set_window_node(hwnd, (khui_config_node) lParam); + + khui_cfg_open(NULL, L"KhmIdentities", &refnode); +#ifdef DEBUG + assert(refnode != NULL); +#endif + add_subpanels(hwnd, + (khui_config_node) lParam, + refnode); + + hw = GetDlgItem(hwnd, IDC_CFG_TAB); + + show_tab_panel(hwnd, + (khui_config_node) lParam, + hw, + TabCtrl_GetCurSel(hw), + TRUE); + + khui_cfg_release(refnode); + } + return FALSE; + + case WM_DESTROY: + return 0; + + case KHUI_WM_CFG_NOTIFY: + return handle_cfg_notify(hwnd, wParam, lParam); + + case WM_NOTIFY: + return handle_notify(hwnd, wParam, lParam); + } + return FALSE; +} diff --git a/src/windows/identity/ui/cfg_notif_wnd.c b/src/windows/identity/ui/cfg_notif_wnd.c index ac5f93028..91650adb8 100644 --- a/src/windows/identity/ui/cfg_notif_wnd.c +++ b/src/windows/identity/ui/cfg_notif_wnd.c @@ -1,341 +1,341 @@ -/* - * 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 - -typedef struct tag_notif_data { - khui_config_node node; - - BOOL modified; - - BOOL monitor; - BOOL renew; - BOOL halflife; - BOOL warn1; - BOOL warn2; - - khui_tracker tc_renew; - khui_tracker tc_warn1; - khui_tracker tc_warn2; -} notif_data; - -static void -read_params(notif_data * d) { - khm_handle csp_cw; - khm_int32 rv; - khm_int32 t; - - rv = khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, &csp_cw); - assert(KHM_SUCCEEDED(rv)); - - rv = khc_read_int32(csp_cw, L"Monitor", &t); - assert(KHM_SUCCEEDED(rv)); - d->monitor = !!t; - - rv = khc_read_int32(csp_cw, L"AllowAutoRenew", &t); - 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; - - rv = khc_read_int32(csp_cw, L"AllowCritical", &t); - assert(KHM_SUCCEEDED(rv)); - d->warn2 = !!t; - - rv = khc_read_int32(csp_cw, L"AutoRenewThreshold", &t); - assert(KHM_SUCCEEDED(rv)); - d->tc_renew.current = t; - - rv = khc_read_int32(csp_cw, L"WarnThreshold", &t); - assert(KHM_SUCCEEDED(rv)); - d->tc_warn1.current = t; - - rv = khc_read_int32(csp_cw, L"CriticalThreshold", &t); - assert(KHM_SUCCEEDED(rv)); - d->tc_warn2.current = t; - - rv = khc_read_int32(csp_cw, L"MaxThreshold", &t); - assert(KHM_SUCCEEDED(rv)); - d->tc_renew.max = t; - d->tc_warn1.max = t; - d->tc_warn2.max = t; - - rv = khc_read_int32(csp_cw, L"MinThreshold", &t); - assert(KHM_SUCCEEDED(rv)); - d->tc_renew.min = t; - d->tc_warn1.min = t; - d->tc_warn2.min = t; - - khc_close_space(csp_cw); - - d->modified = FALSE; -} - -static void -check_for_modification(notif_data * d) { - notif_data t; - - ZeroMemory(&t, sizeof(t)); - - read_params(&t); - - 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 || - d->tc_warn1.current != t.tc_warn1.current || - d->tc_warn2.current != t.tc_warn2.current) { - - khui_cfg_set_flags(d->node, - KHUI_CNFLAG_MODIFIED, - KHUI_CNFLAG_MODIFIED); - - d->modified = TRUE; - - } else { - khui_cfg_set_flags(d->node, - 0, - KHUI_CNFLAG_MODIFIED); - - d->modified = FALSE; - } -} - -static void -write_params(notif_data * d) { - khm_handle csp_cw; - khm_int32 rv; - - if (!d->modified) - return; - - rv = khc_open_space(NULL, L"CredWindow", KHM_PERM_WRITE, &csp_cw); - assert(KHM_SUCCEEDED(rv)); - - rv = khc_write_int32(csp_cw, L"Monitor", d->monitor); - assert(KHM_SUCCEEDED(rv)); - - 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)); - - rv = khc_write_int32(csp_cw, L"AllowCritical", d->warn2); - assert(KHM_SUCCEEDED(rv)); - - - rv = khc_write_int32(csp_cw, L"AutoRenewThreshold", - (khm_int32) d->tc_renew.current); - assert(KHM_SUCCEEDED(rv)); - - rv = khc_write_int32(csp_cw, L"WarnThreshold", - (khm_int32) d->tc_warn1.current); - assert(KHM_SUCCEEDED(rv)); - - rv = khc_write_int32(csp_cw, L"CriticalThreshold", - (khm_int32) d->tc_warn2.current); - assert(KHM_SUCCEEDED(rv)); - - khc_close_space(csp_cw); - - khui_cfg_set_flags(d->node, - KHUI_CNFLAG_APPLIED, - KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); - - khm_timer_refresh(hwnd_notifier); -} - -static void -refresh_view(HWND hwnd, notif_data * d) { - CheckDlgButton(hwnd, IDC_NOTIF_MONITOR, - (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, - (d->warn2?BST_CHECKED:BST_UNCHECKED)); - khui_tracker_refresh(&d->tc_renew); - khui_tracker_refresh(&d->tc_warn1); - 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); - EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN1_THR), FALSE); - 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)); - EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN1_THR), !!(d->warn1)); - EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN2_THR), !!(d->warn2)); - } -} - -static void -refresh_data(HWND hwnd, notif_data * d) { - d->monitor = (IsDlgButtonChecked(hwnd, IDC_NOTIF_MONITOR) - == 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) - == BST_CHECKED); - - check_for_modification(d); -} - -INT_PTR CALLBACK -khm_cfg_notifications_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - - notif_data * d; - - switch(uMsg) { - case WM_INITDIALOG: { - HWND hw; - - d = PMALLOC(sizeof(*d)); -#ifdef DEBUG - assert(d != NULL); -#endif - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); -#pragma warning(pop) - - ZeroMemory(d, sizeof(*d)); - - d->node = (khui_config_node) lParam; - - khui_tracker_initialize(&d->tc_renew); - khui_tracker_initialize(&d->tc_warn1); - khui_tracker_initialize(&d->tc_warn2); - - read_params(d); - - hw = GetDlgItem(hwnd, IDC_NOTIF_RENEW_THR); - khui_tracker_install(hw, &d->tc_renew); - - hw = GetDlgItem(hwnd, IDC_NOTIF_WARN1_THR); - khui_tracker_install(hw, &d->tc_warn1); - - hw = GetDlgItem(hwnd, IDC_NOTIF_WARN2_THR); - khui_tracker_install(hw, &d->tc_warn2); - - refresh_view(hwnd, d); - - /* normally we should return TRUE, but in this case we return - FALSE since we don't want to inadvertently steal the focus - from the treeview. */ - return FALSE; - } - - case WM_COMMAND: { - d = (notif_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); - - if (HIWORD(wParam) == BN_CLICKED) { - refresh_data(hwnd, d); - refresh_view(hwnd, d); - - check_for_modification(d); - } else if (HIWORD(wParam) == EN_CHANGE) { - SetTimer(hwnd, 1, 500, NULL); - } - - khm_set_dialog_result(hwnd, 0); - - return TRUE; - } - - case WM_TIMER: { - d = (notif_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); - KillTimer(hwnd, 1); - check_for_modification(d); - - khm_set_dialog_result(hwnd, 0); - - return TRUE; - } - - case WM_DESTROY: { - d = (notif_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); - - khui_tracker_kill_controls(&d->tc_renew); - khui_tracker_kill_controls(&d->tc_warn1); - khui_tracker_kill_controls(&d->tc_warn2); - - PFREE(d); - - SetWindowLongPtr(hwnd, DWLP_USER, 0); - - khm_set_dialog_result(hwnd, 0); - - return TRUE; - } - - case KHUI_WM_CFG_NOTIFY: { - d = (notif_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); - - if (HIWORD(wParam) == WMCFG_APPLY) { - write_params(d); - } - - khm_set_dialog_result(hwnd, 0); - - return TRUE; - } - - } - - return FALSE; -} +/* + * 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 + +typedef struct tag_notif_data { + khui_config_node node; + + BOOL modified; + + BOOL monitor; + BOOL renew; + BOOL halflife; + BOOL warn1; + BOOL warn2; + + khui_tracker tc_renew; + khui_tracker tc_warn1; + khui_tracker tc_warn2; +} notif_data; + +static void +read_params(notif_data * d) { + khm_handle csp_cw; + khm_int32 rv; + khm_int32 t; + + rv = khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, &csp_cw); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_read_int32(csp_cw, L"Monitor", &t); + assert(KHM_SUCCEEDED(rv)); + d->monitor = !!t; + + rv = khc_read_int32(csp_cw, L"AllowAutoRenew", &t); + 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; + + rv = khc_read_int32(csp_cw, L"AllowCritical", &t); + assert(KHM_SUCCEEDED(rv)); + d->warn2 = !!t; + + rv = khc_read_int32(csp_cw, L"AutoRenewThreshold", &t); + assert(KHM_SUCCEEDED(rv)); + d->tc_renew.current = t; + + rv = khc_read_int32(csp_cw, L"WarnThreshold", &t); + assert(KHM_SUCCEEDED(rv)); + d->tc_warn1.current = t; + + rv = khc_read_int32(csp_cw, L"CriticalThreshold", &t); + assert(KHM_SUCCEEDED(rv)); + d->tc_warn2.current = t; + + rv = khc_read_int32(csp_cw, L"MaxThreshold", &t); + assert(KHM_SUCCEEDED(rv)); + d->tc_renew.max = t; + d->tc_warn1.max = t; + d->tc_warn2.max = t; + + rv = khc_read_int32(csp_cw, L"MinThreshold", &t); + assert(KHM_SUCCEEDED(rv)); + d->tc_renew.min = t; + d->tc_warn1.min = t; + d->tc_warn2.min = t; + + khc_close_space(csp_cw); + + d->modified = FALSE; +} + +static void +check_for_modification(notif_data * d) { + notif_data t; + + ZeroMemory(&t, sizeof(t)); + + read_params(&t); + + 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 || + d->tc_warn1.current != t.tc_warn1.current || + d->tc_warn2.current != t.tc_warn2.current) { + + khui_cfg_set_flags(d->node, + KHUI_CNFLAG_MODIFIED, + KHUI_CNFLAG_MODIFIED); + + d->modified = TRUE; + + } else { + khui_cfg_set_flags(d->node, + 0, + KHUI_CNFLAG_MODIFIED); + + d->modified = FALSE; + } +} + +static void +write_params(notif_data * d) { + khm_handle csp_cw; + khm_int32 rv; + + if (!d->modified) + return; + + rv = khc_open_space(NULL, L"CredWindow", KHM_PERM_WRITE, &csp_cw); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_write_int32(csp_cw, L"Monitor", d->monitor); + assert(KHM_SUCCEEDED(rv)); + + 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)); + + rv = khc_write_int32(csp_cw, L"AllowCritical", d->warn2); + assert(KHM_SUCCEEDED(rv)); + + + rv = khc_write_int32(csp_cw, L"AutoRenewThreshold", + (khm_int32) d->tc_renew.current); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_write_int32(csp_cw, L"WarnThreshold", + (khm_int32) d->tc_warn1.current); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_write_int32(csp_cw, L"CriticalThreshold", + (khm_int32) d->tc_warn2.current); + assert(KHM_SUCCEEDED(rv)); + + khc_close_space(csp_cw); + + khui_cfg_set_flags(d->node, + KHUI_CNFLAG_APPLIED, + KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); + + khm_timer_refresh(hwnd_notifier); +} + +static void +refresh_view(HWND hwnd, notif_data * d) { + CheckDlgButton(hwnd, IDC_NOTIF_MONITOR, + (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, + (d->warn2?BST_CHECKED:BST_UNCHECKED)); + khui_tracker_refresh(&d->tc_renew); + khui_tracker_refresh(&d->tc_warn1); + 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); + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN1_THR), FALSE); + 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)); + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN1_THR), !!(d->warn1)); + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN2_THR), !!(d->warn2)); + } +} + +static void +refresh_data(HWND hwnd, notif_data * d) { + d->monitor = (IsDlgButtonChecked(hwnd, IDC_NOTIF_MONITOR) + == 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) + == BST_CHECKED); + + check_for_modification(d); +} + +INT_PTR CALLBACK +khm_cfg_notifications_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + notif_data * d; + + switch(uMsg) { + case WM_INITDIALOG: { + HWND hw; + + d = PMALLOC(sizeof(*d)); +#ifdef DEBUG + assert(d != NULL); +#endif + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + ZeroMemory(d, sizeof(*d)); + + d->node = (khui_config_node) lParam; + + khui_tracker_initialize(&d->tc_renew); + khui_tracker_initialize(&d->tc_warn1); + khui_tracker_initialize(&d->tc_warn2); + + read_params(d); + + hw = GetDlgItem(hwnd, IDC_NOTIF_RENEW_THR); + khui_tracker_install(hw, &d->tc_renew); + + hw = GetDlgItem(hwnd, IDC_NOTIF_WARN1_THR); + khui_tracker_install(hw, &d->tc_warn1); + + hw = GetDlgItem(hwnd, IDC_NOTIF_WARN2_THR); + khui_tracker_install(hw, &d->tc_warn2); + + refresh_view(hwnd, d); + + /* normally we should return TRUE, but in this case we return + FALSE since we don't want to inadvertently steal the focus + from the treeview. */ + return FALSE; + } + + case WM_COMMAND: { + d = (notif_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == BN_CLICKED) { + refresh_data(hwnd, d); + refresh_view(hwnd, d); + + check_for_modification(d); + } else if (HIWORD(wParam) == EN_CHANGE) { + SetTimer(hwnd, 1, 500, NULL); + } + + khm_set_dialog_result(hwnd, 0); + + return TRUE; + } + + case WM_TIMER: { + d = (notif_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + KillTimer(hwnd, 1); + check_for_modification(d); + + khm_set_dialog_result(hwnd, 0); + + return TRUE; + } + + case WM_DESTROY: { + d = (notif_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + khui_tracker_kill_controls(&d->tc_renew); + khui_tracker_kill_controls(&d->tc_warn1); + khui_tracker_kill_controls(&d->tc_warn2); + + PFREE(d); + + SetWindowLongPtr(hwnd, DWLP_USER, 0); + + khm_set_dialog_result(hwnd, 0); + + return TRUE; + } + + case KHUI_WM_CFG_NOTIFY: { + d = (notif_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == WMCFG_APPLY) { + write_params(d); + } + + khm_set_dialog_result(hwnd, 0); + + return TRUE; + } + + } + + return FALSE; +} diff --git a/src/windows/identity/ui/cfg_plugins_wnd.c b/src/windows/identity/ui/cfg_plugins_wnd.c index cab71c4ea..6290d3703 100644 --- a/src/windows/identity/ui/cfg_plugins_wnd.c +++ b/src/windows/identity/ui/cfg_plugins_wnd.c @@ -1,646 +1,646 @@ -/* - * 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 - -#define MAX_PLUGINS 256 - -typedef struct tag_plugin_data { - kmm_plugin_info plugin; - kmm_module_info module; -} 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, - WPARAM wParam, - LPARAM lParam) { - - plugin_dlg_data * d; - - switch(uMsg) { - case WM_INITDIALOG: - { - kmm_plugin p; - kmm_plugin pn; - kmm_module m; - khm_size i; - LVCOLUMN lvc; - RECT r; - HWND hw; - wchar_t buf[256]; - HIMAGELIST h_ilist; - HICON h_icon; - - d = PMALLOC(sizeof(*d)); -#ifdef DEBUG - assert(d); -#endif - ZeroMemory(d, sizeof(*d)); -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); -#pragma warning(pop) - - p = NULL; - i = 0; - do { - if (KHM_FAILED(kmm_get_next_plugin(p, &pn))) - break; - - if (p) - kmm_release_plugin(p); - p = pn; - -#ifdef DEBUG - assert(d->info[i] == NULL); -#endif - d->info[i] = PMALLOC(sizeof(*(d->info[i]))); -#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]); - d->info[i] = NULL; - break; - } - - ZeroMemory(&d->info[i]->module, - sizeof(d->info[i]->module)); - - if (KHM_SUCCEEDED(kmm_load_module(d->info[i]->plugin.reg.module, - KMM_LM_FLAG_NOLOAD, - &m))) { - kmm_get_module_info_i(m, &d->info[i]->module); - kmm_release_module(m); - } - - i ++; - - if (i == MAX_PLUGINS) - break; - } while(p); - - if (p) - kmm_release_plugin(p); - - d->n_info = i; - - /* now populate the list view */ - hw = GetDlgItem(hwnd, IDC_CFG_PLUGINS); -#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; - GetWindowRect(hw, &r); - lvc.cx = ((r.right - r.left) * 95) / 100; - lvc.pszText = buf; - - LoadString(khm_hInstance, IDS_CFG_PI_COL_PLUGINS, - buf, ARRAYLENGTH(buf)); - - ListView_InsertColumn(hw, 0, &lvc); - - for(i=0; in_info; i++) { - LVITEM lvi; - - ZeroMemory(&lvi, sizeof(lvi)); - - 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; - - case WM_NOTIFY: - { - LPNMHDR lpnm; - HWND hw; - - d = (plugin_dlg_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - if (wParam == IDC_CFG_PLUGINS && - (lpnm = (LPNMHDR) lParam) && - lpnm->code == LVN_ITEMCHANGED) { - - LVITEM lvi; - - hw = GetDlgItem(hwnd, IDC_CFG_PLUGINS); -#ifdef DEBUG - assert(hw); -#endif - if (ListView_GetSelectedCount(hw) != 1) { - SetDlgItemText(hwnd, IDC_CFG_DESC, L""); - 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; - - idx = ListView_GetNextItem(hw, -1, LVNI_SELECTED); -#ifdef DEBUG - assert(idx != -1); -#endif - ZeroMemory(&lvi, sizeof(lvi)); - lvi.iItem = idx; - lvi.iSubItem = 0; - lvi.mask = LVIF_PARAM; - - ListView_GetItem(hw, &lvi); -#ifdef DEBUG - assert(lvi.lParam != 0); -#endif - info = (plugin_data *) lvi.lParam; - - update_dialog_fields(hwnd, d, info); - } - } - } - return TRUE; - - case WM_COMMAND: - { - - d = (plugin_dlg_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - 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; - - khui_alert_create_empty(&alert); - - 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); - - 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); - - khui_alert_set_severity(alert, KHERR_INFO); - - khui_alert_show_modal(alert); - - kmm_enable_plugin(d->selected->plugin.h_plugin, TRUE); - - 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_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; - - 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 - break; - } - - khui_alert_create_empty(&alert); - - LoadString(khm_hInstance, IDS_CFG_P_UNRCNFT, - 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_UNRCNFM, - fmt, ARRAYLENGTH(fmt)); - StringCbPrintf(buf, sizeof(buf), fmt, - d->selected->plugin.reg.name); - - khui_alert_set_message(alert, buf); - - 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); - } - } - -#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; - - case WM_DESTROY: - { - khm_size i; - - d = (plugin_dlg_data *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); -#ifdef DEBUG - assert(d); -#endif - for (i=0; in_info; i++) { -#ifdef DEBUG - assert(d->info[i]); -#endif - kmm_release_plugin_info_i(&d->info[i]->plugin); - kmm_release_module_info_i(&d->info[i]->module); - PFREE(d->info[i]); - } - - PFREE(d); - - khm_set_dialog_result(hwnd, 0); - } - return TRUE; - } - return FALSE; -} +/* + * 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 + +#define MAX_PLUGINS 256 + +typedef struct tag_plugin_data { + kmm_plugin_info plugin; + kmm_module_info module; +} 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, + WPARAM wParam, + LPARAM lParam) { + + plugin_dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + { + kmm_plugin p; + kmm_plugin pn; + kmm_module m; + khm_size i; + LVCOLUMN lvc; + RECT r; + HWND hw; + wchar_t buf[256]; + HIMAGELIST h_ilist; + HICON h_icon; + + d = PMALLOC(sizeof(*d)); +#ifdef DEBUG + assert(d); +#endif + ZeroMemory(d, sizeof(*d)); +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + p = NULL; + i = 0; + do { + if (KHM_FAILED(kmm_get_next_plugin(p, &pn))) + break; + + if (p) + kmm_release_plugin(p); + p = pn; + +#ifdef DEBUG + assert(d->info[i] == NULL); +#endif + d->info[i] = PMALLOC(sizeof(*(d->info[i]))); +#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]); + d->info[i] = NULL; + break; + } + + ZeroMemory(&d->info[i]->module, + sizeof(d->info[i]->module)); + + if (KHM_SUCCEEDED(kmm_load_module(d->info[i]->plugin.reg.module, + KMM_LM_FLAG_NOLOAD, + &m))) { + kmm_get_module_info_i(m, &d->info[i]->module); + kmm_release_module(m); + } + + i ++; + + if (i == MAX_PLUGINS) + break; + } while(p); + + if (p) + kmm_release_plugin(p); + + d->n_info = i; + + /* now populate the list view */ + hw = GetDlgItem(hwnd, IDC_CFG_PLUGINS); +#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; + GetWindowRect(hw, &r); + lvc.cx = ((r.right - r.left) * 95) / 100; + lvc.pszText = buf; + + LoadString(khm_hInstance, IDS_CFG_PI_COL_PLUGINS, + buf, ARRAYLENGTH(buf)); + + ListView_InsertColumn(hw, 0, &lvc); + + for(i=0; in_info; i++) { + LVITEM lvi; + + ZeroMemory(&lvi, sizeof(lvi)); + + 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; + + case WM_NOTIFY: + { + LPNMHDR lpnm; + HWND hw; + + d = (plugin_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (wParam == IDC_CFG_PLUGINS && + (lpnm = (LPNMHDR) lParam) && + lpnm->code == LVN_ITEMCHANGED) { + + LVITEM lvi; + + hw = GetDlgItem(hwnd, IDC_CFG_PLUGINS); +#ifdef DEBUG + assert(hw); +#endif + if (ListView_GetSelectedCount(hw) != 1) { + SetDlgItemText(hwnd, IDC_CFG_DESC, L""); + 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; + + idx = ListView_GetNextItem(hw, -1, LVNI_SELECTED); +#ifdef DEBUG + assert(idx != -1); +#endif + ZeroMemory(&lvi, sizeof(lvi)); + lvi.iItem = idx; + lvi.iSubItem = 0; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hw, &lvi); +#ifdef DEBUG + assert(lvi.lParam != 0); +#endif + info = (plugin_data *) lvi.lParam; + + update_dialog_fields(hwnd, d, info); + } + } + } + return TRUE; + + case WM_COMMAND: + { + + d = (plugin_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + 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; + + khui_alert_create_empty(&alert); + + 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); + + 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); + + khui_alert_set_severity(alert, KHERR_INFO); + + khui_alert_show_modal(alert); + + kmm_enable_plugin(d->selected->plugin.h_plugin, TRUE); + + 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_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; + + 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 + break; + } + + khui_alert_create_empty(&alert); + + LoadString(khm_hInstance, IDS_CFG_P_UNRCNFT, + 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_UNRCNFM, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, + d->selected->plugin.reg.name); + + khui_alert_set_message(alert, buf); + + 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); + } + } + +#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; + + case WM_DESTROY: + { + khm_size i; + + d = (plugin_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); +#ifdef DEBUG + assert(d); +#endif + for (i=0; in_info; i++) { +#ifdef DEBUG + assert(d->info[i]); +#endif + kmm_release_plugin_info_i(&d->info[i]->plugin); + kmm_release_module_info_i(&d->info[i]->module); + PFREE(d->info[i]); + } + + PFREE(d); + + khm_set_dialog_result(hwnd, 0); + } + return TRUE; + } + return FALSE; +} diff --git a/src/windows/identity/ui/configwnd.c b/src/windows/identity/ui/configwnd.c index 03eec9ad5..49ebfe48e 100644 --- a/src/windows/identity/ui/configwnd.c +++ b/src/windows/identity/ui/configwnd.c @@ -1,1219 +1,1219 @@ -/* - * 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 - -static HWND cfgui_hwnd = NULL; - -typedef struct tag_cfgui_wnd_data { - khui_config_node current; - HWND hw_current; - HWND hw_generic_pane; - HBRUSH hbr_white; - HFONT hf_title; - khui_bitmap kbmp_logo; - HIMAGELIST hi_status; - BOOL modified; - int idx_default; - int idx_modified; - int idx_applied; -} cfgui_wnd_data; - -static cfgui_wnd_data * -cfgui_get_wnd_data(HWND hwnd) { - return (cfgui_wnd_data *)(LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); -} - -static void -cfgui_set_wnd_data(HWND hwnd, cfgui_wnd_data * d) { -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); -#pragma warning(pop) -} - -static void -cfgui_add_node(cfgui_wnd_data * d, - HWND hwtv, - khui_config_node node, - khui_config_node parent, - BOOL sorted) { - - khui_config_node_reg reg; - khui_config_node c; - wchar_t wbuf[256]; - const wchar_t * short_desc; - TVINSERTSTRUCT s; - HTREEITEM hItem; - - if (node) { - khui_cfg_get_reg(node, ®); - short_desc = reg.short_desc; - } else { - short_desc = wbuf; - LoadString(khm_hInstance, IDS_CFG_ROOT_NAME, - wbuf, ARRAYLENGTH(wbuf)); - reg.flags = 0; - } - - ZeroMemory(&s, sizeof(s)); - - s.hParent = (node)? - (HTREEITEM) khui_cfg_get_param(parent): - TVI_ROOT; - - s.hInsertAfter = (sorted)? TVI_SORT: TVI_FIRST; - - s.itemex.mask = - TVIF_CHILDREN | - TVIF_PARAM | - TVIF_TEXT | - TVIF_STATE; - - { - khui_config_node n; - - if (KHM_SUCCEEDED(khui_cfg_get_first_child(node, - &n))) { - s.itemex.cChildren = 1; - s.itemex.state = TVIS_EXPANDED; - s.itemex.stateMask = TVIS_EXPANDED; - khui_cfg_release(n); - } else { - s.itemex.cChildren = 0; - s.itemex.state = 0; - s.itemex.stateMask = TVIS_EXPANDED; - } - - s.itemex.state |= INDEXTOSTATEIMAGEMASK(d->idx_default); - s.itemex.stateMask |= TVIS_STATEIMAGEMASK; - } - - s.itemex.lParam = (LPARAM) node; - khui_cfg_hold(node); - - s.itemex.pszText = (LPWSTR) short_desc; - - hItem = TreeView_InsertItem(hwtv, &s); - - khui_cfg_set_param(node, (LPARAM) hItem); - - if (KHM_SUCCEEDED(khui_cfg_get_first_child(node, - &c))) { - do { - cfgui_add_node(d, hwtv, c, node, - !!(reg.flags & KHUI_CNFLAG_SORT_CHILDREN)); - } while (KHM_SUCCEEDED(khui_cfg_get_next_release(&c))); - } -} - -static void -cfgui_initialize_dialog(HWND hwnd) { - cfgui_wnd_data * d; - HWND hwtv; - HWND hwtitle; - HFONT hf; - HDC hdc; - HICON hicon; - - d = cfgui_get_wnd_data(hwnd); - - /* create and fill the image list for the treeview */ - - d->hi_status = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), - ILC_COLOR8 | ILC_MASK, - 4,4); - - hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_DEFAULT), - IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); - - /* note that we can't use index 0 because that is used to indicate - that there is no state image for the node */ - do { - d->idx_default = ImageList_AddIcon(d->hi_status, hicon); - } while(d->idx_default == 0); - - DestroyIcon(hicon); - - hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_MODIFIED), - IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); - - d->idx_modified = ImageList_AddIcon(d->hi_status, hicon); - - DestroyIcon(hicon); - - hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_APPLIED), - IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); - - d->idx_applied = ImageList_AddIcon(d->hi_status, hicon); - - DestroyIcon(hicon); - - /* now for the treeview */ - hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST); - - TreeView_SetImageList(hwtv, d->hi_status, TVSIL_STATE); - - cfgui_add_node(d, hwtv, NULL, NULL, FALSE); - - hdc = GetDC(hwnd); - hf = CreateFont(-MulDiv(12, - GetDeviceCaps(hdc, LOGPIXELSY), - 72), - 0, /* nWidth */ - 0, /* nEscapement */ - 0, /* nOrientation */ - FW_BOLD, /* fnWeight */ - TRUE, /* fdwItalic */ - FALSE, /* fdwUnderline */ - FALSE, /* fdwStrikeOut */ - DEFAULT_CHARSET, /* fdwCharSet */ - OUT_DEFAULT_PRECIS, /* fdwOutputPrecision */ - CLIP_DEFAULT_PRECIS, /* fdwClipPrecision */ - DEFAULT_QUALITY, /* fdwQuality */ - FF_SWISS | DEFAULT_PITCH, /* pitch&family */ - NULL); /* face */ - ReleaseDC(hwnd, hdc); - - d->hf_title = hf; - - hwtitle = GetDlgItem(hwnd, IDC_CFG_TITLE); - - SendMessage(hwtitle, - WM_SETFONT, - (WPARAM) hf, - (LPARAM) FALSE); -} - -static void -cfgui_free_node(HWND hwtv, HTREEITEM hItem) { - TVITEMEX iex; - HTREEITEM hChItem; - - ZeroMemory(&iex, sizeof(iex)); - - iex.mask = TVIF_PARAM; - iex.hItem = hItem; - - if (TreeView_GetItem(hwtv, &iex)) { - khui_config_node node; - - node = (khui_config_node) iex.lParam; - khui_cfg_release(node); - } - - hChItem = TreeView_GetChild(hwtv, hItem); - while(hChItem) { - cfgui_free_node(hwtv, hChItem); - - hChItem = TreeView_GetNextSibling(hwtv, hChItem); - } -} - -static void -cfgui_uninitialize_dialog(HWND hwnd) { - cfgui_wnd_data * d; - HWND hwtv; - - d = cfgui_get_wnd_data(hwnd); - - hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST); - - cfgui_free_node(hwtv, TreeView_GetRoot(hwtv)); - - if (d->hf_title) - DeleteObject(d->hf_title); - - if (d->hi_status) - ImageList_Destroy(d->hi_status); -} - -static HWND -cfgui_create_config_node_window(HWND hwnd, khui_config_node node) { - khui_config_node_reg reg; - khm_int32 rv; - HWND hw_new; - - khui_config_node parent; - - if (KHM_SUCCEEDED(khui_cfg_get_parent(node, &parent))) { - HWND hwp; - - hwp = khui_cfg_get_hwnd(parent); - - if (hwp == NULL) - cfgui_create_config_node_window(hwnd, parent); - - khui_cfg_release(parent); - } - - rv = khui_cfg_get_reg(node, ®); -#ifdef DEBUG - assert(KHM_SUCCEEDED(rv)); -#endif - hw_new = CreateDialogParam(reg.h_module, - reg.dlg_template, - hwnd, - reg.dlg_proc, - (LPARAM) node); -#ifdef DEBUG - assert(hw_new); -#endif - khui_cfg_set_hwnd(node, hw_new); - - return hw_new; -} - -static void -cfgui_activate_node(HWND hwnd, khui_config_node node) { - - cfgui_wnd_data * d; - HTREEITEM hItem; - HWND hw_new; - HWND hwtv; - - d = cfgui_get_wnd_data(hwnd); - hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST); - hItem = (HTREEITEM) khui_cfg_get_param(node); - -#ifdef DEBUG - assert(hItem); - assert(hwtv); -#endif - - if (node == NULL) { - hw_new = d->hw_generic_pane; - } else { - - hw_new = khui_cfg_get_hwnd(node); - - if (hw_new == NULL) { - hw_new = cfgui_create_config_node_window(hwnd, node); - } - } - - if (hw_new == d->hw_current) - return; /* nothing to do */ - - { - RECT r_title; - RECT r_pane; - HWND hw; - - if (d->hw_current) - ShowWindow(d->hw_current, SW_HIDE); - - hw = GetDlgItem(hwnd, IDC_CFG_TITLE); -#ifdef DEBUG - assert(hw); -#endif - GetWindowRect(hw, &r_title); - - hw = GetDlgItem(hwnd, IDC_CFG_PANE); -#ifdef DEBUG - assert(hw); -#endif - GetWindowRect(hw, &r_pane); - - OffsetRect(&r_pane, -r_title.left, -r_title.top); - - SetWindowPos(hw_new, - hwtv, - r_pane.left, r_pane.top, - r_pane.right - r_pane.left, - r_pane.bottom - r_pane.top, - SWP_NOOWNERZORDER | - SWP_SHOWWINDOW | - SWP_NOACTIVATE); - } - - if (node == NULL) { - wchar_t wbuf[256]; - - LoadString(khm_hInstance, IDS_CFG_ROOT_TITLE, - wbuf, ARRAYLENGTH(wbuf)); - - SetDlgItemText(hwnd, IDC_CFG_TITLE, wbuf); - } else { - khm_int32 rv; - khui_config_node_reg reg; - - rv = khui_cfg_get_reg(node, ®); -#ifdef DEBUG - assert(KHM_SUCCEEDED(rv)); -#endif - SetDlgItemText(hwnd, IDC_CFG_TITLE, reg.long_desc); - } - - d->hw_current = hw_new; - d->current = node; - - TreeView_SelectItem(hwtv, hItem); -} - -static BOOL -cfgui_check_mod_state(khui_config_node node) { - khm_int32 flags; - khui_config_node c = NULL; - BOOL rv = FALSE; - - flags = khui_cfg_get_flags(node); - - if (flags & KHUI_CNFLAG_MODIFIED) - return TRUE; - - if (KHM_FAILED(khui_cfg_get_first_child(node, &c))) - return FALSE; - - while(c) { - rv = (rv || cfgui_check_mod_state(c)); - khui_cfg_get_next_release(&c); - } - - return rv; -} - -static void -cfgui_apply_settings(khui_config_node node) { - HWND hwnd; - khui_config_node c; - khm_int32 flags; - - hwnd = khui_cfg_get_hwnd(node); - flags = khui_cfg_get_flags(node); - - if (hwnd && (flags & KHUI_CNFLAG_MODIFIED)) { - SendMessage(hwnd, KHUI_WM_CFG_NOTIFY, - MAKEWPARAM(0, WMCFG_APPLY), - (LPARAM) node); - } - - if (KHM_FAILED(khui_cfg_get_first_child(node, &c))) - return; - - while (c) { - cfgui_apply_settings(c); - khui_cfg_get_next_release(&c); - } -} - -static void -cfgui_remove_item(HWND hwtv, - HTREEITEM hItem) { - khui_config_node node; - HTREEITEM hChild; - TVITEMEX itemex; - - for (hChild = TreeView_GetChild(hwtv, hItem); - hChild; - hChild = TreeView_GetChild(hwtv, hItem)) { - - cfgui_remove_item(hwtv, hChild); - - } - - ZeroMemory(&itemex, sizeof(itemex)); - - itemex.mask = TVIF_PARAM; - itemex.hItem = hItem; - - TreeView_GetChild(hwtv, &itemex); - - node = (khui_config_node) itemex.lParam; - - if (node) { - HWND hw; - hw = khui_cfg_get_hwnd(node); - - if (hw) - DestroyWindow(hw); - - khui_cfg_release(node); - } - - TreeView_DeleteItem(hwtv, hItem); -} - -struct cfgui_child_info { - HTREEITEM hItem; - khui_config_node node; - BOOL checked; -}; - -#define CI_ALLOC_INCR 8 - -static void -cfgui_sync_node(cfgui_wnd_data * d, - HWND hwtv, - khui_config_node c, - HTREEITEM hItem) { - khui_config_node child; - HTREEITEM hChild; - struct cfgui_child_info * childinfo = NULL; - khm_size n_childinfo = 0; - khm_size nc_childinfo = 0; - khm_size i; - - /* first, get the list of children from the treeview control */ - for (hChild = TreeView_GetChild(hwtv, hItem); - hChild; - hChild = TreeView_GetNextSibling(hwtv, hChild)) { - - if (n_childinfo >= nc_childinfo) { - nc_childinfo = UBOUNDSS(n_childinfo + 1, - CI_ALLOC_INCR, CI_ALLOC_INCR); -#ifdef DEBUG - assert(nc_childinfo > n_childinfo); -#endif - childinfo = PREALLOC(childinfo, - sizeof(*childinfo) * nc_childinfo); -#ifdef DEBUG - assert(childinfo); -#endif - } - - ZeroMemory(&childinfo[n_childinfo], - sizeof(childinfo[n_childinfo])); - - childinfo[n_childinfo].hItem = hChild; - childinfo[n_childinfo].checked = FALSE; - n_childinfo++; - } - - /* now, go through the list of actual nodes and make sure they - match up */ - child = NULL; - for (khui_cfg_get_first_child(c, &child); - child; - khui_cfg_get_next_release(&child)) { - - hChild = (HTREEITEM) khui_cfg_get_param(child); - - for (i=0; i < n_childinfo; i++) { - if (childinfo[i].hItem == hChild) - break; - } - - if (i < n_childinfo) { - childinfo[i].checked = TRUE; - } else { - /* add it to the list, so we can create the node in the - tree view control later. */ - if (n_childinfo >= nc_childinfo) { - nc_childinfo = UBOUNDSS(n_childinfo + 1, - CI_ALLOC_INCR, CI_ALLOC_INCR); -#ifdef DEBUG - assert(nc_childinfo > n_childinfo); -#endif - childinfo = PREALLOC(childinfo, - sizeof(*childinfo) * nc_childinfo); -#ifdef DEBUG - assert(childinfo); -#endif - } - - ZeroMemory(&childinfo[n_childinfo], - sizeof(childinfo[n_childinfo])); - - childinfo[n_childinfo].node = child; - khui_cfg_hold(child); - n_childinfo++; - } - } - - /* by this point, the childinfo list contains items of the - following forms: - - 1. childinfo[i].hItem != NULL && childinfo[i].checked == TRUE - - Corresponds to a tree view item that has a matching - configuration node. Nothing to do here. - - 2. childinfo[i].hItem != NULL && childinfo[i].checked == FALSE - - Corresponds to a tree view item that has no matching - configuration node. These should be removed. - - 3. childinfo[i].hItem == NULL && childinfo[i].node != NULL - - Corresponds to a configuration node that has no matching - tree view item. These nodes should be added. - */ - - /* first do the removals */ - for (i=0; i < n_childinfo; i++) { - if (childinfo[i].hItem == NULL) - break; /* nothing more to see from this point - on */ - if (!childinfo[i].checked) { - /* remove! */ - cfgui_remove_item(hwtv, childinfo[i].hItem); - } - } - - /* continue from where the previous loop left off */ - for (; i < n_childinfo; i++) { -#ifdef DEBUG - assert(childinfo[i].hItem == NULL); - assert(childinfo[i].node != NULL); -#endif - - cfgui_add_node(d, hwtv, childinfo[i].node, c, FALSE); - - khui_cfg_release(childinfo[i].node); - childinfo[i].node = NULL; - } - - if (childinfo) - PFREE(childinfo); - - /* finally recurse through to the next level */ - for (hChild = TreeView_GetChild(hwtv, hItem); - hChild; - hChild = TreeView_GetNextSibling(hwtv, hChild)) { - - TVITEMEX itemex; - - ZeroMemory(&itemex, sizeof(itemex)); - - itemex.mask = TVIF_PARAM; - itemex.hItem = hChild; - - TreeView_GetItem(hwtv, &itemex); - - if (itemex.lParam) { - child = (khui_config_node) itemex.lParam; - - cfgui_sync_node(d, hwtv, child, hChild); - } - } -} - -static void -cfgui_sync_node_list(cfgui_wnd_data * d, HWND hwnd) { - HWND hwtv; - HTREEITEM hItem; - - hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST); - hItem = TreeView_GetRoot(hwtv); - - cfgui_sync_node(d, hwtv, NULL, hItem); -} - -static void -cfgui_update_state(HWND hwnd, - khm_int32 flags, - khui_config_node node) { - cfgui_wnd_data * d; - HWND hwtv; - HTREEITEM hItem; - TVITEMEX itx; - int idx; - - d = cfgui_get_wnd_data(hwnd); - hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST); - hItem = (HTREEITEM) khui_cfg_get_param(node); - - ZeroMemory(&itx, sizeof(itx)); - - if (flags & KHUI_CNFLAG_MODIFIED) - idx = d->idx_modified; - else if (flags & KHUI_CNFLAG_APPLIED) - idx = d->idx_applied; - else - idx = d->idx_default; - - itx.hItem = hItem; - itx.mask = TVIF_STATE; - itx.state = INDEXTOSTATEIMAGEMASK(idx); - itx.stateMask = TVIS_STATEIMAGEMASK; - - TreeView_SetItem(hwtv, &itx); - - if(cfgui_check_mod_state(NULL)) { - EnableWindow(GetDlgItem(hwnd, IDAPPLY), TRUE); - } else { - EnableWindow(GetDlgItem(hwnd, IDAPPLY), FALSE); - } -} - - -/* dialog procedure for the generic dialog */ -static INT_PTR CALLBACK -cfgui_dlgproc_generic(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - cfgui_wnd_data * d; - - switch(uMsg) { - case WM_INITDIALOG: - d = (cfgui_wnd_data *) lParam; - cfgui_set_wnd_data(hwnd, d); - return TRUE; - - case WM_CTLCOLORSTATIC: - d = cfgui_get_wnd_data(hwnd); - return (BOOL)(DWORD_PTR) d->hbr_white; - - case WM_ERASEBKGND: - { - HDC hdc = (HDC) wParam; - RECT r_client; - RECT r_logo; - RECT r_fill; - - d = cfgui_get_wnd_data(hwnd); - - GetClientRect(hwnd, &r_client); - SetRectEmpty(&r_logo); - - r_logo.right = d->kbmp_logo.cx; - r_logo.bottom = d->kbmp_logo.cy; - - OffsetRect(&r_logo, - r_client.right - r_logo.right, - r_client.bottom - r_logo.bottom); - - khui_draw_bitmap(hdc, - r_logo.left, - r_logo.top, - &d->kbmp_logo); - - r_fill.left = 0; - r_fill.top = 0; - r_fill.right = r_logo.left; - r_fill.bottom = r_client.bottom; - FillRect(hdc, &r_fill, d->hbr_white); - - r_fill.left = r_logo.left; - r_fill.right = r_client.right; - r_fill.bottom = r_logo.top; - FillRect(hdc, &r_fill, d->hbr_white); - - SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LONG) TRUE); - } - return TRUE; - } - - return FALSE; -} - -static INT_PTR CALLBACK -cfgui_dlgproc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - - khui_config_node node; - cfgui_wnd_data * d; - - switch(uMsg) { - case WM_INITDIALOG: - node = (khui_config_node) lParam; - - khui_cfg_clear_params(); - - khui_cfg_set_configui_handle(hwnd); - - d = PMALLOC(sizeof(*d)); - ZeroMemory(d, sizeof(*d)); - - d->hbr_white = CreateSolidBrush(RGB(255,255,255)); - - d->hw_generic_pane = - CreateDialogParam(khm_hInstance, - MAKEINTRESOURCE(IDD_CFG_GENERIC), - hwnd, - cfgui_dlgproc_generic, - (LPARAM) d); - - khui_bitmap_from_hbmp(&d->kbmp_logo, - LoadImage( - khm_hInstance, - MAKEINTRESOURCE(IDB_LOGO_OPAQUE), - IMAGE_BITMAP, - 0, - 0, - LR_DEFAULTCOLOR)); - - cfgui_set_wnd_data(hwnd, d); - - cfgui_initialize_dialog(hwnd); - - cfgui_activate_node(hwnd, node); - - khm_add_dialog(hwnd); - khm_enter_modal(hwnd); - - return TRUE; - - case WM_DESTROY: - cfgui_hwnd = NULL; - - khui_cfg_set_configui_handle(NULL); - - cfgui_uninitialize_dialog(hwnd); - - d = cfgui_get_wnd_data(hwnd); - khui_delete_bitmap(&d->kbmp_logo); - DeleteObject(d->hbr_white); - - cfgui_set_wnd_data(hwnd, NULL); - - khm_del_dialog(hwnd); - - SetForegroundWindow(khm_hwnd_main); - - PFREE(d); - - return FALSE; - - case WM_NOTIFY: - { - LPNMHDR lpnm; - LPNMTREEVIEW lptv; - LPNMTVGETINFOTIP lpgi; - khui_config_node node; - - lpnm = (LPNMHDR) lParam; - - switch (lpnm->code) { - case TVN_SELCHANGED: - lptv = (LPNMTREEVIEW) lParam; - cfgui_activate_node(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; - - case WM_CTLCOLORSTATIC: - { - d = cfgui_get_wnd_data(hwnd); - return (BOOL)(DWORD_PTR) d->hbr_white; - } - /* implicit break */ - - case WM_COMMAND: - switch(wParam) { - case MAKEWPARAM(IDCANCEL, BN_CLICKED): - khm_leave_modal(); - DestroyWindow(hwnd); - break; - - case MAKEWPARAM(IDAPPLY, BN_CLICKED): - cfgui_apply_settings(NULL); - break; - - case MAKEWPARAM(IDOK, BN_CLICKED): - cfgui_apply_settings(NULL); - khm_leave_modal(); - DestroyWindow(hwnd); - break; - } - return TRUE; - - case KHUI_WM_CFG_NOTIFY: - switch(HIWORD(wParam)) { - case WMCFG_SHOW_NODE: - cfgui_activate_node(hwnd, (khui_config_node) lParam); - break; - - case WMCFG_UPDATE_STATE: - cfgui_update_state(hwnd, LOWORD(wParam), - (khui_config_node) lParam); - break; - - case WMCFG_SYNC_NODE_LIST: - d = cfgui_get_wnd_data(hwnd); - cfgui_sync_node_list(d, hwnd); - break; - } - - return TRUE; - } - - return FALSE; -} - -static void -cfgui_create_window(khui_config_node node) { -#ifdef DEBUG - assert(cfgui_hwnd == NULL); -#endif - - khm_refresh_config(); - - cfgui_hwnd = CreateDialogParam(khm_hInstance, - MAKEINTRESOURCE(IDD_CFG_MAIN), - khm_hwnd_main, - cfgui_dlgproc, - (LPARAM) node); -#ifdef DEBUG - assert(cfgui_hwnd != NULL); -#endif - ShowWindow(cfgui_hwnd,SW_SHOW); -} - -static void -cfgui_destroy_window(void) { - if (cfgui_hwnd) - DestroyWindow(cfgui_hwnd); - /* cfgui_hwnd will be set to NULL in the dialog proc */ -} - -void -khm_show_config_pane(khui_config_node node) { - if (cfgui_hwnd != NULL) { - SendMessage(cfgui_hwnd, KHUI_WM_CFG_NOTIFY, - MAKEWPARAM(0, WMCFG_SHOW_NODE), - (LPARAM) node); - } else { - cfgui_create_window(node); - } -} - -void khm_refresh_config(void) { - khm_size cb; - khm_size n_idents; - wchar_t * idents = NULL; - wchar_t * t; - khm_int32 rv; - int n_tries = 0; - khui_config_node cfg_ids = NULL; - khui_config_node cfg_r = NULL; - khui_config_node cfg_iter = NULL; - khui_menu_def * omenu; - khm_boolean refresh_menu = FALSE; - - do { - rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG, - KCDB_IDENT_FLAG_CONFIG, - NULL, - &cb, - &n_idents); - - if (rv != KHM_ERROR_TOO_LONG || - n_idents == 0) - return; - - if (idents) - PFREE(idents); - idents = PMALLOC(cb); -#ifdef DEBUG - assert(idents); -#endif - - rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG, - KCDB_IDENT_FLAG_CONFIG, - idents, - &cb, - &n_idents); - - n_tries++; - } while(KHM_FAILED(rv) && - n_tries < 5); - - if (KHM_FAILED(rv)) - goto _cleanup; - - if (KHM_FAILED(khui_cfg_open(NULL, - L"KhmIdentities", - &cfg_ids))) - goto _cleanup; - - for(t = idents; t && *t; t = multi_string_next(t)) { - khui_config_node cfg_id = NULL; - - rv = khui_cfg_open(cfg_ids, - t, - &cfg_id); - - if (KHM_FAILED(rv)) { - khui_config_node_reg reg; - wchar_t wshort[KHUI_MAXCCH_SHORT_DESC]; - wchar_t wlong[KHUI_MAXCCH_LONG_DESC]; - wchar_t wfmt[KHUI_MAXCCH_SHORT_DESC]; - - ZeroMemory(®, sizeof(reg)); - - reg.name = t; - reg.short_desc = wshort; - reg.long_desc = wlong; - reg.h_module = khm_hInstance; - reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDENTITY); - reg.dlg_proc = khm_cfg_identity_proc; - reg.flags = 0; - - LoadString(khm_hInstance, IDS_CFG_IDENTITY_SHORT, - wfmt, ARRAYLENGTH(wfmt)); - StringCbPrintf(wshort, sizeof(wshort), wfmt, t); - - LoadString(khm_hInstance, IDS_CFG_IDENTITY_LONG, - wfmt, ARRAYLENGTH(wfmt)); - StringCbPrintf(wlong, sizeof(wlong), wfmt, t); - - khui_cfg_register(cfg_ids, - ®); - } else { - khui_cfg_release(cfg_id); - } - } - - for (khui_cfg_get_first_child(cfg_ids, &cfg_iter); - cfg_iter; - khui_cfg_get_next_release(&cfg_iter)) { - - wchar_t cfgname[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - khm_handle tident = NULL; - khm_int32 tflags = 0; - - cb = sizeof(cfgname); - khui_cfg_get_name(cfg_iter, cfgname, &cb); - - if (KHM_FAILED(kcdb_identity_create(cfgname, 0, &tident)) || - KHM_FAILED(kcdb_identity_get_flags(tident, &tflags)) || - !(tflags & KCDB_IDENT_FLAG_ACTIVE) || - !(tflags & KCDB_IDENT_FLAG_CONFIG)) { - - /* this configuration node needs to be removed */ - - khui_cfg_remove(cfg_iter); - } - - if (tident) - kcdb_identity_release(tident); - } - - /* 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; - - khui_action_lock(); - - 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); - - khui_action_unlock(); - - if (refresh_menu) { - khui_refresh_actions(); - } - - _cleanup: - if (cfg_ids) - khui_cfg_release(cfg_ids); - - if (cfg_r) - khui_cfg_release(cfg_r); - - if (idents) - PFREE(idents); -} - -void khm_init_config(void) { - wchar_t wshort[KHUI_MAXCCH_SHORT_DESC]; - wchar_t wlong[KHUI_MAXCCH_LONG_DESC]; - khui_config_node_reg reg; - khui_config_node node; - - reg.short_desc = wshort; - reg.long_desc = wlong; - reg.h_module = khm_hInstance; - reg.flags = KHUI_CNFLAG_SYSTEM; - - reg.name = L"KhmGeneral"; - reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_GENERAL); - reg.dlg_proc = khm_cfg_general_proc; - LoadString(khm_hInstance, IDS_CFG_GENERAL_SHORT, - wshort, ARRAYLENGTH(wshort)); - LoadString(khm_hInstance, IDS_CFG_GENERAL_LONG, - wlong, ARRAYLENGTH(wlong)); - - khui_cfg_register(NULL, ®); - - reg.name = L"KhmAppear"; - reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_APPEAR); - reg.dlg_proc = khm_cfg_appearance_proc; - LoadString(khm_hInstance, IDS_CFG_APPEAR_SHORT, - wshort, ARRAYLENGTH(wshort)); - LoadString(khm_hInstance, IDS_CFG_APPEAR_LONG, - wlong, ARRAYLENGTH(wlong)); - - khui_cfg_register(NULL, ®); - - reg.name = L"KhmIdentities"; - reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDENTITIES); - reg.dlg_proc = khm_cfg_identities_proc; - LoadString(khm_hInstance, IDS_CFG_IDENTITIES_SHORT, - wshort, ARRAYLENGTH(wshort)); - LoadString(khm_hInstance, IDS_CFG_IDENTITIES_LONG, - wlong, ARRAYLENGTH(wlong)); - - khui_cfg_register(NULL, ®); - - node = NULL; - khui_cfg_open(NULL, L"KhmIdentities", &node); -#ifdef DEBUG - assert(node); -#endif - - reg.name = L"KhmIdentitiesTab"; - reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDS_TAB); - reg.dlg_proc = khm_cfg_ids_tab_proc; - LoadString(khm_hInstance, IDS_CFG_IDS_TAB_SHORT, - wshort, ARRAYLENGTH(wshort)); - LoadString(khm_hInstance, IDS_CFG_IDS_TAB_LONG, - wlong, ARRAYLENGTH(wlong)); - reg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_SYSTEM; - - khui_cfg_register(node, ®); - - reg.name = L"KhmIdentitiesTabPlural"; - reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_ID_TAB); - reg.dlg_proc = khm_cfg_id_tab_proc; - LoadString(khm_hInstance, IDS_CFG_ID_TAB_SHORT, - wshort, ARRAYLENGTH(wshort)); - LoadString(khm_hInstance, IDS_CFG_ID_TAB_LONG, - wlong, ARRAYLENGTH(wlong)); - reg.flags = KHUI_CNFLAG_PLURAL | KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_SYSTEM; - - khui_cfg_register(node, ®); - - reg.flags = KHUI_CNFLAG_SYSTEM; - khui_cfg_release(node); - - reg.name = L"KhmNotifications"; - reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_NOTIF); - reg.dlg_proc = khm_cfg_notifications_proc; - LoadString(khm_hInstance, IDS_CFG_NOTIF_SHORT, - wshort, ARRAYLENGTH(wshort)); - LoadString(khm_hInstance, IDS_CFG_NOTIF_LONG, - wlong, ARRAYLENGTH(wlong)); - - khui_cfg_register(NULL, ®); - - reg.name = L"KhmPlugins"; - reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_PLUGINS); - reg.dlg_proc = khm_cfg_plugins_proc; - LoadString(khm_hInstance, IDS_CFG_PLUGINS_SHORT, - wshort, ARRAYLENGTH(wshort)); - LoadString(khm_hInstance, IDS_CFG_PLUGINS_LONG, - wlong, ARRAYLENGTH(wlong)); - - khui_cfg_register(NULL, ®); -} - -void khm_exit_config(void) { -} +/* + * 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 + +static HWND cfgui_hwnd = NULL; + +typedef struct tag_cfgui_wnd_data { + khui_config_node current; + HWND hw_current; + HWND hw_generic_pane; + HBRUSH hbr_white; + HFONT hf_title; + khui_bitmap kbmp_logo; + HIMAGELIST hi_status; + BOOL modified; + int idx_default; + int idx_modified; + int idx_applied; +} cfgui_wnd_data; + +static cfgui_wnd_data * +cfgui_get_wnd_data(HWND hwnd) { + return (cfgui_wnd_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); +} + +static void +cfgui_set_wnd_data(HWND hwnd, cfgui_wnd_data * d) { +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) +} + +static void +cfgui_add_node(cfgui_wnd_data * d, + HWND hwtv, + khui_config_node node, + khui_config_node parent, + BOOL sorted) { + + khui_config_node_reg reg; + khui_config_node c; + wchar_t wbuf[256]; + const wchar_t * short_desc; + TVINSERTSTRUCT s; + HTREEITEM hItem; + + if (node) { + khui_cfg_get_reg(node, ®); + short_desc = reg.short_desc; + } else { + short_desc = wbuf; + LoadString(khm_hInstance, IDS_CFG_ROOT_NAME, + wbuf, ARRAYLENGTH(wbuf)); + reg.flags = 0; + } + + ZeroMemory(&s, sizeof(s)); + + s.hParent = (node)? + (HTREEITEM) khui_cfg_get_param(parent): + TVI_ROOT; + + s.hInsertAfter = (sorted)? TVI_SORT: TVI_FIRST; + + s.itemex.mask = + TVIF_CHILDREN | + TVIF_PARAM | + TVIF_TEXT | + TVIF_STATE; + + { + khui_config_node n; + + if (KHM_SUCCEEDED(khui_cfg_get_first_child(node, + &n))) { + s.itemex.cChildren = 1; + s.itemex.state = TVIS_EXPANDED; + s.itemex.stateMask = TVIS_EXPANDED; + khui_cfg_release(n); + } else { + s.itemex.cChildren = 0; + s.itemex.state = 0; + s.itemex.stateMask = TVIS_EXPANDED; + } + + s.itemex.state |= INDEXTOSTATEIMAGEMASK(d->idx_default); + s.itemex.stateMask |= TVIS_STATEIMAGEMASK; + } + + s.itemex.lParam = (LPARAM) node; + khui_cfg_hold(node); + + s.itemex.pszText = (LPWSTR) short_desc; + + hItem = TreeView_InsertItem(hwtv, &s); + + khui_cfg_set_param(node, (LPARAM) hItem); + + if (KHM_SUCCEEDED(khui_cfg_get_first_child(node, + &c))) { + do { + cfgui_add_node(d, hwtv, c, node, + !!(reg.flags & KHUI_CNFLAG_SORT_CHILDREN)); + } while (KHM_SUCCEEDED(khui_cfg_get_next_release(&c))); + } +} + +static void +cfgui_initialize_dialog(HWND hwnd) { + cfgui_wnd_data * d; + HWND hwtv; + HWND hwtitle; + HFONT hf; + HDC hdc; + HICON hicon; + + d = cfgui_get_wnd_data(hwnd); + + /* create and fill the image list for the treeview */ + + d->hi_status = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), + ILC_COLOR8 | ILC_MASK, + 4,4); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_DEFAULT), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + /* note that we can't use index 0 because that is used to indicate + that there is no state image for the node */ + do { + d->idx_default = ImageList_AddIcon(d->hi_status, hicon); + } while(d->idx_default == 0); + + DestroyIcon(hicon); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_MODIFIED), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + d->idx_modified = ImageList_AddIcon(d->hi_status, hicon); + + DestroyIcon(hicon); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_APPLIED), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + d->idx_applied = ImageList_AddIcon(d->hi_status, hicon); + + DestroyIcon(hicon); + + /* now for the treeview */ + hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST); + + TreeView_SetImageList(hwtv, d->hi_status, TVSIL_STATE); + + cfgui_add_node(d, hwtv, NULL, NULL, FALSE); + + hdc = GetDC(hwnd); + hf = CreateFont(-MulDiv(12, + GetDeviceCaps(hdc, LOGPIXELSY), + 72), + 0, /* nWidth */ + 0, /* nEscapement */ + 0, /* nOrientation */ + FW_BOLD, /* fnWeight */ + TRUE, /* fdwItalic */ + FALSE, /* fdwUnderline */ + FALSE, /* fdwStrikeOut */ + DEFAULT_CHARSET, /* fdwCharSet */ + OUT_DEFAULT_PRECIS, /* fdwOutputPrecision */ + CLIP_DEFAULT_PRECIS, /* fdwClipPrecision */ + DEFAULT_QUALITY, /* fdwQuality */ + FF_SWISS | DEFAULT_PITCH, /* pitch&family */ + NULL); /* face */ + ReleaseDC(hwnd, hdc); + + d->hf_title = hf; + + hwtitle = GetDlgItem(hwnd, IDC_CFG_TITLE); + + SendMessage(hwtitle, + WM_SETFONT, + (WPARAM) hf, + (LPARAM) FALSE); +} + +static void +cfgui_free_node(HWND hwtv, HTREEITEM hItem) { + TVITEMEX iex; + HTREEITEM hChItem; + + ZeroMemory(&iex, sizeof(iex)); + + iex.mask = TVIF_PARAM; + iex.hItem = hItem; + + if (TreeView_GetItem(hwtv, &iex)) { + khui_config_node node; + + node = (khui_config_node) iex.lParam; + khui_cfg_release(node); + } + + hChItem = TreeView_GetChild(hwtv, hItem); + while(hChItem) { + cfgui_free_node(hwtv, hChItem); + + hChItem = TreeView_GetNextSibling(hwtv, hChItem); + } +} + +static void +cfgui_uninitialize_dialog(HWND hwnd) { + cfgui_wnd_data * d; + HWND hwtv; + + d = cfgui_get_wnd_data(hwnd); + + hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST); + + cfgui_free_node(hwtv, TreeView_GetRoot(hwtv)); + + if (d->hf_title) + DeleteObject(d->hf_title); + + if (d->hi_status) + ImageList_Destroy(d->hi_status); +} + +static HWND +cfgui_create_config_node_window(HWND hwnd, khui_config_node node) { + khui_config_node_reg reg; + khm_int32 rv; + HWND hw_new; + + khui_config_node parent; + + if (KHM_SUCCEEDED(khui_cfg_get_parent(node, &parent))) { + HWND hwp; + + hwp = khui_cfg_get_hwnd(parent); + + if (hwp == NULL) + cfgui_create_config_node_window(hwnd, parent); + + khui_cfg_release(parent); + } + + rv = khui_cfg_get_reg(node, ®); +#ifdef DEBUG + assert(KHM_SUCCEEDED(rv)); +#endif + hw_new = CreateDialogParam(reg.h_module, + reg.dlg_template, + hwnd, + reg.dlg_proc, + (LPARAM) node); +#ifdef DEBUG + assert(hw_new); +#endif + khui_cfg_set_hwnd(node, hw_new); + + return hw_new; +} + +static void +cfgui_activate_node(HWND hwnd, khui_config_node node) { + + cfgui_wnd_data * d; + HTREEITEM hItem; + HWND hw_new; + HWND hwtv; + + d = cfgui_get_wnd_data(hwnd); + hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST); + hItem = (HTREEITEM) khui_cfg_get_param(node); + +#ifdef DEBUG + assert(hItem); + assert(hwtv); +#endif + + if (node == NULL) { + hw_new = d->hw_generic_pane; + } else { + + hw_new = khui_cfg_get_hwnd(node); + + if (hw_new == NULL) { + hw_new = cfgui_create_config_node_window(hwnd, node); + } + } + + if (hw_new == d->hw_current) + return; /* nothing to do */ + + { + RECT r_title; + RECT r_pane; + HWND hw; + + if (d->hw_current) + ShowWindow(d->hw_current, SW_HIDE); + + hw = GetDlgItem(hwnd, IDC_CFG_TITLE); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r_title); + + hw = GetDlgItem(hwnd, IDC_CFG_PANE); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r_pane); + + OffsetRect(&r_pane, -r_title.left, -r_title.top); + + SetWindowPos(hw_new, + hwtv, + r_pane.left, r_pane.top, + r_pane.right - r_pane.left, + r_pane.bottom - r_pane.top, + SWP_NOOWNERZORDER | + SWP_SHOWWINDOW | + SWP_NOACTIVATE); + } + + if (node == NULL) { + wchar_t wbuf[256]; + + LoadString(khm_hInstance, IDS_CFG_ROOT_TITLE, + wbuf, ARRAYLENGTH(wbuf)); + + SetDlgItemText(hwnd, IDC_CFG_TITLE, wbuf); + } else { + khm_int32 rv; + khui_config_node_reg reg; + + rv = khui_cfg_get_reg(node, ®); +#ifdef DEBUG + assert(KHM_SUCCEEDED(rv)); +#endif + SetDlgItemText(hwnd, IDC_CFG_TITLE, reg.long_desc); + } + + d->hw_current = hw_new; + d->current = node; + + TreeView_SelectItem(hwtv, hItem); +} + +static BOOL +cfgui_check_mod_state(khui_config_node node) { + khm_int32 flags; + khui_config_node c = NULL; + BOOL rv = FALSE; + + flags = khui_cfg_get_flags(node); + + if (flags & KHUI_CNFLAG_MODIFIED) + return TRUE; + + if (KHM_FAILED(khui_cfg_get_first_child(node, &c))) + return FALSE; + + while(c) { + rv = (rv || cfgui_check_mod_state(c)); + khui_cfg_get_next_release(&c); + } + + return rv; +} + +static void +cfgui_apply_settings(khui_config_node node) { + HWND hwnd; + khui_config_node c; + khm_int32 flags; + + hwnd = khui_cfg_get_hwnd(node); + flags = khui_cfg_get_flags(node); + + if (hwnd && (flags & KHUI_CNFLAG_MODIFIED)) { + SendMessage(hwnd, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(0, WMCFG_APPLY), + (LPARAM) node); + } + + if (KHM_FAILED(khui_cfg_get_first_child(node, &c))) + return; + + while (c) { + cfgui_apply_settings(c); + khui_cfg_get_next_release(&c); + } +} + +static void +cfgui_remove_item(HWND hwtv, + HTREEITEM hItem) { + khui_config_node node; + HTREEITEM hChild; + TVITEMEX itemex; + + for (hChild = TreeView_GetChild(hwtv, hItem); + hChild; + hChild = TreeView_GetChild(hwtv, hItem)) { + + cfgui_remove_item(hwtv, hChild); + + } + + ZeroMemory(&itemex, sizeof(itemex)); + + itemex.mask = TVIF_PARAM; + itemex.hItem = hItem; + + TreeView_GetChild(hwtv, &itemex); + + node = (khui_config_node) itemex.lParam; + + if (node) { + HWND hw; + hw = khui_cfg_get_hwnd(node); + + if (hw) + DestroyWindow(hw); + + khui_cfg_release(node); + } + + TreeView_DeleteItem(hwtv, hItem); +} + +struct cfgui_child_info { + HTREEITEM hItem; + khui_config_node node; + BOOL checked; +}; + +#define CI_ALLOC_INCR 8 + +static void +cfgui_sync_node(cfgui_wnd_data * d, + HWND hwtv, + khui_config_node c, + HTREEITEM hItem) { + khui_config_node child; + HTREEITEM hChild; + struct cfgui_child_info * childinfo = NULL; + khm_size n_childinfo = 0; + khm_size nc_childinfo = 0; + khm_size i; + + /* first, get the list of children from the treeview control */ + for (hChild = TreeView_GetChild(hwtv, hItem); + hChild; + hChild = TreeView_GetNextSibling(hwtv, hChild)) { + + if (n_childinfo >= nc_childinfo) { + nc_childinfo = UBOUNDSS(n_childinfo + 1, + CI_ALLOC_INCR, CI_ALLOC_INCR); +#ifdef DEBUG + assert(nc_childinfo > n_childinfo); +#endif + childinfo = PREALLOC(childinfo, + sizeof(*childinfo) * nc_childinfo); +#ifdef DEBUG + assert(childinfo); +#endif + } + + ZeroMemory(&childinfo[n_childinfo], + sizeof(childinfo[n_childinfo])); + + childinfo[n_childinfo].hItem = hChild; + childinfo[n_childinfo].checked = FALSE; + n_childinfo++; + } + + /* now, go through the list of actual nodes and make sure they + match up */ + child = NULL; + for (khui_cfg_get_first_child(c, &child); + child; + khui_cfg_get_next_release(&child)) { + + hChild = (HTREEITEM) khui_cfg_get_param(child); + + for (i=0; i < n_childinfo; i++) { + if (childinfo[i].hItem == hChild) + break; + } + + if (i < n_childinfo) { + childinfo[i].checked = TRUE; + } else { + /* add it to the list, so we can create the node in the + tree view control later. */ + if (n_childinfo >= nc_childinfo) { + nc_childinfo = UBOUNDSS(n_childinfo + 1, + CI_ALLOC_INCR, CI_ALLOC_INCR); +#ifdef DEBUG + assert(nc_childinfo > n_childinfo); +#endif + childinfo = PREALLOC(childinfo, + sizeof(*childinfo) * nc_childinfo); +#ifdef DEBUG + assert(childinfo); +#endif + } + + ZeroMemory(&childinfo[n_childinfo], + sizeof(childinfo[n_childinfo])); + + childinfo[n_childinfo].node = child; + khui_cfg_hold(child); + n_childinfo++; + } + } + + /* by this point, the childinfo list contains items of the + following forms: + + 1. childinfo[i].hItem != NULL && childinfo[i].checked == TRUE + + Corresponds to a tree view item that has a matching + configuration node. Nothing to do here. + + 2. childinfo[i].hItem != NULL && childinfo[i].checked == FALSE + + Corresponds to a tree view item that has no matching + configuration node. These should be removed. + + 3. childinfo[i].hItem == NULL && childinfo[i].node != NULL + + Corresponds to a configuration node that has no matching + tree view item. These nodes should be added. + */ + + /* first do the removals */ + for (i=0; i < n_childinfo; i++) { + if (childinfo[i].hItem == NULL) + break; /* nothing more to see from this point + on */ + if (!childinfo[i].checked) { + /* remove! */ + cfgui_remove_item(hwtv, childinfo[i].hItem); + } + } + + /* continue from where the previous loop left off */ + for (; i < n_childinfo; i++) { +#ifdef DEBUG + assert(childinfo[i].hItem == NULL); + assert(childinfo[i].node != NULL); +#endif + + cfgui_add_node(d, hwtv, childinfo[i].node, c, FALSE); + + khui_cfg_release(childinfo[i].node); + childinfo[i].node = NULL; + } + + if (childinfo) + PFREE(childinfo); + + /* finally recurse through to the next level */ + for (hChild = TreeView_GetChild(hwtv, hItem); + hChild; + hChild = TreeView_GetNextSibling(hwtv, hChild)) { + + TVITEMEX itemex; + + ZeroMemory(&itemex, sizeof(itemex)); + + itemex.mask = TVIF_PARAM; + itemex.hItem = hChild; + + TreeView_GetItem(hwtv, &itemex); + + if (itemex.lParam) { + child = (khui_config_node) itemex.lParam; + + cfgui_sync_node(d, hwtv, child, hChild); + } + } +} + +static void +cfgui_sync_node_list(cfgui_wnd_data * d, HWND hwnd) { + HWND hwtv; + HTREEITEM hItem; + + hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST); + hItem = TreeView_GetRoot(hwtv); + + cfgui_sync_node(d, hwtv, NULL, hItem); +} + +static void +cfgui_update_state(HWND hwnd, + khm_int32 flags, + khui_config_node node) { + cfgui_wnd_data * d; + HWND hwtv; + HTREEITEM hItem; + TVITEMEX itx; + int idx; + + d = cfgui_get_wnd_data(hwnd); + hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST); + hItem = (HTREEITEM) khui_cfg_get_param(node); + + ZeroMemory(&itx, sizeof(itx)); + + if (flags & KHUI_CNFLAG_MODIFIED) + idx = d->idx_modified; + else if (flags & KHUI_CNFLAG_APPLIED) + idx = d->idx_applied; + else + idx = d->idx_default; + + itx.hItem = hItem; + itx.mask = TVIF_STATE; + itx.state = INDEXTOSTATEIMAGEMASK(idx); + itx.stateMask = TVIS_STATEIMAGEMASK; + + TreeView_SetItem(hwtv, &itx); + + if(cfgui_check_mod_state(NULL)) { + EnableWindow(GetDlgItem(hwnd, IDAPPLY), TRUE); + } else { + EnableWindow(GetDlgItem(hwnd, IDAPPLY), FALSE); + } +} + + +/* dialog procedure for the generic dialog */ +static INT_PTR CALLBACK +cfgui_dlgproc_generic(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + cfgui_wnd_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + d = (cfgui_wnd_data *) lParam; + cfgui_set_wnd_data(hwnd, d); + return TRUE; + + case WM_CTLCOLORSTATIC: + d = cfgui_get_wnd_data(hwnd); + return (BOOL)(DWORD_PTR) d->hbr_white; + + case WM_ERASEBKGND: + { + HDC hdc = (HDC) wParam; + RECT r_client; + RECT r_logo; + RECT r_fill; + + d = cfgui_get_wnd_data(hwnd); + + GetClientRect(hwnd, &r_client); + SetRectEmpty(&r_logo); + + r_logo.right = d->kbmp_logo.cx; + r_logo.bottom = d->kbmp_logo.cy; + + OffsetRect(&r_logo, + r_client.right - r_logo.right, + r_client.bottom - r_logo.bottom); + + khui_draw_bitmap(hdc, + r_logo.left, + r_logo.top, + &d->kbmp_logo); + + r_fill.left = 0; + r_fill.top = 0; + r_fill.right = r_logo.left; + r_fill.bottom = r_client.bottom; + FillRect(hdc, &r_fill, d->hbr_white); + + r_fill.left = r_logo.left; + r_fill.right = r_client.right; + r_fill.bottom = r_logo.top; + FillRect(hdc, &r_fill, d->hbr_white); + + SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LONG) TRUE); + } + return TRUE; + } + + return FALSE; +} + +static INT_PTR CALLBACK +cfgui_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + khui_config_node node; + cfgui_wnd_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + node = (khui_config_node) lParam; + + khui_cfg_clear_params(); + + khui_cfg_set_configui_handle(hwnd); + + d = PMALLOC(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + + d->hbr_white = CreateSolidBrush(RGB(255,255,255)); + + d->hw_generic_pane = + CreateDialogParam(khm_hInstance, + MAKEINTRESOURCE(IDD_CFG_GENERIC), + hwnd, + cfgui_dlgproc_generic, + (LPARAM) d); + + khui_bitmap_from_hbmp(&d->kbmp_logo, + LoadImage( + khm_hInstance, + MAKEINTRESOURCE(IDB_LOGO_OPAQUE), + IMAGE_BITMAP, + 0, + 0, + LR_DEFAULTCOLOR)); + + cfgui_set_wnd_data(hwnd, d); + + cfgui_initialize_dialog(hwnd); + + cfgui_activate_node(hwnd, node); + + khm_add_dialog(hwnd); + khm_enter_modal(hwnd); + + return TRUE; + + case WM_DESTROY: + cfgui_hwnd = NULL; + + khui_cfg_set_configui_handle(NULL); + + cfgui_uninitialize_dialog(hwnd); + + d = cfgui_get_wnd_data(hwnd); + khui_delete_bitmap(&d->kbmp_logo); + DeleteObject(d->hbr_white); + + cfgui_set_wnd_data(hwnd, NULL); + + khm_del_dialog(hwnd); + + SetForegroundWindow(khm_hwnd_main); + + PFREE(d); + + return FALSE; + + case WM_NOTIFY: + { + LPNMHDR lpnm; + LPNMTREEVIEW lptv; + LPNMTVGETINFOTIP lpgi; + khui_config_node node; + + lpnm = (LPNMHDR) lParam; + + switch (lpnm->code) { + case TVN_SELCHANGED: + lptv = (LPNMTREEVIEW) lParam; + cfgui_activate_node(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; + + case WM_CTLCOLORSTATIC: + { + d = cfgui_get_wnd_data(hwnd); + return (BOOL)(DWORD_PTR) d->hbr_white; + } + /* implicit break */ + + case WM_COMMAND: + switch(wParam) { + case MAKEWPARAM(IDCANCEL, BN_CLICKED): + khm_leave_modal(); + DestroyWindow(hwnd); + break; + + case MAKEWPARAM(IDAPPLY, BN_CLICKED): + cfgui_apply_settings(NULL); + break; + + case MAKEWPARAM(IDOK, BN_CLICKED): + cfgui_apply_settings(NULL); + khm_leave_modal(); + DestroyWindow(hwnd); + break; + } + return TRUE; + + case KHUI_WM_CFG_NOTIFY: + switch(HIWORD(wParam)) { + case WMCFG_SHOW_NODE: + cfgui_activate_node(hwnd, (khui_config_node) lParam); + break; + + case WMCFG_UPDATE_STATE: + cfgui_update_state(hwnd, LOWORD(wParam), + (khui_config_node) lParam); + break; + + case WMCFG_SYNC_NODE_LIST: + d = cfgui_get_wnd_data(hwnd); + cfgui_sync_node_list(d, hwnd); + break; + } + + return TRUE; + } + + return FALSE; +} + +static void +cfgui_create_window(khui_config_node node) { +#ifdef DEBUG + assert(cfgui_hwnd == NULL); +#endif + + khm_refresh_config(); + + cfgui_hwnd = CreateDialogParam(khm_hInstance, + MAKEINTRESOURCE(IDD_CFG_MAIN), + khm_hwnd_main, + cfgui_dlgproc, + (LPARAM) node); +#ifdef DEBUG + assert(cfgui_hwnd != NULL); +#endif + ShowWindow(cfgui_hwnd,SW_SHOW); +} + +static void +cfgui_destroy_window(void) { + if (cfgui_hwnd) + DestroyWindow(cfgui_hwnd); + /* cfgui_hwnd will be set to NULL in the dialog proc */ +} + +void +khm_show_config_pane(khui_config_node node) { + if (cfgui_hwnd != NULL) { + SendMessage(cfgui_hwnd, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(0, WMCFG_SHOW_NODE), + (LPARAM) node); + } else { + cfgui_create_window(node); + } +} + +void khm_refresh_config(void) { + khm_size cb; + khm_size n_idents; + wchar_t * idents = NULL; + wchar_t * t; + khm_int32 rv; + int n_tries = 0; + khui_config_node cfg_ids = NULL; + khui_config_node cfg_r = NULL; + khui_config_node cfg_iter = NULL; + khui_menu_def * omenu; + khm_boolean refresh_menu = FALSE; + + do { + rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG, + KCDB_IDENT_FLAG_CONFIG, + NULL, + &cb, + &n_idents); + + if (rv != KHM_ERROR_TOO_LONG || + n_idents == 0) + return; + + if (idents) + PFREE(idents); + idents = PMALLOC(cb); +#ifdef DEBUG + assert(idents); +#endif + + rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG, + KCDB_IDENT_FLAG_CONFIG, + idents, + &cb, + &n_idents); + + n_tries++; + } while(KHM_FAILED(rv) && + n_tries < 5); + + if (KHM_FAILED(rv)) + goto _cleanup; + + if (KHM_FAILED(khui_cfg_open(NULL, + L"KhmIdentities", + &cfg_ids))) + goto _cleanup; + + for(t = idents; t && *t; t = multi_string_next(t)) { + khui_config_node cfg_id = NULL; + + rv = khui_cfg_open(cfg_ids, + t, + &cfg_id); + + if (KHM_FAILED(rv)) { + khui_config_node_reg reg; + wchar_t wshort[KHUI_MAXCCH_SHORT_DESC]; + wchar_t wlong[KHUI_MAXCCH_LONG_DESC]; + wchar_t wfmt[KHUI_MAXCCH_SHORT_DESC]; + + ZeroMemory(®, sizeof(reg)); + + reg.name = t; + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = khm_hInstance; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDENTITY); + reg.dlg_proc = khm_cfg_identity_proc; + reg.flags = 0; + + LoadString(khm_hInstance, IDS_CFG_IDENTITY_SHORT, + wfmt, ARRAYLENGTH(wfmt)); + StringCbPrintf(wshort, sizeof(wshort), wfmt, t); + + LoadString(khm_hInstance, IDS_CFG_IDENTITY_LONG, + wfmt, ARRAYLENGTH(wfmt)); + StringCbPrintf(wlong, sizeof(wlong), wfmt, t); + + khui_cfg_register(cfg_ids, + ®); + } else { + khui_cfg_release(cfg_id); + } + } + + for (khui_cfg_get_first_child(cfg_ids, &cfg_iter); + cfg_iter; + khui_cfg_get_next_release(&cfg_iter)) { + + wchar_t cfgname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khm_handle tident = NULL; + khm_int32 tflags = 0; + + cb = sizeof(cfgname); + khui_cfg_get_name(cfg_iter, cfgname, &cb); + + if (KHM_FAILED(kcdb_identity_create(cfgname, 0, &tident)) || + KHM_FAILED(kcdb_identity_get_flags(tident, &tflags)) || + !(tflags & KCDB_IDENT_FLAG_ACTIVE) || + !(tflags & KCDB_IDENT_FLAG_CONFIG)) { + + /* this configuration node needs to be removed */ + + khui_cfg_remove(cfg_iter); + } + + if (tident) + kcdb_identity_release(tident); + } + + /* 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; + + khui_action_lock(); + + 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); + + khui_action_unlock(); + + if (refresh_menu) { + khui_refresh_actions(); + } + + _cleanup: + if (cfg_ids) + khui_cfg_release(cfg_ids); + + if (cfg_r) + khui_cfg_release(cfg_r); + + if (idents) + PFREE(idents); +} + +void khm_init_config(void) { + wchar_t wshort[KHUI_MAXCCH_SHORT_DESC]; + wchar_t wlong[KHUI_MAXCCH_LONG_DESC]; + khui_config_node_reg reg; + khui_config_node node; + + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = khm_hInstance; + reg.flags = KHUI_CNFLAG_SYSTEM; + + reg.name = L"KhmGeneral"; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_GENERAL); + reg.dlg_proc = khm_cfg_general_proc; + LoadString(khm_hInstance, IDS_CFG_GENERAL_SHORT, + wshort, ARRAYLENGTH(wshort)); + LoadString(khm_hInstance, IDS_CFG_GENERAL_LONG, + wlong, ARRAYLENGTH(wlong)); + + khui_cfg_register(NULL, ®); + + reg.name = L"KhmAppear"; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_APPEAR); + reg.dlg_proc = khm_cfg_appearance_proc; + LoadString(khm_hInstance, IDS_CFG_APPEAR_SHORT, + wshort, ARRAYLENGTH(wshort)); + LoadString(khm_hInstance, IDS_CFG_APPEAR_LONG, + wlong, ARRAYLENGTH(wlong)); + + khui_cfg_register(NULL, ®); + + reg.name = L"KhmIdentities"; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDENTITIES); + reg.dlg_proc = khm_cfg_identities_proc; + LoadString(khm_hInstance, IDS_CFG_IDENTITIES_SHORT, + wshort, ARRAYLENGTH(wshort)); + LoadString(khm_hInstance, IDS_CFG_IDENTITIES_LONG, + wlong, ARRAYLENGTH(wlong)); + + khui_cfg_register(NULL, ®); + + node = NULL; + khui_cfg_open(NULL, L"KhmIdentities", &node); +#ifdef DEBUG + assert(node); +#endif + + reg.name = L"KhmIdentitiesTab"; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDS_TAB); + reg.dlg_proc = khm_cfg_ids_tab_proc; + LoadString(khm_hInstance, IDS_CFG_IDS_TAB_SHORT, + wshort, ARRAYLENGTH(wshort)); + LoadString(khm_hInstance, IDS_CFG_IDS_TAB_LONG, + wlong, ARRAYLENGTH(wlong)); + reg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_SYSTEM; + + khui_cfg_register(node, ®); + + reg.name = L"KhmIdentitiesTabPlural"; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_ID_TAB); + reg.dlg_proc = khm_cfg_id_tab_proc; + LoadString(khm_hInstance, IDS_CFG_ID_TAB_SHORT, + wshort, ARRAYLENGTH(wshort)); + LoadString(khm_hInstance, IDS_CFG_ID_TAB_LONG, + wlong, ARRAYLENGTH(wlong)); + reg.flags = KHUI_CNFLAG_PLURAL | KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_SYSTEM; + + khui_cfg_register(node, ®); + + reg.flags = KHUI_CNFLAG_SYSTEM; + khui_cfg_release(node); + + reg.name = L"KhmNotifications"; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_NOTIF); + reg.dlg_proc = khm_cfg_notifications_proc; + LoadString(khm_hInstance, IDS_CFG_NOTIF_SHORT, + wshort, ARRAYLENGTH(wshort)); + LoadString(khm_hInstance, IDS_CFG_NOTIF_LONG, + wlong, ARRAYLENGTH(wlong)); + + khui_cfg_register(NULL, ®); + + reg.name = L"KhmPlugins"; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_PLUGINS); + reg.dlg_proc = khm_cfg_plugins_proc; + LoadString(khm_hInstance, IDS_CFG_PLUGINS_SHORT, + wshort, ARRAYLENGTH(wshort)); + LoadString(khm_hInstance, IDS_CFG_PLUGINS_LONG, + wlong, ARRAYLENGTH(wlong)); + + khui_cfg_register(NULL, ®); +} + +void khm_exit_config(void) { +} diff --git a/src/windows/identity/ui/configwnd.h b/src/windows/identity/ui/configwnd.h index 693ec7d72..712805fc1 100644 --- a/src/windows/identity/ui/configwnd.h +++ b/src/windows/identity/ui/configwnd.h @@ -1,88 +1,88 @@ -/* - * 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_CONFIGWND_H -#define __KHIMAIRA_CONFIGWND_H - -#define CFGACTION_MAGIC 0x38f8 - -void -khm_show_config_pane(khui_config_node node); - -void khm_init_config(void); -void khm_exit_config(void); - -void khm_refresh_config(void); - -/* window procedures for other configuration windows */ -INT_PTR CALLBACK -khm_cfg_general_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -INT_PTR CALLBACK -khm_cfg_identities_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -INT_PTR CALLBACK -khm_cfg_identity_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -INT_PTR CALLBACK -khm_cfg_id_tab_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -INT_PTR CALLBACK -khm_cfg_ids_tab_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -INT_PTR CALLBACK -khm_cfg_notifications_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -INT_PTR CALLBACK -khm_cfg_plugins_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -INT_PTR CALLBACK -khm_cfg_appearance_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); -#endif +/* + * 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_CONFIGWND_H +#define __KHIMAIRA_CONFIGWND_H + +#define CFGACTION_MAGIC 0x38f8 + +void +khm_show_config_pane(khui_config_node node); + +void khm_init_config(void); +void khm_exit_config(void); + +void khm_refresh_config(void); + +/* window procedures for other configuration windows */ +INT_PTR CALLBACK +khm_cfg_general_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +khm_cfg_identities_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +khm_cfg_identity_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +khm_cfg_id_tab_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +khm_cfg_ids_tab_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +khm_cfg_notifications_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +khm_cfg_plugins_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +khm_cfg_appearance_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); +#endif diff --git a/src/windows/identity/ui/credfuncs.c b/src/windows/identity/ui/credfuncs.c index 2f1ac8033..8eeba14a3 100644 --- a/src/windows/identity/ui/credfuncs.c +++ b/src/windows/identity/ui/credfuncs.c @@ -1,1398 +1,1398 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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 - -static BOOL in_dialog = FALSE; -static CRITICAL_SECTION cs_dialog; -static HANDLE in_dialog_evt = NULL; -static LONG init_dialog = 0; -static khm_int32 dialog_result = 0; -static wchar_t dialog_identity[KCDB_IDENT_MAXCCH_NAME]; -static khui_new_creds * dialog_nc = NULL; - -static void -dialog_sync_init(void) { - if (InterlockedIncrement(&init_dialog) == 1) { -#ifdef DEBUG - assert(in_dialog_evt == NULL); - assert(in_dialog == FALSE); -#endif - - InitializeCriticalSection(&cs_dialog); - - in_dialog_evt = CreateEvent(NULL, - TRUE, - TRUE, - L"DialogCompletionEvent"); - } else { - InterlockedDecrement(&init_dialog); - if (in_dialog_evt == NULL) { - Sleep(100); - } - } -} - -BOOL -khm_cred_begin_dialog(void) { - BOOL rv; - - dialog_sync_init(); - - EnterCriticalSection(&cs_dialog); - - if (in_dialog) { - rv = FALSE; - - /* if a dialog is being displayed and we got a another request - to show one, we bring the existing one to the - foreground. */ - if (dialog_nc && dialog_nc->hwnd) { - khm_int32 t = 0; - - if (KHM_SUCCEEDED(khc_read_int32(NULL, - L"CredWindow\\Windows\\NewCred\\ForceToTop", - &t)) && - t != 0) { - - khm_activate_main_window(); - - SetWindowPos(dialog_nc->hwnd, HWND_TOP, 0, 0, 0, 0, - (SWP_NOMOVE | SWP_NOSIZE)); - } - } - - } else { - rv = TRUE; - in_dialog = TRUE; - ResetEvent(in_dialog_evt); - } - - LeaveCriticalSection(&cs_dialog); - return rv; -} - -void -khm_cred_end_dialog(khui_new_creds * nc) { - dialog_sync_init(); - - EnterCriticalSection(&cs_dialog); - if (in_dialog) { - in_dialog = FALSE; - SetEvent(in_dialog_evt); - } - dialog_result = nc->result; -#ifdef DEBUG - assert(dialog_nc == nc); -#endif - dialog_nc = NULL; - if (nc->subtype == KMSG_CRED_NEW_CREDS && - nc->n_identities > 0 && - nc->identities[0]) { - khm_size cb; - - cb = sizeof(dialog_identity); - if (KHM_FAILED(kcdb_identity_get_name(nc->identities[0], - dialog_identity, - &cb))) - dialog_identity[0] = 0; - } else { - dialog_identity[0] = 0; - } - LeaveCriticalSection(&cs_dialog); -} - -BOOL -khm_cred_is_in_dialog(void) { - BOOL rv; - - dialog_sync_init(); - - EnterCriticalSection(&cs_dialog); - rv = in_dialog; - LeaveCriticalSection(&cs_dialog); - - return rv; -} - -khm_int32 -khm_cred_wait_for_dialog(DWORD timeout, khm_int32 * result, - wchar_t * ident, khm_size cb_ident) { - khm_int32 rv; - - dialog_sync_init(); - - EnterCriticalSection(&cs_dialog); - if (!in_dialog) - rv = KHM_ERROR_NOT_FOUND; - else { - DWORD dw; - - do { - LeaveCriticalSection(&cs_dialog); - - dw = WaitForSingleObject(in_dialog_evt, timeout); - - EnterCriticalSection(&cs_dialog); - - if (!in_dialog) { - rv = KHM_ERROR_SUCCESS; - if (result) { - *result = dialog_result; - } - if (ident) { - StringCbCopy(ident, cb_ident, dialog_identity); - } - break; - } else if(dw == WAIT_TIMEOUT) { - rv = KHM_ERROR_TIMEOUT; - break; - } - } while(TRUE); - } - LeaveCriticalSection(&cs_dialog); - - return rv; -} - -/* Completion handler for KMSG_CRED messages. We control the overall - logic of credentials acquisition and other operations here. Once a - credentials operation is triggered, each successive message - completion notification will be used to dispatch the messages for - the next step in processing the operation. */ -void KHMAPI -kmsg_cred_completion(kmq_message *m) -{ - khui_new_creds * nc; - -#ifdef DEBUG - assert(m->type == KMSG_CRED); -#else - if(m->type != KMSG_CRED) - return; /* huh? */ -#endif - - switch(m->subtype) { - case KMSG_CRED_PASSWORD: - /* fallthrough */ - case KMSG_CRED_NEW_CREDS: - /* Cred types have attached themselves. Trigger the next - phase. */ - kmq_post_message(KMSG_CRED, KMSG_CRED_DIALOG_SETUP, 0, - m->vparam); - break; - - case KMSG_CRED_RENEW_CREDS: - nc = (khui_new_creds *) m->vparam; - - /* khm_cred_dispatch_process_message() deals with the case - where there are no credential types that wants to - participate in this operation. */ - khm_cred_dispatch_process_message(nc); - break; - - case KMSG_CRED_DIALOG_SETUP: - nc = (khui_new_creds *) m->vparam; - - khm_prep_newcredwnd(nc->hwnd); - - /* all the controls have been created. Now initialize them */ - if (nc->n_types > 0) { - kmq_post_subs_msg(nc->type_subs, - nc->n_types, - KMSG_CRED, - KMSG_CRED_DIALOG_PRESTART, - 0, - m->vparam); - } else { - PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, - MAKEWPARAM(0, WMNC_DIALOG_PROCESS_COMPLETE), 0); - } - break; - - case KMSG_CRED_DIALOG_PRESTART: - /* all prestart stuff is done. Now to activate the dialog */ - nc = (khui_new_creds *) m->vparam; - khm_show_newcredwnd(nc->hwnd); - - kmq_post_subs_msg(nc->type_subs, - nc->n_types, - KMSG_CRED, - KMSG_CRED_DIALOG_START, - 0, - m->vparam); - /* at this point, the dialog window takes over. We let it run - the show until KMSG_CRED_DIALOG_END is posted by the dialog - procedure. */ - break; - - case KMSG_CRED_PROCESS: - /* a wave of these messages have completed. We should check - if there's more */ - nc = (khui_new_creds *) m->vparam; - - /* if we are done processing all the plug-ins, then check if - there were any errors reported. Otherwise we dispatch - another set of messages. */ - if(!khm_cred_dispatch_process_level(nc)) { - - if(kherr_is_error()) { - khui_alert * alert; - kherr_event * evt; - kherr_context * ctx; - wchar_t ws_tfmt[512]; - wchar_t w_idname[KCDB_IDENT_MAXCCH_NAME]; - wchar_t ws_title[ARRAYLENGTH(ws_tfmt) + KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - - /* For renewals, we suppress the error message for the - following case: - - - The renewal was for an identity - - - There are no identity credentials for the - identity (no credentials that have the same type - as the identity provider). */ - - if (nc->subtype == KMSG_CRED_RENEW_CREDS && - nc->ctx.scope == KHUI_SCOPE_IDENT && - nc->ctx.identity != NULL) { - khm_handle tcs = NULL; /* credential set */ - khm_size count = 0; - khm_int32 id_ctype = KCDB_CREDTYPE_INVALID; - khm_int32 delta = 0; - - kcdb_identity_get_type(&id_ctype); - kcdb_credset_create(&tcs); - kcdb_credset_collect(tcs, NULL, - nc->ctx.identity, - id_ctype, - &delta); - kcdb_credset_get_size(tcs, &count); - kcdb_credset_delete(tcs); - - if (count == 0) { - goto done_with_op; - } - } - - ctx = kherr_peek_context(); - evt = kherr_get_err_event(ctx); - kherr_evaluate_event(evt); - - khui_alert_create_empty(&alert); - - if (nc->subtype == KMSG_CRED_NEW_CREDS) { - - khui_alert_set_type(alert, KHUI_ALERTTYPE_ACQUIREFAIL); - - cb = sizeof(w_idname); - if (nc->n_identities == 0 || - KHM_FAILED(kcdb_identity_get_name(nc->identities[0], - w_idname, &cb))) { - /* an identity could not be determined */ - LoadString(khm_hInstance, IDS_NC_FAILED_TITLE, - ws_title, ARRAYLENGTH(ws_title)); - } else { - LoadString(khm_hInstance, IDS_NC_FAILED_TITLE_I, - ws_tfmt, ARRAYLENGTH(ws_tfmt)); - StringCbPrintf(ws_title, sizeof(ws_title), - ws_tfmt, w_idname); - khui_alert_set_ctx(alert, - KHUI_SCOPE_IDENT, - nc->identities[0], - KCDB_CREDTYPE_INVALID, - NULL); - } - - } else if (nc->subtype == KMSG_CRED_PASSWORD) { - - khui_alert_set_type(alert, KHUI_ALERTTYPE_CHPW); - - cb = sizeof(w_idname); - if (nc->n_identities == 0 || - KHM_FAILED(kcdb_identity_get_name(nc->identities[0], - w_idname, &cb))) { - LoadString(khm_hInstance, IDS_NC_PWD_FAILED_TITLE, - ws_title, ARRAYLENGTH(ws_title)); - } else { - LoadString(khm_hInstance, IDS_NC_PWD_FAILED_TITLE_I, - ws_tfmt, ARRAYLENGTH(ws_tfmt)); - StringCbPrintf(ws_title, sizeof(ws_title), - ws_tfmt, w_idname); - khui_alert_set_ctx(alert, - KHUI_SCOPE_IDENT, - nc->identities[0], - KCDB_CREDTYPE_INVALID, - NULL); - } - - } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { - - khui_alert_set_type(alert, KHUI_ALERTTYPE_RENEWFAIL); - - cb = sizeof(w_idname); - if (nc->ctx.identity == NULL || - KHM_FAILED(kcdb_identity_get_name(nc->ctx.identity, - w_idname, &cb))) { - LoadString(khm_hInstance, IDS_NC_REN_FAILED_TITLE, - ws_title, ARRAYLENGTH(ws_title)); - } else { - LoadString(khm_hInstance, IDS_NC_REN_FAILED_TITLE_I, - ws_tfmt, ARRAYLENGTH(ws_tfmt)); - StringCbPrintf(ws_title, sizeof(ws_title), - ws_tfmt, w_idname); - khui_alert_set_ctx(alert, - KHUI_SCOPE_IDENT, - nc->ctx.identity, - KCDB_CREDTYPE_INVALID, - NULL); - } - - } else { -#ifdef DEBUG - assert(FALSE); -#endif - } - - khui_alert_set_title(alert, ws_title); - khui_alert_set_severity(alert, evt->severity); - - if(!evt->long_desc) - khui_alert_set_message(alert, evt->short_desc); - else - khui_alert_set_message(alert, evt->long_desc); - - if(evt->suggestion) - khui_alert_set_suggestion(alert, evt->suggestion); - - if (nc->subtype == KMSG_CRED_RENEW_CREDS && - nc->ctx.identity != NULL) { - - khm_int32 n_cmd; - - n_cmd = khm_get_identity_new_creds_action(nc->ctx.identity); - - if (n_cmd != 0) { - khui_alert_add_command(alert, n_cmd); - khui_alert_add_command(alert, KHUI_PACTION_CLOSE); - - khui_alert_set_flags(alert, KHUI_ALERT_FLAG_DISPATCH_CMD, - KHUI_ALERT_FLAG_DISPATCH_CMD); - } - } - - khui_alert_show(alert); - khui_alert_release(alert); - - kherr_release_context(ctx); - - kherr_clear_error(); - } - - done_with_op: - - if (nc->subtype == KMSG_CRED_RENEW_CREDS) { - kmq_post_message(KMSG_CRED, KMSG_CRED_END, 0, - m->vparam); - } else { - PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, - MAKEWPARAM(0, WMNC_DIALOG_PROCESS_COMPLETE), - 0); - } - } - break; - - case KMSG_CRED_END: - /* all is done. */ - { - khui_new_creds * nc; - khm_boolean continue_cmdline = TRUE; - - nc = (khui_new_creds *) m->vparam; - - if (nc->subtype == KMSG_CRED_NEW_CREDS || - nc->subtype == KMSG_CRED_PASSWORD) { - - khm_cred_end_dialog(nc); - - } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { - - /* if this is a renewal that was triggered while we - were processing the commandline, then we need to - update the pending renewal count. */ - - if (khm_startup.processing) { - LONG renewals; - renewals = InterlockedDecrement(&khm_startup.pending_renewals); - - if (renewals != 0) { - continue_cmdline = FALSE; - } - } - } - - khui_cw_destroy_cred_blob(nc); - - kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0); - - if (continue_cmdline) - kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0); - } - break; - - /* property sheet stuff */ - - case KMSG_CRED_PP_BEGIN: - /* all the pages should have been added by now. Just send out - the precreate message */ - kmq_post_message(KMSG_CRED, KMSG_CRED_PP_PRECREATE, 0, - m->vparam); - break; - - case KMSG_CRED_PP_END: - kmq_post_message(KMSG_CRED, KMSG_CRED_PP_DESTROY, 0, - m->vparam); - break; - - case KMSG_CRED_DESTROY_CREDS: -#ifdef DEBUG - assert(m->vparam != NULL); -#endif - khui_context_release((khui_action_context *) m->vparam); - PFREE(m->vparam); - - kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0); - - kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0); - break; - - case KMSG_CRED_IMPORT: - { - khm_boolean continue_cmdline = FALSE; - LONG pending_renewals; - - /* once an import operation ends, we have to trigger a - renewal so that other plug-ins that didn't participate - in the import operation can have a chance at getting - the necessary credentials. - - If we are in the middle of processing the commandline, - we have to be a little bit careful. We can't issue a - commandline conituation message right now because the - import action is still ongoing (since the renewals are - part of the action). Once the renewals have completed, - the completion handler will automatically issue a - commandline continuation message. However, if there - were no identities to renew, then we have to issue the - message ourselves. - */ - - InterlockedIncrement(&khm_startup.pending_renewals); - - khm_cred_renew_all_identities(); - - pending_renewals = InterlockedDecrement(&khm_startup.pending_renewals); - - if (pending_renewals == 0 && khm_startup.processing) - kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0); - } - break; - - case KMSG_CRED_REFRESH: - kcdb_identity_refresh_all(); - break; - } -} - -void khm_cred_import(void) -{ - _begin_task(KHERR_CF_TRANSITIVE); - _report_sr0(KHERR_NONE, IDS_CTX_IMPORT); - _describe(); - - kmq_post_message(KMSG_CRED, KMSG_CRED_IMPORT, 0, 0); - - _end_task(); -} - -void khm_cred_set_default(void) -{ - khui_action_context ctx; - khm_int32 rv; - - khui_context_get(&ctx); - - if (ctx.identity) { - rv = kcdb_identity_set_default(ctx.identity); - } - - khui_context_release(&ctx); -} - -void khm_cred_destroy_creds(khm_boolean sync, khm_boolean quiet) -{ - khui_action_context * pctx; - - pctx = PMALLOC(sizeof(*pctx)); -#ifdef DEBUG - assert(pctx); -#endif - - khui_context_get(pctx); - - 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]; - wchar_t message[256]; - - LoadString(khm_hInstance, - IDS_ALERT_NOSEL_TITLE, - title, - ARRAYLENGTH(title)); - - LoadString(khm_hInstance, - IDS_ALERT_NOSEL, - message, - ARRAYLENGTH(message)); - - khui_alert_show_simple(title, - message, - KHERR_WARNING); - - khui_context_release(pctx); - PFREE(pctx); - - 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(); -} - -void khm_cred_destroy_identity(khm_handle identity) -{ - khui_action_context * pctx; - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - - if (identity == NULL) - return; - - pctx = PMALLOC(sizeof(*pctx)); -#ifdef DEBUG - assert(pctx); -#endif - - khui_context_create(pctx, - KHUI_SCOPE_IDENT, - identity, - KCDB_CREDTYPE_INVALID, - NULL); - - cb = sizeof(idname); - kcdb_identity_get_name(identity, idname, &cb); - - _begin_task(KHERR_CF_TRANSITIVE); - _report_sr1(KHERR_NONE, IDS_CTX_DESTROY_ID, _dupstr(idname)); - _describe(); - - kmq_post_message(KMSG_CRED, - KMSG_CRED_DESTROY_CREDS, - 0, - (void *) pctx); - - _end_task(); -} - -void khm_cred_renew_all_identities(void) -{ - khm_size count; - khm_size cb = 0; - khm_size n_idents = 0; - khm_int32 rv; - wchar_t * ident_names = NULL; - wchar_t * this_ident; - - kcdb_credset_get_size(NULL, &count); - - /* if there are no credentials, we just skip over the renew - action. */ - - if (count == 0) - return; - - ident_names = NULL; - - while (TRUE) { - if (ident_names) { - PFREE(ident_names); - ident_names = NULL; - } - - cb = 0; - rv = kcdb_identity_enum(KCDB_IDENT_FLAG_EMPTY, 0, - NULL, - &cb, &n_idents); - - if (n_idents == 0 || rv != KHM_ERROR_TOO_LONG || - cb == 0) - break; - - ident_names = PMALLOC(cb); - ident_names[0] = L'\0'; - - rv = kcdb_identity_enum(KCDB_IDENT_FLAG_EMPTY, 0, - ident_names, - &cb, &n_idents); - - if (KHM_SUCCEEDED(rv)) - break; - } - - if (ident_names) { - for (this_ident = ident_names; - this_ident && *this_ident; - this_ident = multi_string_next(this_ident)) { - khm_handle ident; - - if (KHM_FAILED(kcdb_identity_create(this_ident, 0, - &ident))) - continue; - - khm_cred_renew_identity(ident); - - kcdb_identity_release(ident); - } - - PFREE(ident_names); - ident_names = NULL; - } -} - -void khm_cred_renew_identity(khm_handle identity) -{ - khui_new_creds * c; - - khui_cw_create_cred_blob(&c); - - c->subtype = KMSG_CRED_RENEW_CREDS; - c->result = KHUI_NC_RESULT_PROCESS; - khui_context_create(&c->ctx, - KHUI_SCOPE_IDENT, - identity, - KCDB_CREDTYPE_INVALID, - NULL); - - _begin_task(KHERR_CF_TRANSITIVE); - _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS); - _describe(); - - /* if we are calling this while processing startup actions, we - need to keep track of how many we have issued. */ - if (khm_startup.processing) { - InterlockedIncrement(&khm_startup.pending_renewals); - } - - kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c); - - _end_task(); -} - -void khm_cred_renew_cred(khm_handle cred) -{ - khui_new_creds * c; - - khui_cw_create_cred_blob(&c); - - c->subtype = KMSG_CRED_RENEW_CREDS; - c->result = KHUI_NC_RESULT_PROCESS; - khui_context_create(&c->ctx, - KHUI_SCOPE_CRED, - NULL, - KCDB_CREDTYPE_INVALID, - cred); - - _begin_task(KHERR_CF_TRANSITIVE); - _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS); - _describe(); - - /* if we are calling this while processing startup actions, we - need to keep track of how many we have issued. */ - if (khm_startup.processing) { - InterlockedIncrement(&khm_startup.pending_renewals); - } - - kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c); - - _end_task(); -} - -void khm_cred_renew_creds(void) -{ - khui_new_creds * c; - - khui_cw_create_cred_blob(&c); - c->subtype = KMSG_CRED_RENEW_CREDS; - c->result = KHUI_NC_RESULT_PROCESS; - khui_context_get(&c->ctx); - - _begin_task(KHERR_CF_TRANSITIVE); - _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS); - _describe(); - - /* if we are calling this while processing startup actions, we - need to keep track of how many we have issued. */ - if (khm_startup.processing) { - InterlockedIncrement(&khm_startup.pending_renewals); - } - - kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c); - - _end_task(); -} - -void khm_cred_change_password(wchar_t * title) -{ - khui_new_creds * nc; - LPNETID_DLGINFO pdlginfo; - khm_size cb; - - if (!khm_cred_begin_dialog()) - return; - - khui_cw_create_cred_blob(&nc); - nc->subtype = KMSG_CRED_PASSWORD; - dialog_nc = nc; - - khui_context_get(&nc->ctx); - - kcdb_identpro_get_ui_cb((void *) &nc->ident_cb); - - assert(nc->ident_cb); - - if (title) { - - if (SUCCEEDED(StringCbLength(title, KHUI_MAXCB_TITLE, &cb))) { - cb += sizeof(wchar_t); - - nc->window_title = PMALLOC(cb); -#ifdef DEBUG - assert(nc->window_title); -#endif - StringCbCopy(nc->window_title, cb, title); - } - } else if (nc->ctx.cb_vparam == sizeof(NETID_DLGINFO) && - (pdlginfo = nc->ctx.vparam) && - pdlginfo->size == NETID_DLGINFO_V1_SZ && - pdlginfo->in.title[0] && - SUCCEEDED(StringCchLength(pdlginfo->in.title, - NETID_TITLE_SZ, - &cb))) { - - cb = (cb + 1) * sizeof(wchar_t); - nc->window_title = PMALLOC(cb); -#ifdef DEBUG - assert(nc->window_title); -#endif - StringCbCopy(nc->window_title, cb, pdlginfo->in.title); - } - - khm_create_newcredwnd(khm_hwnd_main, nc); - - if (nc->hwnd != NULL) { - _begin_task(KHERR_CF_TRANSITIVE); - _report_sr0(KHERR_NONE, IDS_CTX_PASSWORD); - _describe(); - - kmq_post_message(KMSG_CRED, KMSG_CRED_PASSWORD, 0, - (void *) nc); - - _end_task(); - } else { - khui_cw_destroy_cred_blob(nc); - } -} - -void -khm_cred_obtain_new_creds_for_ident(khm_handle ident, wchar_t * title) -{ - khui_action_context ctx; - - if (ident == NULL) - khm_cred_obtain_new_creds(title); - - khui_context_get(&ctx); - - khui_context_set(KHUI_SCOPE_IDENT, - ident, - KCDB_CREDTYPE_INVALID, - NULL, - NULL, - 0, - NULL); - - khm_cred_obtain_new_creds(title); - - khui_context_set_indirect(&ctx); - - khui_context_release(&ctx); -} - -void khm_cred_obtain_new_creds(wchar_t * title) -{ - khui_new_creds * nc; - LPNETID_DLGINFO pdlginfo; - khm_size cb; - - if (!khm_cred_begin_dialog()) - return; - - khui_cw_create_cred_blob(&nc); - nc->subtype = KMSG_CRED_NEW_CREDS; - dialog_nc = nc; - - khui_context_get(&nc->ctx); - - kcdb_identpro_get_ui_cb((void *) &nc->ident_cb); - - if (nc->ident_cb == NULL) { - wchar_t title[256]; - wchar_t msg[512]; - wchar_t suggestion[512]; - khui_alert * a; - - LoadString(khm_hInstance, IDS_ERR_TITLE_NO_IDENTPRO, - title, ARRAYLENGTH(title)); - LoadString(khm_hInstance, IDS_ERR_MSG_NO_IDENTPRO, - msg, ARRAYLENGTH(msg)); - LoadString(khm_hInstance, IDS_ERR_SUGG_NO_IDENTPRO, - suggestion, ARRAYLENGTH(suggestion)); - - khui_alert_create_simple(title, - msg, - KHERR_ERROR, - &a); - khui_alert_set_suggestion(a, suggestion); - - khui_alert_show(a); - - khui_alert_release(a); - - khui_context_release(&nc->ctx); - nc->result = KHUI_NC_RESULT_CANCEL; - khm_cred_end_dialog(nc); - khui_cw_destroy_cred_blob(nc); - return; - } - - if (title) { - if (SUCCEEDED(StringCbLength(title, KHUI_MAXCB_TITLE, &cb))) { - cb += sizeof(wchar_t); - - nc->window_title = PMALLOC(cb); -#ifdef DEBUG - assert(nc->window_title); -#endif - StringCbCopy(nc->window_title, cb, title); - } - } else if (nc->ctx.cb_vparam == sizeof(NETID_DLGINFO) && - (pdlginfo = nc->ctx.vparam) && - pdlginfo->size == NETID_DLGINFO_V1_SZ && - pdlginfo->in.title[0] && - SUCCEEDED(StringCchLength(pdlginfo->in.title, - NETID_TITLE_SZ, - &cb))) { - - cb = (cb + 1) * sizeof(wchar_t); - nc->window_title = PMALLOC(cb); -#ifdef DEBUG - assert(nc->window_title); -#endif - StringCbCopy(nc->window_title, cb, pdlginfo->in.title); - } - - khm_create_newcredwnd(khm_hwnd_main, nc); - - if (nc->hwnd != NULL) { - _begin_task(KHERR_CF_TRANSITIVE); - _report_sr0(KHERR_NONE, IDS_CTX_NEW_CREDS); - _describe(); - - kmq_post_message(KMSG_CRED, KMSG_CRED_NEW_CREDS, 0, - (void *) nc); - - _end_task(); - } else { - khui_context_release(&nc->ctx); - nc->result = KHUI_NC_RESULT_CANCEL; - khm_cred_end_dialog(nc); - khui_cw_destroy_cred_blob(nc); - } -} - -/* this is called by khm_cred_dispatch_process_message and the - kmsg_cred_completion to initiate and continue checked broadcasts of - KMSG_CRED_DIALOG_PROCESS messages. - - Returns TRUE if more KMSG_CRED_DIALOG_PROCESS messages were - posted. */ -BOOL khm_cred_dispatch_process_level(khui_new_creds *nc) -{ - khm_size i,j; - khm_handle subs[KHUI_MAX_NCTYPES]; - int n_subs = 0; - BOOL cont = FALSE; - khui_new_creds_by_type *t, *d; - - /* at each level, we dispatch a wave of notifications to plug-ins - who's dependencies are all satisfied */ - EnterCriticalSection(&nc->cs); - - /* if any types have already completed, we mark them are processed - and skip them */ - for (i=0; i < nc->n_types; i++) { - t = nc->types[i]; - if(t->flags & KHUI_NC_RESPONSE_COMPLETED) - t->flags |= KHUI_NCT_FLAG_PROCESSED; - } - - for(i=0; in_types; i++) { - t = nc->types[i]; - - if((t->flags & KHUI_NCT_FLAG_PROCESSED) || - (t->flags & KHUI_NC_RESPONSE_COMPLETED)) - continue; - - for(j=0; jn_type_deps; j++) { - if(KHM_FAILED(khui_cw_find_type(nc, t->type_deps[j], &d))) - break; - - if(!(d->flags & KHUI_NC_RESPONSE_COMPLETED)) - break; - } - - if(jn_type_deps) /* there are unmet dependencies */ - continue; - - /* all dependencies for this type have been met. */ - subs[n_subs++] = kcdb_credtype_get_sub(t->type); - t->flags |= KHUI_NCT_FLAG_PROCESSED; - cont = TRUE; - } - - LeaveCriticalSection(&nc->cs); - - /* the reason why we are posting messages in batches is because - when the message has completed we know that all the types that - have the KHUI_NCT_FLAG_PROCESSED set have completed processing. - Otherwise we have to individually track each message and update - the type */ - if(n_subs > 0) - kmq_post_subs_msg(subs, n_subs, KMSG_CRED, KMSG_CRED_PROCESS, 0, - (void *) nc); - - return cont; -} - -void -khm_cred_dispatch_process_message(khui_new_creds *nc) -{ - khm_size i; - BOOL pending; - wchar_t wsinsert[512]; - khm_size cbsize; - - /* see if there's anything to do. We can check this without - obtaining a lock */ - if(nc->n_types == 0 || - (nc->subtype == KMSG_CRED_NEW_CREDS && - nc->n_identities == 0) || - (nc->subtype == KMSG_CRED_PASSWORD && - nc->n_identities == 0)) - goto _terminate_job; - - /* check dependencies and stuff first */ - EnterCriticalSection(&nc->cs); - for(i=0; in_types; i++) { - nc->types[i]->flags &= ~ KHUI_NCT_FLAG_PROCESSED; - } - LeaveCriticalSection(&nc->cs); - - /* Consindering all that can go wrong here and the desire to - handle errors here separately from others, we create a new task - for the purpose of tracking the credentials acquisition - process. */ - _begin_task(KHERR_CF_TRANSITIVE); - - /* Describe the context */ - if(nc->subtype == KMSG_CRED_NEW_CREDS) { - cbsize = sizeof(wsinsert); - kcdb_identity_get_name(nc->identities[0], wsinsert, &cbsize); - - _report_sr1(KHERR_NONE, IDS_CTX_PROC_NEW_CREDS, - _cstr(wsinsert)); - _resolve(); - } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { - cbsize = sizeof(wsinsert); - - if (nc->ctx.scope == KHUI_SCOPE_IDENT) - kcdb_identity_get_name(nc->ctx.identity, wsinsert, &cbsize); - else if (nc->ctx.scope == KHUI_SCOPE_CREDTYPE) { - if (nc->ctx.identity != NULL) - kcdb_identity_get_name(nc->ctx.identity, wsinsert, - &cbsize); - else - kcdb_credtype_get_name(nc->ctx.cred_type, wsinsert, - &cbsize); - } else if (nc->ctx.scope == KHUI_SCOPE_CRED) { - kcdb_cred_get_name(nc->ctx.cred, wsinsert, &cbsize); - } else { - StringCbCopy(wsinsert, sizeof(wsinsert), L"(?)"); - } - - _report_sr1(KHERR_NONE, IDS_CTX_PROC_RENEW_CREDS, - _cstr(wsinsert)); - _resolve(); - } else if (nc->subtype == KMSG_CRED_PASSWORD) { - cbsize = sizeof(wsinsert); - kcdb_identity_get_name(nc->identities[0], wsinsert, &cbsize); - - _report_sr1(KHERR_NONE, IDS_CTX_PROC_PASSWORD, - _cstr(wsinsert)); - _resolve(); - } else { - assert(FALSE); - } - - _describe(); - - pending = khm_cred_dispatch_process_level(nc); - - _end_task(); - - if(!pending) - goto _terminate_job; - - return; - - _terminate_job: - if (nc->subtype == KMSG_CRED_RENEW_CREDS) - kmq_post_message(KMSG_CRED, KMSG_CRED_END, 0, (void *) nc); - else - PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, - MAKEWPARAM(0, WMNC_DIALOG_PROCESS_COMPLETE), 0); -} - -void -khm_cred_process_startup_actions(void) { - khm_handle defident = NULL; - - if (!khm_startup.processing) - return; - - if (khm_startup.init || - khm_startup.renew || - khm_startup.destroy || - khm_startup.autoinit) { - kcdb_identity_get_default(&defident); - } - - /* For asynchronous actions, we trigger the action and then exit - the loop. Once the action completes, the completion handler - will trigger a continuation message which will result in this - function getting called again. Then we can proceed with the - rest of the startup actions. */ - do { - if (khm_startup.init) { - if (defident) - khui_context_set(KHUI_SCOPE_IDENT, - defident, - KCDB_CREDTYPE_INVALID, - NULL, NULL, 0, - NULL); - else - khui_context_reset(); - - khm_cred_obtain_new_creds(NULL); - khm_startup.init = FALSE; - break; - } - - if (khm_startup.import) { - khm_cred_import(); - khm_startup.import = FALSE; - - /* we also set the renew command to false here because we - trigger a renewal for all the identities at the end of - the import operation anyway. */ - khm_startup.renew = FALSE; - break; - } - - if (khm_startup.renew) { - LONG pending_renewals; - - /* if there are no credentials, we just skip over the - renew action. */ - - khm_startup.renew = FALSE; - - InterlockedIncrement(&khm_startup.pending_renewals); - - khm_cred_renew_all_identities(); - - pending_renewals = InterlockedDecrement(&khm_startup.pending_renewals); - - if (pending_renewals != 0) - break; - - /* if there were no pending renewals, then we just fall - through. This means that either there were no - identities to renew, or all the renewals completed. If - all the renewals completed, then the commandline - contiuation message wasn't triggered. Either way, we - must fall through if the count is zero. */ - } - - if (khm_startup.destroy) { - - khm_startup.destroy = FALSE; - - if (defident) { - khui_context_set(KHUI_SCOPE_IDENT, - defident, - KCDB_CREDTYPE_INVALID, - NULL, NULL, 0, - NULL); - - khm_cred_destroy_creds(FALSE, FALSE); - break; - } - } - - if (khm_startup.autoinit) { - khm_size count = 0; - khm_handle credset = NULL; - khm_int32 ctype_ident = KCDB_CREDTYPE_INVALID; - khm_int32 delta = 0; - - khm_startup.autoinit = FALSE; - - kcdb_credset_create(&credset); - kcdb_identity_get_type(&ctype_ident); - - kcdb_credset_collect(credset, NULL, - defident, ctype_ident, - &delta); - - kcdb_credset_get_size(credset, &count); - - kcdb_credset_delete(credset); - - if (count == 0) { - if (defident) - khui_context_set(KHUI_SCOPE_IDENT, - defident, - KCDB_CREDTYPE_INVALID, - NULL, NULL, 0, - NULL); - else - khui_context_reset(); - - khm_cred_obtain_new_creds(NULL); - break; - } - } - - if (khm_startup.exit) { - PostMessage(khm_hwnd_main, - WM_COMMAND, - MAKEWPARAM(KHUI_ACTION_EXIT, 0), 0); - khm_startup.exit = FALSE; - break; - } - - /* when we get here, then we are all done with the command - line stuff */ - khm_startup.processing = FALSE; - khm_startup.remote = FALSE; - - kmq_post_message(KMSG_ACT, KMSG_ACT_END_CMDLINE, 0, 0); - } while(FALSE); - - if (defident) - kcdb_identity_release(defident); -} - -void -khm_cred_begin_startup_actions(void) { - khm_handle csp_cw; - - if (khm_startup.seen) - return; - - if (!khm_startup.remote && - KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", 0, &csp_cw))) { - - khm_int32 t = 0; - - khc_read_int32(csp_cw, L"Autoinit", &t); - if (t) - khm_startup.autoinit = TRUE; - - t = 0; - khc_read_int32(csp_cw, L"AutoImport", &t); - if (t) - khm_startup.import = TRUE; - - khc_close_space(csp_cw); - - } - - khm_startup.seen = TRUE; - khm_startup.processing = TRUE; - - khm_cred_process_startup_actions(); -} - -void -khm_cred_refresh(void) { - kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, NULL); -} - -void -khm_cred_addr_change(void) { - khm_handle csp_cw = NULL; - khm_int32 check_net = 0; - - wchar_t * ids = NULL; - wchar_t * t; - khm_size cb; - khm_size n_idents; - - FILETIME ft_now; - FILETIME ft_exp; - FILETIME ft_issue; - - if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", - 0, &csp_cw))) { - khc_read_int32(csp_cw, L"AutoDetectNet", &check_net); - - khc_close_space(csp_cw); - } - - if (!check_net) - return; - - while(TRUE) { - if (ids) - PFREE(ids); - ids = NULL; - - if (kcdb_identity_enum(KCDB_IDENT_FLAG_VALID | - KCDB_IDENT_FLAG_RENEWABLE, - KCDB_IDENT_FLAG_VALID | - KCDB_IDENT_FLAG_RENEWABLE, - NULL, - &cb, - &n_idents) != KHM_ERROR_TOO_LONG) - break; - - ids = PMALLOC(cb); - - if (KHM_SUCCEEDED - (kcdb_identity_enum(KCDB_IDENT_FLAG_VALID | - KCDB_IDENT_FLAG_RENEWABLE, - KCDB_IDENT_FLAG_VALID | - KCDB_IDENT_FLAG_RENEWABLE, - ids, - &cb, - &n_idents))) - break; - } - - if (!ids) - return; - - GetSystemTimeAsFileTime(&ft_now); - - for (t=ids; t && *t; t = multi_string_next(t)) { - khm_handle ident; - - - if (KHM_FAILED - (kcdb_identity_create(t, 0, &ident))) - continue; - - cb = sizeof(ft_issue); - - if (KHM_SUCCEEDED - (kcdb_identity_get_attr(ident, KCDB_ATTR_ISSUE, NULL, - &ft_issue, &cb)) && - - (cb = sizeof(ft_exp)) && - KHM_SUCCEEDED - (kcdb_identity_get_attr(ident, KCDB_ATTR_EXPIRE, NULL, - &ft_exp, &cb)) && - - CompareFileTime(&ft_now, &ft_exp) < 0) { - - khm_int64 i_issue; - khm_int64 i_exp; - khm_int64 i_now; - - i_issue = FtToInt(&ft_issue); - i_exp = FtToInt(&ft_exp); - i_now = FtToInt(&ft_now); - - if (i_now > (i_issue + i_exp) / 2) { - - khm_cred_renew_identity(ident); - - } - } - - kcdb_identity_release(ident); - } -} +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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 + +static BOOL in_dialog = FALSE; +static CRITICAL_SECTION cs_dialog; +static HANDLE in_dialog_evt = NULL; +static LONG init_dialog = 0; +static khm_int32 dialog_result = 0; +static wchar_t dialog_identity[KCDB_IDENT_MAXCCH_NAME]; +static khui_new_creds * dialog_nc = NULL; + +static void +dialog_sync_init(void) { + if (InterlockedIncrement(&init_dialog) == 1) { +#ifdef DEBUG + assert(in_dialog_evt == NULL); + assert(in_dialog == FALSE); +#endif + + InitializeCriticalSection(&cs_dialog); + + in_dialog_evt = CreateEvent(NULL, + TRUE, + TRUE, + L"DialogCompletionEvent"); + } else { + InterlockedDecrement(&init_dialog); + if (in_dialog_evt == NULL) { + Sleep(100); + } + } +} + +BOOL +khm_cred_begin_dialog(void) { + BOOL rv; + + dialog_sync_init(); + + EnterCriticalSection(&cs_dialog); + + if (in_dialog) { + rv = FALSE; + + /* if a dialog is being displayed and we got a another request + to show one, we bring the existing one to the + foreground. */ + if (dialog_nc && dialog_nc->hwnd) { + khm_int32 t = 0; + + if (KHM_SUCCEEDED(khc_read_int32(NULL, + L"CredWindow\\Windows\\NewCred\\ForceToTop", + &t)) && + t != 0) { + + khm_activate_main_window(); + + SetWindowPos(dialog_nc->hwnd, HWND_TOP, 0, 0, 0, 0, + (SWP_NOMOVE | SWP_NOSIZE)); + } + } + + } else { + rv = TRUE; + in_dialog = TRUE; + ResetEvent(in_dialog_evt); + } + + LeaveCriticalSection(&cs_dialog); + return rv; +} + +void +khm_cred_end_dialog(khui_new_creds * nc) { + dialog_sync_init(); + + EnterCriticalSection(&cs_dialog); + if (in_dialog) { + in_dialog = FALSE; + SetEvent(in_dialog_evt); + } + dialog_result = nc->result; +#ifdef DEBUG + assert(dialog_nc == nc); +#endif + dialog_nc = NULL; + if (nc->subtype == KMSG_CRED_NEW_CREDS && + nc->n_identities > 0 && + nc->identities[0]) { + khm_size cb; + + cb = sizeof(dialog_identity); + if (KHM_FAILED(kcdb_identity_get_name(nc->identities[0], + dialog_identity, + &cb))) + dialog_identity[0] = 0; + } else { + dialog_identity[0] = 0; + } + LeaveCriticalSection(&cs_dialog); +} + +BOOL +khm_cred_is_in_dialog(void) { + BOOL rv; + + dialog_sync_init(); + + EnterCriticalSection(&cs_dialog); + rv = in_dialog; + LeaveCriticalSection(&cs_dialog); + + return rv; +} + +khm_int32 +khm_cred_wait_for_dialog(DWORD timeout, khm_int32 * result, + wchar_t * ident, khm_size cb_ident) { + khm_int32 rv; + + dialog_sync_init(); + + EnterCriticalSection(&cs_dialog); + if (!in_dialog) + rv = KHM_ERROR_NOT_FOUND; + else { + DWORD dw; + + do { + LeaveCriticalSection(&cs_dialog); + + dw = WaitForSingleObject(in_dialog_evt, timeout); + + EnterCriticalSection(&cs_dialog); + + if (!in_dialog) { + rv = KHM_ERROR_SUCCESS; + if (result) { + *result = dialog_result; + } + if (ident) { + StringCbCopy(ident, cb_ident, dialog_identity); + } + break; + } else if(dw == WAIT_TIMEOUT) { + rv = KHM_ERROR_TIMEOUT; + break; + } + } while(TRUE); + } + LeaveCriticalSection(&cs_dialog); + + return rv; +} + +/* Completion handler for KMSG_CRED messages. We control the overall + logic of credentials acquisition and other operations here. Once a + credentials operation is triggered, each successive message + completion notification will be used to dispatch the messages for + the next step in processing the operation. */ +void KHMAPI +kmsg_cred_completion(kmq_message *m) +{ + khui_new_creds * nc; + +#ifdef DEBUG + assert(m->type == KMSG_CRED); +#else + if(m->type != KMSG_CRED) + return; /* huh? */ +#endif + + switch(m->subtype) { + case KMSG_CRED_PASSWORD: + /* fallthrough */ + case KMSG_CRED_NEW_CREDS: + /* Cred types have attached themselves. Trigger the next + phase. */ + kmq_post_message(KMSG_CRED, KMSG_CRED_DIALOG_SETUP, 0, + m->vparam); + break; + + case KMSG_CRED_RENEW_CREDS: + nc = (khui_new_creds *) m->vparam; + + /* khm_cred_dispatch_process_message() deals with the case + where there are no credential types that wants to + participate in this operation. */ + khm_cred_dispatch_process_message(nc); + break; + + case KMSG_CRED_DIALOG_SETUP: + nc = (khui_new_creds *) m->vparam; + + khm_prep_newcredwnd(nc->hwnd); + + /* all the controls have been created. Now initialize them */ + if (nc->n_types > 0) { + kmq_post_subs_msg(nc->type_subs, + nc->n_types, + KMSG_CRED, + KMSG_CRED_DIALOG_PRESTART, + 0, + m->vparam); + } else { + PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_PROCESS_COMPLETE), 0); + } + break; + + case KMSG_CRED_DIALOG_PRESTART: + /* all prestart stuff is done. Now to activate the dialog */ + nc = (khui_new_creds *) m->vparam; + khm_show_newcredwnd(nc->hwnd); + + kmq_post_subs_msg(nc->type_subs, + nc->n_types, + KMSG_CRED, + KMSG_CRED_DIALOG_START, + 0, + m->vparam); + /* at this point, the dialog window takes over. We let it run + the show until KMSG_CRED_DIALOG_END is posted by the dialog + procedure. */ + break; + + case KMSG_CRED_PROCESS: + /* a wave of these messages have completed. We should check + if there's more */ + nc = (khui_new_creds *) m->vparam; + + /* if we are done processing all the plug-ins, then check if + there were any errors reported. Otherwise we dispatch + another set of messages. */ + if(!khm_cred_dispatch_process_level(nc)) { + + if(kherr_is_error()) { + khui_alert * alert; + kherr_event * evt; + kherr_context * ctx; + wchar_t ws_tfmt[512]; + wchar_t w_idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t ws_title[ARRAYLENGTH(ws_tfmt) + KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + + /* For renewals, we suppress the error message for the + following case: + + - The renewal was for an identity + + - There are no identity credentials for the + identity (no credentials that have the same type + as the identity provider). */ + + if (nc->subtype == KMSG_CRED_RENEW_CREDS && + nc->ctx.scope == KHUI_SCOPE_IDENT && + nc->ctx.identity != NULL) { + khm_handle tcs = NULL; /* credential set */ + khm_size count = 0; + khm_int32 id_ctype = KCDB_CREDTYPE_INVALID; + khm_int32 delta = 0; + + kcdb_identity_get_type(&id_ctype); + kcdb_credset_create(&tcs); + kcdb_credset_collect(tcs, NULL, + nc->ctx.identity, + id_ctype, + &delta); + kcdb_credset_get_size(tcs, &count); + kcdb_credset_delete(tcs); + + if (count == 0) { + goto done_with_op; + } + } + + ctx = kherr_peek_context(); + evt = kherr_get_err_event(ctx); + kherr_evaluate_event(evt); + + khui_alert_create_empty(&alert); + + if (nc->subtype == KMSG_CRED_NEW_CREDS) { + + khui_alert_set_type(alert, KHUI_ALERTTYPE_ACQUIREFAIL); + + cb = sizeof(w_idname); + if (nc->n_identities == 0 || + KHM_FAILED(kcdb_identity_get_name(nc->identities[0], + w_idname, &cb))) { + /* an identity could not be determined */ + LoadString(khm_hInstance, IDS_NC_FAILED_TITLE, + ws_title, ARRAYLENGTH(ws_title)); + } else { + LoadString(khm_hInstance, IDS_NC_FAILED_TITLE_I, + ws_tfmt, ARRAYLENGTH(ws_tfmt)); + StringCbPrintf(ws_title, sizeof(ws_title), + ws_tfmt, w_idname); + khui_alert_set_ctx(alert, + KHUI_SCOPE_IDENT, + nc->identities[0], + KCDB_CREDTYPE_INVALID, + NULL); + } + + } else if (nc->subtype == KMSG_CRED_PASSWORD) { + + khui_alert_set_type(alert, KHUI_ALERTTYPE_CHPW); + + cb = sizeof(w_idname); + if (nc->n_identities == 0 || + KHM_FAILED(kcdb_identity_get_name(nc->identities[0], + w_idname, &cb))) { + LoadString(khm_hInstance, IDS_NC_PWD_FAILED_TITLE, + ws_title, ARRAYLENGTH(ws_title)); + } else { + LoadString(khm_hInstance, IDS_NC_PWD_FAILED_TITLE_I, + ws_tfmt, ARRAYLENGTH(ws_tfmt)); + StringCbPrintf(ws_title, sizeof(ws_title), + ws_tfmt, w_idname); + khui_alert_set_ctx(alert, + KHUI_SCOPE_IDENT, + nc->identities[0], + KCDB_CREDTYPE_INVALID, + NULL); + } + + } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { + + khui_alert_set_type(alert, KHUI_ALERTTYPE_RENEWFAIL); + + cb = sizeof(w_idname); + if (nc->ctx.identity == NULL || + KHM_FAILED(kcdb_identity_get_name(nc->ctx.identity, + w_idname, &cb))) { + LoadString(khm_hInstance, IDS_NC_REN_FAILED_TITLE, + ws_title, ARRAYLENGTH(ws_title)); + } else { + LoadString(khm_hInstance, IDS_NC_REN_FAILED_TITLE_I, + ws_tfmt, ARRAYLENGTH(ws_tfmt)); + StringCbPrintf(ws_title, sizeof(ws_title), + ws_tfmt, w_idname); + khui_alert_set_ctx(alert, + KHUI_SCOPE_IDENT, + nc->ctx.identity, + KCDB_CREDTYPE_INVALID, + NULL); + } + + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + + khui_alert_set_title(alert, ws_title); + khui_alert_set_severity(alert, evt->severity); + + if(!evt->long_desc) + khui_alert_set_message(alert, evt->short_desc); + else + khui_alert_set_message(alert, evt->long_desc); + + if(evt->suggestion) + khui_alert_set_suggestion(alert, evt->suggestion); + + if (nc->subtype == KMSG_CRED_RENEW_CREDS && + nc->ctx.identity != NULL) { + + khm_int32 n_cmd; + + n_cmd = khm_get_identity_new_creds_action(nc->ctx.identity); + + if (n_cmd != 0) { + khui_alert_add_command(alert, n_cmd); + khui_alert_add_command(alert, KHUI_PACTION_CLOSE); + + khui_alert_set_flags(alert, KHUI_ALERT_FLAG_DISPATCH_CMD, + KHUI_ALERT_FLAG_DISPATCH_CMD); + } + } + + khui_alert_show(alert); + khui_alert_release(alert); + + kherr_release_context(ctx); + + kherr_clear_error(); + } + + done_with_op: + + if (nc->subtype == KMSG_CRED_RENEW_CREDS) { + kmq_post_message(KMSG_CRED, KMSG_CRED_END, 0, + m->vparam); + } else { + PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_PROCESS_COMPLETE), + 0); + } + } + break; + + case KMSG_CRED_END: + /* all is done. */ + { + khui_new_creds * nc; + khm_boolean continue_cmdline = TRUE; + + nc = (khui_new_creds *) m->vparam; + + if (nc->subtype == KMSG_CRED_NEW_CREDS || + nc->subtype == KMSG_CRED_PASSWORD) { + + khm_cred_end_dialog(nc); + + } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { + + /* if this is a renewal that was triggered while we + were processing the commandline, then we need to + update the pending renewal count. */ + + if (khm_startup.processing) { + LONG renewals; + renewals = InterlockedDecrement(&khm_startup.pending_renewals); + + if (renewals != 0) { + continue_cmdline = FALSE; + } + } + } + + khui_cw_destroy_cred_blob(nc); + + kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0); + + if (continue_cmdline) + kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0); + } + break; + + /* property sheet stuff */ + + case KMSG_CRED_PP_BEGIN: + /* all the pages should have been added by now. Just send out + the precreate message */ + kmq_post_message(KMSG_CRED, KMSG_CRED_PP_PRECREATE, 0, + m->vparam); + break; + + case KMSG_CRED_PP_END: + kmq_post_message(KMSG_CRED, KMSG_CRED_PP_DESTROY, 0, + m->vparam); + break; + + case KMSG_CRED_DESTROY_CREDS: +#ifdef DEBUG + assert(m->vparam != NULL); +#endif + khui_context_release((khui_action_context *) m->vparam); + PFREE(m->vparam); + + kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0); + + kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0); + break; + + case KMSG_CRED_IMPORT: + { + khm_boolean continue_cmdline = FALSE; + LONG pending_renewals; + + /* once an import operation ends, we have to trigger a + renewal so that other plug-ins that didn't participate + in the import operation can have a chance at getting + the necessary credentials. + + If we are in the middle of processing the commandline, + we have to be a little bit careful. We can't issue a + commandline conituation message right now because the + import action is still ongoing (since the renewals are + part of the action). Once the renewals have completed, + the completion handler will automatically issue a + commandline continuation message. However, if there + were no identities to renew, then we have to issue the + message ourselves. + */ + + InterlockedIncrement(&khm_startup.pending_renewals); + + khm_cred_renew_all_identities(); + + pending_renewals = InterlockedDecrement(&khm_startup.pending_renewals); + + if (pending_renewals == 0 && khm_startup.processing) + kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0); + } + break; + + case KMSG_CRED_REFRESH: + kcdb_identity_refresh_all(); + break; + } +} + +void khm_cred_import(void) +{ + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr0(KHERR_NONE, IDS_CTX_IMPORT); + _describe(); + + kmq_post_message(KMSG_CRED, KMSG_CRED_IMPORT, 0, 0); + + _end_task(); +} + +void khm_cred_set_default(void) +{ + khui_action_context ctx; + khm_int32 rv; + + khui_context_get(&ctx); + + if (ctx.identity) { + rv = kcdb_identity_set_default(ctx.identity); + } + + khui_context_release(&ctx); +} + +void khm_cred_destroy_creds(khm_boolean sync, khm_boolean quiet) +{ + khui_action_context * pctx; + + pctx = PMALLOC(sizeof(*pctx)); +#ifdef DEBUG + assert(pctx); +#endif + + khui_context_get(pctx); + + 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]; + wchar_t message[256]; + + LoadString(khm_hInstance, + IDS_ALERT_NOSEL_TITLE, + title, + ARRAYLENGTH(title)); + + LoadString(khm_hInstance, + IDS_ALERT_NOSEL, + message, + ARRAYLENGTH(message)); + + khui_alert_show_simple(title, + message, + KHERR_WARNING); + + khui_context_release(pctx); + PFREE(pctx); + + 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(); +} + +void khm_cred_destroy_identity(khm_handle identity) +{ + khui_action_context * pctx; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + + if (identity == NULL) + return; + + pctx = PMALLOC(sizeof(*pctx)); +#ifdef DEBUG + assert(pctx); +#endif + + khui_context_create(pctx, + KHUI_SCOPE_IDENT, + identity, + KCDB_CREDTYPE_INVALID, + NULL); + + cb = sizeof(idname); + kcdb_identity_get_name(identity, idname, &cb); + + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr1(KHERR_NONE, IDS_CTX_DESTROY_ID, _dupstr(idname)); + _describe(); + + kmq_post_message(KMSG_CRED, + KMSG_CRED_DESTROY_CREDS, + 0, + (void *) pctx); + + _end_task(); +} + +void khm_cred_renew_all_identities(void) +{ + khm_size count; + khm_size cb = 0; + khm_size n_idents = 0; + khm_int32 rv; + wchar_t * ident_names = NULL; + wchar_t * this_ident; + + kcdb_credset_get_size(NULL, &count); + + /* if there are no credentials, we just skip over the renew + action. */ + + if (count == 0) + return; + + ident_names = NULL; + + while (TRUE) { + if (ident_names) { + PFREE(ident_names); + ident_names = NULL; + } + + cb = 0; + rv = kcdb_identity_enum(KCDB_IDENT_FLAG_EMPTY, 0, + NULL, + &cb, &n_idents); + + if (n_idents == 0 || rv != KHM_ERROR_TOO_LONG || + cb == 0) + break; + + ident_names = PMALLOC(cb); + ident_names[0] = L'\0'; + + rv = kcdb_identity_enum(KCDB_IDENT_FLAG_EMPTY, 0, + ident_names, + &cb, &n_idents); + + if (KHM_SUCCEEDED(rv)) + break; + } + + if (ident_names) { + for (this_ident = ident_names; + this_ident && *this_ident; + this_ident = multi_string_next(this_ident)) { + khm_handle ident; + + if (KHM_FAILED(kcdb_identity_create(this_ident, 0, + &ident))) + continue; + + khm_cred_renew_identity(ident); + + kcdb_identity_release(ident); + } + + PFREE(ident_names); + ident_names = NULL; + } +} + +void khm_cred_renew_identity(khm_handle identity) +{ + khui_new_creds * c; + + khui_cw_create_cred_blob(&c); + + c->subtype = KMSG_CRED_RENEW_CREDS; + c->result = KHUI_NC_RESULT_PROCESS; + khui_context_create(&c->ctx, + KHUI_SCOPE_IDENT, + identity, + KCDB_CREDTYPE_INVALID, + NULL); + + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS); + _describe(); + + /* if we are calling this while processing startup actions, we + need to keep track of how many we have issued. */ + if (khm_startup.processing) { + InterlockedIncrement(&khm_startup.pending_renewals); + } + + kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c); + + _end_task(); +} + +void khm_cred_renew_cred(khm_handle cred) +{ + khui_new_creds * c; + + khui_cw_create_cred_blob(&c); + + c->subtype = KMSG_CRED_RENEW_CREDS; + c->result = KHUI_NC_RESULT_PROCESS; + khui_context_create(&c->ctx, + KHUI_SCOPE_CRED, + NULL, + KCDB_CREDTYPE_INVALID, + cred); + + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS); + _describe(); + + /* if we are calling this while processing startup actions, we + need to keep track of how many we have issued. */ + if (khm_startup.processing) { + InterlockedIncrement(&khm_startup.pending_renewals); + } + + kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c); + + _end_task(); +} + +void khm_cred_renew_creds(void) +{ + khui_new_creds * c; + + khui_cw_create_cred_blob(&c); + c->subtype = KMSG_CRED_RENEW_CREDS; + c->result = KHUI_NC_RESULT_PROCESS; + khui_context_get(&c->ctx); + + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS); + _describe(); + + /* if we are calling this while processing startup actions, we + need to keep track of how many we have issued. */ + if (khm_startup.processing) { + InterlockedIncrement(&khm_startup.pending_renewals); + } + + kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c); + + _end_task(); +} + +void khm_cred_change_password(wchar_t * title) +{ + khui_new_creds * nc; + LPNETID_DLGINFO pdlginfo; + khm_size cb; + + if (!khm_cred_begin_dialog()) + return; + + khui_cw_create_cred_blob(&nc); + nc->subtype = KMSG_CRED_PASSWORD; + dialog_nc = nc; + + khui_context_get(&nc->ctx); + + kcdb_identpro_get_ui_cb((void *) &nc->ident_cb); + + assert(nc->ident_cb); + + if (title) { + + if (SUCCEEDED(StringCbLength(title, KHUI_MAXCB_TITLE, &cb))) { + cb += sizeof(wchar_t); + + nc->window_title = PMALLOC(cb); +#ifdef DEBUG + assert(nc->window_title); +#endif + StringCbCopy(nc->window_title, cb, title); + } + } else if (nc->ctx.cb_vparam == sizeof(NETID_DLGINFO) && + (pdlginfo = nc->ctx.vparam) && + pdlginfo->size == NETID_DLGINFO_V1_SZ && + pdlginfo->in.title[0] && + SUCCEEDED(StringCchLength(pdlginfo->in.title, + NETID_TITLE_SZ, + &cb))) { + + cb = (cb + 1) * sizeof(wchar_t); + nc->window_title = PMALLOC(cb); +#ifdef DEBUG + assert(nc->window_title); +#endif + StringCbCopy(nc->window_title, cb, pdlginfo->in.title); + } + + khm_create_newcredwnd(khm_hwnd_main, nc); + + if (nc->hwnd != NULL) { + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr0(KHERR_NONE, IDS_CTX_PASSWORD); + _describe(); + + kmq_post_message(KMSG_CRED, KMSG_CRED_PASSWORD, 0, + (void *) nc); + + _end_task(); + } else { + khui_cw_destroy_cred_blob(nc); + } +} + +void +khm_cred_obtain_new_creds_for_ident(khm_handle ident, wchar_t * title) +{ + khui_action_context ctx; + + if (ident == NULL) + khm_cred_obtain_new_creds(title); + + khui_context_get(&ctx); + + khui_context_set(KHUI_SCOPE_IDENT, + ident, + KCDB_CREDTYPE_INVALID, + NULL, + NULL, + 0, + NULL); + + khm_cred_obtain_new_creds(title); + + khui_context_set_indirect(&ctx); + + khui_context_release(&ctx); +} + +void khm_cred_obtain_new_creds(wchar_t * title) +{ + khui_new_creds * nc; + LPNETID_DLGINFO pdlginfo; + khm_size cb; + + if (!khm_cred_begin_dialog()) + return; + + khui_cw_create_cred_blob(&nc); + nc->subtype = KMSG_CRED_NEW_CREDS; + dialog_nc = nc; + + khui_context_get(&nc->ctx); + + kcdb_identpro_get_ui_cb((void *) &nc->ident_cb); + + if (nc->ident_cb == NULL) { + wchar_t title[256]; + wchar_t msg[512]; + wchar_t suggestion[512]; + khui_alert * a; + + LoadString(khm_hInstance, IDS_ERR_TITLE_NO_IDENTPRO, + title, ARRAYLENGTH(title)); + LoadString(khm_hInstance, IDS_ERR_MSG_NO_IDENTPRO, + msg, ARRAYLENGTH(msg)); + LoadString(khm_hInstance, IDS_ERR_SUGG_NO_IDENTPRO, + suggestion, ARRAYLENGTH(suggestion)); + + khui_alert_create_simple(title, + msg, + KHERR_ERROR, + &a); + khui_alert_set_suggestion(a, suggestion); + + khui_alert_show(a); + + khui_alert_release(a); + + khui_context_release(&nc->ctx); + nc->result = KHUI_NC_RESULT_CANCEL; + khm_cred_end_dialog(nc); + khui_cw_destroy_cred_blob(nc); + return; + } + + if (title) { + if (SUCCEEDED(StringCbLength(title, KHUI_MAXCB_TITLE, &cb))) { + cb += sizeof(wchar_t); + + nc->window_title = PMALLOC(cb); +#ifdef DEBUG + assert(nc->window_title); +#endif + StringCbCopy(nc->window_title, cb, title); + } + } else if (nc->ctx.cb_vparam == sizeof(NETID_DLGINFO) && + (pdlginfo = nc->ctx.vparam) && + pdlginfo->size == NETID_DLGINFO_V1_SZ && + pdlginfo->in.title[0] && + SUCCEEDED(StringCchLength(pdlginfo->in.title, + NETID_TITLE_SZ, + &cb))) { + + cb = (cb + 1) * sizeof(wchar_t); + nc->window_title = PMALLOC(cb); +#ifdef DEBUG + assert(nc->window_title); +#endif + StringCbCopy(nc->window_title, cb, pdlginfo->in.title); + } + + khm_create_newcredwnd(khm_hwnd_main, nc); + + if (nc->hwnd != NULL) { + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr0(KHERR_NONE, IDS_CTX_NEW_CREDS); + _describe(); + + kmq_post_message(KMSG_CRED, KMSG_CRED_NEW_CREDS, 0, + (void *) nc); + + _end_task(); + } else { + khui_context_release(&nc->ctx); + nc->result = KHUI_NC_RESULT_CANCEL; + khm_cred_end_dialog(nc); + khui_cw_destroy_cred_blob(nc); + } +} + +/* this is called by khm_cred_dispatch_process_message and the + kmsg_cred_completion to initiate and continue checked broadcasts of + KMSG_CRED_DIALOG_PROCESS messages. + + Returns TRUE if more KMSG_CRED_DIALOG_PROCESS messages were + posted. */ +BOOL khm_cred_dispatch_process_level(khui_new_creds *nc) +{ + khm_size i,j; + khm_handle subs[KHUI_MAX_NCTYPES]; + int n_subs = 0; + BOOL cont = FALSE; + khui_new_creds_by_type *t, *d; + + /* at each level, we dispatch a wave of notifications to plug-ins + who's dependencies are all satisfied */ + EnterCriticalSection(&nc->cs); + + /* if any types have already completed, we mark them are processed + and skip them */ + for (i=0; i < nc->n_types; i++) { + t = nc->types[i]; + if(t->flags & KHUI_NC_RESPONSE_COMPLETED) + t->flags |= KHUI_NCT_FLAG_PROCESSED; + } + + for(i=0; in_types; i++) { + t = nc->types[i]; + + if((t->flags & KHUI_NCT_FLAG_PROCESSED) || + (t->flags & KHUI_NC_RESPONSE_COMPLETED)) + continue; + + for(j=0; jn_type_deps; j++) { + if(KHM_FAILED(khui_cw_find_type(nc, t->type_deps[j], &d))) + break; + + if(!(d->flags & KHUI_NC_RESPONSE_COMPLETED)) + break; + } + + if(jn_type_deps) /* there are unmet dependencies */ + continue; + + /* all dependencies for this type have been met. */ + subs[n_subs++] = kcdb_credtype_get_sub(t->type); + t->flags |= KHUI_NCT_FLAG_PROCESSED; + cont = TRUE; + } + + LeaveCriticalSection(&nc->cs); + + /* the reason why we are posting messages in batches is because + when the message has completed we know that all the types that + have the KHUI_NCT_FLAG_PROCESSED set have completed processing. + Otherwise we have to individually track each message and update + the type */ + if(n_subs > 0) + kmq_post_subs_msg(subs, n_subs, KMSG_CRED, KMSG_CRED_PROCESS, 0, + (void *) nc); + + return cont; +} + +void +khm_cred_dispatch_process_message(khui_new_creds *nc) +{ + khm_size i; + BOOL pending; + wchar_t wsinsert[512]; + khm_size cbsize; + + /* see if there's anything to do. We can check this without + obtaining a lock */ + if(nc->n_types == 0 || + (nc->subtype == KMSG_CRED_NEW_CREDS && + nc->n_identities == 0) || + (nc->subtype == KMSG_CRED_PASSWORD && + nc->n_identities == 0)) + goto _terminate_job; + + /* check dependencies and stuff first */ + EnterCriticalSection(&nc->cs); + for(i=0; in_types; i++) { + nc->types[i]->flags &= ~ KHUI_NCT_FLAG_PROCESSED; + } + LeaveCriticalSection(&nc->cs); + + /* Consindering all that can go wrong here and the desire to + handle errors here separately from others, we create a new task + for the purpose of tracking the credentials acquisition + process. */ + _begin_task(KHERR_CF_TRANSITIVE); + + /* Describe the context */ + if(nc->subtype == KMSG_CRED_NEW_CREDS) { + cbsize = sizeof(wsinsert); + kcdb_identity_get_name(nc->identities[0], wsinsert, &cbsize); + + _report_sr1(KHERR_NONE, IDS_CTX_PROC_NEW_CREDS, + _cstr(wsinsert)); + _resolve(); + } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { + cbsize = sizeof(wsinsert); + + if (nc->ctx.scope == KHUI_SCOPE_IDENT) + kcdb_identity_get_name(nc->ctx.identity, wsinsert, &cbsize); + else if (nc->ctx.scope == KHUI_SCOPE_CREDTYPE) { + if (nc->ctx.identity != NULL) + kcdb_identity_get_name(nc->ctx.identity, wsinsert, + &cbsize); + else + kcdb_credtype_get_name(nc->ctx.cred_type, wsinsert, + &cbsize); + } else if (nc->ctx.scope == KHUI_SCOPE_CRED) { + kcdb_cred_get_name(nc->ctx.cred, wsinsert, &cbsize); + } else { + StringCbCopy(wsinsert, sizeof(wsinsert), L"(?)"); + } + + _report_sr1(KHERR_NONE, IDS_CTX_PROC_RENEW_CREDS, + _cstr(wsinsert)); + _resolve(); + } else if (nc->subtype == KMSG_CRED_PASSWORD) { + cbsize = sizeof(wsinsert); + kcdb_identity_get_name(nc->identities[0], wsinsert, &cbsize); + + _report_sr1(KHERR_NONE, IDS_CTX_PROC_PASSWORD, + _cstr(wsinsert)); + _resolve(); + } else { + assert(FALSE); + } + + _describe(); + + pending = khm_cred_dispatch_process_level(nc); + + _end_task(); + + if(!pending) + goto _terminate_job; + + return; + + _terminate_job: + if (nc->subtype == KMSG_CRED_RENEW_CREDS) + kmq_post_message(KMSG_CRED, KMSG_CRED_END, 0, (void *) nc); + else + PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_PROCESS_COMPLETE), 0); +} + +void +khm_cred_process_startup_actions(void) { + khm_handle defident = NULL; + + if (!khm_startup.processing) + return; + + if (khm_startup.init || + khm_startup.renew || + khm_startup.destroy || + khm_startup.autoinit) { + kcdb_identity_get_default(&defident); + } + + /* For asynchronous actions, we trigger the action and then exit + the loop. Once the action completes, the completion handler + will trigger a continuation message which will result in this + function getting called again. Then we can proceed with the + rest of the startup actions. */ + do { + if (khm_startup.init) { + if (defident) + khui_context_set(KHUI_SCOPE_IDENT, + defident, + KCDB_CREDTYPE_INVALID, + NULL, NULL, 0, + NULL); + else + khui_context_reset(); + + khm_cred_obtain_new_creds(NULL); + khm_startup.init = FALSE; + break; + } + + if (khm_startup.import) { + khm_cred_import(); + khm_startup.import = FALSE; + + /* we also set the renew command to false here because we + trigger a renewal for all the identities at the end of + the import operation anyway. */ + khm_startup.renew = FALSE; + break; + } + + if (khm_startup.renew) { + LONG pending_renewals; + + /* if there are no credentials, we just skip over the + renew action. */ + + khm_startup.renew = FALSE; + + InterlockedIncrement(&khm_startup.pending_renewals); + + khm_cred_renew_all_identities(); + + pending_renewals = InterlockedDecrement(&khm_startup.pending_renewals); + + if (pending_renewals != 0) + break; + + /* if there were no pending renewals, then we just fall + through. This means that either there were no + identities to renew, or all the renewals completed. If + all the renewals completed, then the commandline + contiuation message wasn't triggered. Either way, we + must fall through if the count is zero. */ + } + + if (khm_startup.destroy) { + + khm_startup.destroy = FALSE; + + if (defident) { + khui_context_set(KHUI_SCOPE_IDENT, + defident, + KCDB_CREDTYPE_INVALID, + NULL, NULL, 0, + NULL); + + khm_cred_destroy_creds(FALSE, FALSE); + break; + } + } + + if (khm_startup.autoinit) { + khm_size count = 0; + khm_handle credset = NULL; + khm_int32 ctype_ident = KCDB_CREDTYPE_INVALID; + khm_int32 delta = 0; + + khm_startup.autoinit = FALSE; + + kcdb_credset_create(&credset); + kcdb_identity_get_type(&ctype_ident); + + kcdb_credset_collect(credset, NULL, + defident, ctype_ident, + &delta); + + kcdb_credset_get_size(credset, &count); + + kcdb_credset_delete(credset); + + if (count == 0) { + if (defident) + khui_context_set(KHUI_SCOPE_IDENT, + defident, + KCDB_CREDTYPE_INVALID, + NULL, NULL, 0, + NULL); + else + khui_context_reset(); + + khm_cred_obtain_new_creds(NULL); + break; + } + } + + if (khm_startup.exit) { + PostMessage(khm_hwnd_main, + WM_COMMAND, + MAKEWPARAM(KHUI_ACTION_EXIT, 0), 0); + khm_startup.exit = FALSE; + break; + } + + /* when we get here, then we are all done with the command + line stuff */ + khm_startup.processing = FALSE; + khm_startup.remote = FALSE; + + kmq_post_message(KMSG_ACT, KMSG_ACT_END_CMDLINE, 0, 0); + } while(FALSE); + + if (defident) + kcdb_identity_release(defident); +} + +void +khm_cred_begin_startup_actions(void) { + khm_handle csp_cw; + + if (khm_startup.seen) + return; + + if (!khm_startup.remote && + KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", 0, &csp_cw))) { + + khm_int32 t = 0; + + khc_read_int32(csp_cw, L"Autoinit", &t); + if (t) + khm_startup.autoinit = TRUE; + + t = 0; + khc_read_int32(csp_cw, L"AutoImport", &t); + if (t) + khm_startup.import = TRUE; + + khc_close_space(csp_cw); + + } + + khm_startup.seen = TRUE; + khm_startup.processing = TRUE; + + khm_cred_process_startup_actions(); +} + +void +khm_cred_refresh(void) { + kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, NULL); +} + +void +khm_cred_addr_change(void) { + khm_handle csp_cw = NULL; + khm_int32 check_net = 0; + + wchar_t * ids = NULL; + wchar_t * t; + khm_size cb; + khm_size n_idents; + + FILETIME ft_now; + FILETIME ft_exp; + FILETIME ft_issue; + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", + 0, &csp_cw))) { + khc_read_int32(csp_cw, L"AutoDetectNet", &check_net); + + khc_close_space(csp_cw); + } + + if (!check_net) + return; + + while(TRUE) { + if (ids) + PFREE(ids); + ids = NULL; + + if (kcdb_identity_enum(KCDB_IDENT_FLAG_VALID | + KCDB_IDENT_FLAG_RENEWABLE, + KCDB_IDENT_FLAG_VALID | + KCDB_IDENT_FLAG_RENEWABLE, + NULL, + &cb, + &n_idents) != KHM_ERROR_TOO_LONG) + break; + + ids = PMALLOC(cb); + + if (KHM_SUCCEEDED + (kcdb_identity_enum(KCDB_IDENT_FLAG_VALID | + KCDB_IDENT_FLAG_RENEWABLE, + KCDB_IDENT_FLAG_VALID | + KCDB_IDENT_FLAG_RENEWABLE, + ids, + &cb, + &n_idents))) + break; + } + + if (!ids) + return; + + GetSystemTimeAsFileTime(&ft_now); + + for (t=ids; t && *t; t = multi_string_next(t)) { + khm_handle ident; + + + if (KHM_FAILED + (kcdb_identity_create(t, 0, &ident))) + continue; + + cb = sizeof(ft_issue); + + if (KHM_SUCCEEDED + (kcdb_identity_get_attr(ident, KCDB_ATTR_ISSUE, NULL, + &ft_issue, &cb)) && + + (cb = sizeof(ft_exp)) && + KHM_SUCCEEDED + (kcdb_identity_get_attr(ident, KCDB_ATTR_EXPIRE, NULL, + &ft_exp, &cb)) && + + CompareFileTime(&ft_now, &ft_exp) < 0) { + + khm_int64 i_issue; + khm_int64 i_exp; + khm_int64 i_now; + + i_issue = FtToInt(&ft_issue); + i_exp = FtToInt(&ft_exp); + i_now = FtToInt(&ft_now); + + if (i_now > (i_issue + i_exp) / 2) { + + khm_cred_renew_identity(ident); + + } + } + + kcdb_identity_release(ident); + } +} diff --git a/src/windows/identity/ui/credfuncs.h b/src/windows/identity/ui/credfuncs.h index 761cbf506..0a4e2531a 100644 --- a/src/windows/identity/ui/credfuncs.h +++ b/src/windows/identity/ui/credfuncs.h @@ -1,93 +1,93 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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_CREDFUNCS_H -#define __KHIMAIRA_CREDFUNCS_H - -void KHMAPI -kmsg_cred_completion(kmq_message *m); - -void -khm_cred_destroy_creds(khm_boolean sync, - khm_boolean quiet); - -void -khm_cred_destroy_identity(khm_handle identity); - -void -khm_cred_renew_all_identities(void); - -void -khm_cred_renew_identity(khm_handle identity); - -void -khm_cred_renew_cred(khm_handle cred); - -void -khm_cred_renew_creds(void); - -void -khm_cred_obtain_new_creds(wchar_t * window_title); - -void -khm_cred_obtain_new_creds_for_ident(khm_handle ident, wchar_t * title); - -void -khm_cred_set_default(void); - -void -khm_cred_change_password(wchar_t * window_title); - -void -khm_cred_dispatch_process_message(khui_new_creds *nc); - -BOOL -khm_cred_dispatch_process_level(khui_new_creds *nc); - -BOOL -khm_cred_is_in_dialog(void); - -khm_int32 -khm_cred_wait_for_dialog(DWORD timeout, khm_int32 * result, - wchar_t * ident, khm_size cb_ident); - -void -khm_cred_begin_startup_actions(void); - -void -khm_cred_process_startup_actions(void); - -void -khm_cred_refresh(void); - -void -khm_cred_addr_change(void); - -void -khm_cred_import(void); - -#endif +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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_CREDFUNCS_H +#define __KHIMAIRA_CREDFUNCS_H + +void KHMAPI +kmsg_cred_completion(kmq_message *m); + +void +khm_cred_destroy_creds(khm_boolean sync, + khm_boolean quiet); + +void +khm_cred_destroy_identity(khm_handle identity); + +void +khm_cred_renew_all_identities(void); + +void +khm_cred_renew_identity(khm_handle identity); + +void +khm_cred_renew_cred(khm_handle cred); + +void +khm_cred_renew_creds(void); + +void +khm_cred_obtain_new_creds(wchar_t * window_title); + +void +khm_cred_obtain_new_creds_for_ident(khm_handle ident, wchar_t * title); + +void +khm_cred_set_default(void); + +void +khm_cred_change_password(wchar_t * window_title); + +void +khm_cred_dispatch_process_message(khui_new_creds *nc); + +BOOL +khm_cred_dispatch_process_level(khui_new_creds *nc); + +BOOL +khm_cred_is_in_dialog(void); + +khm_int32 +khm_cred_wait_for_dialog(DWORD timeout, khm_int32 * result, + wchar_t * ident, khm_size cb_ident); + +void +khm_cred_begin_startup_actions(void); + +void +khm_cred_process_startup_actions(void); + +void +khm_cred_refresh(void); + +void +khm_cred_addr_change(void); + +void +khm_cred_import(void); + +#endif diff --git a/src/windows/identity/ui/credwnd.c b/src/windows/identity/ui/credwnd.c index a3c50dbdb..db13efb9d 100644 --- a/src/windows/identity/ui/credwnd.c +++ b/src/windows/identity/ui/credwnd.c @@ -1,5497 +1,5497 @@ -/* - * 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 - -ATOM khui_credwnd_cls; -khm_int32 khui_cw_flag_id; - -khm_int32 attr_to_action[KCDB_ATTR_MAX_ID + 1]; - -void -khm_set_cw_element_font(wchar_t * name, LOGFONT * pfont) { - khm_handle csp_cw = NULL; - wchar_t * element_name; - - if (name == NULL) - element_name = L"FontBase"; - else - element_name = name; - - if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_WRITE, - &csp_cw))) - return; - - khc_write_binary(csp_cw, element_name, pfont, sizeof(LOGFONT)); - - khc_close_space(csp_cw); -} - -void -khm_get_cw_element_font(HDC hdc, wchar_t * name, BOOL use_default, LOGFONT * pfont) { - khm_handle csp_cw = NULL; - khm_size cb; - wchar_t * element_name; - khm_boolean try_derive = FALSE; - - if (name == NULL) - element_name = L"FontBase"; - else - element_name = name; - - if (use_default) - goto _use_defaults; - - if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", 0, - &csp_cw))) - goto _use_defaults; - - cb = sizeof(LOGFONT); - if (KHM_FAILED(khc_read_binary(csp_cw, element_name, pfont, - &cb)) || - cb != sizeof(LOGFONT)) { - try_derive = TRUE; - } - - if (try_derive) { - cb = sizeof(LOGFONT); - if (!name || - KHM_FAILED(khc_read_binary(csp_cw, L"FontBase", pfont, - &cb)) || - cb != sizeof(LOGFONT)) { - khc_close_space(csp_cw); - goto _use_defaults; - } - - if (!wcscmp(name, L"FontHeaderBold") || - !wcscmp(name, L"FontBold")) { - - pfont->lfWeight = FW_BOLD; - - } - } - - khc_close_space(csp_cw); - - return; - - _use_defaults: - - ZeroMemory(pfont, sizeof(*pfont)); - - if (name == NULL) { - LOGFONT lf = { - -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"}; - - *pfont = lf; - - } else if (!wcscmp(name, L"FontHeader")) { - LOGFONT lf = { - -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"}; - - *pfont = lf; - - } else if (!wcscmp(name, L"FontHeaderBold")) { - LOGFONT lf = { - -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"}; - - *pfont = lf; - - } else if (!wcscmp(name, L"FontNormal")) { - LOGFONT lf = { - -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"}; - - *pfont = lf; - - } else if (!wcscmp(name, L"FontBold")) { - LOGFONT lf = { - -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"}; - - *pfont = lf; - - } else { -#ifdef DEBUG - assert(FALSE); -#endif - } -} - -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) -{ - if(!wcscmp(s, CW_CANAME_FLAGS)) - return CW_CA_FLAGS; - if(!wcscmp(s, CW_CANAME_TYPEICON)) - return CW_CA_TYPEICON; - 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 we aren't saving to a specific view, and the view has been - customized, then we save it to "Custom_0", unless we are in the - mini mode, in which case we save it to "Custom_1" */ - if (!view_name && (tbl->flags & KHUI_CW_TBL_CUSTVIEW)) { - if (!(tbl->flags & KHUI_CW_TBL_EXPIDENT)) { - view_name = L"Custom_0"; - } else { - view_name = L"Custom_1"; - } - } - - 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, ((!(tbl->flags & KHUI_CW_TBL_EXPIDENT))? - L"DefaultView": - L"DefaultViewMini"), view_name); - } - - } else { - csp_view = tbl->csp_view; - } - - if (!csp_view) - goto _cleanup; - - if (tbl->flags & KHUI_CW_TBL_EXPIDENT) { - khc_write_int32(csp_view, L"ExpandedIdentity", 1); - } else { - khm_int32 t; - if (KHM_SUCCEEDED(khc_read_int32(csp_view, L"ExpandedIdentity", &t)) && t) - khc_write_int32(csp_view, L"ExpandedIdentity", 0); - } - - if (tbl->flags & KHUI_CW_TBL_NOHEADER) { - khc_write_int32(csp_view, L"NoHeader", 1); - } else { - khm_int32 t; - if (KHM_SUCCEEDED(khc_read_int32(csp_view, L"NoHeader", &t)) && t) - khc_write_int32(csp_view, L"NoHeader", 0); - } - - 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); - - { - khm_version v = app_version; - - khc_write_binary(csp_view, L"_AppVersion", &v, sizeof(v)); - } - - _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); -} - -static COLORREF -cw_mix_colors(COLORREF c1, COLORREF c2, int alpha) { - int r = (GetRValue(c1) * alpha + GetRValue(c2) * (255 - alpha)) / 255; - int g = (GetGValue(c1) * alpha + GetGValue(c2) * (255 - alpha)) / 255; - int b = (GetBValue(c1) * alpha + GetBValue(c2) * (255 - alpha)) / 255; - -#ifdef DEBUG - assert(alpha >= 0 && alpha < 256); -#endif - - return RGB(r,g,b); -} - -void -cw_load_view(khui_credwnd_tbl * tbl, wchar_t * view, HWND hwnd) { - khm_handle hc_cw = NULL; - khm_handle hc_vs = NULL; - khm_handle hc_v = NULL; - khm_handle hc_cs = NULL; - khm_handle hc_c = NULL; - wchar_t buf[KCONF_MAXCCH_NAME]; - wchar_t * clist = NULL; - khm_size cbsize; - wchar_t * iter = NULL; - int i; - HDC hdc; - LOGFONT log_font; - khm_int32 t; - const wchar_t * viewval; - khm_boolean reopen_csp = FALSE; - - tbl->hwnd = hwnd; - - if (khm_main_wnd_mode == KHM_MAIN_WND_MINI) - viewval = L"DefaultViewMini"; - else - viewval = L"DefaultView"; - - 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))) - goto _exit; - - if(!view) { - cbsize = sizeof(buf); - if(KHM_FAILED(khc_read_string(hc_cw, viewval, buf, &cbsize))) - goto _exit; - view = buf; - } else { - khc_write_string(hc_cw, viewval, view); - } - - /* 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); - else { - /* do nothing */ - } - - kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); - - if(KHM_FAILED(khc_open_space(hc_vs, view, 0, &hc_v))) - goto _exit; - - /* view data is very sensitive to version changes. We need to - check if this configuration data was created with this version - of NetIDMgr. If not, we switch to using a schema handle. */ - { - khm_version this_v = app_version; - khm_version cfg_v; - - cbsize = sizeof(cfg_v); - if (KHM_FAILED(khc_read_binary(hc_v, L"_AppVersion", &cfg_v, &cbsize)) || - khm_compare_version(&cfg_v, &this_v) != 0) { - - khc_close_space(hc_v); - - if (KHM_FAILED(khc_open_space(hc_vs, view, KCONF_FLAG_SCHEMA, - &hc_v)) && - (wcscmp(view, L"Custom_1") || - KHM_FAILED(khc_open_space(hc_vs, L"CompactIdentity", - KCONF_FLAG_SCHEMA, &hc_v)))) { - goto _exit; - } - - reopen_csp = TRUE; - } - } - - tbl->csp_view = hc_v; - - if(KHM_FAILED(khc_open_space(hc_v, L"Columns", - KHM_PERM_READ | (reopen_csp ? KCONF_FLAG_SCHEMA : 0), - &hc_cs))) - goto _exit; - - cbsize = 0; - if(khc_read_multi_string(hc_v, L"ColumnList", NULL, &cbsize) != KHM_ERROR_TOO_LONG) - goto _exit; - - /* temporary */ - clist = PMALLOC(cbsize); - - if(KHM_FAILED(khc_read_multi_string(hc_v, L"ColumnList", clist, &cbsize))) - 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->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); - - if (KHM_SUCCEEDED(khc_read_int32(hc_v, L"ExpandedIdentity", &t)) && t) { - tbl->flags |= KHUI_CW_TBL_EXPIDENT; - } else { - tbl->flags &= ~KHUI_CW_TBL_EXPIDENT; - } - - if (KHM_SUCCEEDED(khc_read_int32(hc_v, L"NoHeader", &t)) && t) { - tbl->flags |= KHUI_CW_TBL_NOHEADER; - } else { - tbl->flags &= ~KHUI_CW_TBL_NOHEADER; - } - - iter = clist; - i = 0; - while(iter) { - khm_int32 attr_id; - - attr_id = cw_get_custom_attr_id(iter); - if(!attr_id) { - /* a KCDB attribute */ - 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) { - 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 */ - tbl->cols[i].title = NULL; - } - - tbl->cols[i].attr_id = attr_id; - - if(KHM_SUCCEEDED(khc_open_space(hc_cs, iter, - KHM_PERM_READ | (reopen_csp ? KCONF_FLAG_SCHEMA : 0), - &hc_c))) { - 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 = 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; - } else { - tbl->cols[i].flags = 0; - tbl->cols[i].width = -1; - tbl->cols[i].sort_index = -1; - } - i++; -_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; - - /* now that all the columns have been loaded, load the view - parameters */ - if(KHM_FAILED(khc_read_int32(hc_v, L"PaddingHorizontal", &(tbl->hpad)))) - khc_read_int32(hc_cw, L"PaddingHorizontal", &(tbl->hpad)); - if(KHM_FAILED(khc_read_int32(hc_v, L"PaddingVertical", &(tbl->vpad)))) - khc_read_int32(hc_cw, L"PaddingVertical", &(tbl->vpad)); - if(KHM_FAILED(khc_read_int32(hc_v, L"PaddingHeader", &(tbl->hpad_h)))) - 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)); - - /* and the font resources and stuff */ - - tbl->flags |= KHUI_CW_TBL_INITIALIZED | KHUI_CW_TBL_COL_DIRTY | KHUI_CW_TBL_ACTIVE; - - /*TODO: the graphics objects should be customizable */ - - hdc = GetWindowDC(hwnd); - - khm_get_cw_element_font(hdc, L"FontHeader", FALSE, &log_font); - tbl->hf_header = CreateFontIndirect(&log_font); - - if(tbl->hf_header && tbl->hwnd_header) - SendMessage(tbl->hwnd_header, WM_SETFONT, (WPARAM) tbl->hf_header, 0); - - khm_get_cw_element_font(hdc, L"FontHeaderBold", FALSE, &log_font); - tbl->hf_bold_header = CreateFontIndirect(&log_font); - - - khm_get_cw_element_font(hdc, L"FontNormal", FALSE, &log_font); - tbl->hf_normal = CreateFontIndirect(&log_font); - - khm_get_cw_element_font(hdc, L"FontBold", FALSE, &log_font); - tbl->hf_bold = CreateFontIndirect(&log_font); - - ReleaseDC(hwnd, hdc); - - khui_bitmap_from_hbmp(&(tbl->kbm_logo_shade), - LoadImage(khm_hInstance, - MAKEINTRESOURCE(IDB_LOGO_SHADE), - IMAGE_BITMAP, - 0, - 0, - LR_DEFAULTCOLOR)); - - { -#define SEL_ALPHA 50 - - COLORREF bg_s = GetSysColor(COLOR_HIGHLIGHT); - COLORREF bg_normal = GetSysColor(COLOR_WINDOW); - COLORREF bg_gray = RGB(240,240,240); - COLORREF bg_hdr = RGB(240,240,240); - COLORREF bg_hdr_warn = RGB(235,235,134); - COLORREF bg_hdr_crit = RGB(235,184,134); - COLORREF bg_hdr_exp = RGB(235,134,134); - COLORREF bg_hdr_def = RGB(184,235,134); - - tbl->cr_normal = GetSysColor(COLOR_WINDOWTEXT); - tbl->cr_s = GetSysColor(COLOR_WINDOWTEXT); - tbl->cr_hdr_outline = RGB(0,0,0); - tbl->cr_hdr_normal = GetSysColor(COLOR_WINDOWTEXT); - tbl->cr_hdr_s = GetSysColor(COLOR_WINDOWTEXT); - tbl->cr_hdr_gray = GetSysColor(COLOR_GRAYTEXT); - tbl->cr_hdr_gray_s = GetSysColor(COLOR_HIGHLIGHTTEXT); - - if (khm_main_wnd_mode == KHM_MAIN_WND_MINI) { - bg_hdr = bg_normal; - tbl->cr_hdr_outline = bg_gray; - } - - tbl->hb_normal = CreateSolidBrush(bg_normal); - tbl->hb_grey = CreateSolidBrush(bg_gray); - tbl->hb_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_normal, SEL_ALPHA)); - - tbl->hb_hdr_bg = CreateSolidBrush(bg_hdr); - tbl->hb_hdr_bg_warn = CreateSolidBrush(bg_hdr_warn); - tbl->hb_hdr_bg_crit = CreateSolidBrush(bg_hdr_crit); - tbl->hb_hdr_bg_exp = CreateSolidBrush(bg_hdr_exp); - tbl->hb_hdr_bg_def = CreateSolidBrush(bg_hdr_def); - - tbl->hb_hdr_bg_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_hdr, SEL_ALPHA)); - tbl->hb_hdr_bg_warn_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_hdr_warn, SEL_ALPHA)); - tbl->hb_hdr_bg_crit_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_hdr_crit, SEL_ALPHA)); - tbl->hb_hdr_bg_exp_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_hdr_exp, SEL_ALPHA)); - tbl->hb_hdr_bg_def_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_hdr_def, SEL_ALPHA)); - } - - tbl->ilist = khui_create_ilist(KHUI_SMICON_CX, KHUI_SMICON_CY-1, 20, 8, 0); - { - HBITMAP hbm; - -#define ADD_BITMAP(i) \ - hbm = LoadImage(khm_hInstance, MAKEINTRESOURCE(i), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); \ - if(hbm) { \ - khui_ilist_add_masked_id(tbl->ilist, hbm, KHUI_TOOLBAR_BGCOLOR, i); \ - DeleteObject(hbm); \ - } - - ADD_BITMAP(IDB_WDG_COLLAPSE); - 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 - } - - if (tbl->flags & KHUI_CW_TBL_EXPIDENT) { - tbl->hi_lg_ident = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP), - IMAGE_ICON, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON), - LR_DEFAULTCOLOR); - } - - tbl->cursor_row = -1; - tbl->scr_left = 0; - tbl->scr_top = 0; - tbl->ext_height = 0; - tbl->ext_width = 0; - - if (reopen_csp) { - khc_close_space(hc_v); - - hc_v = NULL; - - khc_open_space(hc_vs, view, 0, &hc_v); - - tbl->csp_view = hc_v; - } - -_exit: - if(hc_cw) - khc_close_space(hc_cw); - if(hc_vs) - khc_close_space(hc_vs); - 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. */ -} - -khui_credwnd_ident * -cw_find_ident(khui_credwnd_tbl * tbl, khm_handle ident) { - khm_size i; - - for (i=0; i < tbl->n_idents; i++) { - if (kcdb_identity_is_equal(ident, tbl->idents[i].ident)) - break; - } - - if (i < tbl->n_idents) - return &tbl->idents[i]; - else - return NULL; -} - -khm_int32 KHMAPI -cw_credset_iter_func(khm_handle cred, void * rock) { - khui_credwnd_tbl * tbl = (khui_credwnd_tbl *) rock; - khm_handle ident = NULL; - khm_size i; - khui_credwnd_ident * cwi = NULL; - khm_int32 cred_credtype = KCDB_CREDTYPE_INVALID; - khm_int32 cred_flags = 0; - - kcdb_cred_get_identity(cred, &ident); - - if (ident == NULL) - goto _cleanup; - - for (i=0; i < tbl->n_idents; i++) { - if (kcdb_identity_is_equal(ident, tbl->idents[i].ident)) - break; - } - - if (i >= tbl->n_idents) { - khm_size cb; - - /* need to add this one */ - if (tbl->n_idents == tbl->nc_idents) { - tbl->nc_idents = UBOUNDSS(tbl->n_idents + 1, - CW_IDENT_ALLOC_INCR, - CW_IDENT_ALLOC_INCR); -#ifdef DEBUG - assert(tbl->nc_idents > tbl->n_idents); -#endif - tbl->idents = PREALLOC(tbl->idents, sizeof(tbl->idents[0]) * tbl->nc_idents); -#ifdef DEBUG - assert(tbl->idents); -#endif - ZeroMemory(&tbl->idents[tbl->n_idents], - sizeof(tbl->idents[0]) * (tbl->nc_idents - tbl->n_idents)); - } - - i = tbl->n_idents; - cwi = &tbl->idents[tbl->n_idents++]; - - ZeroMemory(cwi, sizeof(*cwi)); - - cwi->ident = ident; - kcdb_identity_hold(ident); - - cb = sizeof(cwi->name); - kcdb_identity_get_name(ident, cwi->name, &cb); - } - - cwi = &tbl->idents[i]; - - /* this is the first time we are seeing this identity. */ - if (cwi->credcount == 0) { - khm_size cb; - - cb = sizeof(cwi->credtype); - if (KHM_SUCCEEDED(kcdb_identity_get_attr(ident, KCDB_ATTR_TYPE, NULL, - &cwi->credtype, &cb))) { - cwi->credtype_name[0] = L'\0'; - - cb = sizeof(cwi->credtype_name); - if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_TYPE_NAME, NULL, - &cwi->credtype, &cb))) { - cb = sizeof(cwi->credtype_name); - kcdb_credtype_describe(cwi->credtype, cwi->credtype_name, - &cb, KCDB_TS_SHORT); - } - } else { - cwi->credtype = KCDB_CREDTYPE_INVALID; - cwi->credtype_name[0] = L'\0'; - } - - cb = sizeof(cwi->ft_expire); - if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_EXPIRE, NULL, - &cwi->ft_expire, &cb))) { - cwi->ft_expire = IntToFt(0); - } - - kcdb_identity_get_flags(cwi->ident, &cwi->ident_flags); - } - - cwi->credcount++; - - kcdb_cred_get_type(cred, &cred_credtype); - if (cred_credtype >= 0 && cred_credtype == cwi->credtype) { - cwi->id_credcount++; - - kcdb_cred_get_flags(cred, &cred_flags); - if (cred_flags & KCDB_CRED_FLAG_INITIAL) { - cwi->init_credcount++; - } - } - - _cleanup: - if (ident) - kcdb_identity_release(ident); - - return KHM_ERROR_SUCCESS; -} - -void -cw_update_creds(khui_credwnd_tbl * tbl) -{ - kcdb_cred_comp_field * fields; - kcdb_cred_comp_order comp_order; - int i; - khm_int32 n; - khm_int32 delta; - khm_handle hc; - khm_int32 flags; - - if(!tbl->credset) { - if(KHM_FAILED(kcdb_credset_create(&(tbl->credset)))) - return; - } - - kcdb_credset_purge(tbl->credset); - - kcdb_identity_refresh_all(); - - kcdb_credset_collect( - tbl->credset, - NULL, - NULL, - KCDB_CREDTYPE_ALL, - &delta); - - /* now we need to figure out how to sort the credentials */ - fields = PMALLOC(sizeof(kcdb_cred_comp_field) * tbl->n_cols); - ZeroMemory(fields, sizeof(kcdb_cred_comp_field) * tbl->n_cols); - - 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)) { - int si; - /* we need to sort by this column */ - si = tbl->cols[i].sort_index; - - if(si < 0 || si >= (int) tbl->n_cols) - { - /* this shouldn't happen */ - tbl->cols[i].flags &= ~(KHUI_CW_COL_SORT_INC | - KHUI_CW_COL_SORT_DEC | - KHUI_CW_COL_GROUP); - continue; - } - - fields[si].attrib = tbl->cols[i].attr_id; - if(tbl->cols[i].flags & KHUI_CW_COL_SORT_DEC) - fields[si].order = KCDB_CRED_COMP_DECREASING; - else - fields[si].order = KCDB_CRED_COMP_INCREASING; - - /* special case. if we are sorting by name, we group - initial tickets before non-initial tickets. - - Also, if we are sorting by credential type name, then - we allow the primary credential type first before - others. */ - - if (fields[si].attrib == KCDB_ATTR_NAME || - fields[si].attrib == KCDB_ATTR_TYPE_NAME) - fields[si].order |= KCDB_CRED_COMP_INITIAL_FIRST; - - if(si >= n) - n = si+1; - } - } - - /* we assume that the sort order is sane */ - /*TODO: don't assume; check if the sort order is sane */ - - comp_order.nFields = n; - comp_order.fields = fields; - - kcdb_credset_sort(tbl->credset, - kcdb_cred_comp_generic, - (void *) &comp_order); - - /* also, if new credentials were added, initialize the UI flag - attribute to 0 */ - if(delta & KCDB_DELTA_ADD) { - khm_size s; - - kcdb_credset_get_size(tbl->credset, &s); - 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, - NULL, NULL))) { - flags = 0; - kcdb_cred_set_attr(hc, khui_cw_flag_id, &flags, sizeof(flags)); - } - kcdb_cred_release(hc); - } - } - - /* refresh the per-identity information */ - for (i=0; i < (int) tbl->n_idents; i++) { - tbl->idents[i].credcount = 0; - tbl->idents[i].id_credcount = 0; - tbl->idents[i].init_credcount = 0; - } - - kcdb_credset_apply(tbl->credset, cw_credset_iter_func, (void *) tbl); - - if (fields) - PFREE(fields); -} - -void -cw_del_outline(khui_credwnd_outline *o) { - khui_credwnd_outline * c; - if(!o) - return; - - /* the outline object is still in a list */ - if(o->next || o->prev) - return; - - if(o->header) - PFREE(o->header); - - if ((o->flags & KHUI_CW_O_DATAALLOC) && - o->data) - PFREE(o->data); - - if ((o->flags & KHUI_CW_O_RELIDENT) && - o->data) - kcdb_identity_release((khm_handle) o->data); - - LPOP(&(o->children), &c); - while(c) { - cw_del_outline(c); - LPOP(&(o->children), &c); - } - - ZeroMemory(o, sizeof(*o)); - PFREE(o); -} - -khui_credwnd_outline * -cw_new_outline_node(wchar_t * heading) { - khui_credwnd_outline * o; - size_t cblen; - - o = PMALLOC(sizeof(khui_credwnd_outline)); - ZeroMemory(o, sizeof(khui_credwnd_outline)); - - if(SUCCEEDED(StringCbLength(heading, KHUI_MAXCB_HEADING, &cblen))) { - cblen += sizeof(wchar_t); - o->header = PMALLOC(cblen); - StringCbCopy(o->header, cblen, heading); - } - o->start = -1; - - return o; -} - -/* buf is a handle to a credential or an identity. the kcdb_buf_* - functions work with either. */ -khm_int32 -cw_get_buf_exp_flags(khui_credwnd_tbl * tbl, khm_handle buf) -{ - khm_int32 flags; - long s; - FILETIME ft_expire; - FILETIME ft_current; - FILETIME ft_difference; - khm_size cbsize; - - cbsize = sizeof(ft_expire); - if(KHM_FAILED(kcdb_buf_get_attr(buf, KCDB_ATTR_EXPIRE, NULL, - &ft_expire, &cbsize))) - return 0; - - GetSystemTimeAsFileTime(&ft_current); - ft_difference = FtSub(&ft_expire, &ft_current); - - s = FtIntervalToSeconds(&ft_difference); - - flags = 0; - if(s < 0) - flags = CW_EXPSTATE_EXPIRED; - else if(s < tbl->threshold_critical) - flags = CW_EXPSTATE_CRITICAL; - else if(s < tbl->threshold_warn) - flags = CW_EXPSTATE_WARN; - else - flags = CW_EXPSTATE_NONE; - - return flags; -} - -void cw_update_outline(khui_credwnd_tbl * tbl); - -static void -cw_update_selection_state(khui_credwnd_tbl * tbl); - -VOID CALLBACK -cw_timer_proc(HWND hwnd, - UINT uMsg, - UINT_PTR idEvent, - DWORD dwTime) -{ - khui_credwnd_tbl * tbl; - khui_credwnd_row * r; - khm_int32 nflags; - int nr; - long ms; - FILETIME ft; - khm_size cbsize; - int timer_set = 0; - - KillTimer(hwnd, idEvent); - - tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - r = (khui_credwnd_row *) idEvent; - r->flags &= ~KHUI_CW_ROW_TIMERSET; - - nr = (int)(r - tbl->rows); - - if(nr < 0 || nr >= tbl->n_rows) - return; - - if(r->flags & KHUI_CW_ROW_CRED) { - - nflags = cw_get_buf_exp_flags(tbl, (khm_handle) r->data); - if((r->flags & CW_EXPSTATE_MASK) != nflags) { - /* flags have changed */ - /* the outline needs to be updated */ - cw_update_outline(tbl); - InvalidateRect(tbl->hwnd, NULL, FALSE); - } else { - /* just invalidate the row */ - RECT rc,rr,ri; - - GetClientRect(tbl->hwnd, &rc); - rc.top += tbl->header_height; - - rr = r->r_ext; - OffsetRect(&rr, 0, tbl->header_height - tbl->scr_top); - - if(IntersectRect(&ri, &rc, &rr)) - InvalidateRect(tbl->hwnd, &ri, FALSE); - - cbsize = sizeof(ft); - 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); - timer_set = 1; - } - } - - if (timer_set) - r->flags |= KHUI_CW_ROW_TIMERSET; - } - } else { - khui_credwnd_outline * o; - khui_credwnd_ident * cwi; - FILETIME ft_now; - - o = (khui_credwnd_outline *) r->data; -#ifdef DEBUG - assert(r->flags & KHUI_CW_ROW_EXPVIEW); - assert(o->attr_id == KCDB_ATTR_ID); - assert(tbl->flags & KHUI_CW_TBL_EXPIDENT); -#endif - - nflags = cw_get_buf_exp_flags(tbl, (khm_handle) o->data); - if ((o->flags & CW_EXPSTATE_MASK) != nflags) { - cw_update_outline(tbl); - InvalidateRect(tbl->hwnd, NULL, FALSE); - } else { - RECT rc, rr, ri; - - GetClientRect(tbl->hwnd, &rc); - rc.top += tbl->header_height; - - rr = r->r_ext; - OffsetRect(&rr, 0, tbl->header_height - tbl->scr_top); - - if (IntersectRect(&ri, &rc, &rr)) - InvalidateRect(tbl->hwnd, &ri, FALSE); - - cwi = cw_find_ident(tbl, o->data); - - GetSystemTimeAsFileTime(&ft_now); - if (CompareFileTime(&cwi->ft_expire, &ft_now) > 0) { - ft = FtSub(&cwi->ft_expire, &ft_now); - ms = FtIntervalMsToRepChange(&ft); - if (ms > 0) { - SetTimer(tbl->hwnd, (UINT_PTR) r, ms + 100, cw_timer_proc); - timer_set = 1; - } - } - - if (timer_set) - r->flags |= KHUI_CW_ROW_TIMERSET; - } - } -} - -void -cw_set_tbl_row_cred(khui_credwnd_tbl * tbl, - int row, - khm_handle cred, - int col) -{ - FILETIME ft; - long ms; - khm_size cbsize; - - if((int) tbl->n_total_rows <= row) { - /* we need to resize the allocation */ - khui_credwnd_row * newrows; - int newsize; - - newsize = UBOUNDSS(row+1,KHUI_CW_ROW_INITIAL, KHUI_CW_ROW_INCREMENT); - newrows = PMALLOC(sizeof(khui_credwnd_row) * newsize); - memcpy(newrows, tbl->rows, sizeof(khui_credwnd_row) * tbl->n_rows); - PFREE(tbl->rows); - tbl->rows = newrows; - tbl->n_total_rows = newsize; - } - - tbl->rows[row].col = col; - tbl->rows[row].data = cred; - tbl->rows[row].flags = KHUI_CW_ROW_CRED; - - /* Set any required timer events */ - cbsize = sizeof(ft); - if(KHM_SUCCEEDED(kcdb_cred_get_attr(cred, KCDB_ATTR_TIMELEFT, NULL, &ft, &cbsize))) { - ms = FtIntervalMsToRepChange(&ft); - if(ms > 0) { - SetTimer(tbl->hwnd, (UINT_PTR) &(tbl->rows[row]), ms + 100, cw_timer_proc); - tbl->rows[row].flags |= KHUI_CW_ROW_TIMERSET; - } - } -} - -void -cw_set_tbl_row_header(khui_credwnd_tbl * tbl, - int row, int col, - khui_credwnd_outline * o) -{ - if((int) tbl->n_total_rows <= row) { - /* we need to resize the allocation */ - khui_credwnd_row * newrows; - int newsize; - - newsize = UBOUNDSS(row+1,KHUI_CW_ROW_INITIAL, KHUI_CW_ROW_INCREMENT); - newrows = PMALLOC(sizeof(khui_credwnd_row) * newsize); - memcpy(newrows, tbl->rows, sizeof(khui_credwnd_row) * tbl->n_rows); - PFREE(tbl->rows); - tbl->rows = newrows; - tbl->n_total_rows = newsize; - } - - tbl->rows[row].col = col; - tbl->rows[row].data = (khm_handle) o; - tbl->rows[row].flags = KHUI_CW_ROW_HEADER; - if(o->flags & KHUI_CW_O_SELECTED) - tbl->rows[row].flags |= KHUI_CW_ROW_SELECTED; - - /* if we are showing expanded identity information, we need to set - a timer so that we can update the identity row when the - identity changes. */ - if ((tbl->flags & KHUI_CW_TBL_EXPIDENT) && - tbl->cols[col].attr_id == KCDB_ATTR_ID_NAME) { - - khui_credwnd_ident * cwi; - - tbl->rows[row].flags |= KHUI_CW_ROW_EXPVIEW; - - cwi = cw_find_ident(tbl, o->data); - if (cwi && FtToInt(&cwi->ft_expire) != 0) { - FILETIME ft; - FILETIME ft_now; - - ft = cwi->ft_expire; - GetSystemTimeAsFileTime(&ft_now); - - if (CompareFileTime(&ft, &ft_now) > 0) { - long ms; - - ft = FtSub(&ft, &ft_now); - ms = FtIntervalMsToRepChange(&ft); - if (ms > 0) { - SetTimer(tbl->hwnd, (UINT_PTR) &(tbl->rows[row]), ms + 100, - cw_timer_proc); - tbl->rows[row].flags |= KHUI_CW_ROW_TIMERSET; - } - } - } - } -} - -static int -iwcscmp(const void * p1, const void * p2) { - const wchar_t * s1 = *(wchar_t **) p1; - const wchar_t * s2 = *(wchar_t **) p2; - - return wcscmp(s1, s2); -} - -void -cw_update_outline(khui_credwnd_tbl * tbl) -{ - int i,j,n_rows; - int level; - int visible; - 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 - group the display by. Say we are grouping by identity and then - by type, then grouping[0]=col# of identity and grouping[1]=col# - of type */ - khm_int32 * grouping = NULL; - khui_credwnd_outline * ol = NULL; - int n_grouping; - wchar_t buf[256]; - khm_size cbbuf; - khm_int32 flags; - int selected; - khm_int32 expstate = 0; - - /* this is called after calling cw_update_creds, so we assume - that the credentials are all loaded and sorted according to - grouping rules */ - - /* if the columns have changed, then any outline info we have - cached are unreliable */ - if(tbl->flags & KHUI_CW_TBL_COL_DIRTY) { - khui_credwnd_outline * o; - LPOP(&(tbl->outline), &o); - while(o) { - cw_del_outline(o); - LPOP(&(tbl->outline), &o); - } - tbl->n_rows = 0; - } - - /* Otherwise, we should reset the outline indices. Just the first - level is enough */ - if (tbl->outline) { - khui_credwnd_outline * o; - - o = tbl->outline; - while(o) { - o->start = -1; - o = LNEXT(o); - } - } - - /* determine the grouping order */ - grouping = PMALLOC(sizeof(khm_int32) * tbl->n_cols); - for(i=0; i < (int) tbl->n_cols; i++) - grouping[i] = -1; - n_grouping = 0; - - for(i=0; i < (int) tbl->n_cols; i++) { - /* since cw_update_creds has run, the KHUI_CW_COL_GROUP flag - only exists for columns that has a valid sort_index */ - if(tbl->cols[i].flags & KHUI_CW_COL_GROUP) { - grouping[tbl->cols[i].sort_index] = i; - if(n_grouping <= tbl->cols[i].sort_index) - n_grouping = tbl->cols[i].sort_index + 1; - } - } - - /* if we have sorted by an index without grouping by it, we can't - establish any grouping beyond that index. */ - for(i=0; i < n_grouping; i++) { - if(grouping[i] == -1) - break; - } - n_grouping = i; - - if(!tbl->rows) { - /* we haven't allocated memory yet */ - tbl->n_total_rows = KHUI_CW_ROW_INITIAL; - tbl->n_rows = 0; - tbl->rows = PMALLOC(sizeof(khui_credwnd_row) * tbl->n_total_rows); - } else { - /* kill any pending timers */ - for(i=0; i < (int) tbl->n_rows; i++) - if(tbl->rows[i].flags & KHUI_CW_ROW_TIMERSET) - { - KillTimer(tbl->hwnd, (UINT_PTR) &(tbl->rows[i])); - tbl->rows[i].flags &= ~KHUI_CW_ROW_TIMERSET; - } - } - - if(KHM_FAILED(kcdb_credset_get_size(tbl->credset, &n_creds))) - goto _exit; - - n_rows = 0; - prevcred = NULL; - ol = NULL; - - for(i=0; i < (int) n_creds; i++) { - if(KHM_FAILED(kcdb_credset_get_cred(tbl->credset, i, &thiscred))) - continue; - - /* if this credential appears to be the same as another for - this view, we skip it. */ - if(prevcred && n_grouping > 0) { - for(j=0; j < (int) tbl->n_cols; j++) { - if(kcdb_creds_comp_attr(prevcred, thiscred, - tbl->cols[j].attr_id)) - break; - } - - if(j >= (int) tbl->n_cols) { - if (n_rows > 0) { - tbl->rows[n_rows - 1].idx_end = i; - } - continue; - } - } - - if(!prevcred) - level = 0; - else { - for(j=0; j < n_grouping; j++) { - /* determine the grouping level at which thiscred - differs from prevcred */ - if(kcdb_creds_comp_attr(prevcred,thiscred, - tbl->cols[grouping[j]].attr_id)) - break; - } - level = j; - } - - /* now we have to walk up until we get to the parent of the - outline level we should be in */ - while(ol && ol->level >= level) { - ol->length = n_rows - ol->start; - ol->idx_end = i - 1; - ol = TPARENT(ol); - } - - if(ol) { - visible = (ol->flags & KHUI_CW_O_VISIBLE) && - (ol->flags & KHUI_CW_O_EXPAND); - selected = (ol->flags & KHUI_CW_O_SELECTED); - } else { - visible = TRUE; - selected = FALSE; - } - - /* now ol points to an outline node at the next highest level - or is NULL if level = 0 */ - - for(j=level; j < n_grouping; j++) { - khui_credwnd_outline * to; - /* now we search for an outline object at the next level - which matches the heading */ - cbbuf = sizeof(buf); - buf[0] = L'\0'; - if(KHM_FAILED - (kcdb_cred_get_attr_string(thiscred, - tbl->cols[grouping[j]].attr_id, - buf, &cbbuf, 0))) { - cbbuf = sizeof(wchar_t); - buf[0] = L'\0'; - } - - if(ol) - to = TFIRSTCHILD(ol); - else - to = tbl->outline; - - while(to) { - if(!wcscmp(buf, to->header)) - break; - to = LNEXT(to); - } - - if(to) { - /* found it */ - ol = to; - } else { - /* not found. create */ - to = cw_new_outline_node(buf); - if(ol) { - TADDCHILD(ol, to); - } else { - LPUSH(&(tbl->outline), to); - } - ol = to; - ol->flags = KHUI_CW_O_EXPAND; - ol->level = j; - ol->col = grouping[j]; - - if(tbl->cols[grouping[j]].attr_id == KCDB_ATTR_ID_NAME) { - khm_handle h; - if(KHM_SUCCEEDED(kcdb_identity_create(buf, 0, &h))) { - ol->attr_id = KCDB_ATTR_ID; - ol->data = (void *) h; - - /* the outline only lasts as long as the - credential, and the credential has a hold - on the identity. */ - kcdb_identity_release(h); - } - else - ol->data = 0; - } else if(tbl->cols[grouping[j]].attr_id == - KCDB_ATTR_TYPE_NAME) { - khm_int32 t; - - ol->attr_id = KCDB_ATTR_TYPE; - if(KHM_SUCCEEDED(kcdb_cred_get_type(thiscred, &t))) - ol->data = (void *)(ssize_t) t; - else - ol->data = (void *)(ssize_t) KCDB_CREDTYPE_INVALID; - } else { - khm_int32 rv; - khm_int32 alt_id; - kcdb_attrib * attrib; - - rv = - kcdb_attrib_get_info(tbl->cols[grouping[j]].attr_id, - &attrib); - assert(KHM_SUCCEEDED(rv)); - - if (attrib->flags & KCDB_ATTR_FLAG_ALTVIEW) - alt_id = attrib->alt_id; - else - alt_id = tbl->cols[grouping[j]].attr_id; - - ol->attr_id = alt_id; - - kcdb_attrib_release_info(attrib); - - rv = kcdb_cred_get_attr(thiscred, - alt_id, - NULL, - NULL, - &cbbuf); - if (rv != KHM_ERROR_TOO_LONG || cbbuf == 0) { - ol->data = NULL; - } else { - ol->data = PMALLOC(cbbuf); - assert(ol->data); - rv = kcdb_cred_get_attr(thiscred, - alt_id, - NULL, - ol->data, - &cbbuf); - assert(KHM_SUCCEEDED(rv)); - ol->cb_data = cbbuf; - ol->flags |= KHUI_CW_O_DATAALLOC; - } - } - } - - /* now ol points at the node at level j we want to be - in */ - ol->start = n_rows; - ol->length = 0; - ol->idx_start = i; - ol->idx_end = i; - ol->flags &= ~(CW_EXPSTATE_MASK | - KHUI_CW_O_SHOWFLAG | - KHUI_CW_O_STICKY | - KHUI_CW_O_EMPTY); - - /* if the outline node is for an identity, then we have to - check the expiration state for the identity. */ - - if (ol->attr_id == KCDB_ATTR_ID) { - khm_handle ident = (khm_handle) ol->data; - - flags = cw_get_buf_exp_flags(tbl, ident); - - if (flags) { - ol->flags |= flags; - ol->flags |= KHUI_CW_O_SHOWFLAG; - expstate |= flags; - } else if (grouping[j] == tbl->n_cols - 1) { - /* if we aren't showing any creds under this - outline level, we should also show any - flags. */ - ol->flags |= KHUI_CW_O_SHOWFLAG; - } - } - - if (grouping[j] == tbl->n_cols - 1) { - ol->flags |= KHUI_CW_O_NOOUTLINE; - } else { - ol->flags &= ~KHUI_CW_O_NOOUTLINE; - } - - if(selected) { - ol->flags |= KHUI_CW_O_SELECTED; - } - if(visible) { - cw_set_tbl_row_header(tbl, n_rows, grouping[j], ol); - n_rows ++; - ol->flags |= KHUI_CW_O_VISIBLE; - } else { - ol->flags &= ~KHUI_CW_O_VISIBLE; - } - visible = visible && (ol->flags & KHUI_CW_O_EXPAND); - selected = (selected || (ol->flags & KHUI_CW_O_SELECTED)); - - } - - /* we need to do this here too just in case we were already at - the level we were supposed to be in */ - if (ol) - visible = visible && (ol->flags & KHUI_CW_O_EXPAND); - - if(visible && n_grouping > 0 && - grouping[n_grouping - 1] < tbl->n_cols - 1) { - khm_int32 c_flags; - - cw_set_tbl_row_cred(tbl, n_rows, thiscred, - grouping[n_grouping-1]); - - flags = cw_get_buf_exp_flags(tbl, thiscred); - if(flags) { - tbl->rows[n_rows].flags |= flags; - } - - kcdb_cred_get_flags(thiscred, &c_flags); - if(selected || - (c_flags & KCDB_CRED_FLAG_SELECTED)) { - tbl->rows[n_rows].flags |= KHUI_CW_ROW_SELECTED; - } - - tbl->rows[n_rows].idx_start = i; - tbl->rows[n_rows].idx_end = i; - - n_rows++; - } - - if(prevcred) - kcdb_cred_release(prevcred); - prevcred = thiscred; - } - - while(ol) { - ol->length = n_rows - ol->start; - ol->idx_end = i - 1; - ol = TPARENT(ol); - } - - if(prevcred) { - kcdb_cred_release(prevcred); - prevcred = NULL; - } - - /* Add any default identities with no credentials and sticky - identities that we haven't seen yet */ - if (n_grouping > 0 && - tbl->cols[grouping[0]].attr_id == KCDB_ATTR_ID_NAME) { - - khui_credwnd_outline * o; - wchar_t * idnames = NULL; - wchar_t * t; - khm_size n_idents; - khm_size cb_names; - wchar_t ** idarray = NULL; - int i; - - /* see if the defualt identity is in the list */ - { - khm_handle id_def = NULL; - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - khm_int32 flags; - - if (KHM_FAILED(kcdb_identity_get_default(&id_def))) { - goto done_with_defident; - } - - kcdb_identity_get_flags(id_def, &flags); - cb = sizeof(idname); - kcdb_identity_get_name(id_def, idname, &cb); - - for (o = tbl->outline; o; o = LNEXT(o)) { - if (!wcscmp(idname, o->header)) - break; - } - - if (o == NULL) { - o = cw_new_outline_node(idname); - LPUSH(&tbl->outline, o); - o->flags = KHUI_CW_O_VISIBLE | KHUI_CW_O_RELIDENT | KHUI_CW_O_EMPTY; - o->level = 0; - o->col = grouping[0]; - o->data = id_def; - o->attr_id = KCDB_ATTR_ID; - o->start = -1; - } else { - kcdb_identity_release(id_def); - } - - if (o->start != -1) - goto done_with_defident; - - if (flags & KCDB_IDENT_FLAG_STICKY) - o->flags |= KHUI_CW_O_STICKY; - else - o->flags &= ~KHUI_CW_O_STICKY; - - o->start = n_rows; - o->length = 1; - o->idx_start = -1; - o->idx_end = -1; - - if (grouping[0] == tbl->n_cols - 1) - o->flags |= KHUI_CW_O_NOOUTLINE; - - cw_set_tbl_row_header(tbl, n_rows, grouping[0], o); - - n_rows ++; - - done_with_defident: - ; - } - - if (kcdb_identity_enum(KCDB_IDENT_FLAG_STICKY, - KCDB_IDENT_FLAG_STICKY, - NULL, - &cb_names, - &n_idents) != KHM_ERROR_TOO_LONG || - n_idents == 0 || - cb_names == 0) - goto _cleanup_sticky; - - idnames = PMALLOC(cb_names); - idarray = PMALLOC(n_idents * sizeof(*idarray)); -#ifdef DEBUG - assert(idnames); - assert(idarray); -#endif - - if (KHM_FAILED(kcdb_identity_enum(KCDB_IDENT_FLAG_STICKY, - KCDB_IDENT_FLAG_STICKY, - idnames, - &cb_names, - &n_idents))) - goto _cleanup_sticky; - - for (i=0, t=idnames; t && *t; t = multi_string_next(t), i++) { - idarray[i] = t; - } - - qsort(idarray, n_idents, sizeof(*idarray), iwcscmp); - - for (i=0; i < (int) n_idents; i++) { - khm_handle h; - - if (KHM_FAILED(kcdb_identity_create(idarray[i], - KCDB_IDENT_FLAG_CREATE, &h))) - continue; - - for (o = tbl->outline; o; o = LNEXT(o)) { - if (!wcscmp(idarray[i], o->header)) - break; - } - - if (o) { - /* found it */ - if (o->start != -1) /* already visible? */ - continue; - o->flags &= KHUI_CW_O_RELIDENT; - o->flags |= KHUI_CW_O_STICKY | KHUI_CW_O_VISIBLE | KHUI_CW_O_EMPTY; - - if (!kcdb_identity_is_equal(o->data, h)) { - if (o->flags & KHUI_CW_O_RELIDENT) - kcdb_identity_release(o->data); - o->data = h; - o->flags |= KHUI_CW_O_RELIDENT; - kcdb_identity_hold(h); - } - } else { - /* not found. create */ - o = cw_new_outline_node(idarray[i]); - LPUSH(&tbl->outline, o); - o->flags = KHUI_CW_O_STICKY | KHUI_CW_O_VISIBLE | KHUI_CW_O_EMPTY | KHUI_CW_O_RELIDENT; - o->level = 0; - o->col = grouping[0]; - o->data = h; - kcdb_identity_hold(h); - o->attr_id = KCDB_ATTR_ID; - } - - if (grouping[0] == tbl->n_cols - 1) - o->flags |= KHUI_CW_O_NOOUTLINE; - - kcdb_identity_release(h); - - o->flags &= ~KHUI_CW_O_EXPAND; - o->start = n_rows; - o->length = 1; - o->idx_start = -1; - o->idx_end = -1; - - cw_set_tbl_row_header(tbl, n_rows, grouping[0], o); - - n_rows ++; - } - - _cleanup_sticky: - if (idnames) - PFREE(idnames); - if (idarray) - PFREE(idarray); - } - - tbl->n_rows = n_rows; - 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); - - /* note that the expstate is derived from whether or not - * we have expiration states set for any active identities */ - if (n_creds == 0) - khm_notify_icon_expstate(KHM_NOTIF_EMPTY); - else if ((expstate & CW_EXPSTATE_EXPIRED) == CW_EXPSTATE_EXPIRED) - khm_notify_icon_expstate(KHM_NOTIF_EXP); - else if ((expstate & CW_EXPSTATE_WARN) == CW_EXPSTATE_WARN || - (expstate & CW_EXPSTATE_CRITICAL) == CW_EXPSTATE_CRITICAL) - khm_notify_icon_expstate(KHM_NOTIF_WARN); - else - khm_notify_icon_expstate(KHM_NOTIF_OK); -} - -void -cw_unload_view(khui_credwnd_tbl * tbl) -{ -#define SafeDeleteObject(o) \ - do { \ - if(o) { \ - DeleteObject(o); \ - o = NULL; \ - } \ - } while(0) - - SafeDeleteObject(tbl->hf_header); - SafeDeleteObject(tbl->hf_normal); - SafeDeleteObject(tbl->hf_bold); - SafeDeleteObject(tbl->hf_bold_header); - - SafeDeleteObject(tbl->hb_grey); - SafeDeleteObject(tbl->hb_normal); - SafeDeleteObject(tbl->hb_s); - - SafeDeleteObject(tbl->hb_hdr_bg); - SafeDeleteObject(tbl->hb_hdr_bg_crit); - SafeDeleteObject(tbl->hb_hdr_bg_exp); - SafeDeleteObject(tbl->hb_hdr_bg_warn); - SafeDeleteObject(tbl->hb_hdr_bg_def); - - SafeDeleteObject(tbl->hb_hdr_bg_s); - SafeDeleteObject(tbl->hb_hdr_bg_crit_s); - SafeDeleteObject(tbl->hb_hdr_bg_exp_s); - SafeDeleteObject(tbl->hb_hdr_bg_warn_s); - SafeDeleteObject(tbl->hb_hdr_bg_def_s); - -#undef SafeDeleteObject - - if (tbl->hi_lg_ident) { - DestroyIcon(tbl->hi_lg_ident); - tbl->hi_lg_ident = NULL; - } - - if(tbl->credset) { - kcdb_credset_delete(tbl->credset); - tbl->credset = NULL; - } - if(tbl->ilist) { - khui_delete_ilist(tbl->ilist); - tbl->ilist = NULL; - } - - if(tbl->cols) { - 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) { - PFREE(tbl->rows); - tbl->rows = NULL; - tbl->n_rows = 0; - tbl->n_total_rows = 0; - } - - khui_delete_bitmap(&tbl->kbm_logo_shade); - - if (tbl->csp_view) { - khc_close_space(tbl->csp_view); - tbl->csp_view = NULL; - } - - tbl->cell_height = 0; /* recalculate cell height next time */ - - if (tbl->idents) { - khm_size i; - - for (i=0; i < tbl->n_idents; i++) { - if (tbl->idents[i].ident) { - kcdb_identity_release(tbl->idents[i].ident); - } - } - - PFREE(tbl->idents); - tbl->idents = NULL; - tbl->n_idents = 0; - tbl->nc_idents = 0; - } -} - -void -cw_hditem_from_tbl_col(khui_credwnd_col * col, HDITEM *phi) -{ - size_t cchsize; - - phi->mask = HDI_FORMAT | HDI_LPARAM | HDI_WIDTH; - if(cw_is_custom_attr(col->attr_id)) { - if(col->attr_id == CW_CA_FLAGS) { - phi->fmt = 0; - } else if(col->attr_id == CW_CA_TYPEICON) { - phi->fmt = 0; - } else { - /* what the? */ - /*TODO: throw up and die */ - } - } else { - phi->mask |= HDI_TEXT; - phi->pszText = col->title; - StringCchLength(col->title, KCDB_MAXCCH_SHORT_DESC, &cchsize); - phi->cchTextMax = (int) cchsize; - phi->fmt = HDF_CENTER | HDF_STRING; - } - phi->lParam = col->attr_id; -#if (_WIN32_WINNT >= 0x501) - if (IS_COMMCTL6()) { - if(col->flags & KHUI_CW_COL_SORT_INC) { - phi->fmt |= HDF_SORTUP; - } else if(col->flags & KHUI_CW_COL_SORT_DEC) { - phi->fmt |= HDF_SORTDOWN; - } - } -#endif - if(col->width < 0) { - /*TODO: come up with a better way to handle this case */ - col->width = 200; - } - phi->cxy = col->width; -} - -int -cw_get_cell_height(HDC hdc, HFONT hf) { - SIZE size; - size_t cbbuf; - wchar_t buf[64]; - HFONT hfold = NULL; - - if (hf) - hfold = SelectFont(hdc, hf); - - LoadString(khm_hInstance, IDS_SAMPLE_STRING, buf, sizeof(buf)/sizeof(buf[0])); - StringCchLength(buf, sizeof(buf)/sizeof(buf[0]), &cbbuf); - GetTextExtentPoint32(hdc, buf, (int) cbbuf, &size); - - if (hf) - SelectFont(hdc, hfold); - - return size.cy; -} - -int -cw_update_header_column_width(khui_credwnd_tbl * tbl, int c) { - int idx; - HDITEM hi; - -#ifdef DEBUG - assert(c >= 0 && c < tbl->n_cols); -#endif - - if (tbl->hwnd_header == NULL) - return 0; - - idx = Header_OrderToIndex(tbl->hwnd_header, c); - ZeroMemory(&hi, sizeof(hi)); - hi.mask = HDI_WIDTH; - hi.cxy = tbl->cols[c].width; - return Header_SetItem(tbl->hwnd_header, idx, &hi); -} - -/* returns a bitmask indicating which measures were changed */ -int -cw_update_extents(khui_credwnd_tbl * tbl, - khm_boolean update_scroll) { - int ext_x = 0; - int ext_y = 0; - int i; - int filler_col = -1; - int fill_adjusted = 0; - - recompute_columns: - - ext_x = 0; - for(i=0; i < (int) tbl->n_cols; i++) { - tbl->cols[i].x = ext_x; - if (tbl->cols[i].flags & KHUI_CW_COL_FILLER) { - if (filler_col == -1) - filler_col = i; - } - ext_x += tbl->cols[i].width; - } - - if (filler_col != -1 && !fill_adjusted) { - RECT r; - int delta; - - GetClientRect(tbl->hwnd, &r); - - /* we decrement the width so that the width data area is - strictly less than the width of the client area. Windows - doesn't disable a scrollbar unless the range is strictly - less than the page size. */ - delta = ((r.right - r.left) - 1) - ext_x; - - if (tbl->cols[filler_col].width + delta <= GetSystemMetrics(SM_CXSMICON)) { - tbl->cols[filler_col].width = GetSystemMetrics(SM_CXICON); - } else { - tbl->cols[filler_col].width += delta; - } - - cw_update_header_column_width(tbl, filler_col); - - fill_adjusted = 1; - goto recompute_columns; - } - - if(!tbl->cell_height) { - HDC dc; - int maxheight = 0; - int height; - - dc = GetWindowDC(tbl->hwnd); - - maxheight = cw_get_cell_height(dc, tbl->hf_normal); - height = cw_get_cell_height(dc, tbl->hf_bold); - if (height > maxheight) - maxheight = height; - height = cw_get_cell_height(dc, tbl->hf_header); - if (height > maxheight) - maxheight = height; - height = cw_get_cell_height(dc, tbl->hf_bold_header); - if (height > maxheight) - maxheight = height; - - ReleaseDC(tbl->hwnd, dc); - - tbl->cell_height = height + tbl->vpad * 2; - } - - if (tbl->flags & KHUI_CW_TBL_EXPIDENT) { - RECT r; - - ext_y = 0; - r.left = 0; - r.right = ext_x; - - for (i=0; i < (int) tbl->n_rows; i++) { - r.top = ext_y; - if (tbl->rows[i].flags & KHUI_CW_ROW_EXPVIEW) { - ext_y += tbl->cell_height * CW_EXP_ROW_MULT; - } else { - ext_y += tbl->cell_height; - } - r.bottom = ext_y; - tbl->rows[i].r_ext = r; - } - } else { - RECT r; - - r.left = 0; - r.right = ext_x; - - for (i=0; i < (int) tbl->n_rows; i++) { - r.top = i * tbl->cell_height; - r.bottom = r.top + tbl->cell_height; - - tbl->rows[i].r_ext = r; - } - - ext_y = (int) tbl->n_rows * tbl->cell_height; - } - - tbl->ext_width = ext_x; - tbl->ext_height = ext_y; - - /* useful in the future when implementing variable height rows. - The KHUI_CW_TBL_ROW_DIRTY bit indicates that the rows have - changed and that the y extent has to be recalculated. */ - tbl->flags &= ~KHUI_CW_TBL_ROW_DIRTY; - - if(update_scroll) { - RECT r; - int cl_w; - int cl_h; - SCROLLINFO si; - WINDOWPOS pw; - HDLAYOUT hdl; - - /* update the header control first */ - - retry_update_scroll: - GetClientRect(tbl->hwnd, &r); - - cl_w = r.right - r.left; - cl_h = (r.bottom - r.top); - cl_h -= tbl->header_height; - - if(tbl->scr_top < 0 || tbl->ext_height < cl_h) - tbl->scr_top = 0; - else if(tbl->scr_top > tbl->ext_height - cl_h) - tbl->scr_top = tbl->ext_height - cl_h; - if(tbl->scr_left < 0 || tbl->ext_width < cl_w) - tbl->scr_left = 0; - else if(tbl->scr_left > tbl->ext_width - cl_w) - tbl->scr_left = tbl->ext_width - cl_w; - - /* adjustments for scrolling */ - r.left -= tbl->scr_left; - r.right = max(tbl->ext_width + r.left, r.right); - - hdl.prc = &r; - hdl.pwpos = &pw; - - Header_Layout(tbl->hwnd_header, &hdl); - - if(tbl->header_height == 0) { - tbl->header_height = pw.cy; - goto retry_update_scroll; - } else - tbl->header_height = pw.cy; - - SetWindowPos( - tbl->hwnd_header, - pw.hwndInsertAfter, - pw.x, - pw.y, - pw.cx, - pw.cy, - pw.flags); - - si.cbSize = sizeof(si); - si.nMin = 0; - si.nMax = tbl->ext_height; - si.nPage = cl_h; - si.nPos = tbl->scr_top; - si.fMask = SIF_ALL | SIF_DISABLENOSCROLL; - SetScrollInfo(tbl->hwnd, SB_VERT, &si, TRUE); - - si.cbSize = sizeof(si); - si.nMin = 0; - si.nMax = tbl->ext_width; - si.nPage = cl_w; - si.nPos = tbl->scr_left; - si.fMask = SIF_ALL | SIF_DISABLENOSCROLL; - SetScrollInfo(tbl->hwnd, SB_HORZ, &si, TRUE); - } - - return 0; -} - -void -cw_insert_header_cols(khui_credwnd_tbl * tbl) { - HWND hdr; - HDITEM hi; - int i; - - hdr = tbl->hwnd_header; - - for(i=0; i < (int) tbl->n_cols; i++) { - cw_hditem_from_tbl_col(&(tbl->cols[i]), &hi); - Header_InsertItem(hdr, 512, &hi); - } -} - -#define CW_ER_BLANK 0 -#define CW_ER_GREY 1 -#define CW_ER_SEL 2 - -void -cw_erase_rect(HDC hdc, - khui_credwnd_tbl * tbl, - RECT * r_wnd, - RECT * r_erase, - int type) -{ - RECT rlogo; - RECT ri; - RECT t; - BOOL rie; - HBRUSH hbr; - - switch(type) { - case CW_ER_BLANK: - hbr = tbl->hb_normal; - break; - - case CW_ER_GREY: - hbr = tbl->hb_grey; - break; - - case CW_ER_SEL: - hbr = tbl->hb_s; - break; - - default: - return; - } - - if(tbl->kbm_logo_shade.cx != -1 && type == CW_ER_BLANK) { - rlogo.left = r_wnd->right - tbl->kbm_logo_shade.cx; - rlogo.right = r_wnd->right; - rlogo.top = r_wnd->bottom - tbl->kbm_logo_shade.cy; - rlogo.bottom = r_wnd->bottom; - rie = FALSE; /* Don't show watermark. */ - } else { - ZeroMemory(&rlogo, sizeof(rlogo)); - ZeroMemory(&ri, sizeof(ri)); - rie = FALSE; - } - - if(!rie) { - FillRect(hdc, r_erase, hbr); - } else { - HDC hdcb = CreateCompatibleDC(hdc); - HBITMAP hbmold = SelectObject(hdcb, tbl->kbm_logo_shade.hbmp); - - BitBlt(hdc, ri.left, ri.top, ri.right - ri.left, ri.bottom - ri.top, - hdcb, ri.left - rlogo.left, ri.top - rlogo.top, SRCCOPY); - - SelectObject(hdcb, hbmold); - DeleteDC(hdcb); - - if(r_erase->top < ri.top && r_erase->left < ri.left) { - t.left = r_erase->left; - t.top = r_erase->top; - t.right = ri.left; - t.bottom = ri.top; - FillRect(hdc, &t, hbr); - } - - if(r_erase->left < ri.left) { - t.left = r_erase->left; - t.top = ri.top; - t.right = ri.left; - t.bottom = ri.bottom; - FillRect(hdc, &t, hbr); - } - - if(r_erase->top < ri.top) { - t.left = ri.left; - t.top = r_erase->top; - t.right = ri.right; - t.bottom = ri.top; - FillRect(hdc, &t, hbr); - } - } -} - -void -cw_draw_header(HDC hdc, - khui_credwnd_tbl * tbl, - int row, - RECT * r) -{ - int colattr; - HPEN pl, pold; - khui_credwnd_row * cr; - khui_credwnd_outline * o; - int selected = 0; - khm_int32 idf = 0; - - /* each header consists of a couple of widgets and some text */ - /* we need to figure out the background color first */ - - cr = &(tbl->rows[row]); - o = (khui_credwnd_outline *) cr->data; - - colattr = tbl->cols[cr->col].attr_id; - - if (colattr == KCDB_ATTR_ID_NAME) { - khm_handle ident = o->data; - - kcdb_identity_get_flags(ident, &idf); - } - - selected = o->flags & KHUI_CW_O_SELECTED; - - { - HBRUSH hbr; - - if(selected) { - if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_EXPIRED) - hbr = tbl->hb_hdr_bg_exp_s; - else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_CRITICAL) - hbr = tbl->hb_hdr_bg_crit_s; - else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_WARN) - hbr = tbl->hb_hdr_bg_warn_s; - else if (idf & KCDB_IDENT_FLAG_DEFAULT) - hbr = tbl->hb_hdr_bg_def_s; - else - hbr = tbl->hb_hdr_bg_s; - } else { - if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_EXPIRED) - hbr = tbl->hb_hdr_bg_exp; - else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_CRITICAL) - hbr = tbl->hb_hdr_bg_crit; - else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_WARN) - hbr = tbl->hb_hdr_bg_warn; - else if (idf & KCDB_IDENT_FLAG_DEFAULT) - hbr = tbl->hb_hdr_bg_def; - else - hbr = tbl->hb_hdr_bg; - } - - FillRect(hdc, r, hbr); - } - - /* draw the background */ - pl = CreatePen(PS_SOLID, 0, tbl->cr_hdr_outline); - pold = SelectObject(hdc, pl); - MoveToEx(hdc, r->left, r->bottom - 1, NULL); - LineTo(hdc,r->right,r->bottom - 1); - SelectObject(hdc, pold); - DeleteObject(pl); - - if (!(o->flags & KHUI_CW_O_NOOUTLINE) && - !(o->flags & KHUI_CW_O_EMPTY)) { - if((tbl->mouse_state & CW_MOUSE_WOUTLINE) && - tbl->mouse_row == row) { - if(o->flags & KHUI_CW_O_EXPAND) { - khui_ilist_draw_id(tbl->ilist, IDB_WDG_EXPAND_HI, - hdc, r->left, - (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); - } else { - khui_ilist_draw_id(tbl->ilist, IDB_WDG_COLLAPSE_HI, - hdc, r->left, - (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); - } - } else { - if(o->flags & KHUI_CW_O_EXPAND) { - khui_ilist_draw_id(tbl->ilist, IDB_WDG_EXPAND, - hdc, r->left, - (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); - } else { - khui_ilist_draw_id(tbl->ilist, IDB_WDG_COLLAPSE, - hdc, r->left, - (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); - } - } - - r->left += KHUI_SMICON_CX * 3 / 2; - } else if (!(o->flags & KHUI_CW_O_NOOUTLINE)) { - r->left += KHUI_SMICON_CX * 3 / 2; - } - - /* try to draw the icon, if there is one */ - if(colattr == KCDB_ATTR_ID_NAME) { - - khui_ilist_draw_id(tbl->ilist, - (((tbl->mouse_state & CW_MOUSE_WSTICKY) && - tbl->mouse_row == row)? - ((idf & KCDB_IDENT_FLAG_STICKY)? - IDB_WDG_STUCK_HI: - IDB_WDG_STICK_HI): - ((idf & KCDB_IDENT_FLAG_STICKY)? - IDB_WDG_STUCK: - IDB_WDG_STICK)), - hdc, - r->left, - (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); - - r->left += KHUI_SMICON_CX * 3 / 2; - - /* the TRUE part of the 'if' is for drawing large icons. It's - disabled for now until we have new icons. */ - if ((cr->flags & KHUI_CW_ROW_EXPVIEW) && FALSE) { - int cx = GetSystemMetrics(SM_CXICON); - int cy = GetSystemMetrics(SM_CYICON); - - DrawIcon(hdc, r->left, (r->top + r->bottom - cy) / 2, tbl->hi_lg_ident); - - r->left += cx + KHUI_SMICON_CX / 2; - - } else { - khui_ilist_draw_id(tbl->ilist, - ((o->flags & KHUI_CW_O_EMPTY)? - IDB_ID_DIS_SM: - IDB_ID_SM), - hdc, - r->left, - (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); - r->left += KHUI_SMICON_CX * 3 / 2 ; - } - } - - - if (!(cr->flags & KHUI_CW_ROW_EXPVIEW)) { - - SetTextAlign(hdc, TA_BOTTOM | TA_LEFT); - - if(selected) - SetTextColor(hdc, tbl->cr_hdr_s); - else - SetTextColor(hdc, tbl->cr_hdr_normal); - - TextOut(hdc, r->left, r->bottom - tbl->vpad, o->header, (int) wcslen(o->header)); - - if (colattr == KCDB_ATTR_ID_NAME && - (idf & KCDB_IDENT_FLAG_DEFAULT)) { - wchar_t defstr[64]; - SIZE size; - - LoadString(khm_hInstance, IDS_CW_DEFAULT, - defstr, ARRAYLENGTH(defstr)); - - GetTextExtentPoint32(hdc, o->header, (int) wcslen(o->header), - &size); - - r->left += size.cx + KHUI_SMICON_CX * 2; - - TextOut(hdc, r->left, r->bottom - tbl->vpad, - defstr, (int) wcslen(defstr)); - } - } else { - - RECT tr; - int len; - wchar_t typestr[128]; - int cx_id; - SIZE size; - khui_credwnd_ident * cwi; - - /* expanded view */ -#ifdef DEBUG - assert(colattr == KCDB_ATTR_ID_NAME); -#endif - - cwi = cw_find_ident(tbl, o->data); - - CopyRect(&tr, r); - tr.bottom -= (tr.bottom - tr.top) / 2; /* drawing two lines of text */ - - if (selected) - SetTextColor(hdc, tbl->cr_hdr_s); - else - SetTextColor(hdc, tbl->cr_hdr_normal); - - len = (int) wcslen(o->header); - DrawText(hdc, o->header, len, &tr, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); - GetTextExtentPoint32(hdc, o->header, (int) len, &size); - cx_id = size.cx; - - typestr[0] = L'\0'; - - if ((idf & KCDB_IDENT_FLAG_DEFAULT)) { - if (cwi && cwi->credtype_name[0]) { - wchar_t fmt[64]; - - LoadString(khm_hInstance, IDS_CW_DEFAULTTF, - fmt, ARRAYLENGTH(fmt)); - StringCbPrintf(typestr, sizeof(typestr), fmt, - cwi->credtype_name); - } else { - LoadString(khm_hInstance, IDS_CW_DEFAULT, - typestr, ARRAYLENGTH(typestr)); - } - } else if (cwi && cwi->credtype_name[0]) { - wchar_t fmt[64]; - - LoadString(khm_hInstance, IDS_CW_TYPEF, - fmt, ARRAYLENGTH(fmt)); - StringCbPrintf(typestr, sizeof(typestr), fmt, - cwi->credtype_name); - } - - if (typestr[0]) { - int cx_str; - - len = (int) wcslen(typestr); - GetTextExtentPoint32(hdc, typestr, (int) len, &size); - cx_str = size.cx + KHUI_SMICON_CX / 2; - - tr.left = max(tr.right - cx_str, tr.left + cx_id + KHUI_SMICON_CX * 2); - if (selected) - SetTextColor(hdc, tbl->cr_hdr_gray_s); - else - SetTextColor(hdc, tbl->cr_hdr_gray); - DrawText(hdc, typestr, len, &tr, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); - } - - CopyRect(&tr, r); - tr.top += (tr.bottom - tr.top) / 2; - - if (1) { - wchar_t buf[128]; - khui_credwnd_ident * cwi; - - buf[0] = L'\0'; - cwi = cw_find_ident(tbl, o->data); - - if (cwi) { -#ifdef SHOW_CREDENTIAL_COUNTS - if (cwi->credcount == 0) - LoadString(khm_hInstance, IDS_IDEXPDISP_NOCRED, - buf, ARRAYLENGTH(buf)); - else if (cwi->credcount == 1) - LoadString(khm_hInstance, IDS_IDEXPDISP_1CRED, - buf, ARRAYLENGTH(buf)); - else { - wchar_t fmt[128]; - LoadString(khm_hInstance, IDS_IDEXPDISP_NCRED, - fmt, ARRAYLENGTH(fmt)); - StringCbPrintf(buf, sizeof(buf), fmt, (int) cwi->credcount); - } -#else - if (FtToInt(&cwi->ft_expire) != 0) { - FILETIME ft_now; - - GetSystemTimeAsFileTime(&ft_now); - if (CompareFileTime(&cwi->ft_expire, &ft_now) > 0) { - wchar_t fmt[64]; - wchar_t intstr[128]; - FILETIME ft; - khm_size cb; - - ft = FtSub(&cwi->ft_expire, &ft_now); - intstr[0] = L'\0'; - cb = sizeof(intstr); - FtIntervalToString(&ft, intstr, &cb); - - LoadString(khm_hInstance, IDS_CW_EXPIREF, - fmt, ARRAYLENGTH(fmt)); - StringCbPrintf(buf, sizeof(buf), fmt, intstr); - } else { - LoadString(khm_hInstance, IDS_CW_EXPIRED, - buf, ARRAYLENGTH(buf)); - } - } -#endif - - len = (int) wcslen(buf); - - if (selected) - SetTextColor(hdc, tbl->cr_hdr_gray_s); - else - SetTextColor(hdc, tbl->cr_hdr_gray); - DrawText(hdc, buf, len, &tr, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); - } - } - } -} - -LRESULT -cw_handle_header_msg(khui_credwnd_tbl * tbl, LPNMHEADER ph) { - RECT r; - HDITEM hi; - - switch(ph->hdr.code) { - /*TODO:Make it track smoother */ - 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: - return FALSE; - - 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_POS) { - 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].flags & KHUI_CW_COL_FIXED_POS)) - 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 - break; - } - - 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_META) - 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++; - } - } - - 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; - - 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)) - break; - - tbl->cols[i].flags &= ~KHUI_CW_COL_GROUP; - - 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); - } - -#if 0 - } else if (tbl->cols[idx].flags & - (KHUI_CW_COL_SORT_INC | - KHUI_CW_COL_SORT_DEC)) { - int i; - - /* remove the sort condition from a column */ - - for (i=idx; i < tbl->n_cols; i++) { - if (!tbl->cols[i].flags & - (KHUI_CW_COL_SORT_INC | - KHUI_CW_COL_SORT_DEC)) - break; - - tbl->cols[i].flags &= - ~(KHUI_CW_COL_SORT_INC | - KHUI_CW_COL_SORT_DEC); - - 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); - } -#endif - } 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++; - } - } - - 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; -} - -LRESULT -cw_wm_create(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - khui_credwnd_tbl * tbl; - - 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)); - ZeroMemory(tbl, sizeof(*tbl)); - - /* some versions of VC generate portability warnings for - SetWindowLongPtr */ -#pragma warning(push) -#pragma warning(disable: 4244) - 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_DRAGDROP -#if (_WIN32_WINNT >= 0x501) - | ((IS_COMMCTL6())?HDS_FLAT:0) -#endif - , - 0,0,0,0,hwnd, (HMENU) 0, khm_hInstance, NULL); - - cw_load_view(tbl, NULL /* default view */, hwnd); - cw_insert_header_cols(tbl); - - cw_update_creds(tbl); - cw_update_outline(tbl); - cw_update_selection_state(tbl); - cw_update_extents(tbl, FALSE); - - { - RECT rect; - WINDOWPOS pw; - HDLAYOUT hdl; - - hdl.prc = ▭ - hdl.pwpos = &pw; - GetClientRect(hwnd, &rect); - - Header_Layout(tbl->hwnd_header, &hdl); - - SetWindowPos( - tbl->hwnd_header, - pw.hwndInsertAfter, - pw.x, - pw.y, - pw.cx, - pw.cy, - pw.flags | SWP_SHOWWINDOW); - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -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); - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -/* handles WM_PAINT and WM_PRINTCLIENT */ -LRESULT -cw_wm_paint(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - khui_credwnd_tbl * tbl; - HDC hdc; - PAINTSTRUCT ps; - RECT r,rh; - HFONT hf_old = NULL; - int row_s, row_e; - int col_s, col_e; - int i,j,x,y,xs,xe,ys,ye; - int flag_col = -1; - int d_x = -1; - int selected = 0; - int rowheight = 0; - BOOL has_dc = FALSE; - - tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - - if (wParam != 0) { - /* we assume that if wParam != 0, then that contains a device - context for us to draw in. Otherwise, we have to call - BeginPaint() to get one. */ - hdc = (HDC) wParam; - has_dc = TRUE; - } - - if(!has_dc && !GetUpdateRect(hwnd, &r, FALSE)) { -#ifdef DEBUG - assert(FALSE); -#endif - goto _exit; - } - - if (!has_dc) - hdc = BeginPaint(hwnd, &ps); - - if(tbl->hf_normal) - hf_old = SelectFont(hdc, tbl->hf_normal); - SetTextAlign(hdc, TA_LEFT | TA_TOP | TA_NOUPDATECP); - SetBkMode(hdc, TRANSPARENT); - - GetClientRect(hwnd,&r); - r.top += tbl->header_height; - - if(tbl->n_rows) { - /* remove the notification window if there is one */ - if(tbl->hwnd_notif) { - DestroyWindow(tbl->hwnd_notif); - tbl->hwnd_notif = NULL; - } - /* we compute the visible area in terms of rows and columns */ - /* row_s : first visible row */ - /* col_s : first visible column */ - /* row_e : last visible row */ - /* col_e : last visible column */ - /* ys : top edge of first visible row */ - /* xs : left edge of first visible column */ - - /* We *NEED* all the meta columns to be on the left */ - - row_s = 0; - ys = 0; - row_e = (int) tbl->n_rows; - x = 0; - col_s = -1; - col_e = -1; - xs = 0; - for(i=0; i < (int) tbl->n_cols; i++) { - if(col_e == -1 && x >= tbl->scr_left + (r.right - r.left)) { - col_e = i; - } - if(tbl->cols[i].attr_id == CW_CA_FLAGS) - flag_col = i; - if(d_x == -1 && !cw_is_custom_attr(tbl->cols[i].attr_id)) - d_x = x; - x += tbl->cols[i].width; - if(col_s == -1 && x > tbl->scr_left) { - col_s = i; - xs = tbl->cols[i].x; - } - } - - if(col_e == -1) - col_e = i; - - if(col_s == -1) - col_s = i; - - if(d_x != -1) - d_x += r.left - tbl->scr_left; - - xs += r.left - tbl->scr_left; - ys += r.top - tbl->scr_top; - xe = r.left + tbl->ext_width - tbl->scr_left; - ye = r.top + tbl->ext_height - tbl->scr_top; - - /* now draw */ - y = ys; - for(i=row_s; i < row_e; i++) { - selected = tbl->rows[i].flags & KHUI_CW_ROW_SELECTED; - rowheight = (tbl->rows[i].flags & KHUI_CW_ROW_EXPVIEW)? tbl->cell_height * CW_EXP_ROW_MULT : tbl->cell_height; - - if(tbl->cursor_row == i) { - if (tbl->rows[i].flags & KHUI_CW_ROW_HEADER) - SelectFont(hdc, tbl->hf_bold_header); - else - SelectFont(hdc, tbl->hf_bold); - } else if (tbl->rows[i].flags & KHUI_CW_ROW_HEADER) { - SelectFont(hdc, tbl->hf_header); - } - - x = xs; - if(tbl->rows[i].flags & KHUI_CW_ROW_HEADER) { - rh.left = xs; - rh.right = xs; - for(j=col_s; j < tbl->rows[i].col; j++) - rh.right += tbl->cols[j].width; - rh.top = y; - rh.bottom = y + rowheight; - if(rh.right > rh.left) { - cw_erase_rect(hdc, tbl, &r, &rh, (selected)?CW_ER_SEL:CW_ER_BLANK); - } - rh.left = rh.right; - rh.right = xe; - - cw_draw_header(hdc, tbl, i, &rh); - } - - if(selected) - SetTextColor(hdc, tbl->cr_s); - else - SetTextColor(hdc, tbl->cr_normal); - - x = xs; - rh.top = y; - rh.bottom = y + rowheight; - for(j=col_s; j < col_e; x += tbl->cols[j++].width) { - wchar_t buf[256]; - khm_size cbbuf; - - rh.left = x; - rh.right = x + tbl->cols[j].width; - - if(!cw_is_custom_attr(tbl->cols[j].attr_id)) { - if(!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) { - cw_erase_rect(hdc, tbl, &r, &rh, (selected)?CW_ER_SEL:CW_ER_BLANK); - - if(j > tbl->rows[i].col) { - cbbuf = sizeof(buf); - if(KHM_FAILED(kcdb_cred_get_attr_string((khm_handle) tbl->rows[i].data, - tbl->cols[j].attr_id, buf, - &cbbuf, KCDB_TS_SHORT))) - continue; - - rh.left += tbl->hpad; - rh.right -= tbl->hpad; - - SetTextAlign(hdc, 0); - DrawText(hdc, buf, (int)((cbbuf / sizeof(wchar_t)) - 1), &rh, - DT_LEFT | DT_VCENTER | DT_NOCLIP | DT_SINGLELINE | DT_END_ELLIPSIS); - } - } - } else { - cw_erase_rect(hdc, tbl, &r, &rh, (selected)?CW_ER_SEL:CW_ER_BLANK); - - if(tbl->cols[j].attr_id == CW_CA_FLAGS) { - khui_credwnd_outline * o; - khm_int32 flag; - - if(tbl->rows[i].flags & KHUI_CW_ROW_HEADER) { - o = ((khui_credwnd_outline *) tbl->rows[i].data); - if(o->flags & KHUI_CW_O_SHOWFLAG) - flag = o->flags; - else - flag = 0; - } else { - flag = tbl->rows[i].flags; - } - - flag &= CW_EXPSTATE_MASK; - - if(flag == CW_EXPSTATE_WARN) { - khui_ilist_draw_id(tbl->ilist, IDB_FLAG_WARN, hdc, x, y, 0); - } else if(flag == CW_EXPSTATE_CRITICAL) { - 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 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)) && - (flags & KCDB_CRED_FLAG_RENEWABLE)) { - khui_ilist_draw_id(tbl->ilist, - IDB_FLAG_RENEW, - hdc, - x, y, 0); - } else { - khui_ilist_draw_id(tbl->ilist, - IDB_TK_SM, - hdc, - x, y, 0); - } - } - } - } - } - - if(tbl->cursor_row == i) { - rh.left = tbl->scr_left; - rh.right = tbl->scr_left + tbl->ext_width; - DrawFocusRect(hdc, &rh); - } - - if (tbl->cursor_row == i || - (tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) { - SelectFont(hdc, tbl->hf_normal); - } - - y += rowheight; - - } - - if(xe < r.right) { - rh.left = xe; - rh.right = r.right; - rh.top = r.top; - rh.bottom = r.bottom; - - cw_erase_rect(hdc, tbl, &r, &rh, CW_ER_BLANK); - } - - if(ye < r.bottom) { - rh.left = r.left; - rh.right = (xe < r.right)?xe:r.right; - rh.top = ye; - rh.bottom = r.bottom; - - cw_erase_rect(hdc, tbl, &r, &rh, CW_ER_BLANK); - } - - } else { - wchar_t buf[512]; - cw_erase_rect(hdc, tbl, &r, &r, CW_ER_BLANK); - - if(tbl->hwnd_notif == NULL) { - LoadString(khm_hInstance, IDS_NO_CREDS, buf, sizeof(buf)/sizeof(buf[0])); - tbl->hwnd_notif = khm_create_htwnd( - tbl->hwnd, - buf, - r.left,r.top,r.right - r.left,tbl->cell_height * 4, - 0, /* This can be WS_EX_TRANSPARENT, but - we don't fully support it yet. */ - WS_VISIBLE); - if(tbl->hwnd_notif) { - SendMessage(tbl->hwnd_notif, WM_SETFONT, (WPARAM) tbl->hf_normal, (LPARAM) FALSE); - ShowWindow(tbl->hwnd_notif, SW_SHOW); - } - } - } - - if(tbl->hf_normal) - SelectFont(hdc, hf_old); - - if (!has_dc) - EndPaint(hwnd,&ps); - - _exit: - return TRUE; -} - -LRESULT -cw_wm_size(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - RECT rect; - khui_credwnd_tbl * tbl; - - tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - - cw_update_extents(tbl, TRUE); - - GetClientRect(hwnd, &rect); - - if(tbl->hwnd_notif) { - SetWindowPos( - tbl->hwnd_notif, - tbl->hwnd_header, - rect.left, - tbl->header_height, - rect.right - rect.left, - tbl->cell_height * 4, - 0); - } - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -LRESULT -cw_wm_notify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - khui_credwnd_tbl * tbl; - LPNMHDR pnmh; - tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - pnmh = (LPNMHDR) lParam; - if(pnmh->hwndFrom == tbl->hwnd_header) { - LPNMHEADER ph; - ph = (LPNMHEADER) lParam; - return cw_handle_header_msg(tbl, ph); - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -static void cw_pp_begin(khui_property_sheet * s); -static void cw_pp_precreate(khui_property_sheet * s); -static void cw_pp_end(khui_property_sheet * s); -static void cw_pp_destroy(khui_property_sheet *ps); - -LRESULT -cw_kmq_wm_dispatch(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - kmq_message * m; - khm_int32 rv = KHM_ERROR_SUCCESS; - khui_credwnd_tbl * tbl; - - 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: - cw_update_creds(tbl); - cw_update_outline(tbl); - cw_update_extents(tbl, TRUE); - InvalidateRect(hwnd, NULL, FALSE); - break; - - case KMSG_CRED_PP_BEGIN: - cw_pp_begin((khui_property_sheet *) m->vparam); - break; - - case KMSG_CRED_PP_PRECREATE: - cw_pp_precreate((khui_property_sheet *) m->vparam); - break; - - case KMSG_CRED_PP_END: - cw_pp_end((khui_property_sheet *) m->vparam); - break; - - case KMSG_CRED_PP_DESTROY: - cw_pp_destroy((khui_property_sheet *) m->vparam); - break; - } - } else if (m->type == KMSG_KCDB) { - if (m->subtype == KMSG_KCDB_IDENT && - m->uparam == KCDB_OP_MODIFY) { - - cw_update_outline(tbl); - cw_update_extents(tbl, TRUE); - InvalidateRect(hwnd, NULL, FALSE); - - } - else if (m->subtype == KMSG_KCDB_IDENT && - m->uparam == KCDB_OP_NEW_DEFAULT) { - - cw_update_outline(tbl); - cw_update_extents(tbl, TRUE); - 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_selection_state(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); -} - -static void -cw_select_outline_level(khui_credwnd_outline * o, - BOOL select) -{ - while(o) { - if (select) - o->flags |= KHUI_CW_O_SELECTED; - else - o->flags &= ~KHUI_CW_O_SELECTED; - cw_select_outline_level(TFIRSTCHILD(o), select); - o = LNEXT(o); - } -} - -static void -cw_select_outline(khui_credwnd_outline * o, - BOOL select) -{ - if (select) - o->flags |= KHUI_CW_O_SELECTED; - else - o->flags &= ~KHUI_CW_O_SELECTED; -} - -static void -cw_select_row_creds(khui_credwnd_tbl * tbl, int row, int selected) { - - khm_size j; - khm_size idx_start, idx_end; - -#ifdef DEBUG - assert(row >= 0 && row < tbl->n_rows); -#endif - - if (row >= tbl->n_rows) - return; - - if (tbl->rows[row].flags & KHUI_CW_ROW_HEADER) { - khui_credwnd_outline * o; - - o = (khui_credwnd_outline *) tbl->rows[row].data; - if (o->col == tbl->n_cols - 1) { - /* this is a special case where the outline column is the - last displayed column. In this case, the credentials - do not occupy any rows, and this header row acts as a - group credential row. */ - idx_start = o->idx_start; - idx_end = o->idx_end; - } else { - return; - } - } else { - idx_start = tbl->rows[row].idx_start; - idx_end = tbl->rows[row].idx_end; - } - - if (idx_start == -1 || idx_end == -1) - return; - - for (j = idx_start; j <= idx_end; j++) { - khm_handle cred = NULL; - - kcdb_credset_get_cred(tbl->credset, (khm_int32) j, &cred); - - if (cred) { - kcdb_cred_set_flags(cred, ((selected)?KCDB_CRED_FLAG_SELECTED:0), - KCDB_CRED_FLAG_SELECTED); - kcdb_cred_release(cred); - } - } -} - -static void -cw_unselect_all(khui_credwnd_tbl * tbl) -{ - int i; - - for(i=0; in_rows; i++) { - tbl->rows[i].flags &= ~KHUI_CW_ROW_SELECTED; - - cw_select_row_creds(tbl, i, FALSE); - } - - cw_select_outline_level(tbl->outline, FALSE); -} - -static void -cw_update_outline_selection_state(khui_credwnd_tbl * tbl, - khui_credwnd_outline * o) -{ - BOOL select = TRUE; - int j; - - for (j = o->start + 1; j < o->start + o->length; j++) { - if (tbl->rows[j].flags & KHUI_CW_ROW_HEADER) { - cw_update_outline_selection_state(tbl, - (khui_credwnd_outline *) - tbl->rows[j].data); - } - - if (!(tbl->rows[j].flags & KHUI_CW_ROW_SELECTED)) { - select = FALSE; - } - - if (tbl->rows[j].flags & KHUI_CW_ROW_HEADER) { - j += ((khui_credwnd_outline *) tbl->rows[j].data)->length - 1; - } - } - - /* special case : the header has been collapsed and we are just - using one row. In this case, the for loop above will do - nothing. */ - - if (o->length == 1) { - select = (tbl->rows[o->start].flags & KHUI_CW_ROW_SELECTED); - } - - cw_select_outline(o, select); - - if (select) { - tbl->rows[o->start].flags |= KHUI_CW_ROW_SELECTED; - } else { - tbl->rows[o->start].flags &= ~KHUI_CW_ROW_SELECTED; - } -} - -static void -cw_update_selection_state(khui_credwnd_tbl * tbl) -{ - int i; - - cw_select_outline_level(tbl->outline, FALSE); - - for (i=0; i < tbl->n_rows; i++) { - if (tbl->rows[i].flags & KHUI_CW_ROW_HEADER) { - khui_credwnd_outline * o; - - o = (khui_credwnd_outline *) tbl->rows[i].data; - - cw_update_outline_selection_state(tbl, o); - - i += o->length - 1; - } - } -} - -/* Examine the current row and set the UI context */ -static void -cw_set_row_context(khui_credwnd_tbl * tbl, int row) -{ - khui_credwnd_outline * o; - BOOL set_context = TRUE; - - if (row < 0 || row >= (int) tbl->n_rows) { - if (tbl->n_rows > 0) - row = 0; - else { - khui_context_reset(); - return; - } - } - - if (tbl->rows[row].flags & KHUI_CW_ROW_HEADER) { - - o = (khui_credwnd_outline *) tbl->rows[row].data; - - if (tbl->cols[o->col].attr_id == KCDB_ATTR_ID_NAME) { - if (TPARENT(o) != NULL) { - khui_credwnd_outline * op; - - op = TPARENT(o); - - if (tbl->cols[op->col].attr_id == KCDB_ATTR_TYPE_NAME && - TPARENT(op) == NULL) { - /* selected a credential type */ - khui_context_set(KHUI_SCOPE_CREDTYPE, - (khm_handle) o->data, - (khm_int32) (DWORD_PTR) op->data, - NULL, - NULL, - 0, - tbl->credset); - } else { - /* we can't narrow it down using the standard set - of scopes. We consider this to be an identity - selection because the user right-clicked on an - identity header. */ - khui_context_set(KHUI_SCOPE_IDENT, - (khm_handle) o->data, - KCDB_CREDTYPE_INVALID, - NULL, - NULL, - 0, - tbl->credset); - } - } else { - /* The user clicked on an identity header. Even - though not all credentials belonging to the - identity maybe within the scope right now, we still - consider this to be an identity scope. */ - khui_context_set(KHUI_SCOPE_IDENT, - (khm_handle) o->data, - KCDB_CREDTYPE_INVALID, - NULL, - NULL, - 0, - tbl->credset); - } - } else if (tbl->cols[o->col].attr_id == KCDB_ATTR_TYPE_NAME) { - if (TPARENT(o) == NULL) { - /* selected an entire cred type */ - khui_context_set(KHUI_SCOPE_CREDTYPE, - NULL, - (khm_int32) (DWORD_PTR) o->data, - NULL, - NULL, - 0, - tbl->credset); - } else { - khui_credwnd_outline * op; - - op = TPARENT(o); - if (tbl->cols[op->col].attr_id == KCDB_ATTR_ID_NAME) { - /* credtype under an identity. Even though not - all the credentials of this credtype belonging - to this identity might be within the scope, we - still consider this to be a type selection - under a specific identity. */ - khui_context_set(KHUI_SCOPE_CREDTYPE, - (khm_handle) op->data, - (khm_int32) (DWORD_PTR) o->data, - NULL, - NULL, - 0, - tbl->credset); - } else { - set_context = FALSE; - } - } - } else { - set_context = FALSE; - } - - if (!set_context) { - /* woohoo. cred group. yay. */ - khui_header headers[KHUI_MAX_HEADERS]; - khm_size n_headers = 0; - - do { - headers[n_headers].attr_id = - o->attr_id; - if (tbl->cols[o->col].attr_id == - KCDB_ATTR_ID_NAME) { - headers[n_headers].data = &(o->data); - headers[n_headers].cb_data = sizeof(khm_handle); - } else if (tbl->cols[o->col].attr_id == - KCDB_ATTR_TYPE_NAME) { - headers[n_headers].data = &(o->data); - headers[n_headers].cb_data = sizeof(khm_int32); - } else { - headers[n_headers].data = o->data; - headers[n_headers].cb_data = o->cb_data; - } - - n_headers++; - - o = TPARENT(o); - } while(o); - - khui_context_set(KHUI_SCOPE_GROUP, - NULL, - KCDB_CREDTYPE_INVALID, - NULL, - headers, - n_headers, - tbl->credset); - } - - } else { - khm_handle cred; - - cred = (khm_handle) tbl->rows[row].data; - - khui_context_set(KHUI_SCOPE_CRED, - NULL, - KCDB_CREDTYPE_INVALID, - cred, - NULL, - 0, - tbl->credset); - } -} - -static void -cw_select_all(khui_credwnd_tbl * tbl) -{ - int i; - - for(i=0; in_rows; i++) { - tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED; - cw_select_row_creds(tbl, i, TRUE); - } - - cw_select_outline_level(tbl->outline, TRUE); - - cw_update_selection_state(tbl); - - cw_set_row_context(tbl, tbl->cursor_row); - - InvalidateRect(tbl->hwnd, NULL, FALSE); -} - -static void -cw_select_row(khui_credwnd_tbl * tbl, int row, WPARAM wParam) -{ - int i; - BOOL toggle; - BOOL extend; - int group_begin; - int group_end; - - if (wParam & MK_CONTROL) { - toggle = TRUE; - extend = FALSE; - } else if (wParam & MK_SHIFT) { - toggle = FALSE; - extend = TRUE; - } else { - toggle = FALSE; - extend = FALSE; - } - - if (row < 0 || row >= (int) tbl->n_rows) - return; - - if (tbl->rows[row].flags & KHUI_CW_ROW_HEADER) { - khui_credwnd_outline * o; - - o = (khui_credwnd_outline *) tbl->rows[row].data; - - group_begin = o->start; - group_end = o->start + o->length - 1; - } else { - group_begin = row; - group_end = row; - } - - if (!toggle && !extend) { - /* selecting a single row */ - cw_unselect_all(tbl); - - tbl->cursor_row = row; - tbl->anchor_row = row; - - for (i = group_begin; i <= group_end; i++) { - tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED; - cw_select_row_creds(tbl, i, TRUE); - } - } else if (toggle) { - BOOL select; - - tbl->cursor_row = row; - tbl->anchor_row = row; - - select = !(tbl->rows[row].flags & KHUI_CW_ROW_SELECTED); - - for (i = group_begin; i <= group_end; i++) { - if (select) - tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED; - else - tbl->rows[i].flags &= ~KHUI_CW_ROW_SELECTED; - - cw_select_row_creds(tbl, i, select); - } - } else if (extend) { - int range_begin; - int range_end; - - cw_unselect_all(tbl); - - range_begin = min(row, tbl->anchor_row); - range_end = max(row, tbl->anchor_row); - - for (i = range_begin; i <= range_end; i++) { - tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED; - - cw_select_row_creds(tbl, i, TRUE); - } - - tbl->cursor_row = row; - } - - cw_update_selection_state(tbl); - - cw_set_row_context(tbl, tbl->cursor_row); - - InvalidateRect(tbl->hwnd, NULL, FALSE); -} - -static void -cw_toggle_outline_state(khui_credwnd_tbl * tbl, - khui_credwnd_outline * o) { - - int old_range_begin; - int old_range_end; - int new_range_begin; - int new_range_end; - - old_range_begin = o->start; - old_range_end = o->start + o->length - 1; - - o->flags ^= KHUI_CW_O_EXPAND; - - cw_update_outline(tbl); - cw_update_extents(tbl, TRUE); - - new_range_begin = o->start; - new_range_end = o->start + o->length - 1; - - if (tbl->cursor_row > old_range_end) { - tbl->cursor_row -= old_range_end - new_range_end; - } else if (tbl->cursor_row >= old_range_begin && - tbl->cursor_row <= old_range_end) { - tbl->cursor_row = new_range_begin; - } - - if (tbl->anchor_row > old_range_end) { - tbl->anchor_row -= old_range_end - new_range_end; - } else if (tbl->anchor_row >= old_range_begin && - tbl->anchor_row <= old_range_end) { - tbl->anchor_row = new_range_begin; - } - - InvalidateRect(tbl->hwnd, NULL, TRUE); - -} - -LRESULT cw_properties(HWND hwnd); - -LRESULT -cw_wm_mouse(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - khui_credwnd_tbl * tbl; - int x,y; - RECT r; - int row; - int col; - int i; - int nm_state,nm_row,nm_col; - - tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - - /* we are basically trying to capture events where the mouse is - hovering over one of the 'hotspots'. There are two kinds of - hotspots one is the little widget thinggy that you click on to - expand or collapse an outline. The other is a text cell that - is partially concealed. */ - - x = GET_X_LPARAM(lParam); - y = GET_Y_LPARAM(lParam); - x += tbl->scr_left; - y += tbl->scr_top - tbl->header_height; - - row = -1; - - for (i=0; i < tbl->n_rows; i++) { - if (y >= tbl->rows[i].r_ext.top && - y < tbl->rows[i].r_ext.bottom) { - row = i; - break; - } - } - - col = -1; - nm_state = CW_MOUSE_NONE; - nm_row = nm_col = -1; - - for(i=0; i < (int) tbl->n_cols; i++) { - if(x >= tbl->cols[i].x && - x < tbl->cols[i].x + tbl->cols[i].width) { - col = i; - break; - } - } - - if(wParam & MK_LBUTTON) - nm_state = CW_MOUSE_LDOWN; - - if(row >= 0 && row < (int) tbl->n_rows) { - nm_state |= CW_MOUSE_ROW; - nm_row = row; - nm_col = col; - if(tbl->rows[row].flags & KHUI_CW_ROW_HEADER) { - khui_credwnd_outline * o; - - o = (khui_credwnd_outline *) tbl->rows[row].data; - - /* are we on a widget then? */ - x -= tbl->cols[o->col].x; - - if (!(o->flags & KHUI_CW_O_NOOUTLINE)) { - if(x >= 0 && x < KHUI_SMICON_CX) /* hit */ { - nm_state |= CW_MOUSE_WOUTLINE | CW_MOUSE_WIDGET; - } else if (tbl->cols[tbl->rows[row].col].attr_id == - KCDB_ATTR_ID_NAME && - col == tbl->rows[row].col && - x >= KHUI_SMICON_CX * 3 / 2 && - x < KHUI_SMICON_CX * 5 / 2){ - nm_state |= CW_MOUSE_WSTICKY | CW_MOUSE_WIDGET; - } else if (tbl->cols[tbl->rows[row].col].attr_id == - KCDB_ATTR_ID_NAME && - col == tbl->rows[row].col && - x >= KHUI_SMICON_CX * 3 && - x < KHUI_SMICON_CX * 4) { - nm_state |= CW_MOUSE_WICON | CW_MOUSE_WIDGET; - } - } else if (tbl->cols[o->col].attr_id == KCDB_ATTR_ID_NAME) { - if (col == tbl->rows[row].col && - x >= 0 && - x < KHUI_SMICON_CX){ - - nm_state |= CW_MOUSE_WSTICKY | CW_MOUSE_WIDGET; - - } else if (col == tbl->rows[row].col && - x >= KHUI_SMICON_CX * 3 / 2 && - x < KHUI_SMICON_CX * 5 / 2) { - nm_state |= CW_MOUSE_WICON | CW_MOUSE_WIDGET; - } - } - } - } - - /* did the user drag the cursor off the current row? */ - if((tbl->mouse_state & CW_MOUSE_LDOWN) && - (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) { - - if((nm_state & CW_MOUSE_WOUTLINE) && - (tbl->mouse_state & CW_MOUSE_WOUTLINE)) { - /* click on an outline widget */ - khui_credwnd_outline * o; - - o = (khui_credwnd_outline *) tbl->rows[nm_row].data; - tbl->mouse_state = CW_MOUSE_WIDGET | CW_MOUSE_WOUTLINE; - - cw_toggle_outline_state(tbl, o); - - return 0; - } else if ((nm_state & CW_MOUSE_WSTICKY) && - (tbl->mouse_state & CW_MOUSE_WSTICKY)) { - - khui_credwnd_outline * o; - khm_handle ident; - khm_int32 idf = 0; - - o = tbl->rows[nm_row].data; - ident = o->data; - - kcdb_identity_get_flags(ident, &idf); - idf &= KCDB_IDENT_FLAG_STICKY; - kcdb_identity_set_flags(ident, (idf ^ KCDB_IDENT_FLAG_STICKY), - KCDB_IDENT_FLAG_STICKY); - - tbl->mouse_state = CW_MOUSE_WIDGET | CW_MOUSE_WSTICKY; - - return 0; - } else if ((nm_state & CW_MOUSE_WICON) && - (tbl->mouse_state & CW_MOUSE_WICON)) { - /* click on an row icon */ - cw_select_row(tbl, nm_row, wParam); - cw_properties(hwnd); - } 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); - } - } - } - - /* ok, now if we are changing state, we need to invalidate a few - regions */ - if (((tbl->mouse_state ^ nm_state) & (CW_MOUSE_WIDGET | - CW_MOUSE_WOUTLINE | - CW_MOUSE_WSTICKY)) || - tbl->mouse_row != nm_row) { - - if(tbl->mouse_state & CW_MOUSE_WOUTLINE) { - r.left = tbl->cols[tbl->mouse_col].x - tbl->scr_left; - r.top = tbl->mouse_row * tbl->cell_height + - tbl->header_height - tbl->scr_top; - r.right = r.left + KHUI_SMICON_CX; - r.bottom = r.top + tbl->cell_height; - InvalidateRect(tbl->hwnd, &r, TRUE); - } - if(tbl->mouse_state & CW_MOUSE_WSTICKY) { - if (tbl->flags & KHUI_CW_TBL_EXPIDENT) { - - if (tbl->mouse_row >= 0 && tbl->mouse_row < tbl->n_rows) { - r = tbl->rows[tbl->mouse_row].r_ext; - OffsetRect(&r, -tbl->scr_left, tbl->header_height - tbl->scr_top); - r.right = r.left + KHUI_SMICON_CX; - InvalidateRect(tbl->hwnd, &r, TRUE); - } - - } else { - r.left = KHUI_SMICON_CX * 3 / 2 + - tbl->cols[tbl->mouse_col].x - tbl->scr_left; - r.top = tbl->mouse_row * tbl->cell_height + - tbl->header_height - tbl->scr_top; - r.right = r.left + KHUI_SMICON_CX; - r.bottom = r.top + tbl->cell_height; - } - InvalidateRect(tbl->hwnd, &r, TRUE); - } - - if ((tbl->mouse_state & nm_state) & CW_MOUSE_LDOWN) { - if (tbl->mouse_row == nm_row) - tbl->mouse_col = nm_col; - } else { - tbl->mouse_col = nm_col; - tbl->mouse_row = nm_row; - } - tbl->mouse_state = nm_state; - - /* same code block as above */ - if(tbl->mouse_state & CW_MOUSE_WOUTLINE) { - r.left = tbl->cols[tbl->mouse_col].x - tbl->scr_left; - r.top = tbl->mouse_row * tbl->cell_height + - tbl->header_height - tbl->scr_top; - r.right = r.left + KHUI_SMICON_CX; - r.bottom = r.top + tbl->cell_height; - InvalidateRect(tbl->hwnd, &r, TRUE); - } - if(tbl->mouse_state & CW_MOUSE_WSTICKY) { - if (tbl->flags & KHUI_CW_TBL_EXPIDENT) { - - if (tbl->mouse_row >= 0 && tbl->mouse_row < tbl->n_rows) { - r = tbl->rows[tbl->mouse_row].r_ext; - OffsetRect(&r, -tbl->scr_left, tbl->header_height - tbl->scr_top); - r.right = r.left + KHUI_SMICON_CX; - InvalidateRect(tbl->hwnd, &r, TRUE); - } - - } else { - r.left = KHUI_SMICON_CX * 3 / 2 + - tbl->cols[tbl->mouse_col].x - tbl->scr_left; - r.top = tbl->mouse_row * tbl->cell_height + - tbl->header_height - tbl->scr_top; - r.right = r.left + KHUI_SMICON_CX; - r.bottom = r.top + tbl->cell_height; - } - InvalidateRect(tbl->hwnd, &r, TRUE); - } - } else if(tbl->mouse_state != nm_state) { - - if ((tbl->mouse_state & nm_state) & CW_MOUSE_LDOWN) { - if (tbl->mouse_row == nm_row) { - tbl->mouse_col = nm_col; - tbl->mouse_state = nm_state; - } - } else { - tbl->mouse_col = nm_col; - tbl->mouse_row = nm_row; - tbl->mouse_state = nm_state; - } - } - - /* if it was a double click, also show the property - window */ - if (uMsg == WM_LBUTTONDBLCLK) { - cw_properties(hwnd); - } - - return 0; -} - -LRESULT -cw_wm_hscroll(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - khui_credwnd_tbl * tbl; - SCROLLINFO si; - RECT cr; - RECT lr; - RECT sr; - int dx; - int newpos; - - tbl = (khui_credwnd_tbl *) (LONG_PTR) GetWindowLongPtr(hwnd, 0); - GetClientRect(hwnd, &cr); - dx = tbl->scr_left; - - switch(LOWORD(wParam)) { - case SB_LEFT: - newpos = 0; - break; - - case SB_RIGHT: - newpos = tbl->ext_width; - break; - - case SB_LINELEFT: - newpos = tbl->scr_left - (tbl->ext_width / 12); - break; - - case SB_LINERIGHT: - newpos = tbl->scr_left + (tbl->ext_width / 12); - break; - - case SB_PAGELEFT: - newpos = tbl->scr_left - (cr.right - cr.left); - break; - - case SB_PAGERIGHT: - newpos = tbl->scr_left + (cr.right - cr.left); - break; - - case SB_THUMBTRACK: - case SB_THUMBPOSITION: - ZeroMemory(&si, sizeof(si)); - si.cbSize = sizeof(si); - si.fMask = SIF_TRACKPOS; - GetScrollInfo(hwnd, SB_HORZ, &si); - - newpos = si.nTrackPos; - break; - - default: - return DefWindowProc(hwnd, uMsg, wParam, lParam); - } - - //cr.top += tbl->header_height; - tbl->scr_left = newpos; - cw_update_extents(tbl, TRUE); - - dx -= tbl->scr_left; - - /* exclude the watermark */ - lr.bottom = cr.bottom; - lr.right = cr.right; - lr.top = max(cr.bottom - tbl->kbm_logo_shade.cy, cr.top); - lr.left = max(cr.right - tbl->kbm_logo_shade.cx, cr.left); - - if(cr.top < lr.top && cr.left < cr.right) { - sr.left = cr.left; - sr.right = cr.right; - sr.top = cr.top; - sr.bottom = lr.top; - ScrollWindowEx( - hwnd, - dx, - 0, - &sr, - &sr, - NULL, - NULL, - SW_INVALIDATE | SW_SCROLLCHILDREN); - } - - if(cr.left < lr.left && lr.top < lr.bottom) { - sr.left = cr.left; - sr.right = lr.left; - sr.top = lr.top; - sr.bottom = lr.bottom; - ScrollWindowEx( - hwnd, - dx, - 0, - &sr, - &sr, - NULL, - NULL, - SW_INVALIDATE | SW_SCROLLCHILDREN); - } - - if(lr.top < lr.bottom && lr.left < lr.right) { - InvalidateRect(hwnd, &lr, FALSE); - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -static void -cw_vscroll_to_pos(HWND hwnd, khui_credwnd_tbl * tbl, int newpos) { - RECT cr; - RECT sr; - RECT lr; - int dy; - - GetClientRect(hwnd, &cr); - cr.top += tbl->header_height; - dy = tbl->scr_top; - - tbl->scr_top = newpos; - cw_update_extents(tbl, TRUE); - - dy -= tbl->scr_top; - - /* exclude watermark */ - lr.bottom = cr.bottom; - lr.right = cr.right; - lr.top = max(cr.bottom - tbl->kbm_logo_shade.cy, cr.top); - lr.left = max(cr.right - tbl->kbm_logo_shade.cx, cr.left); - - if(cr.left < lr.left && cr.top < cr.bottom) { - sr.left = cr.left; - sr.right = lr.left; - sr.top = cr.top; - sr.bottom = cr.bottom; - ScrollWindowEx( - hwnd, - 0, - dy, - &sr, - &sr, - NULL, - NULL, - SW_INVALIDATE); - } - - if(lr.left < lr.right && cr.top < lr.top) { - sr.left = lr.left; - sr.right = lr.right; - sr.top = cr.top; - sr.bottom = lr.top; - ScrollWindowEx( - hwnd, - 0, - dy, - &sr, - &sr, - NULL, - NULL, - SW_INVALIDATE); - } - - if(lr.top < lr.bottom && lr.left < lr.right) { - InvalidateRect(hwnd, &lr, FALSE); - } -} - -LRESULT -cw_wm_vscroll(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - khui_credwnd_tbl * tbl; - SCROLLINFO si; - int newpos; - RECT cr; - - tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - - GetClientRect(hwnd, &cr); - cr.top += tbl->header_height; - - switch(LOWORD(wParam)) { - case SB_LEFT: - newpos = 0; - break; - - case SB_BOTTOM: - newpos = tbl->ext_height; - break; - - case SB_LINEUP: - newpos = tbl->scr_top - (tbl->ext_height / 12); - break; - - case SB_LINEDOWN: - newpos = tbl->scr_top + (tbl->ext_height / 12); - break; - - case SB_PAGEUP: - newpos = tbl->scr_top - (cr.bottom - cr.top); - break; - - case SB_PAGEDOWN: - newpos = tbl->scr_top + (cr.bottom - cr.top); - break; - - case SB_THUMBTRACK: - case SB_THUMBPOSITION: - ZeroMemory(&si, sizeof(si)); - si.cbSize = sizeof(si); - si.fMask = SIF_TRACKPOS; - GetScrollInfo(hwnd, SB_VERT, &si); - - newpos = si.nTrackPos; - break; - - default: - return DefWindowProc(hwnd, uMsg, wParam, lParam); - } - - cw_vscroll_to_pos(hwnd, tbl, newpos); - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -static void -cw_ensure_row_visible(HWND hwnd, khui_credwnd_tbl * tbl, int row) { - RECT r; - int newpos; - - if (row < 0) - row = 0; - else if (row >= (int) tbl->n_rows) - row = (int) tbl->n_rows - 1; - - GetClientRect(hwnd, &r); - r.top += tbl->header_height; - - if (row * tbl->cell_height < tbl->scr_top) { - newpos = row * tbl->cell_height; - } else if ((row + 1) * tbl->cell_height - > tbl->scr_top + (r.bottom - r.top)) { - newpos = ((row + 1) * tbl->cell_height) - (r.bottom - r.top); - } else - return; - - cw_vscroll_to_pos(hwnd, tbl, newpos); -} - -static INT_PTR CALLBACK -cw_pp_ident_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - khui_property_sheet * s; - - switch(uMsg) { - case WM_INITDIALOG: - { - PROPSHEETPAGE * p; - khm_handle ident; - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - khm_size t; - khm_int32 i; - - p = (PROPSHEETPAGE *) lParam; - s = (khui_property_sheet *) p->lParam; - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) s); -#pragma warning(pop) - - ident = s->identity; - - t = sizeof(idname); - kcdb_identity_get_name(ident, idname, &t); - SetDlgItemText(hwnd, IDC_PP_IDNAME, idname); - - kcdb_identity_get_flags(ident, &i); - - CheckDlgButton(hwnd, IDC_PP_IDDEF, - ((i & KCDB_IDENT_FLAG_DEFAULT)?BST_CHECKED: - BST_UNCHECKED)); - - /* if it's default, you can't change it further */ - if (i & KCDB_IDENT_FLAG_DEFAULT) { - EnableWindow(GetDlgItem(hwnd, IDC_PP_IDDEF), FALSE); - } - - CheckDlgButton(hwnd, IDC_PP_IDSEARCH, - ((i & KCDB_IDENT_FLAG_SEARCHABLE)?BST_CHECKED: - BST_UNCHECKED)); - - CheckDlgButton(hwnd, IDC_PP_STICKY, - ((i & KCDB_IDENT_FLAG_STICKY)?BST_CHECKED: - BST_UNCHECKED)); - - khui_property_wnd_set_record(GetDlgItem(hwnd, IDC_PP_PROPLIST), - ident); - } - return TRUE; - - case WM_COMMAND: - s = (khui_property_sheet *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - switch(wParam) { - case MAKEWPARAM(IDC_PP_IDDEF, BN_CLICKED): - /* fallthrough */ - case MAKEWPARAM(IDC_PP_STICKY, BN_CLICKED): - - if (s->status != KHUI_PS_STATUS_NONE) - PropSheet_Changed(s->hwnd, hwnd); - return TRUE; - - case MAKEWPARAM(IDC_PP_CONFIG, BN_CLICKED): - { - khui_config_node cfg_id = NULL; - khui_config_node cfg_ids = NULL; - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - khm_size cb; - khm_int32 rv; - - khm_refresh_config(); - - rv = khui_cfg_open(NULL, - L"KhmIdentities", - &cfg_ids); - - if (KHM_FAILED(rv)) - return TRUE; - - cb = sizeof(idname); - if (KHM_SUCCEEDED(kcdb_identity_get_name(s->identity, - idname, - &cb))) { - rv = khui_cfg_open(cfg_ids, - idname, - &cfg_id); - } - - if (cfg_id) - khm_show_config_pane(cfg_id); - else - khm_show_config_pane(cfg_ids); - - if (cfg_ids) - khui_cfg_release(cfg_ids); - if (cfg_id) - khui_cfg_release(cfg_id); - } - return TRUE; - } - return FALSE; - - case WM_NOTIFY: - { - LPPSHNOTIFY lpp; - khm_int32 flags; - - lpp = (LPPSHNOTIFY) lParam; - s = (khui_property_sheet *) (LONG_PTR) - GetWindowLongPtr(hwnd, DWLP_USER); - - switch(lpp->hdr.code) { - case PSN_APPLY: - flags = 0; - if (IsDlgButtonChecked(hwnd, IDC_PP_STICKY) == BST_CHECKED) - flags |= KCDB_IDENT_FLAG_STICKY; - if (IsDlgButtonChecked(hwnd, IDC_PP_IDDEF) == BST_CHECKED) - flags |= KCDB_IDENT_FLAG_DEFAULT; - - kcdb_identity_set_flags(s->identity, flags, - KCDB_IDENT_FLAG_STICKY | - KCDB_IDENT_FLAG_DEFAULT); - return TRUE; - - case PSN_RESET: - kcdb_identity_get_flags(s->identity, &flags); - - CheckDlgButton(hwnd, - IDC_PP_IDDEF, - ((flags & KCDB_IDENT_FLAG_DEFAULT)?BST_CHECKED: - BST_UNCHECKED)); - - /* if it's default, you can't change it further */ - if (flags & KCDB_IDENT_FLAG_DEFAULT) { - EnableWindow(GetDlgItem(hwnd, IDC_PP_IDDEF), FALSE); - } - - CheckDlgButton(hwnd, IDC_PP_IDSEARCH, - ((flags & KCDB_IDENT_FLAG_SEARCHABLE)?BST_CHECKED:BST_UNCHECKED)); - - CheckDlgButton(hwnd, IDC_PP_STICKY, - ((flags & KCDB_IDENT_FLAG_STICKY)?BST_CHECKED:BST_UNCHECKED)); - return TRUE; - } - } - break; - } - return FALSE; -} - -static INT_PTR CALLBACK -cw_pp_cred_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam - ) -{ - switch(uMsg) { - case WM_INITDIALOG: - { - khui_property_sheet * s; - PROPSHEETPAGE * p; - khm_handle cred; - - p = (PROPSHEETPAGE *) lParam; - s = (khui_property_sheet *) p->lParam; - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) s); -#pragma warning(pop) - - cred = s->cred; - - khui_property_wnd_set_record( - GetDlgItem(hwnd, IDC_PP_CPROPLIST), - cred); - } - return TRUE; - } - return FALSE; -} - -static void -cw_pp_begin(khui_property_sheet * s) -{ - PROPSHEETPAGE *p; - - if(s->identity) { - p = PMALLOC(sizeof(*p)); - ZeroMemory(p, sizeof(*p)); - - p->dwSize = sizeof(*p); - p->dwFlags = 0; - p->hInstance = khm_hInstance; - p->pszTemplate = MAKEINTRESOURCE(IDD_PP_IDENT); - p->pfnDlgProc = cw_pp_ident_proc; - p->lParam = (LPARAM) s; - - khui_ps_add_page(s, KHUI_PPCT_IDENTITY, 129, p, NULL); - } - - if(s->cred) { - p = PMALLOC(sizeof(*p)); - ZeroMemory(p, sizeof(*p)); - - p->dwSize = sizeof(*p); - p->dwFlags = 0; - p->hInstance = khm_hInstance; - p->pszTemplate = MAKEINTRESOURCE(IDD_PP_CRED); - p->pfnDlgProc = cw_pp_cred_proc; - p->lParam = (LPARAM) s; - - khui_ps_add_page(s, KHUI_PPCT_CREDENTIAL, 128, p, NULL); - } -} - -static void -cw_pp_precreate(khui_property_sheet * s) -{ - khui_ps_show_sheet(khm_hwnd_main, s); - - khm_add_property_sheet(s); -} - -static void -cw_pp_end(khui_property_sheet * s) -{ - khui_property_page * p = NULL; - - khui_ps_find_page(s, KHUI_PPCT_IDENTITY, &p); - if(p) { - PFREE(p->p_page); - p->p_page = NULL; - } - - p = NULL; - - khui_ps_find_page(s, KHUI_PPCT_CREDENTIAL, &p); - if(p) { - PFREE(p->p_page); - p->p_page = NULL; - } -} - -static void -cw_pp_destroy(khui_property_sheet *ps) -{ - if(ps->ctx.scope == KHUI_SCOPE_CRED) { - if(ps->header.pszCaption) - PFREE((LPWSTR) ps->header.pszCaption); - } - - khui_context_release(&ps->ctx); - - khui_ps_destroy_sheet(ps); - - /* this is pretty weird because ps gets freed when - khui_ps_destroy_sheet() is called. However, since destroying - ps involves sending a WM_DESTROY message to the property sheet, - we still need to keep it on the property sheet chain (or else - the messages will not be delivered). This is only safe because - we are not relinquishing the thread in-between destroying ps - and removing it from the chain. */ - - /* TODO: fix this */ - khm_del_property_sheet(ps); -} - -LRESULT -cw_properties(HWND hwnd) -{ - /* show a property sheet of some sort */ - khui_action_context ctx; - khui_property_sheet * ps; - khui_credwnd_tbl * tbl; - - khui_context_get(&ctx); - tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - - if(ctx.scope == KHUI_SCOPE_NONE) { - khui_context_release(&ctx); - return FALSE; - - /* While it seems like a good idea, doing this is not */ -#if 0 - /* try to establish a context based on the current cursor - position */ - if(tbl->cursor_row >= 0 && tbl->cursor_row < (int) tbl->n_rows) { - if(tbl->rows[tbl->cursor_row].flags & KHUI_CW_ROW_HEADER) { - if(tbl->cols[tbl->rows[tbl->cursor_row].col].attr_id == KCDB_ATTR_ID_NAME) { - /* identity context */ - ctx.ctx = KHUI_SCOPE_IDENT; - ctx.identity = (khm_handle) - ((khui_credwnd_outline *) tbl->rows[tbl->cursor_row].data)->data; - } else if(tbl->cols[tbl->rows[tbl->cursor_row].col].attr_id == KCDB_ATTR_TYPE_NAME) { - ctx.ctx = KHUI_SCOPE_CREDTYPE; - ctx.cred_type = (khm_int32) (DWORD_PTR) - ((khui_credwnd_outline *) tbl->rows[tbl->cursor_row].data)->data; - } else { - ctx.ctx = KHUI_SCOPE_GROUP; - //ctx.parm = (khm_lparm) tbl->rows[tbl->cursor_row].data; - /* TODO: Figure out method of establishing a credgroup */ - } - } else { - /* a credential context */ - ctx.ctx = KHUI_SCOPE_CRED; - ctx.cred = (khm_handle) tbl->rows[tbl->cursor_row].data; - } - } -#endif - } - - /* if still no context, then we can't show a property sheet */ - if(ctx.scope == KHUI_SCOPE_NONE) { - khui_context_release(&ctx); - return FALSE; - } - - khui_ps_create_sheet(&ps); - - if(ctx.scope == KHUI_SCOPE_IDENT) { - khm_handle ident; - khm_size t; - - ident = ctx.identity; - - ps->header.hInstance = khm_hInstance; - ps->header.pszIcon = MAKEINTRESOURCE(IDI_MAIN_APP); - - kcdb_identity_get_name(ident, NULL, &t); - - if(t > 0) { - ps->header.pszCaption = PMALLOC(t); - kcdb_identity_get_name(ident, - (wchar_t *) ps->header.pszCaption, &t); - } else { - ps->header.pszCaption = NULL; - } - - ps->ctx = ctx; - ps->identity = ident; - ps->credtype = KCDB_CREDTYPE_INVALID; - - kmq_post_message(KMSG_CRED, KMSG_CRED_PP_BEGIN, 0, (void *) ps); - - } else if(ctx.scope == KHUI_SCOPE_CREDTYPE) { - khm_size t = 0; - khm_int32 cred_type; - - if (ctx.identity == NULL) { - /* currently, we can't show a property sheet at this point - since most credentials providers don't provide a - property sheet that works without an identity. */ - - khui_context_release(&ctx); - khui_ps_destroy_sheet(ps); - return TRUE; - } - - cred_type = ctx.cred_type; - - ps->header.hInstance = khm_hInstance; - ps->header.pszIcon = MAKEINTRESOURCE(IDI_MAIN_APP); - - ps->ctx = ctx; - ps->credtype = cred_type; - - if(ctx.identity) { - ps->identity = ctx.identity; - /* also, if there is an associated identity, we assume that - the properties are for the specified credentials type - specific to the identity. Hence we change the title to - something else */ - kcdb_identity_get_name(ctx.identity, NULL, &t); - if (t > 0) { - ps->header.pszCaption = PMALLOC(t); - kcdb_identity_get_name(ctx.identity, (wchar_t *) ps->header.pszCaption, &t); - } else { - ps->header.pszCaption = NULL; - } - } else { - /* we don't actually reach here since we handle this case - above */ - kcdb_credtype_describe(cred_type, NULL, &t, KCDB_TS_LONG); - if(t > 0) { - ps->header.pszCaption = PMALLOC(t); - kcdb_credtype_describe(cred_type, (wchar_t *) ps->header.pszCaption, &t, KCDB_TS_LONG); - } else { - ps->header.pszCaption = NULL; - } - } - - kmq_post_message(KMSG_CRED, KMSG_CRED_PP_BEGIN, 0, (void *) ps); - } else if(ctx.scope == KHUI_SCOPE_CRED) { - khm_handle cred; - khm_size t; - - cred = ctx.cred; - - ps->header.hInstance = khm_hInstance; - ps->header.pszIcon = MAKEINTRESOURCE(IDI_MAIN_APP); - ps->ctx = ctx; - - kcdb_cred_get_name(cred, NULL, &t); - ps->header.pszCaption = PMALLOC(t); - kcdb_cred_get_name(cred, (LPWSTR) ps->header.pszCaption, &t); - - kcdb_cred_get_identity(cred, &ps->identity); - kcdb_cred_get_type(cred, &ps->credtype); - ps->cred = cred; - - kmq_post_message(KMSG_CRED, KMSG_CRED_PP_BEGIN, 0, (void *) ps); - } else { - khui_context_release(&ctx); - khui_ps_destroy_sheet(ps); - } - - /* by the way, if we are actually opening a property sheet, we - leave ctx held (which is now copied to ps->ctx). it will be - released when the property sheet is destroyed */ - - return TRUE; -} - -LRESULT -cw_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - khui_credwnd_tbl * tbl; - - tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - - if(HIWORD(wParam) == BN_CLICKED && - LOWORD(wParam) == KHUI_HTWND_CTLID) { - - wchar_t wid[256]; - /* a hyperlink was activated */ - khui_htwnd_link * l; - l = (khui_htwnd_link *) lParam; - StringCchCopyN(wid, ARRAYLENGTH(wid), l->id, l->id_len); - wid[l->id_len] = 0; - - if(!wcscmp(wid, L"NewCreds")) { - PostMessage(khm_hwnd_main, WM_COMMAND, - MAKEWPARAM(KHUI_ACTION_NEW_CRED,0), 0); - } - return TRUE; - } - - switch(LOWORD(wParam)) - { - case KHUI_PACTION_ENTER: - /* enter key is a synonym for the default action, on the - context, which is to lauch a property sheet */ - /* fallthrough */ - case KHUI_ACTION_PROPERTIES: - { - return cw_properties(hwnd); - } - break; - - case KHUI_ACTION_LAYOUT_RELOAD: - { - 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_selection_state(tbl); - cw_update_extents(tbl, TRUE); - - InvalidateRect(tbl->hwnd, NULL, TRUE); - } - break; - - case KHUI_ACTION_LAYOUT_ID: - { - cw_save_view(tbl, NULL); - cw_unload_view(tbl); - - cw_load_view(tbl, L"ByIdentity", hwnd); - cw_insert_header_cols(tbl); - - cw_update_creds(tbl); - cw_update_outline(tbl); - cw_update_selection_state(tbl); - cw_update_extents(tbl, TRUE); - - InvalidateRect(tbl->hwnd, NULL, TRUE); - - } - break; - - case KHUI_ACTION_LAYOUT_LOC: - { - cw_save_view(tbl, NULL); - cw_unload_view(tbl); - - cw_load_view(tbl, L"ByLocation", hwnd); - cw_insert_header_cols(tbl); - - cw_update_creds(tbl); - cw_update_outline(tbl); - cw_update_selection_state(tbl); - cw_update_extents(tbl, TRUE); - - InvalidateRect(tbl->hwnd, NULL, TRUE); - - } - 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_selection_state(tbl); - cw_update_extents(tbl, TRUE); - - InvalidateRect(tbl->hwnd, NULL, TRUE); - - } - 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_selection_state(tbl); - cw_update_extents(tbl, TRUE); - - InvalidateRect(tbl->hwnd, NULL, TRUE); - - } - break; - - case KHUI_ACTION_LAYOUT_MINI: - { - cw_save_view(tbl, NULL); - cw_unload_view(tbl); - - cw_load_view(tbl, NULL, hwnd); - cw_insert_header_cols(tbl); - - cw_update_creds(tbl); - cw_update_outline(tbl); - cw_update_selection_state(tbl); - cw_update_extents(tbl, TRUE); - - InvalidateRect(tbl->hwnd, NULL, TRUE); - } - break; - - case KHUI_PACTION_UP: - case KHUI_PACTION_UP_EXTEND: - case KHUI_PACTION_UP_TOGGLE: - { /* cursor up */ - khm_int32 new_row; - WPARAM wp = 0; - - new_row = tbl->cursor_row - 1; - - /* checking both bounds. we make no assumption about the - value of cursor_row before this message */ - if(new_row < 0) - new_row = 0; - if(new_row >= (int) tbl->n_rows) - new_row = (int) tbl->n_rows - 1; - - if (LOWORD(wParam) == KHUI_PACTION_UP) - wp = 0; - else if (LOWORD(wParam) == KHUI_PACTION_UP_EXTEND) - wp = MK_SHIFT; - else if (LOWORD(wParam) == KHUI_PACTION_UP_TOGGLE) - wp = 0; //MK_CONTROL; - else { -#ifdef DEBUG - assert(FALSE); -#endif - } - - cw_select_row(tbl, new_row, wp); - cw_ensure_row_visible(hwnd, tbl, new_row); - } - 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: - { /* cursor down */ - khm_int32 new_row; - WPARAM wp = 0; - - new_row = tbl->cursor_row + 1; - - /* checking both bounds. we make no assumption about the - value of cursor_row before this message */ - if(new_row < 0) - new_row = 0; - if(new_row >= (int) tbl->n_rows) - new_row = (int) tbl->n_rows - 1; - - if (LOWORD(wParam) == KHUI_PACTION_DOWN) - wp = 0; - else if (LOWORD(wParam) == KHUI_PACTION_DOWN_EXTEND) - wp = MK_SHIFT; - else if (LOWORD(wParam) == KHUI_PACTION_DOWN_TOGGLE) - wp = 0; //MK_CONTROL; - else { -#ifdef DEBUG - assert(FALSE); -#endif - } - - cw_select_row(tbl, new_row, wp); - cw_ensure_row_visible(hwnd, tbl, new_row); - } - 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); - } - break; - - case KHUI_PACTION_LEFT: - { /* collapse and up*/ - khui_credwnd_outline * o; - int r; - - if(tbl->cursor_row < 0 || tbl->cursor_row >= (int) tbl->n_rows) { - cw_select_row(tbl, 0, 0); - break; - } - - for(r = tbl->cursor_row; - (r >= 0 && !(tbl->rows[r].flags & KHUI_CW_ROW_HEADER)); - r--); - - if(r < 0) - break; - - /* If we were not on a header, we collapse the innermost - outline. Otherwise, we collpase up to the parent - outline level */ - - if(r != tbl->cursor_row) { - o = (khui_credwnd_outline *) tbl->rows[r].data; - - cw_toggle_outline_state(tbl, o); - } else { - o = (khui_credwnd_outline *) tbl->rows[r].data; - - if(o->flags & KHUI_CW_O_EXPAND) { - cw_toggle_outline_state(tbl, o); - } else { - o = TPARENT(o); - if(o) { - cw_toggle_outline_state(tbl, o); - r = o->start; - } else if(r > 0) - r--; - } - } - - cw_select_row(tbl, r, 0); - } - break; - - case KHUI_PACTION_RIGHT: - { /* expand and down*/ - khui_credwnd_outline * o; - int r; - - if(tbl->cursor_row < 0 || - tbl->cursor_row >= (int) tbl->n_rows) { - cw_select_row(tbl, 0, 0); - break; - } - - r = tbl->cursor_row; - - if(tbl->rows[r].flags & KHUI_CW_ROW_HEADER) { - o = (khui_credwnd_outline *) tbl->rows[r].data; - if(!(o->flags & KHUI_CW_O_EXPAND)) { - cw_toggle_outline_state(tbl, o); - } - } - - r++; - if (r >= (int) tbl->n_rows) - r = (int)tbl->n_rows - 1; - - cw_select_row(tbl, r, 0); - } - break; - } - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -LRESULT -cw_wm_contextmenu(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - RECT r; - int x,y; - int row; - khui_credwnd_tbl * tbl; - - tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - - GetWindowRect(hwnd, &r); - - x = GET_X_LPARAM(lParam); - y = GET_Y_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); - } - - if (tbl->flags & KHUI_CW_TBL_EXPIDENT) { - int i, yt; - - yt = 0; - for (i=0; i < tbl->n_rows && yt < y; i++) { - if (tbl->rows[i].flags & KHUI_CW_ROW_EXPVIEW) - yt += tbl->cell_height * CW_EXP_ROW_MULT; - else - yt += tbl->cell_height; - if (yt > y) - break; - } - - row = i; - - } else { - row = y / tbl->cell_height; - } - - if(row < 0 || row >= (int) tbl->n_rows) - return FALSE; - - cw_set_row_context(tbl, row); - - khm_menu_show_panel(KHUI_MENU_IDENT_CTX, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - -#if 0 - /* calling cw_set_row_context() should take care of enabling or - disabling actions as appropriate. We don't need to - differentiate between IDENT_CTX and TOK_CTX here. */ - if((tbl->rows[row].flags & KHUI_CW_ROW_HEADER) && - (tbl->cols[tbl->rows[row].col].attr_id == KCDB_ATTR_ID_NAME)) { - khm_menu_show_panel(KHUI_MENU_IDENT_CTX, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - //khui_context_reset(); - } else { - khm_menu_show_panel(KHUI_MENU_TOK_CTX, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - //khui_context_reset(); - } -#endif - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -/* copy and paste template */ -#if 0 -LRESULT -cw_wm_msg(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} -#endif - -LRESULT CALLBACK -khm_credwnd_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - switch(uMsg) { - case WM_COMMAND: - return cw_wm_command(hwnd, uMsg, wParam, lParam); - - case WM_CREATE: - return cw_wm_create(hwnd, uMsg, wParam, lParam); - - case WM_DESTROY: - return cw_wm_destroy(hwnd, uMsg, wParam, lParam); - - case WM_ERASEBKGND: - /* we don't bother wasting cycles erasing the background - because the foreground elements completely cover the - client area */ - return FALSE; - - case WM_PAINT: - return cw_wm_paint(hwnd, uMsg, wParam, lParam); - - case WM_PRINTCLIENT: - return cw_wm_paint(hwnd, uMsg, wParam, lParam); - - case WM_SIZE: - return cw_wm_size(hwnd, uMsg, wParam, lParam); - - case WM_NOTIFY: - return cw_wm_notify(hwnd, uMsg, wParam, lParam); - - case WM_HSCROLL: - return cw_wm_hscroll(hwnd, uMsg, wParam, lParam); - - case WM_VSCROLL: - return cw_wm_vscroll(hwnd, uMsg, wParam, lParam); - - case KMQ_WM_DISPATCH: - return cw_kmq_wm_dispatch(hwnd, uMsg, wParam, lParam); - - case WM_LBUTTONDBLCLK: - case WM_LBUTTONDOWN: - case WM_MOUSEMOVE: - case WM_LBUTTONUP: - return cw_wm_mouse(hwnd, uMsg, wParam, lParam); - - case WM_CONTEXTMENU: - return cw_wm_contextmenu(hwnd, uMsg, wParam, lParam); - } - - return DefWindowProc(hwnd,uMsg,wParam,lParam); -} - -void -khm_register_credwnd_class(void) { - WNDCLASSEX wcx; - kcdb_attrib attrib; - khm_int32 attr_id; - - wcx.cbSize = sizeof(wcx); - wcx.style = CS_DBLCLKS | CS_OWNDC; - wcx.lpfnWndProc = khm_credwnd_proc; - wcx.cbClsExtra = 0; - wcx.cbWndExtra = sizeof(LONG_PTR); - wcx.hInstance = khm_hInstance; - wcx.hIcon = NULL; - wcx.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); - wcx.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); - wcx.lpszMenuName = NULL; - wcx.lpszClassName = KHUI_CREDWND_CLASS_NAME; - wcx.hIconSm = NULL; - - khui_credwnd_cls = RegisterClassEx(&wcx); - - /* while we are at it, register the credwnd attribute type as well, and - obtain the type ID */ - if(KHM_FAILED(kcdb_attrib_get_id(KHUI_CREDWND_FLAG_ATTRNAME, &attr_id))) { - ZeroMemory(&attrib, sizeof(attrib)); - attrib.id = KCDB_ATTR_INVALID; - attrib.flags = KCDB_ATTR_FLAG_HIDDEN; - attrib.type = KCDB_TYPE_INT32; - attrib.name = KHUI_CREDWND_FLAG_ATTRNAME; - - kcdb_attrib_register(&attrib, &attr_id); - } - - khui_cw_flag_id = attr_id; -} - -void -khm_unregister_credwnd_class(void) { - UnregisterClass(MAKEINTATOM(khui_credwnd_cls), khm_hInstance); -} - -HWND -khm_create_credwnd(HWND parent) { - RECT r; - HWND hwnd; - - ZeroMemory(attr_to_action, sizeof(attr_to_action)); - - GetClientRect(parent, &r); - - hwnd = CreateWindowEx - (0, - MAKEINTATOM(khui_credwnd_cls), - L"", - WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, - r.left, - r.top, - r.right - r.left, - r.bottom - r.top, - parent, - NULL, - khm_hInstance, - NULL); - - return hwnd; -} +/* + * 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 + +ATOM khui_credwnd_cls; +khm_int32 khui_cw_flag_id; + +khm_int32 attr_to_action[KCDB_ATTR_MAX_ID + 1]; + +void +khm_set_cw_element_font(wchar_t * name, LOGFONT * pfont) { + khm_handle csp_cw = NULL; + wchar_t * element_name; + + if (name == NULL) + element_name = L"FontBase"; + else + element_name = name; + + if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_WRITE, + &csp_cw))) + return; + + khc_write_binary(csp_cw, element_name, pfont, sizeof(LOGFONT)); + + khc_close_space(csp_cw); +} + +void +khm_get_cw_element_font(HDC hdc, wchar_t * name, BOOL use_default, LOGFONT * pfont) { + khm_handle csp_cw = NULL; + khm_size cb; + wchar_t * element_name; + khm_boolean try_derive = FALSE; + + if (name == NULL) + element_name = L"FontBase"; + else + element_name = name; + + if (use_default) + goto _use_defaults; + + if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", 0, + &csp_cw))) + goto _use_defaults; + + cb = sizeof(LOGFONT); + if (KHM_FAILED(khc_read_binary(csp_cw, element_name, pfont, + &cb)) || + cb != sizeof(LOGFONT)) { + try_derive = TRUE; + } + + if (try_derive) { + cb = sizeof(LOGFONT); + if (!name || + KHM_FAILED(khc_read_binary(csp_cw, L"FontBase", pfont, + &cb)) || + cb != sizeof(LOGFONT)) { + khc_close_space(csp_cw); + goto _use_defaults; + } + + if (!wcscmp(name, L"FontHeaderBold") || + !wcscmp(name, L"FontBold")) { + + pfont->lfWeight = FW_BOLD; + + } + } + + khc_close_space(csp_cw); + + return; + + _use_defaults: + + ZeroMemory(pfont, sizeof(*pfont)); + + if (name == NULL) { + LOGFONT lf = { + -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"}; + + *pfont = lf; + + } else if (!wcscmp(name, L"FontHeader")) { + LOGFONT lf = { + -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"}; + + *pfont = lf; + + } else if (!wcscmp(name, L"FontHeaderBold")) { + LOGFONT lf = { + -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"}; + + *pfont = lf; + + } else if (!wcscmp(name, L"FontNormal")) { + LOGFONT lf = { + -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"}; + + *pfont = lf; + + } else if (!wcscmp(name, L"FontBold")) { + LOGFONT lf = { + -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"}; + + *pfont = lf; + + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } +} + +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) +{ + if(!wcscmp(s, CW_CANAME_FLAGS)) + return CW_CA_FLAGS; + if(!wcscmp(s, CW_CANAME_TYPEICON)) + return CW_CA_TYPEICON; + 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 we aren't saving to a specific view, and the view has been + customized, then we save it to "Custom_0", unless we are in the + mini mode, in which case we save it to "Custom_1" */ + if (!view_name && (tbl->flags & KHUI_CW_TBL_CUSTVIEW)) { + if (!(tbl->flags & KHUI_CW_TBL_EXPIDENT)) { + view_name = L"Custom_0"; + } else { + view_name = L"Custom_1"; + } + } + + 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, ((!(tbl->flags & KHUI_CW_TBL_EXPIDENT))? + L"DefaultView": + L"DefaultViewMini"), view_name); + } + + } else { + csp_view = tbl->csp_view; + } + + if (!csp_view) + goto _cleanup; + + if (tbl->flags & KHUI_CW_TBL_EXPIDENT) { + khc_write_int32(csp_view, L"ExpandedIdentity", 1); + } else { + khm_int32 t; + if (KHM_SUCCEEDED(khc_read_int32(csp_view, L"ExpandedIdentity", &t)) && t) + khc_write_int32(csp_view, L"ExpandedIdentity", 0); + } + + if (tbl->flags & KHUI_CW_TBL_NOHEADER) { + khc_write_int32(csp_view, L"NoHeader", 1); + } else { + khm_int32 t; + if (KHM_SUCCEEDED(khc_read_int32(csp_view, L"NoHeader", &t)) && t) + khc_write_int32(csp_view, L"NoHeader", 0); + } + + 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); + + { + khm_version v = app_version; + + khc_write_binary(csp_view, L"_AppVersion", &v, sizeof(v)); + } + + _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); +} + +static COLORREF +cw_mix_colors(COLORREF c1, COLORREF c2, int alpha) { + int r = (GetRValue(c1) * alpha + GetRValue(c2) * (255 - alpha)) / 255; + int g = (GetGValue(c1) * alpha + GetGValue(c2) * (255 - alpha)) / 255; + int b = (GetBValue(c1) * alpha + GetBValue(c2) * (255 - alpha)) / 255; + +#ifdef DEBUG + assert(alpha >= 0 && alpha < 256); +#endif + + return RGB(r,g,b); +} + +void +cw_load_view(khui_credwnd_tbl * tbl, wchar_t * view, HWND hwnd) { + khm_handle hc_cw = NULL; + khm_handle hc_vs = NULL; + khm_handle hc_v = NULL; + khm_handle hc_cs = NULL; + khm_handle hc_c = NULL; + wchar_t buf[KCONF_MAXCCH_NAME]; + wchar_t * clist = NULL; + khm_size cbsize; + wchar_t * iter = NULL; + int i; + HDC hdc; + LOGFONT log_font; + khm_int32 t; + const wchar_t * viewval; + khm_boolean reopen_csp = FALSE; + + tbl->hwnd = hwnd; + + if (khm_main_wnd_mode == KHM_MAIN_WND_MINI) + viewval = L"DefaultViewMini"; + else + viewval = L"DefaultView"; + + 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))) + goto _exit; + + if(!view) { + cbsize = sizeof(buf); + if(KHM_FAILED(khc_read_string(hc_cw, viewval, buf, &cbsize))) + goto _exit; + view = buf; + } else { + khc_write_string(hc_cw, viewval, view); + } + + /* 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); + else { + /* do nothing */ + } + + kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); + + if(KHM_FAILED(khc_open_space(hc_vs, view, 0, &hc_v))) + goto _exit; + + /* view data is very sensitive to version changes. We need to + check if this configuration data was created with this version + of NetIDMgr. If not, we switch to using a schema handle. */ + { + khm_version this_v = app_version; + khm_version cfg_v; + + cbsize = sizeof(cfg_v); + if (KHM_FAILED(khc_read_binary(hc_v, L"_AppVersion", &cfg_v, &cbsize)) || + khm_compare_version(&cfg_v, &this_v) != 0) { + + khc_close_space(hc_v); + + if (KHM_FAILED(khc_open_space(hc_vs, view, KCONF_FLAG_SCHEMA, + &hc_v)) && + (wcscmp(view, L"Custom_1") || + KHM_FAILED(khc_open_space(hc_vs, L"CompactIdentity", + KCONF_FLAG_SCHEMA, &hc_v)))) { + goto _exit; + } + + reopen_csp = TRUE; + } + } + + tbl->csp_view = hc_v; + + if(KHM_FAILED(khc_open_space(hc_v, L"Columns", + KHM_PERM_READ | (reopen_csp ? KCONF_FLAG_SCHEMA : 0), + &hc_cs))) + goto _exit; + + cbsize = 0; + if(khc_read_multi_string(hc_v, L"ColumnList", NULL, &cbsize) != KHM_ERROR_TOO_LONG) + goto _exit; + + /* temporary */ + clist = PMALLOC(cbsize); + + if(KHM_FAILED(khc_read_multi_string(hc_v, L"ColumnList", clist, &cbsize))) + 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->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); + + if (KHM_SUCCEEDED(khc_read_int32(hc_v, L"ExpandedIdentity", &t)) && t) { + tbl->flags |= KHUI_CW_TBL_EXPIDENT; + } else { + tbl->flags &= ~KHUI_CW_TBL_EXPIDENT; + } + + if (KHM_SUCCEEDED(khc_read_int32(hc_v, L"NoHeader", &t)) && t) { + tbl->flags |= KHUI_CW_TBL_NOHEADER; + } else { + tbl->flags &= ~KHUI_CW_TBL_NOHEADER; + } + + iter = clist; + i = 0; + while(iter) { + khm_int32 attr_id; + + attr_id = cw_get_custom_attr_id(iter); + if(!attr_id) { + /* a KCDB attribute */ + 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) { + 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 */ + tbl->cols[i].title = NULL; + } + + tbl->cols[i].attr_id = attr_id; + + if(KHM_SUCCEEDED(khc_open_space(hc_cs, iter, + KHM_PERM_READ | (reopen_csp ? KCONF_FLAG_SCHEMA : 0), + &hc_c))) { + 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 = 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; + } else { + tbl->cols[i].flags = 0; + tbl->cols[i].width = -1; + tbl->cols[i].sort_index = -1; + } + i++; +_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; + + /* now that all the columns have been loaded, load the view + parameters */ + if(KHM_FAILED(khc_read_int32(hc_v, L"PaddingHorizontal", &(tbl->hpad)))) + khc_read_int32(hc_cw, L"PaddingHorizontal", &(tbl->hpad)); + if(KHM_FAILED(khc_read_int32(hc_v, L"PaddingVertical", &(tbl->vpad)))) + khc_read_int32(hc_cw, L"PaddingVertical", &(tbl->vpad)); + if(KHM_FAILED(khc_read_int32(hc_v, L"PaddingHeader", &(tbl->hpad_h)))) + 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)); + + /* and the font resources and stuff */ + + tbl->flags |= KHUI_CW_TBL_INITIALIZED | KHUI_CW_TBL_COL_DIRTY | KHUI_CW_TBL_ACTIVE; + + /*TODO: the graphics objects should be customizable */ + + hdc = GetWindowDC(hwnd); + + khm_get_cw_element_font(hdc, L"FontHeader", FALSE, &log_font); + tbl->hf_header = CreateFontIndirect(&log_font); + + if(tbl->hf_header && tbl->hwnd_header) + SendMessage(tbl->hwnd_header, WM_SETFONT, (WPARAM) tbl->hf_header, 0); + + khm_get_cw_element_font(hdc, L"FontHeaderBold", FALSE, &log_font); + tbl->hf_bold_header = CreateFontIndirect(&log_font); + + + khm_get_cw_element_font(hdc, L"FontNormal", FALSE, &log_font); + tbl->hf_normal = CreateFontIndirect(&log_font); + + khm_get_cw_element_font(hdc, L"FontBold", FALSE, &log_font); + tbl->hf_bold = CreateFontIndirect(&log_font); + + ReleaseDC(hwnd, hdc); + + khui_bitmap_from_hbmp(&(tbl->kbm_logo_shade), + LoadImage(khm_hInstance, + MAKEINTRESOURCE(IDB_LOGO_SHADE), + IMAGE_BITMAP, + 0, + 0, + LR_DEFAULTCOLOR)); + + { +#define SEL_ALPHA 50 + + COLORREF bg_s = GetSysColor(COLOR_HIGHLIGHT); + COLORREF bg_normal = GetSysColor(COLOR_WINDOW); + COLORREF bg_gray = RGB(240,240,240); + COLORREF bg_hdr = RGB(240,240,240); + COLORREF bg_hdr_warn = RGB(235,235,134); + COLORREF bg_hdr_crit = RGB(235,184,134); + COLORREF bg_hdr_exp = RGB(235,134,134); + COLORREF bg_hdr_def = RGB(184,235,134); + + tbl->cr_normal = GetSysColor(COLOR_WINDOWTEXT); + tbl->cr_s = GetSysColor(COLOR_WINDOWTEXT); + tbl->cr_hdr_outline = RGB(0,0,0); + tbl->cr_hdr_normal = GetSysColor(COLOR_WINDOWTEXT); + tbl->cr_hdr_s = GetSysColor(COLOR_WINDOWTEXT); + tbl->cr_hdr_gray = GetSysColor(COLOR_GRAYTEXT); + tbl->cr_hdr_gray_s = GetSysColor(COLOR_HIGHLIGHTTEXT); + + if (khm_main_wnd_mode == KHM_MAIN_WND_MINI) { + bg_hdr = bg_normal; + tbl->cr_hdr_outline = bg_gray; + } + + tbl->hb_normal = CreateSolidBrush(bg_normal); + tbl->hb_grey = CreateSolidBrush(bg_gray); + tbl->hb_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_normal, SEL_ALPHA)); + + tbl->hb_hdr_bg = CreateSolidBrush(bg_hdr); + tbl->hb_hdr_bg_warn = CreateSolidBrush(bg_hdr_warn); + tbl->hb_hdr_bg_crit = CreateSolidBrush(bg_hdr_crit); + tbl->hb_hdr_bg_exp = CreateSolidBrush(bg_hdr_exp); + tbl->hb_hdr_bg_def = CreateSolidBrush(bg_hdr_def); + + tbl->hb_hdr_bg_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_hdr, SEL_ALPHA)); + tbl->hb_hdr_bg_warn_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_hdr_warn, SEL_ALPHA)); + tbl->hb_hdr_bg_crit_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_hdr_crit, SEL_ALPHA)); + tbl->hb_hdr_bg_exp_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_hdr_exp, SEL_ALPHA)); + tbl->hb_hdr_bg_def_s = CreateSolidBrush(cw_mix_colors(bg_s, bg_hdr_def, SEL_ALPHA)); + } + + tbl->ilist = khui_create_ilist(KHUI_SMICON_CX, KHUI_SMICON_CY-1, 20, 8, 0); + { + HBITMAP hbm; + +#define ADD_BITMAP(i) \ + hbm = LoadImage(khm_hInstance, MAKEINTRESOURCE(i), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); \ + if(hbm) { \ + khui_ilist_add_masked_id(tbl->ilist, hbm, KHUI_TOOLBAR_BGCOLOR, i); \ + DeleteObject(hbm); \ + } + + ADD_BITMAP(IDB_WDG_COLLAPSE); + 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 + } + + if (tbl->flags & KHUI_CW_TBL_EXPIDENT) { + tbl->hi_lg_ident = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP), + IMAGE_ICON, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON), + LR_DEFAULTCOLOR); + } + + tbl->cursor_row = -1; + tbl->scr_left = 0; + tbl->scr_top = 0; + tbl->ext_height = 0; + tbl->ext_width = 0; + + if (reopen_csp) { + khc_close_space(hc_v); + + hc_v = NULL; + + khc_open_space(hc_vs, view, 0, &hc_v); + + tbl->csp_view = hc_v; + } + +_exit: + if(hc_cw) + khc_close_space(hc_cw); + if(hc_vs) + khc_close_space(hc_vs); + 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. */ +} + +khui_credwnd_ident * +cw_find_ident(khui_credwnd_tbl * tbl, khm_handle ident) { + khm_size i; + + for (i=0; i < tbl->n_idents; i++) { + if (kcdb_identity_is_equal(ident, tbl->idents[i].ident)) + break; + } + + if (i < tbl->n_idents) + return &tbl->idents[i]; + else + return NULL; +} + +khm_int32 KHMAPI +cw_credset_iter_func(khm_handle cred, void * rock) { + khui_credwnd_tbl * tbl = (khui_credwnd_tbl *) rock; + khm_handle ident = NULL; + khm_size i; + khui_credwnd_ident * cwi = NULL; + khm_int32 cred_credtype = KCDB_CREDTYPE_INVALID; + khm_int32 cred_flags = 0; + + kcdb_cred_get_identity(cred, &ident); + + if (ident == NULL) + goto _cleanup; + + for (i=0; i < tbl->n_idents; i++) { + if (kcdb_identity_is_equal(ident, tbl->idents[i].ident)) + break; + } + + if (i >= tbl->n_idents) { + khm_size cb; + + /* need to add this one */ + if (tbl->n_idents == tbl->nc_idents) { + tbl->nc_idents = UBOUNDSS(tbl->n_idents + 1, + CW_IDENT_ALLOC_INCR, + CW_IDENT_ALLOC_INCR); +#ifdef DEBUG + assert(tbl->nc_idents > tbl->n_idents); +#endif + tbl->idents = PREALLOC(tbl->idents, sizeof(tbl->idents[0]) * tbl->nc_idents); +#ifdef DEBUG + assert(tbl->idents); +#endif + ZeroMemory(&tbl->idents[tbl->n_idents], + sizeof(tbl->idents[0]) * (tbl->nc_idents - tbl->n_idents)); + } + + i = tbl->n_idents; + cwi = &tbl->idents[tbl->n_idents++]; + + ZeroMemory(cwi, sizeof(*cwi)); + + cwi->ident = ident; + kcdb_identity_hold(ident); + + cb = sizeof(cwi->name); + kcdb_identity_get_name(ident, cwi->name, &cb); + } + + cwi = &tbl->idents[i]; + + /* this is the first time we are seeing this identity. */ + if (cwi->credcount == 0) { + khm_size cb; + + cb = sizeof(cwi->credtype); + if (KHM_SUCCEEDED(kcdb_identity_get_attr(ident, KCDB_ATTR_TYPE, NULL, + &cwi->credtype, &cb))) { + cwi->credtype_name[0] = L'\0'; + + cb = sizeof(cwi->credtype_name); + if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_TYPE_NAME, NULL, + &cwi->credtype, &cb))) { + cb = sizeof(cwi->credtype_name); + kcdb_credtype_describe(cwi->credtype, cwi->credtype_name, + &cb, KCDB_TS_SHORT); + } + } else { + cwi->credtype = KCDB_CREDTYPE_INVALID; + cwi->credtype_name[0] = L'\0'; + } + + cb = sizeof(cwi->ft_expire); + if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_EXPIRE, NULL, + &cwi->ft_expire, &cb))) { + cwi->ft_expire = IntToFt(0); + } + + kcdb_identity_get_flags(cwi->ident, &cwi->ident_flags); + } + + cwi->credcount++; + + kcdb_cred_get_type(cred, &cred_credtype); + if (cred_credtype >= 0 && cred_credtype == cwi->credtype) { + cwi->id_credcount++; + + kcdb_cred_get_flags(cred, &cred_flags); + if (cred_flags & KCDB_CRED_FLAG_INITIAL) { + cwi->init_credcount++; + } + } + + _cleanup: + if (ident) + kcdb_identity_release(ident); + + return KHM_ERROR_SUCCESS; +} + +void +cw_update_creds(khui_credwnd_tbl * tbl) +{ + kcdb_cred_comp_field * fields; + kcdb_cred_comp_order comp_order; + int i; + khm_int32 n; + khm_int32 delta; + khm_handle hc; + khm_int32 flags; + + if(!tbl->credset) { + if(KHM_FAILED(kcdb_credset_create(&(tbl->credset)))) + return; + } + + kcdb_credset_purge(tbl->credset); + + kcdb_identity_refresh_all(); + + kcdb_credset_collect( + tbl->credset, + NULL, + NULL, + KCDB_CREDTYPE_ALL, + &delta); + + /* now we need to figure out how to sort the credentials */ + fields = PMALLOC(sizeof(kcdb_cred_comp_field) * tbl->n_cols); + ZeroMemory(fields, sizeof(kcdb_cred_comp_field) * tbl->n_cols); + + 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)) { + int si; + /* we need to sort by this column */ + si = tbl->cols[i].sort_index; + + if(si < 0 || si >= (int) tbl->n_cols) + { + /* this shouldn't happen */ + tbl->cols[i].flags &= ~(KHUI_CW_COL_SORT_INC | + KHUI_CW_COL_SORT_DEC | + KHUI_CW_COL_GROUP); + continue; + } + + fields[si].attrib = tbl->cols[i].attr_id; + if(tbl->cols[i].flags & KHUI_CW_COL_SORT_DEC) + fields[si].order = KCDB_CRED_COMP_DECREASING; + else + fields[si].order = KCDB_CRED_COMP_INCREASING; + + /* special case. if we are sorting by name, we group + initial tickets before non-initial tickets. + + Also, if we are sorting by credential type name, then + we allow the primary credential type first before + others. */ + + if (fields[si].attrib == KCDB_ATTR_NAME || + fields[si].attrib == KCDB_ATTR_TYPE_NAME) + fields[si].order |= KCDB_CRED_COMP_INITIAL_FIRST; + + if(si >= n) + n = si+1; + } + } + + /* we assume that the sort order is sane */ + /*TODO: don't assume; check if the sort order is sane */ + + comp_order.nFields = n; + comp_order.fields = fields; + + kcdb_credset_sort(tbl->credset, + kcdb_cred_comp_generic, + (void *) &comp_order); + + /* also, if new credentials were added, initialize the UI flag + attribute to 0 */ + if(delta & KCDB_DELTA_ADD) { + khm_size s; + + kcdb_credset_get_size(tbl->credset, &s); + 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, + NULL, NULL))) { + flags = 0; + kcdb_cred_set_attr(hc, khui_cw_flag_id, &flags, sizeof(flags)); + } + kcdb_cred_release(hc); + } + } + + /* refresh the per-identity information */ + for (i=0; i < (int) tbl->n_idents; i++) { + tbl->idents[i].credcount = 0; + tbl->idents[i].id_credcount = 0; + tbl->idents[i].init_credcount = 0; + } + + kcdb_credset_apply(tbl->credset, cw_credset_iter_func, (void *) tbl); + + if (fields) + PFREE(fields); +} + +void +cw_del_outline(khui_credwnd_outline *o) { + khui_credwnd_outline * c; + if(!o) + return; + + /* the outline object is still in a list */ + if(o->next || o->prev) + return; + + if(o->header) + PFREE(o->header); + + if ((o->flags & KHUI_CW_O_DATAALLOC) && + o->data) + PFREE(o->data); + + if ((o->flags & KHUI_CW_O_RELIDENT) && + o->data) + kcdb_identity_release((khm_handle) o->data); + + LPOP(&(o->children), &c); + while(c) { + cw_del_outline(c); + LPOP(&(o->children), &c); + } + + ZeroMemory(o, sizeof(*o)); + PFREE(o); +} + +khui_credwnd_outline * +cw_new_outline_node(wchar_t * heading) { + khui_credwnd_outline * o; + size_t cblen; + + o = PMALLOC(sizeof(khui_credwnd_outline)); + ZeroMemory(o, sizeof(khui_credwnd_outline)); + + if(SUCCEEDED(StringCbLength(heading, KHUI_MAXCB_HEADING, &cblen))) { + cblen += sizeof(wchar_t); + o->header = PMALLOC(cblen); + StringCbCopy(o->header, cblen, heading); + } + o->start = -1; + + return o; +} + +/* buf is a handle to a credential or an identity. the kcdb_buf_* + functions work with either. */ +khm_int32 +cw_get_buf_exp_flags(khui_credwnd_tbl * tbl, khm_handle buf) +{ + khm_int32 flags; + long s; + FILETIME ft_expire; + FILETIME ft_current; + FILETIME ft_difference; + khm_size cbsize; + + cbsize = sizeof(ft_expire); + if(KHM_FAILED(kcdb_buf_get_attr(buf, KCDB_ATTR_EXPIRE, NULL, + &ft_expire, &cbsize))) + return 0; + + GetSystemTimeAsFileTime(&ft_current); + ft_difference = FtSub(&ft_expire, &ft_current); + + s = FtIntervalToSeconds(&ft_difference); + + flags = 0; + if(s < 0) + flags = CW_EXPSTATE_EXPIRED; + else if(s < tbl->threshold_critical) + flags = CW_EXPSTATE_CRITICAL; + else if(s < tbl->threshold_warn) + flags = CW_EXPSTATE_WARN; + else + flags = CW_EXPSTATE_NONE; + + return flags; +} + +void cw_update_outline(khui_credwnd_tbl * tbl); + +static void +cw_update_selection_state(khui_credwnd_tbl * tbl); + +VOID CALLBACK +cw_timer_proc(HWND hwnd, + UINT uMsg, + UINT_PTR idEvent, + DWORD dwTime) +{ + khui_credwnd_tbl * tbl; + khui_credwnd_row * r; + khm_int32 nflags; + int nr; + long ms; + FILETIME ft; + khm_size cbsize; + int timer_set = 0; + + KillTimer(hwnd, idEvent); + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + r = (khui_credwnd_row *) idEvent; + r->flags &= ~KHUI_CW_ROW_TIMERSET; + + nr = (int)(r - tbl->rows); + + if(nr < 0 || nr >= tbl->n_rows) + return; + + if(r->flags & KHUI_CW_ROW_CRED) { + + nflags = cw_get_buf_exp_flags(tbl, (khm_handle) r->data); + if((r->flags & CW_EXPSTATE_MASK) != nflags) { + /* flags have changed */ + /* the outline needs to be updated */ + cw_update_outline(tbl); + InvalidateRect(tbl->hwnd, NULL, FALSE); + } else { + /* just invalidate the row */ + RECT rc,rr,ri; + + GetClientRect(tbl->hwnd, &rc); + rc.top += tbl->header_height; + + rr = r->r_ext; + OffsetRect(&rr, 0, tbl->header_height - tbl->scr_top); + + if(IntersectRect(&ri, &rc, &rr)) + InvalidateRect(tbl->hwnd, &ri, FALSE); + + cbsize = sizeof(ft); + 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); + timer_set = 1; + } + } + + if (timer_set) + r->flags |= KHUI_CW_ROW_TIMERSET; + } + } else { + khui_credwnd_outline * o; + khui_credwnd_ident * cwi; + FILETIME ft_now; + + o = (khui_credwnd_outline *) r->data; +#ifdef DEBUG + assert(r->flags & KHUI_CW_ROW_EXPVIEW); + assert(o->attr_id == KCDB_ATTR_ID); + assert(tbl->flags & KHUI_CW_TBL_EXPIDENT); +#endif + + nflags = cw_get_buf_exp_flags(tbl, (khm_handle) o->data); + if ((o->flags & CW_EXPSTATE_MASK) != nflags) { + cw_update_outline(tbl); + InvalidateRect(tbl->hwnd, NULL, FALSE); + } else { + RECT rc, rr, ri; + + GetClientRect(tbl->hwnd, &rc); + rc.top += tbl->header_height; + + rr = r->r_ext; + OffsetRect(&rr, 0, tbl->header_height - tbl->scr_top); + + if (IntersectRect(&ri, &rc, &rr)) + InvalidateRect(tbl->hwnd, &ri, FALSE); + + cwi = cw_find_ident(tbl, o->data); + + GetSystemTimeAsFileTime(&ft_now); + if (CompareFileTime(&cwi->ft_expire, &ft_now) > 0) { + ft = FtSub(&cwi->ft_expire, &ft_now); + ms = FtIntervalMsToRepChange(&ft); + if (ms > 0) { + SetTimer(tbl->hwnd, (UINT_PTR) r, ms + 100, cw_timer_proc); + timer_set = 1; + } + } + + if (timer_set) + r->flags |= KHUI_CW_ROW_TIMERSET; + } + } +} + +void +cw_set_tbl_row_cred(khui_credwnd_tbl * tbl, + int row, + khm_handle cred, + int col) +{ + FILETIME ft; + long ms; + khm_size cbsize; + + if((int) tbl->n_total_rows <= row) { + /* we need to resize the allocation */ + khui_credwnd_row * newrows; + int newsize; + + newsize = UBOUNDSS(row+1,KHUI_CW_ROW_INITIAL, KHUI_CW_ROW_INCREMENT); + newrows = PMALLOC(sizeof(khui_credwnd_row) * newsize); + memcpy(newrows, tbl->rows, sizeof(khui_credwnd_row) * tbl->n_rows); + PFREE(tbl->rows); + tbl->rows = newrows; + tbl->n_total_rows = newsize; + } + + tbl->rows[row].col = col; + tbl->rows[row].data = cred; + tbl->rows[row].flags = KHUI_CW_ROW_CRED; + + /* Set any required timer events */ + cbsize = sizeof(ft); + if(KHM_SUCCEEDED(kcdb_cred_get_attr(cred, KCDB_ATTR_TIMELEFT, NULL, &ft, &cbsize))) { + ms = FtIntervalMsToRepChange(&ft); + if(ms > 0) { + SetTimer(tbl->hwnd, (UINT_PTR) &(tbl->rows[row]), ms + 100, cw_timer_proc); + tbl->rows[row].flags |= KHUI_CW_ROW_TIMERSET; + } + } +} + +void +cw_set_tbl_row_header(khui_credwnd_tbl * tbl, + int row, int col, + khui_credwnd_outline * o) +{ + if((int) tbl->n_total_rows <= row) { + /* we need to resize the allocation */ + khui_credwnd_row * newrows; + int newsize; + + newsize = UBOUNDSS(row+1,KHUI_CW_ROW_INITIAL, KHUI_CW_ROW_INCREMENT); + newrows = PMALLOC(sizeof(khui_credwnd_row) * newsize); + memcpy(newrows, tbl->rows, sizeof(khui_credwnd_row) * tbl->n_rows); + PFREE(tbl->rows); + tbl->rows = newrows; + tbl->n_total_rows = newsize; + } + + tbl->rows[row].col = col; + tbl->rows[row].data = (khm_handle) o; + tbl->rows[row].flags = KHUI_CW_ROW_HEADER; + if(o->flags & KHUI_CW_O_SELECTED) + tbl->rows[row].flags |= KHUI_CW_ROW_SELECTED; + + /* if we are showing expanded identity information, we need to set + a timer so that we can update the identity row when the + identity changes. */ + if ((tbl->flags & KHUI_CW_TBL_EXPIDENT) && + tbl->cols[col].attr_id == KCDB_ATTR_ID_NAME) { + + khui_credwnd_ident * cwi; + + tbl->rows[row].flags |= KHUI_CW_ROW_EXPVIEW; + + cwi = cw_find_ident(tbl, o->data); + if (cwi && FtToInt(&cwi->ft_expire) != 0) { + FILETIME ft; + FILETIME ft_now; + + ft = cwi->ft_expire; + GetSystemTimeAsFileTime(&ft_now); + + if (CompareFileTime(&ft, &ft_now) > 0) { + long ms; + + ft = FtSub(&ft, &ft_now); + ms = FtIntervalMsToRepChange(&ft); + if (ms > 0) { + SetTimer(tbl->hwnd, (UINT_PTR) &(tbl->rows[row]), ms + 100, + cw_timer_proc); + tbl->rows[row].flags |= KHUI_CW_ROW_TIMERSET; + } + } + } + } +} + +static int +iwcscmp(const void * p1, const void * p2) { + const wchar_t * s1 = *(wchar_t **) p1; + const wchar_t * s2 = *(wchar_t **) p2; + + return wcscmp(s1, s2); +} + +void +cw_update_outline(khui_credwnd_tbl * tbl) +{ + int i,j,n_rows; + int level; + int visible; + 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 + group the display by. Say we are grouping by identity and then + by type, then grouping[0]=col# of identity and grouping[1]=col# + of type */ + khm_int32 * grouping = NULL; + khui_credwnd_outline * ol = NULL; + int n_grouping; + wchar_t buf[256]; + khm_size cbbuf; + khm_int32 flags; + int selected; + khm_int32 expstate = 0; + + /* this is called after calling cw_update_creds, so we assume + that the credentials are all loaded and sorted according to + grouping rules */ + + /* if the columns have changed, then any outline info we have + cached are unreliable */ + if(tbl->flags & KHUI_CW_TBL_COL_DIRTY) { + khui_credwnd_outline * o; + LPOP(&(tbl->outline), &o); + while(o) { + cw_del_outline(o); + LPOP(&(tbl->outline), &o); + } + tbl->n_rows = 0; + } + + /* Otherwise, we should reset the outline indices. Just the first + level is enough */ + if (tbl->outline) { + khui_credwnd_outline * o; + + o = tbl->outline; + while(o) { + o->start = -1; + o = LNEXT(o); + } + } + + /* determine the grouping order */ + grouping = PMALLOC(sizeof(khm_int32) * tbl->n_cols); + for(i=0; i < (int) tbl->n_cols; i++) + grouping[i] = -1; + n_grouping = 0; + + for(i=0; i < (int) tbl->n_cols; i++) { + /* since cw_update_creds has run, the KHUI_CW_COL_GROUP flag + only exists for columns that has a valid sort_index */ + if(tbl->cols[i].flags & KHUI_CW_COL_GROUP) { + grouping[tbl->cols[i].sort_index] = i; + if(n_grouping <= tbl->cols[i].sort_index) + n_grouping = tbl->cols[i].sort_index + 1; + } + } + + /* if we have sorted by an index without grouping by it, we can't + establish any grouping beyond that index. */ + for(i=0; i < n_grouping; i++) { + if(grouping[i] == -1) + break; + } + n_grouping = i; + + if(!tbl->rows) { + /* we haven't allocated memory yet */ + tbl->n_total_rows = KHUI_CW_ROW_INITIAL; + tbl->n_rows = 0; + tbl->rows = PMALLOC(sizeof(khui_credwnd_row) * tbl->n_total_rows); + } else { + /* kill any pending timers */ + for(i=0; i < (int) tbl->n_rows; i++) + if(tbl->rows[i].flags & KHUI_CW_ROW_TIMERSET) + { + KillTimer(tbl->hwnd, (UINT_PTR) &(tbl->rows[i])); + tbl->rows[i].flags &= ~KHUI_CW_ROW_TIMERSET; + } + } + + if(KHM_FAILED(kcdb_credset_get_size(tbl->credset, &n_creds))) + goto _exit; + + n_rows = 0; + prevcred = NULL; + ol = NULL; + + for(i=0; i < (int) n_creds; i++) { + if(KHM_FAILED(kcdb_credset_get_cred(tbl->credset, i, &thiscred))) + continue; + + /* if this credential appears to be the same as another for + this view, we skip it. */ + if(prevcred && n_grouping > 0) { + for(j=0; j < (int) tbl->n_cols; j++) { + if(kcdb_creds_comp_attr(prevcred, thiscred, + tbl->cols[j].attr_id)) + break; + } + + if(j >= (int) tbl->n_cols) { + if (n_rows > 0) { + tbl->rows[n_rows - 1].idx_end = i; + } + continue; + } + } + + if(!prevcred) + level = 0; + else { + for(j=0; j < n_grouping; j++) { + /* determine the grouping level at which thiscred + differs from prevcred */ + if(kcdb_creds_comp_attr(prevcred,thiscred, + tbl->cols[grouping[j]].attr_id)) + break; + } + level = j; + } + + /* now we have to walk up until we get to the parent of the + outline level we should be in */ + while(ol && ol->level >= level) { + ol->length = n_rows - ol->start; + ol->idx_end = i - 1; + ol = TPARENT(ol); + } + + if(ol) { + visible = (ol->flags & KHUI_CW_O_VISIBLE) && + (ol->flags & KHUI_CW_O_EXPAND); + selected = (ol->flags & KHUI_CW_O_SELECTED); + } else { + visible = TRUE; + selected = FALSE; + } + + /* now ol points to an outline node at the next highest level + or is NULL if level = 0 */ + + for(j=level; j < n_grouping; j++) { + khui_credwnd_outline * to; + /* now we search for an outline object at the next level + which matches the heading */ + cbbuf = sizeof(buf); + buf[0] = L'\0'; + if(KHM_FAILED + (kcdb_cred_get_attr_string(thiscred, + tbl->cols[grouping[j]].attr_id, + buf, &cbbuf, 0))) { + cbbuf = sizeof(wchar_t); + buf[0] = L'\0'; + } + + if(ol) + to = TFIRSTCHILD(ol); + else + to = tbl->outline; + + while(to) { + if(!wcscmp(buf, to->header)) + break; + to = LNEXT(to); + } + + if(to) { + /* found it */ + ol = to; + } else { + /* not found. create */ + to = cw_new_outline_node(buf); + if(ol) { + TADDCHILD(ol, to); + } else { + LPUSH(&(tbl->outline), to); + } + ol = to; + ol->flags = KHUI_CW_O_EXPAND; + ol->level = j; + ol->col = grouping[j]; + + if(tbl->cols[grouping[j]].attr_id == KCDB_ATTR_ID_NAME) { + khm_handle h; + if(KHM_SUCCEEDED(kcdb_identity_create(buf, 0, &h))) { + ol->attr_id = KCDB_ATTR_ID; + ol->data = (void *) h; + + /* the outline only lasts as long as the + credential, and the credential has a hold + on the identity. */ + kcdb_identity_release(h); + } + else + ol->data = 0; + } else if(tbl->cols[grouping[j]].attr_id == + KCDB_ATTR_TYPE_NAME) { + khm_int32 t; + + ol->attr_id = KCDB_ATTR_TYPE; + if(KHM_SUCCEEDED(kcdb_cred_get_type(thiscred, &t))) + ol->data = (void *)(ssize_t) t; + else + ol->data = (void *)(ssize_t) KCDB_CREDTYPE_INVALID; + } else { + khm_int32 rv; + khm_int32 alt_id; + kcdb_attrib * attrib; + + rv = + kcdb_attrib_get_info(tbl->cols[grouping[j]].attr_id, + &attrib); + assert(KHM_SUCCEEDED(rv)); + + if (attrib->flags & KCDB_ATTR_FLAG_ALTVIEW) + alt_id = attrib->alt_id; + else + alt_id = tbl->cols[grouping[j]].attr_id; + + ol->attr_id = alt_id; + + kcdb_attrib_release_info(attrib); + + rv = kcdb_cred_get_attr(thiscred, + alt_id, + NULL, + NULL, + &cbbuf); + if (rv != KHM_ERROR_TOO_LONG || cbbuf == 0) { + ol->data = NULL; + } else { + ol->data = PMALLOC(cbbuf); + assert(ol->data); + rv = kcdb_cred_get_attr(thiscred, + alt_id, + NULL, + ol->data, + &cbbuf); + assert(KHM_SUCCEEDED(rv)); + ol->cb_data = cbbuf; + ol->flags |= KHUI_CW_O_DATAALLOC; + } + } + } + + /* now ol points at the node at level j we want to be + in */ + ol->start = n_rows; + ol->length = 0; + ol->idx_start = i; + ol->idx_end = i; + ol->flags &= ~(CW_EXPSTATE_MASK | + KHUI_CW_O_SHOWFLAG | + KHUI_CW_O_STICKY | + KHUI_CW_O_EMPTY); + + /* if the outline node is for an identity, then we have to + check the expiration state for the identity. */ + + if (ol->attr_id == KCDB_ATTR_ID) { + khm_handle ident = (khm_handle) ol->data; + + flags = cw_get_buf_exp_flags(tbl, ident); + + if (flags) { + ol->flags |= flags; + ol->flags |= KHUI_CW_O_SHOWFLAG; + expstate |= flags; + } else if (grouping[j] == tbl->n_cols - 1) { + /* if we aren't showing any creds under this + outline level, we should also show any + flags. */ + ol->flags |= KHUI_CW_O_SHOWFLAG; + } + } + + if (grouping[j] == tbl->n_cols - 1) { + ol->flags |= KHUI_CW_O_NOOUTLINE; + } else { + ol->flags &= ~KHUI_CW_O_NOOUTLINE; + } + + if(selected) { + ol->flags |= KHUI_CW_O_SELECTED; + } + if(visible) { + cw_set_tbl_row_header(tbl, n_rows, grouping[j], ol); + n_rows ++; + ol->flags |= KHUI_CW_O_VISIBLE; + } else { + ol->flags &= ~KHUI_CW_O_VISIBLE; + } + visible = visible && (ol->flags & KHUI_CW_O_EXPAND); + selected = (selected || (ol->flags & KHUI_CW_O_SELECTED)); + + } + + /* we need to do this here too just in case we were already at + the level we were supposed to be in */ + if (ol) + visible = visible && (ol->flags & KHUI_CW_O_EXPAND); + + if(visible && n_grouping > 0 && + grouping[n_grouping - 1] < tbl->n_cols - 1) { + khm_int32 c_flags; + + cw_set_tbl_row_cred(tbl, n_rows, thiscred, + grouping[n_grouping-1]); + + flags = cw_get_buf_exp_flags(tbl, thiscred); + if(flags) { + tbl->rows[n_rows].flags |= flags; + } + + kcdb_cred_get_flags(thiscred, &c_flags); + if(selected || + (c_flags & KCDB_CRED_FLAG_SELECTED)) { + tbl->rows[n_rows].flags |= KHUI_CW_ROW_SELECTED; + } + + tbl->rows[n_rows].idx_start = i; + tbl->rows[n_rows].idx_end = i; + + n_rows++; + } + + if(prevcred) + kcdb_cred_release(prevcred); + prevcred = thiscred; + } + + while(ol) { + ol->length = n_rows - ol->start; + ol->idx_end = i - 1; + ol = TPARENT(ol); + } + + if(prevcred) { + kcdb_cred_release(prevcred); + prevcred = NULL; + } + + /* Add any default identities with no credentials and sticky + identities that we haven't seen yet */ + if (n_grouping > 0 && + tbl->cols[grouping[0]].attr_id == KCDB_ATTR_ID_NAME) { + + khui_credwnd_outline * o; + wchar_t * idnames = NULL; + wchar_t * t; + khm_size n_idents; + khm_size cb_names; + wchar_t ** idarray = NULL; + int i; + + /* see if the defualt identity is in the list */ + { + khm_handle id_def = NULL; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khm_int32 flags; + + if (KHM_FAILED(kcdb_identity_get_default(&id_def))) { + goto done_with_defident; + } + + kcdb_identity_get_flags(id_def, &flags); + cb = sizeof(idname); + kcdb_identity_get_name(id_def, idname, &cb); + + for (o = tbl->outline; o; o = LNEXT(o)) { + if (!wcscmp(idname, o->header)) + break; + } + + if (o == NULL) { + o = cw_new_outline_node(idname); + LPUSH(&tbl->outline, o); + o->flags = KHUI_CW_O_VISIBLE | KHUI_CW_O_RELIDENT | KHUI_CW_O_EMPTY; + o->level = 0; + o->col = grouping[0]; + o->data = id_def; + o->attr_id = KCDB_ATTR_ID; + o->start = -1; + } else { + kcdb_identity_release(id_def); + } + + if (o->start != -1) + goto done_with_defident; + + if (flags & KCDB_IDENT_FLAG_STICKY) + o->flags |= KHUI_CW_O_STICKY; + else + o->flags &= ~KHUI_CW_O_STICKY; + + o->start = n_rows; + o->length = 1; + o->idx_start = -1; + o->idx_end = -1; + + if (grouping[0] == tbl->n_cols - 1) + o->flags |= KHUI_CW_O_NOOUTLINE; + + cw_set_tbl_row_header(tbl, n_rows, grouping[0], o); + + n_rows ++; + + done_with_defident: + ; + } + + if (kcdb_identity_enum(KCDB_IDENT_FLAG_STICKY, + KCDB_IDENT_FLAG_STICKY, + NULL, + &cb_names, + &n_idents) != KHM_ERROR_TOO_LONG || + n_idents == 0 || + cb_names == 0) + goto _cleanup_sticky; + + idnames = PMALLOC(cb_names); + idarray = PMALLOC(n_idents * sizeof(*idarray)); +#ifdef DEBUG + assert(idnames); + assert(idarray); +#endif + + if (KHM_FAILED(kcdb_identity_enum(KCDB_IDENT_FLAG_STICKY, + KCDB_IDENT_FLAG_STICKY, + idnames, + &cb_names, + &n_idents))) + goto _cleanup_sticky; + + for (i=0, t=idnames; t && *t; t = multi_string_next(t), i++) { + idarray[i] = t; + } + + qsort(idarray, n_idents, sizeof(*idarray), iwcscmp); + + for (i=0; i < (int) n_idents; i++) { + khm_handle h; + + if (KHM_FAILED(kcdb_identity_create(idarray[i], + KCDB_IDENT_FLAG_CREATE, &h))) + continue; + + for (o = tbl->outline; o; o = LNEXT(o)) { + if (!wcscmp(idarray[i], o->header)) + break; + } + + if (o) { + /* found it */ + if (o->start != -1) /* already visible? */ + continue; + o->flags &= KHUI_CW_O_RELIDENT; + o->flags |= KHUI_CW_O_STICKY | KHUI_CW_O_VISIBLE | KHUI_CW_O_EMPTY; + + if (!kcdb_identity_is_equal(o->data, h)) { + if (o->flags & KHUI_CW_O_RELIDENT) + kcdb_identity_release(o->data); + o->data = h; + o->flags |= KHUI_CW_O_RELIDENT; + kcdb_identity_hold(h); + } + } else { + /* not found. create */ + o = cw_new_outline_node(idarray[i]); + LPUSH(&tbl->outline, o); + o->flags = KHUI_CW_O_STICKY | KHUI_CW_O_VISIBLE | KHUI_CW_O_EMPTY | KHUI_CW_O_RELIDENT; + o->level = 0; + o->col = grouping[0]; + o->data = h; + kcdb_identity_hold(h); + o->attr_id = KCDB_ATTR_ID; + } + + if (grouping[0] == tbl->n_cols - 1) + o->flags |= KHUI_CW_O_NOOUTLINE; + + kcdb_identity_release(h); + + o->flags &= ~KHUI_CW_O_EXPAND; + o->start = n_rows; + o->length = 1; + o->idx_start = -1; + o->idx_end = -1; + + cw_set_tbl_row_header(tbl, n_rows, grouping[0], o); + + n_rows ++; + } + + _cleanup_sticky: + if (idnames) + PFREE(idnames); + if (idarray) + PFREE(idarray); + } + + tbl->n_rows = n_rows; + 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); + + /* note that the expstate is derived from whether or not + * we have expiration states set for any active identities */ + if (n_creds == 0) + khm_notify_icon_expstate(KHM_NOTIF_EMPTY); + else if ((expstate & CW_EXPSTATE_EXPIRED) == CW_EXPSTATE_EXPIRED) + khm_notify_icon_expstate(KHM_NOTIF_EXP); + else if ((expstate & CW_EXPSTATE_WARN) == CW_EXPSTATE_WARN || + (expstate & CW_EXPSTATE_CRITICAL) == CW_EXPSTATE_CRITICAL) + khm_notify_icon_expstate(KHM_NOTIF_WARN); + else + khm_notify_icon_expstate(KHM_NOTIF_OK); +} + +void +cw_unload_view(khui_credwnd_tbl * tbl) +{ +#define SafeDeleteObject(o) \ + do { \ + if(o) { \ + DeleteObject(o); \ + o = NULL; \ + } \ + } while(0) + + SafeDeleteObject(tbl->hf_header); + SafeDeleteObject(tbl->hf_normal); + SafeDeleteObject(tbl->hf_bold); + SafeDeleteObject(tbl->hf_bold_header); + + SafeDeleteObject(tbl->hb_grey); + SafeDeleteObject(tbl->hb_normal); + SafeDeleteObject(tbl->hb_s); + + SafeDeleteObject(tbl->hb_hdr_bg); + SafeDeleteObject(tbl->hb_hdr_bg_crit); + SafeDeleteObject(tbl->hb_hdr_bg_exp); + SafeDeleteObject(tbl->hb_hdr_bg_warn); + SafeDeleteObject(tbl->hb_hdr_bg_def); + + SafeDeleteObject(tbl->hb_hdr_bg_s); + SafeDeleteObject(tbl->hb_hdr_bg_crit_s); + SafeDeleteObject(tbl->hb_hdr_bg_exp_s); + SafeDeleteObject(tbl->hb_hdr_bg_warn_s); + SafeDeleteObject(tbl->hb_hdr_bg_def_s); + +#undef SafeDeleteObject + + if (tbl->hi_lg_ident) { + DestroyIcon(tbl->hi_lg_ident); + tbl->hi_lg_ident = NULL; + } + + if(tbl->credset) { + kcdb_credset_delete(tbl->credset); + tbl->credset = NULL; + } + if(tbl->ilist) { + khui_delete_ilist(tbl->ilist); + tbl->ilist = NULL; + } + + if(tbl->cols) { + 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) { + PFREE(tbl->rows); + tbl->rows = NULL; + tbl->n_rows = 0; + tbl->n_total_rows = 0; + } + + khui_delete_bitmap(&tbl->kbm_logo_shade); + + if (tbl->csp_view) { + khc_close_space(tbl->csp_view); + tbl->csp_view = NULL; + } + + tbl->cell_height = 0; /* recalculate cell height next time */ + + if (tbl->idents) { + khm_size i; + + for (i=0; i < tbl->n_idents; i++) { + if (tbl->idents[i].ident) { + kcdb_identity_release(tbl->idents[i].ident); + } + } + + PFREE(tbl->idents); + tbl->idents = NULL; + tbl->n_idents = 0; + tbl->nc_idents = 0; + } +} + +void +cw_hditem_from_tbl_col(khui_credwnd_col * col, HDITEM *phi) +{ + size_t cchsize; + + phi->mask = HDI_FORMAT | HDI_LPARAM | HDI_WIDTH; + if(cw_is_custom_attr(col->attr_id)) { + if(col->attr_id == CW_CA_FLAGS) { + phi->fmt = 0; + } else if(col->attr_id == CW_CA_TYPEICON) { + phi->fmt = 0; + } else { + /* what the? */ + /*TODO: throw up and die */ + } + } else { + phi->mask |= HDI_TEXT; + phi->pszText = col->title; + StringCchLength(col->title, KCDB_MAXCCH_SHORT_DESC, &cchsize); + phi->cchTextMax = (int) cchsize; + phi->fmt = HDF_CENTER | HDF_STRING; + } + phi->lParam = col->attr_id; +#if (_WIN32_WINNT >= 0x501) + if (IS_COMMCTL6()) { + if(col->flags & KHUI_CW_COL_SORT_INC) { + phi->fmt |= HDF_SORTUP; + } else if(col->flags & KHUI_CW_COL_SORT_DEC) { + phi->fmt |= HDF_SORTDOWN; + } + } +#endif + if(col->width < 0) { + /*TODO: come up with a better way to handle this case */ + col->width = 200; + } + phi->cxy = col->width; +} + +int +cw_get_cell_height(HDC hdc, HFONT hf) { + SIZE size; + size_t cbbuf; + wchar_t buf[64]; + HFONT hfold = NULL; + + if (hf) + hfold = SelectFont(hdc, hf); + + LoadString(khm_hInstance, IDS_SAMPLE_STRING, buf, sizeof(buf)/sizeof(buf[0])); + StringCchLength(buf, sizeof(buf)/sizeof(buf[0]), &cbbuf); + GetTextExtentPoint32(hdc, buf, (int) cbbuf, &size); + + if (hf) + SelectFont(hdc, hfold); + + return size.cy; +} + +int +cw_update_header_column_width(khui_credwnd_tbl * tbl, int c) { + int idx; + HDITEM hi; + +#ifdef DEBUG + assert(c >= 0 && c < tbl->n_cols); +#endif + + if (tbl->hwnd_header == NULL) + return 0; + + idx = Header_OrderToIndex(tbl->hwnd_header, c); + ZeroMemory(&hi, sizeof(hi)); + hi.mask = HDI_WIDTH; + hi.cxy = tbl->cols[c].width; + return Header_SetItem(tbl->hwnd_header, idx, &hi); +} + +/* returns a bitmask indicating which measures were changed */ +int +cw_update_extents(khui_credwnd_tbl * tbl, + khm_boolean update_scroll) { + int ext_x = 0; + int ext_y = 0; + int i; + int filler_col = -1; + int fill_adjusted = 0; + + recompute_columns: + + ext_x = 0; + for(i=0; i < (int) tbl->n_cols; i++) { + tbl->cols[i].x = ext_x; + if (tbl->cols[i].flags & KHUI_CW_COL_FILLER) { + if (filler_col == -1) + filler_col = i; + } + ext_x += tbl->cols[i].width; + } + + if (filler_col != -1 && !fill_adjusted) { + RECT r; + int delta; + + GetClientRect(tbl->hwnd, &r); + + /* we decrement the width so that the width data area is + strictly less than the width of the client area. Windows + doesn't disable a scrollbar unless the range is strictly + less than the page size. */ + delta = ((r.right - r.left) - 1) - ext_x; + + if (tbl->cols[filler_col].width + delta <= GetSystemMetrics(SM_CXSMICON)) { + tbl->cols[filler_col].width = GetSystemMetrics(SM_CXICON); + } else { + tbl->cols[filler_col].width += delta; + } + + cw_update_header_column_width(tbl, filler_col); + + fill_adjusted = 1; + goto recompute_columns; + } + + if(!tbl->cell_height) { + HDC dc; + int maxheight = 0; + int height; + + dc = GetWindowDC(tbl->hwnd); + + maxheight = cw_get_cell_height(dc, tbl->hf_normal); + height = cw_get_cell_height(dc, tbl->hf_bold); + if (height > maxheight) + maxheight = height; + height = cw_get_cell_height(dc, tbl->hf_header); + if (height > maxheight) + maxheight = height; + height = cw_get_cell_height(dc, tbl->hf_bold_header); + if (height > maxheight) + maxheight = height; + + ReleaseDC(tbl->hwnd, dc); + + tbl->cell_height = height + tbl->vpad * 2; + } + + if (tbl->flags & KHUI_CW_TBL_EXPIDENT) { + RECT r; + + ext_y = 0; + r.left = 0; + r.right = ext_x; + + for (i=0; i < (int) tbl->n_rows; i++) { + r.top = ext_y; + if (tbl->rows[i].flags & KHUI_CW_ROW_EXPVIEW) { + ext_y += tbl->cell_height * CW_EXP_ROW_MULT; + } else { + ext_y += tbl->cell_height; + } + r.bottom = ext_y; + tbl->rows[i].r_ext = r; + } + } else { + RECT r; + + r.left = 0; + r.right = ext_x; + + for (i=0; i < (int) tbl->n_rows; i++) { + r.top = i * tbl->cell_height; + r.bottom = r.top + tbl->cell_height; + + tbl->rows[i].r_ext = r; + } + + ext_y = (int) tbl->n_rows * tbl->cell_height; + } + + tbl->ext_width = ext_x; + tbl->ext_height = ext_y; + + /* useful in the future when implementing variable height rows. + The KHUI_CW_TBL_ROW_DIRTY bit indicates that the rows have + changed and that the y extent has to be recalculated. */ + tbl->flags &= ~KHUI_CW_TBL_ROW_DIRTY; + + if(update_scroll) { + RECT r; + int cl_w; + int cl_h; + SCROLLINFO si; + WINDOWPOS pw; + HDLAYOUT hdl; + + /* update the header control first */ + + retry_update_scroll: + GetClientRect(tbl->hwnd, &r); + + cl_w = r.right - r.left; + cl_h = (r.bottom - r.top); + cl_h -= tbl->header_height; + + if(tbl->scr_top < 0 || tbl->ext_height < cl_h) + tbl->scr_top = 0; + else if(tbl->scr_top > tbl->ext_height - cl_h) + tbl->scr_top = tbl->ext_height - cl_h; + if(tbl->scr_left < 0 || tbl->ext_width < cl_w) + tbl->scr_left = 0; + else if(tbl->scr_left > tbl->ext_width - cl_w) + tbl->scr_left = tbl->ext_width - cl_w; + + /* adjustments for scrolling */ + r.left -= tbl->scr_left; + r.right = max(tbl->ext_width + r.left, r.right); + + hdl.prc = &r; + hdl.pwpos = &pw; + + Header_Layout(tbl->hwnd_header, &hdl); + + if(tbl->header_height == 0) { + tbl->header_height = pw.cy; + goto retry_update_scroll; + } else + tbl->header_height = pw.cy; + + SetWindowPos( + tbl->hwnd_header, + pw.hwndInsertAfter, + pw.x, + pw.y, + pw.cx, + pw.cy, + pw.flags); + + si.cbSize = sizeof(si); + si.nMin = 0; + si.nMax = tbl->ext_height; + si.nPage = cl_h; + si.nPos = tbl->scr_top; + si.fMask = SIF_ALL | SIF_DISABLENOSCROLL; + SetScrollInfo(tbl->hwnd, SB_VERT, &si, TRUE); + + si.cbSize = sizeof(si); + si.nMin = 0; + si.nMax = tbl->ext_width; + si.nPage = cl_w; + si.nPos = tbl->scr_left; + si.fMask = SIF_ALL | SIF_DISABLENOSCROLL; + SetScrollInfo(tbl->hwnd, SB_HORZ, &si, TRUE); + } + + return 0; +} + +void +cw_insert_header_cols(khui_credwnd_tbl * tbl) { + HWND hdr; + HDITEM hi; + int i; + + hdr = tbl->hwnd_header; + + for(i=0; i < (int) tbl->n_cols; i++) { + cw_hditem_from_tbl_col(&(tbl->cols[i]), &hi); + Header_InsertItem(hdr, 512, &hi); + } +} + +#define CW_ER_BLANK 0 +#define CW_ER_GREY 1 +#define CW_ER_SEL 2 + +void +cw_erase_rect(HDC hdc, + khui_credwnd_tbl * tbl, + RECT * r_wnd, + RECT * r_erase, + int type) +{ + RECT rlogo; + RECT ri; + RECT t; + BOOL rie; + HBRUSH hbr; + + switch(type) { + case CW_ER_BLANK: + hbr = tbl->hb_normal; + break; + + case CW_ER_GREY: + hbr = tbl->hb_grey; + break; + + case CW_ER_SEL: + hbr = tbl->hb_s; + break; + + default: + return; + } + + if(tbl->kbm_logo_shade.cx != -1 && type == CW_ER_BLANK) { + rlogo.left = r_wnd->right - tbl->kbm_logo_shade.cx; + rlogo.right = r_wnd->right; + rlogo.top = r_wnd->bottom - tbl->kbm_logo_shade.cy; + rlogo.bottom = r_wnd->bottom; + rie = FALSE; /* Don't show watermark. */ + } else { + ZeroMemory(&rlogo, sizeof(rlogo)); + ZeroMemory(&ri, sizeof(ri)); + rie = FALSE; + } + + if(!rie) { + FillRect(hdc, r_erase, hbr); + } else { + HDC hdcb = CreateCompatibleDC(hdc); + HBITMAP hbmold = SelectObject(hdcb, tbl->kbm_logo_shade.hbmp); + + BitBlt(hdc, ri.left, ri.top, ri.right - ri.left, ri.bottom - ri.top, + hdcb, ri.left - rlogo.left, ri.top - rlogo.top, SRCCOPY); + + SelectObject(hdcb, hbmold); + DeleteDC(hdcb); + + if(r_erase->top < ri.top && r_erase->left < ri.left) { + t.left = r_erase->left; + t.top = r_erase->top; + t.right = ri.left; + t.bottom = ri.top; + FillRect(hdc, &t, hbr); + } + + if(r_erase->left < ri.left) { + t.left = r_erase->left; + t.top = ri.top; + t.right = ri.left; + t.bottom = ri.bottom; + FillRect(hdc, &t, hbr); + } + + if(r_erase->top < ri.top) { + t.left = ri.left; + t.top = r_erase->top; + t.right = ri.right; + t.bottom = ri.top; + FillRect(hdc, &t, hbr); + } + } +} + +void +cw_draw_header(HDC hdc, + khui_credwnd_tbl * tbl, + int row, + RECT * r) +{ + int colattr; + HPEN pl, pold; + khui_credwnd_row * cr; + khui_credwnd_outline * o; + int selected = 0; + khm_int32 idf = 0; + + /* each header consists of a couple of widgets and some text */ + /* we need to figure out the background color first */ + + cr = &(tbl->rows[row]); + o = (khui_credwnd_outline *) cr->data; + + colattr = tbl->cols[cr->col].attr_id; + + if (colattr == KCDB_ATTR_ID_NAME) { + khm_handle ident = o->data; + + kcdb_identity_get_flags(ident, &idf); + } + + selected = o->flags & KHUI_CW_O_SELECTED; + + { + HBRUSH hbr; + + if(selected) { + if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_EXPIRED) + hbr = tbl->hb_hdr_bg_exp_s; + else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_CRITICAL) + hbr = tbl->hb_hdr_bg_crit_s; + else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_WARN) + hbr = tbl->hb_hdr_bg_warn_s; + else if (idf & KCDB_IDENT_FLAG_DEFAULT) + hbr = tbl->hb_hdr_bg_def_s; + else + hbr = tbl->hb_hdr_bg_s; + } else { + if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_EXPIRED) + hbr = tbl->hb_hdr_bg_exp; + else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_CRITICAL) + hbr = tbl->hb_hdr_bg_crit; + else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_WARN) + hbr = tbl->hb_hdr_bg_warn; + else if (idf & KCDB_IDENT_FLAG_DEFAULT) + hbr = tbl->hb_hdr_bg_def; + else + hbr = tbl->hb_hdr_bg; + } + + FillRect(hdc, r, hbr); + } + + /* draw the background */ + pl = CreatePen(PS_SOLID, 0, tbl->cr_hdr_outline); + pold = SelectObject(hdc, pl); + MoveToEx(hdc, r->left, r->bottom - 1, NULL); + LineTo(hdc,r->right,r->bottom - 1); + SelectObject(hdc, pold); + DeleteObject(pl); + + if (!(o->flags & KHUI_CW_O_NOOUTLINE) && + !(o->flags & KHUI_CW_O_EMPTY)) { + if((tbl->mouse_state & CW_MOUSE_WOUTLINE) && + tbl->mouse_row == row) { + if(o->flags & KHUI_CW_O_EXPAND) { + khui_ilist_draw_id(tbl->ilist, IDB_WDG_EXPAND_HI, + hdc, r->left, + (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); + } else { + khui_ilist_draw_id(tbl->ilist, IDB_WDG_COLLAPSE_HI, + hdc, r->left, + (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); + } + } else { + if(o->flags & KHUI_CW_O_EXPAND) { + khui_ilist_draw_id(tbl->ilist, IDB_WDG_EXPAND, + hdc, r->left, + (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); + } else { + khui_ilist_draw_id(tbl->ilist, IDB_WDG_COLLAPSE, + hdc, r->left, + (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); + } + } + + r->left += KHUI_SMICON_CX * 3 / 2; + } else if (!(o->flags & KHUI_CW_O_NOOUTLINE)) { + r->left += KHUI_SMICON_CX * 3 / 2; + } + + /* try to draw the icon, if there is one */ + if(colattr == KCDB_ATTR_ID_NAME) { + + khui_ilist_draw_id(tbl->ilist, + (((tbl->mouse_state & CW_MOUSE_WSTICKY) && + tbl->mouse_row == row)? + ((idf & KCDB_IDENT_FLAG_STICKY)? + IDB_WDG_STUCK_HI: + IDB_WDG_STICK_HI): + ((idf & KCDB_IDENT_FLAG_STICKY)? + IDB_WDG_STUCK: + IDB_WDG_STICK)), + hdc, + r->left, + (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); + + r->left += KHUI_SMICON_CX * 3 / 2; + + /* the TRUE part of the 'if' is for drawing large icons. It's + disabled for now until we have new icons. */ + if ((cr->flags & KHUI_CW_ROW_EXPVIEW) && FALSE) { + int cx = GetSystemMetrics(SM_CXICON); + int cy = GetSystemMetrics(SM_CYICON); + + DrawIcon(hdc, r->left, (r->top + r->bottom - cy) / 2, tbl->hi_lg_ident); + + r->left += cx + KHUI_SMICON_CX / 2; + + } else { + khui_ilist_draw_id(tbl->ilist, + ((o->flags & KHUI_CW_O_EMPTY)? + IDB_ID_DIS_SM: + IDB_ID_SM), + hdc, + r->left, + (r->top + r->bottom - KHUI_SMICON_CY) / 2, 0); + r->left += KHUI_SMICON_CX * 3 / 2 ; + } + } + + + if (!(cr->flags & KHUI_CW_ROW_EXPVIEW)) { + + SetTextAlign(hdc, TA_BOTTOM | TA_LEFT); + + if(selected) + SetTextColor(hdc, tbl->cr_hdr_s); + else + SetTextColor(hdc, tbl->cr_hdr_normal); + + TextOut(hdc, r->left, r->bottom - tbl->vpad, o->header, (int) wcslen(o->header)); + + if (colattr == KCDB_ATTR_ID_NAME && + (idf & KCDB_IDENT_FLAG_DEFAULT)) { + wchar_t defstr[64]; + SIZE size; + + LoadString(khm_hInstance, IDS_CW_DEFAULT, + defstr, ARRAYLENGTH(defstr)); + + GetTextExtentPoint32(hdc, o->header, (int) wcslen(o->header), + &size); + + r->left += size.cx + KHUI_SMICON_CX * 2; + + TextOut(hdc, r->left, r->bottom - tbl->vpad, + defstr, (int) wcslen(defstr)); + } + } else { + + RECT tr; + int len; + wchar_t typestr[128]; + int cx_id; + SIZE size; + khui_credwnd_ident * cwi; + + /* expanded view */ +#ifdef DEBUG + assert(colattr == KCDB_ATTR_ID_NAME); +#endif + + cwi = cw_find_ident(tbl, o->data); + + CopyRect(&tr, r); + tr.bottom -= (tr.bottom - tr.top) / 2; /* drawing two lines of text */ + + if (selected) + SetTextColor(hdc, tbl->cr_hdr_s); + else + SetTextColor(hdc, tbl->cr_hdr_normal); + + len = (int) wcslen(o->header); + DrawText(hdc, o->header, len, &tr, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); + GetTextExtentPoint32(hdc, o->header, (int) len, &size); + cx_id = size.cx; + + typestr[0] = L'\0'; + + if ((idf & KCDB_IDENT_FLAG_DEFAULT)) { + if (cwi && cwi->credtype_name[0]) { + wchar_t fmt[64]; + + LoadString(khm_hInstance, IDS_CW_DEFAULTTF, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(typestr, sizeof(typestr), fmt, + cwi->credtype_name); + } else { + LoadString(khm_hInstance, IDS_CW_DEFAULT, + typestr, ARRAYLENGTH(typestr)); + } + } else if (cwi && cwi->credtype_name[0]) { + wchar_t fmt[64]; + + LoadString(khm_hInstance, IDS_CW_TYPEF, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(typestr, sizeof(typestr), fmt, + cwi->credtype_name); + } + + if (typestr[0]) { + int cx_str; + + len = (int) wcslen(typestr); + GetTextExtentPoint32(hdc, typestr, (int) len, &size); + cx_str = size.cx + KHUI_SMICON_CX / 2; + + tr.left = max(tr.right - cx_str, tr.left + cx_id + KHUI_SMICON_CX * 2); + if (selected) + SetTextColor(hdc, tbl->cr_hdr_gray_s); + else + SetTextColor(hdc, tbl->cr_hdr_gray); + DrawText(hdc, typestr, len, &tr, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); + } + + CopyRect(&tr, r); + tr.top += (tr.bottom - tr.top) / 2; + + if (1) { + wchar_t buf[128]; + khui_credwnd_ident * cwi; + + buf[0] = L'\0'; + cwi = cw_find_ident(tbl, o->data); + + if (cwi) { +#ifdef SHOW_CREDENTIAL_COUNTS + if (cwi->credcount == 0) + LoadString(khm_hInstance, IDS_IDEXPDISP_NOCRED, + buf, ARRAYLENGTH(buf)); + else if (cwi->credcount == 1) + LoadString(khm_hInstance, IDS_IDEXPDISP_1CRED, + buf, ARRAYLENGTH(buf)); + else { + wchar_t fmt[128]; + LoadString(khm_hInstance, IDS_IDEXPDISP_NCRED, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, (int) cwi->credcount); + } +#else + if (FtToInt(&cwi->ft_expire) != 0) { + FILETIME ft_now; + + GetSystemTimeAsFileTime(&ft_now); + if (CompareFileTime(&cwi->ft_expire, &ft_now) > 0) { + wchar_t fmt[64]; + wchar_t intstr[128]; + FILETIME ft; + khm_size cb; + + ft = FtSub(&cwi->ft_expire, &ft_now); + intstr[0] = L'\0'; + cb = sizeof(intstr); + FtIntervalToString(&ft, intstr, &cb); + + LoadString(khm_hInstance, IDS_CW_EXPIREF, + fmt, ARRAYLENGTH(fmt)); + StringCbPrintf(buf, sizeof(buf), fmt, intstr); + } else { + LoadString(khm_hInstance, IDS_CW_EXPIRED, + buf, ARRAYLENGTH(buf)); + } + } +#endif + + len = (int) wcslen(buf); + + if (selected) + SetTextColor(hdc, tbl->cr_hdr_gray_s); + else + SetTextColor(hdc, tbl->cr_hdr_gray); + DrawText(hdc, buf, len, &tr, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); + } + } + } +} + +LRESULT +cw_handle_header_msg(khui_credwnd_tbl * tbl, LPNMHEADER ph) { + RECT r; + HDITEM hi; + + switch(ph->hdr.code) { + /*TODO:Make it track smoother */ + 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: + return FALSE; + + 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_POS) { + 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].flags & KHUI_CW_COL_FIXED_POS)) + 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 + break; + } + + 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_META) + 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++; + } + } + + 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; + + 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)) + break; + + tbl->cols[i].flags &= ~KHUI_CW_COL_GROUP; + + 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); + } + +#if 0 + } else if (tbl->cols[idx].flags & + (KHUI_CW_COL_SORT_INC | + KHUI_CW_COL_SORT_DEC)) { + int i; + + /* remove the sort condition from a column */ + + for (i=idx; i < tbl->n_cols; i++) { + if (!tbl->cols[i].flags & + (KHUI_CW_COL_SORT_INC | + KHUI_CW_COL_SORT_DEC)) + break; + + tbl->cols[i].flags &= + ~(KHUI_CW_COL_SORT_INC | + KHUI_CW_COL_SORT_DEC); + + 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); + } +#endif + } 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++; + } + } + + 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; +} + +LRESULT +cw_wm_create(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + khui_credwnd_tbl * tbl; + + 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)); + ZeroMemory(tbl, sizeof(*tbl)); + + /* some versions of VC generate portability warnings for + SetWindowLongPtr */ +#pragma warning(push) +#pragma warning(disable: 4244) + 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_DRAGDROP +#if (_WIN32_WINNT >= 0x501) + | ((IS_COMMCTL6())?HDS_FLAT:0) +#endif + , + 0,0,0,0,hwnd, (HMENU) 0, khm_hInstance, NULL); + + cw_load_view(tbl, NULL /* default view */, hwnd); + cw_insert_header_cols(tbl); + + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_selection_state(tbl); + cw_update_extents(tbl, FALSE); + + { + RECT rect; + WINDOWPOS pw; + HDLAYOUT hdl; + + hdl.prc = ▭ + hdl.pwpos = &pw; + GetClientRect(hwnd, &rect); + + Header_Layout(tbl->hwnd_header, &hdl); + + SetWindowPos( + tbl->hwnd_header, + pw.hwndInsertAfter, + pw.x, + pw.y, + pw.cx, + pw.cy, + pw.flags | SWP_SHOWWINDOW); + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +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); + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +/* handles WM_PAINT and WM_PRINTCLIENT */ +LRESULT +cw_wm_paint(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + khui_credwnd_tbl * tbl; + HDC hdc; + PAINTSTRUCT ps; + RECT r,rh; + HFONT hf_old = NULL; + int row_s, row_e; + int col_s, col_e; + int i,j,x,y,xs,xe,ys,ye; + int flag_col = -1; + int d_x = -1; + int selected = 0; + int rowheight = 0; + BOOL has_dc = FALSE; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + if (wParam != 0) { + /* we assume that if wParam != 0, then that contains a device + context for us to draw in. Otherwise, we have to call + BeginPaint() to get one. */ + hdc = (HDC) wParam; + has_dc = TRUE; + } + + if(!has_dc && !GetUpdateRect(hwnd, &r, FALSE)) { +#ifdef DEBUG + assert(FALSE); +#endif + goto _exit; + } + + if (!has_dc) + hdc = BeginPaint(hwnd, &ps); + + if(tbl->hf_normal) + hf_old = SelectFont(hdc, tbl->hf_normal); + SetTextAlign(hdc, TA_LEFT | TA_TOP | TA_NOUPDATECP); + SetBkMode(hdc, TRANSPARENT); + + GetClientRect(hwnd,&r); + r.top += tbl->header_height; + + if(tbl->n_rows) { + /* remove the notification window if there is one */ + if(tbl->hwnd_notif) { + DestroyWindow(tbl->hwnd_notif); + tbl->hwnd_notif = NULL; + } + /* we compute the visible area in terms of rows and columns */ + /* row_s : first visible row */ + /* col_s : first visible column */ + /* row_e : last visible row */ + /* col_e : last visible column */ + /* ys : top edge of first visible row */ + /* xs : left edge of first visible column */ + + /* We *NEED* all the meta columns to be on the left */ + + row_s = 0; + ys = 0; + row_e = (int) tbl->n_rows; + x = 0; + col_s = -1; + col_e = -1; + xs = 0; + for(i=0; i < (int) tbl->n_cols; i++) { + if(col_e == -1 && x >= tbl->scr_left + (r.right - r.left)) { + col_e = i; + } + if(tbl->cols[i].attr_id == CW_CA_FLAGS) + flag_col = i; + if(d_x == -1 && !cw_is_custom_attr(tbl->cols[i].attr_id)) + d_x = x; + x += tbl->cols[i].width; + if(col_s == -1 && x > tbl->scr_left) { + col_s = i; + xs = tbl->cols[i].x; + } + } + + if(col_e == -1) + col_e = i; + + if(col_s == -1) + col_s = i; + + if(d_x != -1) + d_x += r.left - tbl->scr_left; + + xs += r.left - tbl->scr_left; + ys += r.top - tbl->scr_top; + xe = r.left + tbl->ext_width - tbl->scr_left; + ye = r.top + tbl->ext_height - tbl->scr_top; + + /* now draw */ + y = ys; + for(i=row_s; i < row_e; i++) { + selected = tbl->rows[i].flags & KHUI_CW_ROW_SELECTED; + rowheight = (tbl->rows[i].flags & KHUI_CW_ROW_EXPVIEW)? tbl->cell_height * CW_EXP_ROW_MULT : tbl->cell_height; + + if(tbl->cursor_row == i) { + if (tbl->rows[i].flags & KHUI_CW_ROW_HEADER) + SelectFont(hdc, tbl->hf_bold_header); + else + SelectFont(hdc, tbl->hf_bold); + } else if (tbl->rows[i].flags & KHUI_CW_ROW_HEADER) { + SelectFont(hdc, tbl->hf_header); + } + + x = xs; + if(tbl->rows[i].flags & KHUI_CW_ROW_HEADER) { + rh.left = xs; + rh.right = xs; + for(j=col_s; j < tbl->rows[i].col; j++) + rh.right += tbl->cols[j].width; + rh.top = y; + rh.bottom = y + rowheight; + if(rh.right > rh.left) { + cw_erase_rect(hdc, tbl, &r, &rh, (selected)?CW_ER_SEL:CW_ER_BLANK); + } + rh.left = rh.right; + rh.right = xe; + + cw_draw_header(hdc, tbl, i, &rh); + } + + if(selected) + SetTextColor(hdc, tbl->cr_s); + else + SetTextColor(hdc, tbl->cr_normal); + + x = xs; + rh.top = y; + rh.bottom = y + rowheight; + for(j=col_s; j < col_e; x += tbl->cols[j++].width) { + wchar_t buf[256]; + khm_size cbbuf; + + rh.left = x; + rh.right = x + tbl->cols[j].width; + + if(!cw_is_custom_attr(tbl->cols[j].attr_id)) { + if(!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) { + cw_erase_rect(hdc, tbl, &r, &rh, (selected)?CW_ER_SEL:CW_ER_BLANK); + + if(j > tbl->rows[i].col) { + cbbuf = sizeof(buf); + if(KHM_FAILED(kcdb_cred_get_attr_string((khm_handle) tbl->rows[i].data, + tbl->cols[j].attr_id, buf, + &cbbuf, KCDB_TS_SHORT))) + continue; + + rh.left += tbl->hpad; + rh.right -= tbl->hpad; + + SetTextAlign(hdc, 0); + DrawText(hdc, buf, (int)((cbbuf / sizeof(wchar_t)) - 1), &rh, + DT_LEFT | DT_VCENTER | DT_NOCLIP | DT_SINGLELINE | DT_END_ELLIPSIS); + } + } + } else { + cw_erase_rect(hdc, tbl, &r, &rh, (selected)?CW_ER_SEL:CW_ER_BLANK); + + if(tbl->cols[j].attr_id == CW_CA_FLAGS) { + khui_credwnd_outline * o; + khm_int32 flag; + + if(tbl->rows[i].flags & KHUI_CW_ROW_HEADER) { + o = ((khui_credwnd_outline *) tbl->rows[i].data); + if(o->flags & KHUI_CW_O_SHOWFLAG) + flag = o->flags; + else + flag = 0; + } else { + flag = tbl->rows[i].flags; + } + + flag &= CW_EXPSTATE_MASK; + + if(flag == CW_EXPSTATE_WARN) { + khui_ilist_draw_id(tbl->ilist, IDB_FLAG_WARN, hdc, x, y, 0); + } else if(flag == CW_EXPSTATE_CRITICAL) { + 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 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)) && + (flags & KCDB_CRED_FLAG_RENEWABLE)) { + khui_ilist_draw_id(tbl->ilist, + IDB_FLAG_RENEW, + hdc, + x, y, 0); + } else { + khui_ilist_draw_id(tbl->ilist, + IDB_TK_SM, + hdc, + x, y, 0); + } + } + } + } + } + + if(tbl->cursor_row == i) { + rh.left = tbl->scr_left; + rh.right = tbl->scr_left + tbl->ext_width; + DrawFocusRect(hdc, &rh); + } + + if (tbl->cursor_row == i || + (tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) { + SelectFont(hdc, tbl->hf_normal); + } + + y += rowheight; + + } + + if(xe < r.right) { + rh.left = xe; + rh.right = r.right; + rh.top = r.top; + rh.bottom = r.bottom; + + cw_erase_rect(hdc, tbl, &r, &rh, CW_ER_BLANK); + } + + if(ye < r.bottom) { + rh.left = r.left; + rh.right = (xe < r.right)?xe:r.right; + rh.top = ye; + rh.bottom = r.bottom; + + cw_erase_rect(hdc, tbl, &r, &rh, CW_ER_BLANK); + } + + } else { + wchar_t buf[512]; + cw_erase_rect(hdc, tbl, &r, &r, CW_ER_BLANK); + + if(tbl->hwnd_notif == NULL) { + LoadString(khm_hInstance, IDS_NO_CREDS, buf, sizeof(buf)/sizeof(buf[0])); + tbl->hwnd_notif = khm_create_htwnd( + tbl->hwnd, + buf, + r.left,r.top,r.right - r.left,tbl->cell_height * 4, + 0, /* This can be WS_EX_TRANSPARENT, but + we don't fully support it yet. */ + WS_VISIBLE); + if(tbl->hwnd_notif) { + SendMessage(tbl->hwnd_notif, WM_SETFONT, (WPARAM) tbl->hf_normal, (LPARAM) FALSE); + ShowWindow(tbl->hwnd_notif, SW_SHOW); + } + } + } + + if(tbl->hf_normal) + SelectFont(hdc, hf_old); + + if (!has_dc) + EndPaint(hwnd,&ps); + + _exit: + return TRUE; +} + +LRESULT +cw_wm_size(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + RECT rect; + khui_credwnd_tbl * tbl; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + cw_update_extents(tbl, TRUE); + + GetClientRect(hwnd, &rect); + + if(tbl->hwnd_notif) { + SetWindowPos( + tbl->hwnd_notif, + tbl->hwnd_header, + rect.left, + tbl->header_height, + rect.right - rect.left, + tbl->cell_height * 4, + 0); + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +LRESULT +cw_wm_notify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + khui_credwnd_tbl * tbl; + LPNMHDR pnmh; + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + pnmh = (LPNMHDR) lParam; + if(pnmh->hwndFrom == tbl->hwnd_header) { + LPNMHEADER ph; + ph = (LPNMHEADER) lParam; + return cw_handle_header_msg(tbl, ph); + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +static void cw_pp_begin(khui_property_sheet * s); +static void cw_pp_precreate(khui_property_sheet * s); +static void cw_pp_end(khui_property_sheet * s); +static void cw_pp_destroy(khui_property_sheet *ps); + +LRESULT +cw_kmq_wm_dispatch(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + kmq_message * m; + khm_int32 rv = KHM_ERROR_SUCCESS; + khui_credwnd_tbl * tbl; + + 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: + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_extents(tbl, TRUE); + InvalidateRect(hwnd, NULL, FALSE); + break; + + case KMSG_CRED_PP_BEGIN: + cw_pp_begin((khui_property_sheet *) m->vparam); + break; + + case KMSG_CRED_PP_PRECREATE: + cw_pp_precreate((khui_property_sheet *) m->vparam); + break; + + case KMSG_CRED_PP_END: + cw_pp_end((khui_property_sheet *) m->vparam); + break; + + case KMSG_CRED_PP_DESTROY: + cw_pp_destroy((khui_property_sheet *) m->vparam); + break; + } + } else if (m->type == KMSG_KCDB) { + if (m->subtype == KMSG_KCDB_IDENT && + m->uparam == KCDB_OP_MODIFY) { + + cw_update_outline(tbl); + cw_update_extents(tbl, TRUE); + InvalidateRect(hwnd, NULL, FALSE); + + } + else if (m->subtype == KMSG_KCDB_IDENT && + m->uparam == KCDB_OP_NEW_DEFAULT) { + + cw_update_outline(tbl); + cw_update_extents(tbl, TRUE); + 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_selection_state(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); +} + +static void +cw_select_outline_level(khui_credwnd_outline * o, + BOOL select) +{ + while(o) { + if (select) + o->flags |= KHUI_CW_O_SELECTED; + else + o->flags &= ~KHUI_CW_O_SELECTED; + cw_select_outline_level(TFIRSTCHILD(o), select); + o = LNEXT(o); + } +} + +static void +cw_select_outline(khui_credwnd_outline * o, + BOOL select) +{ + if (select) + o->flags |= KHUI_CW_O_SELECTED; + else + o->flags &= ~KHUI_CW_O_SELECTED; +} + +static void +cw_select_row_creds(khui_credwnd_tbl * tbl, int row, int selected) { + + khm_size j; + khm_size idx_start, idx_end; + +#ifdef DEBUG + assert(row >= 0 && row < tbl->n_rows); +#endif + + if (row >= tbl->n_rows) + return; + + if (tbl->rows[row].flags & KHUI_CW_ROW_HEADER) { + khui_credwnd_outline * o; + + o = (khui_credwnd_outline *) tbl->rows[row].data; + if (o->col == tbl->n_cols - 1) { + /* this is a special case where the outline column is the + last displayed column. In this case, the credentials + do not occupy any rows, and this header row acts as a + group credential row. */ + idx_start = o->idx_start; + idx_end = o->idx_end; + } else { + return; + } + } else { + idx_start = tbl->rows[row].idx_start; + idx_end = tbl->rows[row].idx_end; + } + + if (idx_start == -1 || idx_end == -1) + return; + + for (j = idx_start; j <= idx_end; j++) { + khm_handle cred = NULL; + + kcdb_credset_get_cred(tbl->credset, (khm_int32) j, &cred); + + if (cred) { + kcdb_cred_set_flags(cred, ((selected)?KCDB_CRED_FLAG_SELECTED:0), + KCDB_CRED_FLAG_SELECTED); + kcdb_cred_release(cred); + } + } +} + +static void +cw_unselect_all(khui_credwnd_tbl * tbl) +{ + int i; + + for(i=0; in_rows; i++) { + tbl->rows[i].flags &= ~KHUI_CW_ROW_SELECTED; + + cw_select_row_creds(tbl, i, FALSE); + } + + cw_select_outline_level(tbl->outline, FALSE); +} + +static void +cw_update_outline_selection_state(khui_credwnd_tbl * tbl, + khui_credwnd_outline * o) +{ + BOOL select = TRUE; + int j; + + for (j = o->start + 1; j < o->start + o->length; j++) { + if (tbl->rows[j].flags & KHUI_CW_ROW_HEADER) { + cw_update_outline_selection_state(tbl, + (khui_credwnd_outline *) + tbl->rows[j].data); + } + + if (!(tbl->rows[j].flags & KHUI_CW_ROW_SELECTED)) { + select = FALSE; + } + + if (tbl->rows[j].flags & KHUI_CW_ROW_HEADER) { + j += ((khui_credwnd_outline *) tbl->rows[j].data)->length - 1; + } + } + + /* special case : the header has been collapsed and we are just + using one row. In this case, the for loop above will do + nothing. */ + + if (o->length == 1) { + select = (tbl->rows[o->start].flags & KHUI_CW_ROW_SELECTED); + } + + cw_select_outline(o, select); + + if (select) { + tbl->rows[o->start].flags |= KHUI_CW_ROW_SELECTED; + } else { + tbl->rows[o->start].flags &= ~KHUI_CW_ROW_SELECTED; + } +} + +static void +cw_update_selection_state(khui_credwnd_tbl * tbl) +{ + int i; + + cw_select_outline_level(tbl->outline, FALSE); + + for (i=0; i < tbl->n_rows; i++) { + if (tbl->rows[i].flags & KHUI_CW_ROW_HEADER) { + khui_credwnd_outline * o; + + o = (khui_credwnd_outline *) tbl->rows[i].data; + + cw_update_outline_selection_state(tbl, o); + + i += o->length - 1; + } + } +} + +/* Examine the current row and set the UI context */ +static void +cw_set_row_context(khui_credwnd_tbl * tbl, int row) +{ + khui_credwnd_outline * o; + BOOL set_context = TRUE; + + if (row < 0 || row >= (int) tbl->n_rows) { + if (tbl->n_rows > 0) + row = 0; + else { + khui_context_reset(); + return; + } + } + + if (tbl->rows[row].flags & KHUI_CW_ROW_HEADER) { + + o = (khui_credwnd_outline *) tbl->rows[row].data; + + if (tbl->cols[o->col].attr_id == KCDB_ATTR_ID_NAME) { + if (TPARENT(o) != NULL) { + khui_credwnd_outline * op; + + op = TPARENT(o); + + if (tbl->cols[op->col].attr_id == KCDB_ATTR_TYPE_NAME && + TPARENT(op) == NULL) { + /* selected a credential type */ + khui_context_set(KHUI_SCOPE_CREDTYPE, + (khm_handle) o->data, + (khm_int32) (DWORD_PTR) op->data, + NULL, + NULL, + 0, + tbl->credset); + } else { + /* we can't narrow it down using the standard set + of scopes. We consider this to be an identity + selection because the user right-clicked on an + identity header. */ + khui_context_set(KHUI_SCOPE_IDENT, + (khm_handle) o->data, + KCDB_CREDTYPE_INVALID, + NULL, + NULL, + 0, + tbl->credset); + } + } else { + /* The user clicked on an identity header. Even + though not all credentials belonging to the + identity maybe within the scope right now, we still + consider this to be an identity scope. */ + khui_context_set(KHUI_SCOPE_IDENT, + (khm_handle) o->data, + KCDB_CREDTYPE_INVALID, + NULL, + NULL, + 0, + tbl->credset); + } + } else if (tbl->cols[o->col].attr_id == KCDB_ATTR_TYPE_NAME) { + if (TPARENT(o) == NULL) { + /* selected an entire cred type */ + khui_context_set(KHUI_SCOPE_CREDTYPE, + NULL, + (khm_int32) (DWORD_PTR) o->data, + NULL, + NULL, + 0, + tbl->credset); + } else { + khui_credwnd_outline * op; + + op = TPARENT(o); + if (tbl->cols[op->col].attr_id == KCDB_ATTR_ID_NAME) { + /* credtype under an identity. Even though not + all the credentials of this credtype belonging + to this identity might be within the scope, we + still consider this to be a type selection + under a specific identity. */ + khui_context_set(KHUI_SCOPE_CREDTYPE, + (khm_handle) op->data, + (khm_int32) (DWORD_PTR) o->data, + NULL, + NULL, + 0, + tbl->credset); + } else { + set_context = FALSE; + } + } + } else { + set_context = FALSE; + } + + if (!set_context) { + /* woohoo. cred group. yay. */ + khui_header headers[KHUI_MAX_HEADERS]; + khm_size n_headers = 0; + + do { + headers[n_headers].attr_id = + o->attr_id; + if (tbl->cols[o->col].attr_id == + KCDB_ATTR_ID_NAME) { + headers[n_headers].data = &(o->data); + headers[n_headers].cb_data = sizeof(khm_handle); + } else if (tbl->cols[o->col].attr_id == + KCDB_ATTR_TYPE_NAME) { + headers[n_headers].data = &(o->data); + headers[n_headers].cb_data = sizeof(khm_int32); + } else { + headers[n_headers].data = o->data; + headers[n_headers].cb_data = o->cb_data; + } + + n_headers++; + + o = TPARENT(o); + } while(o); + + khui_context_set(KHUI_SCOPE_GROUP, + NULL, + KCDB_CREDTYPE_INVALID, + NULL, + headers, + n_headers, + tbl->credset); + } + + } else { + khm_handle cred; + + cred = (khm_handle) tbl->rows[row].data; + + khui_context_set(KHUI_SCOPE_CRED, + NULL, + KCDB_CREDTYPE_INVALID, + cred, + NULL, + 0, + tbl->credset); + } +} + +static void +cw_select_all(khui_credwnd_tbl * tbl) +{ + int i; + + for(i=0; in_rows; i++) { + tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED; + cw_select_row_creds(tbl, i, TRUE); + } + + cw_select_outline_level(tbl->outline, TRUE); + + cw_update_selection_state(tbl); + + cw_set_row_context(tbl, tbl->cursor_row); + + InvalidateRect(tbl->hwnd, NULL, FALSE); +} + +static void +cw_select_row(khui_credwnd_tbl * tbl, int row, WPARAM wParam) +{ + int i; + BOOL toggle; + BOOL extend; + int group_begin; + int group_end; + + if (wParam & MK_CONTROL) { + toggle = TRUE; + extend = FALSE; + } else if (wParam & MK_SHIFT) { + toggle = FALSE; + extend = TRUE; + } else { + toggle = FALSE; + extend = FALSE; + } + + if (row < 0 || row >= (int) tbl->n_rows) + return; + + if (tbl->rows[row].flags & KHUI_CW_ROW_HEADER) { + khui_credwnd_outline * o; + + o = (khui_credwnd_outline *) tbl->rows[row].data; + + group_begin = o->start; + group_end = o->start + o->length - 1; + } else { + group_begin = row; + group_end = row; + } + + if (!toggle && !extend) { + /* selecting a single row */ + cw_unselect_all(tbl); + + tbl->cursor_row = row; + tbl->anchor_row = row; + + for (i = group_begin; i <= group_end; i++) { + tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED; + cw_select_row_creds(tbl, i, TRUE); + } + } else if (toggle) { + BOOL select; + + tbl->cursor_row = row; + tbl->anchor_row = row; + + select = !(tbl->rows[row].flags & KHUI_CW_ROW_SELECTED); + + for (i = group_begin; i <= group_end; i++) { + if (select) + tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED; + else + tbl->rows[i].flags &= ~KHUI_CW_ROW_SELECTED; + + cw_select_row_creds(tbl, i, select); + } + } else if (extend) { + int range_begin; + int range_end; + + cw_unselect_all(tbl); + + range_begin = min(row, tbl->anchor_row); + range_end = max(row, tbl->anchor_row); + + for (i = range_begin; i <= range_end; i++) { + tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED; + + cw_select_row_creds(tbl, i, TRUE); + } + + tbl->cursor_row = row; + } + + cw_update_selection_state(tbl); + + cw_set_row_context(tbl, tbl->cursor_row); + + InvalidateRect(tbl->hwnd, NULL, FALSE); +} + +static void +cw_toggle_outline_state(khui_credwnd_tbl * tbl, + khui_credwnd_outline * o) { + + int old_range_begin; + int old_range_end; + int new_range_begin; + int new_range_end; + + old_range_begin = o->start; + old_range_end = o->start + o->length - 1; + + o->flags ^= KHUI_CW_O_EXPAND; + + cw_update_outline(tbl); + cw_update_extents(tbl, TRUE); + + new_range_begin = o->start; + new_range_end = o->start + o->length - 1; + + if (tbl->cursor_row > old_range_end) { + tbl->cursor_row -= old_range_end - new_range_end; + } else if (tbl->cursor_row >= old_range_begin && + tbl->cursor_row <= old_range_end) { + tbl->cursor_row = new_range_begin; + } + + if (tbl->anchor_row > old_range_end) { + tbl->anchor_row -= old_range_end - new_range_end; + } else if (tbl->anchor_row >= old_range_begin && + tbl->anchor_row <= old_range_end) { + tbl->anchor_row = new_range_begin; + } + + InvalidateRect(tbl->hwnd, NULL, TRUE); + +} + +LRESULT cw_properties(HWND hwnd); + +LRESULT +cw_wm_mouse(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + khui_credwnd_tbl * tbl; + int x,y; + RECT r; + int row; + int col; + int i; + int nm_state,nm_row,nm_col; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + /* we are basically trying to capture events where the mouse is + hovering over one of the 'hotspots'. There are two kinds of + hotspots one is the little widget thinggy that you click on to + expand or collapse an outline. The other is a text cell that + is partially concealed. */ + + x = GET_X_LPARAM(lParam); + y = GET_Y_LPARAM(lParam); + x += tbl->scr_left; + y += tbl->scr_top - tbl->header_height; + + row = -1; + + for (i=0; i < tbl->n_rows; i++) { + if (y >= tbl->rows[i].r_ext.top && + y < tbl->rows[i].r_ext.bottom) { + row = i; + break; + } + } + + col = -1; + nm_state = CW_MOUSE_NONE; + nm_row = nm_col = -1; + + for(i=0; i < (int) tbl->n_cols; i++) { + if(x >= tbl->cols[i].x && + x < tbl->cols[i].x + tbl->cols[i].width) { + col = i; + break; + } + } + + if(wParam & MK_LBUTTON) + nm_state = CW_MOUSE_LDOWN; + + if(row >= 0 && row < (int) tbl->n_rows) { + nm_state |= CW_MOUSE_ROW; + nm_row = row; + nm_col = col; + if(tbl->rows[row].flags & KHUI_CW_ROW_HEADER) { + khui_credwnd_outline * o; + + o = (khui_credwnd_outline *) tbl->rows[row].data; + + /* are we on a widget then? */ + x -= tbl->cols[o->col].x; + + if (!(o->flags & KHUI_CW_O_NOOUTLINE)) { + if(x >= 0 && x < KHUI_SMICON_CX) /* hit */ { + nm_state |= CW_MOUSE_WOUTLINE | CW_MOUSE_WIDGET; + } else if (tbl->cols[tbl->rows[row].col].attr_id == + KCDB_ATTR_ID_NAME && + col == tbl->rows[row].col && + x >= KHUI_SMICON_CX * 3 / 2 && + x < KHUI_SMICON_CX * 5 / 2){ + nm_state |= CW_MOUSE_WSTICKY | CW_MOUSE_WIDGET; + } else if (tbl->cols[tbl->rows[row].col].attr_id == + KCDB_ATTR_ID_NAME && + col == tbl->rows[row].col && + x >= KHUI_SMICON_CX * 3 && + x < KHUI_SMICON_CX * 4) { + nm_state |= CW_MOUSE_WICON | CW_MOUSE_WIDGET; + } + } else if (tbl->cols[o->col].attr_id == KCDB_ATTR_ID_NAME) { + if (col == tbl->rows[row].col && + x >= 0 && + x < KHUI_SMICON_CX){ + + nm_state |= CW_MOUSE_WSTICKY | CW_MOUSE_WIDGET; + + } else if (col == tbl->rows[row].col && + x >= KHUI_SMICON_CX * 3 / 2 && + x < KHUI_SMICON_CX * 5 / 2) { + nm_state |= CW_MOUSE_WICON | CW_MOUSE_WIDGET; + } + } + } + } + + /* did the user drag the cursor off the current row? */ + if((tbl->mouse_state & CW_MOUSE_LDOWN) && + (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) { + + if((nm_state & CW_MOUSE_WOUTLINE) && + (tbl->mouse_state & CW_MOUSE_WOUTLINE)) { + /* click on an outline widget */ + khui_credwnd_outline * o; + + o = (khui_credwnd_outline *) tbl->rows[nm_row].data; + tbl->mouse_state = CW_MOUSE_WIDGET | CW_MOUSE_WOUTLINE; + + cw_toggle_outline_state(tbl, o); + + return 0; + } else if ((nm_state & CW_MOUSE_WSTICKY) && + (tbl->mouse_state & CW_MOUSE_WSTICKY)) { + + khui_credwnd_outline * o; + khm_handle ident; + khm_int32 idf = 0; + + o = tbl->rows[nm_row].data; + ident = o->data; + + kcdb_identity_get_flags(ident, &idf); + idf &= KCDB_IDENT_FLAG_STICKY; + kcdb_identity_set_flags(ident, (idf ^ KCDB_IDENT_FLAG_STICKY), + KCDB_IDENT_FLAG_STICKY); + + tbl->mouse_state = CW_MOUSE_WIDGET | CW_MOUSE_WSTICKY; + + return 0; + } else if ((nm_state & CW_MOUSE_WICON) && + (tbl->mouse_state & CW_MOUSE_WICON)) { + /* click on an row icon */ + cw_select_row(tbl, nm_row, wParam); + cw_properties(hwnd); + } 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); + } + } + } + + /* ok, now if we are changing state, we need to invalidate a few + regions */ + if (((tbl->mouse_state ^ nm_state) & (CW_MOUSE_WIDGET | + CW_MOUSE_WOUTLINE | + CW_MOUSE_WSTICKY)) || + tbl->mouse_row != nm_row) { + + if(tbl->mouse_state & CW_MOUSE_WOUTLINE) { + r.left = tbl->cols[tbl->mouse_col].x - tbl->scr_left; + r.top = tbl->mouse_row * tbl->cell_height + + tbl->header_height - tbl->scr_top; + r.right = r.left + KHUI_SMICON_CX; + r.bottom = r.top + tbl->cell_height; + InvalidateRect(tbl->hwnd, &r, TRUE); + } + if(tbl->mouse_state & CW_MOUSE_WSTICKY) { + if (tbl->flags & KHUI_CW_TBL_EXPIDENT) { + + if (tbl->mouse_row >= 0 && tbl->mouse_row < tbl->n_rows) { + r = tbl->rows[tbl->mouse_row].r_ext; + OffsetRect(&r, -tbl->scr_left, tbl->header_height - tbl->scr_top); + r.right = r.left + KHUI_SMICON_CX; + InvalidateRect(tbl->hwnd, &r, TRUE); + } + + } else { + r.left = KHUI_SMICON_CX * 3 / 2 + + tbl->cols[tbl->mouse_col].x - tbl->scr_left; + r.top = tbl->mouse_row * tbl->cell_height + + tbl->header_height - tbl->scr_top; + r.right = r.left + KHUI_SMICON_CX; + r.bottom = r.top + tbl->cell_height; + } + InvalidateRect(tbl->hwnd, &r, TRUE); + } + + if ((tbl->mouse_state & nm_state) & CW_MOUSE_LDOWN) { + if (tbl->mouse_row == nm_row) + tbl->mouse_col = nm_col; + } else { + tbl->mouse_col = nm_col; + tbl->mouse_row = nm_row; + } + tbl->mouse_state = nm_state; + + /* same code block as above */ + if(tbl->mouse_state & CW_MOUSE_WOUTLINE) { + r.left = tbl->cols[tbl->mouse_col].x - tbl->scr_left; + r.top = tbl->mouse_row * tbl->cell_height + + tbl->header_height - tbl->scr_top; + r.right = r.left + KHUI_SMICON_CX; + r.bottom = r.top + tbl->cell_height; + InvalidateRect(tbl->hwnd, &r, TRUE); + } + if(tbl->mouse_state & CW_MOUSE_WSTICKY) { + if (tbl->flags & KHUI_CW_TBL_EXPIDENT) { + + if (tbl->mouse_row >= 0 && tbl->mouse_row < tbl->n_rows) { + r = tbl->rows[tbl->mouse_row].r_ext; + OffsetRect(&r, -tbl->scr_left, tbl->header_height - tbl->scr_top); + r.right = r.left + KHUI_SMICON_CX; + InvalidateRect(tbl->hwnd, &r, TRUE); + } + + } else { + r.left = KHUI_SMICON_CX * 3 / 2 + + tbl->cols[tbl->mouse_col].x - tbl->scr_left; + r.top = tbl->mouse_row * tbl->cell_height + + tbl->header_height - tbl->scr_top; + r.right = r.left + KHUI_SMICON_CX; + r.bottom = r.top + tbl->cell_height; + } + InvalidateRect(tbl->hwnd, &r, TRUE); + } + } else if(tbl->mouse_state != nm_state) { + + if ((tbl->mouse_state & nm_state) & CW_MOUSE_LDOWN) { + if (tbl->mouse_row == nm_row) { + tbl->mouse_col = nm_col; + tbl->mouse_state = nm_state; + } + } else { + tbl->mouse_col = nm_col; + tbl->mouse_row = nm_row; + tbl->mouse_state = nm_state; + } + } + + /* if it was a double click, also show the property + window */ + if (uMsg == WM_LBUTTONDBLCLK) { + cw_properties(hwnd); + } + + return 0; +} + +LRESULT +cw_wm_hscroll(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + khui_credwnd_tbl * tbl; + SCROLLINFO si; + RECT cr; + RECT lr; + RECT sr; + int dx; + int newpos; + + tbl = (khui_credwnd_tbl *) (LONG_PTR) GetWindowLongPtr(hwnd, 0); + GetClientRect(hwnd, &cr); + dx = tbl->scr_left; + + switch(LOWORD(wParam)) { + case SB_LEFT: + newpos = 0; + break; + + case SB_RIGHT: + newpos = tbl->ext_width; + break; + + case SB_LINELEFT: + newpos = tbl->scr_left - (tbl->ext_width / 12); + break; + + case SB_LINERIGHT: + newpos = tbl->scr_left + (tbl->ext_width / 12); + break; + + case SB_PAGELEFT: + newpos = tbl->scr_left - (cr.right - cr.left); + break; + + case SB_PAGERIGHT: + newpos = tbl->scr_left + (cr.right - cr.left); + break; + + case SB_THUMBTRACK: + case SB_THUMBPOSITION: + ZeroMemory(&si, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_TRACKPOS; + GetScrollInfo(hwnd, SB_HORZ, &si); + + newpos = si.nTrackPos; + break; + + default: + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + + //cr.top += tbl->header_height; + tbl->scr_left = newpos; + cw_update_extents(tbl, TRUE); + + dx -= tbl->scr_left; + + /* exclude the watermark */ + lr.bottom = cr.bottom; + lr.right = cr.right; + lr.top = max(cr.bottom - tbl->kbm_logo_shade.cy, cr.top); + lr.left = max(cr.right - tbl->kbm_logo_shade.cx, cr.left); + + if(cr.top < lr.top && cr.left < cr.right) { + sr.left = cr.left; + sr.right = cr.right; + sr.top = cr.top; + sr.bottom = lr.top; + ScrollWindowEx( + hwnd, + dx, + 0, + &sr, + &sr, + NULL, + NULL, + SW_INVALIDATE | SW_SCROLLCHILDREN); + } + + if(cr.left < lr.left && lr.top < lr.bottom) { + sr.left = cr.left; + sr.right = lr.left; + sr.top = lr.top; + sr.bottom = lr.bottom; + ScrollWindowEx( + hwnd, + dx, + 0, + &sr, + &sr, + NULL, + NULL, + SW_INVALIDATE | SW_SCROLLCHILDREN); + } + + if(lr.top < lr.bottom && lr.left < lr.right) { + InvalidateRect(hwnd, &lr, FALSE); + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +static void +cw_vscroll_to_pos(HWND hwnd, khui_credwnd_tbl * tbl, int newpos) { + RECT cr; + RECT sr; + RECT lr; + int dy; + + GetClientRect(hwnd, &cr); + cr.top += tbl->header_height; + dy = tbl->scr_top; + + tbl->scr_top = newpos; + cw_update_extents(tbl, TRUE); + + dy -= tbl->scr_top; + + /* exclude watermark */ + lr.bottom = cr.bottom; + lr.right = cr.right; + lr.top = max(cr.bottom - tbl->kbm_logo_shade.cy, cr.top); + lr.left = max(cr.right - tbl->kbm_logo_shade.cx, cr.left); + + if(cr.left < lr.left && cr.top < cr.bottom) { + sr.left = cr.left; + sr.right = lr.left; + sr.top = cr.top; + sr.bottom = cr.bottom; + ScrollWindowEx( + hwnd, + 0, + dy, + &sr, + &sr, + NULL, + NULL, + SW_INVALIDATE); + } + + if(lr.left < lr.right && cr.top < lr.top) { + sr.left = lr.left; + sr.right = lr.right; + sr.top = cr.top; + sr.bottom = lr.top; + ScrollWindowEx( + hwnd, + 0, + dy, + &sr, + &sr, + NULL, + NULL, + SW_INVALIDATE); + } + + if(lr.top < lr.bottom && lr.left < lr.right) { + InvalidateRect(hwnd, &lr, FALSE); + } +} + +LRESULT +cw_wm_vscroll(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + khui_credwnd_tbl * tbl; + SCROLLINFO si; + int newpos; + RECT cr; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + GetClientRect(hwnd, &cr); + cr.top += tbl->header_height; + + switch(LOWORD(wParam)) { + case SB_LEFT: + newpos = 0; + break; + + case SB_BOTTOM: + newpos = tbl->ext_height; + break; + + case SB_LINEUP: + newpos = tbl->scr_top - (tbl->ext_height / 12); + break; + + case SB_LINEDOWN: + newpos = tbl->scr_top + (tbl->ext_height / 12); + break; + + case SB_PAGEUP: + newpos = tbl->scr_top - (cr.bottom - cr.top); + break; + + case SB_PAGEDOWN: + newpos = tbl->scr_top + (cr.bottom - cr.top); + break; + + case SB_THUMBTRACK: + case SB_THUMBPOSITION: + ZeroMemory(&si, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_TRACKPOS; + GetScrollInfo(hwnd, SB_VERT, &si); + + newpos = si.nTrackPos; + break; + + default: + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + + cw_vscroll_to_pos(hwnd, tbl, newpos); + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +static void +cw_ensure_row_visible(HWND hwnd, khui_credwnd_tbl * tbl, int row) { + RECT r; + int newpos; + + if (row < 0) + row = 0; + else if (row >= (int) tbl->n_rows) + row = (int) tbl->n_rows - 1; + + GetClientRect(hwnd, &r); + r.top += tbl->header_height; + + if (row * tbl->cell_height < tbl->scr_top) { + newpos = row * tbl->cell_height; + } else if ((row + 1) * tbl->cell_height + > tbl->scr_top + (r.bottom - r.top)) { + newpos = ((row + 1) * tbl->cell_height) - (r.bottom - r.top); + } else + return; + + cw_vscroll_to_pos(hwnd, tbl, newpos); +} + +static INT_PTR CALLBACK +cw_pp_ident_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + khui_property_sheet * s; + + switch(uMsg) { + case WM_INITDIALOG: + { + PROPSHEETPAGE * p; + khm_handle ident; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size t; + khm_int32 i; + + p = (PROPSHEETPAGE *) lParam; + s = (khui_property_sheet *) p->lParam; + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) s); +#pragma warning(pop) + + ident = s->identity; + + t = sizeof(idname); + kcdb_identity_get_name(ident, idname, &t); + SetDlgItemText(hwnd, IDC_PP_IDNAME, idname); + + kcdb_identity_get_flags(ident, &i); + + CheckDlgButton(hwnd, IDC_PP_IDDEF, + ((i & KCDB_IDENT_FLAG_DEFAULT)?BST_CHECKED: + BST_UNCHECKED)); + + /* if it's default, you can't change it further */ + if (i & KCDB_IDENT_FLAG_DEFAULT) { + EnableWindow(GetDlgItem(hwnd, IDC_PP_IDDEF), FALSE); + } + + CheckDlgButton(hwnd, IDC_PP_IDSEARCH, + ((i & KCDB_IDENT_FLAG_SEARCHABLE)?BST_CHECKED: + BST_UNCHECKED)); + + CheckDlgButton(hwnd, IDC_PP_STICKY, + ((i & KCDB_IDENT_FLAG_STICKY)?BST_CHECKED: + BST_UNCHECKED)); + + khui_property_wnd_set_record(GetDlgItem(hwnd, IDC_PP_PROPLIST), + ident); + } + return TRUE; + + case WM_COMMAND: + s = (khui_property_sheet *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + switch(wParam) { + case MAKEWPARAM(IDC_PP_IDDEF, BN_CLICKED): + /* fallthrough */ + case MAKEWPARAM(IDC_PP_STICKY, BN_CLICKED): + + if (s->status != KHUI_PS_STATUS_NONE) + PropSheet_Changed(s->hwnd, hwnd); + return TRUE; + + case MAKEWPARAM(IDC_PP_CONFIG, BN_CLICKED): + { + khui_config_node cfg_id = NULL; + khui_config_node cfg_ids = NULL; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khm_int32 rv; + + khm_refresh_config(); + + rv = khui_cfg_open(NULL, + L"KhmIdentities", + &cfg_ids); + + if (KHM_FAILED(rv)) + return TRUE; + + cb = sizeof(idname); + if (KHM_SUCCEEDED(kcdb_identity_get_name(s->identity, + idname, + &cb))) { + rv = khui_cfg_open(cfg_ids, + idname, + &cfg_id); + } + + if (cfg_id) + khm_show_config_pane(cfg_id); + else + khm_show_config_pane(cfg_ids); + + if (cfg_ids) + khui_cfg_release(cfg_ids); + if (cfg_id) + khui_cfg_release(cfg_id); + } + return TRUE; + } + return FALSE; + + case WM_NOTIFY: + { + LPPSHNOTIFY lpp; + khm_int32 flags; + + lpp = (LPPSHNOTIFY) lParam; + s = (khui_property_sheet *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + switch(lpp->hdr.code) { + case PSN_APPLY: + flags = 0; + if (IsDlgButtonChecked(hwnd, IDC_PP_STICKY) == BST_CHECKED) + flags |= KCDB_IDENT_FLAG_STICKY; + if (IsDlgButtonChecked(hwnd, IDC_PP_IDDEF) == BST_CHECKED) + flags |= KCDB_IDENT_FLAG_DEFAULT; + + kcdb_identity_set_flags(s->identity, flags, + KCDB_IDENT_FLAG_STICKY | + KCDB_IDENT_FLAG_DEFAULT); + return TRUE; + + case PSN_RESET: + kcdb_identity_get_flags(s->identity, &flags); + + CheckDlgButton(hwnd, + IDC_PP_IDDEF, + ((flags & KCDB_IDENT_FLAG_DEFAULT)?BST_CHECKED: + BST_UNCHECKED)); + + /* if it's default, you can't change it further */ + if (flags & KCDB_IDENT_FLAG_DEFAULT) { + EnableWindow(GetDlgItem(hwnd, IDC_PP_IDDEF), FALSE); + } + + CheckDlgButton(hwnd, IDC_PP_IDSEARCH, + ((flags & KCDB_IDENT_FLAG_SEARCHABLE)?BST_CHECKED:BST_UNCHECKED)); + + CheckDlgButton(hwnd, IDC_PP_STICKY, + ((flags & KCDB_IDENT_FLAG_STICKY)?BST_CHECKED:BST_UNCHECKED)); + return TRUE; + } + } + break; + } + return FALSE; +} + +static INT_PTR CALLBACK +cw_pp_cred_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ) +{ + switch(uMsg) { + case WM_INITDIALOG: + { + khui_property_sheet * s; + PROPSHEETPAGE * p; + khm_handle cred; + + p = (PROPSHEETPAGE *) lParam; + s = (khui_property_sheet *) p->lParam; + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) s); +#pragma warning(pop) + + cred = s->cred; + + khui_property_wnd_set_record( + GetDlgItem(hwnd, IDC_PP_CPROPLIST), + cred); + } + return TRUE; + } + return FALSE; +} + +static void +cw_pp_begin(khui_property_sheet * s) +{ + PROPSHEETPAGE *p; + + if(s->identity) { + p = PMALLOC(sizeof(*p)); + ZeroMemory(p, sizeof(*p)); + + p->dwSize = sizeof(*p); + p->dwFlags = 0; + p->hInstance = khm_hInstance; + p->pszTemplate = MAKEINTRESOURCE(IDD_PP_IDENT); + p->pfnDlgProc = cw_pp_ident_proc; + p->lParam = (LPARAM) s; + + khui_ps_add_page(s, KHUI_PPCT_IDENTITY, 129, p, NULL); + } + + if(s->cred) { + p = PMALLOC(sizeof(*p)); + ZeroMemory(p, sizeof(*p)); + + p->dwSize = sizeof(*p); + p->dwFlags = 0; + p->hInstance = khm_hInstance; + p->pszTemplate = MAKEINTRESOURCE(IDD_PP_CRED); + p->pfnDlgProc = cw_pp_cred_proc; + p->lParam = (LPARAM) s; + + khui_ps_add_page(s, KHUI_PPCT_CREDENTIAL, 128, p, NULL); + } +} + +static void +cw_pp_precreate(khui_property_sheet * s) +{ + khui_ps_show_sheet(khm_hwnd_main, s); + + khm_add_property_sheet(s); +} + +static void +cw_pp_end(khui_property_sheet * s) +{ + khui_property_page * p = NULL; + + khui_ps_find_page(s, KHUI_PPCT_IDENTITY, &p); + if(p) { + PFREE(p->p_page); + p->p_page = NULL; + } + + p = NULL; + + khui_ps_find_page(s, KHUI_PPCT_CREDENTIAL, &p); + if(p) { + PFREE(p->p_page); + p->p_page = NULL; + } +} + +static void +cw_pp_destroy(khui_property_sheet *ps) +{ + if(ps->ctx.scope == KHUI_SCOPE_CRED) { + if(ps->header.pszCaption) + PFREE((LPWSTR) ps->header.pszCaption); + } + + khui_context_release(&ps->ctx); + + khui_ps_destroy_sheet(ps); + + /* this is pretty weird because ps gets freed when + khui_ps_destroy_sheet() is called. However, since destroying + ps involves sending a WM_DESTROY message to the property sheet, + we still need to keep it on the property sheet chain (or else + the messages will not be delivered). This is only safe because + we are not relinquishing the thread in-between destroying ps + and removing it from the chain. */ + + /* TODO: fix this */ + khm_del_property_sheet(ps); +} + +LRESULT +cw_properties(HWND hwnd) +{ + /* show a property sheet of some sort */ + khui_action_context ctx; + khui_property_sheet * ps; + khui_credwnd_tbl * tbl; + + khui_context_get(&ctx); + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + if(ctx.scope == KHUI_SCOPE_NONE) { + khui_context_release(&ctx); + return FALSE; + + /* While it seems like a good idea, doing this is not */ +#if 0 + /* try to establish a context based on the current cursor + position */ + if(tbl->cursor_row >= 0 && tbl->cursor_row < (int) tbl->n_rows) { + if(tbl->rows[tbl->cursor_row].flags & KHUI_CW_ROW_HEADER) { + if(tbl->cols[tbl->rows[tbl->cursor_row].col].attr_id == KCDB_ATTR_ID_NAME) { + /* identity context */ + ctx.ctx = KHUI_SCOPE_IDENT; + ctx.identity = (khm_handle) + ((khui_credwnd_outline *) tbl->rows[tbl->cursor_row].data)->data; + } else if(tbl->cols[tbl->rows[tbl->cursor_row].col].attr_id == KCDB_ATTR_TYPE_NAME) { + ctx.ctx = KHUI_SCOPE_CREDTYPE; + ctx.cred_type = (khm_int32) (DWORD_PTR) + ((khui_credwnd_outline *) tbl->rows[tbl->cursor_row].data)->data; + } else { + ctx.ctx = KHUI_SCOPE_GROUP; + //ctx.parm = (khm_lparm) tbl->rows[tbl->cursor_row].data; + /* TODO: Figure out method of establishing a credgroup */ + } + } else { + /* a credential context */ + ctx.ctx = KHUI_SCOPE_CRED; + ctx.cred = (khm_handle) tbl->rows[tbl->cursor_row].data; + } + } +#endif + } + + /* if still no context, then we can't show a property sheet */ + if(ctx.scope == KHUI_SCOPE_NONE) { + khui_context_release(&ctx); + return FALSE; + } + + khui_ps_create_sheet(&ps); + + if(ctx.scope == KHUI_SCOPE_IDENT) { + khm_handle ident; + khm_size t; + + ident = ctx.identity; + + ps->header.hInstance = khm_hInstance; + ps->header.pszIcon = MAKEINTRESOURCE(IDI_MAIN_APP); + + kcdb_identity_get_name(ident, NULL, &t); + + if(t > 0) { + ps->header.pszCaption = PMALLOC(t); + kcdb_identity_get_name(ident, + (wchar_t *) ps->header.pszCaption, &t); + } else { + ps->header.pszCaption = NULL; + } + + ps->ctx = ctx; + ps->identity = ident; + ps->credtype = KCDB_CREDTYPE_INVALID; + + kmq_post_message(KMSG_CRED, KMSG_CRED_PP_BEGIN, 0, (void *) ps); + + } else if(ctx.scope == KHUI_SCOPE_CREDTYPE) { + khm_size t = 0; + khm_int32 cred_type; + + if (ctx.identity == NULL) { + /* currently, we can't show a property sheet at this point + since most credentials providers don't provide a + property sheet that works without an identity. */ + + khui_context_release(&ctx); + khui_ps_destroy_sheet(ps); + return TRUE; + } + + cred_type = ctx.cred_type; + + ps->header.hInstance = khm_hInstance; + ps->header.pszIcon = MAKEINTRESOURCE(IDI_MAIN_APP); + + ps->ctx = ctx; + ps->credtype = cred_type; + + if(ctx.identity) { + ps->identity = ctx.identity; + /* also, if there is an associated identity, we assume that + the properties are for the specified credentials type + specific to the identity. Hence we change the title to + something else */ + kcdb_identity_get_name(ctx.identity, NULL, &t); + if (t > 0) { + ps->header.pszCaption = PMALLOC(t); + kcdb_identity_get_name(ctx.identity, (wchar_t *) ps->header.pszCaption, &t); + } else { + ps->header.pszCaption = NULL; + } + } else { + /* we don't actually reach here since we handle this case + above */ + kcdb_credtype_describe(cred_type, NULL, &t, KCDB_TS_LONG); + if(t > 0) { + ps->header.pszCaption = PMALLOC(t); + kcdb_credtype_describe(cred_type, (wchar_t *) ps->header.pszCaption, &t, KCDB_TS_LONG); + } else { + ps->header.pszCaption = NULL; + } + } + + kmq_post_message(KMSG_CRED, KMSG_CRED_PP_BEGIN, 0, (void *) ps); + } else if(ctx.scope == KHUI_SCOPE_CRED) { + khm_handle cred; + khm_size t; + + cred = ctx.cred; + + ps->header.hInstance = khm_hInstance; + ps->header.pszIcon = MAKEINTRESOURCE(IDI_MAIN_APP); + ps->ctx = ctx; + + kcdb_cred_get_name(cred, NULL, &t); + ps->header.pszCaption = PMALLOC(t); + kcdb_cred_get_name(cred, (LPWSTR) ps->header.pszCaption, &t); + + kcdb_cred_get_identity(cred, &ps->identity); + kcdb_cred_get_type(cred, &ps->credtype); + ps->cred = cred; + + kmq_post_message(KMSG_CRED, KMSG_CRED_PP_BEGIN, 0, (void *) ps); + } else { + khui_context_release(&ctx); + khui_ps_destroy_sheet(ps); + } + + /* by the way, if we are actually opening a property sheet, we + leave ctx held (which is now copied to ps->ctx). it will be + released when the property sheet is destroyed */ + + return TRUE; +} + +LRESULT +cw_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + khui_credwnd_tbl * tbl; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + if(HIWORD(wParam) == BN_CLICKED && + LOWORD(wParam) == KHUI_HTWND_CTLID) { + + wchar_t wid[256]; + /* a hyperlink was activated */ + khui_htwnd_link * l; + l = (khui_htwnd_link *) lParam; + StringCchCopyN(wid, ARRAYLENGTH(wid), l->id, l->id_len); + wid[l->id_len] = 0; + + if(!wcscmp(wid, L"NewCreds")) { + PostMessage(khm_hwnd_main, WM_COMMAND, + MAKEWPARAM(KHUI_ACTION_NEW_CRED,0), 0); + } + return TRUE; + } + + switch(LOWORD(wParam)) + { + case KHUI_PACTION_ENTER: + /* enter key is a synonym for the default action, on the + context, which is to lauch a property sheet */ + /* fallthrough */ + case KHUI_ACTION_PROPERTIES: + { + return cw_properties(hwnd); + } + break; + + case KHUI_ACTION_LAYOUT_RELOAD: + { + 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_selection_state(tbl); + cw_update_extents(tbl, TRUE); + + InvalidateRect(tbl->hwnd, NULL, TRUE); + } + break; + + case KHUI_ACTION_LAYOUT_ID: + { + cw_save_view(tbl, NULL); + cw_unload_view(tbl); + + cw_load_view(tbl, L"ByIdentity", hwnd); + cw_insert_header_cols(tbl); + + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_selection_state(tbl); + cw_update_extents(tbl, TRUE); + + InvalidateRect(tbl->hwnd, NULL, TRUE); + + } + break; + + case KHUI_ACTION_LAYOUT_LOC: + { + cw_save_view(tbl, NULL); + cw_unload_view(tbl); + + cw_load_view(tbl, L"ByLocation", hwnd); + cw_insert_header_cols(tbl); + + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_selection_state(tbl); + cw_update_extents(tbl, TRUE); + + InvalidateRect(tbl->hwnd, NULL, TRUE); + + } + 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_selection_state(tbl); + cw_update_extents(tbl, TRUE); + + InvalidateRect(tbl->hwnd, NULL, TRUE); + + } + 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_selection_state(tbl); + cw_update_extents(tbl, TRUE); + + InvalidateRect(tbl->hwnd, NULL, TRUE); + + } + break; + + case KHUI_ACTION_LAYOUT_MINI: + { + cw_save_view(tbl, NULL); + cw_unload_view(tbl); + + cw_load_view(tbl, NULL, hwnd); + cw_insert_header_cols(tbl); + + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_selection_state(tbl); + cw_update_extents(tbl, TRUE); + + InvalidateRect(tbl->hwnd, NULL, TRUE); + } + break; + + case KHUI_PACTION_UP: + case KHUI_PACTION_UP_EXTEND: + case KHUI_PACTION_UP_TOGGLE: + { /* cursor up */ + khm_int32 new_row; + WPARAM wp = 0; + + new_row = tbl->cursor_row - 1; + + /* checking both bounds. we make no assumption about the + value of cursor_row before this message */ + if(new_row < 0) + new_row = 0; + if(new_row >= (int) tbl->n_rows) + new_row = (int) tbl->n_rows - 1; + + if (LOWORD(wParam) == KHUI_PACTION_UP) + wp = 0; + else if (LOWORD(wParam) == KHUI_PACTION_UP_EXTEND) + wp = MK_SHIFT; + else if (LOWORD(wParam) == KHUI_PACTION_UP_TOGGLE) + wp = 0; //MK_CONTROL; + else { +#ifdef DEBUG + assert(FALSE); +#endif + } + + cw_select_row(tbl, new_row, wp); + cw_ensure_row_visible(hwnd, tbl, new_row); + } + 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: + { /* cursor down */ + khm_int32 new_row; + WPARAM wp = 0; + + new_row = tbl->cursor_row + 1; + + /* checking both bounds. we make no assumption about the + value of cursor_row before this message */ + if(new_row < 0) + new_row = 0; + if(new_row >= (int) tbl->n_rows) + new_row = (int) tbl->n_rows - 1; + + if (LOWORD(wParam) == KHUI_PACTION_DOWN) + wp = 0; + else if (LOWORD(wParam) == KHUI_PACTION_DOWN_EXTEND) + wp = MK_SHIFT; + else if (LOWORD(wParam) == KHUI_PACTION_DOWN_TOGGLE) + wp = 0; //MK_CONTROL; + else { +#ifdef DEBUG + assert(FALSE); +#endif + } + + cw_select_row(tbl, new_row, wp); + cw_ensure_row_visible(hwnd, tbl, new_row); + } + 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); + } + break; + + case KHUI_PACTION_LEFT: + { /* collapse and up*/ + khui_credwnd_outline * o; + int r; + + if(tbl->cursor_row < 0 || tbl->cursor_row >= (int) tbl->n_rows) { + cw_select_row(tbl, 0, 0); + break; + } + + for(r = tbl->cursor_row; + (r >= 0 && !(tbl->rows[r].flags & KHUI_CW_ROW_HEADER)); + r--); + + if(r < 0) + break; + + /* If we were not on a header, we collapse the innermost + outline. Otherwise, we collpase up to the parent + outline level */ + + if(r != tbl->cursor_row) { + o = (khui_credwnd_outline *) tbl->rows[r].data; + + cw_toggle_outline_state(tbl, o); + } else { + o = (khui_credwnd_outline *) tbl->rows[r].data; + + if(o->flags & KHUI_CW_O_EXPAND) { + cw_toggle_outline_state(tbl, o); + } else { + o = TPARENT(o); + if(o) { + cw_toggle_outline_state(tbl, o); + r = o->start; + } else if(r > 0) + r--; + } + } + + cw_select_row(tbl, r, 0); + } + break; + + case KHUI_PACTION_RIGHT: + { /* expand and down*/ + khui_credwnd_outline * o; + int r; + + if(tbl->cursor_row < 0 || + tbl->cursor_row >= (int) tbl->n_rows) { + cw_select_row(tbl, 0, 0); + break; + } + + r = tbl->cursor_row; + + if(tbl->rows[r].flags & KHUI_CW_ROW_HEADER) { + o = (khui_credwnd_outline *) tbl->rows[r].data; + if(!(o->flags & KHUI_CW_O_EXPAND)) { + cw_toggle_outline_state(tbl, o); + } + } + + r++; + if (r >= (int) tbl->n_rows) + r = (int)tbl->n_rows - 1; + + cw_select_row(tbl, r, 0); + } + break; + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +LRESULT +cw_wm_contextmenu(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + RECT r; + int x,y; + int row; + khui_credwnd_tbl * tbl; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + GetWindowRect(hwnd, &r); + + x = GET_X_LPARAM(lParam); + y = GET_Y_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); + } + + if (tbl->flags & KHUI_CW_TBL_EXPIDENT) { + int i, yt; + + yt = 0; + for (i=0; i < tbl->n_rows && yt < y; i++) { + if (tbl->rows[i].flags & KHUI_CW_ROW_EXPVIEW) + yt += tbl->cell_height * CW_EXP_ROW_MULT; + else + yt += tbl->cell_height; + if (yt > y) + break; + } + + row = i; + + } else { + row = y / tbl->cell_height; + } + + if(row < 0 || row >= (int) tbl->n_rows) + return FALSE; + + cw_set_row_context(tbl, row); + + khm_menu_show_panel(KHUI_MENU_IDENT_CTX, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + +#if 0 + /* calling cw_set_row_context() should take care of enabling or + disabling actions as appropriate. We don't need to + differentiate between IDENT_CTX and TOK_CTX here. */ + if((tbl->rows[row].flags & KHUI_CW_ROW_HEADER) && + (tbl->cols[tbl->rows[row].col].attr_id == KCDB_ATTR_ID_NAME)) { + khm_menu_show_panel(KHUI_MENU_IDENT_CTX, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + //khui_context_reset(); + } else { + khm_menu_show_panel(KHUI_MENU_TOK_CTX, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + //khui_context_reset(); + } +#endif + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +/* copy and paste template */ +#if 0 +LRESULT +cw_wm_msg(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} +#endif + +LRESULT CALLBACK +khm_credwnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) { + case WM_COMMAND: + return cw_wm_command(hwnd, uMsg, wParam, lParam); + + case WM_CREATE: + return cw_wm_create(hwnd, uMsg, wParam, lParam); + + case WM_DESTROY: + return cw_wm_destroy(hwnd, uMsg, wParam, lParam); + + case WM_ERASEBKGND: + /* we don't bother wasting cycles erasing the background + because the foreground elements completely cover the + client area */ + return FALSE; + + case WM_PAINT: + return cw_wm_paint(hwnd, uMsg, wParam, lParam); + + case WM_PRINTCLIENT: + return cw_wm_paint(hwnd, uMsg, wParam, lParam); + + case WM_SIZE: + return cw_wm_size(hwnd, uMsg, wParam, lParam); + + case WM_NOTIFY: + return cw_wm_notify(hwnd, uMsg, wParam, lParam); + + case WM_HSCROLL: + return cw_wm_hscroll(hwnd, uMsg, wParam, lParam); + + case WM_VSCROLL: + return cw_wm_vscroll(hwnd, uMsg, wParam, lParam); + + case KMQ_WM_DISPATCH: + return cw_kmq_wm_dispatch(hwnd, uMsg, wParam, lParam); + + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: + case WM_MOUSEMOVE: + case WM_LBUTTONUP: + return cw_wm_mouse(hwnd, uMsg, wParam, lParam); + + case WM_CONTEXTMENU: + return cw_wm_contextmenu(hwnd, uMsg, wParam, lParam); + } + + return DefWindowProc(hwnd,uMsg,wParam,lParam); +} + +void +khm_register_credwnd_class(void) { + WNDCLASSEX wcx; + kcdb_attrib attrib; + khm_int32 attr_id; + + wcx.cbSize = sizeof(wcx); + wcx.style = CS_DBLCLKS | CS_OWNDC; + wcx.lpfnWndProc = khm_credwnd_proc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = sizeof(LONG_PTR); + wcx.hInstance = khm_hInstance; + wcx.hIcon = NULL; + wcx.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); + wcx.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); + wcx.lpszMenuName = NULL; + wcx.lpszClassName = KHUI_CREDWND_CLASS_NAME; + wcx.hIconSm = NULL; + + khui_credwnd_cls = RegisterClassEx(&wcx); + + /* while we are at it, register the credwnd attribute type as well, and + obtain the type ID */ + if(KHM_FAILED(kcdb_attrib_get_id(KHUI_CREDWND_FLAG_ATTRNAME, &attr_id))) { + ZeroMemory(&attrib, sizeof(attrib)); + attrib.id = KCDB_ATTR_INVALID; + attrib.flags = KCDB_ATTR_FLAG_HIDDEN; + attrib.type = KCDB_TYPE_INT32; + attrib.name = KHUI_CREDWND_FLAG_ATTRNAME; + + kcdb_attrib_register(&attrib, &attr_id); + } + + khui_cw_flag_id = attr_id; +} + +void +khm_unregister_credwnd_class(void) { + UnregisterClass(MAKEINTATOM(khui_credwnd_cls), khm_hInstance); +} + +HWND +khm_create_credwnd(HWND parent) { + RECT r; + HWND hwnd; + + ZeroMemory(attr_to_action, sizeof(attr_to_action)); + + GetClientRect(parent, &r); + + hwnd = CreateWindowEx + (0, + MAKEINTATOM(khui_credwnd_cls), + L"", + WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + 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 adecb9f07..47f8a745e 100644 --- a/src/windows/identity/ui/credwnd.h +++ b/src/windows/identity/ui/credwnd.h @@ -1,300 +1,300 @@ -/* - * 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_CREDWND_H -#define __KHIMAIRA_CREDWND_H - -#define KHUI_CREDWND_CLASS_NAME L"NetIDMgrCredWnd" - -#define KHUI_CREDWND_FLAG_ATTRNAME L"CredWndFlags" - -extern khm_int32 khui_cw_flag_id; - -/* The expiration states */ -#define CW_EXPSTATE_NONE 0x00000000 -#define CW_EXPSTATE_WARN 0x00000400 -#define CW_EXPSTATE_CRITICAL 0x00000800 -#define CW_EXPSTATE_EXPIRED 0x00000c00 - -#define CW_EXPSTATE_MASK 0x00000c00 - -typedef struct khui_credwnd_outline_t { - khm_int32 flags; /* combination of KHUI_CW_O_* */ - khm_int32 start; /* first row of outline */ - khm_int32 length; /* number of rows in outline */ - khm_int32 level; /* outline level */ - khm_int32 col; /* outline column */ - wchar_t *header; /* character string associated with header */ - khm_int32 attr_id; - void * data; /* level specific data : - Identity -> handle to identity - Type -> type ID - otherwise -> canonical data buffer - */ - khm_size cb_data; - - khm_size idx_start; /* index of the first cred in the credset */ - khm_size idx_end; /* index of the last cred in the credset */ - 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_NOOUTLINE 0x00000040 -#define KHUI_CW_O_RELIDENT 0x00000080 -#define KHUI_CW_O_EMPTY 0x00000100 -/* NOTE: KHUI_CW_O_* shares the same bit-space as CW_EXPSTATE_* */ - -typedef struct khui_credwnd_row_t { - khm_int32 flags; - khm_int32 col; - khm_handle data; - khm_size idx_start; - khm_size idx_end; - RECT r_ext; /* extents of this row */ -} khui_credwnd_row; - -#define KHUI_CW_ROW_CRED 0x00000002 -#define KHUI_CW_ROW_HEADER 0x00000004 -#define KHUI_CW_ROW_TIMERSET 0x00000008 -#define KHUI_CW_ROW_SELECTED 0x00000010 -#define KHUI_CW_ROW_EXPVIEW 0x00000020 -/* NOTE: KHUI_CW_ROW_* shares the same bit-space as CW_EXPSTATE_* */ - -/* row allocation */ -/* initial number of rows to be allocated */ -#define KHUI_CW_ROW_INITIAL 512 -/* allocation increment, if we run out of space */ -#define KHUI_CW_ROW_INCREMENT 512 - -typedef struct khui_credwnd_col_t { - khm_int32 attr_id; - khm_int32 width; /* width of the column (screen units) */ - khm_int32 x; /* starting x coordinate (screen units) */ - khm_int32 flags; /* combination of KHUI_CW_COL_* */ - khm_int32 sort_index; - wchar_t * title; -} khui_credwnd_col; - -/* column allocation */ -/* initial number of columns to be allocated */ -#define KHUI_CW_COL_INITIAL 16 -/* allocation increment, if we run out of space */ -#define KHUI_CW_COL_INCREMENT 16 - -#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 -#define KHUI_CW_COL_FILLER 0x00000080 - -/* Custom column attributes (are not kcdb attributes) */ -#define CW_CA_FLAGS -1 -#define CW_CANAME_FLAGS L"_CWFlags" - -#define CW_CA_TYPEICON -2 -#define CW_CANAME_TYPEICON L"_CWTypeIcon" - -#define cw_is_custom_attr(i) ((i)<0) - -typedef struct tag_khui_credwnd_ident { - - khm_handle ident; - khm_int32 ident_flags; - khm_int32 credtype; - wchar_t name[KCDB_IDENT_MAXCCH_NAME]; - wchar_t credtype_name[KCDB_MAXCCH_NAME]; - - khm_size credcount; /* count of all credentials */ - khm_size id_credcount; /* count of identity credentials - (credentials that are of the - identity type */ - khm_size init_credcount; /* count of initial credentials */ - FILETIME ft_expire; - -} khui_credwnd_ident; - -#define CW_IDENT_ALLOC_INCR 4 - -#define CW_EXP_ROW_MULT 2 - -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 */ - khm_int32 ext_height; /* screen units */ - khm_int32 cell_height; /* screen units */ - - HWND hwnd_header; /* header control */ - khm_int32 header_height; /* height of the header */ - HWND hwnd_notif; /* notification control */ - - khui_credwnd_col * cols; /* n_cols elements */ - khui_credwnd_row * rows; /* n_rows elements */ - int n_cols; - int n_total_cols; /* number of columns actually - allocated in cols */ - 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_* */ - - int cursor_row; /* cursor and selection */ - int anchor_row; /* anchor, for range selections */ - - /* view parameters */ - khm_int32 hpad; - khm_int32 vpad; - khm_int32 hpad_h; /* horizontal padding correction for headers */ - khm_int32 threshold_warn; /* Warning threshold, in seconds*/ - khm_int32 threshold_critical; /* Critical threshold, in seconds */ - - /* graphics objects we are going to need. */ - HFONT hf_normal; /* normal text */ - HFONT hf_header; /* header text */ - HFONT hf_bold; /* bold text */ - HFONT hf_bold_header; /* bold header text */ - - HBRUSH hb_normal; /* normal background brush */ - HBRUSH hb_grey; /* normal background brush (greyed) */ - HBRUSH hb_s; /* normal background brush (selected) */ - - HBRUSH hb_hdr_bg; /* header background brush (normal) */ - HBRUSH hb_hdr_bg_exp; /* header background brush (expired) */ - HBRUSH hb_hdr_bg_warn; /* header background brush (warn) */ - HBRUSH hb_hdr_bg_crit; /* header background brush (critical) */ - HBRUSH hb_hdr_bg_def; /* header background brush (default) */ - - HBRUSH hb_hdr_bg_s; /* header background brush (selected) */ - HBRUSH hb_hdr_bg_exp_s; /* header background brush (expired,selected) */ - HBRUSH hb_hdr_bg_warn_s;/* header background brush (warn,selected) */ - HBRUSH hb_hdr_bg_crit_s;/* header background brush (critical,selected) */ - HBRUSH hb_hdr_bg_def_s; /* header background brush (default,selected) */ - - COLORREF cr_normal; /* text color (normal) */ - COLORREF cr_s; /* text color (selected) */ - COLORREF cr_hdr_normal; /* header text color (normal) */ - COLORREF cr_hdr_s; /* header text color (selected) */ - COLORREF cr_hdr_gray; /* header text color (greyed) */ - COLORREF cr_hdr_gray_s; /* header text color (greyed,selected) */ - - COLORREF cr_hdr_outline;/* header outline color */ - - HCURSOR hc_hand; /* the HAND cursor */ - khui_ilist * ilist; /* image list */ - - HICON hi_lg_ident; /* large identity icon */ - - /* mouse state */ - khm_int32 mouse_state; /* state of the mouse can be combo of CW_MOUSE_* values */ - khm_int32 mouse_row; /* row that the mouse state applies to */ - khm_int32 mouse_col; /* col that the mouse state applies to */ - - khui_bitmap kbm_logo_shade; - - /* the credentials set */ - khm_handle credset; - - khui_credwnd_ident * idents; - khm_size n_idents; - khm_size nc_idents; - -} khui_credwnd_tbl; - -#define KHUI_MAXCB_HEADING 256 - -/* table flags */ -#define KHUI_CW_TBL_INITIALIZED 0x00000001 -#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 -#define KHUI_CW_TBL_EXPIDENT 0x00000800 -#define KHUI_CW_TBL_NOHEADER 0x00001000 - -/* mouse_state constants */ -#define CW_MOUSE_NONE 0x00000000 /* nothing interesting */ -#define CW_MOUSE_WIDGET 0x00000001 /* mouse is highlighting a - widget */ -#define CW_MOUSE_LDOWN 0x00000002 /* left button is down */ -#define CW_MOUSE_ROW 0x00000004 /* mouse is acive over a valid - row */ -#define CW_MOUSE_WOUTLINE 0x00000008 /* mouse is highlighting an - outline widget */ -#define CW_MOUSE_WSTICKY 0x00000010 /* mouse is highlighting a - sticky widget */ -#define CW_MOUSE_WICON 0x00000020 /* an icon widget. represents - the icon next to identities - and next to credentials. */ - -#define CW_MOUSE_WMASK 0x00000039 /* all widget bits */ - -void khm_unregister_credwnd_class(void); - -void khm_register_credwnd_class(void); - -HWND khm_create_credwnd(HWND parent); - -LRESULT CALLBACK khm_credwnd_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam - ); - -void cw_load_view(khui_credwnd_tbl * tbl, wchar_t * viewname, HWND hwnd); - -void cw_update_creds(khui_credwnd_tbl * tbl); - -void cw_unload_view(khui_credwnd_tbl * tbl); - -void cw_hditem_from_tbl_col(khui_credwnd_col * col, HDITEM *phi); - -int cw_update_extents(khui_credwnd_tbl * tbl, khm_boolean update_scroll); - -void cw_insert_header_cols(khui_credwnd_tbl * tbl); - -void khm_get_cw_element_font(HDC hdc, wchar_t * name, BOOL use_default, - LOGFONT * pfont); - -void khm_set_cw_element_font(wchar_t * name, LOGFONT * pfont); - -#endif +/* + * 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_CREDWND_H +#define __KHIMAIRA_CREDWND_H + +#define KHUI_CREDWND_CLASS_NAME L"NetIDMgrCredWnd" + +#define KHUI_CREDWND_FLAG_ATTRNAME L"CredWndFlags" + +extern khm_int32 khui_cw_flag_id; + +/* The expiration states */ +#define CW_EXPSTATE_NONE 0x00000000 +#define CW_EXPSTATE_WARN 0x00000400 +#define CW_EXPSTATE_CRITICAL 0x00000800 +#define CW_EXPSTATE_EXPIRED 0x00000c00 + +#define CW_EXPSTATE_MASK 0x00000c00 + +typedef struct khui_credwnd_outline_t { + khm_int32 flags; /* combination of KHUI_CW_O_* */ + khm_int32 start; /* first row of outline */ + khm_int32 length; /* number of rows in outline */ + khm_int32 level; /* outline level */ + khm_int32 col; /* outline column */ + wchar_t *header; /* character string associated with header */ + khm_int32 attr_id; + void * data; /* level specific data : + Identity -> handle to identity + Type -> type ID + otherwise -> canonical data buffer + */ + khm_size cb_data; + + khm_size idx_start; /* index of the first cred in the credset */ + khm_size idx_end; /* index of the last cred in the credset */ + 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_NOOUTLINE 0x00000040 +#define KHUI_CW_O_RELIDENT 0x00000080 +#define KHUI_CW_O_EMPTY 0x00000100 +/* NOTE: KHUI_CW_O_* shares the same bit-space as CW_EXPSTATE_* */ + +typedef struct khui_credwnd_row_t { + khm_int32 flags; + khm_int32 col; + khm_handle data; + khm_size idx_start; + khm_size idx_end; + RECT r_ext; /* extents of this row */ +} khui_credwnd_row; + +#define KHUI_CW_ROW_CRED 0x00000002 +#define KHUI_CW_ROW_HEADER 0x00000004 +#define KHUI_CW_ROW_TIMERSET 0x00000008 +#define KHUI_CW_ROW_SELECTED 0x00000010 +#define KHUI_CW_ROW_EXPVIEW 0x00000020 +/* NOTE: KHUI_CW_ROW_* shares the same bit-space as CW_EXPSTATE_* */ + +/* row allocation */ +/* initial number of rows to be allocated */ +#define KHUI_CW_ROW_INITIAL 512 +/* allocation increment, if we run out of space */ +#define KHUI_CW_ROW_INCREMENT 512 + +typedef struct khui_credwnd_col_t { + khm_int32 attr_id; + khm_int32 width; /* width of the column (screen units) */ + khm_int32 x; /* starting x coordinate (screen units) */ + khm_int32 flags; /* combination of KHUI_CW_COL_* */ + khm_int32 sort_index; + wchar_t * title; +} khui_credwnd_col; + +/* column allocation */ +/* initial number of columns to be allocated */ +#define KHUI_CW_COL_INITIAL 16 +/* allocation increment, if we run out of space */ +#define KHUI_CW_COL_INCREMENT 16 + +#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 +#define KHUI_CW_COL_FILLER 0x00000080 + +/* Custom column attributes (are not kcdb attributes) */ +#define CW_CA_FLAGS -1 +#define CW_CANAME_FLAGS L"_CWFlags" + +#define CW_CA_TYPEICON -2 +#define CW_CANAME_TYPEICON L"_CWTypeIcon" + +#define cw_is_custom_attr(i) ((i)<0) + +typedef struct tag_khui_credwnd_ident { + + khm_handle ident; + khm_int32 ident_flags; + khm_int32 credtype; + wchar_t name[KCDB_IDENT_MAXCCH_NAME]; + wchar_t credtype_name[KCDB_MAXCCH_NAME]; + + khm_size credcount; /* count of all credentials */ + khm_size id_credcount; /* count of identity credentials + (credentials that are of the + identity type */ + khm_size init_credcount; /* count of initial credentials */ + FILETIME ft_expire; + +} khui_credwnd_ident; + +#define CW_IDENT_ALLOC_INCR 4 + +#define CW_EXP_ROW_MULT 2 + +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 */ + khm_int32 ext_height; /* screen units */ + khm_int32 cell_height; /* screen units */ + + HWND hwnd_header; /* header control */ + khm_int32 header_height; /* height of the header */ + HWND hwnd_notif; /* notification control */ + + khui_credwnd_col * cols; /* n_cols elements */ + khui_credwnd_row * rows; /* n_rows elements */ + int n_cols; + int n_total_cols; /* number of columns actually + allocated in cols */ + 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_* */ + + int cursor_row; /* cursor and selection */ + int anchor_row; /* anchor, for range selections */ + + /* view parameters */ + khm_int32 hpad; + khm_int32 vpad; + khm_int32 hpad_h; /* horizontal padding correction for headers */ + khm_int32 threshold_warn; /* Warning threshold, in seconds*/ + khm_int32 threshold_critical; /* Critical threshold, in seconds */ + + /* graphics objects we are going to need. */ + HFONT hf_normal; /* normal text */ + HFONT hf_header; /* header text */ + HFONT hf_bold; /* bold text */ + HFONT hf_bold_header; /* bold header text */ + + HBRUSH hb_normal; /* normal background brush */ + HBRUSH hb_grey; /* normal background brush (greyed) */ + HBRUSH hb_s; /* normal background brush (selected) */ + + HBRUSH hb_hdr_bg; /* header background brush (normal) */ + HBRUSH hb_hdr_bg_exp; /* header background brush (expired) */ + HBRUSH hb_hdr_bg_warn; /* header background brush (warn) */ + HBRUSH hb_hdr_bg_crit; /* header background brush (critical) */ + HBRUSH hb_hdr_bg_def; /* header background brush (default) */ + + HBRUSH hb_hdr_bg_s; /* header background brush (selected) */ + HBRUSH hb_hdr_bg_exp_s; /* header background brush (expired,selected) */ + HBRUSH hb_hdr_bg_warn_s;/* header background brush (warn,selected) */ + HBRUSH hb_hdr_bg_crit_s;/* header background brush (critical,selected) */ + HBRUSH hb_hdr_bg_def_s; /* header background brush (default,selected) */ + + COLORREF cr_normal; /* text color (normal) */ + COLORREF cr_s; /* text color (selected) */ + COLORREF cr_hdr_normal; /* header text color (normal) */ + COLORREF cr_hdr_s; /* header text color (selected) */ + COLORREF cr_hdr_gray; /* header text color (greyed) */ + COLORREF cr_hdr_gray_s; /* header text color (greyed,selected) */ + + COLORREF cr_hdr_outline;/* header outline color */ + + HCURSOR hc_hand; /* the HAND cursor */ + khui_ilist * ilist; /* image list */ + + HICON hi_lg_ident; /* large identity icon */ + + /* mouse state */ + khm_int32 mouse_state; /* state of the mouse can be combo of CW_MOUSE_* values */ + khm_int32 mouse_row; /* row that the mouse state applies to */ + khm_int32 mouse_col; /* col that the mouse state applies to */ + + khui_bitmap kbm_logo_shade; + + /* the credentials set */ + khm_handle credset; + + khui_credwnd_ident * idents; + khm_size n_idents; + khm_size nc_idents; + +} khui_credwnd_tbl; + +#define KHUI_MAXCB_HEADING 256 + +/* table flags */ +#define KHUI_CW_TBL_INITIALIZED 0x00000001 +#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 +#define KHUI_CW_TBL_EXPIDENT 0x00000800 +#define KHUI_CW_TBL_NOHEADER 0x00001000 + +/* mouse_state constants */ +#define CW_MOUSE_NONE 0x00000000 /* nothing interesting */ +#define CW_MOUSE_WIDGET 0x00000001 /* mouse is highlighting a + widget */ +#define CW_MOUSE_LDOWN 0x00000002 /* left button is down */ +#define CW_MOUSE_ROW 0x00000004 /* mouse is acive over a valid + row */ +#define CW_MOUSE_WOUTLINE 0x00000008 /* mouse is highlighting an + outline widget */ +#define CW_MOUSE_WSTICKY 0x00000010 /* mouse is highlighting a + sticky widget */ +#define CW_MOUSE_WICON 0x00000020 /* an icon widget. represents + the icon next to identities + and next to credentials. */ + +#define CW_MOUSE_WMASK 0x00000039 /* all widget bits */ + +void khm_unregister_credwnd_class(void); + +void khm_register_credwnd_class(void); + +HWND khm_create_credwnd(HWND parent); + +LRESULT CALLBACK khm_credwnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ); + +void cw_load_view(khui_credwnd_tbl * tbl, wchar_t * viewname, HWND hwnd); + +void cw_update_creds(khui_credwnd_tbl * tbl); + +void cw_unload_view(khui_credwnd_tbl * tbl); + +void cw_hditem_from_tbl_col(khui_credwnd_col * col, HDITEM *phi); + +int cw_update_extents(khui_credwnd_tbl * tbl, khm_boolean update_scroll); + +void cw_insert_header_cols(khui_credwnd_tbl * tbl); + +void khm_get_cw_element_font(HDC hdc, wchar_t * name, BOOL use_default, + LOGFONT * pfont); + +void khm_set_cw_element_font(wchar_t * name, LOGFONT * pfont); + +#endif diff --git a/src/windows/identity/ui/debugfuncs.c b/src/windows/identity/ui/debugfuncs.c index 7df6e9d65..3e30f117e 100644 --- a/src/windows/identity/ui/debugfuncs.c +++ b/src/windows/identity/ui/debugfuncs.c @@ -1,256 +1,256 @@ -/* - * 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 = NULL; -#if _MSC_VER >= 1400 - _wfopen_s(&logfile, temppath, L"w"); -#else - logfile = _wfopen(temppath, L"w"); -#endif - 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); -} +/* + * 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 = NULL; +#if _MSC_VER >= 1400 + _wfopen_s(&logfile, temppath, L"w"); +#else + logfile = _wfopen(temppath, L"w"); +#endif + 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 index 4c378a3a1..6467185f3 100644 --- a/src/windows/identity/ui/debugfuncs.h +++ b/src/windows/identity/ui/debugfuncs.h @@ -1,37 +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 +/* + * 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/htwnd.c b/src/windows/identity/ui/htwnd.c index b7c037866..a65ceceee 100644 --- a/src/windows/identity/ui/htwnd.c +++ b/src/windows/identity/ui/htwnd.c @@ -1,1286 +1,1286 @@ -/* -* 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 - -ATOM khui_htwnd_cls; - -#define HTW_STYLE_NORMAL 0 - -/* There are currently 4 style "bits" and 3 sizes, which means - there can be 2^4*3=48 possible styles max. If someone is - feeling adventurous you can slightly improve performance of - the parser using this little fact. For now, I don't care. - (hint: combine size and style bits to form a single number - and use it as an index into the styles array) -*/ -#define HTW_STYLE_MAX 48 - -#define HTW_FORMAT_MAX 128 - -#define HTW_TAB_MAX 8 - -#define HTW_DEFAULT (-1) - -#define HTW_NORMAL_SIZE 8 -#define HTW_LARGE_SIZE 12 -#define HTW_HUGE_SIZE 20 - -/* font variant */ -#define FV_ABSOLUTE 0x10000000 - -#define FV_ITALIC 0x00000002 -#define FV_UNDERLINE 0x00000004 -#define FV_STRIKEOUT 0x00000008 -#define FV_BOLD 0x00000010 - -#define FV_NOITALIC 0x00020000 -#define FV_NOUNDERLINE 0x00040000 -#define FV_NOSTRIKEOUT 0x00080000 -#define FV_NOBOLD 0x00100000 - -#define FV_NONE 0x00000000 -#define FV_MASK 0x0000001f - -#define HTW_LINK_ALLOC 8 - -#define ALIGN_LEFT 0 -#define ALIGN_CENTER 1 -#define ALIGN_RIGHT 2 - -struct tx_tbl_t { - wchar_t * string; - LONG value; -} - -htw_color_table[] = { - {L"black", RGB(0,0,0)}, - {L"white", RGB(255,255,255)}, - {L"red", RGB(255,0,0)}, - {L"green", RGB(0,255,0)}, - {L"blue", RGB(0,0,255)}, - {L"grey", RGB(128,128,128)} -}, - -htw_size_table[] = { - {L"normal", HTW_NORMAL_SIZE}, - {L"large", HTW_LARGE_SIZE}, - {L"huge", HTW_HUGE_SIZE} -}, - -htw_align_table[] = { - {L"left", ALIGN_LEFT}, - {L"center", ALIGN_CENTER}, - {L"right", ALIGN_RIGHT} -}; - -typedef struct khui_htwnd_style_t { - LONG height; - LONG variation; /* combination of FV_* */ - - HFONT font; -} khui_htwnd_style; - -typedef struct khui_format_t { - int style_idx; - COLORREF color; -} khui_format; - -typedef struct format_stack_t { - khui_format stack[HTW_FORMAT_MAX]; - int stack_top; -} format_stack; - -typedef struct khui_htwnd_data_t { - int id; /* control ID */ - int flags; - wchar_t * text; - int scroll_left; - int scroll_top; - int ext_width; - int ext_height; - COLORREF bk_color; - HCURSOR hc_hand; - int l_pixel_y; - - khui_htwnd_style styles[HTW_STYLE_MAX]; - int n_styles; - - khui_htwnd_link ** links; - int n_links; - int max_links; - int active_link; - int md_link; - - int tabs[HTW_TAB_MAX]; - int n_tabs; -} khui_htwnd_data; - -static LONG table_lookup(struct tx_tbl_t * tbl, int n, wchar_t * v, int len) -{ - int i; - - for(i=0; in_styles; i++) { - if(d->styles[i].font != NULL) { - DeleteObject(d->styles[i].font); - d->styles[i].font = NULL; - } - } - - d->n_styles = 0; -} - -static void format_init(format_stack * s) -{ - s->stack_top = -1; - ZeroMemory(s->stack, sizeof(s->stack)); -} - -static khui_format * format_current(format_stack * s) -{ - if(s->stack_top >= 0) - return &(s->stack[s->stack_top]); - else - return NULL; -} - -static int format_style(format_stack * s) -{ - if(s->stack_top >= 0) - return s->stack[s->stack_top].style_idx; - else - return 0; -} - -static COLORREF format_color(format_stack * s) -{ - if(s->stack_top >= 0) - return s->stack[s->stack_top].color; - else - return 0; -} - -static int format_level(format_stack * s) -{ - return s->stack_top; -} - -static void format_unwind(format_stack * s, int level) -{ - s->stack_top = level; -} - -static void format_push(format_stack * s, khui_htwnd_data * d, LONG height, LONG variation, COLORREF color) -{ - int i; - khui_format * top; - khui_htwnd_style * style; - - _ASSERT(s->stack_top < (HTW_FORMAT_MAX-1)); - - /* formatting is additive unless FV_NORMAL is set in variation */ - top = format_current(s); - if(top) { - style = &(d->styles[top->style_idx]); - if(height == HTW_DEFAULT) - height = style->height; - - if(variation == HTW_DEFAULT) - variation = style->variation; - else if(!(variation & FV_ABSOLUTE)) - variation |= style->variation; - - if(color == HTW_DEFAULT) - color = top->color; - } - - variation &= ~FV_ABSOLUTE; - variation ^= variation & (variation>>16); - variation &= FV_MASK; - - /* now look for an existing style that matches the requested one */ - for(i=0; in_styles; i++) { - style = &(d->styles[i]); - - if(style->height == height && - style->variation == variation) - break; - } - - s->stack_top++; - - if(in_styles) { - s->stack[s->stack_top].style_idx = i; - } else { - if(d->n_styles == HTW_STYLE_MAX) { - s->stack[s->stack_top].style_idx = 0; - } else { - s->stack[s->stack_top].style_idx = d->n_styles; - d->styles[d->n_styles].font = NULL; - d->styles[d->n_styles].height = height; - d->styles[d->n_styles].variation = variation; - d->n_styles++; - } - } - s->stack[s->stack_top].color = color; -} - -static void format_pop(format_stack * s) { - if(s->stack_top >= 0) - s->stack_top--; -} - -static wchar_t * token_end(wchar_t * s) { - while(iswalnum(*s) || *s == L'/') - s++; - return s; -} - -static wchar_t * skip_ws(wchar_t * s) { - while(iswspace(*s)) - s++; - return s; -} - -/* s points to something like " = \"value\"" - start and len will point to the start and - length of value. return value will point to the - character following the last double quote. */ -static wchar_t * read_attr(wchar_t * s, wchar_t ** start, int * len) -{ - wchar_t *e; - - *start = NULL; - *len = 0; - - do { - s = skip_ws(s); - if(*s != L'=') - break; - s = skip_ws(++s); - if(*s != L'"') - break; - e = wcschr(++s, L'"'); - if(!e) - break; - - *start = s; - *len = (int) (e - s); - - s = e + 1; - } while(FALSE); - - return s; -} - -/* -We currently support the following tags: - -link text -foo -foo -foo - -foo - (color)=black|white|red|green|blue|grey -foo -foo - -
foo
-foo -foo - -

foo

- - -*/ - -static int htw_parse_tag( - wchar_t * start, - wchar_t ** end, - int * align, - khui_htwnd_data * d, - format_stack * s, - PPOINT p_abs, - PPOINT p_rel, - int lh, - BOOL dry_run) -{ - wchar_t * c; - int n = 0; - - /* start initially points to the starting '<' */ - c = token_end(++start); - - if(!_wcsnicmp(start,L"a",c-start)) { - /* start of an 'a' tag */ - wchar_t * id_start = NULL; - int id_len = 0; - wchar_t * param_start = NULL; - int param_len = 0; - - /* We don't need to parse the link - if it is just a dry run */ - if(dry_run) { - format_push(s, d, HTW_DEFAULT, HTW_DEFAULT, RGB(0,0,255)); - *end = wcschr(start, L'>'); - return FALSE; - } - - while(c && *c && *c != L'>') { - wchar_t * e; - - c = skip_ws(c); - e = token_end(c); - - if(c==e) - break; - - if(!_wcsnicmp(c,L"id",e-c)) { - c = read_attr(e, &id_start, &id_len); - } else if(!_wcsnicmp(c,L"param",e-c)) { - c = read_attr(e, ¶m_start, ¶m_len); - } - } - - if(d->active_link == d->n_links) - format_push(s,d, HTW_DEFAULT, FV_UNDERLINE, RGB(0,0,255)); - else - format_push(s,d, HTW_DEFAULT, FV_NONE, RGB(0,0,255)); - - { - khui_htwnd_link * l; - - if(!d->links) { - d->links = PMALLOC(sizeof(khui_htwnd_link *) * HTW_LINK_ALLOC); - ZeroMemory(d->links, sizeof(khui_htwnd_link *) * HTW_LINK_ALLOC); - d->max_links = HTW_LINK_ALLOC; - d->n_links = 0; - } - - if(d->n_links >= d->max_links) { - khui_htwnd_link ** ll; - int n_new; - - n_new = UBOUNDSS(d->n_links + 1, HTW_LINK_ALLOC, HTW_LINK_ALLOC); - - ll = PMALLOC(sizeof(khui_htwnd_link *) * n_new); - ZeroMemory(ll, sizeof(khui_htwnd_link *) * n_new); - memcpy(ll, d->links, sizeof(khui_htwnd_link *) * d->max_links); - PFREE(d->links); - d->links = ll; - d->max_links = n_new; - } - - l = d->links[d->n_links]; - if(!l) { - l = PMALLOC(sizeof(khui_htwnd_link)); - d->links[d->n_links] = l; - } - - l->id = id_start; - l->id_len = id_len; - l->param = param_start; - l->param_len = param_len; - - l->r.left = p_abs->x; - l->r.top = p_abs->y; - - d->n_links++; - } - - } else if(!_wcsnicmp(start, L"/a", c - start)) { - khui_htwnd_link * l; - - c = wcschr(c,L'>'); - if(!c) - c = c + wcslen(c); - - format_pop(s); - - if(!dry_run) { - l = d->links[d->n_links - 1]; /* last link */ - l->r.right = p_abs->x; - l->r.bottom = p_abs->y + lh; - } - } else if(!_wcsnicmp(start, L"p", c - start)) { - wchar_t * e; - wchar_t * align_s = NULL; - int align_len = 0; - - c = skip_ws(c); - e = token_end(c); - - if(c != e && !_wcsnicmp(c,L"align",e-c)) { - c = read_attr(e, &align_s, &align_len); - } - - c = wcschr(c, L'>'); - if(!c) - c = c + wcslen(c); - - - if(align_s) - *align = table_lookup(htw_align_table, ARRAYLENGTH(htw_align_table), align_s, align_len); - else - *align = ALIGN_LEFT; - - n = 1; - } else if(!_wcsnicmp(start, L"b", c - start)) { - format_push(s,d, HTW_DEFAULT, FV_BOLD, HTW_DEFAULT); - } else if(!_wcsnicmp(start, L"/b", c - start)) { - format_pop(s); - } else if(!_wcsnicmp(start, L"u", c - start)) { - format_push(s,d, HTW_DEFAULT, FV_UNDERLINE, HTW_DEFAULT); - } else if(!_wcsnicmp(start, L"/u", c - start)) { - format_pop(s); - } else if(!_wcsnicmp(start, L"i", c - start)) { - format_push(s,d, HTW_DEFAULT, FV_ITALIC, HTW_DEFAULT); - } else if(!_wcsnicmp(start, L"/i", c - start)) { - format_pop(s); - } else if(!_wcsnicmp(start, L"large", c - start)) { - format_push(s,d,-MulDiv(HTW_LARGE_SIZE, d->l_pixel_y, 72), HTW_DEFAULT, HTW_DEFAULT); - } else if(!_wcsnicmp(start, L"/large", c - start)) { - format_pop(s); - } else if(!_wcsnicmp(start, L"huge", c - start)) { - format_push(s,d,-MulDiv(HTW_HUGE_SIZE, d->l_pixel_y, 72), HTW_DEFAULT, HTW_DEFAULT); - } else if(!_wcsnicmp(start, L"/huge", c - start)) { - format_pop(s); - } else if(!_wcsnicmp(start, L"center", c - start)) { - c = wcschr(c, L'>'); - if(!c) - c = c + wcslen(c); - *align = ALIGN_CENTER; - n = 1; - } else if(!_wcsnicmp(start, L"left", c - start) || - !_wcsnicmp(start, L"p", c - start)) - { - c = wcschr(c, L'>'); - if(!c) - c = c + wcslen(c); - *align = ALIGN_LEFT; - n = 1; - } else if(!_wcsnicmp(start, L"right", c - start)) { - c = wcschr(c, L'>'); - if(!c) - c = c + wcslen(c); - *align = ALIGN_RIGHT; - n = 1; - } else if(!_wcsnicmp(start, L"/center", c - start) || - !_wcsnicmp(start, L"/left", c - start) || - !_wcsnicmp(start, L"/right", c - start) || - !_wcsnicmp(start, L"/p", c - start)) { - c = wcschr(c, L'>'); - if(!c) - c = c + wcslen(c); - *align = ALIGN_LEFT; - n = 1; - } else if(!_wcsnicmp(start, L"font", c - start)) { - wchar_t * color_s = NULL; - int color_len = 0; - wchar_t * size_s = NULL; - int size_len = 0; - LONG color = HTW_DEFAULT; - LONG h = HTW_DEFAULT; - - while(c && *c && *c != L'>') { - wchar_t * e; - - c = skip_ws(c); - e = token_end(c); - - if(c==e) - break; - - if(!_wcsnicmp(c,L"color",e-c)) { - c = read_attr(e, &color_s, &color_len); - } else if(!_wcsnicmp(c,L"size",e-c)) { - c = read_attr(e, &size_s, &size_len); - } - } - - if(color_s) - color = table_lookup(htw_color_table, ARRAYLENGTH(htw_color_table), color_s, color_len); - if(size_s) { - h = table_lookup(htw_size_table, ARRAYLENGTH(htw_size_table), size_s, size_len); - if(h) - h = -MulDiv(h, d->l_pixel_y, 72); - else - h = -MulDiv(HTW_NORMAL_SIZE, d->l_pixel_y, 72); - } - - format_push(s,d,h,HTW_DEFAULT,color); - } else if(!_wcsnicmp(start, L"/font", c - start)) { - format_pop(s); - } else if(!_wcsnicmp(start, L"settab", c - start)) { - wchar_t * e; - wchar_t * pos_s = NULL; - int pos_len; - - c = skip_ws(c); - e = token_end(c); - - if(c != e && !_wcsnicmp(c,L"pos",e-c)) { - c = read_attr(e, &pos_s, &pos_len); - } - - c = wcschr(c, L'>'); - if(!c) - c = c + wcslen(c); - - if(pos_s && d->n_tabs < HTW_TAB_MAX && !dry_run) { - wchar_t * dummy; - LONG bu; - int bx; - int dx; - - bu = GetDialogBaseUnits(); - bx = LOWORD(bu); - - dx = wcstol(pos_s, &dummy, 10); - - d->tabs[d->n_tabs++] = MulDiv(dx, bx, 4); - } - } else if(!_wcsnicmp(start, L"tab", c - start)) { - int i; - - if(!dry_run) { - for(i=0; i < d->n_tabs; i++) { - if(d->tabs[i] > p_rel->x) { - p_rel->x = d->tabs[i]; - break; - } - } - } - } - - if(*c) - c++; - *end = c; - - return n; -} - -static void htw_assert_style(HDC hdc, khui_htwnd_data * d, int style) -{ - LOGFONT lf; - - if(d->styles[style].font) - return; - - /*TODO: we need select different fonts depending on system locale */ - lf.lfHeight = d->styles[style].height; //-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72); - lf.lfWidth = 0; - lf.lfEscapement = 0; - lf.lfOrientation = 0; - lf.lfWeight = (d->styles[style].variation & FV_BOLD)? FW_BOLD: FW_NORMAL; - lf.lfItalic = !!(d->styles[style].variation & FV_ITALIC); - lf.lfUnderline = !!(d->styles[style].variation & FV_UNDERLINE); - lf.lfStrikeOut = !!(d->styles[style].variation & FV_STRIKEOUT); - lf.lfCharSet = DEFAULT_CHARSET; - lf.lfOutPrecision = OUT_DEFAULT_PRECIS; - lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; - lf.lfQuality = DEFAULT_QUALITY; - lf.lfPitchAndFamily = DEFAULT_PITCH; - - LoadString(khm_hInstance, IDS_DEFAULT_FONT, lf.lfFaceName, ARRAYLENGTH(lf.lfFaceName)); - - d->styles[style].font = CreateFontIndirect(&lf); -} - -static LRESULT htw_paint(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - PAINTSTRUCT ps; - HBRUSH hbk; - khui_htwnd_data * d; - RECT r; - SIZE s; - HDC hdc; - wchar_t * text; - format_stack s_stack; - - int align; - int y; - wchar_t * par_start; - int ext_width = 0; - int ext_height = 0; - - d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - - if(!GetUpdateRect(hwnd, &r, !(d->flags & KHUI_HTWND_TRANSPARENT))) - return 0; - - if(d->text == NULL) - return 0; - - text = d->text; - - hdc = BeginPaint(hwnd, &ps); - - GetClientRect(hwnd, &r); - -#ifdef DRAW_HTWND_CLIENT_EDGE - /* for the moment, we are skipping on the client edge. */ - if(d->flags & KHUI_HTWND_CLIENTEDGE) - DrawEdge(hdc, &r, EDGE_SUNKEN, BF_ADJUST | BF_RECT | BF_FLAT); -#endif - - hbk = GetSysColorBrush(COLOR_WINDOW); - FillRect(hdc, &r, hbk); - hbk = NULL; /* We don't need to destroy system - brushes */ - - /* push the default format */ - format_init(&s_stack); - - d->l_pixel_y = GetDeviceCaps(hdc, LOGPIXELSY); - format_push(&s_stack,d, -MulDiv(HTW_NORMAL_SIZE, d->l_pixel_y, 72), FV_NONE, RGB(0,0,0)); - - y = r.top - d->scroll_top; - - par_start = text; - - align = ALIGN_LEFT; - - SetTextAlign(hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP); - if(d->flags & KHUI_HTWND_TRANSPARENT) - SetBkMode(hdc, TRANSPARENT); - - d->n_links = 0; - d->n_tabs = 0; - - while(*par_start) { - wchar_t * p = par_start; - wchar_t * c = NULL; - int p_width = 0; - int s_start; - int l_height = 0; - int x = 0; - POINT pt; - POINT pt_rel; - - s_start = format_level(&s_stack); - - /* begin dry run */ - while(*p) { - if(*p == L'<') { - int talign = -1; - int n = htw_parse_tag(p,&c,&talign,d,&s_stack,NULL,NULL,0,TRUE); - - if(n && p_width) - break; - - p = c; - - if(n && talign >= 0) - align = talign; - } else { - HFONT hfold; - c = wcschr(p, L'<'); - if(!c) - c = p + wcslen(p); - - htw_assert_style(hdc, d, format_style(&s_stack)); - hfold = SelectFont(hdc, d->styles[format_style(&s_stack)].font); - GetTextExtentPoint32(hdc, p, (int)(c - p), &s); - SelectFont(hdc, hfold); - - p_width += s.cx; - if(s.cy > l_height) - l_height = s.cy; - - p = c; - } - } - - /* dry run ends */ - - x = r.left - d->scroll_left; - - if(align == ALIGN_CENTER) { - if (r.right - r.left > p_width) - x += (r.right - r.left)/2 - p_width / 2; - } - - else if(align == ALIGN_RIGHT) { - if (r.right - r.left > p_width) - x += (r.right - r.left) - p_width; - } - - /* begin wet run */ - p = par_start; - format_unwind(&s_stack, s_start); /* unwind format stack */ - - p_width = 0; - - while(p && *p) { - if(*p == L'<') { - int talign = -1; - int n; - - pt.x = x + p_width; - pt.y = y; - pt_rel.x = p_width; - pt_rel.y = 0; - - n = htw_parse_tag(p, &c, &talign, d, &s_stack, &pt, &pt_rel, l_height, FALSE); - - if(n && p_width) { - break; - } - - p_width = pt_rel.x; - - p = c; - if(n && talign >= 0) - align = talign; - } else { - HFONT hfold; - RECT rd; - - c = wcschr(p, L'<'); - if(!c) - c = p + wcslen(p); - - htw_assert_style(hdc, d, format_style(&s_stack)); - hfold = SelectFont(hdc, d->styles[format_style(&s_stack)].font); - SetTextColor(hdc, format_color(&s_stack)); - - GetTextExtentPoint32(hdc, p, (int)(c - p), &s); - rd.left = x + p_width; - rd.top = y; - rd.right = rd.left + s.cx; - rd.bottom = rd.top + l_height; - - DrawText(hdc, p, (int)(c - p), &rd, - DT_BOTTOM | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX); - - p_width += s.cx; - - SelectFont(hdc, hfold); - p = c; - } - } - - if (p_width > ext_width) - ext_width = p_width; - - y += l_height; - par_start = p; - } - - if (y > ext_height) - ext_height = y; - - EndPaint(hwnd, &ps); - - if (d->ext_width < ext_width || - d->ext_height < ext_height) { - SCROLLINFO si; - LONG l; - - /* the extents need to be adjusted. But first check if we - have exactly the right scroll bars we need. */ - if ((ext_width > (r.right - r.left) && - !(d->flags & KHUI_HTWND_HSCROLL)) || - (ext_height > (r.bottom - r.top) && - !(d->flags & KHUI_HTWND_VSCROLL)) || - - (ext_width <= (r.right - r.left) && - (d->flags & KHUI_HTWND_HSCROLL)) || - (ext_height <= (r.bottom - r.top) && - (d->flags & KHUI_HTWND_VSCROLL))) { - - /* need to add scroll bars */ - if (ext_width > (r.right - r.left)) - d->flags |= KHUI_HTWND_HSCROLL; - else - d->flags &= ~KHUI_HTWND_HSCROLL; - - if (ext_height > (r.bottom - r.top)) - d->flags |= KHUI_HTWND_VSCROLL; - else - d->flags &= ~KHUI_HTWND_VSCROLL; - - l = GetWindowLongPtr(hwnd, GWL_STYLE); - l &= ~(WS_HSCROLL | WS_VSCROLL); - - l |= ((d->flags & KHUI_HTWND_HSCROLL) ? WS_HSCROLL : 0) | - ((d->flags & KHUI_HTWND_VSCROLL) ? WS_VSCROLL : 0); - - SetWindowLongPtr(hwnd, GWL_STYLE, l); - - InvalidateRect(hwnd, NULL, FALSE); - /* since the client area changed, we do another redraw - before updating the scroll bar positions. */ - } else { - d->ext_width = ext_width; - d->ext_height = ext_height; - - if (d->flags & KHUI_HTWND_HSCROLL) { - ZeroMemory(&si, sizeof(si)); - si.cbSize = sizeof(si); - si.fMask = SIF_ALL | SIF_DISABLENOSCROLL; - si.nMin = 0; - si.nMax = ext_width; - si.nPage = r.right - r.left; - si.nPos = d->scroll_left; - - SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); - } - - if (d->flags & KHUI_HTWND_VSCROLL) { - ZeroMemory(&si, sizeof(si)); - si.cbSize = sizeof(si); - si.fMask = SIF_ALL | SIF_DISABLENOSCROLL; - si.nMin = 0; - si.nMax = ext_height; - si.nPage = r.bottom - r.top; - si.nPos = d->scroll_top; - - SetScrollInfo(hwnd, SB_VERT, &si, TRUE); - } - } - } - - return 0; -} - -LRESULT CALLBACK khui_htwnd_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam - ) -{ - switch(uMsg) { - case WM_CREATE: - { - CREATESTRUCT * cs; - khui_htwnd_data * d; - size_t cbsize; - - cs = (CREATESTRUCT *) lParam; - - d = PMALLOC(sizeof(*d)); - ZeroMemory(d, sizeof(*d)); - - if(cs->dwExStyle & WS_EX_TRANSPARENT) { - d->flags |= KHUI_HTWND_TRANSPARENT; - } - if(cs->dwExStyle & WS_EX_CLIENTEDGE) { - d->flags |= KHUI_HTWND_CLIENTEDGE; - } - if(cs->style & WS_HSCROLL) { - d->flags |= KHUI_HTWND_HSCROLL; - } - if(cs->style & WS_VSCROLL) { - d->flags |= KHUI_HTWND_VSCROLL; - } - d->id = (int)(INT_PTR) cs->hMenu; - - d->active_link = -1; - d->bk_color = RGB(255,255,255); - d->hc_hand = LoadCursor(NULL, IDC_HAND); - - if(SUCCEEDED(StringCbLength(cs->lpszName, KHUI_HTWND_MAXCB_TEXT, &cbsize))) { - cbsize += sizeof(wchar_t); - d->text = PMALLOC(cbsize); - StringCbCopy(d->text, cbsize, cs->lpszName); - } - - /* this is just a flag to the WM_PAINT handler that the - extents haven't been set yet. */ - d->ext_width = -1; - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, 0, (LONG_PTR) d); -#pragma warning(pop) - - return 0; - } - break; - - case WM_SETTEXT: - { - wchar_t * newtext; - size_t cbsize; - khui_htwnd_data * d; - BOOL rv; - - d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - newtext = (wchar_t *) lParam; - - if(d->text) { - PFREE(d->text); - d->text = NULL; - } - - if(SUCCEEDED(StringCbLength(newtext, KHUI_HTWND_MAXCB_TEXT, &cbsize))) { - cbsize += sizeof(wchar_t); - d->text = PMALLOC(cbsize); - StringCbCopy(d->text, cbsize, newtext); - rv = TRUE; - } else - rv = FALSE; - - clear_styles(d); - - d->ext_width = -1; - d->scroll_left = 0; - d->scroll_top = 0; - - InvalidateRect(hwnd, NULL, TRUE); - - return rv; - } - break; - - case WM_DESTROY: - { - khui_htwnd_data * d; - int i; - - d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - if(d->text) - PFREE(d->text); - d->text = 0; - - if(d->links) { - for(i=0;imax_links;i++) { - if(d->links[i]) - PFREE(d->links[i]); - } - PFREE(d->links); - } - - clear_styles(d); - - PFREE(d); - } - break; - - case WM_ERASEBKGND: - { - HDC hdc = (HDC) wParam; - khui_htwnd_data * d; - HBRUSH hbr; - RECT r; - - d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - - GetClientRect(hwnd, &r); - hbr = GetSysColorBrush(COLOR_WINDOW); - FillRect(hdc, &r, hbr); - - /* no need to destroy the brush since it's a system - brush. */ - - return TRUE; - } - - case WM_SIZE: - { - khui_htwnd_data * d; - - d = (khui_htwnd_data *) (LONG_PTR) GetWindowLongPtr(hwnd, 0); - - if (d) { - d->ext_width = 0; - d->ext_height = 0; - } - } - return 0; - - case WM_PAINT: - htw_paint(hwnd, uMsg, wParam, lParam); - return 0; - - case WM_SETCURSOR: - { - khui_htwnd_data * d; - - if(hwnd != (HWND)wParam) - break; - - d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - - if(d->active_link >= 0) { - SetCursor(d->hc_hand); - return TRUE; - } - } - break; - - case WM_SETFOCUS: - { - khui_htwnd_data * d; - - d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - - d->flags |= KHUI_HTWND_FOCUS; - - InvalidateRect(hwnd, NULL, TRUE); - } - break; - - case WM_KILLFOCUS: - { - khui_htwnd_data * d; - - d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - - d->flags &= ~KHUI_HTWND_FOCUS; - - InvalidateRect(hwnd, NULL, TRUE); - } - break; - - case WM_LBUTTONDOWN: - { - khui_htwnd_data * d; - - d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - - d->md_link = d->active_link; - - SetCapture(hwnd); - } - break; - - case WM_LBUTTONUP: - { - khui_htwnd_data * d; - - d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - - if(d->md_link == d->active_link && d->md_link >= 0) { - /* clicked */ - SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(d->id, BN_CLICKED), (LPARAM) d->links[d->md_link]); - } - - ReleaseCapture(); - } - break; - - case WM_HSCROLL: - { - khui_htwnd_data * d; - int old_pos; - int new_pos; - int ext; - SCROLLINFO si; - RECT r; - - d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - - old_pos = new_pos = d->scroll_left; - ext = d->ext_width; - - switch(LOWORD(wParam)) { - case SB_THUMBPOSITION: - case SB_ENDSCROLL: - ZeroMemory(&si, sizeof(si)); - si.cbSize = sizeof(si); - si.fMask = SIF_POS; - GetScrollInfo(hwnd, SB_HORZ, &si); - new_pos = si.nPos; - break; - - case SB_THUMBTRACK: - ZeroMemory(&si, sizeof(si)); - si.cbSize = sizeof(si); - si.fMask = SIF_TRACKPOS; - GetScrollInfo(hwnd, SB_HORZ, &si); - new_pos = si.nTrackPos; - break; - - case SB_LINELEFT: - new_pos -= ext / 12; /* arbitrary unit */ - break; - - case SB_LINERIGHT: - new_pos += ext / 12; /* arbitrary unit */ - break; - - case SB_PAGELEFT: - GetClientRect(hwnd, &r); - new_pos -= r.right - r.left; - break; - - case SB_PAGERIGHT: - GetClientRect(hwnd, &r); - new_pos += r.right - r.left; - break; - } - - if (new_pos == old_pos) - break; - - GetClientRect(hwnd, &r); - - if (new_pos > ext - (r.right - r.left)) - new_pos = ext - (r.right - r.left); - - if (new_pos < 0) - new_pos = 0; - - if (new_pos == old_pos) - break; - - ZeroMemory(&si, sizeof(si)); - si.cbSize = sizeof(si); - si.fMask = SIF_POS; - si.nPos = new_pos; - SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); - /* note that Windows sometimes adjusts the position after - setting it with SetScrollInfo. We have to look it up - again to see what value it ended up at. */ - GetScrollInfo(hwnd, SB_HORZ, &si); - new_pos = si.nPos; - - if (new_pos == old_pos) - break; - - d->scroll_left = new_pos; - - ScrollWindow(hwnd, old_pos - new_pos, 0, NULL, NULL); - - return 0; - } - break; - - case WM_MOUSEMOVE: - { - khui_htwnd_data * d; - int i; - POINT p; - int nl; - - d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - p.x = GET_X_LPARAM(lParam) + d->scroll_left; - p.y = GET_Y_LPARAM(lParam) + d->scroll_top; - - for(i=0; in_links; i++) { - if(d->links && d->links[i] && PtInRect(&(d->links[i]->r), p)) - break; - } - - if(i == d->n_links) - nl = -1; - else - nl = i; - - if(d->active_link != nl) { - if(d->active_link >= 0) { - if(d->flags & KHUI_HTWND_TRANSPARENT) { - HWND parent = GetParent(hwnd); - if(parent) { - RECT rdest = d->links[d->active_link]->r; - - MapWindowPoints(hwnd, parent, (LPPOINT) &rdest, 2); - InvalidateRect(parent, &rdest, TRUE); - } - } - /* although we are invalidating the rect before setting active_link, - WM_PAINT will not be issued until wndproc returns */ - InvalidateRect(hwnd, &(d->links[d->active_link]->r), TRUE); - } - d->active_link = nl; - if(d->active_link >= 0) { - /* although we are invalidating the rect before setting active_link, - WM_PAINT will not be issued until wndproc returns */ - if(d->flags & KHUI_HTWND_TRANSPARENT) { - HWND parent = GetParent(hwnd); - if(parent) { - RECT rdest = d->links[d->active_link]->r; - - MapWindowPoints(hwnd, parent, (LPPOINT) &rdest, 2); - InvalidateRect(parent, &rdest, TRUE); - } - } - InvalidateRect(hwnd, &(d->links[d->active_link]->r), TRUE); - } - } - } - break; - } - - return DefWindowProc(hwnd, uMsg,wParam,lParam); -} - -void khm_register_htwnd_class(void) -{ - WNDCLASSEX wcx; - - wcx.cbSize = sizeof(wcx); - wcx.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; - wcx.lpfnWndProc = khui_htwnd_proc; - wcx.cbClsExtra = 0; - wcx.cbWndExtra = sizeof(LONG_PTR); - wcx.hInstance = khm_hInstance; - wcx.hIcon = NULL; - wcx.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); - wcx.hbrBackground = CreateSolidBrush(RGB(255,255,255)); - wcx.lpszMenuName = NULL; - wcx.lpszClassName = KHUI_HTWND_CLASS; - wcx.hIconSm = NULL; - - khui_htwnd_cls = RegisterClassEx(&wcx); -} - -void khm_unregister_htwnd_class(void) -{ - UnregisterClass(MAKEINTATOM(khui_htwnd_cls), khm_hInstance); -} - -HWND khm_create_htwnd(HWND parent, LPWSTR text, int x, int y, int width, int height, DWORD ex_style, DWORD style) -{ - - return CreateWindowEx( - ex_style, - MAKEINTATOM(khui_htwnd_cls), - text, - style | WS_CHILD, - x,y,width,height, - parent, - (HMENU) KHUI_HTWND_CTLID, - khm_hInstance, - NULL); -} +/* +* 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 + +ATOM khui_htwnd_cls; + +#define HTW_STYLE_NORMAL 0 + +/* There are currently 4 style "bits" and 3 sizes, which means + there can be 2^4*3=48 possible styles max. If someone is + feeling adventurous you can slightly improve performance of + the parser using this little fact. For now, I don't care. + (hint: combine size and style bits to form a single number + and use it as an index into the styles array) +*/ +#define HTW_STYLE_MAX 48 + +#define HTW_FORMAT_MAX 128 + +#define HTW_TAB_MAX 8 + +#define HTW_DEFAULT (-1) + +#define HTW_NORMAL_SIZE 8 +#define HTW_LARGE_SIZE 12 +#define HTW_HUGE_SIZE 20 + +/* font variant */ +#define FV_ABSOLUTE 0x10000000 + +#define FV_ITALIC 0x00000002 +#define FV_UNDERLINE 0x00000004 +#define FV_STRIKEOUT 0x00000008 +#define FV_BOLD 0x00000010 + +#define FV_NOITALIC 0x00020000 +#define FV_NOUNDERLINE 0x00040000 +#define FV_NOSTRIKEOUT 0x00080000 +#define FV_NOBOLD 0x00100000 + +#define FV_NONE 0x00000000 +#define FV_MASK 0x0000001f + +#define HTW_LINK_ALLOC 8 + +#define ALIGN_LEFT 0 +#define ALIGN_CENTER 1 +#define ALIGN_RIGHT 2 + +struct tx_tbl_t { + wchar_t * string; + LONG value; +} + +htw_color_table[] = { + {L"black", RGB(0,0,0)}, + {L"white", RGB(255,255,255)}, + {L"red", RGB(255,0,0)}, + {L"green", RGB(0,255,0)}, + {L"blue", RGB(0,0,255)}, + {L"grey", RGB(128,128,128)} +}, + +htw_size_table[] = { + {L"normal", HTW_NORMAL_SIZE}, + {L"large", HTW_LARGE_SIZE}, + {L"huge", HTW_HUGE_SIZE} +}, + +htw_align_table[] = { + {L"left", ALIGN_LEFT}, + {L"center", ALIGN_CENTER}, + {L"right", ALIGN_RIGHT} +}; + +typedef struct khui_htwnd_style_t { + LONG height; + LONG variation; /* combination of FV_* */ + + HFONT font; +} khui_htwnd_style; + +typedef struct khui_format_t { + int style_idx; + COLORREF color; +} khui_format; + +typedef struct format_stack_t { + khui_format stack[HTW_FORMAT_MAX]; + int stack_top; +} format_stack; + +typedef struct khui_htwnd_data_t { + int id; /* control ID */ + int flags; + wchar_t * text; + int scroll_left; + int scroll_top; + int ext_width; + int ext_height; + COLORREF bk_color; + HCURSOR hc_hand; + int l_pixel_y; + + khui_htwnd_style styles[HTW_STYLE_MAX]; + int n_styles; + + khui_htwnd_link ** links; + int n_links; + int max_links; + int active_link; + int md_link; + + int tabs[HTW_TAB_MAX]; + int n_tabs; +} khui_htwnd_data; + +static LONG table_lookup(struct tx_tbl_t * tbl, int n, wchar_t * v, int len) +{ + int i; + + for(i=0; in_styles; i++) { + if(d->styles[i].font != NULL) { + DeleteObject(d->styles[i].font); + d->styles[i].font = NULL; + } + } + + d->n_styles = 0; +} + +static void format_init(format_stack * s) +{ + s->stack_top = -1; + ZeroMemory(s->stack, sizeof(s->stack)); +} + +static khui_format * format_current(format_stack * s) +{ + if(s->stack_top >= 0) + return &(s->stack[s->stack_top]); + else + return NULL; +} + +static int format_style(format_stack * s) +{ + if(s->stack_top >= 0) + return s->stack[s->stack_top].style_idx; + else + return 0; +} + +static COLORREF format_color(format_stack * s) +{ + if(s->stack_top >= 0) + return s->stack[s->stack_top].color; + else + return 0; +} + +static int format_level(format_stack * s) +{ + return s->stack_top; +} + +static void format_unwind(format_stack * s, int level) +{ + s->stack_top = level; +} + +static void format_push(format_stack * s, khui_htwnd_data * d, LONG height, LONG variation, COLORREF color) +{ + int i; + khui_format * top; + khui_htwnd_style * style; + + _ASSERT(s->stack_top < (HTW_FORMAT_MAX-1)); + + /* formatting is additive unless FV_NORMAL is set in variation */ + top = format_current(s); + if(top) { + style = &(d->styles[top->style_idx]); + if(height == HTW_DEFAULT) + height = style->height; + + if(variation == HTW_DEFAULT) + variation = style->variation; + else if(!(variation & FV_ABSOLUTE)) + variation |= style->variation; + + if(color == HTW_DEFAULT) + color = top->color; + } + + variation &= ~FV_ABSOLUTE; + variation ^= variation & (variation>>16); + variation &= FV_MASK; + + /* now look for an existing style that matches the requested one */ + for(i=0; in_styles; i++) { + style = &(d->styles[i]); + + if(style->height == height && + style->variation == variation) + break; + } + + s->stack_top++; + + if(in_styles) { + s->stack[s->stack_top].style_idx = i; + } else { + if(d->n_styles == HTW_STYLE_MAX) { + s->stack[s->stack_top].style_idx = 0; + } else { + s->stack[s->stack_top].style_idx = d->n_styles; + d->styles[d->n_styles].font = NULL; + d->styles[d->n_styles].height = height; + d->styles[d->n_styles].variation = variation; + d->n_styles++; + } + } + s->stack[s->stack_top].color = color; +} + +static void format_pop(format_stack * s) { + if(s->stack_top >= 0) + s->stack_top--; +} + +static wchar_t * token_end(wchar_t * s) { + while(iswalnum(*s) || *s == L'/') + s++; + return s; +} + +static wchar_t * skip_ws(wchar_t * s) { + while(iswspace(*s)) + s++; + return s; +} + +/* s points to something like " = \"value\"" + start and len will point to the start and + length of value. return value will point to the + character following the last double quote. */ +static wchar_t * read_attr(wchar_t * s, wchar_t ** start, int * len) +{ + wchar_t *e; + + *start = NULL; + *len = 0; + + do { + s = skip_ws(s); + if(*s != L'=') + break; + s = skip_ws(++s); + if(*s != L'"') + break; + e = wcschr(++s, L'"'); + if(!e) + break; + + *start = s; + *len = (int) (e - s); + + s = e + 1; + } while(FALSE); + + return s; +} + +/* +We currently support the following tags: + +link text +foo +foo +foo + +foo + (color)=black|white|red|green|blue|grey +foo +foo + +
foo
+foo +foo + +

foo

+ + +*/ + +static int htw_parse_tag( + wchar_t * start, + wchar_t ** end, + int * align, + khui_htwnd_data * d, + format_stack * s, + PPOINT p_abs, + PPOINT p_rel, + int lh, + BOOL dry_run) +{ + wchar_t * c; + int n = 0; + + /* start initially points to the starting '<' */ + c = token_end(++start); + + if(!_wcsnicmp(start,L"a",c-start)) { + /* start of an 'a' tag */ + wchar_t * id_start = NULL; + int id_len = 0; + wchar_t * param_start = NULL; + int param_len = 0; + + /* We don't need to parse the link + if it is just a dry run */ + if(dry_run) { + format_push(s, d, HTW_DEFAULT, HTW_DEFAULT, RGB(0,0,255)); + *end = wcschr(start, L'>'); + return FALSE; + } + + while(c && *c && *c != L'>') { + wchar_t * e; + + c = skip_ws(c); + e = token_end(c); + + if(c==e) + break; + + if(!_wcsnicmp(c,L"id",e-c)) { + c = read_attr(e, &id_start, &id_len); + } else if(!_wcsnicmp(c,L"param",e-c)) { + c = read_attr(e, ¶m_start, ¶m_len); + } + } + + if(d->active_link == d->n_links) + format_push(s,d, HTW_DEFAULT, FV_UNDERLINE, RGB(0,0,255)); + else + format_push(s,d, HTW_DEFAULT, FV_NONE, RGB(0,0,255)); + + { + khui_htwnd_link * l; + + if(!d->links) { + d->links = PMALLOC(sizeof(khui_htwnd_link *) * HTW_LINK_ALLOC); + ZeroMemory(d->links, sizeof(khui_htwnd_link *) * HTW_LINK_ALLOC); + d->max_links = HTW_LINK_ALLOC; + d->n_links = 0; + } + + if(d->n_links >= d->max_links) { + khui_htwnd_link ** ll; + int n_new; + + n_new = UBOUNDSS(d->n_links + 1, HTW_LINK_ALLOC, HTW_LINK_ALLOC); + + ll = PMALLOC(sizeof(khui_htwnd_link *) * n_new); + ZeroMemory(ll, sizeof(khui_htwnd_link *) * n_new); + memcpy(ll, d->links, sizeof(khui_htwnd_link *) * d->max_links); + PFREE(d->links); + d->links = ll; + d->max_links = n_new; + } + + l = d->links[d->n_links]; + if(!l) { + l = PMALLOC(sizeof(khui_htwnd_link)); + d->links[d->n_links] = l; + } + + l->id = id_start; + l->id_len = id_len; + l->param = param_start; + l->param_len = param_len; + + l->r.left = p_abs->x; + l->r.top = p_abs->y; + + d->n_links++; + } + + } else if(!_wcsnicmp(start, L"/a", c - start)) { + khui_htwnd_link * l; + + c = wcschr(c,L'>'); + if(!c) + c = c + wcslen(c); + + format_pop(s); + + if(!dry_run) { + l = d->links[d->n_links - 1]; /* last link */ + l->r.right = p_abs->x; + l->r.bottom = p_abs->y + lh; + } + } else if(!_wcsnicmp(start, L"p", c - start)) { + wchar_t * e; + wchar_t * align_s = NULL; + int align_len = 0; + + c = skip_ws(c); + e = token_end(c); + + if(c != e && !_wcsnicmp(c,L"align",e-c)) { + c = read_attr(e, &align_s, &align_len); + } + + c = wcschr(c, L'>'); + if(!c) + c = c + wcslen(c); + + + if(align_s) + *align = table_lookup(htw_align_table, ARRAYLENGTH(htw_align_table), align_s, align_len); + else + *align = ALIGN_LEFT; + + n = 1; + } else if(!_wcsnicmp(start, L"b", c - start)) { + format_push(s,d, HTW_DEFAULT, FV_BOLD, HTW_DEFAULT); + } else if(!_wcsnicmp(start, L"/b", c - start)) { + format_pop(s); + } else if(!_wcsnicmp(start, L"u", c - start)) { + format_push(s,d, HTW_DEFAULT, FV_UNDERLINE, HTW_DEFAULT); + } else if(!_wcsnicmp(start, L"/u", c - start)) { + format_pop(s); + } else if(!_wcsnicmp(start, L"i", c - start)) { + format_push(s,d, HTW_DEFAULT, FV_ITALIC, HTW_DEFAULT); + } else if(!_wcsnicmp(start, L"/i", c - start)) { + format_pop(s); + } else if(!_wcsnicmp(start, L"large", c - start)) { + format_push(s,d,-MulDiv(HTW_LARGE_SIZE, d->l_pixel_y, 72), HTW_DEFAULT, HTW_DEFAULT); + } else if(!_wcsnicmp(start, L"/large", c - start)) { + format_pop(s); + } else if(!_wcsnicmp(start, L"huge", c - start)) { + format_push(s,d,-MulDiv(HTW_HUGE_SIZE, d->l_pixel_y, 72), HTW_DEFAULT, HTW_DEFAULT); + } else if(!_wcsnicmp(start, L"/huge", c - start)) { + format_pop(s); + } else if(!_wcsnicmp(start, L"center", c - start)) { + c = wcschr(c, L'>'); + if(!c) + c = c + wcslen(c); + *align = ALIGN_CENTER; + n = 1; + } else if(!_wcsnicmp(start, L"left", c - start) || + !_wcsnicmp(start, L"p", c - start)) + { + c = wcschr(c, L'>'); + if(!c) + c = c + wcslen(c); + *align = ALIGN_LEFT; + n = 1; + } else if(!_wcsnicmp(start, L"right", c - start)) { + c = wcschr(c, L'>'); + if(!c) + c = c + wcslen(c); + *align = ALIGN_RIGHT; + n = 1; + } else if(!_wcsnicmp(start, L"/center", c - start) || + !_wcsnicmp(start, L"/left", c - start) || + !_wcsnicmp(start, L"/right", c - start) || + !_wcsnicmp(start, L"/p", c - start)) { + c = wcschr(c, L'>'); + if(!c) + c = c + wcslen(c); + *align = ALIGN_LEFT; + n = 1; + } else if(!_wcsnicmp(start, L"font", c - start)) { + wchar_t * color_s = NULL; + int color_len = 0; + wchar_t * size_s = NULL; + int size_len = 0; + LONG color = HTW_DEFAULT; + LONG h = HTW_DEFAULT; + + while(c && *c && *c != L'>') { + wchar_t * e; + + c = skip_ws(c); + e = token_end(c); + + if(c==e) + break; + + if(!_wcsnicmp(c,L"color",e-c)) { + c = read_attr(e, &color_s, &color_len); + } else if(!_wcsnicmp(c,L"size",e-c)) { + c = read_attr(e, &size_s, &size_len); + } + } + + if(color_s) + color = table_lookup(htw_color_table, ARRAYLENGTH(htw_color_table), color_s, color_len); + if(size_s) { + h = table_lookup(htw_size_table, ARRAYLENGTH(htw_size_table), size_s, size_len); + if(h) + h = -MulDiv(h, d->l_pixel_y, 72); + else + h = -MulDiv(HTW_NORMAL_SIZE, d->l_pixel_y, 72); + } + + format_push(s,d,h,HTW_DEFAULT,color); + } else if(!_wcsnicmp(start, L"/font", c - start)) { + format_pop(s); + } else if(!_wcsnicmp(start, L"settab", c - start)) { + wchar_t * e; + wchar_t * pos_s = NULL; + int pos_len; + + c = skip_ws(c); + e = token_end(c); + + if(c != e && !_wcsnicmp(c,L"pos",e-c)) { + c = read_attr(e, &pos_s, &pos_len); + } + + c = wcschr(c, L'>'); + if(!c) + c = c + wcslen(c); + + if(pos_s && d->n_tabs < HTW_TAB_MAX && !dry_run) { + wchar_t * dummy; + LONG bu; + int bx; + int dx; + + bu = GetDialogBaseUnits(); + bx = LOWORD(bu); + + dx = wcstol(pos_s, &dummy, 10); + + d->tabs[d->n_tabs++] = MulDiv(dx, bx, 4); + } + } else if(!_wcsnicmp(start, L"tab", c - start)) { + int i; + + if(!dry_run) { + for(i=0; i < d->n_tabs; i++) { + if(d->tabs[i] > p_rel->x) { + p_rel->x = d->tabs[i]; + break; + } + } + } + } + + if(*c) + c++; + *end = c; + + return n; +} + +static void htw_assert_style(HDC hdc, khui_htwnd_data * d, int style) +{ + LOGFONT lf; + + if(d->styles[style].font) + return; + + /*TODO: we need select different fonts depending on system locale */ + lf.lfHeight = d->styles[style].height; //-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72); + lf.lfWidth = 0; + lf.lfEscapement = 0; + lf.lfOrientation = 0; + lf.lfWeight = (d->styles[style].variation & FV_BOLD)? FW_BOLD: FW_NORMAL; + lf.lfItalic = !!(d->styles[style].variation & FV_ITALIC); + lf.lfUnderline = !!(d->styles[style].variation & FV_UNDERLINE); + lf.lfStrikeOut = !!(d->styles[style].variation & FV_STRIKEOUT); + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfQuality = DEFAULT_QUALITY; + lf.lfPitchAndFamily = DEFAULT_PITCH; + + LoadString(khm_hInstance, IDS_DEFAULT_FONT, lf.lfFaceName, ARRAYLENGTH(lf.lfFaceName)); + + d->styles[style].font = CreateFontIndirect(&lf); +} + +static LRESULT htw_paint(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + PAINTSTRUCT ps; + HBRUSH hbk; + khui_htwnd_data * d; + RECT r; + SIZE s; + HDC hdc; + wchar_t * text; + format_stack s_stack; + + int align; + int y; + wchar_t * par_start; + int ext_width = 0; + int ext_height = 0; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + if(!GetUpdateRect(hwnd, &r, !(d->flags & KHUI_HTWND_TRANSPARENT))) + return 0; + + if(d->text == NULL) + return 0; + + text = d->text; + + hdc = BeginPaint(hwnd, &ps); + + GetClientRect(hwnd, &r); + +#ifdef DRAW_HTWND_CLIENT_EDGE + /* for the moment, we are skipping on the client edge. */ + if(d->flags & KHUI_HTWND_CLIENTEDGE) + DrawEdge(hdc, &r, EDGE_SUNKEN, BF_ADJUST | BF_RECT | BF_FLAT); +#endif + + hbk = GetSysColorBrush(COLOR_WINDOW); + FillRect(hdc, &r, hbk); + hbk = NULL; /* We don't need to destroy system + brushes */ + + /* push the default format */ + format_init(&s_stack); + + d->l_pixel_y = GetDeviceCaps(hdc, LOGPIXELSY); + format_push(&s_stack,d, -MulDiv(HTW_NORMAL_SIZE, d->l_pixel_y, 72), FV_NONE, RGB(0,0,0)); + + y = r.top - d->scroll_top; + + par_start = text; + + align = ALIGN_LEFT; + + SetTextAlign(hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP); + if(d->flags & KHUI_HTWND_TRANSPARENT) + SetBkMode(hdc, TRANSPARENT); + + d->n_links = 0; + d->n_tabs = 0; + + while(*par_start) { + wchar_t * p = par_start; + wchar_t * c = NULL; + int p_width = 0; + int s_start; + int l_height = 0; + int x = 0; + POINT pt; + POINT pt_rel; + + s_start = format_level(&s_stack); + + /* begin dry run */ + while(*p) { + if(*p == L'<') { + int talign = -1; + int n = htw_parse_tag(p,&c,&talign,d,&s_stack,NULL,NULL,0,TRUE); + + if(n && p_width) + break; + + p = c; + + if(n && talign >= 0) + align = talign; + } else { + HFONT hfold; + c = wcschr(p, L'<'); + if(!c) + c = p + wcslen(p); + + htw_assert_style(hdc, d, format_style(&s_stack)); + hfold = SelectFont(hdc, d->styles[format_style(&s_stack)].font); + GetTextExtentPoint32(hdc, p, (int)(c - p), &s); + SelectFont(hdc, hfold); + + p_width += s.cx; + if(s.cy > l_height) + l_height = s.cy; + + p = c; + } + } + + /* dry run ends */ + + x = r.left - d->scroll_left; + + if(align == ALIGN_CENTER) { + if (r.right - r.left > p_width) + x += (r.right - r.left)/2 - p_width / 2; + } + + else if(align == ALIGN_RIGHT) { + if (r.right - r.left > p_width) + x += (r.right - r.left) - p_width; + } + + /* begin wet run */ + p = par_start; + format_unwind(&s_stack, s_start); /* unwind format stack */ + + p_width = 0; + + while(p && *p) { + if(*p == L'<') { + int talign = -1; + int n; + + pt.x = x + p_width; + pt.y = y; + pt_rel.x = p_width; + pt_rel.y = 0; + + n = htw_parse_tag(p, &c, &talign, d, &s_stack, &pt, &pt_rel, l_height, FALSE); + + if(n && p_width) { + break; + } + + p_width = pt_rel.x; + + p = c; + if(n && talign >= 0) + align = talign; + } else { + HFONT hfold; + RECT rd; + + c = wcschr(p, L'<'); + if(!c) + c = p + wcslen(p); + + htw_assert_style(hdc, d, format_style(&s_stack)); + hfold = SelectFont(hdc, d->styles[format_style(&s_stack)].font); + SetTextColor(hdc, format_color(&s_stack)); + + GetTextExtentPoint32(hdc, p, (int)(c - p), &s); + rd.left = x + p_width; + rd.top = y; + rd.right = rd.left + s.cx; + rd.bottom = rd.top + l_height; + + DrawText(hdc, p, (int)(c - p), &rd, + DT_BOTTOM | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX); + + p_width += s.cx; + + SelectFont(hdc, hfold); + p = c; + } + } + + if (p_width > ext_width) + ext_width = p_width; + + y += l_height; + par_start = p; + } + + if (y > ext_height) + ext_height = y; + + EndPaint(hwnd, &ps); + + if (d->ext_width < ext_width || + d->ext_height < ext_height) { + SCROLLINFO si; + LONG l; + + /* the extents need to be adjusted. But first check if we + have exactly the right scroll bars we need. */ + if ((ext_width > (r.right - r.left) && + !(d->flags & KHUI_HTWND_HSCROLL)) || + (ext_height > (r.bottom - r.top) && + !(d->flags & KHUI_HTWND_VSCROLL)) || + + (ext_width <= (r.right - r.left) && + (d->flags & KHUI_HTWND_HSCROLL)) || + (ext_height <= (r.bottom - r.top) && + (d->flags & KHUI_HTWND_VSCROLL))) { + + /* need to add scroll bars */ + if (ext_width > (r.right - r.left)) + d->flags |= KHUI_HTWND_HSCROLL; + else + d->flags &= ~KHUI_HTWND_HSCROLL; + + if (ext_height > (r.bottom - r.top)) + d->flags |= KHUI_HTWND_VSCROLL; + else + d->flags &= ~KHUI_HTWND_VSCROLL; + + l = GetWindowLongPtr(hwnd, GWL_STYLE); + l &= ~(WS_HSCROLL | WS_VSCROLL); + + l |= ((d->flags & KHUI_HTWND_HSCROLL) ? WS_HSCROLL : 0) | + ((d->flags & KHUI_HTWND_VSCROLL) ? WS_VSCROLL : 0); + + SetWindowLongPtr(hwnd, GWL_STYLE, l); + + InvalidateRect(hwnd, NULL, FALSE); + /* since the client area changed, we do another redraw + before updating the scroll bar positions. */ + } else { + d->ext_width = ext_width; + d->ext_height = ext_height; + + if (d->flags & KHUI_HTWND_HSCROLL) { + ZeroMemory(&si, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_ALL | SIF_DISABLENOSCROLL; + si.nMin = 0; + si.nMax = ext_width; + si.nPage = r.right - r.left; + si.nPos = d->scroll_left; + + SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); + } + + if (d->flags & KHUI_HTWND_VSCROLL) { + ZeroMemory(&si, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_ALL | SIF_DISABLENOSCROLL; + si.nMin = 0; + si.nMax = ext_height; + si.nPage = r.bottom - r.top; + si.nPos = d->scroll_top; + + SetScrollInfo(hwnd, SB_VERT, &si, TRUE); + } + } + } + + return 0; +} + +LRESULT CALLBACK khui_htwnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ) +{ + switch(uMsg) { + case WM_CREATE: + { + CREATESTRUCT * cs; + khui_htwnd_data * d; + size_t cbsize; + + cs = (CREATESTRUCT *) lParam; + + d = PMALLOC(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + + if(cs->dwExStyle & WS_EX_TRANSPARENT) { + d->flags |= KHUI_HTWND_TRANSPARENT; + } + if(cs->dwExStyle & WS_EX_CLIENTEDGE) { + d->flags |= KHUI_HTWND_CLIENTEDGE; + } + if(cs->style & WS_HSCROLL) { + d->flags |= KHUI_HTWND_HSCROLL; + } + if(cs->style & WS_VSCROLL) { + d->flags |= KHUI_HTWND_VSCROLL; + } + d->id = (int)(INT_PTR) cs->hMenu; + + d->active_link = -1; + d->bk_color = RGB(255,255,255); + d->hc_hand = LoadCursor(NULL, IDC_HAND); + + if(SUCCEEDED(StringCbLength(cs->lpszName, KHUI_HTWND_MAXCB_TEXT, &cbsize))) { + cbsize += sizeof(wchar_t); + d->text = PMALLOC(cbsize); + StringCbCopy(d->text, cbsize, cs->lpszName); + } + + /* this is just a flag to the WM_PAINT handler that the + extents haven't been set yet. */ + d->ext_width = -1; + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, 0, (LONG_PTR) d); +#pragma warning(pop) + + return 0; + } + break; + + case WM_SETTEXT: + { + wchar_t * newtext; + size_t cbsize; + khui_htwnd_data * d; + BOOL rv; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + newtext = (wchar_t *) lParam; + + if(d->text) { + PFREE(d->text); + d->text = NULL; + } + + if(SUCCEEDED(StringCbLength(newtext, KHUI_HTWND_MAXCB_TEXT, &cbsize))) { + cbsize += sizeof(wchar_t); + d->text = PMALLOC(cbsize); + StringCbCopy(d->text, cbsize, newtext); + rv = TRUE; + } else + rv = FALSE; + + clear_styles(d); + + d->ext_width = -1; + d->scroll_left = 0; + d->scroll_top = 0; + + InvalidateRect(hwnd, NULL, TRUE); + + return rv; + } + break; + + case WM_DESTROY: + { + khui_htwnd_data * d; + int i; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + if(d->text) + PFREE(d->text); + d->text = 0; + + if(d->links) { + for(i=0;imax_links;i++) { + if(d->links[i]) + PFREE(d->links[i]); + } + PFREE(d->links); + } + + clear_styles(d); + + PFREE(d); + } + break; + + case WM_ERASEBKGND: + { + HDC hdc = (HDC) wParam; + khui_htwnd_data * d; + HBRUSH hbr; + RECT r; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + GetClientRect(hwnd, &r); + hbr = GetSysColorBrush(COLOR_WINDOW); + FillRect(hdc, &r, hbr); + + /* no need to destroy the brush since it's a system + brush. */ + + return TRUE; + } + + case WM_SIZE: + { + khui_htwnd_data * d; + + d = (khui_htwnd_data *) (LONG_PTR) GetWindowLongPtr(hwnd, 0); + + if (d) { + d->ext_width = 0; + d->ext_height = 0; + } + } + return 0; + + case WM_PAINT: + htw_paint(hwnd, uMsg, wParam, lParam); + return 0; + + case WM_SETCURSOR: + { + khui_htwnd_data * d; + + if(hwnd != (HWND)wParam) + break; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + if(d->active_link >= 0) { + SetCursor(d->hc_hand); + return TRUE; + } + } + break; + + case WM_SETFOCUS: + { + khui_htwnd_data * d; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + d->flags |= KHUI_HTWND_FOCUS; + + InvalidateRect(hwnd, NULL, TRUE); + } + break; + + case WM_KILLFOCUS: + { + khui_htwnd_data * d; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + d->flags &= ~KHUI_HTWND_FOCUS; + + InvalidateRect(hwnd, NULL, TRUE); + } + break; + + case WM_LBUTTONDOWN: + { + khui_htwnd_data * d; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + d->md_link = d->active_link; + + SetCapture(hwnd); + } + break; + + case WM_LBUTTONUP: + { + khui_htwnd_data * d; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + if(d->md_link == d->active_link && d->md_link >= 0) { + /* clicked */ + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(d->id, BN_CLICKED), (LPARAM) d->links[d->md_link]); + } + + ReleaseCapture(); + } + break; + + case WM_HSCROLL: + { + khui_htwnd_data * d; + int old_pos; + int new_pos; + int ext; + SCROLLINFO si; + RECT r; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + old_pos = new_pos = d->scroll_left; + ext = d->ext_width; + + switch(LOWORD(wParam)) { + case SB_THUMBPOSITION: + case SB_ENDSCROLL: + ZeroMemory(&si, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_POS; + GetScrollInfo(hwnd, SB_HORZ, &si); + new_pos = si.nPos; + break; + + case SB_THUMBTRACK: + ZeroMemory(&si, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_TRACKPOS; + GetScrollInfo(hwnd, SB_HORZ, &si); + new_pos = si.nTrackPos; + break; + + case SB_LINELEFT: + new_pos -= ext / 12; /* arbitrary unit */ + break; + + case SB_LINERIGHT: + new_pos += ext / 12; /* arbitrary unit */ + break; + + case SB_PAGELEFT: + GetClientRect(hwnd, &r); + new_pos -= r.right - r.left; + break; + + case SB_PAGERIGHT: + GetClientRect(hwnd, &r); + new_pos += r.right - r.left; + break; + } + + if (new_pos == old_pos) + break; + + GetClientRect(hwnd, &r); + + if (new_pos > ext - (r.right - r.left)) + new_pos = ext - (r.right - r.left); + + if (new_pos < 0) + new_pos = 0; + + if (new_pos == old_pos) + break; + + ZeroMemory(&si, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_POS; + si.nPos = new_pos; + SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); + /* note that Windows sometimes adjusts the position after + setting it with SetScrollInfo. We have to look it up + again to see what value it ended up at. */ + GetScrollInfo(hwnd, SB_HORZ, &si); + new_pos = si.nPos; + + if (new_pos == old_pos) + break; + + d->scroll_left = new_pos; + + ScrollWindow(hwnd, old_pos - new_pos, 0, NULL, NULL); + + return 0; + } + break; + + case WM_MOUSEMOVE: + { + khui_htwnd_data * d; + int i; + POINT p; + int nl; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + p.x = GET_X_LPARAM(lParam) + d->scroll_left; + p.y = GET_Y_LPARAM(lParam) + d->scroll_top; + + for(i=0; in_links; i++) { + if(d->links && d->links[i] && PtInRect(&(d->links[i]->r), p)) + break; + } + + if(i == d->n_links) + nl = -1; + else + nl = i; + + if(d->active_link != nl) { + if(d->active_link >= 0) { + if(d->flags & KHUI_HTWND_TRANSPARENT) { + HWND parent = GetParent(hwnd); + if(parent) { + RECT rdest = d->links[d->active_link]->r; + + MapWindowPoints(hwnd, parent, (LPPOINT) &rdest, 2); + InvalidateRect(parent, &rdest, TRUE); + } + } + /* although we are invalidating the rect before setting active_link, + WM_PAINT will not be issued until wndproc returns */ + InvalidateRect(hwnd, &(d->links[d->active_link]->r), TRUE); + } + d->active_link = nl; + if(d->active_link >= 0) { + /* although we are invalidating the rect before setting active_link, + WM_PAINT will not be issued until wndproc returns */ + if(d->flags & KHUI_HTWND_TRANSPARENT) { + HWND parent = GetParent(hwnd); + if(parent) { + RECT rdest = d->links[d->active_link]->r; + + MapWindowPoints(hwnd, parent, (LPPOINT) &rdest, 2); + InvalidateRect(parent, &rdest, TRUE); + } + } + InvalidateRect(hwnd, &(d->links[d->active_link]->r), TRUE); + } + } + } + break; + } + + return DefWindowProc(hwnd, uMsg,wParam,lParam); +} + +void khm_register_htwnd_class(void) +{ + WNDCLASSEX wcx; + + wcx.cbSize = sizeof(wcx); + wcx.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; + wcx.lpfnWndProc = khui_htwnd_proc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = sizeof(LONG_PTR); + wcx.hInstance = khm_hInstance; + wcx.hIcon = NULL; + wcx.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); + wcx.hbrBackground = CreateSolidBrush(RGB(255,255,255)); + wcx.lpszMenuName = NULL; + wcx.lpszClassName = KHUI_HTWND_CLASS; + wcx.hIconSm = NULL; + + khui_htwnd_cls = RegisterClassEx(&wcx); +} + +void khm_unregister_htwnd_class(void) +{ + UnregisterClass(MAKEINTATOM(khui_htwnd_cls), khm_hInstance); +} + +HWND khm_create_htwnd(HWND parent, LPWSTR text, int x, int y, int width, int height, DWORD ex_style, DWORD style) +{ + + return CreateWindowEx( + ex_style, + MAKEINTATOM(khui_htwnd_cls), + text, + style | WS_CHILD, + x,y,width,height, + parent, + (HMENU) KHUI_HTWND_CTLID, + khm_hInstance, + NULL); +} diff --git a/src/windows/identity/ui/htwnd.h b/src/windows/identity/ui/htwnd.h index 2ca8c261b..f842d2d39 100644 --- a/src/windows/identity/ui/htwnd.h +++ b/src/windows/identity/ui/htwnd.h @@ -1,57 +1,57 @@ -/* - * 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_HTWND_H -#define __KHIMAIRA_HTWND_H - -#include - -/* -We currently support the following tags: - -link text -
foo
-foo -foo -*/ - -#define KHUI_HTWND_TRANSPARENT 1 -#define KHUI_HTWND_CLIENTEDGE 2 -#define KHUI_HTWND_HSCROLL 4 -#define KHUI_HTWND_VSCROLL 8 -#define KHUI_HTWND_FOCUS 2048 - -#define KHUI_HTWND_CLASS L"KhmHtWnd" -#define KHUI_HTWND_CTLID 2040 - -#define KHUI_HTWND_MAXCCH_TEXT 2048 -#define KHUI_HTWND_MAXCB_TEXT (sizeof(wchar_t) * KHUI_HTWND_MAXCCH_TEXT) - -HWND khm_create_htwnd(HWND parent, LPWSTR text, int x, int y, int width, int height, DWORD ex_style, DWORD style); -void khm_unregister_htwnd_class(void); -void khm_register_htwnd_class(void); - -#endif +/* + * 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_HTWND_H +#define __KHIMAIRA_HTWND_H + +#include + +/* +We currently support the following tags: + +link text +
foo
+foo +foo +*/ + +#define KHUI_HTWND_TRANSPARENT 1 +#define KHUI_HTWND_CLIENTEDGE 2 +#define KHUI_HTWND_HSCROLL 4 +#define KHUI_HTWND_VSCROLL 8 +#define KHUI_HTWND_FOCUS 2048 + +#define KHUI_HTWND_CLASS L"KhmHtWnd" +#define KHUI_HTWND_CTLID 2040 + +#define KHUI_HTWND_MAXCCH_TEXT 2048 +#define KHUI_HTWND_MAXCB_TEXT (sizeof(wchar_t) * KHUI_HTWND_MAXCCH_TEXT) + +HWND khm_create_htwnd(HWND parent, LPWSTR text, int x, int y, int width, int height, DWORD ex_style, DWORD style); +void khm_unregister_htwnd_class(void); +void khm_register_htwnd_class(void); + +#endif diff --git a/src/windows/identity/ui/khmapp.h b/src/windows/identity/ui/khmapp.h index 54beb2a12..ba036c649 100644 --- a/src/windows/identity/ui/khmapp.h +++ b/src/windows/identity/ui/khmapp.h @@ -1,70 +1,70 @@ -/* - * 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_KHIMAIRA_H -#define __KHIMAIRA_KHIMAIRA_H - -#include -#include -#include -#include -#include - -#define KHERR_HMODULE khm_hInstance -#define KHERR_FACILITY khm_facility -#define KHERR_FACILITY_ID 3 - -#define NOEXPORT - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#endif +/* + * 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_KHIMAIRA_H +#define __KHIMAIRA_KHIMAIRA_H + +#include +#include +#include +#include +#include + +#define KHERR_HMODULE khm_hInstance +#define KHERR_FACILITY khm_facility +#define KHERR_FACILITY_ID 3 + +#define NOEXPORT + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#endif diff --git a/src/windows/identity/ui/main.c b/src/windows/identity/ui/main.c index 3e3a94f67..e094f0273 100644 --- a/src/windows/identity/ui/main.c +++ b/src/windows/identity/ui/main.c @@ -1,897 +1,897 @@ -/* - * 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 - -#if DEBUG -#include - -#if defined(KH_BUILD_PRIVATE) || defined(KH_BUILD_SPECIAL) -/* needed for writing out leaked allocation and handle report */ -#include -#endif - -#endif - -HINSTANCE khm_hInstance; -const wchar_t * khm_facility = L"NetIDMgr"; -int khm_nCmdShow; -khm_ui_4 khm_commctl_version = 0; - -khm_startup_options khm_startup; - -const khm_version app_version = {KH_VERSION_LIST}; - -HRESULT hr_coinitialize = S_OK; - -void khm_init_gui(void) { - - hr_coinitialize = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); - - khui_init_actions(); - khui_init_rescache(); - khui_init_menu(); - khui_init_toolbar(); - khm_init_notifier(); - khm_init_config(); - khm_init_debug(); - khm_init_taskbar_funcs(); -} - -void khm_exit_gui(void) { - khm_exit_taskbar_funcs(); - khm_exit_debug(); - khm_exit_config(); - khm_exit_notifier(); - khui_exit_toolbar(); - khui_exit_menu(); - khui_exit_rescache(); - khui_exit_actions(); - - if (hr_coinitialize == S_OK || - hr_coinitialize == S_FALSE) { - CoUninitialize(); - } -} - -void khm_parse_commandline(void) { - LPWSTR wcmdline; - LPWSTR * wargs; - int wargc; - int i; - - ZeroMemory(&khm_startup, sizeof(khm_startup)); - - wcmdline = GetCommandLine(); - wargs = CommandLineToArgvW(wcmdline, &wargc); - - for (i=1; i= 0x501) - ((IS_COMMCTL6())? - ICC_LINK_CLASS | - ICC_STANDARD_CLASSES : - 0) | -#endif - 0; - - InitCommonControlsEx(&ics); - - khm_register_main_wnd_class(); - khm_register_credwnd_class(); - khm_register_htwnd_class(); - khm_register_passwnd_class(); - khm_register_newcredwnd_class(); - khm_register_propertywnd_class(); -} - -void khm_unregister_window_classes(void) { - khm_unregister_main_wnd_class(); - khm_unregister_credwnd_class(); - khm_unregister_htwnd_class(); - khm_unregister_passwnd_class(); - khm_unregister_newcredwnd_class(); - khm_unregister_propertywnd_class(); -} - - -/* we support up to 16 simutaneous dialogs. In reality, more than two - is pretty unlikely. Property sheets are special and are handled - separately. */ -#define MAX_UI_DIALOGS 16 - -typedef struct tag_khui_dialog { - HWND hwnd; - HWND hwnd_next; - BOOL active; -} khui_dialog; - -static khui_dialog khui_dialogs[MAX_UI_DIALOGS]; -static int n_khui_dialogs = 0; -static HWND khui_modal_dialog = NULL; -static BOOL khui_main_window_active; - -/* should only be called from the UI thread */ -void khm_add_dialog(HWND dlg) { - if(n_khui_dialogs < MAX_UI_DIALOGS - 1) { - khui_dialogs[n_khui_dialogs].hwnd = dlg; - khui_dialogs[n_khui_dialogs].hwnd_next = NULL; - khui_dialogs[n_khui_dialogs].active = TRUE; - n_khui_dialogs++; - } else { -#if DEBUG - assert(FALSE); -#endif - } -} - -/* should only be called from the UI thread */ -void khm_enter_modal(HWND hwnd) { - int i; - - if (khui_modal_dialog) { - - /* we are already in a modal loop. */ - -#ifdef DEBUG - assert(hwnd != khui_modal_dialog); -#endif - - for (i=0; i < n_khui_dialogs; i++) { - if (khui_dialogs[i].hwnd == khui_modal_dialog) { - khui_dialogs[i].active = TRUE; - EnableWindow(khui_modal_dialog, FALSE); - break; - } - } - -#ifdef DEBUG - assert(i < n_khui_dialogs); -#endif - - for (i=0; i < n_khui_dialogs; i++) { - if (khui_dialogs[i].hwnd == hwnd) { - khui_dialogs[i].hwnd_next = khui_modal_dialog; - break; - } - } - -#ifdef DEBUG - assert(i < n_khui_dialogs); -#endif - - khui_modal_dialog = hwnd; - - } else { - - /* we are entering a modal loop. preserve the active state of - the overlapped dialogs and proceed with the modal - dialog. */ - - for (i=0; i < n_khui_dialogs; i++) { - if(khui_dialogs[i].hwnd != hwnd) { - khui_dialogs[i].active = IsWindowEnabled(khui_dialogs[i].hwnd); - EnableWindow(khui_dialogs[i].hwnd, FALSE); - } - } - - khui_main_window_active = khm_is_main_window_active(); - EnableWindow(khm_hwnd_main, FALSE); - - khui_modal_dialog = hwnd; - - SetForegroundWindow(hwnd); - } -} - -/* should only be called from the UI thread */ -void khm_leave_modal(void) { - int i; - - for (i=0; i < n_khui_dialogs; i++) { - if (khui_dialogs[i].hwnd == khui_modal_dialog) - break; - } - -#ifdef DEBUG - assert(i < n_khui_dialogs); -#endif - - if (i < n_khui_dialogs && khui_dialogs[i].hwnd_next) { - - /* we need to proceed to the next one down the modal dialog - chain. We are not exiting a modal loop. */ - - khui_modal_dialog = khui_dialogs[i].hwnd_next; - khui_dialogs[i].hwnd_next = FALSE; - - EnableWindow(khui_modal_dialog, TRUE); - - } else { - - HWND last_dialog = NULL; - - /* we are exiting a modal loop. */ - - for (i=0; i < n_khui_dialogs; i++) { - if(khui_dialogs[i].hwnd != khui_modal_dialog) { - EnableWindow(khui_dialogs[i].hwnd, khui_dialogs[i].active); - last_dialog = khui_dialogs[i].hwnd; - } - } - - EnableWindow(khm_hwnd_main, TRUE); - - khui_modal_dialog = NULL; - - if(last_dialog) - SetActiveWindow(last_dialog); - else - SetActiveWindow(khm_hwnd_main); - } -} - -/* should only be called from the UI thread */ -void khm_del_dialog(HWND dlg) { - int i; - for(i=0;i < n_khui_dialogs; i++) { - if(khui_dialogs[i].hwnd == dlg) - break; - } - - if(i < n_khui_dialogs) - n_khui_dialogs--; - else - return; - - for(;i < n_khui_dialogs; i++) { - khui_dialogs[i] = khui_dialogs[i+1]; - } -} - -BOOL khm_check_dlg_message(LPMSG pmsg) { - int i; - BOOL found = FALSE; - for(i=0;istatus == KHUI_PS_STATUS_DONE) { - ps = _ui_propsheets[i]; - - ps->status = KHUI_PS_STATUS_DESTROY; - kmq_post_message(KMSG_CRED, KMSG_CRED_PP_END, 0, (void *) ps); - - return TRUE; - } - return TRUE; - } - } - - return FALSE; -} - -static HACCEL ha_menu; - -WPARAM khm_message_loop_int(khm_boolean * p_exit) { - int r; - MSG msg; - - 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)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - 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_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); - - /* 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); - - khui_alert_set_severity(a, e->severity); - khui_alert_set_title(a, e->short_desc); - khui_alert_set_message(a, e->long_desc); - if (e->suggestion) - khui_alert_set_suggestion(a, e->suggestion); - - khui_alert_queue(a); - - khui_alert_release(a); - } - } -} - -static wchar_t helpfile[MAX_PATH] = L""; - -HWND khm_html_help(HWND hwnd, wchar_t * suffix, - UINT command, DWORD_PTR data) { - - wchar_t gpath[MAX_PATH + MAX_PATH]; - - if (!*helpfile) { - DWORD dw; - wchar_t ppath[MAX_PATH]; - - dw = GetModuleFileName(NULL, ppath, ARRAYLENGTH(ppath)); - - if (dw == 0) { - StringCbCopy(helpfile, sizeof(helpfile), NIDM_HELPFILE); - } else { - PathRemoveFileSpec(ppath); - PathAppend(ppath, NIDM_HELPFILE); - StringCbCopy(helpfile, sizeof(helpfile), ppath); - } - } - - StringCbCopy(gpath, sizeof(gpath), helpfile); - - if (suffix) - StringCbCat(gpath, sizeof(gpath), suffix); - - return HtmlHelp(hwnd, gpath, command, data); -} - -void khm_load_default_modules(void) { - kmm_load_default_modules(); -} - -int khm_compare_version(const khm_version * v1, const khm_version * v2) { - - if (v1->major != v2->major) - return ((int)v1->major) - ((int)v2->major); - - if (v1->minor != v2->minor) - return ((int)v1->minor) - ((int)v2->minor); - - if (v1->patch != v2->patch) - return ((int)v1->patch) - ((int)v2->patch); - - return ((int)v1->aux - ((int)v2->aux)); -} - -int WINAPI WinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow) -{ - int rv = 0; - HANDLE h_appmutex; - BOOL slave = FALSE; - int mutex_retries = 5; - - khm_hInstance = hInstance; - khm_nCmdShow = nCmdShow; - - khm_parse_commandline(); - - if (khm_startup.error_exit) - return 0; - - _retry_mutex: - - if (--mutex_retries < 0) - return 2; - - h_appmutex = CreateMutex(NULL, FALSE, L"Local\\NetIDMgr_GlobalAppMutex"); - if (h_appmutex == NULL) - return 5; - if (GetLastError() == ERROR_ALREADY_EXISTS) - slave = TRUE; - - khc_load_schema(NULL, schema_uiconfig); - - _start_app: - - if(!slave) { - - PDESCTHREAD(L"UI", L"App"); - - /* set this so that we don't accidently invoke an API that - inadvertently puts up the new creds dialog at an - inopportune moment, like, say, during the new creds dialog - is open. This only affects this process, and any child - processes started by plugins. */ - SetEnvironmentVariable(L"KERBEROSLOGIN_NEVER_PROMPT", L"1"); - - khm_version_init(); - - khm_commctl_version = khm_get_commctl_version(NULL); - - /* we only open a main window if this is the only instance - of the application that is running. */ - kmq_init(); - khm_init_gui(); - kmm_init(); - - 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(); - - khm_register_window_classes(); - - khm_init_request_daemon(); - - khm_create_main_window(); - - 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); - - khm_exit_request_daemon(); - - kmm_exit(); - khm_exit_gui(); - khm_unregister_window_classes(); - kmq_exit(); - - CloseHandle(h_appmutex); - } else { - HWND hwnd = NULL; - int retries = 5; - HANDLE hmap; - wchar_t mapname[256]; - DWORD tid; - void * xfer; - khm_query_app_version query_app_version; - khm_version v; - BOOL use_cmd_v2 = TRUE; - khm_size cb = 0; - - CloseHandle(h_appmutex); - - while (hwnd == NULL && retries) { - hwnd = FindWindowEx(NULL, NULL, KHUI_MAIN_WINDOW_CLASS, NULL); - - if (hwnd) - break; - - retries--; - - /* if the app was just starting, we might have to wait - till the main window is created. */ - - Sleep(1000); - } - - if (!hwnd) { - - /* if the app was just exiting, we might see the mutex but - not the window. We go back and check if the mutex is - still there. */ - - goto _retry_mutex; - } - - /* 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)); - - ZeroMemory(&query_app_version, sizeof(query_app_version)); - - if (xfer) { - 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.magic != KHM_QUERY_APP_VER_MAGIC || - query_app_version.code != KHM_ERROR_SUCCESS) { - - /* We managed to communicate with the remote instance, but - it didn't send us useful information. The remote - instance is not running an actual NetIDMgr instance. - However, it owns a top level window that was registered - with our classname. This instance won't function - properly if we let it proceed. - */ - - wchar_t error_msg[1024]; - wchar_t error_title[256]; - - LoadString(khm_hInstance, IDS_REMOTE_FAIL_TITLE, - error_title, ARRAYLENGTH(error_title)); - LoadString(khm_hInstance, IDS_REMOTE_FAIL, - error_msg, ARRAYLENGTH(error_msg)); - - MessageBox(NULL, error_msg, error_title, - MB_OK); - - goto done_with_remote; - } - - 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; - } - - /* Now we can work on sending the command-line to the remote - instance. However we need to figure out which version of - the startup structure it supports. */ - v.major = 1; - v.minor = 2; - v.patch = 0; - v.aux = 0; - - if (khm_compare_version(&query_app_version.ver_remote, &app_version) == 0 || - khm_compare_version(&query_app_version.ver_remote, &v) > 0) - use_cmd_v2 = TRUE; - else - use_cmd_v2 = FALSE; - - StringCbPrintf(mapname, sizeof(mapname), - COMMANDLINE_MAP_FMT, - (tid = GetCurrentThreadId())); - - cb = max(sizeof(struct tag_khm_startup_options_v1), - sizeof(struct tag_khm_startup_options_v2)); - - cb = UBOUNDSS(cb, 4096, 4096); - -#ifdef DEBUG - assert(cb >= 4096); -#endif - - hmap = CreateFileMapping(INVALID_HANDLE_VALUE, - NULL, - PAGE_READWRITE, - 0, - (DWORD) cb, - mapname); - - if (hmap == NULL) - return 3; - - /* make the call */ - - if (use_cmd_v2) { - /* use the v2 structure */ - struct tag_khm_startup_options_v2 v2opt; - - ZeroMemory(&v2opt, sizeof(v2opt)); - - v2opt.magic = STARTUP_OPTIONS_MAGIC; - v2opt.cb_size = sizeof(v2opt); - - v2opt.init = khm_startup.init; - v2opt.import = khm_startup.import; - v2opt.renew = khm_startup.renew; - v2opt.destroy = khm_startup.destroy; - - v2opt.autoinit = khm_startup.autoinit; - v2opt.remote_exit = khm_startup.remote_exit; - - v2opt.code = KHM_ERROR_NOT_IMPLEMENTED; - - xfer = MapViewOfFile(hmap, - FILE_MAP_WRITE, - 0, 0, - sizeof(v2opt)); - - if (xfer) { - memcpy(xfer, &v2opt, sizeof(v2opt)); - - SendMessage(hwnd, WM_KHUI_ASSIGN_COMMANDLINE_V2, - 0, (LPARAM) tid); - - memcpy(&v2opt, xfer, sizeof(v2opt)); - - /* If the request looks like it wasn't processed, we - fallback to the v1 request. */ - - if (v2opt.code == KHM_ERROR_NOT_IMPLEMENTED) - use_cmd_v2 = FALSE; - - UnmapViewOfFile(xfer); - xfer = NULL; - } - } - - if (!use_cmd_v2) { - /* use the v1 structure */ - - struct tag_khm_startup_options_v1 v1opt; - - ZeroMemory(&v1opt, sizeof(v1opt)); - - v1opt.init = khm_startup.init; - v1opt.import = khm_startup.import; - v1opt.renew = khm_startup.renew; - v1opt.destroy = khm_startup.destroy; - v1opt.autoinit = khm_startup.autoinit; - - xfer = MapViewOfFile(hmap, - FILE_MAP_WRITE, - 0, 0, - sizeof(v1opt)); - - if (xfer) { - memcpy(xfer, &v1opt, sizeof(v1opt)); - - SendMessage(hwnd, WM_KHUI_ASSIGN_COMMANDLINE_V1, - 0, (LPARAM) tid); - - UnmapViewOfFile(xfer); - xfer = NULL; - } - } - - done_with_remote: - - if (hmap) - CloseHandle(hmap); - } - -#if defined(DEBUG) && (defined(KH_BUILD_PRIVATE) || defined(KH_BUILD_SPECIAL)) - { - FILE * f = NULL; - - KHMEXP void KHMAPI khcint_dump_handles(FILE * f); - KHMEXP void KHMAPI perf_dump(FILE * f); - KHMEXP void KHMAPI kmqint_dump(FILE * f); - -#if _MSC_VER >= 1400 - if (fopen_s(&f, "memleak.txt", "w") != 0) - goto done_with_dump; -#else - f = fopen("memleak.txt", "w"); - if (f == NULL) - goto done_with_dump; -#endif - - perf_dump(f); - khcint_dump_handles(f); - kmqint_dump(f); - - fclose(f); - - done_with_dump: - ; - } -#endif - - return rv; -} +/* + * 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 + +#if DEBUG +#include + +#if defined(KH_BUILD_PRIVATE) || defined(KH_BUILD_SPECIAL) +/* needed for writing out leaked allocation and handle report */ +#include +#endif + +#endif + +HINSTANCE khm_hInstance; +const wchar_t * khm_facility = L"NetIDMgr"; +int khm_nCmdShow; +khm_ui_4 khm_commctl_version = 0; + +khm_startup_options khm_startup; + +const khm_version app_version = {KH_VERSION_LIST}; + +HRESULT hr_coinitialize = S_OK; + +void khm_init_gui(void) { + + hr_coinitialize = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + khui_init_actions(); + khui_init_rescache(); + khui_init_menu(); + khui_init_toolbar(); + khm_init_notifier(); + khm_init_config(); + khm_init_debug(); + khm_init_taskbar_funcs(); +} + +void khm_exit_gui(void) { + khm_exit_taskbar_funcs(); + khm_exit_debug(); + khm_exit_config(); + khm_exit_notifier(); + khui_exit_toolbar(); + khui_exit_menu(); + khui_exit_rescache(); + khui_exit_actions(); + + if (hr_coinitialize == S_OK || + hr_coinitialize == S_FALSE) { + CoUninitialize(); + } +} + +void khm_parse_commandline(void) { + LPWSTR wcmdline; + LPWSTR * wargs; + int wargc; + int i; + + ZeroMemory(&khm_startup, sizeof(khm_startup)); + + wcmdline = GetCommandLine(); + wargs = CommandLineToArgvW(wcmdline, &wargc); + + for (i=1; i= 0x501) + ((IS_COMMCTL6())? + ICC_LINK_CLASS | + ICC_STANDARD_CLASSES : + 0) | +#endif + 0; + + InitCommonControlsEx(&ics); + + khm_register_main_wnd_class(); + khm_register_credwnd_class(); + khm_register_htwnd_class(); + khm_register_passwnd_class(); + khm_register_newcredwnd_class(); + khm_register_propertywnd_class(); +} + +void khm_unregister_window_classes(void) { + khm_unregister_main_wnd_class(); + khm_unregister_credwnd_class(); + khm_unregister_htwnd_class(); + khm_unregister_passwnd_class(); + khm_unregister_newcredwnd_class(); + khm_unregister_propertywnd_class(); +} + + +/* we support up to 16 simutaneous dialogs. In reality, more than two + is pretty unlikely. Property sheets are special and are handled + separately. */ +#define MAX_UI_DIALOGS 16 + +typedef struct tag_khui_dialog { + HWND hwnd; + HWND hwnd_next; + BOOL active; +} khui_dialog; + +static khui_dialog khui_dialogs[MAX_UI_DIALOGS]; +static int n_khui_dialogs = 0; +static HWND khui_modal_dialog = NULL; +static BOOL khui_main_window_active; + +/* should only be called from the UI thread */ +void khm_add_dialog(HWND dlg) { + if(n_khui_dialogs < MAX_UI_DIALOGS - 1) { + khui_dialogs[n_khui_dialogs].hwnd = dlg; + khui_dialogs[n_khui_dialogs].hwnd_next = NULL; + khui_dialogs[n_khui_dialogs].active = TRUE; + n_khui_dialogs++; + } else { +#if DEBUG + assert(FALSE); +#endif + } +} + +/* should only be called from the UI thread */ +void khm_enter_modal(HWND hwnd) { + int i; + + if (khui_modal_dialog) { + + /* we are already in a modal loop. */ + +#ifdef DEBUG + assert(hwnd != khui_modal_dialog); +#endif + + for (i=0; i < n_khui_dialogs; i++) { + if (khui_dialogs[i].hwnd == khui_modal_dialog) { + khui_dialogs[i].active = TRUE; + EnableWindow(khui_modal_dialog, FALSE); + break; + } + } + +#ifdef DEBUG + assert(i < n_khui_dialogs); +#endif + + for (i=0; i < n_khui_dialogs; i++) { + if (khui_dialogs[i].hwnd == hwnd) { + khui_dialogs[i].hwnd_next = khui_modal_dialog; + break; + } + } + +#ifdef DEBUG + assert(i < n_khui_dialogs); +#endif + + khui_modal_dialog = hwnd; + + } else { + + /* we are entering a modal loop. preserve the active state of + the overlapped dialogs and proceed with the modal + dialog. */ + + for (i=0; i < n_khui_dialogs; i++) { + if(khui_dialogs[i].hwnd != hwnd) { + khui_dialogs[i].active = IsWindowEnabled(khui_dialogs[i].hwnd); + EnableWindow(khui_dialogs[i].hwnd, FALSE); + } + } + + khui_main_window_active = khm_is_main_window_active(); + EnableWindow(khm_hwnd_main, FALSE); + + khui_modal_dialog = hwnd; + + SetForegroundWindow(hwnd); + } +} + +/* should only be called from the UI thread */ +void khm_leave_modal(void) { + int i; + + for (i=0; i < n_khui_dialogs; i++) { + if (khui_dialogs[i].hwnd == khui_modal_dialog) + break; + } + +#ifdef DEBUG + assert(i < n_khui_dialogs); +#endif + + if (i < n_khui_dialogs && khui_dialogs[i].hwnd_next) { + + /* we need to proceed to the next one down the modal dialog + chain. We are not exiting a modal loop. */ + + khui_modal_dialog = khui_dialogs[i].hwnd_next; + khui_dialogs[i].hwnd_next = FALSE; + + EnableWindow(khui_modal_dialog, TRUE); + + } else { + + HWND last_dialog = NULL; + + /* we are exiting a modal loop. */ + + for (i=0; i < n_khui_dialogs; i++) { + if(khui_dialogs[i].hwnd != khui_modal_dialog) { + EnableWindow(khui_dialogs[i].hwnd, khui_dialogs[i].active); + last_dialog = khui_dialogs[i].hwnd; + } + } + + EnableWindow(khm_hwnd_main, TRUE); + + khui_modal_dialog = NULL; + + if(last_dialog) + SetActiveWindow(last_dialog); + else + SetActiveWindow(khm_hwnd_main); + } +} + +/* should only be called from the UI thread */ +void khm_del_dialog(HWND dlg) { + int i; + for(i=0;i < n_khui_dialogs; i++) { + if(khui_dialogs[i].hwnd == dlg) + break; + } + + if(i < n_khui_dialogs) + n_khui_dialogs--; + else + return; + + for(;i < n_khui_dialogs; i++) { + khui_dialogs[i] = khui_dialogs[i+1]; + } +} + +BOOL khm_check_dlg_message(LPMSG pmsg) { + int i; + BOOL found = FALSE; + for(i=0;istatus == KHUI_PS_STATUS_DONE) { + ps = _ui_propsheets[i]; + + ps->status = KHUI_PS_STATUS_DESTROY; + kmq_post_message(KMSG_CRED, KMSG_CRED_PP_END, 0, (void *) ps); + + return TRUE; + } + return TRUE; + } + } + + return FALSE; +} + +static HACCEL ha_menu; + +WPARAM khm_message_loop_int(khm_boolean * p_exit) { + int r; + MSG msg; + + 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)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + 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_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); + + /* 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); + + khui_alert_set_severity(a, e->severity); + khui_alert_set_title(a, e->short_desc); + khui_alert_set_message(a, e->long_desc); + if (e->suggestion) + khui_alert_set_suggestion(a, e->suggestion); + + khui_alert_queue(a); + + khui_alert_release(a); + } + } +} + +static wchar_t helpfile[MAX_PATH] = L""; + +HWND khm_html_help(HWND hwnd, wchar_t * suffix, + UINT command, DWORD_PTR data) { + + wchar_t gpath[MAX_PATH + MAX_PATH]; + + if (!*helpfile) { + DWORD dw; + wchar_t ppath[MAX_PATH]; + + dw = GetModuleFileName(NULL, ppath, ARRAYLENGTH(ppath)); + + if (dw == 0) { + StringCbCopy(helpfile, sizeof(helpfile), NIDM_HELPFILE); + } else { + PathRemoveFileSpec(ppath); + PathAppend(ppath, NIDM_HELPFILE); + StringCbCopy(helpfile, sizeof(helpfile), ppath); + } + } + + StringCbCopy(gpath, sizeof(gpath), helpfile); + + if (suffix) + StringCbCat(gpath, sizeof(gpath), suffix); + + return HtmlHelp(hwnd, gpath, command, data); +} + +void khm_load_default_modules(void) { + kmm_load_default_modules(); +} + +int khm_compare_version(const khm_version * v1, const khm_version * v2) { + + if (v1->major != v2->major) + return ((int)v1->major) - ((int)v2->major); + + if (v1->minor != v2->minor) + return ((int)v1->minor) - ((int)v2->minor); + + if (v1->patch != v2->patch) + return ((int)v1->patch) - ((int)v2->patch); + + return ((int)v1->aux - ((int)v2->aux)); +} + +int WINAPI WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + int rv = 0; + HANDLE h_appmutex; + BOOL slave = FALSE; + int mutex_retries = 5; + + khm_hInstance = hInstance; + khm_nCmdShow = nCmdShow; + + khm_parse_commandline(); + + if (khm_startup.error_exit) + return 0; + + _retry_mutex: + + if (--mutex_retries < 0) + return 2; + + h_appmutex = CreateMutex(NULL, FALSE, L"Local\\NetIDMgr_GlobalAppMutex"); + if (h_appmutex == NULL) + return 5; + if (GetLastError() == ERROR_ALREADY_EXISTS) + slave = TRUE; + + khc_load_schema(NULL, schema_uiconfig); + + _start_app: + + if(!slave) { + + PDESCTHREAD(L"UI", L"App"); + + /* set this so that we don't accidently invoke an API that + inadvertently puts up the new creds dialog at an + inopportune moment, like, say, during the new creds dialog + is open. This only affects this process, and any child + processes started by plugins. */ + SetEnvironmentVariable(L"KERBEROSLOGIN_NEVER_PROMPT", L"1"); + + khm_version_init(); + + khm_commctl_version = khm_get_commctl_version(NULL); + + /* we only open a main window if this is the only instance + of the application that is running. */ + kmq_init(); + khm_init_gui(); + kmm_init(); + + 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(); + + khm_register_window_classes(); + + khm_init_request_daemon(); + + khm_create_main_window(); + + 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); + + khm_exit_request_daemon(); + + kmm_exit(); + khm_exit_gui(); + khm_unregister_window_classes(); + kmq_exit(); + + CloseHandle(h_appmutex); + } else { + HWND hwnd = NULL; + int retries = 5; + HANDLE hmap; + wchar_t mapname[256]; + DWORD tid; + void * xfer; + khm_query_app_version query_app_version; + khm_version v; + BOOL use_cmd_v2 = TRUE; + khm_size cb = 0; + + CloseHandle(h_appmutex); + + while (hwnd == NULL && retries) { + hwnd = FindWindowEx(NULL, NULL, KHUI_MAIN_WINDOW_CLASS, NULL); + + if (hwnd) + break; + + retries--; + + /* if the app was just starting, we might have to wait + till the main window is created. */ + + Sleep(1000); + } + + if (!hwnd) { + + /* if the app was just exiting, we might see the mutex but + not the window. We go back and check if the mutex is + still there. */ + + goto _retry_mutex; + } + + /* 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)); + + ZeroMemory(&query_app_version, sizeof(query_app_version)); + + if (xfer) { + 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.magic != KHM_QUERY_APP_VER_MAGIC || + query_app_version.code != KHM_ERROR_SUCCESS) { + + /* We managed to communicate with the remote instance, but + it didn't send us useful information. The remote + instance is not running an actual NetIDMgr instance. + However, it owns a top level window that was registered + with our classname. This instance won't function + properly if we let it proceed. + */ + + wchar_t error_msg[1024]; + wchar_t error_title[256]; + + LoadString(khm_hInstance, IDS_REMOTE_FAIL_TITLE, + error_title, ARRAYLENGTH(error_title)); + LoadString(khm_hInstance, IDS_REMOTE_FAIL, + error_msg, ARRAYLENGTH(error_msg)); + + MessageBox(NULL, error_msg, error_title, + MB_OK); + + goto done_with_remote; + } + + 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; + } + + /* Now we can work on sending the command-line to the remote + instance. However we need to figure out which version of + the startup structure it supports. */ + v.major = 1; + v.minor = 2; + v.patch = 0; + v.aux = 0; + + if (khm_compare_version(&query_app_version.ver_remote, &app_version) == 0 || + khm_compare_version(&query_app_version.ver_remote, &v) > 0) + use_cmd_v2 = TRUE; + else + use_cmd_v2 = FALSE; + + StringCbPrintf(mapname, sizeof(mapname), + COMMANDLINE_MAP_FMT, + (tid = GetCurrentThreadId())); + + cb = max(sizeof(struct tag_khm_startup_options_v1), + sizeof(struct tag_khm_startup_options_v2)); + + cb = UBOUNDSS(cb, 4096, 4096); + +#ifdef DEBUG + assert(cb >= 4096); +#endif + + hmap = CreateFileMapping(INVALID_HANDLE_VALUE, + NULL, + PAGE_READWRITE, + 0, + (DWORD) cb, + mapname); + + if (hmap == NULL) + return 3; + + /* make the call */ + + if (use_cmd_v2) { + /* use the v2 structure */ + struct tag_khm_startup_options_v2 v2opt; + + ZeroMemory(&v2opt, sizeof(v2opt)); + + v2opt.magic = STARTUP_OPTIONS_MAGIC; + v2opt.cb_size = sizeof(v2opt); + + v2opt.init = khm_startup.init; + v2opt.import = khm_startup.import; + v2opt.renew = khm_startup.renew; + v2opt.destroy = khm_startup.destroy; + + v2opt.autoinit = khm_startup.autoinit; + v2opt.remote_exit = khm_startup.remote_exit; + + v2opt.code = KHM_ERROR_NOT_IMPLEMENTED; + + xfer = MapViewOfFile(hmap, + FILE_MAP_WRITE, + 0, 0, + sizeof(v2opt)); + + if (xfer) { + memcpy(xfer, &v2opt, sizeof(v2opt)); + + SendMessage(hwnd, WM_KHUI_ASSIGN_COMMANDLINE_V2, + 0, (LPARAM) tid); + + memcpy(&v2opt, xfer, sizeof(v2opt)); + + /* If the request looks like it wasn't processed, we + fallback to the v1 request. */ + + if (v2opt.code == KHM_ERROR_NOT_IMPLEMENTED) + use_cmd_v2 = FALSE; + + UnmapViewOfFile(xfer); + xfer = NULL; + } + } + + if (!use_cmd_v2) { + /* use the v1 structure */ + + struct tag_khm_startup_options_v1 v1opt; + + ZeroMemory(&v1opt, sizeof(v1opt)); + + v1opt.init = khm_startup.init; + v1opt.import = khm_startup.import; + v1opt.renew = khm_startup.renew; + v1opt.destroy = khm_startup.destroy; + v1opt.autoinit = khm_startup.autoinit; + + xfer = MapViewOfFile(hmap, + FILE_MAP_WRITE, + 0, 0, + sizeof(v1opt)); + + if (xfer) { + memcpy(xfer, &v1opt, sizeof(v1opt)); + + SendMessage(hwnd, WM_KHUI_ASSIGN_COMMANDLINE_V1, + 0, (LPARAM) tid); + + UnmapViewOfFile(xfer); + xfer = NULL; + } + } + + done_with_remote: + + if (hmap) + CloseHandle(hmap); + } + +#if defined(DEBUG) && (defined(KH_BUILD_PRIVATE) || defined(KH_BUILD_SPECIAL)) + { + FILE * f = NULL; + + KHMEXP void KHMAPI khcint_dump_handles(FILE * f); + KHMEXP void KHMAPI perf_dump(FILE * f); + KHMEXP void KHMAPI kmqint_dump(FILE * f); + +#if _MSC_VER >= 1400 + if (fopen_s(&f, "memleak.txt", "w") != 0) + goto done_with_dump; +#else + f = fopen("memleak.txt", "w"); + if (f == NULL) + goto done_with_dump; +#endif + + perf_dump(f); + khcint_dump_handles(f); + kmqint_dump(f); + + fclose(f); + + done_with_dump: + ; + } +#endif + + return rv; +} diff --git a/src/windows/identity/ui/mainmenu.c b/src/windows/identity/ui/mainmenu.c index 6634549b4..bc45bddb3 100644 --- a/src/windows/identity/ui/mainmenu.c +++ b/src/windows/identity/ui/mainmenu.c @@ -1,1139 +1,1139 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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 - -HWND khui_main_menu_toolbar; -int mm_last_hot_item = -1; -int mm_next_hot_item = -1; -BOOL mm_hot_track = FALSE; - -#define MAX_ILIST 256 -/* not the same as MENU_SIZE_ICON_* */ -#define ILIST_ICON_X 16 -#define ILIST_ICON_Y 15 - -khui_ilist * il_icon; -int il_icon_id[MAX_ILIST]; - -void khui_init_menu(void) { - int i; - - il_icon = khui_create_ilist(ILIST_ICON_X, - ILIST_ICON_Y, - MAX_ILIST, 5, 0); - for(i=0;icaption) { - StringCbCopy(buf, cb_buf, act->caption); - } else if (act->is_caption) { - LoadString(khm_hInstance, act->is_caption, - buf, (int)(cb_buf / sizeof(wchar_t))); - } - - done: - khui_action_unlock(); -} - -void khm_get_action_tooltip(khm_int32 action, wchar_t * buf, khm_size cb_buf) { - khui_action * act; - - StringCbCopy(buf, cb_buf, L""); - - khui_action_lock(); - act = khui_find_action(action); - - if (act == NULL) - goto done; - - if (act->tooltip) { - StringCbCopy(buf, cb_buf, act->tooltip); - } else if (act->is_tooltip) { - LoadString(khm_hInstance, act->is_tooltip, - buf, (int) (cb_buf / sizeof(wchar_t))); - } - - done: - khui_action_unlock(); -} - -void add_action_to_menu(HMENU hm, khui_action * act, - int idx, int flags) { - MENUITEMINFO mii; - 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; - - if(act == NULL) { - mii.fMask = MIIM_FTYPE; - mii.fType = MFT_SEPARATOR; - } else { - khui_menu_def * def; - - khm_get_action_caption(act->cmd, buf, sizeof(buf)); - - if(khui_get_cmd_accel_string(act->cmd, accel, - ARRAYLENGTH(accel))) { - StringCbCat(buf, sizeof(buf), L"\t"); - StringCbCat(buf, sizeof(buf), accel); - } - - mii.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID; - mii.fType = MFT_STRING; - - mii.dwTypeData = buf; - mii.cch = (int) wcslen(buf); - - mii.wID = act->cmd; - - if(act->state & KHUI_ACTIONSTATE_DISABLED) { - mii.fMask |= MIIM_STATE; - mii.fState = MFS_DISABLED; - } else { - mii.fState = 0; - } - - if((act->type & KHUI_ACTIONTYPE_TOGGLE) && - (act->state & KHUI_ACTIONSTATE_CHECKED)) { - mii.fMask |= MIIM_STATE; - mii.fState |= MFS_CHECKED; - } - - if(act->ib_icon) { - mii.fMask |= MIIM_BITMAP; - mii.hbmpItem = HBMMENU_CALLBACK; - } - - 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) { - mii.fMask |= MIIM_STATE; - mii.fState |= MFS_DEFAULT; - } - } - - InsertMenuItem(hm,idx,TRUE,&mii); -} - -static void refresh_menu(HMENU hm, khui_menu_def * def); - -static int refresh_menu_item(HMENU hm, khui_action * act, - int idx, int flags) { - MENUITEMINFO mii; - khui_menu_def * def; - - mii.cbSize = sizeof(mii); - mii.fMask = 0; - - if (flags & KHUI_ACTIONREF_END) { - /* we have been asked to assert that the menu doesn't have - more than idx items */ - mii.fMask = MIIM_FTYPE; - while (GetMenuItemInfo(hm, idx, TRUE, &mii)) { - RemoveMenu(hm, idx, MF_BYPOSITION); - mii.fMask = MIIM_FTYPE; - } - - return 0; - } - - /* Check if the menu item is there. Otherwise we need to add - it. */ - mii.fMask = MIIM_STATE | MIIM_ID | MIIM_FTYPE; - if (!GetMenuItemInfo(hm, idx, TRUE, &mii) || - ((flags & KHUI_ACTIONREF_SEP) && !(mii.fType & MFT_SEPARATOR)) || - (!(flags & KHUI_ACTIONREF_SEP) && mii.wID != act->cmd)) { - add_action_to_menu(hm, ((flags & KHUI_ACTIONREF_SEP)? NULL : act), - idx, flags); - return 0; - } - - if (flags & KHUI_ACTIONREF_SEP) - return 0; - -#ifdef DEBUG - assert(act); -#endif - if (!act) - return 0; - - if (flags & KHUI_ACTIONREF_DEFAULT) { - if (!(mii.fState & MFS_DEFAULT)) { - mii.fMask |= MIIM_STATE; - mii.fState |= MFS_DEFAULT; - } - } else { - if (mii.fState & MFS_DEFAULT) { - RemoveMenu(hm, idx, MF_BYPOSITION); - add_action_to_menu(hm, act, idx, flags); - return 0; - } - } - - mii.fMask = 0; - - if(act->state & KHUI_ACTIONSTATE_DISABLED) { - mii.fMask |= MIIM_STATE; - mii.fState &= ~MFS_ENABLED; - mii.fState |= MFS_DISABLED; - } else { - mii.fMask |= MIIM_STATE; - mii.fState &= ~MFS_DISABLED; - mii.fState |= MFS_ENABLED; - } - - if(act->type & KHUI_ACTIONTYPE_TOGGLE) { - mii.fMask |= MIIM_STATE; - if (act->state & KHUI_ACTIONSTATE_CHECKED) { - mii.fState &= ~MFS_UNCHECKED; - mii.fState |= MFS_CHECKED; - } else { - mii.fState &= ~MFS_CHECKED; - mii.fState |= MFS_UNCHECKED; - } - } - - SetMenuItemInfo(hm, act->cmd, FALSE, &mii); - - def = khui_find_menu(act->cmd); - - if(def) { - MENUITEMINFO mii2; - - mii2.cbSize = sizeof(mii2); - mii2.fMask = MIIM_SUBMENU; - - if (GetMenuItemInfo(hm, act->cmd, FALSE, &mii2)) { - refresh_menu(mii2.hSubMenu, def); - } - } - - return 0; -} - - -static void refresh_menu(HMENU hm, khui_menu_def * def) { - khui_action_ref * act; - khm_size i, n; - - for(i = 0, n = khui_menu_get_size(def); i < n; i++) { - act = khui_menu_get_action(def, i); - refresh_menu_item(hm, khui_find_action(act->action), (int) i, act->flags); - } - - refresh_menu_item(hm, NULL, (int) i, KHUI_ACTIONREF_END); -} - -static HMENU mm_create_menu_from_def(khui_menu_def * def, BOOL main) { - HMENU hm; - khui_action_ref * act; - khm_size i, n; - - if (main) - hm = CreateMenu(); - else - hm = CreatePopupMenu(); - - for (i = 0, n = khui_menu_get_size(def); i < n; i++) { - act = khui_menu_get_action(def, i); - add_action_to_menu(hm, khui_find_action(act->action), (int) i, act->flags); - } - - return hm; -} - -void mm_begin_hot_track(void); -void mm_end_hot_track(void); - -static void mm_show_panel_def(khui_menu_def * def, LONG x, LONG y) -{ - HMENU hm; - - hm = mm_create_menu_from_def(def, FALSE); - - mm_hot_track = (mm_last_hot_item >= 0); - - if (mm_hot_track) - mm_begin_hot_track(); - - TrackPopupMenuEx(hm, - TPM_LEFTALIGN | TPM_TOPALIGN | - TPM_VERPOSANIMATION, - x, y, khm_hwnd_main, NULL); - - mm_last_hot_item = -1; - - if (mm_hot_track) - mm_end_hot_track(); - - mm_hot_track = FALSE; - - DestroyMenu(hm); -} - -void khm_menu_show_panel(int id, LONG x, LONG y) { - khui_menu_def * def; - - def = khui_find_menu(id); - if(!def) - return; - - mm_show_panel_def(def, x, y); -} - -LRESULT khm_menu_activate(int menu_id) { - khui_menu_def * mmdef; - int nmm; - - mmdef = khui_find_menu(KHUI_MENU_MAIN); - nmm = (int) khui_action_list_length(mmdef->items); - - if(menu_id == MENU_ACTIVATE_DEFAULT) { - if (mm_last_hot_item != -1) - menu_id = mm_last_hot_item; - else - menu_id = 0; - } else if(menu_id == MENU_ACTIVATE_LEFT) { - menu_id = (mm_last_hot_item > 0)? - mm_last_hot_item - 1: - ((mm_last_hot_item == 0)? nmm - 1: 0); - } else if(menu_id == MENU_ACTIVATE_RIGHT) { - menu_id = (mm_last_hot_item >=0 && mm_last_hot_item < nmm - 1)? - mm_last_hot_item + 1: - 0; - } else if(menu_id == MENU_ACTIVATE_NONE) { - menu_id = -1; - } - - SendMessage(khui_main_menu_toolbar, - TB_SETHOTITEM, - menu_id, - 0); - - khm_menu_track_current(); - - return TRUE; -} - -LRESULT khm_menu_measure_item(WPARAM wParam, LPARAM lParam) { - /* all menu icons have a fixed size */ - LPMEASUREITEMSTRUCT lpm = (LPMEASUREITEMSTRUCT) lParam; - lpm->itemWidth = MENU_SIZE_ICON_X; - lpm->itemHeight = MENU_SIZE_ICON_Y; - return TRUE; -} - -LRESULT khm_menu_draw_item(WPARAM wParam, LPARAM lParam) { - LPDRAWITEMSTRUCT lpd; - khui_action * act; - int resid; - int iidx; - UINT style; - - lpd = (LPDRAWITEMSTRUCT) lParam; - act = khui_find_action(lpd->itemID); - - resid = 0; - if((lpd->itemState & ODS_DISABLED) || (lpd->itemState & ODS_GRAYED)) { - resid = act->ib_icon_dis; - } - if(!resid) - resid = act->ib_icon; - - if(!resid) /* nothing to draw */ - return TRUE; - - - iidx = khui_get_icon_index(resid); - if(iidx == -1) - return TRUE; - - - style = ILD_TRANSPARENT; - if(lpd->itemState & ODS_HOTLIGHT || lpd->itemState & ODS_SELECTED) { - style |= ILD_SELECTED; - } - - khui_ilist_draw(il_icon, - iidx, - lpd->hDC, - lpd->rcItem.left, lpd->rcItem.top, style); - - return TRUE; -} - -void khm_track_menu(int menu) { - TBBUTTON bi; - RECT r; - RECT wr; - - if (menu != -1) - mm_last_hot_item = menu; - - if (mm_last_hot_item != -1) { - SendMessage(khui_main_menu_toolbar, - TB_GETBUTTON, - mm_last_hot_item, - (LPARAM) &bi); - - SendMessage(khui_main_menu_toolbar, - TB_GETITEMRECT, - mm_last_hot_item, - (LPARAM) &r); - - GetWindowRect(khui_main_menu_toolbar, &wr); - - khm_menu_show_panel(bi.idCommand, wr.left + r.left, wr.top + r.bottom); - - r.left = 0; - - if (mm_next_hot_item != -1) { - mm_last_hot_item = mm_next_hot_item; - mm_next_hot_item = -1; - - PostMessage(khm_hwnd_main, WM_COMMAND, - MAKEWPARAM(KHUI_PACTION_MENU,0), - MAKELPARAM(mm_last_hot_item,1)); - } - } -} - -void khm_menu_track_current(void) { - khm_track_menu(-1); -} - -LRESULT khm_menu_handle_select(WPARAM wParam, LPARAM lParam) { - if((HIWORD(wParam) == 0xffff && lParam == 0) || - (HIWORD(wParam) & MF_POPUP)) { - /* the menu was closed */ - khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, NULL); - } else { - khui_action * act; - int id; - wchar_t buf[MAX_RES_STRING] = L""; - - id = LOWORD(wParam); - act = khui_find_action(id); - if(act == NULL || (act->is_tooltip == 0 && act->tooltip == NULL)) - khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, NULL); - else { - khm_get_action_tooltip(act->cmd, buf, sizeof(buf)); - - khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, buf); - } - } - return 0; -} - -HHOOK mm_hevt_hook = NULL; -HWND mm_hwnd_menu_panel = NULL; - -LRESULT CALLBACK mm_event_filter(int code, - WPARAM wParam, - LPARAM lParam) { - MSG * m; - RECT r; - int x,y; - - if (code == MSGF_MENU) { - /* do stuff */ - m = (MSG *) lParam; - GetWindowRect(khui_main_menu_toolbar, &r); - - if (m->hwnd != khm_hwnd_main) - mm_hwnd_menu_panel = m->hwnd; - - switch(m->message) { - case WM_MOUSEMOVE: - - x = GET_X_LPARAM(m->lParam); - y = GET_Y_LPARAM(m->lParam); - x -= r.left; - y -= r.top; - - SendMessage(khui_main_menu_toolbar, - m->message, - m->wParam, - MAKELPARAM(x,y)); - break; - } - } - - return CallNextHookEx(mm_hevt_hook, code, wParam, lParam); -} - - -void mm_begin_hot_track(void) { - - if (mm_hevt_hook) - UnhookWindowsHookEx(mm_hevt_hook); - - mm_hevt_hook = SetWindowsHookEx(WH_MSGFILTER, - mm_event_filter, - NULL, - GetCurrentThreadId()); -} - -void mm_end_hot_track(void) { - if (mm_hevt_hook) - UnhookWindowsHookEx(mm_hevt_hook); - - mm_hevt_hook = NULL; - mm_hwnd_menu_panel = NULL; -} - -void mm_cancel_menu(void) { - if (mm_hwnd_menu_panel) - SendMessage(mm_hwnd_menu_panel, WM_CANCELMODE, 0, 0); -} - -LRESULT khm_menu_notify_main(LPNMHDR notice) { - LPNMTOOLBAR nmt; - LRESULT ret = FALSE; - RECT r; - khui_menu_def * mmdef; - khui_action_ref * mm; - int nmm; - - mmdef = khui_find_menu(KHUI_MENU_MAIN); - mm = mmdef->items; - nmm = (int) khui_action_list_length(mm); - - GetWindowRect(khui_main_menu_toolbar, &r); - - nmt = (LPNMTOOLBAR) notice; - switch(notice->code) { - case TBN_DROPDOWN: - khm_track_menu(-1); - /* - khm_menu_show_panel(nmt->iItem, - r.left + nmt->rcButton.left, - r.top + nmt->rcButton.bottom); - */ - ret = TBDDRET_DEFAULT; - break; - - case TBN_HOTITEMCHANGE: - { - LPNMTBHOTITEM nmhi; - int new_item = -1; - - nmhi = (LPNMTBHOTITEM) notice; - - if(nmhi->dwFlags & HICF_LEAVING) - new_item = -1; - else { - int i; - for(i=0; i < nmm; i++) { - if(mm[i].action == nmhi->idNew) { - new_item = i; - break; - } - } - } - - if (mm_hot_track && - new_item != mm_last_hot_item && - new_item != -1 && - mm_last_hot_item != -1) { - - EndMenu(); - mm_next_hot_item = new_item; - - } - - ret = 0; - - if (!mm_hot_track || new_item != -1) - mm_last_hot_item = new_item; - - } break; - - default: - /* hmm. what to do */ - ret = FALSE; - } - return ret; -} - -struct identity_action_map { - khm_handle identity; - khm_int32 renew_cmd; - khm_int32 destroy_cmd; - khm_int32 new_cmd; - int refreshcycle; -}; - -#define IDMAP_ALLOC_INCR 8 - -struct identity_action_map * id_action_map = NULL; -khm_size n_id_action_map = 0; -khm_size nc_id_action_map = 0; - -int idcmd_refreshcycle = 0; - -static struct identity_action_map * -create_identity_cmd_map(khm_handle ident) { - - struct identity_action_map * actmap; - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - wchar_t fmt[128]; - wchar_t caption[KHUI_MAXCCH_SHORT_DESC]; - wchar_t tooltip[KHUI_MAXCCH_SHORT_DESC]; - wchar_t actionname[KHUI_MAXCCH_NAME]; - khm_size cb; - - if (n_id_action_map + 1 > nc_id_action_map) { - nc_id_action_map = UBOUNDSS(n_id_action_map + 1, - IDMAP_ALLOC_INCR, - IDMAP_ALLOC_INCR); -#ifdef DEBUG - assert(nc_id_action_map > n_id_action_map + 1); -#endif - id_action_map = PREALLOC(id_action_map, - nc_id_action_map * sizeof(id_action_map[0])); -#ifdef DEBUG - assert(id_action_map); -#endif - ZeroMemory(&id_action_map[n_id_action_map], - sizeof(id_action_map[0]) * (nc_id_action_map - n_id_action_map)); - } - - actmap = &id_action_map[n_id_action_map]; - n_id_action_map++; - - cb = sizeof(idname); - kcdb_identity_get_name(ident, idname, &cb); - - actmap->identity = ident; - kcdb_identity_hold(ident); - -#define GETFORMAT(I) do { fmt[0] = L'\0'; LoadString(khm_hInstance, I, fmt, ARRAYLENGTH(fmt)); } while(0) -#define EXPFORMAT(d,s) do { StringCbPrintf(d, sizeof(d), fmt, s); } while(0) - /* renew */ - - GETFORMAT(IDS_IDACTIONT_RENEW); - EXPFORMAT(tooltip, idname); - - GETFORMAT(IDS_IDACTION_RENEW); - EXPFORMAT(caption, idname); - - StringCbPrintf(actionname, sizeof(actionname), L"R:%s", idname); - - actmap->renew_cmd = - khui_action_create(actionname, caption, tooltip, NULL, - KHUI_ACTIONTYPE_TRIGGER, NULL); - - /* destroy */ - - GETFORMAT(IDS_IDACTIONT_DESTROY); - EXPFORMAT(tooltip, idname); - - GETFORMAT(IDS_IDACTION_DESTROY); - EXPFORMAT(caption, idname); - - StringCbPrintf(actionname, sizeof(actionname), L"D:%s", idname); - - actmap->destroy_cmd = - khui_action_create(actionname, caption, tooltip, NULL, - KHUI_ACTIONTYPE_TRIGGER, NULL); - - /* new */ - - GETFORMAT(IDS_IDACTIONT_NEW); - EXPFORMAT(tooltip, idname); - - GETFORMAT(IDS_IDACTION_NEW); - EXPFORMAT(caption, idname); - - StringCbPrintf(actionname, sizeof(actionname), L"N:%s", idname); - - actmap->new_cmd = - khui_action_create(actionname, caption, tooltip, NULL, - KHUI_ACTIONTYPE_TRIGGER, NULL); - - actmap->refreshcycle = idcmd_refreshcycle; - -#undef GETFORMAT -#undef EXPFORMAT - - return actmap; -} - -static void -purge_identity_cmd_map(void) { - khm_size i; - - for (i=0; i < n_id_action_map; i++) { - khm_handle ident; - - if (id_action_map[i].refreshcycle != idcmd_refreshcycle) { - ident = id_action_map[i].identity; - id_action_map[i].identity = NULL; - kcdb_identity_release(ident); - - khui_action_delete(id_action_map[i].renew_cmd); - khui_action_delete(id_action_map[i].destroy_cmd); - - id_action_map[i].renew_cmd = 0; - id_action_map[i].destroy_cmd = 0; - } - } -} - -static struct identity_action_map * -get_identity_cmd_map(khm_handle ident) { - khm_size i; - - for (i=0; i < n_id_action_map; i++) { - if (kcdb_identity_is_equal(id_action_map[i].identity, - ident)) - break; - } - - if (i < n_id_action_map) { - id_action_map[i].refreshcycle = idcmd_refreshcycle; - return &id_action_map[i]; - } else { - return create_identity_cmd_map(ident); - } -} - -khm_int32 -khm_get_identity_renew_action(khm_handle ident) { - struct identity_action_map * map; - - map = get_identity_cmd_map(ident); - - if (map) - return map->renew_cmd; - else - return 0; -} - -khm_int32 -khm_get_identity_destroy_action(khm_handle ident) { - struct identity_action_map * map; - - map = get_identity_cmd_map(ident); - - if (map) - return map->destroy_cmd; - else - return 0; -} - -khm_int32 -khm_get_identity_new_creds_action(khm_handle ident) { - struct identity_action_map * map; - - map = get_identity_cmd_map(ident); - - if (map) - return map->new_cmd; - else - return 0; -} - -void -khm_refresh_identity_menus(void) { - khui_menu_def * renew_def = NULL; - khui_menu_def * dest_def = NULL; - wchar_t * idlist = NULL; - wchar_t * idname = NULL; - khm_size cb = 0; - khm_size n_idents = 0; - khm_size t; - khm_int32 rv = KHM_ERROR_SUCCESS; - khm_handle csp_cw = NULL; - khm_int32 idflags; - khm_int32 def_sticky = 0; - khm_boolean sticky_done = FALSE; - - if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", 0, &csp_cw))) { - khc_read_int32(csp_cw, L"DefaultSticky", &def_sticky); - khc_close_space(csp_cw); - csp_cw = NULL; - } - - kcdb_identity_refresh_all(); - - khui_action_lock(); - - idcmd_refreshcycle++; - - do { - if (idlist) - PFREE(idlist); - idlist = NULL; - cb = 0; - - rv = kcdb_identity_enum(KCDB_IDENT_FLAG_ACTIVE | KCDB_IDENT_FLAG_EMPTY, - KCDB_IDENT_FLAG_ACTIVE, - NULL, - &cb, - &n_idents); - if (rv != KHM_ERROR_TOO_LONG || cb == 0 || cb == sizeof(wchar_t) * 2) - break; - - idlist = PMALLOC(cb); -#ifdef DEBUG - assert(idlist); -#endif - - rv = kcdb_identity_enum(KCDB_IDENT_FLAG_ACTIVE | KCDB_IDENT_FLAG_EMPTY, - KCDB_IDENT_FLAG_ACTIVE, - idlist, - &cb, - &n_idents); - if (rv == KHM_ERROR_TOO_LONG) - continue; - - if (KHM_FAILED(rv)) { - /* something else went wrong. hmm. */ - if (idlist) - PFREE(idlist); - idlist = NULL; - } - break; - - } while(TRUE); - - if (idlist != NULL && n_idents > 0) { - khui_enable_action(KHUI_MENU_RENEW_CRED, TRUE); - khui_enable_action(KHUI_MENU_DESTROY_CRED, TRUE); - khui_enable_action(KHUI_ACTION_RENEW_CRED, TRUE); - khui_enable_action(KHUI_ACTION_DESTROY_CRED, TRUE); - } else { - khui_enable_action(KHUI_MENU_RENEW_CRED, FALSE); - khui_enable_action(KHUI_MENU_DESTROY_CRED, FALSE); - khui_enable_action(KHUI_ACTION_RENEW_CRED, FALSE); - khui_enable_action(KHUI_ACTION_DESTROY_CRED, FALSE); - } - - renew_def = khui_find_menu(KHUI_MENU_RENEW_CRED); - dest_def = khui_find_menu(KHUI_MENU_DESTROY_CRED); -#ifdef DEBUG - assert(renew_def); - assert(dest_def); -#endif - - t = khui_menu_get_size(renew_def); - while(t) { - khui_menu_remove_action(renew_def, 0); - t--; - } - - t = khui_menu_get_size(dest_def); - while(t) { - khui_menu_remove_action(dest_def, 0); - t--; - } - - if (idlist != NULL && n_idents > 1) { - khui_menu_insert_action(renew_def, 0, KHUI_ACTION_RENEW_ALL, 0); - khui_menu_insert_action(renew_def, 1, KHUI_MENU_SEP, 0); - - khui_menu_insert_action(dest_def, 0, KHUI_ACTION_DESTROY_ALL, 0); - khui_menu_insert_action(dest_def, 1, KHUI_MENU_SEP, 0); - } - - for (idname = idlist; idname && idname[0]; - idname = multi_string_next(idname)) { - khm_handle identity = NULL; - - if (KHM_FAILED(kcdb_identity_create(idname, 0, &identity))) { -#ifdef DEBUG - assert(FALSE); -#endif - continue; - } - - khui_menu_insert_action(renew_def, 1000, - khm_get_identity_renew_action(identity), - 0); - - khui_menu_insert_action(dest_def, 1000, - khm_get_identity_destroy_action(identity), - 0); - - idflags = 0; - kcdb_identity_get_flags(identity, &idflags); - - if (!(idflags & KCDB_IDENT_FLAG_STICKY) && def_sticky) { - kcdb_identity_set_flags(identity, - KCDB_IDENT_FLAG_STICKY, - KCDB_IDENT_FLAG_STICKY); - sticky_done = TRUE; - } - } - - if (idlist) - PFREE(idlist); - - purge_identity_cmd_map(); - - khui_action_unlock(); - - khui_refresh_actions(); - - if (sticky_done) { - InvalidateRect(khm_hwnd_main_cred, NULL, TRUE); - } -} - -khm_boolean -khm_check_identity_menu_action(khm_int32 act_id) { - - if (act_id == KHUI_ACTION_DESTROY_ALL) { - khm_size i; - - for (i=0; i < n_id_action_map; i++) { - if (id_action_map[i].identity != NULL) { - khm_cred_destroy_identity(id_action_map[i].identity); - } - } - - return TRUE; - } else if (act_id == KHUI_ACTION_RENEW_ALL) { - khm_size i; - - for (i=0; i < n_id_action_map; i++) { - if (id_action_map[i].identity != NULL) { - khm_cred_renew_identity(id_action_map[i].identity); - } - } - - return TRUE; - } else { - khm_size i; - - for (i=0; i < n_id_action_map; i++) { - if (id_action_map[i].identity == NULL) - continue; - - if (id_action_map[i].renew_cmd == act_id) { - khm_cred_renew_identity(id_action_map[i].identity); - return TRUE; - } - - if (id_action_map[i].destroy_cmd == act_id) { - khm_cred_destroy_identity(id_action_map[i].identity); - return TRUE; - } - - if (id_action_map[i].new_cmd == act_id) { - khm_cred_obtain_new_creds_for_ident(id_action_map[i].identity, - NULL); - return TRUE; - } - } - } - - return FALSE; -} - - -HMENU khui_hmenu_main = NULL; - -void khm_menu_refresh_items(void) { - khui_menu_def * def; - - if (!khui_hmenu_main) - return; - - khui_action_lock(); - - def = khui_find_menu(KHUI_MENU_MAIN); - - refresh_menu(khui_hmenu_main, def); - - khui_action_unlock(); - - DrawMenuBar(khm_hwnd_main); -} - -void khm_menu_create_main(HWND parent) { - HMENU hmenu; - khui_menu_def * def; - - def = khui_find_menu(KHUI_MENU_MAIN); - - hmenu = mm_create_menu_from_def(def, TRUE); - - SetMenu(parent, hmenu); - - khui_hmenu_main = hmenu; - - return; - -#ifdef USE_EXPLORER_STYLE_MENU_BAR - HWND hwtb; - REBARBANDINFO rbi; - SIZE sz; - int i; - khui_menu_def * mmdef; - khui_action_ref * mm; - int nmm; - - mmdef = khui_find_menu(KHUI_MENU_MAIN); - mm = mmdef->items; - nmm = (int) khui_action_list_length(mm); - - hwtb = CreateWindowEx(0 -#if (_WIN32_IE >= 0x0501) - | TBSTYLE_EX_MIXEDBUTTONS -#endif - , - TOOLBARCLASSNAME, - (LPWSTR) NULL, - WS_CHILD | - CCS_ADJUSTABLE | - TBSTYLE_FLAT | - TBSTYLE_AUTOSIZE | - TBSTYLE_LIST | - CCS_NORESIZE | - CCS_NOPARENTALIGN | - CCS_NODIVIDER, - 0, 0, 0, 0, rebar, - (HMENU) NULL, khm_hInstance, - NULL); - - if(!hwtb) { -#ifdef DEBUG - assert(FALSE); -#endif - return; - } - - khui_main_menu_toolbar = hwtb; - - SendMessage(hwtb, - TB_BUTTONSTRUCTSIZE, - (WPARAM) sizeof(TBBUTTON), - 0); - - for(i=0; i +#include + +HWND khui_main_menu_toolbar; +int mm_last_hot_item = -1; +int mm_next_hot_item = -1; +BOOL mm_hot_track = FALSE; + +#define MAX_ILIST 256 +/* not the same as MENU_SIZE_ICON_* */ +#define ILIST_ICON_X 16 +#define ILIST_ICON_Y 15 + +khui_ilist * il_icon; +int il_icon_id[MAX_ILIST]; + +void khui_init_menu(void) { + int i; + + il_icon = khui_create_ilist(ILIST_ICON_X, + ILIST_ICON_Y, + MAX_ILIST, 5, 0); + for(i=0;icaption) { + StringCbCopy(buf, cb_buf, act->caption); + } else if (act->is_caption) { + LoadString(khm_hInstance, act->is_caption, + buf, (int)(cb_buf / sizeof(wchar_t))); + } + + done: + khui_action_unlock(); +} + +void khm_get_action_tooltip(khm_int32 action, wchar_t * buf, khm_size cb_buf) { + khui_action * act; + + StringCbCopy(buf, cb_buf, L""); + + khui_action_lock(); + act = khui_find_action(action); + + if (act == NULL) + goto done; + + if (act->tooltip) { + StringCbCopy(buf, cb_buf, act->tooltip); + } else if (act->is_tooltip) { + LoadString(khm_hInstance, act->is_tooltip, + buf, (int) (cb_buf / sizeof(wchar_t))); + } + + done: + khui_action_unlock(); +} + +void add_action_to_menu(HMENU hm, khui_action * act, + int idx, int flags) { + MENUITEMINFO mii; + 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; + + if(act == NULL) { + mii.fMask = MIIM_FTYPE; + mii.fType = MFT_SEPARATOR; + } else { + khui_menu_def * def; + + khm_get_action_caption(act->cmd, buf, sizeof(buf)); + + if(khui_get_cmd_accel_string(act->cmd, accel, + ARRAYLENGTH(accel))) { + StringCbCat(buf, sizeof(buf), L"\t"); + StringCbCat(buf, sizeof(buf), accel); + } + + mii.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID; + mii.fType = MFT_STRING; + + mii.dwTypeData = buf; + mii.cch = (int) wcslen(buf); + + mii.wID = act->cmd; + + if(act->state & KHUI_ACTIONSTATE_DISABLED) { + mii.fMask |= MIIM_STATE; + mii.fState = MFS_DISABLED; + } else { + mii.fState = 0; + } + + if((act->type & KHUI_ACTIONTYPE_TOGGLE) && + (act->state & KHUI_ACTIONSTATE_CHECKED)) { + mii.fMask |= MIIM_STATE; + mii.fState |= MFS_CHECKED; + } + + if(act->ib_icon) { + mii.fMask |= MIIM_BITMAP; + mii.hbmpItem = HBMMENU_CALLBACK; + } + + 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) { + mii.fMask |= MIIM_STATE; + mii.fState |= MFS_DEFAULT; + } + } + + InsertMenuItem(hm,idx,TRUE,&mii); +} + +static void refresh_menu(HMENU hm, khui_menu_def * def); + +static int refresh_menu_item(HMENU hm, khui_action * act, + int idx, int flags) { + MENUITEMINFO mii; + khui_menu_def * def; + + mii.cbSize = sizeof(mii); + mii.fMask = 0; + + if (flags & KHUI_ACTIONREF_END) { + /* we have been asked to assert that the menu doesn't have + more than idx items */ + mii.fMask = MIIM_FTYPE; + while (GetMenuItemInfo(hm, idx, TRUE, &mii)) { + RemoveMenu(hm, idx, MF_BYPOSITION); + mii.fMask = MIIM_FTYPE; + } + + return 0; + } + + /* Check if the menu item is there. Otherwise we need to add + it. */ + mii.fMask = MIIM_STATE | MIIM_ID | MIIM_FTYPE; + if (!GetMenuItemInfo(hm, idx, TRUE, &mii) || + ((flags & KHUI_ACTIONREF_SEP) && !(mii.fType & MFT_SEPARATOR)) || + (!(flags & KHUI_ACTIONREF_SEP) && mii.wID != act->cmd)) { + add_action_to_menu(hm, ((flags & KHUI_ACTIONREF_SEP)? NULL : act), + idx, flags); + return 0; + } + + if (flags & KHUI_ACTIONREF_SEP) + return 0; + +#ifdef DEBUG + assert(act); +#endif + if (!act) + return 0; + + if (flags & KHUI_ACTIONREF_DEFAULT) { + if (!(mii.fState & MFS_DEFAULT)) { + mii.fMask |= MIIM_STATE; + mii.fState |= MFS_DEFAULT; + } + } else { + if (mii.fState & MFS_DEFAULT) { + RemoveMenu(hm, idx, MF_BYPOSITION); + add_action_to_menu(hm, act, idx, flags); + return 0; + } + } + + mii.fMask = 0; + + if(act->state & KHUI_ACTIONSTATE_DISABLED) { + mii.fMask |= MIIM_STATE; + mii.fState &= ~MFS_ENABLED; + mii.fState |= MFS_DISABLED; + } else { + mii.fMask |= MIIM_STATE; + mii.fState &= ~MFS_DISABLED; + mii.fState |= MFS_ENABLED; + } + + if(act->type & KHUI_ACTIONTYPE_TOGGLE) { + mii.fMask |= MIIM_STATE; + if (act->state & KHUI_ACTIONSTATE_CHECKED) { + mii.fState &= ~MFS_UNCHECKED; + mii.fState |= MFS_CHECKED; + } else { + mii.fState &= ~MFS_CHECKED; + mii.fState |= MFS_UNCHECKED; + } + } + + SetMenuItemInfo(hm, act->cmd, FALSE, &mii); + + def = khui_find_menu(act->cmd); + + if(def) { + MENUITEMINFO mii2; + + mii2.cbSize = sizeof(mii2); + mii2.fMask = MIIM_SUBMENU; + + if (GetMenuItemInfo(hm, act->cmd, FALSE, &mii2)) { + refresh_menu(mii2.hSubMenu, def); + } + } + + return 0; +} + + +static void refresh_menu(HMENU hm, khui_menu_def * def) { + khui_action_ref * act; + khm_size i, n; + + for(i = 0, n = khui_menu_get_size(def); i < n; i++) { + act = khui_menu_get_action(def, i); + refresh_menu_item(hm, khui_find_action(act->action), (int) i, act->flags); + } + + refresh_menu_item(hm, NULL, (int) i, KHUI_ACTIONREF_END); +} + +static HMENU mm_create_menu_from_def(khui_menu_def * def, BOOL main) { + HMENU hm; + khui_action_ref * act; + khm_size i, n; + + if (main) + hm = CreateMenu(); + else + hm = CreatePopupMenu(); + + for (i = 0, n = khui_menu_get_size(def); i < n; i++) { + act = khui_menu_get_action(def, i); + add_action_to_menu(hm, khui_find_action(act->action), (int) i, act->flags); + } + + return hm; +} + +void mm_begin_hot_track(void); +void mm_end_hot_track(void); + +static void mm_show_panel_def(khui_menu_def * def, LONG x, LONG y) +{ + HMENU hm; + + hm = mm_create_menu_from_def(def, FALSE); + + mm_hot_track = (mm_last_hot_item >= 0); + + if (mm_hot_track) + mm_begin_hot_track(); + + TrackPopupMenuEx(hm, + TPM_LEFTALIGN | TPM_TOPALIGN | + TPM_VERPOSANIMATION, + x, y, khm_hwnd_main, NULL); + + mm_last_hot_item = -1; + + if (mm_hot_track) + mm_end_hot_track(); + + mm_hot_track = FALSE; + + DestroyMenu(hm); +} + +void khm_menu_show_panel(int id, LONG x, LONG y) { + khui_menu_def * def; + + def = khui_find_menu(id); + if(!def) + return; + + mm_show_panel_def(def, x, y); +} + +LRESULT khm_menu_activate(int menu_id) { + khui_menu_def * mmdef; + int nmm; + + mmdef = khui_find_menu(KHUI_MENU_MAIN); + nmm = (int) khui_action_list_length(mmdef->items); + + if(menu_id == MENU_ACTIVATE_DEFAULT) { + if (mm_last_hot_item != -1) + menu_id = mm_last_hot_item; + else + menu_id = 0; + } else if(menu_id == MENU_ACTIVATE_LEFT) { + menu_id = (mm_last_hot_item > 0)? + mm_last_hot_item - 1: + ((mm_last_hot_item == 0)? nmm - 1: 0); + } else if(menu_id == MENU_ACTIVATE_RIGHT) { + menu_id = (mm_last_hot_item >=0 && mm_last_hot_item < nmm - 1)? + mm_last_hot_item + 1: + 0; + } else if(menu_id == MENU_ACTIVATE_NONE) { + menu_id = -1; + } + + SendMessage(khui_main_menu_toolbar, + TB_SETHOTITEM, + menu_id, + 0); + + khm_menu_track_current(); + + return TRUE; +} + +LRESULT khm_menu_measure_item(WPARAM wParam, LPARAM lParam) { + /* all menu icons have a fixed size */ + LPMEASUREITEMSTRUCT lpm = (LPMEASUREITEMSTRUCT) lParam; + lpm->itemWidth = MENU_SIZE_ICON_X; + lpm->itemHeight = MENU_SIZE_ICON_Y; + return TRUE; +} + +LRESULT khm_menu_draw_item(WPARAM wParam, LPARAM lParam) { + LPDRAWITEMSTRUCT lpd; + khui_action * act; + int resid; + int iidx; + UINT style; + + lpd = (LPDRAWITEMSTRUCT) lParam; + act = khui_find_action(lpd->itemID); + + resid = 0; + if((lpd->itemState & ODS_DISABLED) || (lpd->itemState & ODS_GRAYED)) { + resid = act->ib_icon_dis; + } + if(!resid) + resid = act->ib_icon; + + if(!resid) /* nothing to draw */ + return TRUE; + + + iidx = khui_get_icon_index(resid); + if(iidx == -1) + return TRUE; + + + style = ILD_TRANSPARENT; + if(lpd->itemState & ODS_HOTLIGHT || lpd->itemState & ODS_SELECTED) { + style |= ILD_SELECTED; + } + + khui_ilist_draw(il_icon, + iidx, + lpd->hDC, + lpd->rcItem.left, lpd->rcItem.top, style); + + return TRUE; +} + +void khm_track_menu(int menu) { + TBBUTTON bi; + RECT r; + RECT wr; + + if (menu != -1) + mm_last_hot_item = menu; + + if (mm_last_hot_item != -1) { + SendMessage(khui_main_menu_toolbar, + TB_GETBUTTON, + mm_last_hot_item, + (LPARAM) &bi); + + SendMessage(khui_main_menu_toolbar, + TB_GETITEMRECT, + mm_last_hot_item, + (LPARAM) &r); + + GetWindowRect(khui_main_menu_toolbar, &wr); + + khm_menu_show_panel(bi.idCommand, wr.left + r.left, wr.top + r.bottom); + + r.left = 0; + + if (mm_next_hot_item != -1) { + mm_last_hot_item = mm_next_hot_item; + mm_next_hot_item = -1; + + PostMessage(khm_hwnd_main, WM_COMMAND, + MAKEWPARAM(KHUI_PACTION_MENU,0), + MAKELPARAM(mm_last_hot_item,1)); + } + } +} + +void khm_menu_track_current(void) { + khm_track_menu(-1); +} + +LRESULT khm_menu_handle_select(WPARAM wParam, LPARAM lParam) { + if((HIWORD(wParam) == 0xffff && lParam == 0) || + (HIWORD(wParam) & MF_POPUP)) { + /* the menu was closed */ + khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, NULL); + } else { + khui_action * act; + int id; + wchar_t buf[MAX_RES_STRING] = L""; + + id = LOWORD(wParam); + act = khui_find_action(id); + if(act == NULL || (act->is_tooltip == 0 && act->tooltip == NULL)) + khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, NULL); + else { + khm_get_action_tooltip(act->cmd, buf, sizeof(buf)); + + khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, buf); + } + } + return 0; +} + +HHOOK mm_hevt_hook = NULL; +HWND mm_hwnd_menu_panel = NULL; + +LRESULT CALLBACK mm_event_filter(int code, + WPARAM wParam, + LPARAM lParam) { + MSG * m; + RECT r; + int x,y; + + if (code == MSGF_MENU) { + /* do stuff */ + m = (MSG *) lParam; + GetWindowRect(khui_main_menu_toolbar, &r); + + if (m->hwnd != khm_hwnd_main) + mm_hwnd_menu_panel = m->hwnd; + + switch(m->message) { + case WM_MOUSEMOVE: + + x = GET_X_LPARAM(m->lParam); + y = GET_Y_LPARAM(m->lParam); + x -= r.left; + y -= r.top; + + SendMessage(khui_main_menu_toolbar, + m->message, + m->wParam, + MAKELPARAM(x,y)); + break; + } + } + + return CallNextHookEx(mm_hevt_hook, code, wParam, lParam); +} + + +void mm_begin_hot_track(void) { + + if (mm_hevt_hook) + UnhookWindowsHookEx(mm_hevt_hook); + + mm_hevt_hook = SetWindowsHookEx(WH_MSGFILTER, + mm_event_filter, + NULL, + GetCurrentThreadId()); +} + +void mm_end_hot_track(void) { + if (mm_hevt_hook) + UnhookWindowsHookEx(mm_hevt_hook); + + mm_hevt_hook = NULL; + mm_hwnd_menu_panel = NULL; +} + +void mm_cancel_menu(void) { + if (mm_hwnd_menu_panel) + SendMessage(mm_hwnd_menu_panel, WM_CANCELMODE, 0, 0); +} + +LRESULT khm_menu_notify_main(LPNMHDR notice) { + LPNMTOOLBAR nmt; + LRESULT ret = FALSE; + RECT r; + khui_menu_def * mmdef; + khui_action_ref * mm; + int nmm; + + mmdef = khui_find_menu(KHUI_MENU_MAIN); + mm = mmdef->items; + nmm = (int) khui_action_list_length(mm); + + GetWindowRect(khui_main_menu_toolbar, &r); + + nmt = (LPNMTOOLBAR) notice; + switch(notice->code) { + case TBN_DROPDOWN: + khm_track_menu(-1); + /* + khm_menu_show_panel(nmt->iItem, + r.left + nmt->rcButton.left, + r.top + nmt->rcButton.bottom); + */ + ret = TBDDRET_DEFAULT; + break; + + case TBN_HOTITEMCHANGE: + { + LPNMTBHOTITEM nmhi; + int new_item = -1; + + nmhi = (LPNMTBHOTITEM) notice; + + if(nmhi->dwFlags & HICF_LEAVING) + new_item = -1; + else { + int i; + for(i=0; i < nmm; i++) { + if(mm[i].action == nmhi->idNew) { + new_item = i; + break; + } + } + } + + if (mm_hot_track && + new_item != mm_last_hot_item && + new_item != -1 && + mm_last_hot_item != -1) { + + EndMenu(); + mm_next_hot_item = new_item; + + } + + ret = 0; + + if (!mm_hot_track || new_item != -1) + mm_last_hot_item = new_item; + + } break; + + default: + /* hmm. what to do */ + ret = FALSE; + } + return ret; +} + +struct identity_action_map { + khm_handle identity; + khm_int32 renew_cmd; + khm_int32 destroy_cmd; + khm_int32 new_cmd; + int refreshcycle; +}; + +#define IDMAP_ALLOC_INCR 8 + +struct identity_action_map * id_action_map = NULL; +khm_size n_id_action_map = 0; +khm_size nc_id_action_map = 0; + +int idcmd_refreshcycle = 0; + +static struct identity_action_map * +create_identity_cmd_map(khm_handle ident) { + + struct identity_action_map * actmap; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t fmt[128]; + wchar_t caption[KHUI_MAXCCH_SHORT_DESC]; + wchar_t tooltip[KHUI_MAXCCH_SHORT_DESC]; + wchar_t actionname[KHUI_MAXCCH_NAME]; + khm_size cb; + + if (n_id_action_map + 1 > nc_id_action_map) { + nc_id_action_map = UBOUNDSS(n_id_action_map + 1, + IDMAP_ALLOC_INCR, + IDMAP_ALLOC_INCR); +#ifdef DEBUG + assert(nc_id_action_map > n_id_action_map + 1); +#endif + id_action_map = PREALLOC(id_action_map, + nc_id_action_map * sizeof(id_action_map[0])); +#ifdef DEBUG + assert(id_action_map); +#endif + ZeroMemory(&id_action_map[n_id_action_map], + sizeof(id_action_map[0]) * (nc_id_action_map - n_id_action_map)); + } + + actmap = &id_action_map[n_id_action_map]; + n_id_action_map++; + + cb = sizeof(idname); + kcdb_identity_get_name(ident, idname, &cb); + + actmap->identity = ident; + kcdb_identity_hold(ident); + +#define GETFORMAT(I) do { fmt[0] = L'\0'; LoadString(khm_hInstance, I, fmt, ARRAYLENGTH(fmt)); } while(0) +#define EXPFORMAT(d,s) do { StringCbPrintf(d, sizeof(d), fmt, s); } while(0) + /* renew */ + + GETFORMAT(IDS_IDACTIONT_RENEW); + EXPFORMAT(tooltip, idname); + + GETFORMAT(IDS_IDACTION_RENEW); + EXPFORMAT(caption, idname); + + StringCbPrintf(actionname, sizeof(actionname), L"R:%s", idname); + + actmap->renew_cmd = + khui_action_create(actionname, caption, tooltip, NULL, + KHUI_ACTIONTYPE_TRIGGER, NULL); + + /* destroy */ + + GETFORMAT(IDS_IDACTIONT_DESTROY); + EXPFORMAT(tooltip, idname); + + GETFORMAT(IDS_IDACTION_DESTROY); + EXPFORMAT(caption, idname); + + StringCbPrintf(actionname, sizeof(actionname), L"D:%s", idname); + + actmap->destroy_cmd = + khui_action_create(actionname, caption, tooltip, NULL, + KHUI_ACTIONTYPE_TRIGGER, NULL); + + /* new */ + + GETFORMAT(IDS_IDACTIONT_NEW); + EXPFORMAT(tooltip, idname); + + GETFORMAT(IDS_IDACTION_NEW); + EXPFORMAT(caption, idname); + + StringCbPrintf(actionname, sizeof(actionname), L"N:%s", idname); + + actmap->new_cmd = + khui_action_create(actionname, caption, tooltip, NULL, + KHUI_ACTIONTYPE_TRIGGER, NULL); + + actmap->refreshcycle = idcmd_refreshcycle; + +#undef GETFORMAT +#undef EXPFORMAT + + return actmap; +} + +static void +purge_identity_cmd_map(void) { + khm_size i; + + for (i=0; i < n_id_action_map; i++) { + khm_handle ident; + + if (id_action_map[i].refreshcycle != idcmd_refreshcycle) { + ident = id_action_map[i].identity; + id_action_map[i].identity = NULL; + kcdb_identity_release(ident); + + khui_action_delete(id_action_map[i].renew_cmd); + khui_action_delete(id_action_map[i].destroy_cmd); + + id_action_map[i].renew_cmd = 0; + id_action_map[i].destroy_cmd = 0; + } + } +} + +static struct identity_action_map * +get_identity_cmd_map(khm_handle ident) { + khm_size i; + + for (i=0; i < n_id_action_map; i++) { + if (kcdb_identity_is_equal(id_action_map[i].identity, + ident)) + break; + } + + if (i < n_id_action_map) { + id_action_map[i].refreshcycle = idcmd_refreshcycle; + return &id_action_map[i]; + } else { + return create_identity_cmd_map(ident); + } +} + +khm_int32 +khm_get_identity_renew_action(khm_handle ident) { + struct identity_action_map * map; + + map = get_identity_cmd_map(ident); + + if (map) + return map->renew_cmd; + else + return 0; +} + +khm_int32 +khm_get_identity_destroy_action(khm_handle ident) { + struct identity_action_map * map; + + map = get_identity_cmd_map(ident); + + if (map) + return map->destroy_cmd; + else + return 0; +} + +khm_int32 +khm_get_identity_new_creds_action(khm_handle ident) { + struct identity_action_map * map; + + map = get_identity_cmd_map(ident); + + if (map) + return map->new_cmd; + else + return 0; +} + +void +khm_refresh_identity_menus(void) { + khui_menu_def * renew_def = NULL; + khui_menu_def * dest_def = NULL; + wchar_t * idlist = NULL; + wchar_t * idname = NULL; + khm_size cb = 0; + khm_size n_idents = 0; + khm_size t; + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_handle csp_cw = NULL; + khm_int32 idflags; + khm_int32 def_sticky = 0; + khm_boolean sticky_done = FALSE; + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", 0, &csp_cw))) { + khc_read_int32(csp_cw, L"DefaultSticky", &def_sticky); + khc_close_space(csp_cw); + csp_cw = NULL; + } + + kcdb_identity_refresh_all(); + + khui_action_lock(); + + idcmd_refreshcycle++; + + do { + if (idlist) + PFREE(idlist); + idlist = NULL; + cb = 0; + + rv = kcdb_identity_enum(KCDB_IDENT_FLAG_ACTIVE | KCDB_IDENT_FLAG_EMPTY, + KCDB_IDENT_FLAG_ACTIVE, + NULL, + &cb, + &n_idents); + if (rv != KHM_ERROR_TOO_LONG || cb == 0 || cb == sizeof(wchar_t) * 2) + break; + + idlist = PMALLOC(cb); +#ifdef DEBUG + assert(idlist); +#endif + + rv = kcdb_identity_enum(KCDB_IDENT_FLAG_ACTIVE | KCDB_IDENT_FLAG_EMPTY, + KCDB_IDENT_FLAG_ACTIVE, + idlist, + &cb, + &n_idents); + if (rv == KHM_ERROR_TOO_LONG) + continue; + + if (KHM_FAILED(rv)) { + /* something else went wrong. hmm. */ + if (idlist) + PFREE(idlist); + idlist = NULL; + } + break; + + } while(TRUE); + + if (idlist != NULL && n_idents > 0) { + khui_enable_action(KHUI_MENU_RENEW_CRED, TRUE); + khui_enable_action(KHUI_MENU_DESTROY_CRED, TRUE); + khui_enable_action(KHUI_ACTION_RENEW_CRED, TRUE); + khui_enable_action(KHUI_ACTION_DESTROY_CRED, TRUE); + } else { + khui_enable_action(KHUI_MENU_RENEW_CRED, FALSE); + khui_enable_action(KHUI_MENU_DESTROY_CRED, FALSE); + khui_enable_action(KHUI_ACTION_RENEW_CRED, FALSE); + khui_enable_action(KHUI_ACTION_DESTROY_CRED, FALSE); + } + + renew_def = khui_find_menu(KHUI_MENU_RENEW_CRED); + dest_def = khui_find_menu(KHUI_MENU_DESTROY_CRED); +#ifdef DEBUG + assert(renew_def); + assert(dest_def); +#endif + + t = khui_menu_get_size(renew_def); + while(t) { + khui_menu_remove_action(renew_def, 0); + t--; + } + + t = khui_menu_get_size(dest_def); + while(t) { + khui_menu_remove_action(dest_def, 0); + t--; + } + + if (idlist != NULL && n_idents > 1) { + khui_menu_insert_action(renew_def, 0, KHUI_ACTION_RENEW_ALL, 0); + khui_menu_insert_action(renew_def, 1, KHUI_MENU_SEP, 0); + + khui_menu_insert_action(dest_def, 0, KHUI_ACTION_DESTROY_ALL, 0); + khui_menu_insert_action(dest_def, 1, KHUI_MENU_SEP, 0); + } + + for (idname = idlist; idname && idname[0]; + idname = multi_string_next(idname)) { + khm_handle identity = NULL; + + if (KHM_FAILED(kcdb_identity_create(idname, 0, &identity))) { +#ifdef DEBUG + assert(FALSE); +#endif + continue; + } + + khui_menu_insert_action(renew_def, 1000, + khm_get_identity_renew_action(identity), + 0); + + khui_menu_insert_action(dest_def, 1000, + khm_get_identity_destroy_action(identity), + 0); + + idflags = 0; + kcdb_identity_get_flags(identity, &idflags); + + if (!(idflags & KCDB_IDENT_FLAG_STICKY) && def_sticky) { + kcdb_identity_set_flags(identity, + KCDB_IDENT_FLAG_STICKY, + KCDB_IDENT_FLAG_STICKY); + sticky_done = TRUE; + } + } + + if (idlist) + PFREE(idlist); + + purge_identity_cmd_map(); + + khui_action_unlock(); + + khui_refresh_actions(); + + if (sticky_done) { + InvalidateRect(khm_hwnd_main_cred, NULL, TRUE); + } +} + +khm_boolean +khm_check_identity_menu_action(khm_int32 act_id) { + + if (act_id == KHUI_ACTION_DESTROY_ALL) { + khm_size i; + + for (i=0; i < n_id_action_map; i++) { + if (id_action_map[i].identity != NULL) { + khm_cred_destroy_identity(id_action_map[i].identity); + } + } + + return TRUE; + } else if (act_id == KHUI_ACTION_RENEW_ALL) { + khm_size i; + + for (i=0; i < n_id_action_map; i++) { + if (id_action_map[i].identity != NULL) { + khm_cred_renew_identity(id_action_map[i].identity); + } + } + + return TRUE; + } else { + khm_size i; + + for (i=0; i < n_id_action_map; i++) { + if (id_action_map[i].identity == NULL) + continue; + + if (id_action_map[i].renew_cmd == act_id) { + khm_cred_renew_identity(id_action_map[i].identity); + return TRUE; + } + + if (id_action_map[i].destroy_cmd == act_id) { + khm_cred_destroy_identity(id_action_map[i].identity); + return TRUE; + } + + if (id_action_map[i].new_cmd == act_id) { + khm_cred_obtain_new_creds_for_ident(id_action_map[i].identity, + NULL); + return TRUE; + } + } + } + + return FALSE; +} + + +HMENU khui_hmenu_main = NULL; + +void khm_menu_refresh_items(void) { + khui_menu_def * def; + + if (!khui_hmenu_main) + return; + + khui_action_lock(); + + def = khui_find_menu(KHUI_MENU_MAIN); + + refresh_menu(khui_hmenu_main, def); + + khui_action_unlock(); + + DrawMenuBar(khm_hwnd_main); +} + +void khm_menu_create_main(HWND parent) { + HMENU hmenu; + khui_menu_def * def; + + def = khui_find_menu(KHUI_MENU_MAIN); + + hmenu = mm_create_menu_from_def(def, TRUE); + + SetMenu(parent, hmenu); + + khui_hmenu_main = hmenu; + + return; + +#ifdef USE_EXPLORER_STYLE_MENU_BAR + HWND hwtb; + REBARBANDINFO rbi; + SIZE sz; + int i; + khui_menu_def * mmdef; + khui_action_ref * mm; + int nmm; + + mmdef = khui_find_menu(KHUI_MENU_MAIN); + mm = mmdef->items; + nmm = (int) khui_action_list_length(mm); + + hwtb = CreateWindowEx(0 +#if (_WIN32_IE >= 0x0501) + | TBSTYLE_EX_MIXEDBUTTONS +#endif + , + TOOLBARCLASSNAME, + (LPWSTR) NULL, + WS_CHILD | + CCS_ADJUSTABLE | + TBSTYLE_FLAT | + TBSTYLE_AUTOSIZE | + TBSTYLE_LIST | + CCS_NORESIZE | + CCS_NOPARENTALIGN | + CCS_NODIVIDER, + 0, 0, 0, 0, rebar, + (HMENU) NULL, khm_hInstance, + NULL); + + if(!hwtb) { +#ifdef DEBUG + assert(FALSE); +#endif + return; + } + + khui_main_menu_toolbar = hwtb; + + SendMessage(hwtb, + TB_BUTTONSTRUCTSIZE, + (WPARAM) sizeof(TBBUTTON), + 0); + + for(i=0; i -#include - -#define KHUI_NOTIFIER_CLASS L"KhuiNotifierMsgWindowClass" -#define KHUI_ALERTER_CLASS L"KhuiAlerterWindowClass" -#define KHUI_ALERTBIN_CLASS L"KhuiAlertBinWindowClass" - -#define KHUI_NOTIFIER_WINDOW L"KhuiNotifierMsgWindow" - - -/* The commands that are available as default actions when the user - clicks the notification icon. */ - -khm_int32 khm_notifier_actions[] = { - KHUI_ACTION_OPEN_APP, - KHUI_ACTION_NEW_CRED -}; - -khm_size n_khm_notifier_actions = ARRAYLENGTH(khm_notifier_actions); - -/* notifier message for notification icon */ -#define KHUI_WM_NOTIFIER WM_COMMAND - -#define DRAWTEXTOPTIONS (DT_CALCRECT | DT_NOPREFIX | DT_WORDBREAK) - -/* are we showing an alert? */ -#define ALERT_DISPLAYED() (balloon_alert != NULL || khui_alert_windows != NULL) - -/* Forward declarations */ - -struct tag_alerter_wnd_data; -typedef struct tag_alerter_wnd_data alerter_wnd_data; - -struct tag_alert_list; -typedef struct tag_alert_list alert_list; - -static khm_int32 -alert_show(khui_alert * a); - -static khm_int32 -alert_show_minimized(khui_alert * a); - -static khm_int32 -alert_show_normal(khui_alert * a); - -static khm_int32 -alert_show_list(alert_list * alist); - -static khm_int32 -alert_enqueue(khui_alert * a); - -static khm_boolean -alert_is_equal(khui_alert * a1, khui_alert * a2); - -static void -check_for_queued_alerts(void); - -static void -show_queued_alerts(void); - -static khm_int32 -alert_consolidate(alert_list * alist, - khui_alert * alert, - khm_boolean add_from_queue); - -static khm_int32 -get_default_notifier_action(void); - -/* Globals */ - -/* window class registration atom for message only notifier window - class */ -ATOM atom_notifier = 0; - -/* window class registration atom for alert windows */ -ATOM atom_alerter = 0; -/* window class registration atom for the alert "bin", which is the - window that holds all the alerts. */ -ATOM atom_alert_bin = 0; - -/* notifier message window */ -HWND hwnd_notifier = NULL; - -BOOL notifier_ready = FALSE; - -/* The list of alert windows currently active */ -alerter_wnd_data * khui_alert_windows = NULL; - -/* Notification icon for when there are no alerts to be displayed */ -int iid_normal = IDI_NOTIFY_NONE; - -/* The alert currently being displayed in a balloon */ -khui_alert * balloon_alert = NULL; - -/********************************************************************** - Alert Queue - - The alert queue is the data structure that keeps track of all the - alerts that are waiting to be displayed. Alerts will be placed on - the queue if they cannot be immediately displayed for some reason - (e.g. another alert is being displayed, or the user is working in - another window). -***********************************************************************/ - -#define KHUI_ALERT_QUEUE_MAX 64 - -khui_alert * alert_queue[KHUI_ALERT_QUEUE_MAX]; -khm_int32 alert_queue_head = 0; -khm_int32 alert_queue_tail = 0; - -#define is_alert_queue_empty() (alert_queue_head == alert_queue_tail) -#define is_alert_queue_full() (((alert_queue_tail + 1) % KHUI_ALERT_QUEUE_MAX) == alert_queue_head) - -/* NOTE: the alert queue functions are unsafe to call from any thread - other than the UI thread. */ - -static void -alert_queue_put_alert(khui_alert * a) { - if (is_alert_queue_full()) return; - alert_queue[alert_queue_tail++] = a; - khui_alert_hold(a); - alert_queue_tail %= KHUI_ALERT_QUEUE_MAX; -} - -/* the caller needs to release the alert that's returned */ -static khui_alert * -alert_queue_get_alert(void) { - khui_alert * a; - - if (is_alert_queue_empty()) return NULL; - a = alert_queue[alert_queue_head++]; - alert_queue_head %= KHUI_ALERT_QUEUE_MAX; - - return a; /* held */ -} - -static int -alert_queue_get_size(void) { - if (is_alert_queue_empty()) - return 0; - - if (alert_queue_tail < alert_queue_head) { - return (alert_queue_tail + KHUI_ALERT_QUEUE_MAX - alert_queue_head); - } else { - return alert_queue_tail - alert_queue_head; - } -} - -static khui_alert * -alert_queue_get_alert_by_pos(int pos) { - khui_alert * a; - - if (is_alert_queue_empty() || - pos >= alert_queue_get_size() || - pos < 0) { - return NULL; - } - - a = alert_queue[(alert_queue_head + pos) % KHUI_ALERT_QUEUE_MAX]; - if (a) { - khui_alert_hold(a); - } - return a; -} - -static int -alert_queue_delete_alert(khui_alert * a) { - int idx; - int succ; - - idx = alert_queue_head; - while(idx != alert_queue_tail) { - if (alert_queue[idx] == a) - break; - - idx = (idx + 1) % KHUI_ALERT_QUEUE_MAX; - } - - if (idx == alert_queue_tail) - return 0; - -#ifdef DEBUG - assert(alert_queue[idx]); -#endif - khui_alert_release(alert_queue[idx]); - - succ = (idx + 1) % KHUI_ALERT_QUEUE_MAX; - while(succ != alert_queue_tail) { - alert_queue[idx] = alert_queue[succ]; - - succ = (succ + 1) % KHUI_ALERT_QUEUE_MAX; - idx = (idx + 1) % KHUI_ALERT_QUEUE_MAX; - } - - alert_queue_tail = idx; - return 1; -} - -/* the caller needs to release the alert that's returned */ -static khui_alert * -alert_queue_peek(void) { - khui_alert * a; - - if (is_alert_queue_empty()) - return NULL; - - a = alert_queue[alert_queue_head]; - khui_alert_hold(a); - - return a; -} - -/********************************************************************** - Alert List - - A list of alerts. Currently has a fixed upper limit, but the limit - is high enough for now. -***********************************************************************/ - -typedef struct tag_alert_list { - khui_alert * alerts[KHUI_ALERT_QUEUE_MAX]; - int n_alerts; - wchar_t title[KHUI_MAXCCH_TITLE]; -} alert_list; - -static void -alert_list_init(alert_list * alist) { - ZeroMemory(alist, sizeof(*alist)); -} - -static void -alert_list_set_title(alert_list * alist, wchar_t * title) { - StringCbCopy(alist->title, sizeof(alist->title), title); -} - -static khm_int32 -alert_list_add_alert(alert_list * alist, - khui_alert * alert) { - - if (alist->n_alerts == ARRAYLENGTH(alist->alerts)) - return KHM_ERROR_NO_RESOURCES; - - khui_alert_hold(alert); - alist->alerts[alist->n_alerts++] = alert; - - return KHM_ERROR_SUCCESS; -} - -static void -alert_list_destroy(alert_list * alist) { - int i; - - for (i=0; i < alist->n_alerts; i++) { - if (alist->alerts[i] != NULL) { - khui_alert_release(alist->alerts[i]); - alist->alerts[i] = NULL; - } - } - - alist->n_alerts = 0; -} - - -/********************************************************************** - Notifier Window - - The notifier window manages the notification icon and handles - KMSG_ALERT messages sent from the UI library. The window will exist - for the lifetime of the application. -***********************************************************************/ - -/* These are defined for APPVER >= 0x501. We are defining them here - so that we can build with APPVER = 0x500 and use the same binaries - with Win XP. */ - -#ifndef NIN_BALLOONSHOW -#define NIN_BALLOONSHOW (WM_USER + 2) -#endif - -#ifndef NIN_BALLOONHIDE -#define NIN_BALLOONHIDE (WM_USER + 3) -#endif - -#ifndef NIN_BALLOONTIMEOUT -#define NIN_BALLOONTIMEOUT (WM_USER + 4) -#endif - -#ifndef NIN_BALLOONUSERCLICK -#define NIN_BALLOONUSERCLICK (WM_USER + 5) -#endif - - -static LRESULT CALLBACK -notifier_wnd_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - kmq_message * m; - khm_int32 rv; - - if(uMsg == KMQ_WM_DISPATCH) { - kmq_wm_begin(lParam, &m); - rv = KHM_ERROR_SUCCESS; - - if(m->type == KMSG_ALERT) { - /* handle notifier messages */ - switch(m->subtype) { - case KMSG_ALERT_SHOW: - { - khui_alert * a; - - a = (khui_alert *) m->vparam; -#ifdef DEBUG - assert(a != NULL); -#endif - rv = alert_show(a); - khui_alert_release(a); - } - break; - - case KMSG_ALERT_QUEUE: - { - khui_alert * a; - - a = (khui_alert *) m->vparam; -#ifdef DEBUG - assert(a != NULL); -#endif - rv = alert_enqueue(a); - khui_alert_release(a); - } - break; - - case KMSG_ALERT_CHECK_QUEUE: - check_for_queued_alerts(); - break; - - case KMSG_ALERT_SHOW_QUEUED: - show_queued_alerts(); - break; - - case KMSG_ALERT_SHOW_MODAL: - { - khui_alert * a; - - a = (khui_alert *) m->vparam; -#ifdef DEBUG - assert(a != NULL); -#endif - khui_alert_lock(a); - a->flags |= KHUI_ALERT_FLAG_MODAL; - khui_alert_unlock(a); - - rv = alert_show(a); - - if (KHM_SUCCEEDED(rv)) { - khm_message_loop_int(&a->displayed); - } - - khui_alert_release(a); - } - break; - } - } else if (m->type == KMSG_CRED && - m->subtype == KMSG_CRED_ROOTDELTA) { - - KillTimer(hwnd, KHUI_REFRESH_TIMER_ID); - SetTimer(hwnd, KHUI_REFRESH_TIMER_ID, - KHUI_REFRESH_TIMEOUT, - NULL); - - } - - return kmq_wm_end(m, rv); - } else if (uMsg == KHUI_WM_NOTIFIER) { - /* Handle events generated from the notification icon */ - - /* wParam is the identifier of the notify icon, but we only - have one. */ - switch(lParam) { - case WM_CONTEXTMENU: - { - POINT pt; - int menu_id; - khui_menu_def * mdef; - khui_action_ref * act; - khm_size i, n; - khm_int32 def_cmd; - - /* before we show the context menu, we need to make - sure that the default action for the notification - icon is present in the menu and that it is marked - as the default. */ - - def_cmd = get_default_notifier_action(); - - if (khm_is_main_window_visible()) { - menu_id = KHUI_MENU_ICO_CTX_NORMAL; - - if (def_cmd == KHUI_ACTION_OPEN_APP) - def_cmd = KHUI_ACTION_CLOSE_APP; - } else { - menu_id = KHUI_MENU_ICO_CTX_MIN; - } - - mdef = khui_find_menu(menu_id); - -#ifdef DEBUG - assert(mdef); -#endif - n = khui_menu_get_size(mdef); - for (i=0; i < n; i++) { - act = khui_menu_get_action(mdef, i); - if (!(act->flags & KHUI_ACTIONREF_PACTION) && - (act->action == def_cmd)) - break; - } - - if (i < n) { - if (!(act->flags & KHUI_ACTIONREF_DEFAULT)) { - khui_menu_remove_action(mdef, i); - khui_menu_insert_action(mdef, i, def_cmd, KHUI_ACTIONREF_DEFAULT); - } else { - /* we are all set */ - } - } else { - /* the default action was not found on the context - menu */ -#ifdef DEBUG - assert(FALSE); -#endif - khui_menu_insert_action(mdef, 0, def_cmd, KHUI_ACTIONREF_DEFAULT); - } - - SetForegroundWindow(khm_hwnd_main); - - GetCursorPos(&pt); - khm_menu_show_panel(menu_id, pt.x, pt.y); - - PostMessage(khm_hwnd_main, WM_NULL, 0, 0); - } - break; - - case NIN_SELECT: - /* fall through */ - case NIN_KEYSELECT: - /* If there were any alerts waiting to be shown, we show - them. Otherwise we perform the default action. */ - khm_notify_icon_activate(); - break; - - case NIN_BALLOONUSERCLICK: - if (balloon_alert) { - khui_alert * a; - - khm_notify_icon_change(KHERR_NONE); - - a = balloon_alert; - balloon_alert = NULL; - - khui_alert_lock(a); - a->displayed = FALSE; - - if ((a->flags & KHUI_ALERT_FLAG_DEFACTION) && - !(a->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW) && - a->n_alert_commands > 0) { - PostMessage(khm_hwnd_main, WM_COMMAND, - MAKEWPARAM(a->alert_commands[0], - 0), - 0); - } else if (a->flags & - KHUI_ALERT_FLAG_REQUEST_WINDOW) { - khm_show_main_window(); - alert_show_normal(a); - } - - khui_alert_unlock(a); - khui_alert_release(a); - } else { -#ifdef DEBUG - assert(FALSE); -#endif - } - break; - - case NIN_BALLOONHIDE: - case NIN_BALLOONTIMEOUT: - khm_notify_icon_change(KHERR_NONE); - if (balloon_alert) { - khui_alert * a; - a = balloon_alert; - balloon_alert = NULL; - - khui_alert_lock(a); - a->displayed = FALSE; - khui_alert_unlock(a); - - khui_alert_release(a); - } - break; - } - } else if (uMsg == WM_TIMER) { - if (wParam == KHUI_TRIGGER_TIMER_ID) { - KillTimer(hwnd, KHUI_TRIGGER_TIMER_ID); - khm_timer_fire(hwnd); - } else if (wParam == KHUI_REFRESH_TIMER_ID) { - KillTimer(hwnd, KHUI_REFRESH_TIMER_ID); - kcdb_identity_refresh_all(); - khm_timer_refresh(hwnd); - } - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -ATOM -khm_register_notifier_wnd_class(void) -{ - WNDCLASSEX wcx; - - ZeroMemory(&wcx, sizeof(wcx)); - - wcx.cbSize = sizeof(wcx); - wcx.style = 0; - wcx.lpfnWndProc = notifier_wnd_proc; - wcx.cbClsExtra = 0; - wcx.cbWndExtra = 0; - wcx.hInstance = khm_hInstance; - wcx.hIcon = NULL; - wcx.hCursor = NULL; - wcx.hbrBackground = NULL; - wcx.lpszMenuName = NULL; - wcx.lpszClassName = KHUI_NOTIFIER_CLASS; - wcx.hIconSm = NULL; - - atom_notifier = RegisterClassEx(&wcx); - - return atom_notifier; -} - -/********************************************************************* - Alerter -**********************************************************************/ - -typedef struct tag_alerter_alert_data { - khui_alert * alert; - - BOOL seen; /* has the user seen this alert? */ - - BOOL has_commands; /* we cache the value here. otherwise - we'll have to get a lock on the - alert each time we have to find out - whether there are any commands for - this alert. */ - - RECT r_alert; /* the entire alert, relative to self. */ - - /* the following rects are relative to the top left of r_alert. */ - - RECT r_title; /* the title. deflate by padding to - get the text rect. */ - RECT r_icon; /* rect for icon */ - RECT r_message; /* rect for the text. no padding - necessary. */ - RECT r_suggestion; /* rect for the suggestion. deflate - by padding to get the suggestion - rect. The suggestion rect includes - space for the small icon on the - left and padding between the icon - and the text. The size of the small - icon are as per system metrics - SM_C{X,Y}SMICON. Padding is - s_pad.cx vertical. */ - - int n_cmd_buttons; /* number of command buttons in this alert. */ - - RECT r_buttons[KHUI_MAX_ALERT_COMMANDS]; - /* rects for the command buttons. */ - - HWND hwnd_buttons[KHUI_MAX_ALERT_COMMANDS]; - /* handles for the command buttons */ - - HWND hwnd_marker; - /* handle to the marker window used as - a tab-stop target when there are - not buttons associated with the - alert. */ - - LDCL(struct tag_alerter_alert_data); -} alerter_alert_data; - -typedef struct tag_alerter_wnd_data { - HWND hwnd; - HFONT hfont; - - wchar_t caption[KHUI_MAXCCH_TITLE]; /* the original - caption for the - dialog. */ - - HWND hw_bin; - HWND hw_scroll; - HWND hw_close; - - int scroll_top; - - int n_cmd_buttons; /* total number of command buttons - in all the alerts being shown in - this dialog. */ - - int c_alert; /* current selected alert. */ - - /* various metrics */ - /* calculated during WM_CREATE */ - SIZE s_button; /* minimum dimensions for command button */ - SIZE s_margin; - RECT r_text; /* only .left and .right are used. rest are 0 */ - RECT r_title; /* only .left, .right and .bottom are used. .top=0 */ - SIZE s_icon; - SIZE s_pad; - - int cx_wnd; - int cy_max_wnd; - - /* derived from the alert sizes */ - SIZE s_alerts; - - QDCL(alerter_alert_data); /* queue of alerts that are being - shown in this window. */ - - LDCL(struct tag_alerter_wnd_data); /* for adding to - khui_alert_windows list. */ - - int n_alerts; - -} alerter_wnd_data; - -#define NTF_PARAM DWLP_USER - -/* dialog sizes in base dialog units */ - -#define NTF_MARGIN 5 -#define NTF_WIDTH 200 -#define NTF_MAXHEIGHT 150 - -#define NTF_TITLE_X NTF_MARGIN -#define NTF_TITLE_WIDTH (NTF_WIDTH - NTF_MARGIN*2) -#define NTF_TITLE_HEIGHT 10 - -#define NTF_TEXT_PAD 2 - -#define NTF_BUTTON_HEIGHT 14 - -#define NTF_TIMEOUT 20000 - -#define ALERT_WINDOW_EX_SYLES (WS_EX_DLGMODALFRAME | WS_EX_CONTEXTHELP) -#define ALERT_WINDOW_STYLES (WS_DLGFRAME | WS_POPUPWINDOW | WS_CLIPCHILDREN | DS_NOIDLEMSG) - -/* Control ids */ -#define IDC_NTF_ALERTBIN 998 -#define IDC_NTF_CLOSE 999 - -#define IDC_NTF_CMDBUTTONS 1001 -#define IDC_FROM_IDX(alert, bn) ((alert) * (KHUI_MAX_ALERT_COMMANDS + 1) + (bn) + 1 + IDC_NTF_CMDBUTTONS) -#define ALERT_FROM_IDC(idc) (((idc) - IDC_NTF_CMDBUTTONS) / (KHUI_MAX_ALERT_COMMANDS + 1)) -#define BUTTON_FROM_IDC(idc) (((idc) - IDC_NTF_CMDBUTTONS) % (KHUI_MAX_ALERT_COMMANDS + 1) - 1) - -/* if the only command in an alert is "Close", we assume that the - alert has no commands. */ -#define ALERT_HAS_CMDS(a) ((a)->n_alert_commands > 1 || ((a)->n_alert_commands == 1 && (a)->alert_commands[0] != KHUI_PACTION_CLOSE)) - -#define SCROLL_LINE_SIZE(d) ((d)->cy_max_wnd / 12) - -static void -add_alert_to_wnd_data(alerter_wnd_data * d, - khui_alert * a) { - alerter_alert_data * aiter; - khm_boolean exists = 0; - - khui_alert_lock(a); - - /* check if the alert is already there */ - aiter = QTOP(d); - while(aiter && !exists) { - if (aiter->alert) { - khui_alert_lock(aiter->alert); - - if (alert_is_equal(aiter->alert, a)) { - exists = TRUE; - } - - khui_alert_unlock(aiter->alert); - } - - aiter = QNEXT(aiter); - } - - a->flags |= KHUI_ALERT_FLAG_DISPLAY_WINDOW; - - if (!exists) { - a->displayed = TRUE; - } - - khui_alert_unlock(a); - - if (!exists) { - alerter_alert_data * adata; - - adata = PMALLOC(sizeof(*adata)); - ZeroMemory(adata, sizeof(*adata)); - - adata->alert = a; - khui_alert_hold(a); - - QPUT(d, adata); - d->n_alerts ++; - } -} - -static alerter_wnd_data * -create_alerter_wnd_data(HWND hwnd, alert_list * l) { - alerter_wnd_data * d; - int i; - LONG dlgb; - - d = PMALLOC(sizeof(*d)); - ZeroMemory(d, sizeof(*d)); - - d->hwnd = hwnd; - - GetWindowText(hwnd, d->caption, ARRAYLENGTH(d->caption)); - - for (i=0; i < l->n_alerts; i++) { - add_alert_to_wnd_data(d, l->alerts[i]); - } - - d->n_alerts = l->n_alerts; - - LPUSH(&khui_alert_windows, d); - - /* Compute a few metrics first */ - - dlgb = GetDialogBaseUnits(); - -#define DLG2SCNX(x) MulDiv((x), LOWORD(dlgb), 4) -#define DLG2SCNY(y) MulDiv((y), HIWORD(dlgb), 8) - - d->cx_wnd = DLG2SCNX(NTF_WIDTH); - d->cy_max_wnd = DLG2SCNY(NTF_MAXHEIGHT); - - d->s_margin.cx = DLG2SCNX(NTF_MARGIN); - d->s_margin.cy = DLG2SCNY(NTF_MARGIN); - - d->r_title.left = DLG2SCNX(NTF_TITLE_X); - d->r_title.right = DLG2SCNX(NTF_TITLE_X + NTF_TITLE_WIDTH); - d->r_title.top = 0; - d->r_title.bottom = DLG2SCNY(NTF_TITLE_HEIGHT); - - d->s_pad.cx = DLG2SCNX(NTF_TEXT_PAD); - d->s_pad.cy = DLG2SCNY(NTF_TEXT_PAD); - - d->s_icon.cx = GetSystemMetrics(SM_CXICON); - d->s_icon.cy = GetSystemMetrics(SM_CYICON); - - d->r_text.left = d->s_margin.cx * 2 + d->s_icon.cx; - d->r_text.right = d->cx_wnd - d->s_margin.cx; - d->r_text.top = 0; - d->r_text.bottom = 0; - - d->s_button.cx = ((d->r_text.right - d->r_text.left) - (KHUI_MAX_ALERT_COMMANDS - 1) * d->s_margin.cx) / KHUI_MAX_ALERT_COMMANDS; - d->s_button.cy = DLG2SCNY(NTF_BUTTON_HEIGHT); - -#undef DLG2SCNX -#undef DLG2SCNY - - d->c_alert = -1; - - return d; -} - -static void -layout_alert(HDC hdc, alerter_wnd_data * d, - alerter_alert_data * adata) { - RECT r; - size_t len; - int y; - int icon_y; - -#ifdef DEBUG - assert(adata->alert); -#endif - - khui_alert_lock(adata->alert); - - y = 0; - - /* Title */ - - y += d->s_margin.cy; - - /* If there is a title and it differs from the title of the - alerter window, then we have to show the alert title - separately. */ - if (adata->alert->title && - wcscmp(adata->alert->title, d->caption)) { - - CopyRect(&adata->r_title, &d->r_title); - OffsetRect(&adata->r_title, 0, y); - - y = adata->r_title.bottom + d->s_margin.cy; - - } else { - - SetRectEmpty(&adata->r_title); - - } - - /* Icon */ - - SetRect(&adata->r_icon, d->s_margin.cx, y, - d->s_margin.cx + d->s_icon.cx, - y + d->s_icon.cy); - - icon_y = adata->r_icon.bottom + d->s_margin.cy; /* the bottom of the icon */ - - /* Message */ - - if (adata->alert->message && - SUCCEEDED(StringCchLength(adata->alert->message, - KHUI_MAXCCH_MESSAGE, - &len))) { - - CopyRect(&r, &d->r_text); - - DrawTextEx(hdc, adata->alert->message, (int) len, - &r, - DRAWTEXTOPTIONS, - NULL); - - OffsetRect(&r, 0, y); - CopyRect(&adata->r_message, &r); - - y = r.bottom + d->s_margin.cy; - - } else { - - SetRectEmpty(&adata->r_message); - - } - - /* Suggestion */ - - if (adata->alert->suggestion && - SUCCEEDED(StringCchLength(adata->alert->suggestion, - KHUI_MAXCCH_SUGGESTION, - &len))) { - int pad = d->s_pad.cx + GetSystemMetrics(SM_CXSMICON); - - CopyRect(&r, &d->r_text); - r.left += pad; - - DrawTextEx(hdc, adata->alert->suggestion, (int) len, - &r, - DRAWTEXTOPTIONS, - NULL); - - r.left -= pad; - - InflateRect(&r, d->s_pad.cx, d->s_pad.cy); - OffsetRect(&r, 0, -r.top + y); - CopyRect(&adata->r_suggestion, &r); - - y = r.bottom + d->s_margin.cy; - - } else { - - SetRectEmpty(&adata->r_suggestion); - - } - - y = max(y, icon_y); - - /* Buttons */ - - if (ALERT_HAS_CMDS(adata->alert)) { - khm_int32 i; - int x, width; - wchar_t caption[KHUI_MAXCCH_SHORT_DESC]; - size_t len; - SIZE s; - int skip_close; - - adata->has_commands = TRUE; - - if (d->n_alerts > 1) - skip_close = TRUE; - else - skip_close = FALSE; - - x = d->r_text.left; - -#ifdef DEBUG - assert(adata->alert->n_alert_commands <= KHUI_MAX_ALERT_COMMANDS); -#endif - - for (i=0; i < adata->alert->n_alert_commands; i++) { - - if (adata->alert->alert_commands[i] == KHUI_PACTION_CLOSE && skip_close) { - SetRectEmpty(&adata->r_buttons[i]); - continue; - } - - caption[0] = L'\0'; - len = 0; - khm_get_action_caption(adata->alert->alert_commands[i], - caption, sizeof(caption)); - StringCchLength(caption, ARRAYLENGTH(caption), &len); - - if (!GetTextExtentPoint32(hdc, caption, (int) len, &s)) { - width = d->s_button.cx; - } else { - width = s.cx + d->s_margin.cx * 2; - } - - if (width < d->s_button.cx) - width = d->s_button.cx; - else if (width > (d->r_text.right - d->r_text.left)) - width = d->r_text.right - d->r_text.left; - - if (x + width > d->r_text.right) { - /* new line */ - x = d->r_text.left; - y += d->s_button.cy + d->s_pad.cy; - } - - SetRect(&adata->r_buttons[i], x, y, x + width, y + d->s_button.cy); - - x += width + d->s_margin.cx; - } - - y += d->s_button.cy + d->s_margin.cy; - } - - khui_alert_unlock(adata->alert); - - /* Now set the rect for the whole alert */ - SetRect(&adata->r_alert, 0, 0, d->cx_wnd, y); - -} - -static void -pick_title_for_alerter_window(alerter_wnd_data * d) { - alerter_alert_data * adata; - wchar_t caption[KHUI_MAXCCH_TITLE]; - khm_boolean common_caption = TRUE; - khui_alert_type ctype = KHUI_ALERTTYPE_NONE; - khm_boolean common_type = TRUE; - - /* - If all the alerts have the same title, then we use the common - title. - - - If all the alerts are of the same type, then we pick a title - that is suitable for the type. - - - All else fails, we use a default caption for the window. - */ - - caption[0] = L'\0'; - adata = QTOP(d); - while (adata && (common_caption || common_type)) { - - if (adata->alert) { - khui_alert_lock(adata->alert); - - if (common_caption) { - if (caption[0] == L'\0') { - if (adata->alert->title) - StringCbCopy(caption, sizeof(caption), adata->alert->title); - } else if (adata->alert->title && - wcscmp(caption, adata->alert->title)) { - common_caption = FALSE; - } - } - - if (common_type) { - if (ctype == KHUI_ALERTTYPE_NONE) - ctype = adata->alert->alert_type; - else if (ctype != adata->alert->alert_type) - common_type = FALSE; - } - - khui_alert_unlock(adata->alert); - } - - adata = QNEXT(adata); - } - - /* just in case someone changes d->caption to a pointer from an - array */ -#ifdef DEBUG - assert(sizeof(d->caption) > sizeof(wchar_t *)); -#endif - - if (common_caption && caption[0] != L'\0') { - StringCbCopy(d->caption, sizeof(d->caption), caption); - } else if (common_type && ctype != KHUI_ALERTTYPE_NONE) { - switch(ctype) { - case KHUI_ALERTTYPE_PLUGIN: - LoadString(khm_hInstance, IDS_ALERTTYPE_PLUGIN, - d->caption, ARRAYLENGTH(d->caption)); - break; - - case KHUI_ALERTTYPE_EXPIRE: - LoadString(khm_hInstance, IDS_ALERTTYPE_EXPIRE, - d->caption, ARRAYLENGTH(d->caption)); - break; - - case KHUI_ALERTTYPE_RENEWFAIL: - LoadString(khm_hInstance, IDS_ALERTTYPE_RENEWFAIL, - d->caption, ARRAYLENGTH(d->caption)); - break; - - case KHUI_ALERTTYPE_ACQUIREFAIL: - LoadString(khm_hInstance, IDS_ALERTTYPE_ACQUIREFAIL, - d->caption, ARRAYLENGTH(d->caption)); - break; - - case KHUI_ALERTTYPE_CHPW: - LoadString(khm_hInstance, IDS_ALERTTYPE_CHPW, - d->caption, ARRAYLENGTH(d->caption)); - break; - - default: - LoadString(khm_hInstance, IDS_ALERT_DEFAULT, - d->caption, ARRAYLENGTH(d->caption)); - } - } else { - LoadString(khm_hInstance, IDS_ALERT_DEFAULT, - d->caption, ARRAYLENGTH(d->caption)); - } - - SetWindowText(d->hwnd, d->caption); -} - -static void -estimate_alerter_wnd_sizes(alerter_wnd_data * d) { - HDC hdc; - HFONT hf_old; - int height = 0; - - alerter_alert_data * adata; - - pick_title_for_alerter_window(d); - - hdc = GetDC(d->hwnd); -#ifdef DEBUG - assert(hdc); -#endif - - if (d->hfont == NULL) - d->hfont = (HFONT) GetStockObject(DEFAULT_GUI_FONT); - -#ifdef DEBUG - assert(d->hfont); -#endif - - hf_old = SelectFont(hdc, d->hfont); - - adata = QTOP(d); - while(adata) { - layout_alert(hdc, d, adata); - - height += adata->r_alert.bottom; - - adata = QNEXT(adata); - } - - SelectFont(hdc, hf_old); - ReleaseDC(d->hwnd, hdc); - - d->s_alerts.cx = d->cx_wnd; - d->s_alerts.cy = height; -} - -static void -layout_command_buttons(alerter_wnd_data * d) { - - alerter_alert_data * adata; - HDWP hdefer; - int y; - - hdefer = BeginDeferWindowPos(d->n_cmd_buttons); - - y = 0; - adata = QTOP(d); - while (adata) { - RECT r; - int i; - - if (!adata->has_commands) - goto done; - - for (i=0; i < adata->n_cmd_buttons; i++) { - if (IsRectEmpty(&adata->r_buttons[i])) { - /* the button is no longer needed */ - if (adata->hwnd_buttons[i] != NULL) { - DestroyWindow(adata->hwnd_buttons[i]); - adata->hwnd_buttons[i] = NULL; - } - - continue; - } - - if (adata->hwnd_buttons[i] == NULL) { - continue; - } - - CopyRect(&r, &adata->r_buttons[i]); - OffsetRect(&r, 0, y - d->scroll_top); - - DeferWindowPos(hdefer, - adata->hwnd_buttons[i], NULL, - r.left, r.top, 0, 0, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | - SWP_NOSIZE); - } - - done: - y += adata->r_alert.bottom; - adata = QNEXT(adata); - } - - EndDeferWindowPos(hdefer); -} - -static void -setup_alerter_window_controls(alerter_wnd_data * d) { - - RECT r_alerts; - RECT r_window; - RECT r_client; - RECT r_parent; - HWND hw_parent; - HWND hw_focus = NULL; - BOOL close_button = FALSE; - BOOL scrollbar = FALSE; - BOOL redraw_scollbar = FALSE; - - /* estimate_alerter_wnd_sizes() must be called before calling - this. */ -#ifdef DEBUG - assert(d->s_alerts.cy > 0); -#endif - - r_alerts.left = 0; - r_alerts.top = 0; - r_alerts.right = d->cx_wnd; - - if (d->s_alerts.cy > d->cy_max_wnd) { - - BOOL redraw = FALSE; - - r_alerts.right += GetSystemMetrics(SM_CXVSCROLL); - r_alerts.bottom = d->cy_max_wnd; - - CopyRect(&r_client, &r_alerts); - r_client.bottom += d->s_margin.cy + d->s_button.cy + d->s_pad.cy; - close_button = TRUE; - - if (d->scroll_top > d->s_alerts.cy - d->cy_max_wnd) - d->scroll_top = d->s_alerts.cy - d->cy_max_wnd; - - scrollbar = TRUE; - } else { - r_alerts.bottom = d->s_alerts.cy; - - CopyRect(&r_client, &r_alerts); - - if (d->n_alerts == 1) { - - if (!QTOP(d)->has_commands) { - r_client.bottom += d->s_margin.cy * 2 + d->s_button.cy; - close_button = TRUE; - } - - } else { - - r_client.bottom += d->s_margin.cy * 2 + d->s_button.cy; - close_button = TRUE; - } - - d->scroll_top = 0; - } - - if (d->hw_bin == NULL) { - d->hw_bin = CreateWindowEx(WS_EX_CONTROLPARENT, - MAKEINTATOM(atom_alert_bin), - L"Alert Container", - WS_CHILD | WS_CLIPCHILDREN | - WS_VISIBLE | - ((scrollbar)? WS_VSCROLL : 0), - r_alerts.left, r_alerts.top, - r_alerts.right - r_alerts.left, - r_alerts.bottom - r_alerts.top, - d->hwnd, - (HMENU) IDC_NTF_ALERTBIN, - khm_hInstance, - (LPVOID) d); - } else { - redraw_scollbar = TRUE; - SetWindowLongPtr(d->hw_bin, GWL_STYLE, - WS_CHILD | WS_CLIPCHILDREN | - WS_VISIBLE | - ((scrollbar)? WS_VSCROLL : 0)); - SetWindowPos(d->hw_bin, NULL, - r_alerts.left, r_alerts.top, - r_alerts.right - r_alerts.left, - r_alerts.bottom - r_alerts.top, - SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOACTIVATE); - } - - if (scrollbar) { - SCROLLINFO si; - - ZeroMemory(&si, sizeof(si)); - si.cbSize = sizeof(si); - si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; - si.nMin = 0; - si.nMax = d->s_alerts.cy; - si.nPage = d->cy_max_wnd; - si.nPos = d->scroll_top; - - SetScrollInfo(d->hw_bin, SB_VERT, &si, redraw_scollbar); - } - - /* create the action buttons */ - { - alerter_alert_data * adata; - int y; - int idx; - HWND last_window = HWND_TOP; - int n_buttons = 0; - - idx = 0; - y = - d->scroll_top; - adata = QTOP(d); - while(adata) { - if (adata->has_commands) { - int i; - wchar_t caption[KHUI_MAXCCH_SHORT_DESC]; - RECT r; - - if (adata->hwnd_marker) { - DestroyWindow(adata->hwnd_marker); - adata->hwnd_marker = NULL; - } - - khui_alert_lock(adata->alert); - - adata->n_cmd_buttons = adata->alert->n_alert_commands; - - for (i=0; i < adata->alert->n_alert_commands; i++) { - - n_buttons ++; - - if (IsRectEmpty(&adata->r_buttons[i])) { - /* this button is not necessary */ - if (adata->hwnd_buttons[i]) { - DestroyWindow(adata->hwnd_buttons[i]); - adata->hwnd_buttons[i] = NULL; - } - - continue; - } - - if (adata->hwnd_buttons[i] != NULL) { - /* already there */ - CopyRect(&r, &adata->r_buttons[i]); - OffsetRect(&r, 0, y); - - SetWindowPos(adata->hwnd_buttons[i], last_window, - r.left, r.top, - r.right - r.left, - r.bottom - r.top, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | - SWP_SHOWWINDOW); - - last_window = adata->hwnd_buttons[i]; - - if (hw_focus == NULL) - hw_focus = adata->hwnd_buttons[i]; - - continue; - } - - khm_get_action_caption(adata->alert->alert_commands[i], - caption, sizeof(caption)); - - CopyRect(&r, &adata->r_buttons[i]); - OffsetRect(&r, 0, y); - - adata->hwnd_buttons[i] = - CreateWindowEx(0, - L"BUTTON", - caption, - WS_CHILD | WS_TABSTOP | BS_NOTIFY, - r.left, r.top, - r.right - r.left, - r.bottom - r.top, - d->hw_bin, - (HMENU) (INT_PTR) IDC_FROM_IDX(idx, i), - khm_hInstance, - NULL); -#ifdef DEBUG - assert(adata->hwnd_buttons[i]); -#endif - - if (d->hfont) { - SendMessage(adata->hwnd_buttons[i], WM_SETFONT, - (WPARAM) d->hfont, FALSE); - } - - SetWindowPos(adata->hwnd_buttons[i], last_window, - 0, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | - SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); - - last_window = adata->hwnd_buttons[i]; - - if (hw_focus == NULL) - hw_focus = adata->hwnd_buttons[i]; - } - - khui_alert_unlock(adata->alert); - } else { - int i; - - /* Destroy any buttons that belong to the alert. We - might have some left over, if there were command - belonging to the alert that were ignored.*/ - - for (i=0; i < adata->n_cmd_buttons; i++) { - if (adata->hwnd_buttons[i]) { - DestroyWindow(adata->hwnd_buttons[i]); - adata->hwnd_buttons[i] = NULL; - } - } - - adata->n_cmd_buttons = 0; - - if (adata->hwnd_marker == NULL) { - adata->hwnd_marker = - CreateWindowEx(0, - L"BUTTON", - L"Marker", - WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_NOTIFY, - -10, 0, - 5, 5, - d->hw_bin, - (HMENU) (INT_PTR) IDC_FROM_IDX(idx, -1), - khm_hInstance, - NULL); -#ifdef DEBUG - assert(adata->hwnd_marker); -#endif - } - - SetWindowPos(adata->hwnd_marker, last_window, - 0, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | - SWP_NOMOVE | SWP_NOSIZE); - - last_window = adata->hwnd_marker; - - if (scrollbar) { - EnableWindow(adata->hwnd_marker, TRUE); - if (hw_focus == NULL) - hw_focus = adata->hwnd_marker; - } else { - EnableWindow(adata->hwnd_marker, FALSE); - } - } - - y += adata->r_alert.bottom; - adata = QNEXT(adata); - idx++; - } - - d->n_cmd_buttons = n_buttons; - } - - if (close_button) { - if (d->hw_close == NULL) { - wchar_t caption[256]; - - khm_get_action_caption(KHUI_PACTION_CLOSE, caption, sizeof(caption)); - - d->hw_close = CreateWindowEx(0, - L"BUTTON", - caption, - WS_CHILD | BS_DEFPUSHBUTTON | WS_TABSTOP | BS_NOTIFY, - 0,0,100,100, - d->hwnd, - (HMENU) IDC_NTF_CLOSE, - khm_hInstance, - NULL); - -#ifdef DEBUG - assert(d->hw_close); - assert(d->hfont); -#endif - if (d->hfont) - SendMessage(d->hw_close, WM_SETFONT, (WPARAM) d->hfont, FALSE); - } - - { - int x,y,width,height; - - x = d->r_text.left; - y = r_client.bottom - (d->s_margin.cy + d->s_button.cy); - width = d->s_button.cx; - height = d->s_button.cy; - - SetWindowPos(d->hw_close, NULL, - x, y, width, height, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | - SWP_SHOWWINDOW); - } - - if (hw_focus == NULL || d->n_cmd_buttons == 0) - hw_focus = d->hw_close; - - } else { - if (d->hw_close != NULL) { - DestroyWindow(d->hw_close); - d->hw_close = NULL; - } - } - - CopyRect(&r_window, &r_client); - AdjustWindowRectEx(&r_window, ALERT_WINDOW_STYLES, - FALSE, ALERT_WINDOW_EX_SYLES); - OffsetRect(&r_window, -r_window.left, -r_window.top); - - /* center the window above the parent window. */ - - hw_parent = GetWindow(d->hwnd, GW_OWNER); - GetWindowRect(hw_parent, &r_parent); - - { - int x,y; - - x = (r_parent.left + r_parent.right - (r_window.right - r_window.left)) / 2; - y = (r_parent.top + r_parent.bottom - (r_window.bottom - r_window.top)) / 2; - - SetWindowPos(d->hwnd, - HWND_TOP, - x, y, - r_window.right - r_window.left, - r_window.bottom - r_window.top, - SWP_SHOWWINDOW | SWP_NOOWNERZORDER); - } - - if (hw_focus != NULL) - PostMessage(d->hwnd, WM_NEXTDLGCTL, (WPARAM) hw_focus, MAKELPARAM(TRUE, 0)); -} - -static void -scroll_to_position(alerter_wnd_data * d, int new_pos, khm_boolean redraw_scrollbar) { - int delta; - SCROLLINFO si; - HWND hwnd = d->hw_bin; - - if (new_pos < 0) - new_pos = 0; - else if (new_pos > d->s_alerts.cy - d->cy_max_wnd) - new_pos = d->s_alerts.cy - d->cy_max_wnd; - - if (new_pos == d->scroll_top) - return; - - delta = d->scroll_top - new_pos; - - d->scroll_top -= delta; - - ScrollWindowEx(hwnd, 0, delta, - NULL, NULL, NULL, NULL, - SW_INVALIDATE | SW_ERASE); - - layout_command_buttons(d); - - ZeroMemory(&si, sizeof(si)); - - si.fMask = SIF_POS; - si.nPos = d->scroll_top; - - SetScrollInfo(hwnd, SB_VERT, &si, redraw_scrollbar); -} - -static void -select_alert(alerter_wnd_data * d, int alert) { - - int y; - RECT old_sel, new_sel; - alerter_alert_data * adata; - int idx; - - if (d->n_alerts == 1 || - alert < 0 || - alert > d->n_alerts || - d->c_alert == alert) - return; - - SetRectEmpty(&old_sel); - SetRectEmpty(&new_sel); - idx = 0; y = -d->scroll_top; - adata = QTOP(d); - while(adata && (idx <= d->c_alert || idx <= alert)) { - - if (idx == d->c_alert) { - CopyRect(&old_sel, &adata->r_alert); - OffsetRect(&old_sel, 0, y); - } - - if (idx == alert) { - CopyRect(&new_sel, &adata->r_alert); - OffsetRect(&new_sel, 0, y); - } - - y += adata->r_alert.bottom; - idx ++; - adata = QNEXT(adata); - } - - d->c_alert = alert; - if (!IsRectEmpty(&old_sel)) - InvalidateRect(d->hw_bin, &old_sel, TRUE); - if (!IsRectEmpty(&new_sel)) - InvalidateRect(d->hw_bin, &new_sel, TRUE); -} - -static void -ensure_command_is_visible(alerter_wnd_data * d, int id) { - int alert_idx; - int y = 0; - alerter_alert_data * adata; - int new_pos = 0; - - alert_idx = ALERT_FROM_IDC(id); - -#ifdef DEBUG - assert(alert_idx >= 0 && alert_idx < d->n_alerts); -#endif - if (alert_idx >= d->n_alerts || alert_idx < 0) - return; - - adata = QTOP(d); - while(adata && alert_idx > 0) { - y += adata->r_alert.bottom; - alert_idx--; - adata = QNEXT(adata); - } - -#ifdef DEBUG - assert(alert_idx == 0); - assert(adata); - assert(adata->alert); -#endif - if (adata == NULL || alert_idx != 0) - return; - - new_pos = d->scroll_top; - if (y < d->scroll_top) { - new_pos = y; - } else if (y + adata->r_alert.bottom > d->scroll_top + d->cy_max_wnd) { - new_pos = y + adata->r_alert.bottom - d->cy_max_wnd; - } - - if (new_pos != d->scroll_top) - scroll_to_position(d, new_pos, TRUE); - - select_alert(d, ALERT_FROM_IDC(id)); -} - -static void -handle_mouse_select(alerter_wnd_data * d, int mouse_x, int mouse_y) { - int y; - alerter_alert_data * adata; - - y = -d->scroll_top; - adata = QTOP(d); - while(adata) { - if (y <= mouse_y && (y + adata->r_alert.bottom) > mouse_y) { - HWND hw = NULL; - - if (adata->n_cmd_buttons > 0) - hw = adata->hwnd_buttons[0]; - else - hw = adata->hwnd_marker; - - if (hw && !IsWindowEnabled(hw)) - hw = GetNextDlgTabItem(d->hwnd, hw, FALSE); - - if (hw) - PostMessage(d->hwnd, WM_NEXTDLGCTL, (WPARAM) hw, MAKELPARAM(TRUE, 0)); - - return; - } - - y += adata->r_alert.bottom; - adata = QNEXT(adata); - } -} - -static void -process_command_button(alerter_wnd_data * d, int id) { - int alert_idx; - int cmd_idx; - khm_int32 flags = 0; - khm_int32 cmd = 0; - alerter_alert_data * adata; - int i; - - alert_idx = ALERT_FROM_IDC(id); - cmd_idx = BUTTON_FROM_IDC(id); - -#ifdef DEBUG - assert(alert_idx >= 0 && alert_idx < d->n_alerts); -#endif - if (alert_idx >= d->n_alerts || alert_idx < 0) - return; - - if (cmd_idx < 0) { - /* the user selected a marker button. Nothing to do. */ - return; - } - - adata = QTOP(d); - while(adata && alert_idx > 0) { - alert_idx--; - adata = QNEXT(adata); - } - -#ifdef DEBUG - assert(alert_idx == 0); - assert(adata); - assert(adata->alert); -#endif - if (adata == NULL || alert_idx != 0) - return; - - khui_alert_lock(adata->alert); -#ifdef DEBUG - assert(cmd_idx >= 0 && cmd_idx < adata->alert->n_alert_commands); -#endif - - if (cmd_idx >= 0 && cmd_idx < adata->alert->n_alert_commands) { - cmd = adata->alert->alert_commands[cmd_idx]; - } - - flags = adata->alert->flags; - - adata->alert->response = cmd; - - khui_alert_unlock(adata->alert); - - /* if we were supposed to dispatch the command, do so */ - if (cmd != 0 && - cmd != KHUI_PACTION_CLOSE && - (flags & KHUI_ALERT_FLAG_DISPATCH_CMD)) { - PostMessage(khm_hwnd_main, WM_COMMAND, - MAKEWPARAM(cmd, 0), 0); - } - - /* if this was the only alert in the alert group and its close - button was clicked, we close the alert window. Otherwise, the - alert window creates its own close button that closes the - window. */ - if (d->n_alerts == 1) { - PostMessage(d->hwnd, WM_CLOSE, 0, 0); - } - - /* While we are at it, we should disable the buttons for this - alert since we have already dispatched the command for it. */ - if (cmd != 0) { - HWND hw_focus = GetFocus(); - khm_boolean focus_trapped = FALSE; - - for (i=0; i < adata->n_cmd_buttons; i++) { - if (adata->hwnd_buttons[i]) { - if (hw_focus == adata->hwnd_buttons[i]) - focus_trapped = TRUE; - - EnableWindow(adata->hwnd_buttons[i], FALSE); - } - } - - if (focus_trapped) { - hw_focus = GetNextDlgTabItem(d->hwnd, hw_focus, FALSE); - if (hw_focus) - PostMessage(d->hwnd, WM_NEXTDLGCTL, (WPARAM) hw_focus, MAKELPARAM(TRUE,0)); - } - } -} - -static void -destroy_alerter_wnd_data(alerter_wnd_data * d) { - alerter_alert_data * adata; - - LDELETE(&khui_alert_windows, d); - - QGET(d, &adata); - while(adata) { - - if (adata->alert) { - - khui_alert_lock(adata->alert); - - adata->alert->displayed = FALSE; - - khui_alert_unlock(adata->alert); - - khui_alert_release(adata->alert); - adata->alert = NULL; - } - - PFREE(adata); - - QGET(d, &adata); - } - - PFREE(d); -} - -/* both ref and to_add must be locked and held */ -static khm_boolean -alert_can_consolidate(khui_alert * ref, - khui_alert * to_add, - alert_list * alist) { - - /* first check if we can add anything */ - if (alist->n_alerts == ARRAYLENGTH(alist->alerts)) - return FALSE; - -#ifdef DEBUG - assert(to_add != NULL); -#endif - - if (ref == NULL) { - /* we are testing whether to_add should be added to the alist - on its own. */ - if ((to_add->flags & KHUI_ALERT_FLAG_DISPLAY_BALLOON) && - !(to_add->flags & KHUI_ALERT_FLAG_DISPLAY_WINDOW)) { - /* already displayed */ - return FALSE; - } - - if ((to_add->flags & (KHUI_ALERT_FLAG_REQUEST_BALLOON | - KHUI_ALERT_FLAG_REQUEST_WINDOW)) == KHUI_ALERT_FLAG_REQUEST_BALLOON) { - /* needs to be shown in a balloon */ - return FALSE; - } - - return TRUE; - } - - /* if the ref or to_add are marked for modal, then we can't - consolidate them */ - if ((ref->flags & KHUI_ALERT_FLAG_MODAL) || - (to_add->flags & KHUI_ALERT_FLAG_MODAL)) - return FALSE; - - /* also, if either of them have requested to be exclusively shown - in a balloon, then we can't consolidate them. */ - if (((ref->flags & (KHUI_ALERT_FLAG_REQUEST_BALLOON | - KHUI_ALERT_FLAG_REQUEST_WINDOW)) == KHUI_ALERT_FLAG_REQUEST_BALLOON) - - || - - ((to_add->flags & (KHUI_ALERT_FLAG_REQUEST_BALLOON | - KHUI_ALERT_FLAG_REQUEST_WINDOW)) == KHUI_ALERT_FLAG_REQUEST_BALLOON)) - return FALSE; - - /* for now, all we check if whether they are of the same type. */ - if (ref->alert_type != KHUI_ALERTTYPE_NONE && - ref->alert_type == to_add->alert_type) - return TRUE; - else - return FALSE; -} - -/* both a1 and a2 must be locked */ -static khm_boolean -alert_is_equal(khui_alert * a1, khui_alert * a2) { - khm_int32 i; - - if ((a1->severity != a2->severity) || - (a1->n_alert_commands != a2->n_alert_commands) || - (a1->title && (!a2->title || wcscmp(a1->title, a2->title))) || - (!a1->title && a2->title) || - (a1->message && (!a2->message || wcscmp(a1->message, a2->message))) || - (!a1->message && a2->message) || - (a1->suggestion && (!a2->suggestion || wcscmp(a1->suggestion, a2->suggestion))) || - (!a1->suggestion && a2->suggestion)) { - - return FALSE; - - } - - for (i=0; i < a1->n_alert_commands; i++) { - if (a1->alert_commands[i] != a2->alert_commands[i]) - return FALSE; - } - - return TRUE; -} - -/* the return value is the number of alerts added to alist */ -static khm_int32 -alert_consolidate(alert_list * alist, - khui_alert * alert, - khm_boolean add_from_queue) { - - khui_alert * listtop; - int queue_size = 0; - int i; - khm_int32 n_added = 0; - -#ifdef DEBUG - assert(alist); -#endif - - if (alist->n_alerts == ARRAYLENGTH(alist->alerts)) { - /* can't add anything */ - - return 0; - } - - /* if the list is empty, we just add one alert */ - if (alist->n_alerts == 0) { - - if (alert) { - khui_alert_lock(alert); - if (alert_can_consolidate(NULL, alert, alist)) { - alert_list_add_alert(alist, alert); - n_added ++; - alert = NULL; - } - khui_alert_unlock(alert); - } - - if (n_added == 0 && add_from_queue) { - khui_alert * q; - int i; - - queue_size = alert_queue_get_size(); - for (i=0; i < queue_size && n_added == 0; i++) { - q = alert_queue_get_alert_by_pos(i); - if (q) { - khui_alert_lock(q); - if (alert_can_consolidate(NULL, q, alist)) { - alert_list_add_alert(alist, q); - n_added++; - alert_queue_delete_alert(q); - } - khui_alert_unlock(q); - khui_alert_release(q); - } - } - } - - if (n_added == 0) { - /* nothing to add */ - return 0; - } - } - - /* at this point, the alert list is not empty */ -#ifdef DEBUG - assert(alist->n_alerts != 0); - assert(alist->alerts[0]); -#endif - - listtop = alist->alerts[0]; - khui_alert_hold(listtop); - khui_alert_lock(listtop); - - queue_size = alert_queue_get_size(); - - if (alert) { - khui_alert_lock(alert); - if (alert_can_consolidate(listtop, alert, alist)) { - alert_list_add_alert(alist, alert); - n_added ++; - } - khui_alert_unlock(alert); - } - - if (add_from_queue) { - for (i=0; i < queue_size; i++) { - khui_alert * a; - - a = alert_queue_get_alert_by_pos(i); - if (a == NULL) - continue; - - khui_alert_lock(a); - if (alert_can_consolidate(listtop, a, alist)) { - alert_queue_delete_alert(a); - alert_list_add_alert(alist, a); - n_added ++; - - queue_size--; - i--; -#ifdef DEBUG - assert(alert_queue_get_size() == queue_size); -#endif - } - khui_alert_unlock(a); - khui_alert_release(a); - } - } - - khui_alert_unlock(listtop); - khui_alert_release(listtop); - - return n_added; -} - -static khm_int32 -alert_check_consolidate_window(alerter_wnd_data * d, khui_alert * a) { - alert_list alist; - alerter_alert_data * adata; - int n_added; - - alert_list_init(&alist); - - adata = QTOP(d); - while(adata) { - -#ifdef DEBUG - assert(adata->alert); -#endif - alert_list_add_alert(&alist, adata->alert); - - adata = QNEXT(adata); - } - - n_added = alert_consolidate(&alist, a, FALSE); - - alert_list_destroy(&alist); - - return n_added; -} - -static khm_int32 -alert_show_minimized(khui_alert * a) { - wchar_t tbuf[64]; /* corresponds to NOTIFYICONDATA::szInfoTitle[] */ - wchar_t mbuf[256]; /* corresponds to NOTIFYICONDATA::szInfo[] */ - -#ifdef DEBUG - assert(a); -#endif - if (a == NULL) - return KHM_ERROR_INVALID_PARAM; - - khui_alert_lock(a); - - if (a->message == NULL) - goto done; - - if (a->title == NULL) { - LoadString(khm_hInstance, IDS_ALERT_DEFAULT, - tbuf, ARRAYLENGTH(tbuf)); - } else { - StringCbCopy(tbuf, sizeof(tbuf), a->title); - } - - if (FAILED(StringCbCopy(mbuf, sizeof(mbuf), a->message)) || - (!(a->flags & KHUI_ALERT_FLAG_DEFACTION) && - (a->n_alert_commands > 0 || - a->suggestion || - (a->flags & KHUI_ALERT_FLAG_VALID_ERROR)))) { - /* if mbuf wasn't big enough, this should have copied a - truncated version of it */ - size_t cch_m, cch_p; - wchar_t postfix[256]; - - cch_p = LoadString(khm_hInstance, IDS_ALERT_MOREINFO, postfix, - ARRAYLENGTH(postfix)); - cch_p++; /* account for NULL */ - - StringCchLength(mbuf, ARRAYLENGTH(mbuf), &cch_m); - cch_m = min(cch_m, ARRAYLENGTH(mbuf) - cch_p); - - StringCchCopy(mbuf + cch_m, ARRAYLENGTH(mbuf) - cch_m, - postfix); - - a->flags |= KHUI_ALERT_FLAG_REQUEST_WINDOW; - } - - a->flags |= KHUI_ALERT_FLAG_DISPLAY_BALLOON; - -#ifdef DEBUG - assert(balloon_alert == NULL); -#endif - - if (balloon_alert) { - khui_alert_lock(balloon_alert); - balloon_alert->displayed = FALSE; - khui_alert_unlock(balloon_alert); - khui_alert_release(balloon_alert); - balloon_alert = NULL; - } - - balloon_alert = a; - khui_alert_hold(a); - - a->displayed = TRUE; - - khm_notify_icon_balloon(a->severity, - tbuf, - mbuf, - NTF_TIMEOUT); - - done: - khui_alert_unlock(a); - - return KHM_ERROR_SUCCESS; -} - -static khm_int32 -alert_show_normal(khui_alert * a) { - wchar_t buf[256]; - wchar_t * title; - alert_list alist; - - khui_alert_lock(a); - - if(a->title == NULL) { - LoadString(khm_hInstance, IDS_ALERT_DEFAULT, - buf, ARRAYLENGTH(buf)); - title = buf; - } else - title = a->title; - - khui_alert_unlock(a); - - alert_list_init(&alist); - alert_list_set_title(&alist, title); - alert_list_add_alert(&alist, a); - - alert_show_list(&alist); - - alert_list_destroy(&alist); - - return KHM_ERROR_SUCCESS; -} - -static khm_int32 -alert_show_list(alert_list * alist) { - HWND hwa; - - /* we don't need to keep track of the window handle - because the window procedure adds it to the dialog - list automatically */ - - hwa = - CreateWindowEx(ALERT_WINDOW_EX_SYLES, - MAKEINTATOM(atom_alerter), - alist->title, - ALERT_WINDOW_STYLES, - 0, 0, 300, 300, // bogus values - khm_hwnd_main, - (HMENU) NULL, - khm_hInstance, - (LPVOID) alist); - - ShowWindow(hwa, SW_SHOW); - - return (hwa != NULL); -} - -static khm_int32 -alert_show(khui_alert * a) { - khm_boolean show_normal = FALSE; - khm_boolean show_mini = FALSE; - - khui_alert_lock(a); - - /* is there an alert already? If so, we just enqueue the message - and let it sit. */ - if (ALERT_DISPLAYED() && - !(a->flags & KHUI_ALERT_FLAG_MODAL)) { - khm_int32 rv; - alerter_wnd_data * wdata; - - khui_alert_unlock(a); - - /* if there are any alerter windows displayed, check if this - alert can be consolidated with any of them. If so, we - should consolidate it. Otherwise, just enqueue it. */ - for(wdata = khui_alert_windows; - wdata; - wdata = LNEXT(wdata)) { - if (alert_check_consolidate_window(wdata, a)) { - - add_alert_to_wnd_data(wdata, a); - estimate_alerter_wnd_sizes(wdata); - setup_alerter_window_controls(wdata); - - return KHM_ERROR_SUCCESS; - - } - } - - rv = alert_enqueue(a); - - if (KHM_SUCCEEDED(rv)) - return KHM_ERROR_HELD; - else - return rv; - } - - if((a->flags & KHUI_ALERT_FLAG_DISPLAY_WINDOW) || - ((a->flags & KHUI_ALERT_FLAG_DISPLAY_BALLOON) && - !(a->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW))) { - - /* The alert has already been displayed. */ - - show_normal = FALSE; - show_mini = FALSE; - - } else { - - if(a->err_context != NULL || - a->err_event != NULL) { - a->flags |= KHUI_ALERT_FLAG_VALID_ERROR; - } - - /* depending on the state of the main window, we - need to either show a window or a balloon */ - if ((a->flags & KHUI_ALERT_FLAG_MODAL) || - (khm_is_main_window_active() && - !(a->flags & KHUI_ALERT_FLAG_REQUEST_BALLOON)) || - (a->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW)) { - - show_normal = TRUE; - - } else { - - show_mini = TRUE; - - } - } - - khui_alert_unlock(a); - - if (show_normal) - return alert_show_normal(a); - else if (show_mini) - return alert_show_minimized(a); - else - return KHM_ERROR_SUCCESS; -} - -static void -show_queued_alerts(void) { - - if (!ALERT_DISPLAYED()) { - - /* show next consolidated batch */ - alert_list alist; - int n; - - alert_list_init(&alist); - n = alert_consolidate(&alist, NULL, TRUE); - - if (n) { - if (n == 1) { - khui_alert_lock(alist.alerts[0]); - - if (alist.alerts[0]->title) { - alert_list_set_title(&alist, alist.alerts[0]->title); - } else { - wchar_t title[KHUI_MAXCCH_TITLE]; - LoadString(khm_hInstance, IDS_ALERT_DEFAULT, - title, ARRAYLENGTH(title)); - alert_list_set_title(&alist, title); - } - - khui_alert_unlock(alist.alerts[0]); - } else { - wchar_t title[KHUI_MAXCCH_TITLE]; - LoadString(khm_hInstance, IDS_ALERT_DEFAULT, - title, ARRAYLENGTH(title)); - alert_list_set_title(&alist, title); - } - - alert_show_list(&alist); - } - - alert_list_destroy(&alist); - - if (n == 0) { - khui_alert * a; - - /* no alerts were shown above. This maybe because none of - the alerts were consolidatable or they were requested - to be shown in a balloon. In this case, we just take - the first alert from the queue and show it manually. */ - - a = alert_queue_get_alert(); - if (a) { - alert_show(a); - khui_alert_release(a); - } - } - - check_for_queued_alerts(); - } -} - - -static void -check_for_queued_alerts(void) { - if (!is_alert_queue_empty()) { - khui_alert * a; - - a = alert_queue_peek(); - - khui_alert_lock(a); - - if (a->title) { - HICON hi; - int res; - - if (a->severity == KHERR_ERROR) - res = OIC_ERROR; - else if (a->severity == KHERR_WARNING) - res = OIC_WARNING; - else - res = OIC_INFORMATION; - - hi = LoadImage(0, MAKEINTRESOURCE(res), - IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), - LR_SHARED); - - khm_statusbar_set_part(KHUI_SBPART_NOTICE, - hi, - a->title); - } else { - khm_statusbar_set_part(KHUI_SBPART_NOTICE, - NULL, NULL); -#ifdef DEBUG - DebugBreak(); -#endif - } - - khui_alert_unlock(a); - khui_alert_release(a); - - } else { - khm_statusbar_set_part(KHUI_SBPART_NOTICE, - NULL, NULL); - } -} - -static khm_int32 -alert_enqueue(khui_alert * a) { - if (is_alert_queue_full()) - return KHM_ERROR_NO_RESOURCES; - - alert_queue_put_alert(a); - check_for_queued_alerts(); - - return KHM_ERROR_SUCCESS; -} - -/* the alerter window is actually a dialog */ -static LRESULT CALLBACK -alerter_wnd_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - switch(uMsg) { - case WM_CREATE: - { - LPCREATESTRUCT lpcs; - alert_list * alist; - alerter_wnd_data * d; - - lpcs = (LPCREATESTRUCT) lParam; - alist = (alert_list *) lpcs->lpCreateParams; - - d = create_alerter_wnd_data(hwnd, alist); - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, NTF_PARAM, (LONG_PTR) d); -#pragma warning(pop) - - khm_add_dialog(hwnd); - khm_enter_modal(hwnd); - - estimate_alerter_wnd_sizes(d); - setup_alerter_window_controls(d); - - if (d->hw_close) { - SetFocus(d->hw_close); - } - - return TRUE; - } - break; /* not reached */ - - case WM_DESTROY: - { - alerter_wnd_data * d; - - /* khm_leave_modal() could be here, but instead it is in - the WM_COMMAND handler. This is because the modal loop - has to be exited before DestroyWindow() is issued. */ - //khm_leave_modal(); - khm_del_dialog(hwnd); - - d = (alerter_wnd_data *)(LONG_PTR) - GetWindowLongPtr(hwnd, NTF_PARAM); - - destroy_alerter_wnd_data(d); - - return TRUE; - } - break; - - case WM_COMMAND: - { - alerter_wnd_data * d; - - d = (alerter_wnd_data *)(LONG_PTR) - GetWindowLongPtr(hwnd, NTF_PARAM); - - if(HIWORD(wParam) == BN_CLICKED) { - if (LOWORD(wParam) == IDC_NTF_CLOSE || - LOWORD(wParam) == KHUI_PACTION_NEXT) { - - khm_leave_modal(); - - DestroyWindow(hwnd); - - return 0; - } - } - } - break; - - case WM_CLOSE: - { - khm_leave_modal(); - - DestroyWindow(hwnd); - - return 0; - } - } - - /* Since this is a custom built dialog, we use DefDlgProc instead - of DefWindowProc. */ - return DefDlgProc(hwnd, uMsg, wParam, lParam); -} - -static LRESULT CALLBACK -alert_bin_wnd_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - BOOL in_printclient = FALSE; - - switch(uMsg) { - case WM_CREATE: - { - LPCREATESTRUCT lpcs; - alerter_wnd_data * d; - - lpcs = (LPCREATESTRUCT) lParam; - d = (alerter_wnd_data *) lpcs->lpCreateParams; - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) d); -#pragma warning(pop) - } - return 0; - - case WM_ERASEBKGND: - /* we erase the background when we are drawing the alerts - anyway. */ - return 0; - - case WM_PRINTCLIENT: - in_printclient = TRUE; - /* fallthrough */ - case WM_PAINT: - { - HDC hdc; - PAINTSTRUCT ps; - RECT r; - HFONT hf_old; - int y; - alerter_wnd_data * d; - alerter_alert_data * adata; - size_t len; - int idx; - - d = (alerter_wnd_data *) (LONG_PTR) GetWindowLongPtr(hwnd, GWLP_USERDATA); -#ifdef DEBUG - assert(d); -#endif - - if (in_printclient) { - hdc = (HDC) wParam; - } else { - hdc = BeginPaint(hwnd, &ps); - } - -#ifdef DEBUG - assert(hdc); - assert(d->hfont); -#endif - -#ifdef ALERT_STATIC_BACKGROUND - if (in_printclient || ps.fErase) { - HBRUSH hb_background; - - hb_background = GetSysColorBrush(COLOR_BTNFACE); - - GetClientRect(hwnd, &r); - FillRect(hdc, &r, hb_background); - } -#endif - - SetBkMode(hdc, TRANSPARENT); - - hf_old = SelectFont(hdc, d->hfont); - - y = -d->scroll_top; - idx = 0; - /* go through the alerts and display them */ - adata = QTOP(d); - while(adata) { - khui_alert * a; - -#ifndef ALERT_STATIC_BACKGROUND -#define MIX_C(v1, v2, p) (((int)v1) * p + (((int) v2) * (256 - p))) -#define ALPHA 50 - if (in_printclient || ps.fErase) { - TRIVERTEX v[2]; - GRADIENT_RECT gr; - COLORREF clr; - COLORREF clr2; - - CopyRect(&r, &adata->r_alert); - OffsetRect(&r, 0, y); - - v[0].x = r.left; - v[0].y = r.top; - v[0].Alpha = 0; - - v[1].x = r.right; - v[1].y = r.bottom; - v[1].Alpha = 0; - - if (idx == d->c_alert) { - clr = GetSysColor(COLOR_HOTLIGHT); - - clr2 = GetSysColor(COLOR_BTNHIGHLIGHT); - v[0].Red = MIX_C(GetRValue(clr), GetRValue(clr2), ALPHA); - v[0].Green = MIX_C(GetGValue(clr), GetGValue(clr2), ALPHA); - v[0].Blue = MIX_C(GetBValue(clr), GetBValue(clr2), ALPHA); - - clr2 = GetSysColor(COLOR_BTNFACE); - v[1].Red = MIX_C(GetRValue(clr), GetRValue(clr2), ALPHA); - v[1].Green = MIX_C(GetGValue(clr), GetGValue(clr2), ALPHA); - v[1].Blue = MIX_C(GetBValue(clr), GetBValue(clr2), ALPHA); - } else { - clr = GetSysColor(COLOR_BTNHIGHLIGHT); - v[0].Red = ((int)GetRValue(clr)) << 8; - v[0].Green = ((int)GetGValue(clr)) << 8; - v[0].Blue = ((int)GetBValue(clr)) << 8; - - clr = GetSysColor(COLOR_BTNFACE); - v[1].Red = ((int)GetRValue(clr)) << 8; - v[1].Green = ((int)GetGValue(clr)) << 8; - v[1].Blue = ((int)GetBValue(clr)) << 8; - } - - gr.UpperLeft = 0; - gr.LowerRight = 1; - GradientFill(hdc, v, 2, &gr, 1, GRADIENT_FILL_RECT_V); - } -#undef ALPHA -#undef MIX_C -#endif - - a = adata->alert; -#ifdef DEBUG - assert(a != NULL); -#endif - khui_alert_lock(a); - - if (!IsRectEmpty(&adata->r_title)) { - - CopyRect(&r, &adata->r_title); - OffsetRect(&r, 0, y); - - StringCchLength(a->title, KHUI_MAXCCH_TITLE, &len); - - DrawEdge(hdc, &r, EDGE_RAISED, BF_RECT | BF_MIDDLE); - - InflateRect(&r, -d->s_pad.cx, -d->s_pad.cy); - - DrawText(hdc, a->title, (int) len, &r, - DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); - } - - { - HICON hicon; - int iid; - - CopyRect(&r, &adata->r_icon); - OffsetRect(&r, 0, y); - - if(a->severity == KHERR_ERROR) - iid = OIC_HAND; - else if(a->severity == KHERR_WARNING) - iid = OIC_BANG; - else - iid = OIC_NOTE; - - hicon = (HICON) LoadImage(NULL, - MAKEINTRESOURCE(iid), - IMAGE_ICON, - GetSystemMetrics(SM_CXICON), - GetSystemMetrics(SM_CYICON), - LR_SHARED); - - DrawIcon(hdc, r.left, r.top, hicon); - } - - if (a->message) { - - CopyRect(&r, &adata->r_message); - OffsetRect(&r, 0, y); - - StringCchLength(a->message, KHUI_MAXCCH_MESSAGE, &len); - - DrawText(hdc, a->message, (int) len, &r, - DT_WORDBREAK); - } - - if (a->suggestion) { - HICON hicon; - SIZE sz; - - CopyRect(&r, &adata->r_suggestion); - OffsetRect(&r, 0, y); - - DrawEdge(hdc, &r, EDGE_SUNKEN, BF_RECT | BF_MIDDLE); - - InflateRect(&r, -d->s_pad.cx, -d->s_pad.cy); - - sz.cx = GetSystemMetrics(SM_CXSMICON); - sz.cy = GetSystemMetrics(SM_CYSMICON); - - hicon = (HICON) LoadImage(NULL, - MAKEINTRESOURCE(OIC_NOTE), - IMAGE_ICON, - sz.cx, - sz.cy, - LR_SHARED); - - DrawIconEx(hdc, r.left, r.top, hicon, sz.cx, sz.cy, 0, NULL, - DI_NORMAL); - - r.left += d->s_pad.cx + GetSystemMetrics(SM_CXSMICON); - - StringCchLength(a->suggestion, KHUI_MAXCCH_SUGGESTION, &len); - - DrawText(hdc, a->suggestion, (int) len, &r, - DT_WORDBREAK); - } - khui_alert_unlock(a); - - y += adata->r_alert.bottom; - idx++; - - adata = QNEXT(adata); - } - - SelectFont(hdc, hf_old); - - if (!in_printclient) { - EndPaint(hwnd, &ps); - } - } - return 0; - - case WM_VSCROLL: - { - alerter_wnd_data * d; - int new_pos = 0; - SCROLLINFO si; - - d = (alerter_wnd_data *) (LONG_PTR) GetWindowLongPtr(hwnd, GWLP_USERDATA); -#ifdef DEBUG - assert(d); -#endif - if (d == NULL) - break; /* we can't handle the message */ - - ZeroMemory(&si, sizeof(si)); - - switch(LOWORD(wParam)) { - case SB_BOTTOM: - new_pos = d->s_alerts.cy - d->cy_max_wnd; - break; - - case SB_LINEDOWN: - new_pos = d->scroll_top + SCROLL_LINE_SIZE(d); - break; - - case SB_LINEUP: - new_pos = d->scroll_top - SCROLL_LINE_SIZE(d); - break; - - case SB_PAGEDOWN: - new_pos = d->scroll_top + d->cy_max_wnd; - break; - - case SB_PAGEUP: - new_pos = d->scroll_top - d->cy_max_wnd; - break; - - case SB_THUMBPOSITION: - case SB_THUMBTRACK: - si.fMask = SIF_TRACKPOS; - GetScrollInfo(hwnd, SB_VERT, &si); - new_pos = si.nTrackPos; - break; - - case SB_TOP: - new_pos = 0; - break; - - case SB_ENDSCROLL: - si.fMask = SIF_POS; - si.nPos = d->scroll_top; - SetScrollInfo(hwnd, SB_VERT, &si, TRUE); - return 0; - - default: - return 0; - } - - scroll_to_position(d, new_pos, FALSE); - } - return 0; - - case WM_COMMAND: - { - alerter_wnd_data * d; - - d = (alerter_wnd_data *) (LONG_PTR) GetWindowLongPtr(hwnd, GWLP_USERDATA); -#ifdef DEBUG - assert(d); -#endif - if (d == NULL) - break; - - if (HIWORD(wParam) == BN_CLICKED) { - process_command_button(d, LOWORD(wParam)); - return 0; - } else if (HIWORD(wParam) == BN_SETFOCUS) { - ensure_command_is_visible(d, LOWORD(wParam)); - return 0; - } - } - break; - - case WM_LBUTTONUP: - { - alerter_wnd_data * d; - int x,y; - - d = (alerter_wnd_data *) (LONG_PTR) GetWindowLongPtr(hwnd, GWLP_USERDATA); -#ifdef DEBUG - assert(d); -#endif - if (d == NULL) - break; - - x = GET_X_LPARAM(lParam); - y = GET_Y_LPARAM(lParam); - - handle_mouse_select(d, x, y); - } - break; - - case WM_SIZE: - { - InvalidateRect(hwnd, NULL, TRUE); - } - break; - - case WM_DESTROY: - { - /* nothing needs to be done here */ - } - return 0; - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -ATOM khm_register_alerter_wnd_class(void) -{ - WNDCLASSEX wcx; - - ZeroMemory(&wcx, sizeof(wcx)); - - wcx.cbSize = sizeof(wcx); - wcx.style = - CS_OWNDC | -#if(_WIN32_WINNT >= 0x0501) - ((IS_COMMCTL6())? CS_DROPSHADOW: 0) | -#endif - 0; - wcx.lpfnWndProc = alerter_wnd_proc; - wcx.cbClsExtra = 0; - wcx.cbWndExtra = DLGWINDOWEXTRA + sizeof(LONG_PTR); - wcx.hInstance = khm_hInstance; - wcx.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP)); - wcx.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)); - wcx.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); - wcx.lpszMenuName = NULL; - wcx.lpszClassName = KHUI_ALERTER_CLASS; - wcx.hIconSm = NULL; - - atom_alerter = RegisterClassEx(&wcx); - - return atom_alerter; -} - -ATOM khm_register_alert_bin_wnd_class(void) -{ - WNDCLASSEX wcx; - - ZeroMemory(&wcx, sizeof(wcx)); - - wcx.cbSize = sizeof(wcx); - wcx.style = CS_OWNDC; - - wcx.lpfnWndProc = alert_bin_wnd_proc; - wcx.cbClsExtra = 0; - wcx.cbWndExtra = sizeof(LONG_PTR); - wcx.hInstance = khm_hInstance; - wcx.hIcon = NULL; - wcx.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)); - wcx.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); - wcx.lpszMenuName = NULL; - wcx.lpszClassName = KHUI_ALERTBIN_CLASS; - wcx.hIconSm = NULL; - - atom_alert_bin = RegisterClassEx(&wcx); - - return atom_alert_bin; -} - -/********************************************************************** - Notification Icon -***********************************************************************/ - -#define KHUI_NOTIFY_ICON_ID 0 - -void khm_notify_icon_add(void) { - NOTIFYICONDATA ni; - wchar_t buf[256]; - - ZeroMemory(&ni, sizeof(ni)); - - ni.cbSize = sizeof(ni); - ni.hWnd = hwnd_notifier; - ni.uID = KHUI_NOTIFY_ICON_ID; - ni.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; - ni.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(iid_normal)); - ni.uCallbackMessage = KHUI_WM_NOTIFIER; - LoadString(khm_hInstance, IDS_NOTIFY_PREFIX, buf, ARRAYLENGTH(buf)); - StringCbCopy(ni.szTip, sizeof(ni.szTip), buf); - LoadString(khm_hInstance, IDS_NOTIFY_READY, buf, ARRAYLENGTH(buf)); - StringCbCat(ni.szTip, sizeof(ni.szTip), buf); - - Shell_NotifyIcon(NIM_ADD, &ni); - - DestroyIcon(ni.hIcon); - - ni.cbSize = sizeof(ni); - ni.uVersion = NOTIFYICON_VERSION; - Shell_NotifyIcon(NIM_SETVERSION, &ni); -} - -void -khm_notify_icon_balloon(khm_int32 severity, - wchar_t * title, - wchar_t * msg, - khm_int32 timeout) { - NOTIFYICONDATA ni; - int iid; - - if (!msg || !title) - return; - - ZeroMemory(&ni, sizeof(ni)); - ni.cbSize = sizeof(ni); - - if (severity == KHERR_INFO) { - ni.dwInfoFlags = NIIF_INFO; - iid = IDI_NOTIFY_INFO; - } else if (severity == KHERR_WARNING) { - ni.dwInfoFlags = NIIF_WARNING; - iid = IDI_NOTIFY_WARN; - } else if (severity == KHERR_ERROR) { - ni.dwInfoFlags = NIIF_ERROR; - iid = IDI_NOTIFY_ERROR; - } else { - ni.dwInfoFlags = NIIF_NONE; - iid = iid_normal; - } - - ni.hWnd = hwnd_notifier; - ni.uID = KHUI_NOTIFY_ICON_ID; - ni.uFlags = NIF_INFO | NIF_ICON; - ni.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(iid)); - - if (FAILED(StringCbCopy(ni.szInfo, sizeof(ni.szInfo), msg))) { - /* too long? */ - StringCchCopyN(ni.szInfo, ARRAYLENGTH(ni.szInfo), - msg, - ARRAYLENGTH(ni.szInfo) - ARRAYLENGTH(ELLIPSIS)); - StringCchCat(ni.szInfo, ARRAYLENGTH(ni.szInfo), - ELLIPSIS); - } - - if (FAILED(StringCbCopy(ni.szInfoTitle, sizeof(ni.szInfoTitle), - title))) { - StringCchCopyN(ni.szInfoTitle, ARRAYLENGTH(ni.szInfoTitle), - title, - ARRAYLENGTH(ni.szInfoTitle) - ARRAYLENGTH(ELLIPSIS)); - StringCchCat(ni.szInfoTitle, ARRAYLENGTH(ni.szInfoTitle), - ELLIPSIS); - } - - ni.uTimeout = timeout; - - Shell_NotifyIcon(NIM_MODIFY, &ni); - - DestroyIcon(ni.hIcon); -} - -void khm_notify_icon_expstate(enum khm_notif_expstate expseverity) { - int new_iid; - - if (expseverity == KHM_NOTIF_OK) - new_iid = IDI_APPICON_OK; - else if (expseverity == KHM_NOTIF_WARN) - new_iid = IDI_APPICON_WARN; - else if (expseverity == KHM_NOTIF_EXP) - new_iid = IDI_APPICON_EXP; - else - new_iid = IDI_NOTIFY_NONE; - - if (iid_normal == new_iid) - return; - - iid_normal = new_iid; - - if (balloon_alert == NULL) - khm_notify_icon_change(KHERR_NONE); -} - -void khm_notify_icon_change(khm_int32 severity) { - NOTIFYICONDATA ni; - wchar_t buf[256]; - int iid; - - if (severity == KHERR_INFO) - iid = IDI_NOTIFY_INFO; - else if (severity == KHERR_WARNING) - iid = IDI_NOTIFY_WARN; - else if (severity == KHERR_ERROR) - iid = IDI_NOTIFY_ERROR; - else - iid = iid_normal; - - ZeroMemory(&ni, sizeof(ni)); - - ni.cbSize = sizeof(ni); - ni.hWnd = hwnd_notifier; - ni.uID = KHUI_NOTIFY_ICON_ID; - ni.uFlags = NIF_ICON | NIF_TIP; - ni.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(iid)); - LoadString(khm_hInstance, IDS_NOTIFY_PREFIX, buf, ARRAYLENGTH(buf)); - StringCbCopy(ni.szTip, sizeof(ni.szTip), buf); - if(severity == KHERR_NONE) - LoadString(khm_hInstance, IDS_NOTIFY_READY, buf, ARRAYLENGTH(buf)); - else - LoadString(khm_hInstance, IDS_NOTIFY_ATTENTION, buf, ARRAYLENGTH(buf)); - StringCbCat(ni.szTip, sizeof(ni.szTip), buf); - - Shell_NotifyIcon(NIM_MODIFY, &ni); - - DestroyIcon(ni.hIcon); -} - -void khm_notify_icon_remove(void) { - NOTIFYICONDATA ni; - - ZeroMemory(&ni, sizeof(ni)); - - ni.cbSize = sizeof(ni); - ni.hWnd = hwnd_notifier; - ni.uID = KHUI_NOTIFY_ICON_ID; - - Shell_NotifyIcon(NIM_DELETE, &ni); -} - -static khm_int32 -get_default_notifier_action(void) { - khm_int32 def_cmd = KHUI_ACTION_OPEN_APP; - khm_handle csp_cw = NULL; - khm_size i; - - if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, - &csp_cw))) - def_cmd; - - khc_read_int32(csp_cw, L"NotificationAction", &def_cmd); - - khc_close_space(csp_cw); - - for (i=0; i < n_khm_notifier_actions; i++) { - if (khm_notifier_actions[i] == def_cmd) - break; - } - - if (i < n_khm_notifier_actions) - return def_cmd; - else - return KHUI_ACTION_OPEN_APP; -} - -void khm_notify_icon_activate(void) { - /* if there are any notifications waiting to be shown and there - are no alerts already being shown, we show them. Otherwise we - execute the default action. */ - - khm_notify_icon_change(KHERR_NONE); - - if (balloon_alert != NULL && khui_alert_windows == NULL) { - - khui_alert * a; - khm_boolean alert_done = FALSE; - - a = balloon_alert; - balloon_alert = NULL; - - khui_alert_lock(a); - - a->displayed = FALSE; - - if ((a->flags & KHUI_ALERT_FLAG_DEFACTION) && - (a->n_alert_commands > 0)) { - - PostMessage(khm_hwnd_main, WM_COMMAND, - MAKEWPARAM(a->alert_commands[0], - 0), - 0); - alert_done = TRUE; - - } else if (a->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW) { - - alert_show_normal(a); - alert_done = TRUE; - - } - khui_alert_unlock(a); - khui_alert_release(a); - - if (alert_done) - return; - } - - if (!is_alert_queue_empty() && !ALERT_DISPLAYED()) { - - khm_show_main_window(); - show_queued_alerts(); - - return; - } - - - /* if none of the above applied, then we perform the default - action for the notification icon. */ - { - khm_int32 cmd = 0; - - cmd = get_default_notifier_action(); - - if (cmd == KHUI_ACTION_OPEN_APP) { - if (khm_is_main_window_visible()) { - khm_hide_main_window(); - } else { - khm_show_main_window(); - } - } else { - khui_action_trigger(cmd, NULL); - } - - check_for_queued_alerts(); - } -} - -/********************************************************************* - Initialization -**********************************************************************/ - -void khm_init_notifier(void) -{ - if(!khm_register_notifier_wnd_class()) - return; - - if(!khm_register_alerter_wnd_class()) - return; - - if(!khm_register_alert_bin_wnd_class()) - return; - - hwnd_notifier = CreateWindowEx(0, - MAKEINTATOM(atom_notifier), - KHUI_NOTIFIER_WINDOW, - 0, - 0,0,0,0, - HWND_MESSAGE, - NULL, - khm_hInstance, - NULL); - - if(hwnd_notifier != NULL) { - kmq_subscribe_hwnd(KMSG_ALERT, hwnd_notifier); - kmq_subscribe_hwnd(KMSG_CRED, hwnd_notifier); - notifier_ready = TRUE; - - khm_notify_icon_add(); - } else { -#ifdef DEBUG - assert(hwnd_notifier != NULL); -#endif - } - khm_timer_init(); - - khm_addr_change_notifier_init(); -} - -void khm_exit_notifier(void) -{ - khm_addr_change_notifier_exit(); - - khm_timer_exit(); - - if(hwnd_notifier != NULL) { - khm_notify_icon_remove(); - kmq_unsubscribe_hwnd(KMSG_ALERT, hwnd_notifier); - kmq_unsubscribe_hwnd(KMSG_CRED, hwnd_notifier); - DestroyWindow(hwnd_notifier); - hwnd_notifier = NULL; - } - - if(atom_notifier != 0) { - UnregisterClass(MAKEINTATOM(atom_notifier), khm_hInstance); - atom_notifier = 0; - } - - if(atom_alerter != 0) { - UnregisterClass(MAKEINTATOM(atom_alerter), khm_hInstance); - atom_alerter = 0; - } - - if(atom_alert_bin != 0) { - UnregisterClass(MAKEINTATOM(atom_alert_bin), khm_hInstance); - atom_alert_bin = 0; - } - - notifier_ready = FALSE; -} - -/***** testing *****/ - -void -create_test_alerts(void) { - - khui_alert * a; - int i; - - for (i=0; i < 50; i++) { - wchar_t buf[128]; - - StringCbPrintf(buf, sizeof(buf), L"Foo bar baz. This is alert number %d", i); - khui_alert_create_simple(L"Title", buf, KHERR_INFO, &a); - khui_alert_set_type(a, KHUI_ALERTTYPE_PLUGIN); - khui_alert_set_suggestion(a, L"This is a suggestion. It is kinda long to see if the word wrapping actually works as we expect it to. Just in case, here's a line feed.\n\nDoes this show up on a different line? Cool!"); - - khui_alert_add_command(a, KHUI_ACTION_NEW_CRED); - khui_alert_add_command(a, KHUI_ACTION_CLOSE_APP); - khui_alert_add_command(a, KHUI_ACTION_PROPERTIES); - khui_alert_add_command(a, KHUI_ACTION_OPEN_APP); - khui_alert_add_command(a, KHUI_ACTION_VIEW_REFRESH); - - khui_alert_show(a); - khui_alert_release(a); - } -} +/* + * 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$ */ + +#define OEMRESOURCE + +#include +#include + +#define KHUI_NOTIFIER_CLASS L"KhuiNotifierMsgWindowClass" +#define KHUI_ALERTER_CLASS L"KhuiAlerterWindowClass" +#define KHUI_ALERTBIN_CLASS L"KhuiAlertBinWindowClass" + +#define KHUI_NOTIFIER_WINDOW L"KhuiNotifierMsgWindow" + + +/* The commands that are available as default actions when the user + clicks the notification icon. */ + +khm_int32 khm_notifier_actions[] = { + KHUI_ACTION_OPEN_APP, + KHUI_ACTION_NEW_CRED +}; + +khm_size n_khm_notifier_actions = ARRAYLENGTH(khm_notifier_actions); + +/* notifier message for notification icon */ +#define KHUI_WM_NOTIFIER WM_COMMAND + +#define DRAWTEXTOPTIONS (DT_CALCRECT | DT_NOPREFIX | DT_WORDBREAK) + +/* are we showing an alert? */ +#define ALERT_DISPLAYED() (balloon_alert != NULL || khui_alert_windows != NULL) + +/* Forward declarations */ + +struct tag_alerter_wnd_data; +typedef struct tag_alerter_wnd_data alerter_wnd_data; + +struct tag_alert_list; +typedef struct tag_alert_list alert_list; + +static khm_int32 +alert_show(khui_alert * a); + +static khm_int32 +alert_show_minimized(khui_alert * a); + +static khm_int32 +alert_show_normal(khui_alert * a); + +static khm_int32 +alert_show_list(alert_list * alist); + +static khm_int32 +alert_enqueue(khui_alert * a); + +static khm_boolean +alert_is_equal(khui_alert * a1, khui_alert * a2); + +static void +check_for_queued_alerts(void); + +static void +show_queued_alerts(void); + +static khm_int32 +alert_consolidate(alert_list * alist, + khui_alert * alert, + khm_boolean add_from_queue); + +static khm_int32 +get_default_notifier_action(void); + +/* Globals */ + +/* window class registration atom for message only notifier window + class */ +ATOM atom_notifier = 0; + +/* window class registration atom for alert windows */ +ATOM atom_alerter = 0; +/* window class registration atom for the alert "bin", which is the + window that holds all the alerts. */ +ATOM atom_alert_bin = 0; + +/* notifier message window */ +HWND hwnd_notifier = NULL; + +BOOL notifier_ready = FALSE; + +/* The list of alert windows currently active */ +alerter_wnd_data * khui_alert_windows = NULL; + +/* Notification icon for when there are no alerts to be displayed */ +int iid_normal = IDI_NOTIFY_NONE; + +/* The alert currently being displayed in a balloon */ +khui_alert * balloon_alert = NULL; + +/********************************************************************** + Alert Queue + + The alert queue is the data structure that keeps track of all the + alerts that are waiting to be displayed. Alerts will be placed on + the queue if they cannot be immediately displayed for some reason + (e.g. another alert is being displayed, or the user is working in + another window). +***********************************************************************/ + +#define KHUI_ALERT_QUEUE_MAX 64 + +khui_alert * alert_queue[KHUI_ALERT_QUEUE_MAX]; +khm_int32 alert_queue_head = 0; +khm_int32 alert_queue_tail = 0; + +#define is_alert_queue_empty() (alert_queue_head == alert_queue_tail) +#define is_alert_queue_full() (((alert_queue_tail + 1) % KHUI_ALERT_QUEUE_MAX) == alert_queue_head) + +/* NOTE: the alert queue functions are unsafe to call from any thread + other than the UI thread. */ + +static void +alert_queue_put_alert(khui_alert * a) { + if (is_alert_queue_full()) return; + alert_queue[alert_queue_tail++] = a; + khui_alert_hold(a); + alert_queue_tail %= KHUI_ALERT_QUEUE_MAX; +} + +/* the caller needs to release the alert that's returned */ +static khui_alert * +alert_queue_get_alert(void) { + khui_alert * a; + + if (is_alert_queue_empty()) return NULL; + a = alert_queue[alert_queue_head++]; + alert_queue_head %= KHUI_ALERT_QUEUE_MAX; + + return a; /* held */ +} + +static int +alert_queue_get_size(void) { + if (is_alert_queue_empty()) + return 0; + + if (alert_queue_tail < alert_queue_head) { + return (alert_queue_tail + KHUI_ALERT_QUEUE_MAX - alert_queue_head); + } else { + return alert_queue_tail - alert_queue_head; + } +} + +static khui_alert * +alert_queue_get_alert_by_pos(int pos) { + khui_alert * a; + + if (is_alert_queue_empty() || + pos >= alert_queue_get_size() || + pos < 0) { + return NULL; + } + + a = alert_queue[(alert_queue_head + pos) % KHUI_ALERT_QUEUE_MAX]; + if (a) { + khui_alert_hold(a); + } + return a; +} + +static int +alert_queue_delete_alert(khui_alert * a) { + int idx; + int succ; + + idx = alert_queue_head; + while(idx != alert_queue_tail) { + if (alert_queue[idx] == a) + break; + + idx = (idx + 1) % KHUI_ALERT_QUEUE_MAX; + } + + if (idx == alert_queue_tail) + return 0; + +#ifdef DEBUG + assert(alert_queue[idx]); +#endif + khui_alert_release(alert_queue[idx]); + + succ = (idx + 1) % KHUI_ALERT_QUEUE_MAX; + while(succ != alert_queue_tail) { + alert_queue[idx] = alert_queue[succ]; + + succ = (succ + 1) % KHUI_ALERT_QUEUE_MAX; + idx = (idx + 1) % KHUI_ALERT_QUEUE_MAX; + } + + alert_queue_tail = idx; + return 1; +} + +/* the caller needs to release the alert that's returned */ +static khui_alert * +alert_queue_peek(void) { + khui_alert * a; + + if (is_alert_queue_empty()) + return NULL; + + a = alert_queue[alert_queue_head]; + khui_alert_hold(a); + + return a; +} + +/********************************************************************** + Alert List + + A list of alerts. Currently has a fixed upper limit, but the limit + is high enough for now. +***********************************************************************/ + +typedef struct tag_alert_list { + khui_alert * alerts[KHUI_ALERT_QUEUE_MAX]; + int n_alerts; + wchar_t title[KHUI_MAXCCH_TITLE]; +} alert_list; + +static void +alert_list_init(alert_list * alist) { + ZeroMemory(alist, sizeof(*alist)); +} + +static void +alert_list_set_title(alert_list * alist, wchar_t * title) { + StringCbCopy(alist->title, sizeof(alist->title), title); +} + +static khm_int32 +alert_list_add_alert(alert_list * alist, + khui_alert * alert) { + + if (alist->n_alerts == ARRAYLENGTH(alist->alerts)) + return KHM_ERROR_NO_RESOURCES; + + khui_alert_hold(alert); + alist->alerts[alist->n_alerts++] = alert; + + return KHM_ERROR_SUCCESS; +} + +static void +alert_list_destroy(alert_list * alist) { + int i; + + for (i=0; i < alist->n_alerts; i++) { + if (alist->alerts[i] != NULL) { + khui_alert_release(alist->alerts[i]); + alist->alerts[i] = NULL; + } + } + + alist->n_alerts = 0; +} + + +/********************************************************************** + Notifier Window + + The notifier window manages the notification icon and handles + KMSG_ALERT messages sent from the UI library. The window will exist + for the lifetime of the application. +***********************************************************************/ + +/* These are defined for APPVER >= 0x501. We are defining them here + so that we can build with APPVER = 0x500 and use the same binaries + with Win XP. */ + +#ifndef NIN_BALLOONSHOW +#define NIN_BALLOONSHOW (WM_USER + 2) +#endif + +#ifndef NIN_BALLOONHIDE +#define NIN_BALLOONHIDE (WM_USER + 3) +#endif + +#ifndef NIN_BALLOONTIMEOUT +#define NIN_BALLOONTIMEOUT (WM_USER + 4) +#endif + +#ifndef NIN_BALLOONUSERCLICK +#define NIN_BALLOONUSERCLICK (WM_USER + 5) +#endif + + +static LRESULT CALLBACK +notifier_wnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + kmq_message * m; + khm_int32 rv; + + if(uMsg == KMQ_WM_DISPATCH) { + kmq_wm_begin(lParam, &m); + rv = KHM_ERROR_SUCCESS; + + if(m->type == KMSG_ALERT) { + /* handle notifier messages */ + switch(m->subtype) { + case KMSG_ALERT_SHOW: + { + khui_alert * a; + + a = (khui_alert *) m->vparam; +#ifdef DEBUG + assert(a != NULL); +#endif + rv = alert_show(a); + khui_alert_release(a); + } + break; + + case KMSG_ALERT_QUEUE: + { + khui_alert * a; + + a = (khui_alert *) m->vparam; +#ifdef DEBUG + assert(a != NULL); +#endif + rv = alert_enqueue(a); + khui_alert_release(a); + } + break; + + case KMSG_ALERT_CHECK_QUEUE: + check_for_queued_alerts(); + break; + + case KMSG_ALERT_SHOW_QUEUED: + show_queued_alerts(); + break; + + case KMSG_ALERT_SHOW_MODAL: + { + khui_alert * a; + + a = (khui_alert *) m->vparam; +#ifdef DEBUG + assert(a != NULL); +#endif + khui_alert_lock(a); + a->flags |= KHUI_ALERT_FLAG_MODAL; + khui_alert_unlock(a); + + rv = alert_show(a); + + if (KHM_SUCCEEDED(rv)) { + khm_message_loop_int(&a->displayed); + } + + khui_alert_release(a); + } + break; + } + } else if (m->type == KMSG_CRED && + m->subtype == KMSG_CRED_ROOTDELTA) { + + KillTimer(hwnd, KHUI_REFRESH_TIMER_ID); + SetTimer(hwnd, KHUI_REFRESH_TIMER_ID, + KHUI_REFRESH_TIMEOUT, + NULL); + + } + + return kmq_wm_end(m, rv); + } else if (uMsg == KHUI_WM_NOTIFIER) { + /* Handle events generated from the notification icon */ + + /* wParam is the identifier of the notify icon, but we only + have one. */ + switch(lParam) { + case WM_CONTEXTMENU: + { + POINT pt; + int menu_id; + khui_menu_def * mdef; + khui_action_ref * act; + khm_size i, n; + khm_int32 def_cmd; + + /* before we show the context menu, we need to make + sure that the default action for the notification + icon is present in the menu and that it is marked + as the default. */ + + def_cmd = get_default_notifier_action(); + + if (khm_is_main_window_visible()) { + menu_id = KHUI_MENU_ICO_CTX_NORMAL; + + if (def_cmd == KHUI_ACTION_OPEN_APP) + def_cmd = KHUI_ACTION_CLOSE_APP; + } else { + menu_id = KHUI_MENU_ICO_CTX_MIN; + } + + mdef = khui_find_menu(menu_id); + +#ifdef DEBUG + assert(mdef); +#endif + n = khui_menu_get_size(mdef); + for (i=0; i < n; i++) { + act = khui_menu_get_action(mdef, i); + if (!(act->flags & KHUI_ACTIONREF_PACTION) && + (act->action == def_cmd)) + break; + } + + if (i < n) { + if (!(act->flags & KHUI_ACTIONREF_DEFAULT)) { + khui_menu_remove_action(mdef, i); + khui_menu_insert_action(mdef, i, def_cmd, KHUI_ACTIONREF_DEFAULT); + } else { + /* we are all set */ + } + } else { + /* the default action was not found on the context + menu */ +#ifdef DEBUG + assert(FALSE); +#endif + khui_menu_insert_action(mdef, 0, def_cmd, KHUI_ACTIONREF_DEFAULT); + } + + SetForegroundWindow(khm_hwnd_main); + + GetCursorPos(&pt); + khm_menu_show_panel(menu_id, pt.x, pt.y); + + PostMessage(khm_hwnd_main, WM_NULL, 0, 0); + } + break; + + case NIN_SELECT: + /* fall through */ + case NIN_KEYSELECT: + /* If there were any alerts waiting to be shown, we show + them. Otherwise we perform the default action. */ + khm_notify_icon_activate(); + break; + + case NIN_BALLOONUSERCLICK: + if (balloon_alert) { + khui_alert * a; + + khm_notify_icon_change(KHERR_NONE); + + a = balloon_alert; + balloon_alert = NULL; + + khui_alert_lock(a); + a->displayed = FALSE; + + if ((a->flags & KHUI_ALERT_FLAG_DEFACTION) && + !(a->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW) && + a->n_alert_commands > 0) { + PostMessage(khm_hwnd_main, WM_COMMAND, + MAKEWPARAM(a->alert_commands[0], + 0), + 0); + } else if (a->flags & + KHUI_ALERT_FLAG_REQUEST_WINDOW) { + khm_show_main_window(); + alert_show_normal(a); + } + + khui_alert_unlock(a); + khui_alert_release(a); + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + break; + + case NIN_BALLOONHIDE: + case NIN_BALLOONTIMEOUT: + khm_notify_icon_change(KHERR_NONE); + if (balloon_alert) { + khui_alert * a; + a = balloon_alert; + balloon_alert = NULL; + + khui_alert_lock(a); + a->displayed = FALSE; + khui_alert_unlock(a); + + khui_alert_release(a); + } + break; + } + } else if (uMsg == WM_TIMER) { + if (wParam == KHUI_TRIGGER_TIMER_ID) { + KillTimer(hwnd, KHUI_TRIGGER_TIMER_ID); + khm_timer_fire(hwnd); + } else if (wParam == KHUI_REFRESH_TIMER_ID) { + KillTimer(hwnd, KHUI_REFRESH_TIMER_ID); + kcdb_identity_refresh_all(); + khm_timer_refresh(hwnd); + } + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +ATOM +khm_register_notifier_wnd_class(void) +{ + WNDCLASSEX wcx; + + ZeroMemory(&wcx, sizeof(wcx)); + + wcx.cbSize = sizeof(wcx); + wcx.style = 0; + wcx.lpfnWndProc = notifier_wnd_proc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = 0; + wcx.hInstance = khm_hInstance; + wcx.hIcon = NULL; + wcx.hCursor = NULL; + wcx.hbrBackground = NULL; + wcx.lpszMenuName = NULL; + wcx.lpszClassName = KHUI_NOTIFIER_CLASS; + wcx.hIconSm = NULL; + + atom_notifier = RegisterClassEx(&wcx); + + return atom_notifier; +} + +/********************************************************************* + Alerter +**********************************************************************/ + +typedef struct tag_alerter_alert_data { + khui_alert * alert; + + BOOL seen; /* has the user seen this alert? */ + + BOOL has_commands; /* we cache the value here. otherwise + we'll have to get a lock on the + alert each time we have to find out + whether there are any commands for + this alert. */ + + RECT r_alert; /* the entire alert, relative to self. */ + + /* the following rects are relative to the top left of r_alert. */ + + RECT r_title; /* the title. deflate by padding to + get the text rect. */ + RECT r_icon; /* rect for icon */ + RECT r_message; /* rect for the text. no padding + necessary. */ + RECT r_suggestion; /* rect for the suggestion. deflate + by padding to get the suggestion + rect. The suggestion rect includes + space for the small icon on the + left and padding between the icon + and the text. The size of the small + icon are as per system metrics + SM_C{X,Y}SMICON. Padding is + s_pad.cx vertical. */ + + int n_cmd_buttons; /* number of command buttons in this alert. */ + + RECT r_buttons[KHUI_MAX_ALERT_COMMANDS]; + /* rects for the command buttons. */ + + HWND hwnd_buttons[KHUI_MAX_ALERT_COMMANDS]; + /* handles for the command buttons */ + + HWND hwnd_marker; + /* handle to the marker window used as + a tab-stop target when there are + not buttons associated with the + alert. */ + + LDCL(struct tag_alerter_alert_data); +} alerter_alert_data; + +typedef struct tag_alerter_wnd_data { + HWND hwnd; + HFONT hfont; + + wchar_t caption[KHUI_MAXCCH_TITLE]; /* the original + caption for the + dialog. */ + + HWND hw_bin; + HWND hw_scroll; + HWND hw_close; + + int scroll_top; + + int n_cmd_buttons; /* total number of command buttons + in all the alerts being shown in + this dialog. */ + + int c_alert; /* current selected alert. */ + + /* various metrics */ + /* calculated during WM_CREATE */ + SIZE s_button; /* minimum dimensions for command button */ + SIZE s_margin; + RECT r_text; /* only .left and .right are used. rest are 0 */ + RECT r_title; /* only .left, .right and .bottom are used. .top=0 */ + SIZE s_icon; + SIZE s_pad; + + int cx_wnd; + int cy_max_wnd; + + /* derived from the alert sizes */ + SIZE s_alerts; + + QDCL(alerter_alert_data); /* queue of alerts that are being + shown in this window. */ + + LDCL(struct tag_alerter_wnd_data); /* for adding to + khui_alert_windows list. */ + + int n_alerts; + +} alerter_wnd_data; + +#define NTF_PARAM DWLP_USER + +/* dialog sizes in base dialog units */ + +#define NTF_MARGIN 5 +#define NTF_WIDTH 200 +#define NTF_MAXHEIGHT 150 + +#define NTF_TITLE_X NTF_MARGIN +#define NTF_TITLE_WIDTH (NTF_WIDTH - NTF_MARGIN*2) +#define NTF_TITLE_HEIGHT 10 + +#define NTF_TEXT_PAD 2 + +#define NTF_BUTTON_HEIGHT 14 + +#define NTF_TIMEOUT 20000 + +#define ALERT_WINDOW_EX_SYLES (WS_EX_DLGMODALFRAME | WS_EX_CONTEXTHELP) +#define ALERT_WINDOW_STYLES (WS_DLGFRAME | WS_POPUPWINDOW | WS_CLIPCHILDREN | DS_NOIDLEMSG) + +/* Control ids */ +#define IDC_NTF_ALERTBIN 998 +#define IDC_NTF_CLOSE 999 + +#define IDC_NTF_CMDBUTTONS 1001 +#define IDC_FROM_IDX(alert, bn) ((alert) * (KHUI_MAX_ALERT_COMMANDS + 1) + (bn) + 1 + IDC_NTF_CMDBUTTONS) +#define ALERT_FROM_IDC(idc) (((idc) - IDC_NTF_CMDBUTTONS) / (KHUI_MAX_ALERT_COMMANDS + 1)) +#define BUTTON_FROM_IDC(idc) (((idc) - IDC_NTF_CMDBUTTONS) % (KHUI_MAX_ALERT_COMMANDS + 1) - 1) + +/* if the only command in an alert is "Close", we assume that the + alert has no commands. */ +#define ALERT_HAS_CMDS(a) ((a)->n_alert_commands > 1 || ((a)->n_alert_commands == 1 && (a)->alert_commands[0] != KHUI_PACTION_CLOSE)) + +#define SCROLL_LINE_SIZE(d) ((d)->cy_max_wnd / 12) + +static void +add_alert_to_wnd_data(alerter_wnd_data * d, + khui_alert * a) { + alerter_alert_data * aiter; + khm_boolean exists = 0; + + khui_alert_lock(a); + + /* check if the alert is already there */ + aiter = QTOP(d); + while(aiter && !exists) { + if (aiter->alert) { + khui_alert_lock(aiter->alert); + + if (alert_is_equal(aiter->alert, a)) { + exists = TRUE; + } + + khui_alert_unlock(aiter->alert); + } + + aiter = QNEXT(aiter); + } + + a->flags |= KHUI_ALERT_FLAG_DISPLAY_WINDOW; + + if (!exists) { + a->displayed = TRUE; + } + + khui_alert_unlock(a); + + if (!exists) { + alerter_alert_data * adata; + + adata = PMALLOC(sizeof(*adata)); + ZeroMemory(adata, sizeof(*adata)); + + adata->alert = a; + khui_alert_hold(a); + + QPUT(d, adata); + d->n_alerts ++; + } +} + +static alerter_wnd_data * +create_alerter_wnd_data(HWND hwnd, alert_list * l) { + alerter_wnd_data * d; + int i; + LONG dlgb; + + d = PMALLOC(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + + d->hwnd = hwnd; + + GetWindowText(hwnd, d->caption, ARRAYLENGTH(d->caption)); + + for (i=0; i < l->n_alerts; i++) { + add_alert_to_wnd_data(d, l->alerts[i]); + } + + d->n_alerts = l->n_alerts; + + LPUSH(&khui_alert_windows, d); + + /* Compute a few metrics first */ + + dlgb = GetDialogBaseUnits(); + +#define DLG2SCNX(x) MulDiv((x), LOWORD(dlgb), 4) +#define DLG2SCNY(y) MulDiv((y), HIWORD(dlgb), 8) + + d->cx_wnd = DLG2SCNX(NTF_WIDTH); + d->cy_max_wnd = DLG2SCNY(NTF_MAXHEIGHT); + + d->s_margin.cx = DLG2SCNX(NTF_MARGIN); + d->s_margin.cy = DLG2SCNY(NTF_MARGIN); + + d->r_title.left = DLG2SCNX(NTF_TITLE_X); + d->r_title.right = DLG2SCNX(NTF_TITLE_X + NTF_TITLE_WIDTH); + d->r_title.top = 0; + d->r_title.bottom = DLG2SCNY(NTF_TITLE_HEIGHT); + + d->s_pad.cx = DLG2SCNX(NTF_TEXT_PAD); + d->s_pad.cy = DLG2SCNY(NTF_TEXT_PAD); + + d->s_icon.cx = GetSystemMetrics(SM_CXICON); + d->s_icon.cy = GetSystemMetrics(SM_CYICON); + + d->r_text.left = d->s_margin.cx * 2 + d->s_icon.cx; + d->r_text.right = d->cx_wnd - d->s_margin.cx; + d->r_text.top = 0; + d->r_text.bottom = 0; + + d->s_button.cx = ((d->r_text.right - d->r_text.left) - (KHUI_MAX_ALERT_COMMANDS - 1) * d->s_margin.cx) / KHUI_MAX_ALERT_COMMANDS; + d->s_button.cy = DLG2SCNY(NTF_BUTTON_HEIGHT); + +#undef DLG2SCNX +#undef DLG2SCNY + + d->c_alert = -1; + + return d; +} + +static void +layout_alert(HDC hdc, alerter_wnd_data * d, + alerter_alert_data * adata) { + RECT r; + size_t len; + int y; + int icon_y; + +#ifdef DEBUG + assert(adata->alert); +#endif + + khui_alert_lock(adata->alert); + + y = 0; + + /* Title */ + + y += d->s_margin.cy; + + /* If there is a title and it differs from the title of the + alerter window, then we have to show the alert title + separately. */ + if (adata->alert->title && + wcscmp(adata->alert->title, d->caption)) { + + CopyRect(&adata->r_title, &d->r_title); + OffsetRect(&adata->r_title, 0, y); + + y = adata->r_title.bottom + d->s_margin.cy; + + } else { + + SetRectEmpty(&adata->r_title); + + } + + /* Icon */ + + SetRect(&adata->r_icon, d->s_margin.cx, y, + d->s_margin.cx + d->s_icon.cx, + y + d->s_icon.cy); + + icon_y = adata->r_icon.bottom + d->s_margin.cy; /* the bottom of the icon */ + + /* Message */ + + if (adata->alert->message && + SUCCEEDED(StringCchLength(adata->alert->message, + KHUI_MAXCCH_MESSAGE, + &len))) { + + CopyRect(&r, &d->r_text); + + DrawTextEx(hdc, adata->alert->message, (int) len, + &r, + DRAWTEXTOPTIONS, + NULL); + + OffsetRect(&r, 0, y); + CopyRect(&adata->r_message, &r); + + y = r.bottom + d->s_margin.cy; + + } else { + + SetRectEmpty(&adata->r_message); + + } + + /* Suggestion */ + + if (adata->alert->suggestion && + SUCCEEDED(StringCchLength(adata->alert->suggestion, + KHUI_MAXCCH_SUGGESTION, + &len))) { + int pad = d->s_pad.cx + GetSystemMetrics(SM_CXSMICON); + + CopyRect(&r, &d->r_text); + r.left += pad; + + DrawTextEx(hdc, adata->alert->suggestion, (int) len, + &r, + DRAWTEXTOPTIONS, + NULL); + + r.left -= pad; + + InflateRect(&r, d->s_pad.cx, d->s_pad.cy); + OffsetRect(&r, 0, -r.top + y); + CopyRect(&adata->r_suggestion, &r); + + y = r.bottom + d->s_margin.cy; + + } else { + + SetRectEmpty(&adata->r_suggestion); + + } + + y = max(y, icon_y); + + /* Buttons */ + + if (ALERT_HAS_CMDS(adata->alert)) { + khm_int32 i; + int x, width; + wchar_t caption[KHUI_MAXCCH_SHORT_DESC]; + size_t len; + SIZE s; + int skip_close; + + adata->has_commands = TRUE; + + if (d->n_alerts > 1) + skip_close = TRUE; + else + skip_close = FALSE; + + x = d->r_text.left; + +#ifdef DEBUG + assert(adata->alert->n_alert_commands <= KHUI_MAX_ALERT_COMMANDS); +#endif + + for (i=0; i < adata->alert->n_alert_commands; i++) { + + if (adata->alert->alert_commands[i] == KHUI_PACTION_CLOSE && skip_close) { + SetRectEmpty(&adata->r_buttons[i]); + continue; + } + + caption[0] = L'\0'; + len = 0; + khm_get_action_caption(adata->alert->alert_commands[i], + caption, sizeof(caption)); + StringCchLength(caption, ARRAYLENGTH(caption), &len); + + if (!GetTextExtentPoint32(hdc, caption, (int) len, &s)) { + width = d->s_button.cx; + } else { + width = s.cx + d->s_margin.cx * 2; + } + + if (width < d->s_button.cx) + width = d->s_button.cx; + else if (width > (d->r_text.right - d->r_text.left)) + width = d->r_text.right - d->r_text.left; + + if (x + width > d->r_text.right) { + /* new line */ + x = d->r_text.left; + y += d->s_button.cy + d->s_pad.cy; + } + + SetRect(&adata->r_buttons[i], x, y, x + width, y + d->s_button.cy); + + x += width + d->s_margin.cx; + } + + y += d->s_button.cy + d->s_margin.cy; + } + + khui_alert_unlock(adata->alert); + + /* Now set the rect for the whole alert */ + SetRect(&adata->r_alert, 0, 0, d->cx_wnd, y); + +} + +static void +pick_title_for_alerter_window(alerter_wnd_data * d) { + alerter_alert_data * adata; + wchar_t caption[KHUI_MAXCCH_TITLE]; + khm_boolean common_caption = TRUE; + khui_alert_type ctype = KHUI_ALERTTYPE_NONE; + khm_boolean common_type = TRUE; + + /* - If all the alerts have the same title, then we use the common + title. + + - If all the alerts are of the same type, then we pick a title + that is suitable for the type. + + - All else fails, we use a default caption for the window. + */ + + caption[0] = L'\0'; + adata = QTOP(d); + while (adata && (common_caption || common_type)) { + + if (adata->alert) { + khui_alert_lock(adata->alert); + + if (common_caption) { + if (caption[0] == L'\0') { + if (adata->alert->title) + StringCbCopy(caption, sizeof(caption), adata->alert->title); + } else if (adata->alert->title && + wcscmp(caption, adata->alert->title)) { + common_caption = FALSE; + } + } + + if (common_type) { + if (ctype == KHUI_ALERTTYPE_NONE) + ctype = adata->alert->alert_type; + else if (ctype != adata->alert->alert_type) + common_type = FALSE; + } + + khui_alert_unlock(adata->alert); + } + + adata = QNEXT(adata); + } + + /* just in case someone changes d->caption to a pointer from an + array */ +#ifdef DEBUG + assert(sizeof(d->caption) > sizeof(wchar_t *)); +#endif + + if (common_caption && caption[0] != L'\0') { + StringCbCopy(d->caption, sizeof(d->caption), caption); + } else if (common_type && ctype != KHUI_ALERTTYPE_NONE) { + switch(ctype) { + case KHUI_ALERTTYPE_PLUGIN: + LoadString(khm_hInstance, IDS_ALERTTYPE_PLUGIN, + d->caption, ARRAYLENGTH(d->caption)); + break; + + case KHUI_ALERTTYPE_EXPIRE: + LoadString(khm_hInstance, IDS_ALERTTYPE_EXPIRE, + d->caption, ARRAYLENGTH(d->caption)); + break; + + case KHUI_ALERTTYPE_RENEWFAIL: + LoadString(khm_hInstance, IDS_ALERTTYPE_RENEWFAIL, + d->caption, ARRAYLENGTH(d->caption)); + break; + + case KHUI_ALERTTYPE_ACQUIREFAIL: + LoadString(khm_hInstance, IDS_ALERTTYPE_ACQUIREFAIL, + d->caption, ARRAYLENGTH(d->caption)); + break; + + case KHUI_ALERTTYPE_CHPW: + LoadString(khm_hInstance, IDS_ALERTTYPE_CHPW, + d->caption, ARRAYLENGTH(d->caption)); + break; + + default: + LoadString(khm_hInstance, IDS_ALERT_DEFAULT, + d->caption, ARRAYLENGTH(d->caption)); + } + } else { + LoadString(khm_hInstance, IDS_ALERT_DEFAULT, + d->caption, ARRAYLENGTH(d->caption)); + } + + SetWindowText(d->hwnd, d->caption); +} + +static void +estimate_alerter_wnd_sizes(alerter_wnd_data * d) { + HDC hdc; + HFONT hf_old; + int height = 0; + + alerter_alert_data * adata; + + pick_title_for_alerter_window(d); + + hdc = GetDC(d->hwnd); +#ifdef DEBUG + assert(hdc); +#endif + + if (d->hfont == NULL) + d->hfont = (HFONT) GetStockObject(DEFAULT_GUI_FONT); + +#ifdef DEBUG + assert(d->hfont); +#endif + + hf_old = SelectFont(hdc, d->hfont); + + adata = QTOP(d); + while(adata) { + layout_alert(hdc, d, adata); + + height += adata->r_alert.bottom; + + adata = QNEXT(adata); + } + + SelectFont(hdc, hf_old); + ReleaseDC(d->hwnd, hdc); + + d->s_alerts.cx = d->cx_wnd; + d->s_alerts.cy = height; +} + +static void +layout_command_buttons(alerter_wnd_data * d) { + + alerter_alert_data * adata; + HDWP hdefer; + int y; + + hdefer = BeginDeferWindowPos(d->n_cmd_buttons); + + y = 0; + adata = QTOP(d); + while (adata) { + RECT r; + int i; + + if (!adata->has_commands) + goto done; + + for (i=0; i < adata->n_cmd_buttons; i++) { + if (IsRectEmpty(&adata->r_buttons[i])) { + /* the button is no longer needed */ + if (adata->hwnd_buttons[i] != NULL) { + DestroyWindow(adata->hwnd_buttons[i]); + adata->hwnd_buttons[i] = NULL; + } + + continue; + } + + if (adata->hwnd_buttons[i] == NULL) { + continue; + } + + CopyRect(&r, &adata->r_buttons[i]); + OffsetRect(&r, 0, y - d->scroll_top); + + DeferWindowPos(hdefer, + adata->hwnd_buttons[i], NULL, + r.left, r.top, 0, 0, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | + SWP_NOSIZE); + } + + done: + y += adata->r_alert.bottom; + adata = QNEXT(adata); + } + + EndDeferWindowPos(hdefer); +} + +static void +setup_alerter_window_controls(alerter_wnd_data * d) { + + RECT r_alerts; + RECT r_window; + RECT r_client; + RECT r_parent; + HWND hw_parent; + HWND hw_focus = NULL; + BOOL close_button = FALSE; + BOOL scrollbar = FALSE; + BOOL redraw_scollbar = FALSE; + + /* estimate_alerter_wnd_sizes() must be called before calling + this. */ +#ifdef DEBUG + assert(d->s_alerts.cy > 0); +#endif + + r_alerts.left = 0; + r_alerts.top = 0; + r_alerts.right = d->cx_wnd; + + if (d->s_alerts.cy > d->cy_max_wnd) { + + BOOL redraw = FALSE; + + r_alerts.right += GetSystemMetrics(SM_CXVSCROLL); + r_alerts.bottom = d->cy_max_wnd; + + CopyRect(&r_client, &r_alerts); + r_client.bottom += d->s_margin.cy + d->s_button.cy + d->s_pad.cy; + close_button = TRUE; + + if (d->scroll_top > d->s_alerts.cy - d->cy_max_wnd) + d->scroll_top = d->s_alerts.cy - d->cy_max_wnd; + + scrollbar = TRUE; + } else { + r_alerts.bottom = d->s_alerts.cy; + + CopyRect(&r_client, &r_alerts); + + if (d->n_alerts == 1) { + + if (!QTOP(d)->has_commands) { + r_client.bottom += d->s_margin.cy * 2 + d->s_button.cy; + close_button = TRUE; + } + + } else { + + r_client.bottom += d->s_margin.cy * 2 + d->s_button.cy; + close_button = TRUE; + } + + d->scroll_top = 0; + } + + if (d->hw_bin == NULL) { + d->hw_bin = CreateWindowEx(WS_EX_CONTROLPARENT, + MAKEINTATOM(atom_alert_bin), + L"Alert Container", + WS_CHILD | WS_CLIPCHILDREN | + WS_VISIBLE | + ((scrollbar)? WS_VSCROLL : 0), + r_alerts.left, r_alerts.top, + r_alerts.right - r_alerts.left, + r_alerts.bottom - r_alerts.top, + d->hwnd, + (HMENU) IDC_NTF_ALERTBIN, + khm_hInstance, + (LPVOID) d); + } else { + redraw_scollbar = TRUE; + SetWindowLongPtr(d->hw_bin, GWL_STYLE, + WS_CHILD | WS_CLIPCHILDREN | + WS_VISIBLE | + ((scrollbar)? WS_VSCROLL : 0)); + SetWindowPos(d->hw_bin, NULL, + r_alerts.left, r_alerts.top, + r_alerts.right - r_alerts.left, + r_alerts.bottom - r_alerts.top, + SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOACTIVATE); + } + + if (scrollbar) { + SCROLLINFO si; + + ZeroMemory(&si, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; + si.nMin = 0; + si.nMax = d->s_alerts.cy; + si.nPage = d->cy_max_wnd; + si.nPos = d->scroll_top; + + SetScrollInfo(d->hw_bin, SB_VERT, &si, redraw_scollbar); + } + + /* create the action buttons */ + { + alerter_alert_data * adata; + int y; + int idx; + HWND last_window = HWND_TOP; + int n_buttons = 0; + + idx = 0; + y = - d->scroll_top; + adata = QTOP(d); + while(adata) { + if (adata->has_commands) { + int i; + wchar_t caption[KHUI_MAXCCH_SHORT_DESC]; + RECT r; + + if (adata->hwnd_marker) { + DestroyWindow(adata->hwnd_marker); + adata->hwnd_marker = NULL; + } + + khui_alert_lock(adata->alert); + + adata->n_cmd_buttons = adata->alert->n_alert_commands; + + for (i=0; i < adata->alert->n_alert_commands; i++) { + + n_buttons ++; + + if (IsRectEmpty(&adata->r_buttons[i])) { + /* this button is not necessary */ + if (adata->hwnd_buttons[i]) { + DestroyWindow(adata->hwnd_buttons[i]); + adata->hwnd_buttons[i] = NULL; + } + + continue; + } + + if (adata->hwnd_buttons[i] != NULL) { + /* already there */ + CopyRect(&r, &adata->r_buttons[i]); + OffsetRect(&r, 0, y); + + SetWindowPos(adata->hwnd_buttons[i], last_window, + r.left, r.top, + r.right - r.left, + r.bottom - r.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | + SWP_SHOWWINDOW); + + last_window = adata->hwnd_buttons[i]; + + if (hw_focus == NULL) + hw_focus = adata->hwnd_buttons[i]; + + continue; + } + + khm_get_action_caption(adata->alert->alert_commands[i], + caption, sizeof(caption)); + + CopyRect(&r, &adata->r_buttons[i]); + OffsetRect(&r, 0, y); + + adata->hwnd_buttons[i] = + CreateWindowEx(0, + L"BUTTON", + caption, + WS_CHILD | WS_TABSTOP | BS_NOTIFY, + r.left, r.top, + r.right - r.left, + r.bottom - r.top, + d->hw_bin, + (HMENU) (INT_PTR) IDC_FROM_IDX(idx, i), + khm_hInstance, + NULL); +#ifdef DEBUG + assert(adata->hwnd_buttons[i]); +#endif + + if (d->hfont) { + SendMessage(adata->hwnd_buttons[i], WM_SETFONT, + (WPARAM) d->hfont, FALSE); + } + + SetWindowPos(adata->hwnd_buttons[i], last_window, + 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | + SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); + + last_window = adata->hwnd_buttons[i]; + + if (hw_focus == NULL) + hw_focus = adata->hwnd_buttons[i]; + } + + khui_alert_unlock(adata->alert); + } else { + int i; + + /* Destroy any buttons that belong to the alert. We + might have some left over, if there were command + belonging to the alert that were ignored.*/ + + for (i=0; i < adata->n_cmd_buttons; i++) { + if (adata->hwnd_buttons[i]) { + DestroyWindow(adata->hwnd_buttons[i]); + adata->hwnd_buttons[i] = NULL; + } + } + + adata->n_cmd_buttons = 0; + + if (adata->hwnd_marker == NULL) { + adata->hwnd_marker = + CreateWindowEx(0, + L"BUTTON", + L"Marker", + WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_NOTIFY, + -10, 0, + 5, 5, + d->hw_bin, + (HMENU) (INT_PTR) IDC_FROM_IDX(idx, -1), + khm_hInstance, + NULL); +#ifdef DEBUG + assert(adata->hwnd_marker); +#endif + } + + SetWindowPos(adata->hwnd_marker, last_window, + 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | + SWP_NOMOVE | SWP_NOSIZE); + + last_window = adata->hwnd_marker; + + if (scrollbar) { + EnableWindow(adata->hwnd_marker, TRUE); + if (hw_focus == NULL) + hw_focus = adata->hwnd_marker; + } else { + EnableWindow(adata->hwnd_marker, FALSE); + } + } + + y += adata->r_alert.bottom; + adata = QNEXT(adata); + idx++; + } + + d->n_cmd_buttons = n_buttons; + } + + if (close_button) { + if (d->hw_close == NULL) { + wchar_t caption[256]; + + khm_get_action_caption(KHUI_PACTION_CLOSE, caption, sizeof(caption)); + + d->hw_close = CreateWindowEx(0, + L"BUTTON", + caption, + WS_CHILD | BS_DEFPUSHBUTTON | WS_TABSTOP | BS_NOTIFY, + 0,0,100,100, + d->hwnd, + (HMENU) IDC_NTF_CLOSE, + khm_hInstance, + NULL); + +#ifdef DEBUG + assert(d->hw_close); + assert(d->hfont); +#endif + if (d->hfont) + SendMessage(d->hw_close, WM_SETFONT, (WPARAM) d->hfont, FALSE); + } + + { + int x,y,width,height; + + x = d->r_text.left; + y = r_client.bottom - (d->s_margin.cy + d->s_button.cy); + width = d->s_button.cx; + height = d->s_button.cy; + + SetWindowPos(d->hw_close, NULL, + x, y, width, height, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | + SWP_SHOWWINDOW); + } + + if (hw_focus == NULL || d->n_cmd_buttons == 0) + hw_focus = d->hw_close; + + } else { + if (d->hw_close != NULL) { + DestroyWindow(d->hw_close); + d->hw_close = NULL; + } + } + + CopyRect(&r_window, &r_client); + AdjustWindowRectEx(&r_window, ALERT_WINDOW_STYLES, + FALSE, ALERT_WINDOW_EX_SYLES); + OffsetRect(&r_window, -r_window.left, -r_window.top); + + /* center the window above the parent window. */ + + hw_parent = GetWindow(d->hwnd, GW_OWNER); + GetWindowRect(hw_parent, &r_parent); + + { + int x,y; + + x = (r_parent.left + r_parent.right - (r_window.right - r_window.left)) / 2; + y = (r_parent.top + r_parent.bottom - (r_window.bottom - r_window.top)) / 2; + + SetWindowPos(d->hwnd, + HWND_TOP, + x, y, + r_window.right - r_window.left, + r_window.bottom - r_window.top, + SWP_SHOWWINDOW | SWP_NOOWNERZORDER); + } + + if (hw_focus != NULL) + PostMessage(d->hwnd, WM_NEXTDLGCTL, (WPARAM) hw_focus, MAKELPARAM(TRUE, 0)); +} + +static void +scroll_to_position(alerter_wnd_data * d, int new_pos, khm_boolean redraw_scrollbar) { + int delta; + SCROLLINFO si; + HWND hwnd = d->hw_bin; + + if (new_pos < 0) + new_pos = 0; + else if (new_pos > d->s_alerts.cy - d->cy_max_wnd) + new_pos = d->s_alerts.cy - d->cy_max_wnd; + + if (new_pos == d->scroll_top) + return; + + delta = d->scroll_top - new_pos; + + d->scroll_top -= delta; + + ScrollWindowEx(hwnd, 0, delta, + NULL, NULL, NULL, NULL, + SW_INVALIDATE | SW_ERASE); + + layout_command_buttons(d); + + ZeroMemory(&si, sizeof(si)); + + si.fMask = SIF_POS; + si.nPos = d->scroll_top; + + SetScrollInfo(hwnd, SB_VERT, &si, redraw_scrollbar); +} + +static void +select_alert(alerter_wnd_data * d, int alert) { + + int y; + RECT old_sel, new_sel; + alerter_alert_data * adata; + int idx; + + if (d->n_alerts == 1 || + alert < 0 || + alert > d->n_alerts || + d->c_alert == alert) + return; + + SetRectEmpty(&old_sel); + SetRectEmpty(&new_sel); + idx = 0; y = -d->scroll_top; + adata = QTOP(d); + while(adata && (idx <= d->c_alert || idx <= alert)) { + + if (idx == d->c_alert) { + CopyRect(&old_sel, &adata->r_alert); + OffsetRect(&old_sel, 0, y); + } + + if (idx == alert) { + CopyRect(&new_sel, &adata->r_alert); + OffsetRect(&new_sel, 0, y); + } + + y += adata->r_alert.bottom; + idx ++; + adata = QNEXT(adata); + } + + d->c_alert = alert; + if (!IsRectEmpty(&old_sel)) + InvalidateRect(d->hw_bin, &old_sel, TRUE); + if (!IsRectEmpty(&new_sel)) + InvalidateRect(d->hw_bin, &new_sel, TRUE); +} + +static void +ensure_command_is_visible(alerter_wnd_data * d, int id) { + int alert_idx; + int y = 0; + alerter_alert_data * adata; + int new_pos = 0; + + alert_idx = ALERT_FROM_IDC(id); + +#ifdef DEBUG + assert(alert_idx >= 0 && alert_idx < d->n_alerts); +#endif + if (alert_idx >= d->n_alerts || alert_idx < 0) + return; + + adata = QTOP(d); + while(adata && alert_idx > 0) { + y += adata->r_alert.bottom; + alert_idx--; + adata = QNEXT(adata); + } + +#ifdef DEBUG + assert(alert_idx == 0); + assert(adata); + assert(adata->alert); +#endif + if (adata == NULL || alert_idx != 0) + return; + + new_pos = d->scroll_top; + if (y < d->scroll_top) { + new_pos = y; + } else if (y + adata->r_alert.bottom > d->scroll_top + d->cy_max_wnd) { + new_pos = y + adata->r_alert.bottom - d->cy_max_wnd; + } + + if (new_pos != d->scroll_top) + scroll_to_position(d, new_pos, TRUE); + + select_alert(d, ALERT_FROM_IDC(id)); +} + +static void +handle_mouse_select(alerter_wnd_data * d, int mouse_x, int mouse_y) { + int y; + alerter_alert_data * adata; + + y = -d->scroll_top; + adata = QTOP(d); + while(adata) { + if (y <= mouse_y && (y + adata->r_alert.bottom) > mouse_y) { + HWND hw = NULL; + + if (adata->n_cmd_buttons > 0) + hw = adata->hwnd_buttons[0]; + else + hw = adata->hwnd_marker; + + if (hw && !IsWindowEnabled(hw)) + hw = GetNextDlgTabItem(d->hwnd, hw, FALSE); + + if (hw) + PostMessage(d->hwnd, WM_NEXTDLGCTL, (WPARAM) hw, MAKELPARAM(TRUE, 0)); + + return; + } + + y += adata->r_alert.bottom; + adata = QNEXT(adata); + } +} + +static void +process_command_button(alerter_wnd_data * d, int id) { + int alert_idx; + int cmd_idx; + khm_int32 flags = 0; + khm_int32 cmd = 0; + alerter_alert_data * adata; + int i; + + alert_idx = ALERT_FROM_IDC(id); + cmd_idx = BUTTON_FROM_IDC(id); + +#ifdef DEBUG + assert(alert_idx >= 0 && alert_idx < d->n_alerts); +#endif + if (alert_idx >= d->n_alerts || alert_idx < 0) + return; + + if (cmd_idx < 0) { + /* the user selected a marker button. Nothing to do. */ + return; + } + + adata = QTOP(d); + while(adata && alert_idx > 0) { + alert_idx--; + adata = QNEXT(adata); + } + +#ifdef DEBUG + assert(alert_idx == 0); + assert(adata); + assert(adata->alert); +#endif + if (adata == NULL || alert_idx != 0) + return; + + khui_alert_lock(adata->alert); +#ifdef DEBUG + assert(cmd_idx >= 0 && cmd_idx < adata->alert->n_alert_commands); +#endif + + if (cmd_idx >= 0 && cmd_idx < adata->alert->n_alert_commands) { + cmd = adata->alert->alert_commands[cmd_idx]; + } + + flags = adata->alert->flags; + + adata->alert->response = cmd; + + khui_alert_unlock(adata->alert); + + /* if we were supposed to dispatch the command, do so */ + if (cmd != 0 && + cmd != KHUI_PACTION_CLOSE && + (flags & KHUI_ALERT_FLAG_DISPATCH_CMD)) { + PostMessage(khm_hwnd_main, WM_COMMAND, + MAKEWPARAM(cmd, 0), 0); + } + + /* if this was the only alert in the alert group and its close + button was clicked, we close the alert window. Otherwise, the + alert window creates its own close button that closes the + window. */ + if (d->n_alerts == 1) { + PostMessage(d->hwnd, WM_CLOSE, 0, 0); + } + + /* While we are at it, we should disable the buttons for this + alert since we have already dispatched the command for it. */ + if (cmd != 0) { + HWND hw_focus = GetFocus(); + khm_boolean focus_trapped = FALSE; + + for (i=0; i < adata->n_cmd_buttons; i++) { + if (adata->hwnd_buttons[i]) { + if (hw_focus == adata->hwnd_buttons[i]) + focus_trapped = TRUE; + + EnableWindow(adata->hwnd_buttons[i], FALSE); + } + } + + if (focus_trapped) { + hw_focus = GetNextDlgTabItem(d->hwnd, hw_focus, FALSE); + if (hw_focus) + PostMessage(d->hwnd, WM_NEXTDLGCTL, (WPARAM) hw_focus, MAKELPARAM(TRUE,0)); + } + } +} + +static void +destroy_alerter_wnd_data(alerter_wnd_data * d) { + alerter_alert_data * adata; + + LDELETE(&khui_alert_windows, d); + + QGET(d, &adata); + while(adata) { + + if (adata->alert) { + + khui_alert_lock(adata->alert); + + adata->alert->displayed = FALSE; + + khui_alert_unlock(adata->alert); + + khui_alert_release(adata->alert); + adata->alert = NULL; + } + + PFREE(adata); + + QGET(d, &adata); + } + + PFREE(d); +} + +/* both ref and to_add must be locked and held */ +static khm_boolean +alert_can_consolidate(khui_alert * ref, + khui_alert * to_add, + alert_list * alist) { + + /* first check if we can add anything */ + if (alist->n_alerts == ARRAYLENGTH(alist->alerts)) + return FALSE; + +#ifdef DEBUG + assert(to_add != NULL); +#endif + + if (ref == NULL) { + /* we are testing whether to_add should be added to the alist + on its own. */ + if ((to_add->flags & KHUI_ALERT_FLAG_DISPLAY_BALLOON) && + !(to_add->flags & KHUI_ALERT_FLAG_DISPLAY_WINDOW)) { + /* already displayed */ + return FALSE; + } + + if ((to_add->flags & (KHUI_ALERT_FLAG_REQUEST_BALLOON | + KHUI_ALERT_FLAG_REQUEST_WINDOW)) == KHUI_ALERT_FLAG_REQUEST_BALLOON) { + /* needs to be shown in a balloon */ + return FALSE; + } + + return TRUE; + } + + /* if the ref or to_add are marked for modal, then we can't + consolidate them */ + if ((ref->flags & KHUI_ALERT_FLAG_MODAL) || + (to_add->flags & KHUI_ALERT_FLAG_MODAL)) + return FALSE; + + /* also, if either of them have requested to be exclusively shown + in a balloon, then we can't consolidate them. */ + if (((ref->flags & (KHUI_ALERT_FLAG_REQUEST_BALLOON | + KHUI_ALERT_FLAG_REQUEST_WINDOW)) == KHUI_ALERT_FLAG_REQUEST_BALLOON) + + || + + ((to_add->flags & (KHUI_ALERT_FLAG_REQUEST_BALLOON | + KHUI_ALERT_FLAG_REQUEST_WINDOW)) == KHUI_ALERT_FLAG_REQUEST_BALLOON)) + return FALSE; + + /* for now, all we check if whether they are of the same type. */ + if (ref->alert_type != KHUI_ALERTTYPE_NONE && + ref->alert_type == to_add->alert_type) + return TRUE; + else + return FALSE; +} + +/* both a1 and a2 must be locked */ +static khm_boolean +alert_is_equal(khui_alert * a1, khui_alert * a2) { + khm_int32 i; + + if ((a1->severity != a2->severity) || + (a1->n_alert_commands != a2->n_alert_commands) || + (a1->title && (!a2->title || wcscmp(a1->title, a2->title))) || + (!a1->title && a2->title) || + (a1->message && (!a2->message || wcscmp(a1->message, a2->message))) || + (!a1->message && a2->message) || + (a1->suggestion && (!a2->suggestion || wcscmp(a1->suggestion, a2->suggestion))) || + (!a1->suggestion && a2->suggestion)) { + + return FALSE; + + } + + for (i=0; i < a1->n_alert_commands; i++) { + if (a1->alert_commands[i] != a2->alert_commands[i]) + return FALSE; + } + + return TRUE; +} + +/* the return value is the number of alerts added to alist */ +static khm_int32 +alert_consolidate(alert_list * alist, + khui_alert * alert, + khm_boolean add_from_queue) { + + khui_alert * listtop; + int queue_size = 0; + int i; + khm_int32 n_added = 0; + +#ifdef DEBUG + assert(alist); +#endif + + if (alist->n_alerts == ARRAYLENGTH(alist->alerts)) { + /* can't add anything */ + + return 0; + } + + /* if the list is empty, we just add one alert */ + if (alist->n_alerts == 0) { + + if (alert) { + khui_alert_lock(alert); + if (alert_can_consolidate(NULL, alert, alist)) { + alert_list_add_alert(alist, alert); + n_added ++; + alert = NULL; + } + khui_alert_unlock(alert); + } + + if (n_added == 0 && add_from_queue) { + khui_alert * q; + int i; + + queue_size = alert_queue_get_size(); + for (i=0; i < queue_size && n_added == 0; i++) { + q = alert_queue_get_alert_by_pos(i); + if (q) { + khui_alert_lock(q); + if (alert_can_consolidate(NULL, q, alist)) { + alert_list_add_alert(alist, q); + n_added++; + alert_queue_delete_alert(q); + } + khui_alert_unlock(q); + khui_alert_release(q); + } + } + } + + if (n_added == 0) { + /* nothing to add */ + return 0; + } + } + + /* at this point, the alert list is not empty */ +#ifdef DEBUG + assert(alist->n_alerts != 0); + assert(alist->alerts[0]); +#endif + + listtop = alist->alerts[0]; + khui_alert_hold(listtop); + khui_alert_lock(listtop); + + queue_size = alert_queue_get_size(); + + if (alert) { + khui_alert_lock(alert); + if (alert_can_consolidate(listtop, alert, alist)) { + alert_list_add_alert(alist, alert); + n_added ++; + } + khui_alert_unlock(alert); + } + + if (add_from_queue) { + for (i=0; i < queue_size; i++) { + khui_alert * a; + + a = alert_queue_get_alert_by_pos(i); + if (a == NULL) + continue; + + khui_alert_lock(a); + if (alert_can_consolidate(listtop, a, alist)) { + alert_queue_delete_alert(a); + alert_list_add_alert(alist, a); + n_added ++; + + queue_size--; + i--; +#ifdef DEBUG + assert(alert_queue_get_size() == queue_size); +#endif + } + khui_alert_unlock(a); + khui_alert_release(a); + } + } + + khui_alert_unlock(listtop); + khui_alert_release(listtop); + + return n_added; +} + +static khm_int32 +alert_check_consolidate_window(alerter_wnd_data * d, khui_alert * a) { + alert_list alist; + alerter_alert_data * adata; + int n_added; + + alert_list_init(&alist); + + adata = QTOP(d); + while(adata) { + +#ifdef DEBUG + assert(adata->alert); +#endif + alert_list_add_alert(&alist, adata->alert); + + adata = QNEXT(adata); + } + + n_added = alert_consolidate(&alist, a, FALSE); + + alert_list_destroy(&alist); + + return n_added; +} + +static khm_int32 +alert_show_minimized(khui_alert * a) { + wchar_t tbuf[64]; /* corresponds to NOTIFYICONDATA::szInfoTitle[] */ + wchar_t mbuf[256]; /* corresponds to NOTIFYICONDATA::szInfo[] */ + +#ifdef DEBUG + assert(a); +#endif + if (a == NULL) + return KHM_ERROR_INVALID_PARAM; + + khui_alert_lock(a); + + if (a->message == NULL) + goto done; + + if (a->title == NULL) { + LoadString(khm_hInstance, IDS_ALERT_DEFAULT, + tbuf, ARRAYLENGTH(tbuf)); + } else { + StringCbCopy(tbuf, sizeof(tbuf), a->title); + } + + if (FAILED(StringCbCopy(mbuf, sizeof(mbuf), a->message)) || + (!(a->flags & KHUI_ALERT_FLAG_DEFACTION) && + (a->n_alert_commands > 0 || + a->suggestion || + (a->flags & KHUI_ALERT_FLAG_VALID_ERROR)))) { + /* if mbuf wasn't big enough, this should have copied a + truncated version of it */ + size_t cch_m, cch_p; + wchar_t postfix[256]; + + cch_p = LoadString(khm_hInstance, IDS_ALERT_MOREINFO, postfix, + ARRAYLENGTH(postfix)); + cch_p++; /* account for NULL */ + + StringCchLength(mbuf, ARRAYLENGTH(mbuf), &cch_m); + cch_m = min(cch_m, ARRAYLENGTH(mbuf) - cch_p); + + StringCchCopy(mbuf + cch_m, ARRAYLENGTH(mbuf) - cch_m, + postfix); + + a->flags |= KHUI_ALERT_FLAG_REQUEST_WINDOW; + } + + a->flags |= KHUI_ALERT_FLAG_DISPLAY_BALLOON; + +#ifdef DEBUG + assert(balloon_alert == NULL); +#endif + + if (balloon_alert) { + khui_alert_lock(balloon_alert); + balloon_alert->displayed = FALSE; + khui_alert_unlock(balloon_alert); + khui_alert_release(balloon_alert); + balloon_alert = NULL; + } + + balloon_alert = a; + khui_alert_hold(a); + + a->displayed = TRUE; + + khm_notify_icon_balloon(a->severity, + tbuf, + mbuf, + NTF_TIMEOUT); + + done: + khui_alert_unlock(a); + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +alert_show_normal(khui_alert * a) { + wchar_t buf[256]; + wchar_t * title; + alert_list alist; + + khui_alert_lock(a); + + if(a->title == NULL) { + LoadString(khm_hInstance, IDS_ALERT_DEFAULT, + buf, ARRAYLENGTH(buf)); + title = buf; + } else + title = a->title; + + khui_alert_unlock(a); + + alert_list_init(&alist); + alert_list_set_title(&alist, title); + alert_list_add_alert(&alist, a); + + alert_show_list(&alist); + + alert_list_destroy(&alist); + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +alert_show_list(alert_list * alist) { + HWND hwa; + + /* we don't need to keep track of the window handle + because the window procedure adds it to the dialog + list automatically */ + + hwa = + CreateWindowEx(ALERT_WINDOW_EX_SYLES, + MAKEINTATOM(atom_alerter), + alist->title, + ALERT_WINDOW_STYLES, + 0, 0, 300, 300, // bogus values + khm_hwnd_main, + (HMENU) NULL, + khm_hInstance, + (LPVOID) alist); + + ShowWindow(hwa, SW_SHOW); + + return (hwa != NULL); +} + +static khm_int32 +alert_show(khui_alert * a) { + khm_boolean show_normal = FALSE; + khm_boolean show_mini = FALSE; + + khui_alert_lock(a); + + /* is there an alert already? If so, we just enqueue the message + and let it sit. */ + if (ALERT_DISPLAYED() && + !(a->flags & KHUI_ALERT_FLAG_MODAL)) { + khm_int32 rv; + alerter_wnd_data * wdata; + + khui_alert_unlock(a); + + /* if there are any alerter windows displayed, check if this + alert can be consolidated with any of them. If so, we + should consolidate it. Otherwise, just enqueue it. */ + for(wdata = khui_alert_windows; + wdata; + wdata = LNEXT(wdata)) { + if (alert_check_consolidate_window(wdata, a)) { + + add_alert_to_wnd_data(wdata, a); + estimate_alerter_wnd_sizes(wdata); + setup_alerter_window_controls(wdata); + + return KHM_ERROR_SUCCESS; + + } + } + + rv = alert_enqueue(a); + + if (KHM_SUCCEEDED(rv)) + return KHM_ERROR_HELD; + else + return rv; + } + + if((a->flags & KHUI_ALERT_FLAG_DISPLAY_WINDOW) || + ((a->flags & KHUI_ALERT_FLAG_DISPLAY_BALLOON) && + !(a->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW))) { + + /* The alert has already been displayed. */ + + show_normal = FALSE; + show_mini = FALSE; + + } else { + + if(a->err_context != NULL || + a->err_event != NULL) { + a->flags |= KHUI_ALERT_FLAG_VALID_ERROR; + } + + /* depending on the state of the main window, we + need to either show a window or a balloon */ + if ((a->flags & KHUI_ALERT_FLAG_MODAL) || + (khm_is_main_window_active() && + !(a->flags & KHUI_ALERT_FLAG_REQUEST_BALLOON)) || + (a->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW)) { + + show_normal = TRUE; + + } else { + + show_mini = TRUE; + + } + } + + khui_alert_unlock(a); + + if (show_normal) + return alert_show_normal(a); + else if (show_mini) + return alert_show_minimized(a); + else + return KHM_ERROR_SUCCESS; +} + +static void +show_queued_alerts(void) { + + if (!ALERT_DISPLAYED()) { + + /* show next consolidated batch */ + alert_list alist; + int n; + + alert_list_init(&alist); + n = alert_consolidate(&alist, NULL, TRUE); + + if (n) { + if (n == 1) { + khui_alert_lock(alist.alerts[0]); + + if (alist.alerts[0]->title) { + alert_list_set_title(&alist, alist.alerts[0]->title); + } else { + wchar_t title[KHUI_MAXCCH_TITLE]; + LoadString(khm_hInstance, IDS_ALERT_DEFAULT, + title, ARRAYLENGTH(title)); + alert_list_set_title(&alist, title); + } + + khui_alert_unlock(alist.alerts[0]); + } else { + wchar_t title[KHUI_MAXCCH_TITLE]; + LoadString(khm_hInstance, IDS_ALERT_DEFAULT, + title, ARRAYLENGTH(title)); + alert_list_set_title(&alist, title); + } + + alert_show_list(&alist); + } + + alert_list_destroy(&alist); + + if (n == 0) { + khui_alert * a; + + /* no alerts were shown above. This maybe because none of + the alerts were consolidatable or they were requested + to be shown in a balloon. In this case, we just take + the first alert from the queue and show it manually. */ + + a = alert_queue_get_alert(); + if (a) { + alert_show(a); + khui_alert_release(a); + } + } + + check_for_queued_alerts(); + } +} + + +static void +check_for_queued_alerts(void) { + if (!is_alert_queue_empty()) { + khui_alert * a; + + a = alert_queue_peek(); + + khui_alert_lock(a); + + if (a->title) { + HICON hi; + int res; + + if (a->severity == KHERR_ERROR) + res = OIC_ERROR; + else if (a->severity == KHERR_WARNING) + res = OIC_WARNING; + else + res = OIC_INFORMATION; + + hi = LoadImage(0, MAKEINTRESOURCE(res), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), + LR_SHARED); + + khm_statusbar_set_part(KHUI_SBPART_NOTICE, + hi, + a->title); + } else { + khm_statusbar_set_part(KHUI_SBPART_NOTICE, + NULL, NULL); +#ifdef DEBUG + DebugBreak(); +#endif + } + + khui_alert_unlock(a); + khui_alert_release(a); + + } else { + khm_statusbar_set_part(KHUI_SBPART_NOTICE, + NULL, NULL); + } +} + +static khm_int32 +alert_enqueue(khui_alert * a) { + if (is_alert_queue_full()) + return KHM_ERROR_NO_RESOURCES; + + alert_queue_put_alert(a); + check_for_queued_alerts(); + + return KHM_ERROR_SUCCESS; +} + +/* the alerter window is actually a dialog */ +static LRESULT CALLBACK +alerter_wnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) { + case WM_CREATE: + { + LPCREATESTRUCT lpcs; + alert_list * alist; + alerter_wnd_data * d; + + lpcs = (LPCREATESTRUCT) lParam; + alist = (alert_list *) lpcs->lpCreateParams; + + d = create_alerter_wnd_data(hwnd, alist); + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, NTF_PARAM, (LONG_PTR) d); +#pragma warning(pop) + + khm_add_dialog(hwnd); + khm_enter_modal(hwnd); + + estimate_alerter_wnd_sizes(d); + setup_alerter_window_controls(d); + + if (d->hw_close) { + SetFocus(d->hw_close); + } + + return TRUE; + } + break; /* not reached */ + + case WM_DESTROY: + { + alerter_wnd_data * d; + + /* khm_leave_modal() could be here, but instead it is in + the WM_COMMAND handler. This is because the modal loop + has to be exited before DestroyWindow() is issued. */ + //khm_leave_modal(); + khm_del_dialog(hwnd); + + d = (alerter_wnd_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, NTF_PARAM); + + destroy_alerter_wnd_data(d); + + return TRUE; + } + break; + + case WM_COMMAND: + { + alerter_wnd_data * d; + + d = (alerter_wnd_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, NTF_PARAM); + + if(HIWORD(wParam) == BN_CLICKED) { + if (LOWORD(wParam) == IDC_NTF_CLOSE || + LOWORD(wParam) == KHUI_PACTION_NEXT) { + + khm_leave_modal(); + + DestroyWindow(hwnd); + + return 0; + } + } + } + break; + + case WM_CLOSE: + { + khm_leave_modal(); + + DestroyWindow(hwnd); + + return 0; + } + } + + /* Since this is a custom built dialog, we use DefDlgProc instead + of DefWindowProc. */ + return DefDlgProc(hwnd, uMsg, wParam, lParam); +} + +static LRESULT CALLBACK +alert_bin_wnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + BOOL in_printclient = FALSE; + + switch(uMsg) { + case WM_CREATE: + { + LPCREATESTRUCT lpcs; + alerter_wnd_data * d; + + lpcs = (LPCREATESTRUCT) lParam; + d = (alerter_wnd_data *) lpcs->lpCreateParams; + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) d); +#pragma warning(pop) + } + return 0; + + case WM_ERASEBKGND: + /* we erase the background when we are drawing the alerts + anyway. */ + return 0; + + case WM_PRINTCLIENT: + in_printclient = TRUE; + /* fallthrough */ + case WM_PAINT: + { + HDC hdc; + PAINTSTRUCT ps; + RECT r; + HFONT hf_old; + int y; + alerter_wnd_data * d; + alerter_alert_data * adata; + size_t len; + int idx; + + d = (alerter_wnd_data *) (LONG_PTR) GetWindowLongPtr(hwnd, GWLP_USERDATA); +#ifdef DEBUG + assert(d); +#endif + + if (in_printclient) { + hdc = (HDC) wParam; + } else { + hdc = BeginPaint(hwnd, &ps); + } + +#ifdef DEBUG + assert(hdc); + assert(d->hfont); +#endif + +#ifdef ALERT_STATIC_BACKGROUND + if (in_printclient || ps.fErase) { + HBRUSH hb_background; + + hb_background = GetSysColorBrush(COLOR_BTNFACE); + + GetClientRect(hwnd, &r); + FillRect(hdc, &r, hb_background); + } +#endif + + SetBkMode(hdc, TRANSPARENT); + + hf_old = SelectFont(hdc, d->hfont); + + y = -d->scroll_top; + idx = 0; + /* go through the alerts and display them */ + adata = QTOP(d); + while(adata) { + khui_alert * a; + +#ifndef ALERT_STATIC_BACKGROUND +#define MIX_C(v1, v2, p) (((int)v1) * p + (((int) v2) * (256 - p))) +#define ALPHA 50 + if (in_printclient || ps.fErase) { + TRIVERTEX v[2]; + GRADIENT_RECT gr; + COLORREF clr; + COLORREF clr2; + + CopyRect(&r, &adata->r_alert); + OffsetRect(&r, 0, y); + + v[0].x = r.left; + v[0].y = r.top; + v[0].Alpha = 0; + + v[1].x = r.right; + v[1].y = r.bottom; + v[1].Alpha = 0; + + if (idx == d->c_alert) { + clr = GetSysColor(COLOR_HOTLIGHT); + + clr2 = GetSysColor(COLOR_BTNHIGHLIGHT); + v[0].Red = MIX_C(GetRValue(clr), GetRValue(clr2), ALPHA); + v[0].Green = MIX_C(GetGValue(clr), GetGValue(clr2), ALPHA); + v[0].Blue = MIX_C(GetBValue(clr), GetBValue(clr2), ALPHA); + + clr2 = GetSysColor(COLOR_BTNFACE); + v[1].Red = MIX_C(GetRValue(clr), GetRValue(clr2), ALPHA); + v[1].Green = MIX_C(GetGValue(clr), GetGValue(clr2), ALPHA); + v[1].Blue = MIX_C(GetBValue(clr), GetBValue(clr2), ALPHA); + } else { + clr = GetSysColor(COLOR_BTNHIGHLIGHT); + v[0].Red = ((int)GetRValue(clr)) << 8; + v[0].Green = ((int)GetGValue(clr)) << 8; + v[0].Blue = ((int)GetBValue(clr)) << 8; + + clr = GetSysColor(COLOR_BTNFACE); + v[1].Red = ((int)GetRValue(clr)) << 8; + v[1].Green = ((int)GetGValue(clr)) << 8; + v[1].Blue = ((int)GetBValue(clr)) << 8; + } + + gr.UpperLeft = 0; + gr.LowerRight = 1; + GradientFill(hdc, v, 2, &gr, 1, GRADIENT_FILL_RECT_V); + } +#undef ALPHA +#undef MIX_C +#endif + + a = adata->alert; +#ifdef DEBUG + assert(a != NULL); +#endif + khui_alert_lock(a); + + if (!IsRectEmpty(&adata->r_title)) { + + CopyRect(&r, &adata->r_title); + OffsetRect(&r, 0, y); + + StringCchLength(a->title, KHUI_MAXCCH_TITLE, &len); + + DrawEdge(hdc, &r, EDGE_RAISED, BF_RECT | BF_MIDDLE); + + InflateRect(&r, -d->s_pad.cx, -d->s_pad.cy); + + DrawText(hdc, a->title, (int) len, &r, + DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); + } + + { + HICON hicon; + int iid; + + CopyRect(&r, &adata->r_icon); + OffsetRect(&r, 0, y); + + if(a->severity == KHERR_ERROR) + iid = OIC_HAND; + else if(a->severity == KHERR_WARNING) + iid = OIC_BANG; + else + iid = OIC_NOTE; + + hicon = (HICON) LoadImage(NULL, + MAKEINTRESOURCE(iid), + IMAGE_ICON, + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON), + LR_SHARED); + + DrawIcon(hdc, r.left, r.top, hicon); + } + + if (a->message) { + + CopyRect(&r, &adata->r_message); + OffsetRect(&r, 0, y); + + StringCchLength(a->message, KHUI_MAXCCH_MESSAGE, &len); + + DrawText(hdc, a->message, (int) len, &r, + DT_WORDBREAK); + } + + if (a->suggestion) { + HICON hicon; + SIZE sz; + + CopyRect(&r, &adata->r_suggestion); + OffsetRect(&r, 0, y); + + DrawEdge(hdc, &r, EDGE_SUNKEN, BF_RECT | BF_MIDDLE); + + InflateRect(&r, -d->s_pad.cx, -d->s_pad.cy); + + sz.cx = GetSystemMetrics(SM_CXSMICON); + sz.cy = GetSystemMetrics(SM_CYSMICON); + + hicon = (HICON) LoadImage(NULL, + MAKEINTRESOURCE(OIC_NOTE), + IMAGE_ICON, + sz.cx, + sz.cy, + LR_SHARED); + + DrawIconEx(hdc, r.left, r.top, hicon, sz.cx, sz.cy, 0, NULL, + DI_NORMAL); + + r.left += d->s_pad.cx + GetSystemMetrics(SM_CXSMICON); + + StringCchLength(a->suggestion, KHUI_MAXCCH_SUGGESTION, &len); + + DrawText(hdc, a->suggestion, (int) len, &r, + DT_WORDBREAK); + } + khui_alert_unlock(a); + + y += adata->r_alert.bottom; + idx++; + + adata = QNEXT(adata); + } + + SelectFont(hdc, hf_old); + + if (!in_printclient) { + EndPaint(hwnd, &ps); + } + } + return 0; + + case WM_VSCROLL: + { + alerter_wnd_data * d; + int new_pos = 0; + SCROLLINFO si; + + d = (alerter_wnd_data *) (LONG_PTR) GetWindowLongPtr(hwnd, GWLP_USERDATA); +#ifdef DEBUG + assert(d); +#endif + if (d == NULL) + break; /* we can't handle the message */ + + ZeroMemory(&si, sizeof(si)); + + switch(LOWORD(wParam)) { + case SB_BOTTOM: + new_pos = d->s_alerts.cy - d->cy_max_wnd; + break; + + case SB_LINEDOWN: + new_pos = d->scroll_top + SCROLL_LINE_SIZE(d); + break; + + case SB_LINEUP: + new_pos = d->scroll_top - SCROLL_LINE_SIZE(d); + break; + + case SB_PAGEDOWN: + new_pos = d->scroll_top + d->cy_max_wnd; + break; + + case SB_PAGEUP: + new_pos = d->scroll_top - d->cy_max_wnd; + break; + + case SB_THUMBPOSITION: + case SB_THUMBTRACK: + si.fMask = SIF_TRACKPOS; + GetScrollInfo(hwnd, SB_VERT, &si); + new_pos = si.nTrackPos; + break; + + case SB_TOP: + new_pos = 0; + break; + + case SB_ENDSCROLL: + si.fMask = SIF_POS; + si.nPos = d->scroll_top; + SetScrollInfo(hwnd, SB_VERT, &si, TRUE); + return 0; + + default: + return 0; + } + + scroll_to_position(d, new_pos, FALSE); + } + return 0; + + case WM_COMMAND: + { + alerter_wnd_data * d; + + d = (alerter_wnd_data *) (LONG_PTR) GetWindowLongPtr(hwnd, GWLP_USERDATA); +#ifdef DEBUG + assert(d); +#endif + if (d == NULL) + break; + + if (HIWORD(wParam) == BN_CLICKED) { + process_command_button(d, LOWORD(wParam)); + return 0; + } else if (HIWORD(wParam) == BN_SETFOCUS) { + ensure_command_is_visible(d, LOWORD(wParam)); + return 0; + } + } + break; + + case WM_LBUTTONUP: + { + alerter_wnd_data * d; + int x,y; + + d = (alerter_wnd_data *) (LONG_PTR) GetWindowLongPtr(hwnd, GWLP_USERDATA); +#ifdef DEBUG + assert(d); +#endif + if (d == NULL) + break; + + x = GET_X_LPARAM(lParam); + y = GET_Y_LPARAM(lParam); + + handle_mouse_select(d, x, y); + } + break; + + case WM_SIZE: + { + InvalidateRect(hwnd, NULL, TRUE); + } + break; + + case WM_DESTROY: + { + /* nothing needs to be done here */ + } + return 0; + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +ATOM khm_register_alerter_wnd_class(void) +{ + WNDCLASSEX wcx; + + ZeroMemory(&wcx, sizeof(wcx)); + + wcx.cbSize = sizeof(wcx); + wcx.style = + CS_OWNDC | +#if(_WIN32_WINNT >= 0x0501) + ((IS_COMMCTL6())? CS_DROPSHADOW: 0) | +#endif + 0; + wcx.lpfnWndProc = alerter_wnd_proc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = DLGWINDOWEXTRA + sizeof(LONG_PTR); + wcx.hInstance = khm_hInstance; + wcx.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP)); + wcx.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)); + wcx.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); + wcx.lpszMenuName = NULL; + wcx.lpszClassName = KHUI_ALERTER_CLASS; + wcx.hIconSm = NULL; + + atom_alerter = RegisterClassEx(&wcx); + + return atom_alerter; +} + +ATOM khm_register_alert_bin_wnd_class(void) +{ + WNDCLASSEX wcx; + + ZeroMemory(&wcx, sizeof(wcx)); + + wcx.cbSize = sizeof(wcx); + wcx.style = CS_OWNDC; + + wcx.lpfnWndProc = alert_bin_wnd_proc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = sizeof(LONG_PTR); + wcx.hInstance = khm_hInstance; + wcx.hIcon = NULL; + wcx.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)); + wcx.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); + wcx.lpszMenuName = NULL; + wcx.lpszClassName = KHUI_ALERTBIN_CLASS; + wcx.hIconSm = NULL; + + atom_alert_bin = RegisterClassEx(&wcx); + + return atom_alert_bin; +} + +/********************************************************************** + Notification Icon +***********************************************************************/ + +#define KHUI_NOTIFY_ICON_ID 0 + +void khm_notify_icon_add(void) { + NOTIFYICONDATA ni; + wchar_t buf[256]; + + ZeroMemory(&ni, sizeof(ni)); + + ni.cbSize = sizeof(ni); + ni.hWnd = hwnd_notifier; + ni.uID = KHUI_NOTIFY_ICON_ID; + ni.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; + ni.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(iid_normal)); + ni.uCallbackMessage = KHUI_WM_NOTIFIER; + LoadString(khm_hInstance, IDS_NOTIFY_PREFIX, buf, ARRAYLENGTH(buf)); + StringCbCopy(ni.szTip, sizeof(ni.szTip), buf); + LoadString(khm_hInstance, IDS_NOTIFY_READY, buf, ARRAYLENGTH(buf)); + StringCbCat(ni.szTip, sizeof(ni.szTip), buf); + + Shell_NotifyIcon(NIM_ADD, &ni); + + DestroyIcon(ni.hIcon); + + ni.cbSize = sizeof(ni); + ni.uVersion = NOTIFYICON_VERSION; + Shell_NotifyIcon(NIM_SETVERSION, &ni); +} + +void +khm_notify_icon_balloon(khm_int32 severity, + wchar_t * title, + wchar_t * msg, + khm_int32 timeout) { + NOTIFYICONDATA ni; + int iid; + + if (!msg || !title) + return; + + ZeroMemory(&ni, sizeof(ni)); + ni.cbSize = sizeof(ni); + + if (severity == KHERR_INFO) { + ni.dwInfoFlags = NIIF_INFO; + iid = IDI_NOTIFY_INFO; + } else if (severity == KHERR_WARNING) { + ni.dwInfoFlags = NIIF_WARNING; + iid = IDI_NOTIFY_WARN; + } else if (severity == KHERR_ERROR) { + ni.dwInfoFlags = NIIF_ERROR; + iid = IDI_NOTIFY_ERROR; + } else { + ni.dwInfoFlags = NIIF_NONE; + iid = iid_normal; + } + + ni.hWnd = hwnd_notifier; + ni.uID = KHUI_NOTIFY_ICON_ID; + ni.uFlags = NIF_INFO | NIF_ICON; + ni.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(iid)); + + if (FAILED(StringCbCopy(ni.szInfo, sizeof(ni.szInfo), msg))) { + /* too long? */ + StringCchCopyN(ni.szInfo, ARRAYLENGTH(ni.szInfo), + msg, + ARRAYLENGTH(ni.szInfo) - ARRAYLENGTH(ELLIPSIS)); + StringCchCat(ni.szInfo, ARRAYLENGTH(ni.szInfo), + ELLIPSIS); + } + + if (FAILED(StringCbCopy(ni.szInfoTitle, sizeof(ni.szInfoTitle), + title))) { + StringCchCopyN(ni.szInfoTitle, ARRAYLENGTH(ni.szInfoTitle), + title, + ARRAYLENGTH(ni.szInfoTitle) - ARRAYLENGTH(ELLIPSIS)); + StringCchCat(ni.szInfoTitle, ARRAYLENGTH(ni.szInfoTitle), + ELLIPSIS); + } + + ni.uTimeout = timeout; + + Shell_NotifyIcon(NIM_MODIFY, &ni); + + DestroyIcon(ni.hIcon); +} + +void khm_notify_icon_expstate(enum khm_notif_expstate expseverity) { + int new_iid; + + if (expseverity == KHM_NOTIF_OK) + new_iid = IDI_APPICON_OK; + else if (expseverity == KHM_NOTIF_WARN) + new_iid = IDI_APPICON_WARN; + else if (expseverity == KHM_NOTIF_EXP) + new_iid = IDI_APPICON_EXP; + else + new_iid = IDI_NOTIFY_NONE; + + if (iid_normal == new_iid) + return; + + iid_normal = new_iid; + + if (balloon_alert == NULL) + khm_notify_icon_change(KHERR_NONE); +} + +void khm_notify_icon_change(khm_int32 severity) { + NOTIFYICONDATA ni; + wchar_t buf[256]; + int iid; + + if (severity == KHERR_INFO) + iid = IDI_NOTIFY_INFO; + else if (severity == KHERR_WARNING) + iid = IDI_NOTIFY_WARN; + else if (severity == KHERR_ERROR) + iid = IDI_NOTIFY_ERROR; + else + iid = iid_normal; + + ZeroMemory(&ni, sizeof(ni)); + + ni.cbSize = sizeof(ni); + ni.hWnd = hwnd_notifier; + ni.uID = KHUI_NOTIFY_ICON_ID; + ni.uFlags = NIF_ICON | NIF_TIP; + ni.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(iid)); + LoadString(khm_hInstance, IDS_NOTIFY_PREFIX, buf, ARRAYLENGTH(buf)); + StringCbCopy(ni.szTip, sizeof(ni.szTip), buf); + if(severity == KHERR_NONE) + LoadString(khm_hInstance, IDS_NOTIFY_READY, buf, ARRAYLENGTH(buf)); + else + LoadString(khm_hInstance, IDS_NOTIFY_ATTENTION, buf, ARRAYLENGTH(buf)); + StringCbCat(ni.szTip, sizeof(ni.szTip), buf); + + Shell_NotifyIcon(NIM_MODIFY, &ni); + + DestroyIcon(ni.hIcon); +} + +void khm_notify_icon_remove(void) { + NOTIFYICONDATA ni; + + ZeroMemory(&ni, sizeof(ni)); + + ni.cbSize = sizeof(ni); + ni.hWnd = hwnd_notifier; + ni.uID = KHUI_NOTIFY_ICON_ID; + + Shell_NotifyIcon(NIM_DELETE, &ni); +} + +static khm_int32 +get_default_notifier_action(void) { + khm_int32 def_cmd = KHUI_ACTION_OPEN_APP; + khm_handle csp_cw = NULL; + khm_size i; + + if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, + &csp_cw))) + def_cmd; + + khc_read_int32(csp_cw, L"NotificationAction", &def_cmd); + + khc_close_space(csp_cw); + + for (i=0; i < n_khm_notifier_actions; i++) { + if (khm_notifier_actions[i] == def_cmd) + break; + } + + if (i < n_khm_notifier_actions) + return def_cmd; + else + return KHUI_ACTION_OPEN_APP; +} + +void khm_notify_icon_activate(void) { + /* if there are any notifications waiting to be shown and there + are no alerts already being shown, we show them. Otherwise we + execute the default action. */ + + khm_notify_icon_change(KHERR_NONE); + + if (balloon_alert != NULL && khui_alert_windows == NULL) { + + khui_alert * a; + khm_boolean alert_done = FALSE; + + a = balloon_alert; + balloon_alert = NULL; + + khui_alert_lock(a); + + a->displayed = FALSE; + + if ((a->flags & KHUI_ALERT_FLAG_DEFACTION) && + (a->n_alert_commands > 0)) { + + PostMessage(khm_hwnd_main, WM_COMMAND, + MAKEWPARAM(a->alert_commands[0], + 0), + 0); + alert_done = TRUE; + + } else if (a->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW) { + + alert_show_normal(a); + alert_done = TRUE; + + } + khui_alert_unlock(a); + khui_alert_release(a); + + if (alert_done) + return; + } + + if (!is_alert_queue_empty() && !ALERT_DISPLAYED()) { + + khm_show_main_window(); + show_queued_alerts(); + + return; + } + + + /* if none of the above applied, then we perform the default + action for the notification icon. */ + { + khm_int32 cmd = 0; + + cmd = get_default_notifier_action(); + + if (cmd == KHUI_ACTION_OPEN_APP) { + if (khm_is_main_window_visible()) { + khm_hide_main_window(); + } else { + khm_show_main_window(); + } + } else { + khui_action_trigger(cmd, NULL); + } + + check_for_queued_alerts(); + } +} + +/********************************************************************* + Initialization +**********************************************************************/ + +void khm_init_notifier(void) +{ + if(!khm_register_notifier_wnd_class()) + return; + + if(!khm_register_alerter_wnd_class()) + return; + + if(!khm_register_alert_bin_wnd_class()) + return; + + hwnd_notifier = CreateWindowEx(0, + MAKEINTATOM(atom_notifier), + KHUI_NOTIFIER_WINDOW, + 0, + 0,0,0,0, + HWND_MESSAGE, + NULL, + khm_hInstance, + NULL); + + if(hwnd_notifier != NULL) { + kmq_subscribe_hwnd(KMSG_ALERT, hwnd_notifier); + kmq_subscribe_hwnd(KMSG_CRED, hwnd_notifier); + notifier_ready = TRUE; + + khm_notify_icon_add(); + } else { +#ifdef DEBUG + assert(hwnd_notifier != NULL); +#endif + } + khm_timer_init(); + + khm_addr_change_notifier_init(); +} + +void khm_exit_notifier(void) +{ + khm_addr_change_notifier_exit(); + + khm_timer_exit(); + + if(hwnd_notifier != NULL) { + khm_notify_icon_remove(); + kmq_unsubscribe_hwnd(KMSG_ALERT, hwnd_notifier); + kmq_unsubscribe_hwnd(KMSG_CRED, hwnd_notifier); + DestroyWindow(hwnd_notifier); + hwnd_notifier = NULL; + } + + if(atom_notifier != 0) { + UnregisterClass(MAKEINTATOM(atom_notifier), khm_hInstance); + atom_notifier = 0; + } + + if(atom_alerter != 0) { + UnregisterClass(MAKEINTATOM(atom_alerter), khm_hInstance); + atom_alerter = 0; + } + + if(atom_alert_bin != 0) { + UnregisterClass(MAKEINTATOM(atom_alert_bin), khm_hInstance); + atom_alert_bin = 0; + } + + notifier_ready = FALSE; +} + +/***** testing *****/ + +void +create_test_alerts(void) { + + khui_alert * a; + int i; + + for (i=0; i < 50; i++) { + wchar_t buf[128]; + + StringCbPrintf(buf, sizeof(buf), L"Foo bar baz. This is alert number %d", i); + khui_alert_create_simple(L"Title", buf, KHERR_INFO, &a); + khui_alert_set_type(a, KHUI_ALERTTYPE_PLUGIN); + khui_alert_set_suggestion(a, L"This is a suggestion. It is kinda long to see if the word wrapping actually works as we expect it to. Just in case, here's a line feed.\n\nDoes this show up on a different line? Cool!"); + + khui_alert_add_command(a, KHUI_ACTION_NEW_CRED); + khui_alert_add_command(a, KHUI_ACTION_CLOSE_APP); + khui_alert_add_command(a, KHUI_ACTION_PROPERTIES); + khui_alert_add_command(a, KHUI_ACTION_OPEN_APP); + khui_alert_add_command(a, KHUI_ACTION_VIEW_REFRESH); + + khui_alert_show(a); + khui_alert_release(a); + } +} diff --git a/src/windows/identity/ui/notifier.h b/src/windows/identity/ui/notifier.h index a42e63f1f..b0cd5dc2c 100644 --- a/src/windows/identity/ui/notifier.h +++ b/src/windows/identity/ui/notifier.h @@ -1,63 +1,63 @@ -/* - * 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_NOTIFIER_H -#define __KHIMAIRA_NOTIFIER_H - -extern HWND hwnd_notifier; - -enum khm_notif_expstate { - KHM_NOTIF_EMPTY, - KHM_NOTIF_OK, - KHM_NOTIF_WARN, - KHM_NOTIF_EXP -}; - -extern khm_int32 khm_notifier_actions[]; -extern khm_size n_khm_notifier_actions; - -void -khm_init_notifier(void); - -void -khm_exit_notifier(void); - -void -khm_notify_icon_change(khm_int32 severity); - -void -khm_notify_icon_balloon(khm_int32 severity, - wchar_t * title, - wchar_t * msg, - khm_int32 timeout); - -void -khm_notify_icon_expstate(enum khm_notif_expstate expseverity); - -void -khm_notify_icon_activate(void); - -#endif +/* + * 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_NOTIFIER_H +#define __KHIMAIRA_NOTIFIER_H + +extern HWND hwnd_notifier; + +enum khm_notif_expstate { + KHM_NOTIF_EMPTY, + KHM_NOTIF_OK, + KHM_NOTIF_WARN, + KHM_NOTIF_EXP +}; + +extern khm_int32 khm_notifier_actions[]; +extern khm_size n_khm_notifier_actions; + +void +khm_init_notifier(void); + +void +khm_exit_notifier(void); + +void +khm_notify_icon_change(khm_int32 severity); + +void +khm_notify_icon_balloon(khm_int32 severity, + wchar_t * title, + wchar_t * msg, + khm_int32 timeout); + +void +khm_notify_icon_expstate(enum khm_notif_expstate expseverity); + +void +khm_notify_icon_activate(void); + +#endif diff --git a/src/windows/identity/ui/passwnd.c b/src/windows/identity/ui/passwnd.c index 4084ede41..65cc06fe7 100644 --- a/src/windows/identity/ui/passwnd.c +++ b/src/windows/identity/ui/passwnd.c @@ -1,133 +1,133 @@ -#include - -static ATOM sAtom = 0; -static HINSTANCE shInstance = 0; - -/* Callback for the MITPasswordControl -This is a replacement for the normal edit control. It does not show the -annoying password char in the edit box so that the number of chars in the -password are not known. -*/ - -#define PASSWORDCHAR L'#' -#define DLGHT(ht) (HIWORD(GetDialogBaseUnits())*(ht)/8) -#define DLGWD(wd) (LOWORD(GetDialogBaseUnits())*(wd)/4) - -static -LRESULT -CALLBACK -MITPasswordEditProc( - HWND hWnd, - UINT message, - WPARAM wParam, - LPARAM lParam - ) -{ - static SIZE pwdcharsz; - BOOL pass_the_buck = FALSE; - - if (message > WM_USER && message < 0x7FFF) - pass_the_buck = TRUE; - - switch(message) - { - case WM_GETTEXT: - case WM_GETTEXTLENGTH: - case WM_SETTEXT: - pass_the_buck = TRUE; - break; - case WM_PAINT: - { - HDC hdc; - PAINTSTRUCT ps; - RECT r; - - hdc = BeginPaint(hWnd, &ps); - GetClientRect(hWnd, &r); - Rectangle(hdc, 0, 0, r.right, r.bottom); - EndPaint(hWnd, &ps); - } - break; - case WM_SIZE: - { - MoveWindow(GetDlgItem(hWnd, 1), DLGWD(2), DLGHT(2), - pwdcharsz.cx / 2, pwdcharsz.cy, TRUE); - } - break; - case WM_LBUTTONDOWN: - case WM_SETFOCUS: - { - SetFocus(GetDlgItem(hWnd, 1)); - } - break; - case WM_CREATE: - { - HWND heditchild; - wchar_t pwdchar = PASSWORDCHAR; - HDC hdc; - /* Create a child window of this control for default processing. */ - hdc = GetDC(hWnd); - GetTextExtentPoint32(hdc, &pwdchar, 1, &pwdcharsz); - ReleaseDC(hWnd, hdc); - - heditchild = - CreateWindow(L"edit", L"", WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | - ES_LEFT | ES_PASSWORD | WS_TABSTOP, - 0, 0, 0, 0, - hWnd, - (HMENU)1, - ((LPCREATESTRUCT)lParam)->hInstance, - NULL); - SendMessage(heditchild, EM_SETPASSWORDCHAR, PASSWORDCHAR, 0L); - } - break; - } - - if (pass_the_buck) - return SendMessage(GetDlgItem(hWnd, 1), message, wParam, lParam); - return DefWindowProc(hWnd, message, wParam, lParam); -} - -khm_int32 -khm_register_passwnd_class(void) -{ - if (!sAtom) { - WNDCLASS wndclass; - - memset(&wndclass, 0, sizeof(WNDCLASS)); - - shInstance = khm_hInstance; - - wndclass.style = CS_HREDRAW | CS_VREDRAW; - wndclass.lpfnWndProc = (WNDPROC)MITPasswordEditProc; - wndclass.cbClsExtra = sizeof(HWND); - wndclass.cbWndExtra = 0; - wndclass.hInstance = shInstance; - wndclass.hbrBackground = (void *)(COLOR_WINDOW + 1); - wndclass.lpszClassName = MIT_PWD_DLL_CLASS; - wndclass.hCursor = LoadCursor((HINSTANCE)NULL, IDC_IBEAM); - - sAtom = RegisterClass(&wndclass); - } - - return (sAtom)?KHM_ERROR_SUCCESS:KHM_ERROR_UNKNOWN; -} - -khm_int32 -khm_unregister_passwnd_class(void) -{ - BOOL result = TRUE; - - if ((khm_hInstance != shInstance) || !sAtom) { - return KHM_ERROR_INVALID_OPERATION; - } - - result = UnregisterClass(MIT_PWD_DLL_CLASS, khm_hInstance); - if (result) { - sAtom = 0; - shInstance = 0; - return KHM_ERROR_SUCCESS; - } else { - return KHM_ERROR_UNKNOWN; - } -} +#include + +static ATOM sAtom = 0; +static HINSTANCE shInstance = 0; + +/* Callback for the MITPasswordControl +This is a replacement for the normal edit control. It does not show the +annoying password char in the edit box so that the number of chars in the +password are not known. +*/ + +#define PASSWORDCHAR L'#' +#define DLGHT(ht) (HIWORD(GetDialogBaseUnits())*(ht)/8) +#define DLGWD(wd) (LOWORD(GetDialogBaseUnits())*(wd)/4) + +static +LRESULT +CALLBACK +MITPasswordEditProc( + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam + ) +{ + static SIZE pwdcharsz; + BOOL pass_the_buck = FALSE; + + if (message > WM_USER && message < 0x7FFF) + pass_the_buck = TRUE; + + switch(message) + { + case WM_GETTEXT: + case WM_GETTEXTLENGTH: + case WM_SETTEXT: + pass_the_buck = TRUE; + break; + case WM_PAINT: + { + HDC hdc; + PAINTSTRUCT ps; + RECT r; + + hdc = BeginPaint(hWnd, &ps); + GetClientRect(hWnd, &r); + Rectangle(hdc, 0, 0, r.right, r.bottom); + EndPaint(hWnd, &ps); + } + break; + case WM_SIZE: + { + MoveWindow(GetDlgItem(hWnd, 1), DLGWD(2), DLGHT(2), + pwdcharsz.cx / 2, pwdcharsz.cy, TRUE); + } + break; + case WM_LBUTTONDOWN: + case WM_SETFOCUS: + { + SetFocus(GetDlgItem(hWnd, 1)); + } + break; + case WM_CREATE: + { + HWND heditchild; + wchar_t pwdchar = PASSWORDCHAR; + HDC hdc; + /* Create a child window of this control for default processing. */ + hdc = GetDC(hWnd); + GetTextExtentPoint32(hdc, &pwdchar, 1, &pwdcharsz); + ReleaseDC(hWnd, hdc); + + heditchild = + CreateWindow(L"edit", L"", WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | + ES_LEFT | ES_PASSWORD | WS_TABSTOP, + 0, 0, 0, 0, + hWnd, + (HMENU)1, + ((LPCREATESTRUCT)lParam)->hInstance, + NULL); + SendMessage(heditchild, EM_SETPASSWORDCHAR, PASSWORDCHAR, 0L); + } + break; + } + + if (pass_the_buck) + return SendMessage(GetDlgItem(hWnd, 1), message, wParam, lParam); + return DefWindowProc(hWnd, message, wParam, lParam); +} + +khm_int32 +khm_register_passwnd_class(void) +{ + if (!sAtom) { + WNDCLASS wndclass; + + memset(&wndclass, 0, sizeof(WNDCLASS)); + + shInstance = khm_hInstance; + + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = (WNDPROC)MITPasswordEditProc; + wndclass.cbClsExtra = sizeof(HWND); + wndclass.cbWndExtra = 0; + wndclass.hInstance = shInstance; + wndclass.hbrBackground = (void *)(COLOR_WINDOW + 1); + wndclass.lpszClassName = MIT_PWD_DLL_CLASS; + wndclass.hCursor = LoadCursor((HINSTANCE)NULL, IDC_IBEAM); + + sAtom = RegisterClass(&wndclass); + } + + return (sAtom)?KHM_ERROR_SUCCESS:KHM_ERROR_UNKNOWN; +} + +khm_int32 +khm_unregister_passwnd_class(void) +{ + BOOL result = TRUE; + + if ((khm_hInstance != shInstance) || !sAtom) { + return KHM_ERROR_INVALID_OPERATION; + } + + result = UnregisterClass(MIT_PWD_DLL_CLASS, khm_hInstance); + if (result) { + sAtom = 0; + shInstance = 0; + return KHM_ERROR_SUCCESS; + } else { + return KHM_ERROR_UNKNOWN; + } +} diff --git a/src/windows/identity/ui/passwnd.h b/src/windows/identity/ui/passwnd.h index b0adcf689..c3ab8ef31 100644 --- a/src/windows/identity/ui/passwnd.h +++ b/src/windows/identity/ui/passwnd.h @@ -1,39 +1,39 @@ -/* - * 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_PASSWND_H -#define __KHIMAIRA_PASSWND_H - -/* Declarations for the MIT password change control. Functionally the - same as the regular Windows password edit control but doesn't - display the '*' password character. */ - -#define MIT_PWD_DLL_CLASS L"MITPasswordWnd" - -khm_int32 khm_unregister_passwnd_class(void); -khm_int32 khm_register_passwnd_class(void); - -#endif +/* + * 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_PASSWND_H +#define __KHIMAIRA_PASSWND_H + +/* Declarations for the MIT password change control. Functionally the + same as the regular Windows password edit control but doesn't + display the '*' password character. */ + +#define MIT_PWD_DLL_CLASS L"MITPasswordWnd" + +khm_int32 khm_unregister_passwnd_class(void); +khm_int32 khm_register_passwnd_class(void); + +#endif diff --git a/src/windows/identity/ui/propertywnd.c b/src/windows/identity/ui/propertywnd.c index 4061cd78d..4255b481b 100644 --- a/src/windows/identity/ui/propertywnd.c +++ b/src/windows/identity/ui/propertywnd.c @@ -1,248 +1,248 @@ -/* - * 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 - -typedef struct tag_pw_data { - khm_handle record; - HWND hwnd_lv; -} pw_data; - -ATOM khui_propertywnd_cls; - -#define ID_LISTVIEW 1 - -#define PW_WM_SET_RECORD WM_USER - -void pw_update_property_data(HWND hw, pw_data * d) -{ - HWND hwnd_lv; - khm_int32 * attrs = NULL; - - hwnd_lv = d->hwnd_lv; - - if(hwnd_lv == NULL) - return; - - ListView_DeleteAllItems(hwnd_lv); - - if(d->record != NULL) { - wchar_t * buffer; - khm_size attr_count; - khm_size i; - khm_size cb_buf; - khm_size t; - LVITEM lvi; - int idx; - - if(KHM_FAILED(kcdb_attrib_get_count( - KCDB_ATTR_FLAG_VOLATILE | - KCDB_ATTR_FLAG_HIDDEN, - 0, - &attr_count))) - return; - - attrs = PMALLOC(sizeof(khm_int32) * attr_count); - assert(attrs != NULL); - - kcdb_attrib_get_ids( - KCDB_ATTR_FLAG_VOLATILE | - KCDB_ATTR_FLAG_HIDDEN, - 0, - attrs, - &attr_count); - - cb_buf = sizeof(wchar_t) * 2048; - buffer = PMALLOC(cb_buf); - assert(buffer != NULL); - - for(i=0; irecord, attrs[i], NULL, NULL, NULL))) - continue; - - ZeroMemory(&lvi, sizeof(lvi)); - lvi.mask = LVIF_TEXT | LVIF_PARAM; - lvi.iItem = (int) i; - lvi.iSubItem = 0; - lvi.pszText = buffer; - lvi.lParam = (LPARAM) attrs[i]; - - t = cb_buf; - kcdb_attrib_describe(attrs[i], buffer, &t, KCDB_TS_SHORT); - - idx = ListView_InsertItem(hwnd_lv, &lvi); - - ZeroMemory(&lvi, sizeof(lvi)); - lvi.mask = LVIF_TEXT; - lvi.iItem = idx; - lvi.iSubItem = 1; - lvi.pszText = buffer; - - t = cb_buf; - kcdb_buf_get_attr_string(d->record, attrs[i], buffer, &t, 0); - - ListView_SetItem(hwnd_lv, &lvi); - } - - PFREE(attrs); - PFREE(buffer); - } -} - -LRESULT CALLBACK khui_property_wnd_proc( - HWND hwnd, - UINT msg, - WPARAM wParam, - LPARAM lParam) -{ - BOOL child_msg = FALSE; - pw_data * child; - - switch(msg) { - case WM_CREATE: - { - CREATESTRUCT * cs; - LVCOLUMN lvc; - wchar_t sz_title[256]; - - cs = (CREATESTRUCT *) lParam; - - child = PMALLOC(sizeof(*child)); - ZeroMemory(child, sizeof(*child)); - -#pragma warning(push) -#pragma warning(disable:4244) - SetWindowLongPtr(hwnd, 0, (LONG_PTR) child); -#pragma warning(pop) - - child->hwnd_lv = CreateWindow( - WC_LISTVIEW, - L"", - WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | - LVS_REPORT | LVS_SORTASCENDING, - 0, 0, - cs->cx, cs->cy, - hwnd, - (HMENU) ID_LISTVIEW, - khm_hInstance, - NULL); - - ListView_SetExtendedListViewStyle(child->hwnd_lv, - LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); - - ZeroMemory(&lvc, sizeof(lvc)); - lvc.mask = LVCF_FMT | LVCF_ORDER | LVCF_TEXT | LVCF_WIDTH; - lvc.fmt = LVCFMT_LEFT; - lvc.cx = (cs->cx * 2)/ 5; - lvc.pszText = sz_title; - lvc.iSubItem = 0; - lvc.iOrder = 0; - LoadString(khm_hInstance, IDS_PROP_COL_PROPERTY, sz_title, ARRAYLENGTH(sz_title)); - - ListView_InsertColumn(child->hwnd_lv, 0, &lvc); - - ZeroMemory(&lvc, sizeof(lvc)); - lvc.mask = LVCF_FMT | LVCF_ORDER | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH; - lvc.fmt = LVCFMT_LEFT; - lvc.cx = (cs->cx * 3)/ 5; - lvc.pszText = sz_title; - lvc.iSubItem = 1; - lvc.iOrder = 1; - LoadString(khm_hInstance, IDS_PROP_COL_VALUE, sz_title, ARRAYLENGTH(sz_title)); - - ListView_InsertColumn(child->hwnd_lv, 1, &lvc); - - if(cs->lpCreateParams != NULL) { - child->record = cs->lpCreateParams; - kcdb_buf_hold(child->record); - pw_update_property_data(hwnd, child); - } - } - break; - - case PW_WM_SET_RECORD: - { - child = (pw_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - kcdb_buf_release(child->record); - child->record = (khm_handle) lParam; - kcdb_buf_hold(child->record); - pw_update_property_data(hwnd, child); - } - return 0; - - case WM_DESTROY: - { - child = (pw_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - kcdb_buf_release(child->record); - PFREE(child); - } - break; - - case WM_PAINT: - break; - - default: - child = (pw_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); - child_msg = TRUE; - } - - /* - if(child_msg && child && child->hwnd_lv) - return SendMessage(child->hwnd_lv, msg, wParam, lParam); - else - */ - return DefWindowProc(hwnd, msg, wParam, lParam); -} - -khm_int32 khm_register_propertywnd_class(void) -{ - WNDCLASSEX wcx; - - wcx.cbSize = sizeof(wcx); - wcx.style = CS_DBLCLKS; - wcx.lpfnWndProc = khui_property_wnd_proc; - wcx.cbClsExtra = 0; - wcx.cbWndExtra = sizeof(LONG_PTR); - wcx.hInstance = khm_hInstance; - wcx.hIcon = NULL; - wcx.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); - wcx.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - wcx.lpszMenuName = NULL; - wcx.lpszClassName = KHUI_PROPERTYWND_CLASS_NAME; - wcx.hIconSm = NULL; - - khui_propertywnd_cls = RegisterClassEx(&wcx); - - return (khui_propertywnd_cls == 0)?KHM_ERROR_UNKNOWN:KHM_ERROR_SUCCESS; -} - -khm_int32 khm_unregister_propertywnd_class(void) -{ - UnregisterClass(MAKEINTATOM(khui_propertywnd_cls), khm_hInstance); - - return KHM_ERROR_SUCCESS; -} +/* + * 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 + +typedef struct tag_pw_data { + khm_handle record; + HWND hwnd_lv; +} pw_data; + +ATOM khui_propertywnd_cls; + +#define ID_LISTVIEW 1 + +#define PW_WM_SET_RECORD WM_USER + +void pw_update_property_data(HWND hw, pw_data * d) +{ + HWND hwnd_lv; + khm_int32 * attrs = NULL; + + hwnd_lv = d->hwnd_lv; + + if(hwnd_lv == NULL) + return; + + ListView_DeleteAllItems(hwnd_lv); + + if(d->record != NULL) { + wchar_t * buffer; + khm_size attr_count; + khm_size i; + khm_size cb_buf; + khm_size t; + LVITEM lvi; + int idx; + + if(KHM_FAILED(kcdb_attrib_get_count( + KCDB_ATTR_FLAG_VOLATILE | + KCDB_ATTR_FLAG_HIDDEN, + 0, + &attr_count))) + return; + + attrs = PMALLOC(sizeof(khm_int32) * attr_count); + assert(attrs != NULL); + + kcdb_attrib_get_ids( + KCDB_ATTR_FLAG_VOLATILE | + KCDB_ATTR_FLAG_HIDDEN, + 0, + attrs, + &attr_count); + + cb_buf = sizeof(wchar_t) * 2048; + buffer = PMALLOC(cb_buf); + assert(buffer != NULL); + + for(i=0; irecord, attrs[i], NULL, NULL, NULL))) + continue; + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.mask = LVIF_TEXT | LVIF_PARAM; + lvi.iItem = (int) i; + lvi.iSubItem = 0; + lvi.pszText = buffer; + lvi.lParam = (LPARAM) attrs[i]; + + t = cb_buf; + kcdb_attrib_describe(attrs[i], buffer, &t, KCDB_TS_SHORT); + + idx = ListView_InsertItem(hwnd_lv, &lvi); + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.mask = LVIF_TEXT; + lvi.iItem = idx; + lvi.iSubItem = 1; + lvi.pszText = buffer; + + t = cb_buf; + kcdb_buf_get_attr_string(d->record, attrs[i], buffer, &t, 0); + + ListView_SetItem(hwnd_lv, &lvi); + } + + PFREE(attrs); + PFREE(buffer); + } +} + +LRESULT CALLBACK khui_property_wnd_proc( + HWND hwnd, + UINT msg, + WPARAM wParam, + LPARAM lParam) +{ + BOOL child_msg = FALSE; + pw_data * child; + + switch(msg) { + case WM_CREATE: + { + CREATESTRUCT * cs; + LVCOLUMN lvc; + wchar_t sz_title[256]; + + cs = (CREATESTRUCT *) lParam; + + child = PMALLOC(sizeof(*child)); + ZeroMemory(child, sizeof(*child)); + +#pragma warning(push) +#pragma warning(disable:4244) + SetWindowLongPtr(hwnd, 0, (LONG_PTR) child); +#pragma warning(pop) + + child->hwnd_lv = CreateWindow( + WC_LISTVIEW, + L"", + WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | + LVS_REPORT | LVS_SORTASCENDING, + 0, 0, + cs->cx, cs->cy, + hwnd, + (HMENU) ID_LISTVIEW, + khm_hInstance, + NULL); + + ListView_SetExtendedListViewStyle(child->hwnd_lv, + LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); + + ZeroMemory(&lvc, sizeof(lvc)); + lvc.mask = LVCF_FMT | LVCF_ORDER | LVCF_TEXT | LVCF_WIDTH; + lvc.fmt = LVCFMT_LEFT; + lvc.cx = (cs->cx * 2)/ 5; + lvc.pszText = sz_title; + lvc.iSubItem = 0; + lvc.iOrder = 0; + LoadString(khm_hInstance, IDS_PROP_COL_PROPERTY, sz_title, ARRAYLENGTH(sz_title)); + + ListView_InsertColumn(child->hwnd_lv, 0, &lvc); + + ZeroMemory(&lvc, sizeof(lvc)); + lvc.mask = LVCF_FMT | LVCF_ORDER | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH; + lvc.fmt = LVCFMT_LEFT; + lvc.cx = (cs->cx * 3)/ 5; + lvc.pszText = sz_title; + lvc.iSubItem = 1; + lvc.iOrder = 1; + LoadString(khm_hInstance, IDS_PROP_COL_VALUE, sz_title, ARRAYLENGTH(sz_title)); + + ListView_InsertColumn(child->hwnd_lv, 1, &lvc); + + if(cs->lpCreateParams != NULL) { + child->record = cs->lpCreateParams; + kcdb_buf_hold(child->record); + pw_update_property_data(hwnd, child); + } + } + break; + + case PW_WM_SET_RECORD: + { + child = (pw_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + kcdb_buf_release(child->record); + child->record = (khm_handle) lParam; + kcdb_buf_hold(child->record); + pw_update_property_data(hwnd, child); + } + return 0; + + case WM_DESTROY: + { + child = (pw_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + kcdb_buf_release(child->record); + PFREE(child); + } + break; + + case WM_PAINT: + break; + + default: + child = (pw_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + child_msg = TRUE; + } + + /* + if(child_msg && child && child->hwnd_lv) + return SendMessage(child->hwnd_lv, msg, wParam, lParam); + else + */ + return DefWindowProc(hwnd, msg, wParam, lParam); +} + +khm_int32 khm_register_propertywnd_class(void) +{ + WNDCLASSEX wcx; + + wcx.cbSize = sizeof(wcx); + wcx.style = CS_DBLCLKS; + wcx.lpfnWndProc = khui_property_wnd_proc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = sizeof(LONG_PTR); + wcx.hInstance = khm_hInstance; + wcx.hIcon = NULL; + wcx.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); + wcx.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); + wcx.lpszMenuName = NULL; + wcx.lpszClassName = KHUI_PROPERTYWND_CLASS_NAME; + wcx.hIconSm = NULL; + + khui_propertywnd_cls = RegisterClassEx(&wcx); + + return (khui_propertywnd_cls == 0)?KHM_ERROR_UNKNOWN:KHM_ERROR_SUCCESS; +} + +khm_int32 khm_unregister_propertywnd_class(void) +{ + UnregisterClass(MAKEINTATOM(khui_propertywnd_cls), khm_hInstance); + + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/ui/propertywnd.h b/src/windows/identity/ui/propertywnd.h index 89305dd7b..c4a738eaf 100644 --- a/src/windows/identity/ui/propertywnd.h +++ b/src/windows/identity/ui/propertywnd.h @@ -1,36 +1,36 @@ -/* - * 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_PROPERTYWND_H -#define __KHIMAIRA_PROPERTYWND_H - -#define KHUI_PROPERTYWND_CLASS_NAME L"NetIDMgrPropertyWnd" - -khm_int32 khm_register_propertywnd_class(void); - -khm_int32 khm_unregister_propertywnd_class(void); - -#endif +/* + * 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_PROPERTYWND_H +#define __KHIMAIRA_PROPERTYWND_H + +#define KHUI_PROPERTYWND_CLASS_NAME L"NetIDMgrPropertyWnd" + +khm_int32 khm_register_propertywnd_class(void); + +khm_int32 khm_unregister_propertywnd_class(void); + +#endif diff --git a/src/windows/identity/ui/reqdaemon.c b/src/windows/identity/ui/reqdaemon.c index e72e3e22b..20b126e27 100644 --- a/src/windows/identity/ui/reqdaemon.c +++ b/src/windows/identity/ui/reqdaemon.c @@ -1,453 +1,453 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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 - -ATOM reqdaemon_atom = 0; -HANDLE reqdaemon_thread = NULL; -HWND reqdaemon_hwnd = NULL; - -LRESULT CALLBACK -reqdaemonwnd_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) { - - switch(uMsg) { - case WM_CREATE: - break; - - case WM_CLOSE: - DestroyWindow(hwnd); - break; - - case WM_DESTROY: - reqdaemon_hwnd = NULL; - PostQuitMessage(0); - break; - - /* Leash compatibility */ - case ID_OBTAIN_TGT_WITH_LPARAM: - { - wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; - wchar_t wmapping[ARRAYLENGTH(KHUI_REQD_MAPPING_FORMAT) + 10]; - khm_handle identity = NULL; - LPNETID_DLGINFO pdlginfo; - LRESULT lr = 1; - khm_int32 result; - HANDLE hmap = NULL; - HRESULT hr; - - hr = StringCbPrintf(wmapping, sizeof(wmapping), - KHUI_REQD_MAPPING_FORMAT, (DWORD) lParam); -#ifdef DEBUG - assert(SUCCEEDED(hr)); -#endif - hmap = CreateFileMapping(INVALID_HANDLE_VALUE, - NULL, - PAGE_READWRITE, - 0, 4096, - wmapping); - - if (hmap == NULL) { - return -1; - } else if (hmap != NULL && GetLastError() != ERROR_ALREADY_EXISTS) { - CloseHandle(hmap); - return -1; - } - - pdlginfo = MapViewOfFile(hmap, - FILE_MAP_WRITE, - 0, 0, - sizeof(*pdlginfo)); - - if (pdlginfo == NULL) { - CloseHandle(hmap); - return 1; - } - - if (pdlginfo->in.username[0] && - pdlginfo->in.realm[0] && - SUCCEEDED(StringCbPrintf(widname, - sizeof(widname), - L"%s@%s", - pdlginfo->in.username, - pdlginfo->in.realm))) { - - kcdb_identity_create(widname, - KCDB_IDENT_FLAG_CREATE, - &identity); - } - - widname[0] = 0; - - do { - if (khm_cred_is_in_dialog()) { - khm_cred_wait_for_dialog(INFINITE, NULL, NULL, 0); - } - - if (identity) - khui_context_set_ex(KHUI_SCOPE_IDENT, - identity, - KCDB_CREDTYPE_INVALID, - NULL, - NULL, - 0, - NULL, - pdlginfo, - sizeof(*pdlginfo)); - else - khui_context_reset(); - - if (pdlginfo->dlgtype == NETID_DLGTYPE_TGT) - SendMessage(khm_hwnd_main, WM_COMMAND, - MAKEWPARAM(KHUI_ACTION_NEW_CRED, 0), 0); - else if (pdlginfo->dlgtype == NETID_DLGTYPE_CHPASSWD) - SendMessage(khm_hwnd_main, WM_COMMAND, - MAKEWPARAM(KHUI_ACTION_PASSWD_ID, 0), 0); - else - break; - - if (KHM_FAILED(khm_cred_wait_for_dialog(INFINITE, &result, - widname, - sizeof(widname)))) - continue; - else { - lr = (result != KHUI_NC_RESULT_PROCESS); - break; - } - } while(TRUE); - -#ifdef DEBUG - assert(lr || pdlginfo->dlgtype != NETID_DLGTYPE_TGT || - widname[0]); -#endif - - if (!lr && pdlginfo->dlgtype == NETID_DLGTYPE_TGT && - widname[0]) { - khm_handle out_ident; - wchar_t * atsign; - - atsign = wcsrchr(widname, L'@'); - - if (atsign == NULL) - goto _exit; - - if (KHM_SUCCEEDED(kcdb_identity_create(widname, - 0, - &out_ident))) { - khm_size cb; - - pdlginfo->out.ccache[0] = 0; - - cb = sizeof(pdlginfo->out.ccache); - kcdb_identity_get_attrib(out_ident, - L"Krb5CCName", - NULL, - pdlginfo->out.ccache, - &cb); - kcdb_identity_release(out_ident); - } else { -#ifdef DEBUG - assert(FALSE); -#endif - } - - *atsign++ = 0; - - StringCbCopy(pdlginfo->out.username, - sizeof(pdlginfo->out.username), - widname); - - StringCbCopy(pdlginfo->out.realm, - sizeof(pdlginfo->out.realm), - atsign); - } - - _exit: - - if (pdlginfo) - UnmapViewOfFile(pdlginfo); - if (hmap) - CloseHandle(hmap); - if (identity) - kcdb_identity_release(identity); - - return lr; - } - -#ifdef DEPRECATED_REMOTE_CALL - /* deprecated */ - case ID_OBTAIN_TGT_WITH_LPARAM: - { - char * param = (char *) GlobalLock((HGLOBAL) lParam); - char * username = NULL; - char * realm = NULL; - char * title = NULL; - char * ccache = NULL; - wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; - wchar_t wtitle[KHUI_MAXCCH_TITLE]; - size_t cch; - khm_int32 rv = KHM_ERROR_SUCCESS; - khm_handle identity = NULL; - NETID_DLGINFO dlginfo; - - if (param) { - if (*param) - title = param; - - if (FAILED(StringCchLengthA(param, KHUI_MAXCCH_TITLE, &cch))) { -#ifdef DEBUG - assert(FALSE); -#endif - rv = KHM_ERROR_INVALID_PARAM; - goto _exit_tgt_with_lparam; - } - - param += cch + 1; - - if (*param) - username = param; - - if (FAILED(StringCchLengthA(param, KCDB_IDENT_MAXCCH_NAME, &cch))) { -#ifdef DEBUG - assert(FALSE); -#endif - rv = KHM_ERROR_INVALID_PARAM; - goto _exit_tgt_with_lparam; - } - - param += cch + 1; - - if (*param) - realm = param; - - if (FAILED(StringCchLengthA(param, KCDB_IDENT_MAXCCH_NAME, &cch))) { -#ifdef DEBUG - assert(FALSE); -#endif - rv = KHM_ERROR_INVALID_PARAM; - goto _exit_tgt_with_lparam; - } - - param += cch + 1; - - if (*param) - ccache = param; - } - - if (username && realm) { - - if (FAILED(StringCbPrintf(widname, sizeof(widname), - L"%hs@%hs", username, realm))) { - rv = KHM_ERROR_INVALID_PARAM; - goto _exit_tgt_with_lparam; - } - - rv = kcdb_identity_create(widname, - KCDB_IDENT_FLAG_CREATE, - &identity); - if (KHM_FAILED(rv)) { - goto _exit_tgt_with_lparam; - } - } - - ZeroMemory(&dlginfo, sizeof(dlginfo)); - - dlginfo.size = NETID_DLGINFO_V1_SZ; - dlginfo.dlgtype = NETID_DLGTYPE_TGT; - - if (title) - StringCbCopy(dlginfo.in.title, sizeof(dlginfo.in.title), - wtitle); - if (username) - AnsiStrToUnicode(dlginfo.in.username, sizeof(dlginfo.in.username), - username); - if (realm) - AnsiStrToUnicode(dlginfo.in.realm, sizeof(dlginfo.in.realm), - realm); - - if (ccache) - AnsiStrToUnicode(dlginfo.in.ccache, sizeof(dlginfo.in.ccache), - ccache); - - dlginfo.in.use_defaults = TRUE; - - do { - if (khm_cred_is_in_dialog()) { - khm_cred_wait_for_dialog(INFINITE); - } - - khui_context_set_ex(KHUI_SCOPE_IDENT, - identity, - KCDB_CREDTYPE_INVALID, - NULL, - NULL, - 0, - NULL, - &dlginfo, - sizeof(dlginfo)); - - if (title) { - AnsiStrToUnicode(wtitle, sizeof(wtitle), - title); - - khm_cred_obtain_new_creds(wtitle); - } else { - khm_cred_obtain_new_creds(NULL); - } - - if (KHM_FAILED(khm_cred_wait_for_dialog(INFINITE))) - continue; - else - break; - } while(TRUE); - - _exit_tgt_with_lparam: - if (identity) - kcdb_identity_release(identity); - - GlobalUnlock((HGLOBAL) lParam); - } - return 0; -#endif - - } - - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -DWORD WINAPI -khm_reqdaemon_thread_proc(LPVOID vparam) { - BOOL rv; - MSG msg; -#ifdef DEBUG - DWORD dw; -#endif - - PDESCTHREAD(L"Remote Request Daemon", L"App"); - - khm_register_reqdaemonwnd_class(); - -#ifdef DEBUG - assert(reqdaemon_atom != 0); -#endif - - reqdaemon_hwnd = CreateWindowEx(0, - MAKEINTATOM(reqdaemon_atom), - KHUI_REQDAEMONWND_NAME, - 0, - 0,0,0,0, - HWND_MESSAGE, - NULL, - khm_hInstance, - NULL); - -#ifdef DEBUG - dw = GetLastError(); - assert(reqdaemon_hwnd != NULL); -#endif - - while(rv = GetMessage(&msg, NULL, 0, 0)) { - if (rv == -1) { -#ifdef DEBUG - assert(FALSE); -#endif - break; - } else { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - reqdaemon_thread = NULL; - - khm_unregister_reqdaemonwnd_class(); - - return 0; -} - -void -khm_register_reqdaemonwnd_class(void) { - WNDCLASSEX wcx; - - ZeroMemory(&wcx, sizeof(wcx)); - - wcx.cbSize = sizeof(wcx); - wcx.style = 0; - wcx.lpfnWndProc = reqdaemonwnd_proc; - wcx.cbClsExtra = 0; - wcx.cbWndExtra = 0; - wcx.hInstance = khm_hInstance; - wcx.hIcon = NULL; - wcx.hCursor = NULL; - wcx.hbrBackground = NULL; - wcx.lpszMenuName = NULL; - wcx.lpszClassName = KHUI_REQDAEMONWND_CLASS; - wcx.hIconSm = NULL; - - reqdaemon_atom = RegisterClassEx(&wcx); - -#ifdef DEBUG - assert(reqdaemon_atom != 0); -#endif -} - -void -khm_unregister_reqdaemonwnd_class(void) { - if (reqdaemon_atom != 0) { - UnregisterClass(MAKEINTATOM(reqdaemon_atom), khm_hInstance); - reqdaemon_atom = 0; - } -} - -void -khm_init_request_daemon(void) { -#ifdef DEBUG - assert(reqdaemon_thread == NULL); -#endif - - reqdaemon_thread = CreateThread(NULL, - 0, - khm_reqdaemon_thread_proc, - NULL, - 0, - NULL); - -#ifdef DEBUG - assert(reqdaemon_thread != NULL); -#endif -} - -void -khm_exit_request_daemon(void) { - if (reqdaemon_hwnd == NULL) - return; - - SendMessage(reqdaemon_hwnd, WM_CLOSE, 0, 0); -} +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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 + +ATOM reqdaemon_atom = 0; +HANDLE reqdaemon_thread = NULL; +HWND reqdaemon_hwnd = NULL; + +LRESULT CALLBACK +reqdaemonwnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + switch(uMsg) { + case WM_CREATE: + break; + + case WM_CLOSE: + DestroyWindow(hwnd); + break; + + case WM_DESTROY: + reqdaemon_hwnd = NULL; + PostQuitMessage(0); + break; + + /* Leash compatibility */ + case ID_OBTAIN_TGT_WITH_LPARAM: + { + wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wmapping[ARRAYLENGTH(KHUI_REQD_MAPPING_FORMAT) + 10]; + khm_handle identity = NULL; + LPNETID_DLGINFO pdlginfo; + LRESULT lr = 1; + khm_int32 result; + HANDLE hmap = NULL; + HRESULT hr; + + hr = StringCbPrintf(wmapping, sizeof(wmapping), + KHUI_REQD_MAPPING_FORMAT, (DWORD) lParam); +#ifdef DEBUG + assert(SUCCEEDED(hr)); +#endif + hmap = CreateFileMapping(INVALID_HANDLE_VALUE, + NULL, + PAGE_READWRITE, + 0, 4096, + wmapping); + + if (hmap == NULL) { + return -1; + } else if (hmap != NULL && GetLastError() != ERROR_ALREADY_EXISTS) { + CloseHandle(hmap); + return -1; + } + + pdlginfo = MapViewOfFile(hmap, + FILE_MAP_WRITE, + 0, 0, + sizeof(*pdlginfo)); + + if (pdlginfo == NULL) { + CloseHandle(hmap); + return 1; + } + + if (pdlginfo->in.username[0] && + pdlginfo->in.realm[0] && + SUCCEEDED(StringCbPrintf(widname, + sizeof(widname), + L"%s@%s", + pdlginfo->in.username, + pdlginfo->in.realm))) { + + kcdb_identity_create(widname, + KCDB_IDENT_FLAG_CREATE, + &identity); + } + + widname[0] = 0; + + do { + if (khm_cred_is_in_dialog()) { + khm_cred_wait_for_dialog(INFINITE, NULL, NULL, 0); + } + + if (identity) + khui_context_set_ex(KHUI_SCOPE_IDENT, + identity, + KCDB_CREDTYPE_INVALID, + NULL, + NULL, + 0, + NULL, + pdlginfo, + sizeof(*pdlginfo)); + else + khui_context_reset(); + + if (pdlginfo->dlgtype == NETID_DLGTYPE_TGT) + SendMessage(khm_hwnd_main, WM_COMMAND, + MAKEWPARAM(KHUI_ACTION_NEW_CRED, 0), 0); + else if (pdlginfo->dlgtype == NETID_DLGTYPE_CHPASSWD) + SendMessage(khm_hwnd_main, WM_COMMAND, + MAKEWPARAM(KHUI_ACTION_PASSWD_ID, 0), 0); + else + break; + + if (KHM_FAILED(khm_cred_wait_for_dialog(INFINITE, &result, + widname, + sizeof(widname)))) + continue; + else { + lr = (result != KHUI_NC_RESULT_PROCESS); + break; + } + } while(TRUE); + +#ifdef DEBUG + assert(lr || pdlginfo->dlgtype != NETID_DLGTYPE_TGT || + widname[0]); +#endif + + if (!lr && pdlginfo->dlgtype == NETID_DLGTYPE_TGT && + widname[0]) { + khm_handle out_ident; + wchar_t * atsign; + + atsign = wcsrchr(widname, L'@'); + + if (atsign == NULL) + goto _exit; + + if (KHM_SUCCEEDED(kcdb_identity_create(widname, + 0, + &out_ident))) { + khm_size cb; + + pdlginfo->out.ccache[0] = 0; + + cb = sizeof(pdlginfo->out.ccache); + kcdb_identity_get_attrib(out_ident, + L"Krb5CCName", + NULL, + pdlginfo->out.ccache, + &cb); + kcdb_identity_release(out_ident); + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + + *atsign++ = 0; + + StringCbCopy(pdlginfo->out.username, + sizeof(pdlginfo->out.username), + widname); + + StringCbCopy(pdlginfo->out.realm, + sizeof(pdlginfo->out.realm), + atsign); + } + + _exit: + + if (pdlginfo) + UnmapViewOfFile(pdlginfo); + if (hmap) + CloseHandle(hmap); + if (identity) + kcdb_identity_release(identity); + + return lr; + } + +#ifdef DEPRECATED_REMOTE_CALL + /* deprecated */ + case ID_OBTAIN_TGT_WITH_LPARAM: + { + char * param = (char *) GlobalLock((HGLOBAL) lParam); + char * username = NULL; + char * realm = NULL; + char * title = NULL; + char * ccache = NULL; + wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wtitle[KHUI_MAXCCH_TITLE]; + size_t cch; + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_handle identity = NULL; + NETID_DLGINFO dlginfo; + + if (param) { + if (*param) + title = param; + + if (FAILED(StringCchLengthA(param, KHUI_MAXCCH_TITLE, &cch))) { +#ifdef DEBUG + assert(FALSE); +#endif + rv = KHM_ERROR_INVALID_PARAM; + goto _exit_tgt_with_lparam; + } + + param += cch + 1; + + if (*param) + username = param; + + if (FAILED(StringCchLengthA(param, KCDB_IDENT_MAXCCH_NAME, &cch))) { +#ifdef DEBUG + assert(FALSE); +#endif + rv = KHM_ERROR_INVALID_PARAM; + goto _exit_tgt_with_lparam; + } + + param += cch + 1; + + if (*param) + realm = param; + + if (FAILED(StringCchLengthA(param, KCDB_IDENT_MAXCCH_NAME, &cch))) { +#ifdef DEBUG + assert(FALSE); +#endif + rv = KHM_ERROR_INVALID_PARAM; + goto _exit_tgt_with_lparam; + } + + param += cch + 1; + + if (*param) + ccache = param; + } + + if (username && realm) { + + if (FAILED(StringCbPrintf(widname, sizeof(widname), + L"%hs@%hs", username, realm))) { + rv = KHM_ERROR_INVALID_PARAM; + goto _exit_tgt_with_lparam; + } + + rv = kcdb_identity_create(widname, + KCDB_IDENT_FLAG_CREATE, + &identity); + if (KHM_FAILED(rv)) { + goto _exit_tgt_with_lparam; + } + } + + ZeroMemory(&dlginfo, sizeof(dlginfo)); + + dlginfo.size = NETID_DLGINFO_V1_SZ; + dlginfo.dlgtype = NETID_DLGTYPE_TGT; + + if (title) + StringCbCopy(dlginfo.in.title, sizeof(dlginfo.in.title), + wtitle); + if (username) + AnsiStrToUnicode(dlginfo.in.username, sizeof(dlginfo.in.username), + username); + if (realm) + AnsiStrToUnicode(dlginfo.in.realm, sizeof(dlginfo.in.realm), + realm); + + if (ccache) + AnsiStrToUnicode(dlginfo.in.ccache, sizeof(dlginfo.in.ccache), + ccache); + + dlginfo.in.use_defaults = TRUE; + + do { + if (khm_cred_is_in_dialog()) { + khm_cred_wait_for_dialog(INFINITE); + } + + khui_context_set_ex(KHUI_SCOPE_IDENT, + identity, + KCDB_CREDTYPE_INVALID, + NULL, + NULL, + 0, + NULL, + &dlginfo, + sizeof(dlginfo)); + + if (title) { + AnsiStrToUnicode(wtitle, sizeof(wtitle), + title); + + khm_cred_obtain_new_creds(wtitle); + } else { + khm_cred_obtain_new_creds(NULL); + } + + if (KHM_FAILED(khm_cred_wait_for_dialog(INFINITE))) + continue; + else + break; + } while(TRUE); + + _exit_tgt_with_lparam: + if (identity) + kcdb_identity_release(identity); + + GlobalUnlock((HGLOBAL) lParam); + } + return 0; +#endif + + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +DWORD WINAPI +khm_reqdaemon_thread_proc(LPVOID vparam) { + BOOL rv; + MSG msg; +#ifdef DEBUG + DWORD dw; +#endif + + PDESCTHREAD(L"Remote Request Daemon", L"App"); + + khm_register_reqdaemonwnd_class(); + +#ifdef DEBUG + assert(reqdaemon_atom != 0); +#endif + + reqdaemon_hwnd = CreateWindowEx(0, + MAKEINTATOM(reqdaemon_atom), + KHUI_REQDAEMONWND_NAME, + 0, + 0,0,0,0, + HWND_MESSAGE, + NULL, + khm_hInstance, + NULL); + +#ifdef DEBUG + dw = GetLastError(); + assert(reqdaemon_hwnd != NULL); +#endif + + while(rv = GetMessage(&msg, NULL, 0, 0)) { + if (rv == -1) { +#ifdef DEBUG + assert(FALSE); +#endif + break; + } else { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + reqdaemon_thread = NULL; + + khm_unregister_reqdaemonwnd_class(); + + return 0; +} + +void +khm_register_reqdaemonwnd_class(void) { + WNDCLASSEX wcx; + + ZeroMemory(&wcx, sizeof(wcx)); + + wcx.cbSize = sizeof(wcx); + wcx.style = 0; + wcx.lpfnWndProc = reqdaemonwnd_proc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = 0; + wcx.hInstance = khm_hInstance; + wcx.hIcon = NULL; + wcx.hCursor = NULL; + wcx.hbrBackground = NULL; + wcx.lpszMenuName = NULL; + wcx.lpszClassName = KHUI_REQDAEMONWND_CLASS; + wcx.hIconSm = NULL; + + reqdaemon_atom = RegisterClassEx(&wcx); + +#ifdef DEBUG + assert(reqdaemon_atom != 0); +#endif +} + +void +khm_unregister_reqdaemonwnd_class(void) { + if (reqdaemon_atom != 0) { + UnregisterClass(MAKEINTATOM(reqdaemon_atom), khm_hInstance); + reqdaemon_atom = 0; + } +} + +void +khm_init_request_daemon(void) { +#ifdef DEBUG + assert(reqdaemon_thread == NULL); +#endif + + reqdaemon_thread = CreateThread(NULL, + 0, + khm_reqdaemon_thread_proc, + NULL, + 0, + NULL); + +#ifdef DEBUG + assert(reqdaemon_thread != NULL); +#endif +} + +void +khm_exit_request_daemon(void) { + if (reqdaemon_hwnd == NULL) + return; + + SendMessage(reqdaemon_hwnd, WM_CLOSE, 0, 0); +} diff --git a/src/windows/identity/ui/reqdaemon.h b/src/windows/identity/ui/reqdaemon.h index b55e93c99..99a50f5e0 100644 --- a/src/windows/identity/ui/reqdaemon.h +++ b/src/windows/identity/ui/reqdaemon.h @@ -1,42 +1,42 @@ -/* - * 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_REQDAEMON_H -#define __KHIMAIRA_REQDAEMON_H - -void -khm_register_reqdaemonwnd_class(void); - -void -khm_unregister_reqdaemonwnd_class(void); - -void -khm_init_request_daemon(void); - -void -khm_exit_request_daemon(void); - -#endif +/* + * 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_REQDAEMON_H +#define __KHIMAIRA_REQDAEMON_H + +void +khm_register_reqdaemonwnd_class(void); + +void +khm_unregister_reqdaemonwnd_class(void); + +void +khm_init_request_daemon(void); + +void +khm_exit_request_daemon(void); + +#endif diff --git a/src/windows/identity/ui/resource.h b/src/windows/identity/ui/resource.h index 7be9a84be..1a3c35b23 100644 --- a/src/windows/identity/ui/resource.h +++ b/src/windows/identity/ui/resource.h @@ -1,415 +1,415 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by C:\work\pismere\athena\auth\krb5\src\windows\identity\ui\lang\en_us\khapp.rc -// -#define IDI_MAIN_APP 104 -#define IDD_PP_CRED 106 -#define IDD_PP_IDENT 107 -#define IDB_TK_REFRESH 108 -#define IDS_MAIN_WINDOW_TITLE 108 -#define IDS_MENU_FILE 109 -#define IDB_ID 110 -#define IDS_MENU_CRED 110 -#define IDB_ID_DELETE 111 -#define IDS_MENU_VIEW 111 -#define IDB_ID_NEW 112 -#define IDS_MENU_OPTIONS 112 -#define IDB_ID_REFRESH 113 -#define IDS_MENU_HELP 113 -#define IDB_TK 114 -#define IDS_ACTION_PROPERTIES 114 -#define IDB_TK_DELETE 115 -#define IDS_ACTION_EXIT 115 -#define IDB_TK_NEW 116 -#define IDS_CFG_ROOT_NAME 116 -#define IDS_ACTION_SET_DEF_ID 117 -#define IDS_ACTION_SET_SRCH_ID 118 -#define IDB_VW_REFRESH_SM 118 -#define IDR_MENU_BAR 119 -#define IDS_CFG_ROOT_TITLE 119 -#define IDS_CFG_GENERAL_SHORT 120 -#define IDB_TB_BLANK 121 -#define IDS_ACTION_NEW_CRED 121 -#define IDS_ACTION_PASSWD_ID 122 -#define IDS_ACTION_CHOOSE_COLS 123 -#define IDB_TB_BLANK_SM 123 -#define IDS_ACTION_DEBUG_WINDOW 124 -#define IDB_VW_REFRESH 124 -#define IDS_ACTION_VIEW_REFRESH 125 -#define IDB_ID_DELETE_DIS 125 -#define IDS_MENU_LAYOUT 126 -#define IDB_ID_DELETE_DIS_SM 126 -#define IDS_MENU_TOOLBARS 127 -#define IDB_ID_DELETE_SM 127 -#define IDS_ACTION_LAYOUT_ID 128 -#define IDB_ID_DIS 128 -#define IDS_ACTION_LAYOUT_TYPE 129 -#define IDB_ID_DIS_SM 129 -#define IDS_ACTION_LAYOUT_LOC 130 -#define IDB_ID_NEW_DIS 130 -#define IDS_ACTION_TB_STANDARD 131 -#define IDB_ID_NEW_DIS_SM 131 -#define IDS_ACTION_OPT_KHIM 132 -#define IDB_ID_NEW_SM 132 -#define IDB_ID_REFRESH_DIS 133 -#define IDS_ACTION_OPT_IDENTS 133 -#define IDS_ACTION_OPT_NOTIF 134 -#define IDB_ID_REFRESH_SM 134 -#define IDS_ACTION_HELP_CTX 135 -#define IDB_ID_REFRESH_DIS_SM 135 -#define IDS_ACTION_HELP_CONTENTS 136 -#define IDB_TK_DELETE_DIS 136 -#define IDS_ACTION_HELP_INDEX 137 -#define IDB_TK_DELETE_DIS_SM 137 -#define IDS_ACTION_HELP_ABOUT 138 -#define IDB_TK_DELETE_SM 138 -#define IDB_TK_DIS_SM 139 -#define IDS_CFG_GENERAL_LONG 139 -#define IDB_TK_NEW_DIS 140 -#define IDS_SAMPLE_STRING 140 -#define IDB_TK_NEW_DIS_SM 141 -#define IDS_NO_CREDS 141 -#define IDB_TK_NEW_SM 142 -#define IDS_WT_INIT_CREDS 142 -#define IDB_TK_REFRESH_DIS 143 -#define IDS_WT_NEW_CREDS 143 -#define IDB_TK_REFRESH_DIS_SM 144 -#define IDS_NC_IDENTITY 144 -#define IDB_TK_REFRESH_SM 145 -#define IDS_NC_IDENTS 145 -#define IDB_TK_SM 146 -#define IDS_NC_CREDTEXT_ID_NONE 146 -#define IDB_HELP_SM 147 -#define IDS_NC_CREDTEXT_ID_ONE 147 -#define IDB_HELP 148 -#define IDS_NC_CREDTEXT_ID_MANY 148 -#define IDB_LOGO_SHADE 149 -#define IDS_NC_CREDTEXT_ID_INVALID 149 -#define IDS_WTPOST_INIT_CREDS 150 -#define IDS_WTPOST_NEW_CREDS 151 -#define IDB_WDG_EXPAND 152 -#define IDS_ACTION_RENEW_CRED 152 -#define IDB_WDG_COLLAPSE 153 -#define IDS_ACTION_DESTROY_CRED 153 -#define IDB_ID_SM 154 -#define IDS_DEFAULT_FONT 154 -#define IDB_WDG_EXPAND_HI 155 -#define IDS_NC_CREDTEXT_TABS 155 -#define IDB_WDG_COLLAPSE_HI 156 -#define IDS_NOTIFY_PREFIX 156 -#define IDB_WDG_CREDTYPE 157 -#define IDS_NOTIFY_READY 157 -#define IDB_WDG_FLAG 158 -#define IDS_NOTIFY_ATTENTION 158 -#define IDB_FLAG_WARN 159 -#define IDS_ALERT_DEFAULT 159 -#define IDB_FLAG_EXPIRED 160 -#define IDS_PACTION_OK 160 -#define IDB_FLAG_CRITICAL 161 -#define IDS_PACTION_CANCEL 161 -#define IDS_PACTION_CLOSE 162 -#define IDD_NC_NEWCRED 162 -#define IDD_NC_BBAR 163 -#define IDS_ALERT_NOSEL_TITLE 163 -#define IDS_ALERT_NOSEL 164 -#define IDI_ENABLED 165 -#define IDS_NC_CREDTEXT_ID_VALID 165 -#define IDI_DISABLED 166 -#define IDS_NC_CREDTEXT_ID_UNCHECKED 166 -#define IDS_PROP_COL_PROPERTY 167 -#define IDS_PROP_COL_VALUE 168 -#define IDI_NOTIFY_NONE 169 -#define IDS_NC_NEW_IDENT 169 -#define IDI_NOTIFY_INFO 170 -#define IDS_NC_CREDTEXT_ID_CHECKING 170 -#define IDI_NOTIFY_WARN 171 -#define IDS_ACTION_OPEN_APP 171 -#define IDI_NOTIFY_ERROR 172 -#define IDS_CTX_NEW_IDENT 172 -#define IDS_CTX_NEW_CREDS 173 -#define IDD_CFG_MAIN 173 -#define IDS_CTX_RENEW_CREDS 174 -#define IDD_CFG_GENERIC 174 -#define IDS_CTX_PROC_NEW_IDENT 175 -#define IDB_LOGO_OPAQUE 175 -#define IDS_CTX_PROC_NEW_CREDS 176 -#define IDD_CFG_GENERAL 176 -#define IDS_CTX_PROC_RENEW_CREDS 177 -#define IDD_CFG_IDENTITIES 177 -#define IDS_ACTION_CLOSE_APP 178 -#define IDD_CFG_NOTIF 178 -#define IDS_NC_FAILED_TITLE 179 -#define IDD_CFG_PLUGINS 179 -#define IDS_CFG_IDENTITIES_SHORT 180 -#define IDD_CFG_IDENTITY 180 -#define IDS_CFG_IDENTITIES_LONG 181 -#define IDI_CFG_DEFAULT 181 -#define IDS_CFG_NOTIF_SHORT 182 -#define IDI_CFG_MODIFIED 182 -#define IDS_CFG_NOTIF_LONG 183 -#define IDI_CFG_APPLIED 183 -#define IDS_CFG_PLUGINS_SHORT 184 -#define IDD_CFG_IDS_TAB 184 -#define IDS_CFG_PLUGINS_LONG 185 -#define IDD_CFG_ID_TAB 185 -#define IDS_CFG_IDENTITY_SHORT 186 -#define IDI_CFG_DELETED 186 -#define IDS_CFG_IDENTITY_LONG 187 -#define IDI_ID 187 -#define IDS_CTX_DESTROY_CREDS 188 -#define IDB_IMPORT_SM_DIS 188 -#define IDS_WARN_EXPIRE 189 -#define IDB_IMPORT 189 -#define IDS_WARN_TITLE 190 -#define IDB_IMPORT_DIS 190 -#define IDS_ALERT_MOREINFO 191 -#define IDB_IMPORT_SM 191 -#define IDS_WARN_EXPIRED 192 -#define IDB_CHPW_SM 192 -#define IDS_WARN_EXPIRE_ID 193 -#define IDB_CHPW 193 -#define IDS_WARN_EXPIRED_ID 194 -#define IDB_CHPW_DIS 194 -#define IDS_WARN_WM_TITLE 195 -#define IDB_CHPW_DIS_SM 195 -#define IDS_WARN_WM_MSG 196 -#define IDD_ABOUT 196 -#define IDS_CFG_ID_TAB_SHORT 197 -#define IDB_TB_SPACE 197 -#define IDS_CFG_ID_TAB_LONG 198 -#define IDB_WDG_STUCK_HI 198 -#define IDS_CFG_IDS_TAB_SHORT 199 -#define IDB_WDG_STICK 199 -#define IDS_CFG_IDS_TAB_LONG 200 -#define IDB_WDG_STICK_HI 200 -#define IDS_CFG_IDS_IDENTITY 201 -#define IDB_WDG_STUCK 201 -#define IDS_ACTION_IMPORT 202 -#define IDS_CTX_IMPORT 203 -#define IDB_FLAG_RENEW 203 -#define IDS_CFG_PI_COL_PLUGINS 204 -#define IDI_APPICON_WARN 204 -#define IDS_PISTATE_FAILUNK 205 -#define IDI_APPICON_EXP 205 -#define IDS_PISTATE_FAILMAX 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 IDD_CFG_APPEAR 210 -#define IDS_PISTATE_REG 211 -#define IDD_CFG_ADDIDENT 211 -#define IDS_PISTATE_HOLD 212 -#define IDS_PISTATE_INIT 213 -#define IDS_PISTATE_RUN 214 -#define IDS_PISTATE_EXIT 215 -#define IDS_CTX_PASSWORD 216 -#define IDS_WT_PASSWORD 217 -#define IDS_WTPOST_PASSWORD 218 -#define IDS_CTX_PROC_PASSWORD 219 -#define IDS_NC_PWD_FAILED_TITLE 220 -#define IDS_CMDLINE_HELP 221 -#define IDS_PACTION_NEXT 222 -#define IDS_ERR_TITLE_NO_IDENTPRO 223 -#define IDS_ERR_MSG_NO_IDENTPRO 224 -#define IDS_ERR_SUGG_NO_IDENTPRO 225 -#define IDS_NC_REN_FAILED_TITLE 226 -#define IDS_CW_DEFAULT 227 -#define IDS_ACTION_OPT_PLUGINS 228 -#define IDS_NC_SETDEF 229 -#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 IDS_APR_HEADER_TEXT 255 -#define IDS_APR_HEADER_TEXT_BOLD 256 -#define IDS_APR_TEXT 257 -#define IDS_APR_TEXT_BOLD 258 -#define IDS_APR_SAMPLE_TEXT_NORMAL 259 -#define IDS_CFG_APPEAR_SHORT 260 -#define IDS_CFG_APPEAR_LONG 261 -#define IDS_ACTION_OPT_APPEAR 262 -#define IDS_APR_SAMPLE_TEXT_SEL 263 -#define IDS_CFG_IDNAME_INV 264 -#define IDS_CFG_IDNAME_PRB 265 -#define IDS_CFG_IDNAME_EXT 266 -#define IDS_CFG_IDNAME_CCR 267 -#define IDS_CFG_IDNAME_CCC 268 -#define IDS_CFG_LOGF_CS 269 -#define IDS_CFG_LOGF_CSR 270 -#define IDS_ACTIONT_PROPERTIES 271 -#define IDS_ACTIONT_EXIT 272 -#define IDS_ACTIONT_SET_DEF_ID 273 -#define IDS_ACTIONT_PASSWD_ID 274 -#define IDS_ACTIONT_NEW_CRED 275 -#define IDS_ACTIONT_RENEW_CRED 276 -#define IDS_ACTIONT_DESTROY_CRED 277 -#define IDS_ACTIONT_VIEW_REFRESH 278 -#define IDS_ACTIONT_OPT_IDENTS 279 -#define IDS_ACTIONT_OPT_KHIM 280 -#define IDS_ACTIONT_OPT_NOTIF 281 -#define IDS_ACTIONT_OPT_PLUGINS 282 -#define IDS_ACTIONT_OPT_APPEAR 283 -#define IDS_ACTIONT_HELP_CTX 284 -#define IDS_ACTIONT_IMPORT 285 -#define IDS_NC_FAILED_TITLE_I 286 -#define IDS_NC_PWD_FAILED_TITLE_I 287 -#define IDS_NC_REN_FAILED_TITLE_I 288 -#define IDS_CFG_IDNAME_NON 289 -#define IDS_MENU_DESTROY_CRED 290 -#define IDS_MENU_RENEW_CRED 291 -#define IDS_ACTION_DESTROY_ALL 292 -#define IDS_ACTION_RENEW_ALL 293 -#define IDS_IDACTION_RENEW 294 -#define IDS_IDACTION_DESTROY 295 -#define IDS_CTX_DESTROY_ID 296 -#define IDS_NCN_IDENT_INVALID 297 -#define IDS_NCN_IDENT_CHECKING 298 -#define IDS_NCN_IDENT_UNKNOWN 299 -#define IDS_REMOTE_FAIL 300 -#define IDS_REMOTE_FAIL_TITLE 301 -#define IDS_IDACTION_NEW 302 -#define IDS_IDACTIONT_NEW 303 -#define IDS_IDACTIONT_RENEW 304 -#define IDS_IDACTIONT_DESTROY 305 -#define IDS_ALERTTYPE_PLUGIN 306 -#define IDS_ALERTTYPE_EXPIRE 307 -#define IDS_ALERTTYPE_RENEWFAIL 308 -#define IDS_ALERTTYPE_ACQUIREFAIL 309 -#define IDS_ALERTTYPE_CHPW 310 -#define IDS_ACTION_LAYOUT_MINI 311 -#define IDS_IDEXPDISP_NOCRED 312 -#define IDS_IDEXPDISP_1CRED 313 -#define IDS_IDEXPDISP_NCRED 314 -#define IDS_CW_DEFAULTTF 315 -#define IDS_CW_TYPEF 316 -#define IDS_CW_EXPIREF 317 -#define IDS_CW_EXPIRED 318 -#define IDC_NC_CREDTEXT_LABEL 1009 -#define IDC_NC_CREDTEXT 1012 -#define IDC_NC_HELP 1017 -#define IDC_NC_ADVANCED 1019 -#define IDC_PP_IDNAME 1026 -#define IDC_PP_IDDEF 1027 -#define IDC_PP_IDSEARCH 1028 -#define IDC_PP_PROPLIST 1035 -#define IDC_PP_CPROPLIST 1036 -#define IDC_NC_TPL_ROW 1039 -#define IDC_NC_TPL_PANEL 1040 -#define IDC_NC_TPL_LABEL 1041 -#define IDC_NC_TPL_INPUT 1042 -#define IDC_NC_TPL_LABEL_LG 1043 -#define IDC_NC_TPL_INPUT_LG 1044 -#define IDC_NC_TPL_ROW_LG 1045 -#define IDC_CFG_NODELIST 1045 -#define IDAPPLY 1048 -#define IDC_CFG_TITLE 1050 -#define IDC_CFG_PANE 1051 -#define IDC_NOTIF_MONITOR 1053 -#define IDC_PP_DUMMY 1054 -#define IDC_NOTIF_RENEW 1055 -#define IDC_NOTIF_RENEW_THR 1056 -#define IDC_NOTIF_WARN1 1057 -#define IDC_NOTIF_WARN1_THR 1058 -#define IDC_NOTIF_WARN2 1059 -#define IDC_NOTIF_WARN2_THR 1060 -#define IDC_CFG_KEEPRUNNING 1061 -#define IDC_CFG_STARTUP_GROUP 1062 -#define IDC_CFG_AUTOSTART 1063 -#define IDC_CFG_AUTOIMPORT 1064 -#define IDC_CFG_AUTOINIT 1065 -#define IDC_CFG_OTHER 1066 -#define IDC_CFG_MONITOR 1069 -#define IDC_CFG_STICKY 1070 -#define IDC_CFG_RENEW 1075 -#define IDC_CFG_REMOVE 1076 -#define IDC_CFG_TAB 1077 -#define IDC_CFG_TARGET 1078 -#define IDC_CFG_PLUGINS 1079 -#define IDC_CFG_DESC 1084 -#define IDC_CFG_LBL_STATE 1085 -#define IDC_CFG_STATE 1086 -#define IDC_CFG_LBL_DEPS 1087 -#define IDC_CFG_DEPS 1088 -#define IDC_CFG_DISABLE 1089 -#define IDC_CFG_ENABLE 1090 -#define IDC_CFG_LBL_MOD 1092 -#define IDC_CFG_MODULE 1093 -#define IDC_CFG_LBL_VEN 1094 -#define IDC_CFG_VENDOR 1095 -#define IDC_CFG_REGISTER 1097 -#define IDC_CFG_NETDETECT 1098 -#define IDC_PP_STICKY 1099 -#define IDC_PRODUCT 1100 -#define IDC_COPYRIGHT 1101 -#define IDC_BUILDINFO 1102 -#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 IDC_CFG_SAMPLE_NORMAL 1123 -#define IDC_CFG_REVERT 1127 -#define IDC_CFG_FONTS 1128 -#define IDC_CFG_SAMPLE_BOLD 1129 -#define IDC_CFG_SIZE 1130 -#define IDC_CFG_BOLD 1131 -#define IDC_CFG_ITALICS 1132 -#define IDC_CFG_ADDIDENT 1133 -#define IDC_SM_CTL 1134 -#define IDC_CFG_SHOWLOG 1135 -#define IDC_MED_CTL 1135 -#define IDC_LG_CTL 1136 -#define IDC_SM_LBL 1137 -#define IDC_MED_LBL 1138 -#define IDC_LG_LBL 1139 -#define IDC_CFG_NOTACTION 1141 -#define IDC_CFG_NOTACT_STATIC 1142 -#define IDC_NC_BASIC 1143 -#define IDA_ACTIVATE_MENU 40003 -#define IDA_UP 40004 -#define IDA_DOWN 40005 -#define IDA_LEFT 40006 -#define IDA_RIGHT 40007 -#define IDA_ESC 40008 -#define IDA_ENTER 40009 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 212 -#define _APS_NEXT_COMMAND_VALUE 40010 -#define _APS_NEXT_CONTROL_VALUE 1144 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by C:\work\pismere\athena\auth\krb5\src\windows\identity\ui\lang\en_us\khapp.rc +// +#define IDI_MAIN_APP 104 +#define IDD_PP_CRED 106 +#define IDD_PP_IDENT 107 +#define IDB_TK_REFRESH 108 +#define IDS_MAIN_WINDOW_TITLE 108 +#define IDS_MENU_FILE 109 +#define IDB_ID 110 +#define IDS_MENU_CRED 110 +#define IDB_ID_DELETE 111 +#define IDS_MENU_VIEW 111 +#define IDB_ID_NEW 112 +#define IDS_MENU_OPTIONS 112 +#define IDB_ID_REFRESH 113 +#define IDS_MENU_HELP 113 +#define IDB_TK 114 +#define IDS_ACTION_PROPERTIES 114 +#define IDB_TK_DELETE 115 +#define IDS_ACTION_EXIT 115 +#define IDB_TK_NEW 116 +#define IDS_CFG_ROOT_NAME 116 +#define IDS_ACTION_SET_DEF_ID 117 +#define IDS_ACTION_SET_SRCH_ID 118 +#define IDB_VW_REFRESH_SM 118 +#define IDR_MENU_BAR 119 +#define IDS_CFG_ROOT_TITLE 119 +#define IDS_CFG_GENERAL_SHORT 120 +#define IDB_TB_BLANK 121 +#define IDS_ACTION_NEW_CRED 121 +#define IDS_ACTION_PASSWD_ID 122 +#define IDS_ACTION_CHOOSE_COLS 123 +#define IDB_TB_BLANK_SM 123 +#define IDS_ACTION_DEBUG_WINDOW 124 +#define IDB_VW_REFRESH 124 +#define IDS_ACTION_VIEW_REFRESH 125 +#define IDB_ID_DELETE_DIS 125 +#define IDS_MENU_LAYOUT 126 +#define IDB_ID_DELETE_DIS_SM 126 +#define IDS_MENU_TOOLBARS 127 +#define IDB_ID_DELETE_SM 127 +#define IDS_ACTION_LAYOUT_ID 128 +#define IDB_ID_DIS 128 +#define IDS_ACTION_LAYOUT_TYPE 129 +#define IDB_ID_DIS_SM 129 +#define IDS_ACTION_LAYOUT_LOC 130 +#define IDB_ID_NEW_DIS 130 +#define IDS_ACTION_TB_STANDARD 131 +#define IDB_ID_NEW_DIS_SM 131 +#define IDS_ACTION_OPT_KHIM 132 +#define IDB_ID_NEW_SM 132 +#define IDB_ID_REFRESH_DIS 133 +#define IDS_ACTION_OPT_IDENTS 133 +#define IDS_ACTION_OPT_NOTIF 134 +#define IDB_ID_REFRESH_SM 134 +#define IDS_ACTION_HELP_CTX 135 +#define IDB_ID_REFRESH_DIS_SM 135 +#define IDS_ACTION_HELP_CONTENTS 136 +#define IDB_TK_DELETE_DIS 136 +#define IDS_ACTION_HELP_INDEX 137 +#define IDB_TK_DELETE_DIS_SM 137 +#define IDS_ACTION_HELP_ABOUT 138 +#define IDB_TK_DELETE_SM 138 +#define IDB_TK_DIS_SM 139 +#define IDS_CFG_GENERAL_LONG 139 +#define IDB_TK_NEW_DIS 140 +#define IDS_SAMPLE_STRING 140 +#define IDB_TK_NEW_DIS_SM 141 +#define IDS_NO_CREDS 141 +#define IDB_TK_NEW_SM 142 +#define IDS_WT_INIT_CREDS 142 +#define IDB_TK_REFRESH_DIS 143 +#define IDS_WT_NEW_CREDS 143 +#define IDB_TK_REFRESH_DIS_SM 144 +#define IDS_NC_IDENTITY 144 +#define IDB_TK_REFRESH_SM 145 +#define IDS_NC_IDENTS 145 +#define IDB_TK_SM 146 +#define IDS_NC_CREDTEXT_ID_NONE 146 +#define IDB_HELP_SM 147 +#define IDS_NC_CREDTEXT_ID_ONE 147 +#define IDB_HELP 148 +#define IDS_NC_CREDTEXT_ID_MANY 148 +#define IDB_LOGO_SHADE 149 +#define IDS_NC_CREDTEXT_ID_INVALID 149 +#define IDS_WTPOST_INIT_CREDS 150 +#define IDS_WTPOST_NEW_CREDS 151 +#define IDB_WDG_EXPAND 152 +#define IDS_ACTION_RENEW_CRED 152 +#define IDB_WDG_COLLAPSE 153 +#define IDS_ACTION_DESTROY_CRED 153 +#define IDB_ID_SM 154 +#define IDS_DEFAULT_FONT 154 +#define IDB_WDG_EXPAND_HI 155 +#define IDS_NC_CREDTEXT_TABS 155 +#define IDB_WDG_COLLAPSE_HI 156 +#define IDS_NOTIFY_PREFIX 156 +#define IDB_WDG_CREDTYPE 157 +#define IDS_NOTIFY_READY 157 +#define IDB_WDG_FLAG 158 +#define IDS_NOTIFY_ATTENTION 158 +#define IDB_FLAG_WARN 159 +#define IDS_ALERT_DEFAULT 159 +#define IDB_FLAG_EXPIRED 160 +#define IDS_PACTION_OK 160 +#define IDB_FLAG_CRITICAL 161 +#define IDS_PACTION_CANCEL 161 +#define IDS_PACTION_CLOSE 162 +#define IDD_NC_NEWCRED 162 +#define IDD_NC_BBAR 163 +#define IDS_ALERT_NOSEL_TITLE 163 +#define IDS_ALERT_NOSEL 164 +#define IDI_ENABLED 165 +#define IDS_NC_CREDTEXT_ID_VALID 165 +#define IDI_DISABLED 166 +#define IDS_NC_CREDTEXT_ID_UNCHECKED 166 +#define IDS_PROP_COL_PROPERTY 167 +#define IDS_PROP_COL_VALUE 168 +#define IDI_NOTIFY_NONE 169 +#define IDS_NC_NEW_IDENT 169 +#define IDI_NOTIFY_INFO 170 +#define IDS_NC_CREDTEXT_ID_CHECKING 170 +#define IDI_NOTIFY_WARN 171 +#define IDS_ACTION_OPEN_APP 171 +#define IDI_NOTIFY_ERROR 172 +#define IDS_CTX_NEW_IDENT 172 +#define IDS_CTX_NEW_CREDS 173 +#define IDD_CFG_MAIN 173 +#define IDS_CTX_RENEW_CREDS 174 +#define IDD_CFG_GENERIC 174 +#define IDS_CTX_PROC_NEW_IDENT 175 +#define IDB_LOGO_OPAQUE 175 +#define IDS_CTX_PROC_NEW_CREDS 176 +#define IDD_CFG_GENERAL 176 +#define IDS_CTX_PROC_RENEW_CREDS 177 +#define IDD_CFG_IDENTITIES 177 +#define IDS_ACTION_CLOSE_APP 178 +#define IDD_CFG_NOTIF 178 +#define IDS_NC_FAILED_TITLE 179 +#define IDD_CFG_PLUGINS 179 +#define IDS_CFG_IDENTITIES_SHORT 180 +#define IDD_CFG_IDENTITY 180 +#define IDS_CFG_IDENTITIES_LONG 181 +#define IDI_CFG_DEFAULT 181 +#define IDS_CFG_NOTIF_SHORT 182 +#define IDI_CFG_MODIFIED 182 +#define IDS_CFG_NOTIF_LONG 183 +#define IDI_CFG_APPLIED 183 +#define IDS_CFG_PLUGINS_SHORT 184 +#define IDD_CFG_IDS_TAB 184 +#define IDS_CFG_PLUGINS_LONG 185 +#define IDD_CFG_ID_TAB 185 +#define IDS_CFG_IDENTITY_SHORT 186 +#define IDI_CFG_DELETED 186 +#define IDS_CFG_IDENTITY_LONG 187 +#define IDI_ID 187 +#define IDS_CTX_DESTROY_CREDS 188 +#define IDB_IMPORT_SM_DIS 188 +#define IDS_WARN_EXPIRE 189 +#define IDB_IMPORT 189 +#define IDS_WARN_TITLE 190 +#define IDB_IMPORT_DIS 190 +#define IDS_ALERT_MOREINFO 191 +#define IDB_IMPORT_SM 191 +#define IDS_WARN_EXPIRED 192 +#define IDB_CHPW_SM 192 +#define IDS_WARN_EXPIRE_ID 193 +#define IDB_CHPW 193 +#define IDS_WARN_EXPIRED_ID 194 +#define IDB_CHPW_DIS 194 +#define IDS_WARN_WM_TITLE 195 +#define IDB_CHPW_DIS_SM 195 +#define IDS_WARN_WM_MSG 196 +#define IDD_ABOUT 196 +#define IDS_CFG_ID_TAB_SHORT 197 +#define IDB_TB_SPACE 197 +#define IDS_CFG_ID_TAB_LONG 198 +#define IDB_WDG_STUCK_HI 198 +#define IDS_CFG_IDS_TAB_SHORT 199 +#define IDB_WDG_STICK 199 +#define IDS_CFG_IDS_TAB_LONG 200 +#define IDB_WDG_STICK_HI 200 +#define IDS_CFG_IDS_IDENTITY 201 +#define IDB_WDG_STUCK 201 +#define IDS_ACTION_IMPORT 202 +#define IDS_CTX_IMPORT 203 +#define IDB_FLAG_RENEW 203 +#define IDS_CFG_PI_COL_PLUGINS 204 +#define IDI_APPICON_WARN 204 +#define IDS_PISTATE_FAILUNK 205 +#define IDI_APPICON_EXP 205 +#define IDS_PISTATE_FAILMAX 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 IDD_CFG_APPEAR 210 +#define IDS_PISTATE_REG 211 +#define IDD_CFG_ADDIDENT 211 +#define IDS_PISTATE_HOLD 212 +#define IDS_PISTATE_INIT 213 +#define IDS_PISTATE_RUN 214 +#define IDS_PISTATE_EXIT 215 +#define IDS_CTX_PASSWORD 216 +#define IDS_WT_PASSWORD 217 +#define IDS_WTPOST_PASSWORD 218 +#define IDS_CTX_PROC_PASSWORD 219 +#define IDS_NC_PWD_FAILED_TITLE 220 +#define IDS_CMDLINE_HELP 221 +#define IDS_PACTION_NEXT 222 +#define IDS_ERR_TITLE_NO_IDENTPRO 223 +#define IDS_ERR_MSG_NO_IDENTPRO 224 +#define IDS_ERR_SUGG_NO_IDENTPRO 225 +#define IDS_NC_REN_FAILED_TITLE 226 +#define IDS_CW_DEFAULT 227 +#define IDS_ACTION_OPT_PLUGINS 228 +#define IDS_NC_SETDEF 229 +#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 IDS_APR_HEADER_TEXT 255 +#define IDS_APR_HEADER_TEXT_BOLD 256 +#define IDS_APR_TEXT 257 +#define IDS_APR_TEXT_BOLD 258 +#define IDS_APR_SAMPLE_TEXT_NORMAL 259 +#define IDS_CFG_APPEAR_SHORT 260 +#define IDS_CFG_APPEAR_LONG 261 +#define IDS_ACTION_OPT_APPEAR 262 +#define IDS_APR_SAMPLE_TEXT_SEL 263 +#define IDS_CFG_IDNAME_INV 264 +#define IDS_CFG_IDNAME_PRB 265 +#define IDS_CFG_IDNAME_EXT 266 +#define IDS_CFG_IDNAME_CCR 267 +#define IDS_CFG_IDNAME_CCC 268 +#define IDS_CFG_LOGF_CS 269 +#define IDS_CFG_LOGF_CSR 270 +#define IDS_ACTIONT_PROPERTIES 271 +#define IDS_ACTIONT_EXIT 272 +#define IDS_ACTIONT_SET_DEF_ID 273 +#define IDS_ACTIONT_PASSWD_ID 274 +#define IDS_ACTIONT_NEW_CRED 275 +#define IDS_ACTIONT_RENEW_CRED 276 +#define IDS_ACTIONT_DESTROY_CRED 277 +#define IDS_ACTIONT_VIEW_REFRESH 278 +#define IDS_ACTIONT_OPT_IDENTS 279 +#define IDS_ACTIONT_OPT_KHIM 280 +#define IDS_ACTIONT_OPT_NOTIF 281 +#define IDS_ACTIONT_OPT_PLUGINS 282 +#define IDS_ACTIONT_OPT_APPEAR 283 +#define IDS_ACTIONT_HELP_CTX 284 +#define IDS_ACTIONT_IMPORT 285 +#define IDS_NC_FAILED_TITLE_I 286 +#define IDS_NC_PWD_FAILED_TITLE_I 287 +#define IDS_NC_REN_FAILED_TITLE_I 288 +#define IDS_CFG_IDNAME_NON 289 +#define IDS_MENU_DESTROY_CRED 290 +#define IDS_MENU_RENEW_CRED 291 +#define IDS_ACTION_DESTROY_ALL 292 +#define IDS_ACTION_RENEW_ALL 293 +#define IDS_IDACTION_RENEW 294 +#define IDS_IDACTION_DESTROY 295 +#define IDS_CTX_DESTROY_ID 296 +#define IDS_NCN_IDENT_INVALID 297 +#define IDS_NCN_IDENT_CHECKING 298 +#define IDS_NCN_IDENT_UNKNOWN 299 +#define IDS_REMOTE_FAIL 300 +#define IDS_REMOTE_FAIL_TITLE 301 +#define IDS_IDACTION_NEW 302 +#define IDS_IDACTIONT_NEW 303 +#define IDS_IDACTIONT_RENEW 304 +#define IDS_IDACTIONT_DESTROY 305 +#define IDS_ALERTTYPE_PLUGIN 306 +#define IDS_ALERTTYPE_EXPIRE 307 +#define IDS_ALERTTYPE_RENEWFAIL 308 +#define IDS_ALERTTYPE_ACQUIREFAIL 309 +#define IDS_ALERTTYPE_CHPW 310 +#define IDS_ACTION_LAYOUT_MINI 311 +#define IDS_IDEXPDISP_NOCRED 312 +#define IDS_IDEXPDISP_1CRED 313 +#define IDS_IDEXPDISP_NCRED 314 +#define IDS_CW_DEFAULTTF 315 +#define IDS_CW_TYPEF 316 +#define IDS_CW_EXPIREF 317 +#define IDS_CW_EXPIRED 318 +#define IDC_NC_CREDTEXT_LABEL 1009 +#define IDC_NC_CREDTEXT 1012 +#define IDC_NC_HELP 1017 +#define IDC_NC_ADVANCED 1019 +#define IDC_PP_IDNAME 1026 +#define IDC_PP_IDDEF 1027 +#define IDC_PP_IDSEARCH 1028 +#define IDC_PP_PROPLIST 1035 +#define IDC_PP_CPROPLIST 1036 +#define IDC_NC_TPL_ROW 1039 +#define IDC_NC_TPL_PANEL 1040 +#define IDC_NC_TPL_LABEL 1041 +#define IDC_NC_TPL_INPUT 1042 +#define IDC_NC_TPL_LABEL_LG 1043 +#define IDC_NC_TPL_INPUT_LG 1044 +#define IDC_NC_TPL_ROW_LG 1045 +#define IDC_CFG_NODELIST 1045 +#define IDAPPLY 1048 +#define IDC_CFG_TITLE 1050 +#define IDC_CFG_PANE 1051 +#define IDC_NOTIF_MONITOR 1053 +#define IDC_PP_DUMMY 1054 +#define IDC_NOTIF_RENEW 1055 +#define IDC_NOTIF_RENEW_THR 1056 +#define IDC_NOTIF_WARN1 1057 +#define IDC_NOTIF_WARN1_THR 1058 +#define IDC_NOTIF_WARN2 1059 +#define IDC_NOTIF_WARN2_THR 1060 +#define IDC_CFG_KEEPRUNNING 1061 +#define IDC_CFG_STARTUP_GROUP 1062 +#define IDC_CFG_AUTOSTART 1063 +#define IDC_CFG_AUTOIMPORT 1064 +#define IDC_CFG_AUTOINIT 1065 +#define IDC_CFG_OTHER 1066 +#define IDC_CFG_MONITOR 1069 +#define IDC_CFG_STICKY 1070 +#define IDC_CFG_RENEW 1075 +#define IDC_CFG_REMOVE 1076 +#define IDC_CFG_TAB 1077 +#define IDC_CFG_TARGET 1078 +#define IDC_CFG_PLUGINS 1079 +#define IDC_CFG_DESC 1084 +#define IDC_CFG_LBL_STATE 1085 +#define IDC_CFG_STATE 1086 +#define IDC_CFG_LBL_DEPS 1087 +#define IDC_CFG_DEPS 1088 +#define IDC_CFG_DISABLE 1089 +#define IDC_CFG_ENABLE 1090 +#define IDC_CFG_LBL_MOD 1092 +#define IDC_CFG_MODULE 1093 +#define IDC_CFG_LBL_VEN 1094 +#define IDC_CFG_VENDOR 1095 +#define IDC_CFG_REGISTER 1097 +#define IDC_CFG_NETDETECT 1098 +#define IDC_PP_STICKY 1099 +#define IDC_PRODUCT 1100 +#define IDC_COPYRIGHT 1101 +#define IDC_BUILDINFO 1102 +#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 IDC_CFG_SAMPLE_NORMAL 1123 +#define IDC_CFG_REVERT 1127 +#define IDC_CFG_FONTS 1128 +#define IDC_CFG_SAMPLE_BOLD 1129 +#define IDC_CFG_SIZE 1130 +#define IDC_CFG_BOLD 1131 +#define IDC_CFG_ITALICS 1132 +#define IDC_CFG_ADDIDENT 1133 +#define IDC_SM_CTL 1134 +#define IDC_CFG_SHOWLOG 1135 +#define IDC_MED_CTL 1135 +#define IDC_LG_CTL 1136 +#define IDC_SM_LBL 1137 +#define IDC_MED_LBL 1138 +#define IDC_LG_LBL 1139 +#define IDC_CFG_NOTACTION 1141 +#define IDC_CFG_NOTACT_STATIC 1142 +#define IDC_NC_BASIC 1143 +#define IDA_ACTIVATE_MENU 40003 +#define IDA_UP 40004 +#define IDA_DOWN 40005 +#define IDA_LEFT 40006 +#define IDA_RIGHT 40007 +#define IDA_ESC 40008 +#define IDA_ENTER 40009 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 212 +#define _APS_NEXT_COMMAND_VALUE 40010 +#define _APS_NEXT_CONTROL_VALUE 1144 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/windows/identity/ui/statusbar.c b/src/windows/identity/ui/statusbar.c index e5f7e2009..b785dfdd0 100644 --- a/src/windows/identity/ui/statusbar.c +++ b/src/windows/identity/ui/statusbar.c @@ -1,208 +1,208 @@ -/* - * 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 -#ifdef DEBUG -#include -#endif - -khm_statusbar_part khm_statusbar_parts[] = { - {KHUI_SBPART_INFO, 0, KHUI_SB_WTYPE_FILLER, NULL}, - {KHUI_SBPART_NOTICE, 40, KHUI_SB_WTYPE_RELATIVE, NULL}, -#if 0 - /* Not implemented. This was originally intended to provide - location information. */ - {KHUI_SBPART_LOC, 40, KHUI_SB_WTYPE_ABSOLUTE, NULL} -#endif -}; - -int khm_n_statusbar_parts = sizeof(khm_statusbar_parts) / sizeof(khm_statusbar_part); - -HWND khm_hwnd_statusbar = NULL; - -LRESULT -khm_statusbar_notify(LPNMHDR nmhdr) { - LPNMMOUSE pnmm; - - switch(nmhdr->code) { - case NM_CLICK: - case NM_DBLCLK: - pnmm = (LPNMMOUSE) nmhdr; - - if (pnmm->dwItemSpec >= (DWORD) khm_n_statusbar_parts) - return TRUE; - - if (khm_statusbar_parts[pnmm->dwItemSpec].id == KHUI_SBPART_NOTICE) { - /* means, show next notification */ - kmq_post_message(KMSG_ALERT, KMSG_ALERT_SHOW_QUEUED, 0, 0); - } - - return TRUE; - } - - return FALSE; -} - -void -khui_statusbar_set_parts(HWND parent) { - int i; - int fillerwidth; - int staticwidth; - int lastx; - int width; - RECT r; - INT * parts; - - GetClientRect(parent, &r); - width = r.right - r.left; - - /* calculate fillerwidth and staticwidth */ - staticwidth = 0; - for(i=0;i +#ifdef DEBUG +#include +#endif + +khm_statusbar_part khm_statusbar_parts[] = { + {KHUI_SBPART_INFO, 0, KHUI_SB_WTYPE_FILLER, NULL}, + {KHUI_SBPART_NOTICE, 40, KHUI_SB_WTYPE_RELATIVE, NULL}, +#if 0 + /* Not implemented. This was originally intended to provide + location information. */ + {KHUI_SBPART_LOC, 40, KHUI_SB_WTYPE_ABSOLUTE, NULL} +#endif +}; + +int khm_n_statusbar_parts = sizeof(khm_statusbar_parts) / sizeof(khm_statusbar_part); + +HWND khm_hwnd_statusbar = NULL; + +LRESULT +khm_statusbar_notify(LPNMHDR nmhdr) { + LPNMMOUSE pnmm; + + switch(nmhdr->code) { + case NM_CLICK: + case NM_DBLCLK: + pnmm = (LPNMMOUSE) nmhdr; + + if (pnmm->dwItemSpec >= (DWORD) khm_n_statusbar_parts) + return TRUE; + + if (khm_statusbar_parts[pnmm->dwItemSpec].id == KHUI_SBPART_NOTICE) { + /* means, show next notification */ + kmq_post_message(KMSG_ALERT, KMSG_ALERT_SHOW_QUEUED, 0, 0); + } + + return TRUE; + } + + return FALSE; +} + +void +khui_statusbar_set_parts(HWND parent) { + int i; + int fillerwidth; + int staticwidth; + int lastx; + int width; + RECT r; + INT * parts; + + GetClientRect(parent, &r); + width = r.right - r.left; + + /* calculate fillerwidth and staticwidth */ + staticwidth = 0; + for(i=0;i -#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; -khm_int32 khui_timeout_crit = KHUI_DEF_TIMEOUT_CRIT; -khm_int32 khui_timeout_renew = KHUI_DEF_TIMEOUT_RENEW; - -khm_boolean khui_do_renew = TRUE; -khm_boolean khui_do_warn = TRUE; -khm_boolean khui_do_crit = TRUE; -#endif - -khui_timer_event * khui_timers = NULL; -khm_size khui_n_timers = 0; -khm_size khui_nc_timers = 0; - -CRITICAL_SECTION cs_timers; - -/********************************************************************* - Timers - *********************************************************************/ - - -#define KHUI_TIMER_ALLOC_INCR 16 - -void -khm_timer_init(void) { -#ifdef DEBUG - assert(khui_timers == NULL); -#endif - - khui_nc_timers = KHUI_TIMER_ALLOC_INCR; - khui_n_timers = 0; - khui_timers = PMALLOC(sizeof(*khui_timers) * khui_nc_timers); - -#ifdef DEBUG - assert(khui_timers != NULL); -#endif - - InitializeCriticalSection(&cs_timers); -} - -void -khm_timer_exit(void) { - EnterCriticalSection(&cs_timers); - - if (khui_timers) - PFREE(khui_timers); - khui_timers = NULL; - khui_n_timers = 0; - khui_nc_timers = 0; - - LeaveCriticalSection(&cs_timers); - DeleteCriticalSection(&cs_timers); -} - -/* called with cs_timers held */ -static void -tmr_fire_timer(void) { - int i; - khm_int64 curtime; - khm_int64 err; - khm_int64 next_event; - int tmr_count[KHUI_N_TTYPES]; - khm_int64 tmr_offset[KHUI_N_TTYPES]; - int t; - khm_handle eff_ident = NULL; - khui_timer_type eff_type = 0; /* meaningless */ - int fire_count = 0; - FILETIME ft; - - _begin_task(0); - _report_cs0(KHERR_DEBUG_1, L"Checking for expired timers"); - _describe(); - - TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR_SMALL, &ft); - err = FtToInt(&ft); - GetSystemTimeAsFileTime(&ft); - curtime = FtToInt(&ft); - - next_event = 0; - - ZeroMemory(tmr_count, sizeof(tmr_count)); - ZeroMemory(tmr_offset, sizeof(tmr_offset)); - - for (i=0; i < (int) khui_n_timers; i++) { - if (!(khui_timers[i].flags & - (KHUI_TE_FLAG_STALE | KHUI_TE_FLAG_EXPIRED)) && - khui_timers[i].type != KHUI_TTYPE_ID_MARK && - khui_timers[i].expire < curtime + err) { - - _report_cs3(KHERR_DEBUG_1, L"Expiring timer index=%1!d!, type=%2!d!, key=%3!p!", - _int32(i), _int32(khui_timers[i].type), - _cptr(khui_timers[i].key)); - - t = khui_timers[i].type; - - switch(t) { - case KHUI_TTYPE_ID_RENEW: - _report_cs1(KHERR_DEBUG_1, L"Renewing identity %1!p!", - _cptr(khui_timers[i].key)); - khm_cred_renew_identity(khui_timers[i].key); - khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED; - break; - - case KHUI_TTYPE_CRED_RENEW: - /* the equivalence threshold for setting the timer is - a lot larger than what we are testing for here - (KHUI_TIMEEQ_ERROR vs KHUI_TIMEEQ_ERROR_SMALL) so - we assume that it is safe to trigger a renew_cred - call here without checking if there's an imminent - renew_identity call. */ - _report_cs1(KHERR_DEBUG_1, L"Renewing credential %1!p!", - _cptr(khui_timers[i].key)); - khm_cred_renew_cred(khui_timers[i].key); - khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED; - break; - - default: - if (t < KHUI_N_TTYPES) { - tmr_count[t]++; - if (tmr_offset[t] == 0 || - tmr_offset[t] > khui_timers[i].offset) - tmr_offset[t] = khui_timers[i].offset; - if (next_event == 0 || - next_event > - khui_timers[i].expire + khui_timers[i].offset) - next_event = khui_timers[i].expire + - khui_timers[i].offset; - - if (eff_ident == NULL && - (t == KHUI_TTYPE_ID_EXP || - t == KHUI_TTYPE_ID_CRIT || - t == KHUI_TTYPE_ID_WARN)) { - /* we don't need a hold since we will be done - with the handle before the marker is - expired (the marker is the timer with the - KHUI_TTYPE_ID_MARK which contains a held - handle and is not really a timer.) */ - eff_ident = khui_timers[i].key; - eff_type = t; - } - - fire_count++; - - khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED; - } - else { -#ifdef DEBUG - assert(FALSE); -#endif - } - } - } - } - - /* See if we have anything to do */ - if (next_event == 0) - return; - else { - wchar_t fmt[128]; - wchar_t wtime[128]; - wchar_t wmsg[256]; - wchar_t wtitle[64]; - khm_int64 second; - khui_alert * alert = NULL; - - khm_size cb; - - next_event -= curtime; - - /* Due to measurement errors we may be slightly off on our - next_event calculation which shows up as '4 mins 59 - seconds' instead of '5 mins' and so on when converting to a - string. So we add half a second to make the message - neater. */ - TimetToFileTimeInterval(1, &ft); - second = FtToInt(&ft); - next_event += second / 2; - - cb = sizeof(wtime); - ft = IntToFt(next_event); - FtIntervalToString(&ft, - wtime, - &cb); - - if (fire_count == 1 && - eff_ident != NULL && - (eff_type == KHUI_TTYPE_ID_EXP || - eff_type == KHUI_TTYPE_ID_CRIT || - eff_type == KHUI_TTYPE_ID_WARN)) { - - wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; - - cb = sizeof(idname); - kcdb_identity_get_name(eff_ident, idname, &cb); - - if (next_event < second) { - LoadString(khm_hInstance, IDS_WARN_EXPIRED_ID, - fmt, ARRAYLENGTH(fmt)); - - StringCbPrintf(wmsg, sizeof(wmsg), fmt, idname); - } else { - LoadString(khm_hInstance, IDS_WARN_EXPIRE_ID, - fmt, ARRAYLENGTH(fmt)); - - StringCbPrintf(wmsg, sizeof(wmsg), fmt, idname, wtime); - } - } else { - if (next_event < second) { - LoadString(khm_hInstance, IDS_WARN_EXPIRED, - wmsg, ARRAYLENGTH(wmsg)); - } else { - LoadString(khm_hInstance, IDS_WARN_EXPIRE, - fmt, ARRAYLENGTH(fmt)); - - StringCbPrintf(wmsg, sizeof(wmsg), fmt, wtime); - } - } - - LoadString(khm_hInstance, IDS_WARN_TITLE, - wtitle, ARRAYLENGTH(wtitle)); - - khui_alert_create_simple(wtitle, wmsg, KHERR_WARNING, &alert); - khui_alert_set_flags(alert, - KHUI_ALERT_FLAG_REQUEST_BALLOON | KHUI_ALERT_FLAG_DISPATCH_CMD, - KHUI_ALERT_FLAG_REQUEST_BALLOON | KHUI_ALERT_FLAG_DISPATCH_CMD); - - if (eff_ident != NULL) { - khm_int32 cmd; - - cmd = khm_get_identity_new_creds_action(eff_ident); - - if (cmd) { - khui_alert_add_command(alert, cmd); - khui_alert_add_command(alert, KHUI_PACTION_CLOSE); - } - } - - khui_alert_show(alert); - khui_alert_release(alert); - } - - _end_task(); - -} - -void -khm_timer_fire(HWND hwnd) { - EnterCriticalSection(&cs_timers); - tmr_fire_timer(); - LeaveCriticalSection(&cs_timers); - - khm_timer_refresh(hwnd); -} - -static int -tmr_update(khm_handle key, khui_timer_type type, __int64 expire, - __int64 offset, void * data, khm_boolean reinstate) { - int i; - wchar_t name[KCDB_MAXCCH_NAME]; - wchar_t tstamp[128]; - wchar_t *type_str = NULL; - SYSTEMTIME st; - FILETIME ft; - FILETIME ftl; - khm_size cb; - - switch(type) { - case KHUI_TTYPE_ID_MARK: - type_str = L"marker"; - break; - - case KHUI_TTYPE_CRED_WARN: - case KHUI_TTYPE_ID_WARN: - type_str = L"warning"; - break; - - case KHUI_TTYPE_CRED_CRIT: - case KHUI_TTYPE_ID_CRIT: - type_str = L"critical"; - break; - - case KHUI_TTYPE_CRED_EXP: - case KHUI_TTYPE_ID_EXP: - type_str = L"expiry"; - break; - - case KHUI_TTYPE_CRED_RENEW: - case KHUI_TTYPE_ID_RENEW: - type_str = L"renew"; - break; - } - - ft = IntToFt(expire); - FileTimeToLocalFileTime(&ft, &ftl); - FileTimeToSystemTime(&ftl, &st); - StringCbPrintf(tstamp, sizeof(tstamp), - L"%d-%d-%d %d:%d:%d", - st.wYear, st.wMonth, st.wDay, - st.wHour, st.wMinute, st.wSecond); - - cb = sizeof(name); name[0] = L'\0'; - if (type_str == NULL) { - - _report_cs2(KHERR_DEBUG_1, - L"Updating uknown timer of type %1!d! exp(%2!s!)", - _int32(type), - _cstr(tstamp)); - _resolve(); - - } else if (type == KHUI_TTYPE_ID_MARK || - type == KHUI_TTYPE_ID_WARN || - type == KHUI_TTYPE_ID_CRIT || - type == KHUI_TTYPE_ID_EXP || - type == KHUI_TTYPE_ID_RENEW) { - - kcdb_identity_get_name(key, name, &cb); - _report_cs3(KHERR_DEBUG_1, - L"Updating identity %1!s! timer for %2!s! exp(%3!s!)", - _cstr(type_str), - _cstr(name), - _cstr(tstamp)); - _resolve(); - - } else if (type == KHUI_TTYPE_CRED_RENEW || - type == KHUI_TTYPE_CRED_WARN || - type == KHUI_TTYPE_CRED_CRIT || - type == KHUI_TTYPE_CRED_EXP) { - - kcdb_cred_get_name(key, name, &cb); - _report_cs3(KHERR_DEBUG_1, - L"Updating credential %1!s! timer for %2!s! exp(%3!s!)", - _cstr(type_str), - _cstr(name), - _cstr(tstamp)); - _resolve(); - - } - - for (i=0; i < (int) khui_n_timers; i++) { - if (khui_timers[i].key == key && - khui_timers[i].type == type) - break; - } - - if (i >= (int) khui_n_timers) { - i = (int) khui_n_timers; - - if (i >= (int) khui_nc_timers) { - khui_timer_event * nt; -#ifdef DEBUG - assert(khui_timers); -#endif - khui_nc_timers = UBOUNDSS(i+1, KHUI_TIMER_ALLOC_INCR, - KHUI_TIMER_ALLOC_INCR); - nt = PMALLOC(sizeof(*nt) * khui_nc_timers); -#ifdef DEBUG - assert(nt); -#endif - memcpy(nt, khui_timers, sizeof(*nt) * khui_n_timers); - - PFREE(khui_timers); - khui_timers = nt; - } - - khui_timers[i].key = key; - khui_timers[i].type = type; - khui_timers[i].flags = 0; - khui_n_timers++; - } - - khui_timers[i].expire = expire; - khui_timers[i].offset = offset; - khui_timers[i].data = data; - - khui_timers[i].flags &= ~KHUI_TE_FLAG_STALE; - if (reinstate) - khui_timers[i].flags &= ~KHUI_TE_FLAG_EXPIRED; - - return i; -} - -/* called with cs_timers held */ -static int -tmr_find(khm_handle key, khui_timer_type type, - khm_int32 and_flags, khm_int32 eq_flags) { - int i; - - eq_flags &= and_flags; - - for (i=0; i < (int) khui_n_timers; i++) { - if (khui_timers[i].key == key && - khui_timers[i].type == type && - (khui_timers[i].flags & and_flags) == eq_flags) - break; - } - - if (i < (int) khui_n_timers) - return i; - else - 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 < iret) { - - khui_timers[idx].flags &= ~KHUI_TE_FLAG_EXPIRED; - khui_timers[idx].expire = iret; - } - - return ret; -} - -/* called with cs_timers held. Called once for each credential in the - root credentials set. */ -static khm_int32 KHMAPI -tmr_cred_apply_proc(khm_handle cred, void * rock) { - khm_handle ident = NULL; - int mark_idx; - int idx; - FILETIME ft_expiry; - FILETIME ft_current; - FILETIME ft_creinst; - FILETIME ft_cred_expiry; - FILETIME ft_cred_issue; - FILETIME ft_issue; - FILETIME ft; - FILETIME fte; - FILETIME ft_reinst; - khm_size cb; - wchar_t wname[KCDB_MAXCCH_NAME]; - - cb = sizeof(wname); - wname[0] = L'\0'; - kcdb_cred_get_name(cred, wname, &cb); - - _report_cs1(KHERR_DEBUG_1, L"Looking at cred [%1!s!]", - _cstr(wname)); - _resolve(); - - kcdb_cred_get_identity(cred, &ident); -#ifdef DEBUG - assert(ident); -#endif - - /* now get the expiry for the identity*/ - cb = sizeof(ft_expiry); - if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_EXPIRE, - NULL, - &ft_expiry, &cb))) { - - /* failing which, we get the expiry for this credential */ - cb = sizeof(ft_expiry); - if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_EXPIRE, - NULL, - &ft_expiry, &cb))) { - /* we don't have an expiry time to work with */ - _report_cs1(KHERR_DEBUG_1, L"Skipping cred [%1!s!]. No expiry time", - _cstr(wname)); - _resolve(); - - kcdb_identity_release(ident); - return KHM_ERROR_SUCCESS; - } else { - /* and the time of issue */ - cb = sizeof(ft_issue); - if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_ISSUE, - NULL, &ft_issue, &cb))) - ZeroMemory(&ft_issue, sizeof(ft_issue)); - } - - } else { - /* also try to get the time of issue. */ - cb = sizeof(ft_issue); - if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_ISSUE, - NULL, &ft_issue, &cb))) - /* if we fail, we just zero out the time of issue and - failover to using the threshold value to set the expiry - timer instead of the half life algorithm. */ - ZeroMemory(&ft_issue, sizeof(ft_issue)); - } - - /* and the current time */ - GetSystemTimeAsFileTime(&ft_current); - - TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR, &ft_reinst); - - ft_creinst = FtAdd(&ft_current, &ft_reinst); - - mark_idx = tmr_find(ident, KHUI_TTYPE_ID_MARK, 0, 0); - - if (mark_idx < 0) { - mark_idx = tmr_update(ident, KHUI_TTYPE_ID_MARK, 0, 0, 0, FALSE); - kcdb_identity_hold(ident); -#ifdef DEBUG - assert(mark_idx >= 0); -#endif - khui_timers[mark_idx].flags |= KHUI_TE_FLAG_STALE; - } - - if (khui_timers[mark_idx].flags & KHUI_TE_FLAG_STALE) { - /* first time we are touching this */ - khm_handle csp_cw = NULL; - khm_handle csp_id = NULL; - khm_int32 rv; - khm_int32 t; - 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; - khm_int32 to_crit = KHUI_DEF_TIMEOUT_CRIT; - khm_int32 to_renew = KHUI_DEF_TIMEOUT_RENEW; - - if (CompareFileTime(&ft_expiry, &ft_current) < 0) - /* already expired */ - goto _done_with_ident; - - rv = khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, - &csp_cw); - - assert(KHM_SUCCEEDED(rv)); - - rv = kcdb_identity_get_config(ident, KHM_PERM_READ, &csp_id); - if (KHM_SUCCEEDED(rv)) { - khc_shadow_space(csp_id, csp_cw); - khc_close_space(csp_cw); - } else { - csp_id = csp_cw; - } - csp_cw = NULL; - - rv = khc_read_int32(csp_id, L"Monitor", &t); - if (KHM_SUCCEEDED(rv)) - monitor = t; - - rv = khc_read_int32(csp_id, L"AllowWarn", &t); - if (KHM_SUCCEEDED(rv)) - do_warn = t; - - rv = khc_read_int32(csp_id, L"AllowCritical", &t); - if (KHM_SUCCEEDED(rv)) - do_crit = t; - - rv = khc_read_int32(csp_id, L"AllowAutoRenew", &t); - 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; - - rv = khc_read_int32(csp_id, L"CriticalThreshold", &t); - if (KHM_SUCCEEDED(rv)) - to_crit = t; - - rv = khc_read_int32(csp_id, L"AutoRenewThreshold", &t); - if (KHM_SUCCEEDED(rv)) - to_renew = t; - - khc_close_space(csp_id); - - if (monitor && do_renew) { - int prev; - - TimetToFileTimeInterval(to_renew, &ft); - - prev = - tmr_find(ident, KHUI_TTYPE_ID_RENEW, 0, 0); - - if (do_halflife && (ft_issue.dwLowDateTime != 0 || - ft_issue.dwHighDateTime != 0)) - 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)) { - - if (CompareFileTime(&fte, &ft_current) < 0) - fte = ft_current; - - tmr_update(ident, KHUI_TTYPE_ID_RENEW, - 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); - - } - } - - if (monitor && do_warn && !renew_done) { - - TimetToFileTimeInterval(to_warn, &ft); - fte = FtSub(&ft_expiry, &ft); - - if (CompareFileTime(&fte, &ft_current) > 0) - tmr_update(ident, KHUI_TTYPE_ID_WARN, - FtToInt(&fte), FtToInt(&ft), 0, - CompareFileTime(&fte, &ft_creinst) > 0); - } - - if (monitor && do_crit && !renew_done) { - TimetToFileTimeInterval(to_crit, &ft); - fte = FtSub(&ft_expiry, &ft); - - if (CompareFileTime(&fte, &ft_current) > 0) - tmr_update(ident, KHUI_TTYPE_ID_CRIT, - FtToInt(&fte), FtToInt(&ft), 0, - CompareFileTime(&fte, &ft_creinst) > 0); - } - - if (monitor && !renew_done) { - if (CompareFileTime(&ft_expiry, &ft_current) > 0) - tmr_update(ident, KHUI_TTYPE_ID_EXP, - FtToInt(&ft_expiry), 0, 0, - CompareFileTime(&fte, &ft_creinst) > 0); - } - - _done_with_ident: - khui_timers[mark_idx].flags &= ~KHUI_TE_FLAG_STALE; - } - - cb = sizeof(ft_cred_expiry); - if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_EXPIRE, - NULL, - &ft_cred_expiry, - &cb))) { - _report_cs1(KHERR_DEBUG_1, L"Skipping cred [%1!s!]. Can't lookup cred expiry", - _cstr(wname)); - _resolve(); - goto _cleanup; - } - - cb = sizeof(ft_cred_issue); - if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_ISSUE, - NULL, - &ft_cred_issue, - &cb))) { - - ZeroMemory(&ft_cred_issue, sizeof(ft_cred_issue)); - - } - - 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); - - if (CompareFileTime(&ft_cred_expiry, &ft_expiry) >= 0 || - CompareFileTime(&ft_delta, &ft) < 0) { - - _report_cs1(KHERR_DEBUG_1, - L"Skipping credential [%1!s!]. The expiry time is too close to the identity expiry.", - _cstr(wname)); - _resolve(); - goto _cleanup; - } - } - - if ((idx = tmr_find(ident, KHUI_TTYPE_ID_WARN, 0, 0)) >= 0 && - !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { - - 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); - } - } - - if ((idx = tmr_find(ident, KHUI_TTYPE_ID_CRIT, 0, 0)) >= 0 && - !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { - - fte = IntToFt(FtToInt(&ft_cred_expiry) - khui_timers[idx].offset); - if (CompareFileTime(&fte, &ft_current) > 0) { - tmr_update(cred, KHUI_TTYPE_CRED_CRIT, - FtToInt(&fte), - khui_timers[idx].offset, 0, - CompareFileTime(&fte, &ft_creinst) > 0); - kcdb_cred_hold(cred); - } - } - - if ((idx = tmr_find(ident, KHUI_TTYPE_ID_RENEW, 0, 0)) >= 0 && - !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { - - int cidx = tmr_find(cred, KHUI_TTYPE_CRED_RENEW, 0, 0); - - if (ft_cred_issue.dwLowDateTime == 0 && - ft_cred_issue.dwHighDateTime == 0) { - fte = IntToFt(FtToInt(&ft_cred_expiry) - khui_timers[idx].offset); - /* a special case, for a credential whose remaining - lifetime is less than the offset, we try half life on - the current time and the expiry. */ - if (CompareFileTime(&fte, &ft_current) <= 0 && - CompareFileTime(&ft_current, &ft_expiry) < 0) { - fte = tmr_next_halflife_timeout(cidx, &ft_current, &ft_cred_expiry); -#if 0 - /* now, if we already have a renew timer for this - credential that hasn't expired yet and that is set - for earlier than fte, we let it be. */ - if (cidx >= 0 && - khui_timers[cidx].expire < FtToInt(&fte) && - khui_timers[cidx].expire > FtToInt(&ft_current) && - !(khui_timers[cidx].flags & KHUI_TE_FLAG_EXPIRED)) { - - fte = IntToFt(khui_timers[cidx].expire); - - } -#endif - } - } else { - fte = tmr_next_halflife_timeout(cidx, &ft_cred_issue, &ft_cred_expiry); - } - - if (CompareFileTime(&fte, &ft_current) > 0) { - tmr_update(cred, KHUI_TTYPE_CRED_RENEW, - FtToInt(&fte), - khui_timers[idx].offset, 0, - CompareFileTime(&fte, &ft_creinst) > 0); - kcdb_cred_hold(cred); - } - } - - if ((idx = tmr_find(ident, KHUI_TTYPE_ID_EXP, 0, 0)) >= 0 && - !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { - - if (CompareFileTime(&ft_cred_expiry, &ft_current) > 0) { - tmr_update(cred, KHUI_TTYPE_CRED_EXP, - FtToInt(&ft_cred_expiry), - 0, 0, - CompareFileTime(&ft_cred_expiry, &ft_creinst) > 0); - } - } - - _cleanup: - - if (ident) - kcdb_identity_release(ident); - - return KHM_ERROR_SUCCESS; -} - -/* called with cs_timers held */ -static void -tmr_purge(void) { - int i, j; - - for (i=0,j=0; i < (int) khui_n_timers; i++) { - if (khui_timers[i].flags & KHUI_TE_FLAG_STALE) { - if (khui_timers[i].type == KHUI_TTYPE_ID_MARK) { - kcdb_identity_release(khui_timers[i].key); -#ifdef DEBUG - { - int idx; - - idx = tmr_find(khui_timers[i].key, - KHUI_TTYPE_ID_CRIT, 0, 0); - assert(idx < 0 || - (khui_timers[idx].flags & - KHUI_TE_FLAG_STALE)); - - idx = tmr_find(khui_timers[i].key, - KHUI_TTYPE_ID_RENEW, 0, 0); - assert(idx < 0 || - (khui_timers[idx].flags & - KHUI_TE_FLAG_STALE)); - - idx = tmr_find(khui_timers[i].key, - KHUI_TTYPE_ID_WARN, 0, 0); - assert(idx < 0 || - (khui_timers[idx].flags & - KHUI_TE_FLAG_STALE)); - - idx = tmr_find(khui_timers[i].key, - KHUI_TTYPE_ID_EXP, 0, 0); - assert(idx < 0 || - (khui_timers[idx].flags & - KHUI_TE_FLAG_STALE)); - } -#endif - } else if (khui_timers[i].type == KHUI_TTYPE_CRED_WARN || - khui_timers[i].type == KHUI_TTYPE_CRED_CRIT || - khui_timers[i].type == KHUI_TTYPE_CRED_RENEW || - khui_timers[i].type == KHUI_TTYPE_CRED_EXP) { - kcdb_cred_release(khui_timers[i].key); - } - } else { - if (i != j) - khui_timers[j] = khui_timers[i]; - j++; - } - } - - khui_n_timers = j; -} - -/* go through all the credentials and set timers as appropriate. hwnd - is the window that will receive the timer events.*/ -void -khm_timer_refresh(HWND hwnd) { - int i; - khm_int64 next_event = 0; - khm_int64 curtime; - khm_int64 diff; - - _begin_task(0); - _report_cs0(KHERR_DEBUG_1, L"Refreshing timers"); - _describe(); - - EnterCriticalSection(&cs_timers); - - 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 { -#endif - - khui_timers[i].flags |= KHUI_TE_FLAG_STALE; - -#ifdef NOT_IMPLEMENTED_YET - } -#endif - } - - _report_cs1(KHERR_DEBUG_1, L"Starting with %1!d! timers", - _int32(khui_n_timers)); - - kcdb_credset_apply(NULL, - tmr_cred_apply_proc, - NULL); - - tmr_purge(); - - _report_cs1(KHERR_DEBUG_1, L"Leaving with %1!d! timers", - _int32(khui_n_timers)); - - _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) && - khui_timers[i].type != KHUI_TTYPE_ID_MARK && - (next_event == 0 || - next_event > khui_timers[i].expire)) { - - next_event = khui_timers[i].expire; - - } - } - - if (next_event != 0) { - FILETIME ft; - - GetSystemTimeAsFileTime(&ft); - curtime = FtToInt(&ft); - - TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR_SMALL, &ft); - diff = FtToInt(&ft); - - if (curtime + diff > next_event) { - tmr_fire_timer(); - goto _check_next_event; - } else { - diff = next_event - curtime; - ft = IntToFt(diff); - SetTimer(hwnd, - KHUI_TRIGGER_TIMER_ID, - FtIntervalToMilliseconds(&ft), - NULL); - } - } - - LeaveCriticalSection(&cs_timers); - - _end_task(); -} +/* + * 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 + +/* 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; +khm_int32 khui_timeout_crit = KHUI_DEF_TIMEOUT_CRIT; +khm_int32 khui_timeout_renew = KHUI_DEF_TIMEOUT_RENEW; + +khm_boolean khui_do_renew = TRUE; +khm_boolean khui_do_warn = TRUE; +khm_boolean khui_do_crit = TRUE; +#endif + +khui_timer_event * khui_timers = NULL; +khm_size khui_n_timers = 0; +khm_size khui_nc_timers = 0; + +CRITICAL_SECTION cs_timers; + +/********************************************************************* + Timers + *********************************************************************/ + + +#define KHUI_TIMER_ALLOC_INCR 16 + +void +khm_timer_init(void) { +#ifdef DEBUG + assert(khui_timers == NULL); +#endif + + khui_nc_timers = KHUI_TIMER_ALLOC_INCR; + khui_n_timers = 0; + khui_timers = PMALLOC(sizeof(*khui_timers) * khui_nc_timers); + +#ifdef DEBUG + assert(khui_timers != NULL); +#endif + + InitializeCriticalSection(&cs_timers); +} + +void +khm_timer_exit(void) { + EnterCriticalSection(&cs_timers); + + if (khui_timers) + PFREE(khui_timers); + khui_timers = NULL; + khui_n_timers = 0; + khui_nc_timers = 0; + + LeaveCriticalSection(&cs_timers); + DeleteCriticalSection(&cs_timers); +} + +/* called with cs_timers held */ +static void +tmr_fire_timer(void) { + int i; + khm_int64 curtime; + khm_int64 err; + khm_int64 next_event; + int tmr_count[KHUI_N_TTYPES]; + khm_int64 tmr_offset[KHUI_N_TTYPES]; + int t; + khm_handle eff_ident = NULL; + khui_timer_type eff_type = 0; /* meaningless */ + int fire_count = 0; + FILETIME ft; + + _begin_task(0); + _report_cs0(KHERR_DEBUG_1, L"Checking for expired timers"); + _describe(); + + TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR_SMALL, &ft); + err = FtToInt(&ft); + GetSystemTimeAsFileTime(&ft); + curtime = FtToInt(&ft); + + next_event = 0; + + ZeroMemory(tmr_count, sizeof(tmr_count)); + ZeroMemory(tmr_offset, sizeof(tmr_offset)); + + for (i=0; i < (int) khui_n_timers; i++) { + if (!(khui_timers[i].flags & + (KHUI_TE_FLAG_STALE | KHUI_TE_FLAG_EXPIRED)) && + khui_timers[i].type != KHUI_TTYPE_ID_MARK && + khui_timers[i].expire < curtime + err) { + + _report_cs3(KHERR_DEBUG_1, L"Expiring timer index=%1!d!, type=%2!d!, key=%3!p!", + _int32(i), _int32(khui_timers[i].type), + _cptr(khui_timers[i].key)); + + t = khui_timers[i].type; + + switch(t) { + case KHUI_TTYPE_ID_RENEW: + _report_cs1(KHERR_DEBUG_1, L"Renewing identity %1!p!", + _cptr(khui_timers[i].key)); + khm_cred_renew_identity(khui_timers[i].key); + khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED; + break; + + case KHUI_TTYPE_CRED_RENEW: + /* the equivalence threshold for setting the timer is + a lot larger than what we are testing for here + (KHUI_TIMEEQ_ERROR vs KHUI_TIMEEQ_ERROR_SMALL) so + we assume that it is safe to trigger a renew_cred + call here without checking if there's an imminent + renew_identity call. */ + _report_cs1(KHERR_DEBUG_1, L"Renewing credential %1!p!", + _cptr(khui_timers[i].key)); + khm_cred_renew_cred(khui_timers[i].key); + khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED; + break; + + default: + if (t < KHUI_N_TTYPES) { + tmr_count[t]++; + if (tmr_offset[t] == 0 || + tmr_offset[t] > khui_timers[i].offset) + tmr_offset[t] = khui_timers[i].offset; + if (next_event == 0 || + next_event > + khui_timers[i].expire + khui_timers[i].offset) + next_event = khui_timers[i].expire + + khui_timers[i].offset; + + if (eff_ident == NULL && + (t == KHUI_TTYPE_ID_EXP || + t == KHUI_TTYPE_ID_CRIT || + t == KHUI_TTYPE_ID_WARN)) { + /* we don't need a hold since we will be done + with the handle before the marker is + expired (the marker is the timer with the + KHUI_TTYPE_ID_MARK which contains a held + handle and is not really a timer.) */ + eff_ident = khui_timers[i].key; + eff_type = t; + } + + fire_count++; + + khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED; + } + else { +#ifdef DEBUG + assert(FALSE); +#endif + } + } + } + } + + /* See if we have anything to do */ + if (next_event == 0) + return; + else { + wchar_t fmt[128]; + wchar_t wtime[128]; + wchar_t wmsg[256]; + wchar_t wtitle[64]; + khm_int64 second; + khui_alert * alert = NULL; + + khm_size cb; + + next_event -= curtime; + + /* Due to measurement errors we may be slightly off on our + next_event calculation which shows up as '4 mins 59 + seconds' instead of '5 mins' and so on when converting to a + string. So we add half a second to make the message + neater. */ + TimetToFileTimeInterval(1, &ft); + second = FtToInt(&ft); + next_event += second / 2; + + cb = sizeof(wtime); + ft = IntToFt(next_event); + FtIntervalToString(&ft, + wtime, + &cb); + + if (fire_count == 1 && + eff_ident != NULL && + (eff_type == KHUI_TTYPE_ID_EXP || + eff_type == KHUI_TTYPE_ID_CRIT || + eff_type == KHUI_TTYPE_ID_WARN)) { + + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + + cb = sizeof(idname); + kcdb_identity_get_name(eff_ident, idname, &cb); + + if (next_event < second) { + LoadString(khm_hInstance, IDS_WARN_EXPIRED_ID, + fmt, ARRAYLENGTH(fmt)); + + StringCbPrintf(wmsg, sizeof(wmsg), fmt, idname); + } else { + LoadString(khm_hInstance, IDS_WARN_EXPIRE_ID, + fmt, ARRAYLENGTH(fmt)); + + StringCbPrintf(wmsg, sizeof(wmsg), fmt, idname, wtime); + } + } else { + if (next_event < second) { + LoadString(khm_hInstance, IDS_WARN_EXPIRED, + wmsg, ARRAYLENGTH(wmsg)); + } else { + LoadString(khm_hInstance, IDS_WARN_EXPIRE, + fmt, ARRAYLENGTH(fmt)); + + StringCbPrintf(wmsg, sizeof(wmsg), fmt, wtime); + } + } + + LoadString(khm_hInstance, IDS_WARN_TITLE, + wtitle, ARRAYLENGTH(wtitle)); + + khui_alert_create_simple(wtitle, wmsg, KHERR_WARNING, &alert); + khui_alert_set_flags(alert, + KHUI_ALERT_FLAG_REQUEST_BALLOON | KHUI_ALERT_FLAG_DISPATCH_CMD, + KHUI_ALERT_FLAG_REQUEST_BALLOON | KHUI_ALERT_FLAG_DISPATCH_CMD); + + if (eff_ident != NULL) { + khm_int32 cmd; + + cmd = khm_get_identity_new_creds_action(eff_ident); + + if (cmd) { + khui_alert_add_command(alert, cmd); + khui_alert_add_command(alert, KHUI_PACTION_CLOSE); + } + } + + khui_alert_show(alert); + khui_alert_release(alert); + } + + _end_task(); + +} + +void +khm_timer_fire(HWND hwnd) { + EnterCriticalSection(&cs_timers); + tmr_fire_timer(); + LeaveCriticalSection(&cs_timers); + + khm_timer_refresh(hwnd); +} + +static int +tmr_update(khm_handle key, khui_timer_type type, __int64 expire, + __int64 offset, void * data, khm_boolean reinstate) { + int i; + wchar_t name[KCDB_MAXCCH_NAME]; + wchar_t tstamp[128]; + wchar_t *type_str = NULL; + SYSTEMTIME st; + FILETIME ft; + FILETIME ftl; + khm_size cb; + + switch(type) { + case KHUI_TTYPE_ID_MARK: + type_str = L"marker"; + break; + + case KHUI_TTYPE_CRED_WARN: + case KHUI_TTYPE_ID_WARN: + type_str = L"warning"; + break; + + case KHUI_TTYPE_CRED_CRIT: + case KHUI_TTYPE_ID_CRIT: + type_str = L"critical"; + break; + + case KHUI_TTYPE_CRED_EXP: + case KHUI_TTYPE_ID_EXP: + type_str = L"expiry"; + break; + + case KHUI_TTYPE_CRED_RENEW: + case KHUI_TTYPE_ID_RENEW: + type_str = L"renew"; + break; + } + + ft = IntToFt(expire); + FileTimeToLocalFileTime(&ft, &ftl); + FileTimeToSystemTime(&ftl, &st); + StringCbPrintf(tstamp, sizeof(tstamp), + L"%d-%d-%d %d:%d:%d", + st.wYear, st.wMonth, st.wDay, + st.wHour, st.wMinute, st.wSecond); + + cb = sizeof(name); name[0] = L'\0'; + if (type_str == NULL) { + + _report_cs2(KHERR_DEBUG_1, + L"Updating uknown timer of type %1!d! exp(%2!s!)", + _int32(type), + _cstr(tstamp)); + _resolve(); + + } else if (type == KHUI_TTYPE_ID_MARK || + type == KHUI_TTYPE_ID_WARN || + type == KHUI_TTYPE_ID_CRIT || + type == KHUI_TTYPE_ID_EXP || + type == KHUI_TTYPE_ID_RENEW) { + + kcdb_identity_get_name(key, name, &cb); + _report_cs3(KHERR_DEBUG_1, + L"Updating identity %1!s! timer for %2!s! exp(%3!s!)", + _cstr(type_str), + _cstr(name), + _cstr(tstamp)); + _resolve(); + + } else if (type == KHUI_TTYPE_CRED_RENEW || + type == KHUI_TTYPE_CRED_WARN || + type == KHUI_TTYPE_CRED_CRIT || + type == KHUI_TTYPE_CRED_EXP) { + + kcdb_cred_get_name(key, name, &cb); + _report_cs3(KHERR_DEBUG_1, + L"Updating credential %1!s! timer for %2!s! exp(%3!s!)", + _cstr(type_str), + _cstr(name), + _cstr(tstamp)); + _resolve(); + + } + + for (i=0; i < (int) khui_n_timers; i++) { + if (khui_timers[i].key == key && + khui_timers[i].type == type) + break; + } + + if (i >= (int) khui_n_timers) { + i = (int) khui_n_timers; + + if (i >= (int) khui_nc_timers) { + khui_timer_event * nt; +#ifdef DEBUG + assert(khui_timers); +#endif + khui_nc_timers = UBOUNDSS(i+1, KHUI_TIMER_ALLOC_INCR, + KHUI_TIMER_ALLOC_INCR); + nt = PMALLOC(sizeof(*nt) * khui_nc_timers); +#ifdef DEBUG + assert(nt); +#endif + memcpy(nt, khui_timers, sizeof(*nt) * khui_n_timers); + + PFREE(khui_timers); + khui_timers = nt; + } + + khui_timers[i].key = key; + khui_timers[i].type = type; + khui_timers[i].flags = 0; + khui_n_timers++; + } + + khui_timers[i].expire = expire; + khui_timers[i].offset = offset; + khui_timers[i].data = data; + + khui_timers[i].flags &= ~KHUI_TE_FLAG_STALE; + if (reinstate) + khui_timers[i].flags &= ~KHUI_TE_FLAG_EXPIRED; + + return i; +} + +/* called with cs_timers held */ +static int +tmr_find(khm_handle key, khui_timer_type type, + khm_int32 and_flags, khm_int32 eq_flags) { + int i; + + eq_flags &= and_flags; + + for (i=0; i < (int) khui_n_timers; i++) { + if (khui_timers[i].key == key && + khui_timers[i].type == type && + (khui_timers[i].flags & and_flags) == eq_flags) + break; + } + + if (i < (int) khui_n_timers) + return i; + else + 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 < iret) { + + khui_timers[idx].flags &= ~KHUI_TE_FLAG_EXPIRED; + khui_timers[idx].expire = iret; + } + + return ret; +} + +/* called with cs_timers held. Called once for each credential in the + root credentials set. */ +static khm_int32 KHMAPI +tmr_cred_apply_proc(khm_handle cred, void * rock) { + khm_handle ident = NULL; + int mark_idx; + int idx; + FILETIME ft_expiry; + FILETIME ft_current; + FILETIME ft_creinst; + FILETIME ft_cred_expiry; + FILETIME ft_cred_issue; + FILETIME ft_issue; + FILETIME ft; + FILETIME fte; + FILETIME ft_reinst; + khm_size cb; + wchar_t wname[KCDB_MAXCCH_NAME]; + + cb = sizeof(wname); + wname[0] = L'\0'; + kcdb_cred_get_name(cred, wname, &cb); + + _report_cs1(KHERR_DEBUG_1, L"Looking at cred [%1!s!]", + _cstr(wname)); + _resolve(); + + kcdb_cred_get_identity(cred, &ident); +#ifdef DEBUG + assert(ident); +#endif + + /* now get the expiry for the identity*/ + cb = sizeof(ft_expiry); + if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_EXPIRE, + NULL, + &ft_expiry, &cb))) { + + /* failing which, we get the expiry for this credential */ + cb = sizeof(ft_expiry); + if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_EXPIRE, + NULL, + &ft_expiry, &cb))) { + /* we don't have an expiry time to work with */ + _report_cs1(KHERR_DEBUG_1, L"Skipping cred [%1!s!]. No expiry time", + _cstr(wname)); + _resolve(); + + kcdb_identity_release(ident); + return KHM_ERROR_SUCCESS; + } else { + /* and the time of issue */ + cb = sizeof(ft_issue); + if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_ISSUE, + NULL, &ft_issue, &cb))) + ZeroMemory(&ft_issue, sizeof(ft_issue)); + } + + } else { + /* also try to get the time of issue. */ + cb = sizeof(ft_issue); + if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_ISSUE, + NULL, &ft_issue, &cb))) + /* if we fail, we just zero out the time of issue and + failover to using the threshold value to set the expiry + timer instead of the half life algorithm. */ + ZeroMemory(&ft_issue, sizeof(ft_issue)); + } + + /* and the current time */ + GetSystemTimeAsFileTime(&ft_current); + + TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR, &ft_reinst); + + ft_creinst = FtAdd(&ft_current, &ft_reinst); + + mark_idx = tmr_find(ident, KHUI_TTYPE_ID_MARK, 0, 0); + + if (mark_idx < 0) { + mark_idx = tmr_update(ident, KHUI_TTYPE_ID_MARK, 0, 0, 0, FALSE); + kcdb_identity_hold(ident); +#ifdef DEBUG + assert(mark_idx >= 0); +#endif + khui_timers[mark_idx].flags |= KHUI_TE_FLAG_STALE; + } + + if (khui_timers[mark_idx].flags & KHUI_TE_FLAG_STALE) { + /* first time we are touching this */ + khm_handle csp_cw = NULL; + khm_handle csp_id = NULL; + khm_int32 rv; + khm_int32 t; + 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; + khm_int32 to_crit = KHUI_DEF_TIMEOUT_CRIT; + khm_int32 to_renew = KHUI_DEF_TIMEOUT_RENEW; + + if (CompareFileTime(&ft_expiry, &ft_current) < 0) + /* already expired */ + goto _done_with_ident; + + rv = khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, + &csp_cw); + + assert(KHM_SUCCEEDED(rv)); + + rv = kcdb_identity_get_config(ident, KHM_PERM_READ, &csp_id); + if (KHM_SUCCEEDED(rv)) { + khc_shadow_space(csp_id, csp_cw); + khc_close_space(csp_cw); + } else { + csp_id = csp_cw; + } + csp_cw = NULL; + + rv = khc_read_int32(csp_id, L"Monitor", &t); + if (KHM_SUCCEEDED(rv)) + monitor = t; + + rv = khc_read_int32(csp_id, L"AllowWarn", &t); + if (KHM_SUCCEEDED(rv)) + do_warn = t; + + rv = khc_read_int32(csp_id, L"AllowCritical", &t); + if (KHM_SUCCEEDED(rv)) + do_crit = t; + + rv = khc_read_int32(csp_id, L"AllowAutoRenew", &t); + 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; + + rv = khc_read_int32(csp_id, L"CriticalThreshold", &t); + if (KHM_SUCCEEDED(rv)) + to_crit = t; + + rv = khc_read_int32(csp_id, L"AutoRenewThreshold", &t); + if (KHM_SUCCEEDED(rv)) + to_renew = t; + + khc_close_space(csp_id); + + if (monitor && do_renew) { + int prev; + + TimetToFileTimeInterval(to_renew, &ft); + + prev = + tmr_find(ident, KHUI_TTYPE_ID_RENEW, 0, 0); + + if (do_halflife && (ft_issue.dwLowDateTime != 0 || + ft_issue.dwHighDateTime != 0)) + 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)) { + + if (CompareFileTime(&fte, &ft_current) < 0) + fte = ft_current; + + tmr_update(ident, KHUI_TTYPE_ID_RENEW, + 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); + + } + } + + if (monitor && do_warn && !renew_done) { + + TimetToFileTimeInterval(to_warn, &ft); + fte = FtSub(&ft_expiry, &ft); + + if (CompareFileTime(&fte, &ft_current) > 0) + tmr_update(ident, KHUI_TTYPE_ID_WARN, + FtToInt(&fte), FtToInt(&ft), 0, + CompareFileTime(&fte, &ft_creinst) > 0); + } + + if (monitor && do_crit && !renew_done) { + TimetToFileTimeInterval(to_crit, &ft); + fte = FtSub(&ft_expiry, &ft); + + if (CompareFileTime(&fte, &ft_current) > 0) + tmr_update(ident, KHUI_TTYPE_ID_CRIT, + FtToInt(&fte), FtToInt(&ft), 0, + CompareFileTime(&fte, &ft_creinst) > 0); + } + + if (monitor && !renew_done) { + if (CompareFileTime(&ft_expiry, &ft_current) > 0) + tmr_update(ident, KHUI_TTYPE_ID_EXP, + FtToInt(&ft_expiry), 0, 0, + CompareFileTime(&fte, &ft_creinst) > 0); + } + + _done_with_ident: + khui_timers[mark_idx].flags &= ~KHUI_TE_FLAG_STALE; + } + + cb = sizeof(ft_cred_expiry); + if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_EXPIRE, + NULL, + &ft_cred_expiry, + &cb))) { + _report_cs1(KHERR_DEBUG_1, L"Skipping cred [%1!s!]. Can't lookup cred expiry", + _cstr(wname)); + _resolve(); + goto _cleanup; + } + + cb = sizeof(ft_cred_issue); + if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_ISSUE, + NULL, + &ft_cred_issue, + &cb))) { + + ZeroMemory(&ft_cred_issue, sizeof(ft_cred_issue)); + + } + + 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); + + if (CompareFileTime(&ft_cred_expiry, &ft_expiry) >= 0 || + CompareFileTime(&ft_delta, &ft) < 0) { + + _report_cs1(KHERR_DEBUG_1, + L"Skipping credential [%1!s!]. The expiry time is too close to the identity expiry.", + _cstr(wname)); + _resolve(); + goto _cleanup; + } + } + + if ((idx = tmr_find(ident, KHUI_TTYPE_ID_WARN, 0, 0)) >= 0 && + !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { + + 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); + } + } + + if ((idx = tmr_find(ident, KHUI_TTYPE_ID_CRIT, 0, 0)) >= 0 && + !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { + + fte = IntToFt(FtToInt(&ft_cred_expiry) - khui_timers[idx].offset); + if (CompareFileTime(&fte, &ft_current) > 0) { + tmr_update(cred, KHUI_TTYPE_CRED_CRIT, + FtToInt(&fte), + khui_timers[idx].offset, 0, + CompareFileTime(&fte, &ft_creinst) > 0); + kcdb_cred_hold(cred); + } + } + + if ((idx = tmr_find(ident, KHUI_TTYPE_ID_RENEW, 0, 0)) >= 0 && + !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { + + int cidx = tmr_find(cred, KHUI_TTYPE_CRED_RENEW, 0, 0); + + if (ft_cred_issue.dwLowDateTime == 0 && + ft_cred_issue.dwHighDateTime == 0) { + fte = IntToFt(FtToInt(&ft_cred_expiry) - khui_timers[idx].offset); + /* a special case, for a credential whose remaining + lifetime is less than the offset, we try half life on + the current time and the expiry. */ + if (CompareFileTime(&fte, &ft_current) <= 0 && + CompareFileTime(&ft_current, &ft_expiry) < 0) { + fte = tmr_next_halflife_timeout(cidx, &ft_current, &ft_cred_expiry); +#if 0 + /* now, if we already have a renew timer for this + credential that hasn't expired yet and that is set + for earlier than fte, we let it be. */ + if (cidx >= 0 && + khui_timers[cidx].expire < FtToInt(&fte) && + khui_timers[cidx].expire > FtToInt(&ft_current) && + !(khui_timers[cidx].flags & KHUI_TE_FLAG_EXPIRED)) { + + fte = IntToFt(khui_timers[cidx].expire); + + } +#endif + } + } else { + fte = tmr_next_halflife_timeout(cidx, &ft_cred_issue, &ft_cred_expiry); + } + + if (CompareFileTime(&fte, &ft_current) > 0) { + tmr_update(cred, KHUI_TTYPE_CRED_RENEW, + FtToInt(&fte), + khui_timers[idx].offset, 0, + CompareFileTime(&fte, &ft_creinst) > 0); + kcdb_cred_hold(cred); + } + } + + if ((idx = tmr_find(ident, KHUI_TTYPE_ID_EXP, 0, 0)) >= 0 && + !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { + + if (CompareFileTime(&ft_cred_expiry, &ft_current) > 0) { + tmr_update(cred, KHUI_TTYPE_CRED_EXP, + FtToInt(&ft_cred_expiry), + 0, 0, + CompareFileTime(&ft_cred_expiry, &ft_creinst) > 0); + } + } + + _cleanup: + + if (ident) + kcdb_identity_release(ident); + + return KHM_ERROR_SUCCESS; +} + +/* called with cs_timers held */ +static void +tmr_purge(void) { + int i, j; + + for (i=0,j=0; i < (int) khui_n_timers; i++) { + if (khui_timers[i].flags & KHUI_TE_FLAG_STALE) { + if (khui_timers[i].type == KHUI_TTYPE_ID_MARK) { + kcdb_identity_release(khui_timers[i].key); +#ifdef DEBUG + { + int idx; + + idx = tmr_find(khui_timers[i].key, + KHUI_TTYPE_ID_CRIT, 0, 0); + assert(idx < 0 || + (khui_timers[idx].flags & + KHUI_TE_FLAG_STALE)); + + idx = tmr_find(khui_timers[i].key, + KHUI_TTYPE_ID_RENEW, 0, 0); + assert(idx < 0 || + (khui_timers[idx].flags & + KHUI_TE_FLAG_STALE)); + + idx = tmr_find(khui_timers[i].key, + KHUI_TTYPE_ID_WARN, 0, 0); + assert(idx < 0 || + (khui_timers[idx].flags & + KHUI_TE_FLAG_STALE)); + + idx = tmr_find(khui_timers[i].key, + KHUI_TTYPE_ID_EXP, 0, 0); + assert(idx < 0 || + (khui_timers[idx].flags & + KHUI_TE_FLAG_STALE)); + } +#endif + } else if (khui_timers[i].type == KHUI_TTYPE_CRED_WARN || + khui_timers[i].type == KHUI_TTYPE_CRED_CRIT || + khui_timers[i].type == KHUI_TTYPE_CRED_RENEW || + khui_timers[i].type == KHUI_TTYPE_CRED_EXP) { + kcdb_cred_release(khui_timers[i].key); + } + } else { + if (i != j) + khui_timers[j] = khui_timers[i]; + j++; + } + } + + khui_n_timers = j; +} + +/* go through all the credentials and set timers as appropriate. hwnd + is the window that will receive the timer events.*/ +void +khm_timer_refresh(HWND hwnd) { + int i; + khm_int64 next_event = 0; + khm_int64 curtime; + khm_int64 diff; + + _begin_task(0); + _report_cs0(KHERR_DEBUG_1, L"Refreshing timers"); + _describe(); + + EnterCriticalSection(&cs_timers); + + 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 { +#endif + + khui_timers[i].flags |= KHUI_TE_FLAG_STALE; + +#ifdef NOT_IMPLEMENTED_YET + } +#endif + } + + _report_cs1(KHERR_DEBUG_1, L"Starting with %1!d! timers", + _int32(khui_n_timers)); + + kcdb_credset_apply(NULL, + tmr_cred_apply_proc, + NULL); + + tmr_purge(); + + _report_cs1(KHERR_DEBUG_1, L"Leaving with %1!d! timers", + _int32(khui_n_timers)); + + _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) && + khui_timers[i].type != KHUI_TTYPE_ID_MARK && + (next_event == 0 || + next_event > khui_timers[i].expire)) { + + next_event = khui_timers[i].expire; + + } + } + + if (next_event != 0) { + FILETIME ft; + + GetSystemTimeAsFileTime(&ft); + curtime = FtToInt(&ft); + + TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR_SMALL, &ft); + diff = FtToInt(&ft); + + if (curtime + diff > next_event) { + tmr_fire_timer(); + goto _check_next_event; + } else { + diff = next_event - curtime; + ft = IntToFt(diff); + SetTimer(hwnd, + KHUI_TRIGGER_TIMER_ID, + FtIntervalToMilliseconds(&ft), + NULL); + } + } + + LeaveCriticalSection(&cs_timers); + + _end_task(); +} diff --git a/src/windows/identity/ui/timer.h b/src/windows/identity/ui/timer.h index 130ae999a..af4ece723 100644 --- a/src/windows/identity/ui/timer.h +++ b/src/windows/identity/ui/timer.h @@ -1,100 +1,100 @@ -/* - * 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_TIMER_H -#define __KHIMAIRA_TIMER_H - -/* note that the ordering of the first few enum constants are - significant. The values of the constants up to KHUI_N_TTYPES are - used as indices. */ -typedef enum tag_khui_timer_type { - KHUI_TTYPE_ID_EXP = 0, /* Identity expiration */ - KHUI_TTYPE_ID_CRIT, /* Identity critical */ - KHUI_TTYPE_ID_WARN, /* Identity warning */ - KHUI_TTYPE_CRED_EXP, /* Credential expiration */ - KHUI_TTYPE_CRED_CRIT, /* Credential critical */ - KHUI_TTYPE_CRED_WARN, /* Credential warning */ - - KHUI_N_TTYPES, /* Count of the timers that we - aggregate for notifications */ - - KHUI_TTYPE_ID_MARK, /* Identity marker */ - - KHUI_TTYPE_ID_RENEW, /* Identity auto renewal */ - KHUI_TTYPE_CRED_RENEW, /* Credential renewal */ - -#if 0 - KHUI_TTYPE_BMSG, /* Custom. Sends broadcast message - when triggered.*/ - KHUI_TTYPE_SMSG, /* Custom. Sends subscription message - when triggered. */ -#endif -} khui_timer_type; - -typedef struct tag_khui_timer_event { - khm_handle key; - khui_timer_type type; - - khm_int64 expire; /* time at which the timer expires */ - khm_int64 offset; /* time offset at which the event that the - timer warns of happens */ - void * data; - khm_int32 flags; -} khui_timer_event; - -#define KHUI_TRIGGER_TIMER_ID 48 -#define KHUI_REFRESH_TIMER_ID 49 - -#define KHUI_REFRESH_TIMEOUT 5000 - -#define KHUI_TE_FLAG_EXPIRED 0x00000001 -#define KHUI_TE_FLAG_STALE 0x00000002 - -#define KHUI_DEF_TIMEOUT_WARN 900 -#define KHUI_DEF_TIMEOUT_CRIT 300 -#define KHUI_DEF_TIMEOUT_RENEW 60 - -/* the max absolute difference between two timers (in seconds) that - can exist where we consider both timers to be in the same - timeslot. */ -#define KHUI_TIMEEQ_ERROR 20 - -/* the small error. */ -#define KHUI_TIMEEQ_ERROR_SMALL 1 - -void -khm_timer_refresh(HWND hwnd); - -void -khm_timer_fire(HWND hwnd); - -void -khm_timer_init(void); - -void -khm_timer_exit(void); - -#endif +/* + * 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_TIMER_H +#define __KHIMAIRA_TIMER_H + +/* note that the ordering of the first few enum constants are + significant. The values of the constants up to KHUI_N_TTYPES are + used as indices. */ +typedef enum tag_khui_timer_type { + KHUI_TTYPE_ID_EXP = 0, /* Identity expiration */ + KHUI_TTYPE_ID_CRIT, /* Identity critical */ + KHUI_TTYPE_ID_WARN, /* Identity warning */ + KHUI_TTYPE_CRED_EXP, /* Credential expiration */ + KHUI_TTYPE_CRED_CRIT, /* Credential critical */ + KHUI_TTYPE_CRED_WARN, /* Credential warning */ + + KHUI_N_TTYPES, /* Count of the timers that we + aggregate for notifications */ + + KHUI_TTYPE_ID_MARK, /* Identity marker */ + + KHUI_TTYPE_ID_RENEW, /* Identity auto renewal */ + KHUI_TTYPE_CRED_RENEW, /* Credential renewal */ + +#if 0 + KHUI_TTYPE_BMSG, /* Custom. Sends broadcast message + when triggered.*/ + KHUI_TTYPE_SMSG, /* Custom. Sends subscription message + when triggered. */ +#endif +} khui_timer_type; + +typedef struct tag_khui_timer_event { + khm_handle key; + khui_timer_type type; + + khm_int64 expire; /* time at which the timer expires */ + khm_int64 offset; /* time offset at which the event that the + timer warns of happens */ + void * data; + khm_int32 flags; +} khui_timer_event; + +#define KHUI_TRIGGER_TIMER_ID 48 +#define KHUI_REFRESH_TIMER_ID 49 + +#define KHUI_REFRESH_TIMEOUT 5000 + +#define KHUI_TE_FLAG_EXPIRED 0x00000001 +#define KHUI_TE_FLAG_STALE 0x00000002 + +#define KHUI_DEF_TIMEOUT_WARN 900 +#define KHUI_DEF_TIMEOUT_CRIT 300 +#define KHUI_DEF_TIMEOUT_RENEW 60 + +/* the max absolute difference between two timers (in seconds) that + can exist where we consider both timers to be in the same + timeslot. */ +#define KHUI_TIMEEQ_ERROR 20 + +/* the small error. */ +#define KHUI_TIMEEQ_ERROR_SMALL 1 + +void +khm_timer_refresh(HWND hwnd); + +void +khm_timer_fire(HWND hwnd); + +void +khm_timer_init(void); + +void +khm_timer_exit(void); + +#endif diff --git a/src/windows/identity/ui/toolbar.c b/src/windows/identity/ui/toolbar.c index a464009fc..c543e6923 100644 --- a/src/windows/identity/ui/toolbar.c +++ b/src/windows/identity/ui/toolbar.c @@ -1,471 +1,471 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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 - -HWND khui_hwnd_standard_toolbar; -int khui_tb_blank; - -khui_ilist * ilist_toolbar; - -void khui_init_toolbar(void) { - ilist_toolbar = khui_create_ilist(KHUI_TOOLBAR_IMAGE_WIDTH, KHUI_TOOLBAR_IMAGE_HEIGHT, KHUI_TOOLBAR_MAX_BTNS, 5, 0); -} - -void khui_exit_toolbar(void) { - khui_delete_ilist(ilist_toolbar); -} - -LRESULT khm_toolbar_notify(LPNMHDR notice) { - switch(notice->code) { - case TBN_GETINFOTIP: - { - LPNMTBGETINFOTIP git = (LPNMTBGETINFOTIP) notice; - int cmd; - khui_action * a; - - cmd = git->iItem; - a = khui_find_action(cmd); - - if (a) { - if (a->caption) { - StringCchCopy(git->pszText, git->cchTextMax, a->caption); - } else if (a->tooltip) { - StringCchCopy(git->pszText, git->cchTextMax, a->tooltip); - } else if (a->is_caption) { - wchar_t buf[INFOTIPSIZE]; - - buf[0] = L'\0'; - LoadString(khm_hInstance, a->is_caption, - buf, ARRAYLENGTH(buf)); - - StringCchCopy(git->pszText, git->cchTextMax, buf); - } else { - StringCchCopy(git->pszText, git->cchTextMax, L""); - } - } else { - StringCchCopy(git->pszText, - git->cchTextMax, - L""); - } - } - break; - - case TBN_HOTITEMCHANGE: - { - LPNMTBHOTITEM hi = (LPNMTBHOTITEM) notice; - - if (hi->dwFlags & HICF_LEAVING) { - khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, L""); - } else { - khui_action * a; - int cmd; - wchar_t buf[256]; - - cmd = hi->idNew; - a = khui_find_action(cmd); - - buf[0] = L'\0'; - - if (a) { - if (a->tooltip) - StringCbCopy(buf, sizeof(buf), a->tooltip); - else if (a->is_tooltip) { - LoadString(khm_hInstance, a->is_tooltip, - buf, ARRAYLENGTH(buf)); - } - } - - khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, buf); - } - } - break; - - case TBN_DROPDOWN: - { - LPNMTOOLBAR nmtb = (LPNMTOOLBAR) notice; - RECT r; - - GetWindowRect(khui_hwnd_standard_toolbar, &r); - if (nmtb->iItem == KHUI_ACTION_DESTROY_CRED) { - khm_menu_show_panel(KHUI_MENU_DESTROY_CRED, - r.left + nmtb->rcButton.left, - r.top + nmtb->rcButton.bottom); - } else if (nmtb->iItem == KHUI_ACTION_RENEW_CRED) { - khm_menu_show_panel(KHUI_MENU_RENEW_CRED, - r.left + nmtb->rcButton.left, - r.top + nmtb->rcButton.bottom); - } else { - return TBDDRET_NODEFAULT; - } - - return TBDDRET_DEFAULT; - } - break; - - case NM_CUSTOMDRAW: - { - LPNMTBCUSTOMDRAW nmcd = (LPNMTBCUSTOMDRAW) notice; - if(nmcd->nmcd.dwDrawStage == CDDS_PREPAINT) { - return CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTERASE; - } else if(nmcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) { - return CDRF_NOTIFYPOSTPAINT; - } else if(nmcd->nmcd.dwDrawStage == CDDS_ITEMPOSTPAINT) { - /* draw the actual icon */ - int iidx; - int ibmp; - HBITMAP hbmp; - RECT r; - - khui_action * act = - khui_find_action((int) nmcd->nmcd.dwItemSpec); - - if(!act || !act->ib_normal) - return CDRF_DODEFAULT; - - if((act->state & KHUI_ACTIONSTATE_DISABLED) && - act->ib_disabled) { - ibmp = act->ib_disabled; - } else if(act->ib_hot && - ((nmcd->nmcd.uItemState & CDIS_HOT) || - (nmcd->nmcd.uItemState & CDIS_SELECTED))){ - ibmp = act->ib_hot; - } else { - ibmp = act->ib_normal; - } - - iidx = khui_ilist_lookup_id(ilist_toolbar, ibmp); - if(iidx < 0) { - hbmp = LoadImage(khm_hInstance, - MAKEINTRESOURCE(ibmp), - IMAGE_BITMAP, - KHUI_TOOLBAR_IMAGE_WIDTH, - KHUI_TOOLBAR_IMAGE_HEIGHT, 0); - iidx = - khui_ilist_add_masked_id(ilist_toolbar, - hbmp, - KHUI_TOOLBAR_BGCOLOR, - ibmp); - DeleteObject(hbmp); - } - - if(iidx < 0) - return CDRF_DODEFAULT; - - CopyRect(&r, &(nmcd->nmcd.rc)); - r.left += ((r.bottom - r.top) - - KHUI_TOOLBAR_IMAGE_HEIGHT) / 2; - r.top += ((r.bottom - r.top) - - KHUI_TOOLBAR_IMAGE_HEIGHT) / 2; -#if 0 - r.left += ((r.right - r.left) - - KHUI_TOOLBAR_IMAGE_WIDTH) / 2; -#endif - khui_ilist_draw(ilist_toolbar, - iidx, - nmcd->nmcd.hdc, - r.left, - r.top, - 0); - - return CDRF_DODEFAULT; - } - } - break; - } - return 0; -} - -void khui_add_action_to_toolbar(HWND tb, khui_action *a, int opt, HIMAGELIST hiList) { - wchar_t buf[MAX_RES_STRING] = L""; - int idx_caption = 0; - TBBUTTON bn; - LRESULT lr; - - ZeroMemory(&bn,sizeof(bn)); - - if(opt & KHUI_TOOLBAR_ADD_SEP) { - bn.fsStyle = BTNS_SEP; - bn.iBitmap = 3; - - lr = SendMessage(tb, - TB_ADDBUTTONS, - 1, - (LPARAM) &bn); -#ifdef DEBUG - assert(lr); -#endif - return; - } - - bn.fsStyle = BTNS_BUTTON; - - if(opt & KHUI_TOOLBAR_VARSIZE) { - bn.fsStyle |= BTNS_AUTOSIZE; - } - - if(opt & KHUI_TOOLBAR_ADD_TEXT) { - int sid = 0; - if((opt & KHUI_TOOLBAR_ADD_LONGTEXT) == - KHUI_TOOLBAR_ADD_LONGTEXT) { - sid = a->is_tooltip; - } - if(!sid) - sid = a->is_caption; - if(sid) { - LoadString(khm_hInstance, - sid, - buf, ARRAYLENGTH(buf)); - buf[wcslen(buf) + 1] = L'\0'; - idx_caption = (int) SendMessage(tb, - TB_ADDSTRING, - (WPARAM) NULL, - (LPARAM) buf); -#if (_WIN32_IE >= 0x0501) - bn.fsStyle |= BTNS_SHOWTEXT; -#endif - bn.iString = idx_caption; - } - } - - if(opt & KHUI_TOOLBAR_ADD_DROPDOWN) { - bn.fsStyle |= BTNS_DROPDOWN; - } - - if((opt & KHUI_TOOLBAR_ADD_BITMAP) && a->ib_normal) { - bn.fsStyle |= TBSTYLE_CUSTOMERASE; - bn.iBitmap = khui_tb_blank; - } else { -#if (_WIN32_IE >= 0x0501) - bn.iBitmap = I_IMAGENONE; -#endif - } - - bn.idCommand = a->cmd; - - if(a->state & KHUI_ACTIONSTATE_DISABLED) { - bn.fsState = 0; - } else { - bn.fsState = TBSTATE_ENABLED; - } - - if(a->state & KHUI_ACTIONSTATE_CHECKED) { - bn.fsState |= TBSTATE_CHECKED; - } - - bn.dwData = 0; - - lr = SendMessage( - tb, - TB_ADDBUTTONS, - 1, - (LPARAM) &bn); - -#ifdef DEBUG - assert(lr); -#endif -} - -void khm_update_standard_toolbar(void) -{ - khui_menu_def * def; - khui_action_ref * aref; - khui_action * act; - - def = khui_find_menu(KHUI_TOOLBAR_STANDARD); - - aref = def->items; - - while(aref && aref->action != KHUI_MENU_END) { - if(aref->action == KHUI_MENU_SEP) { - aref++; - continue; - } - - act = khui_find_action(aref->action); - if(act) { - BOOL enable; - - enable = !(act->state & KHUI_ACTIONSTATE_DISABLED); - SendMessage(khui_hwnd_standard_toolbar, - TB_ENABLEBUTTON, - (WPARAM) act->cmd, - MAKELPARAM(enable, 0)); - } - - aref++; - } -} - -void khm_create_standard_toolbar(HWND rebar) { - HWND hwtb; - SIZE sz; - HBITMAP hbm_blank; - HIMAGELIST hiList; - REBARBANDINFO rbi; - khui_menu_def * def; - khui_action * act; - khui_action_ref * aref; - int idx_blank; - - def = khui_find_menu(KHUI_TOOLBAR_STANDARD); - - if (!def) { -#ifdef DEBUG - assert(FALSE); -#endif - return; - } - - hwtb = CreateWindowEx(0 , - TOOLBARCLASSNAME, - (LPWSTR) NULL, - WS_CHILD | - TBSTYLE_FLAT | - TBSTYLE_AUTOSIZE | - TBSTYLE_TOOLTIPS | - CCS_NORESIZE | - CCS_NOPARENTALIGN | - CCS_ADJUSTABLE | - CCS_NODIVIDER, - 0, 0, 0, 0, rebar, - (HMENU) NULL, khm_hInstance, - NULL); - - if(!hwtb) { -#ifdef DEBUG - assert(FALSE); -#endif - return; - } - -#if (_WIN32_IE >= 0x0501) - SendMessage(hwtb, TB_SETEXTENDEDSTYLE, 0, - TBSTYLE_EX_MIXEDBUTTONS | TBSTYLE_EX_DRAWDDARROWS); -#endif - - hiList = ImageList_Create( - KHUI_TOOLBAR_IMAGE_WIDTH, - KHUI_TOOLBAR_IMAGE_HEIGHT, - ILC_MASK, - (int) khui_action_list_length(def->items), - 3); - - hbm_blank = LoadImage(khm_hInstance, - MAKEINTRESOURCE(IDB_TB_BLANK), - IMAGE_BITMAP, - KHUI_TOOLBAR_IMAGE_WIDTH, - KHUI_TOOLBAR_IMAGE_HEIGHT, 0); - idx_blank = ImageList_AddMasked(hiList, hbm_blank, RGB(0,0,0)); - - khui_hwnd_standard_toolbar = hwtb; - khui_tb_blank = idx_blank; - - def = khui_find_menu(KHUI_TOOLBAR_STANDARD); - - aref = def->items; - - SendMessage(hwtb, - TB_BUTTONSTRUCTSIZE, - sizeof(TBBUTTON), - 0); - - SendMessage(hwtb, - TB_SETBITMAPSIZE, - 0, - MAKELONG(KHUI_TOOLBAR_IMAGE_WIDTH,KHUI_TOOLBAR_IMAGE_HEIGHT)); - - SendMessage(hwtb, - TB_SETIMAGELIST, - 0, - (LPARAM) hiList); - - SendMessage(hwtb, - TB_SETBUTTONSIZE, - 0, - MAKELONG(KHUI_TOOLBAR_IMAGE_WIDTH,KHUI_TOOLBAR_IMAGE_HEIGHT)); - - while(aref && aref->action != KHUI_MENU_END) { - if(aref->action == KHUI_MENU_SEP) { - khui_add_action_to_toolbar(hwtb, - NULL, - KHUI_TOOLBAR_ADD_SEP, - hiList); - } else { - act = khui_find_action(aref->action); - khui_add_action_to_toolbar(hwtb, - act, - KHUI_TOOLBAR_ADD_BITMAP | - ((aref->flags & KHUI_ACTIONREF_SUBMENU)? - KHUI_TOOLBAR_ADD_DROPDOWN: 0), - hiList); - } - aref ++; - } - - SendMessage(hwtb, - TB_AUTOSIZE, - 0,0); - - SendMessage(hwtb, - TB_GETMAXSIZE, - 0, - (LPARAM) &sz); - - sz.cy += 5; - - ZeroMemory(&rbi, sizeof(rbi)); - - rbi.cbSize = sizeof(rbi); - rbi.fMask = - RBBIM_ID | - RBBIM_CHILD | - RBBIM_CHILDSIZE | - RBBIM_IDEALSIZE | - RBBIM_SIZE | - RBBIM_STYLE; - rbi.fStyle = - RBBS_USECHEVRON | - RBBS_BREAK; - rbi.hwndChild = hwtb; - - rbi.wID = KHUI_TOOLBAR_STANDARD; - rbi.cx = sz.cx; - rbi.cxMinChild = sz.cx; - rbi.cyMinChild = sz.cy; - rbi.cyChild = rbi.cyMinChild; - rbi.cyMaxChild = rbi.cyMinChild; - rbi.cyIntegral = rbi.cyMinChild; - - rbi.cxIdeal = rbi.cx; - - SendMessage(rebar, - RB_INSERTBAND, - 0, - (LPARAM) &rbi); -} +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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 + +HWND khui_hwnd_standard_toolbar; +int khui_tb_blank; + +khui_ilist * ilist_toolbar; + +void khui_init_toolbar(void) { + ilist_toolbar = khui_create_ilist(KHUI_TOOLBAR_IMAGE_WIDTH, KHUI_TOOLBAR_IMAGE_HEIGHT, KHUI_TOOLBAR_MAX_BTNS, 5, 0); +} + +void khui_exit_toolbar(void) { + khui_delete_ilist(ilist_toolbar); +} + +LRESULT khm_toolbar_notify(LPNMHDR notice) { + switch(notice->code) { + case TBN_GETINFOTIP: + { + LPNMTBGETINFOTIP git = (LPNMTBGETINFOTIP) notice; + int cmd; + khui_action * a; + + cmd = git->iItem; + a = khui_find_action(cmd); + + if (a) { + if (a->caption) { + StringCchCopy(git->pszText, git->cchTextMax, a->caption); + } else if (a->tooltip) { + StringCchCopy(git->pszText, git->cchTextMax, a->tooltip); + } else if (a->is_caption) { + wchar_t buf[INFOTIPSIZE]; + + buf[0] = L'\0'; + LoadString(khm_hInstance, a->is_caption, + buf, ARRAYLENGTH(buf)); + + StringCchCopy(git->pszText, git->cchTextMax, buf); + } else { + StringCchCopy(git->pszText, git->cchTextMax, L""); + } + } else { + StringCchCopy(git->pszText, + git->cchTextMax, + L""); + } + } + break; + + case TBN_HOTITEMCHANGE: + { + LPNMTBHOTITEM hi = (LPNMTBHOTITEM) notice; + + if (hi->dwFlags & HICF_LEAVING) { + khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, L""); + } else { + khui_action * a; + int cmd; + wchar_t buf[256]; + + cmd = hi->idNew; + a = khui_find_action(cmd); + + buf[0] = L'\0'; + + if (a) { + if (a->tooltip) + StringCbCopy(buf, sizeof(buf), a->tooltip); + else if (a->is_tooltip) { + LoadString(khm_hInstance, a->is_tooltip, + buf, ARRAYLENGTH(buf)); + } + } + + khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, buf); + } + } + break; + + case TBN_DROPDOWN: + { + LPNMTOOLBAR nmtb = (LPNMTOOLBAR) notice; + RECT r; + + GetWindowRect(khui_hwnd_standard_toolbar, &r); + if (nmtb->iItem == KHUI_ACTION_DESTROY_CRED) { + khm_menu_show_panel(KHUI_MENU_DESTROY_CRED, + r.left + nmtb->rcButton.left, + r.top + nmtb->rcButton.bottom); + } else if (nmtb->iItem == KHUI_ACTION_RENEW_CRED) { + khm_menu_show_panel(KHUI_MENU_RENEW_CRED, + r.left + nmtb->rcButton.left, + r.top + nmtb->rcButton.bottom); + } else { + return TBDDRET_NODEFAULT; + } + + return TBDDRET_DEFAULT; + } + break; + + case NM_CUSTOMDRAW: + { + LPNMTBCUSTOMDRAW nmcd = (LPNMTBCUSTOMDRAW) notice; + if(nmcd->nmcd.dwDrawStage == CDDS_PREPAINT) { + return CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTERASE; + } else if(nmcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) { + return CDRF_NOTIFYPOSTPAINT; + } else if(nmcd->nmcd.dwDrawStage == CDDS_ITEMPOSTPAINT) { + /* draw the actual icon */ + int iidx; + int ibmp; + HBITMAP hbmp; + RECT r; + + khui_action * act = + khui_find_action((int) nmcd->nmcd.dwItemSpec); + + if(!act || !act->ib_normal) + return CDRF_DODEFAULT; + + if((act->state & KHUI_ACTIONSTATE_DISABLED) && + act->ib_disabled) { + ibmp = act->ib_disabled; + } else if(act->ib_hot && + ((nmcd->nmcd.uItemState & CDIS_HOT) || + (nmcd->nmcd.uItemState & CDIS_SELECTED))){ + ibmp = act->ib_hot; + } else { + ibmp = act->ib_normal; + } + + iidx = khui_ilist_lookup_id(ilist_toolbar, ibmp); + if(iidx < 0) { + hbmp = LoadImage(khm_hInstance, + MAKEINTRESOURCE(ibmp), + IMAGE_BITMAP, + KHUI_TOOLBAR_IMAGE_WIDTH, + KHUI_TOOLBAR_IMAGE_HEIGHT, 0); + iidx = + khui_ilist_add_masked_id(ilist_toolbar, + hbmp, + KHUI_TOOLBAR_BGCOLOR, + ibmp); + DeleteObject(hbmp); + } + + if(iidx < 0) + return CDRF_DODEFAULT; + + CopyRect(&r, &(nmcd->nmcd.rc)); + r.left += ((r.bottom - r.top) - + KHUI_TOOLBAR_IMAGE_HEIGHT) / 2; + r.top += ((r.bottom - r.top) - + KHUI_TOOLBAR_IMAGE_HEIGHT) / 2; +#if 0 + r.left += ((r.right - r.left) - + KHUI_TOOLBAR_IMAGE_WIDTH) / 2; +#endif + khui_ilist_draw(ilist_toolbar, + iidx, + nmcd->nmcd.hdc, + r.left, + r.top, + 0); + + return CDRF_DODEFAULT; + } + } + break; + } + return 0; +} + +void khui_add_action_to_toolbar(HWND tb, khui_action *a, int opt, HIMAGELIST hiList) { + wchar_t buf[MAX_RES_STRING] = L""; + int idx_caption = 0; + TBBUTTON bn; + LRESULT lr; + + ZeroMemory(&bn,sizeof(bn)); + + if(opt & KHUI_TOOLBAR_ADD_SEP) { + bn.fsStyle = BTNS_SEP; + bn.iBitmap = 3; + + lr = SendMessage(tb, + TB_ADDBUTTONS, + 1, + (LPARAM) &bn); +#ifdef DEBUG + assert(lr); +#endif + return; + } + + bn.fsStyle = BTNS_BUTTON; + + if(opt & KHUI_TOOLBAR_VARSIZE) { + bn.fsStyle |= BTNS_AUTOSIZE; + } + + if(opt & KHUI_TOOLBAR_ADD_TEXT) { + int sid = 0; + if((opt & KHUI_TOOLBAR_ADD_LONGTEXT) == + KHUI_TOOLBAR_ADD_LONGTEXT) { + sid = a->is_tooltip; + } + if(!sid) + sid = a->is_caption; + if(sid) { + LoadString(khm_hInstance, + sid, + buf, ARRAYLENGTH(buf)); + buf[wcslen(buf) + 1] = L'\0'; + idx_caption = (int) SendMessage(tb, + TB_ADDSTRING, + (WPARAM) NULL, + (LPARAM) buf); +#if (_WIN32_IE >= 0x0501) + bn.fsStyle |= BTNS_SHOWTEXT; +#endif + bn.iString = idx_caption; + } + } + + if(opt & KHUI_TOOLBAR_ADD_DROPDOWN) { + bn.fsStyle |= BTNS_DROPDOWN; + } + + if((opt & KHUI_TOOLBAR_ADD_BITMAP) && a->ib_normal) { + bn.fsStyle |= TBSTYLE_CUSTOMERASE; + bn.iBitmap = khui_tb_blank; + } else { +#if (_WIN32_IE >= 0x0501) + bn.iBitmap = I_IMAGENONE; +#endif + } + + bn.idCommand = a->cmd; + + if(a->state & KHUI_ACTIONSTATE_DISABLED) { + bn.fsState = 0; + } else { + bn.fsState = TBSTATE_ENABLED; + } + + if(a->state & KHUI_ACTIONSTATE_CHECKED) { + bn.fsState |= TBSTATE_CHECKED; + } + + bn.dwData = 0; + + lr = SendMessage( + tb, + TB_ADDBUTTONS, + 1, + (LPARAM) &bn); + +#ifdef DEBUG + assert(lr); +#endif +} + +void khm_update_standard_toolbar(void) +{ + khui_menu_def * def; + khui_action_ref * aref; + khui_action * act; + + def = khui_find_menu(KHUI_TOOLBAR_STANDARD); + + aref = def->items; + + while(aref && aref->action != KHUI_MENU_END) { + if(aref->action == KHUI_MENU_SEP) { + aref++; + continue; + } + + act = khui_find_action(aref->action); + if(act) { + BOOL enable; + + enable = !(act->state & KHUI_ACTIONSTATE_DISABLED); + SendMessage(khui_hwnd_standard_toolbar, + TB_ENABLEBUTTON, + (WPARAM) act->cmd, + MAKELPARAM(enable, 0)); + } + + aref++; + } +} + +void khm_create_standard_toolbar(HWND rebar) { + HWND hwtb; + SIZE sz; + HBITMAP hbm_blank; + HIMAGELIST hiList; + REBARBANDINFO rbi; + khui_menu_def * def; + khui_action * act; + khui_action_ref * aref; + int idx_blank; + + def = khui_find_menu(KHUI_TOOLBAR_STANDARD); + + if (!def) { +#ifdef DEBUG + assert(FALSE); +#endif + return; + } + + hwtb = CreateWindowEx(0 , + TOOLBARCLASSNAME, + (LPWSTR) NULL, + WS_CHILD | + TBSTYLE_FLAT | + TBSTYLE_AUTOSIZE | + TBSTYLE_TOOLTIPS | + CCS_NORESIZE | + CCS_NOPARENTALIGN | + CCS_ADJUSTABLE | + CCS_NODIVIDER, + 0, 0, 0, 0, rebar, + (HMENU) NULL, khm_hInstance, + NULL); + + if(!hwtb) { +#ifdef DEBUG + assert(FALSE); +#endif + return; + } + +#if (_WIN32_IE >= 0x0501) + SendMessage(hwtb, TB_SETEXTENDEDSTYLE, 0, + TBSTYLE_EX_MIXEDBUTTONS | TBSTYLE_EX_DRAWDDARROWS); +#endif + + hiList = ImageList_Create( + KHUI_TOOLBAR_IMAGE_WIDTH, + KHUI_TOOLBAR_IMAGE_HEIGHT, + ILC_MASK, + (int) khui_action_list_length(def->items), + 3); + + hbm_blank = LoadImage(khm_hInstance, + MAKEINTRESOURCE(IDB_TB_BLANK), + IMAGE_BITMAP, + KHUI_TOOLBAR_IMAGE_WIDTH, + KHUI_TOOLBAR_IMAGE_HEIGHT, 0); + idx_blank = ImageList_AddMasked(hiList, hbm_blank, RGB(0,0,0)); + + khui_hwnd_standard_toolbar = hwtb; + khui_tb_blank = idx_blank; + + def = khui_find_menu(KHUI_TOOLBAR_STANDARD); + + aref = def->items; + + SendMessage(hwtb, + TB_BUTTONSTRUCTSIZE, + sizeof(TBBUTTON), + 0); + + SendMessage(hwtb, + TB_SETBITMAPSIZE, + 0, + MAKELONG(KHUI_TOOLBAR_IMAGE_WIDTH,KHUI_TOOLBAR_IMAGE_HEIGHT)); + + SendMessage(hwtb, + TB_SETIMAGELIST, + 0, + (LPARAM) hiList); + + SendMessage(hwtb, + TB_SETBUTTONSIZE, + 0, + MAKELONG(KHUI_TOOLBAR_IMAGE_WIDTH,KHUI_TOOLBAR_IMAGE_HEIGHT)); + + while(aref && aref->action != KHUI_MENU_END) { + if(aref->action == KHUI_MENU_SEP) { + khui_add_action_to_toolbar(hwtb, + NULL, + KHUI_TOOLBAR_ADD_SEP, + hiList); + } else { + act = khui_find_action(aref->action); + khui_add_action_to_toolbar(hwtb, + act, + KHUI_TOOLBAR_ADD_BITMAP | + ((aref->flags & KHUI_ACTIONREF_SUBMENU)? + KHUI_TOOLBAR_ADD_DROPDOWN: 0), + hiList); + } + aref ++; + } + + SendMessage(hwtb, + TB_AUTOSIZE, + 0,0); + + SendMessage(hwtb, + TB_GETMAXSIZE, + 0, + (LPARAM) &sz); + + sz.cy += 5; + + ZeroMemory(&rbi, sizeof(rbi)); + + rbi.cbSize = sizeof(rbi); + rbi.fMask = + RBBIM_ID | + RBBIM_CHILD | + RBBIM_CHILDSIZE | + RBBIM_IDEALSIZE | + RBBIM_SIZE | + RBBIM_STYLE; + rbi.fStyle = + RBBS_USECHEVRON | + RBBS_BREAK; + rbi.hwndChild = hwtb; + + rbi.wID = KHUI_TOOLBAR_STANDARD; + rbi.cx = sz.cx; + rbi.cxMinChild = sz.cx; + rbi.cyMinChild = sz.cy; + rbi.cyChild = rbi.cyMinChild; + rbi.cyMaxChild = rbi.cyMinChild; + rbi.cyIntegral = rbi.cyMinChild; + + rbi.cxIdeal = rbi.cx; + + SendMessage(rebar, + RB_INSERTBAND, + 0, + (LPARAM) &rbi); +} diff --git a/src/windows/identity/ui/toolbar.h b/src/windows/identity/ui/toolbar.h index 8068a6be2..ac09c6619 100644 --- a/src/windows/identity/ui/toolbar.h +++ b/src/windows/identity/ui/toolbar.h @@ -1,52 +1,52 @@ -/* - * 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_TOOLBAR_H -#define __KHIMAIRA_TOOLBAR_H - -extern HWND khui_hwnd_standard_toolbar; - -void khui_init_toolbar(void); -void khui_exit_toolbar(void); -LRESULT khm_toolbar_notify(LPNMHDR notice); -void khm_create_standard_toolbar(HWND rebar); -void khui_add_action_to_toolbar(HWND toolbar, khui_action * act, int opt, HIMAGELIST hiList); -void khm_update_standard_toolbar(void); - -/* options for khui_add_action_to_toolbar */ -#define KHUI_TOOLBAR_ADD_TEXT 0x00000001 -#define KHUI_TOOLBAR_ADD_BITMAP 0x00000002 -#define KHUI_TOOLBAR_ADD_LONGTEXT 0x00000005 -#define KHUI_TOOLBAR_ADD_DROPDOWN 0x00000008 -#define KHUI_TOOLBAR_ADD_SEP 0x00000010 -#define KHUI_TOOLBAR_VARSIZE 0x00000020 - -#define KHUI_TOOLBAR_IMAGE_WIDTH 29 -#define KHUI_TOOLBAR_IMAGE_HEIGHT 27 -#define KHUI_TOOLBAR_BGCOLOR RGB(0xd7,0xd7,0xd7) -#define KHUI_TOOLBAR_MAX_BTNS 64 - -#endif +/* + * 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_TOOLBAR_H +#define __KHIMAIRA_TOOLBAR_H + +extern HWND khui_hwnd_standard_toolbar; + +void khui_init_toolbar(void); +void khui_exit_toolbar(void); +LRESULT khm_toolbar_notify(LPNMHDR notice); +void khm_create_standard_toolbar(HWND rebar); +void khui_add_action_to_toolbar(HWND toolbar, khui_action * act, int opt, HIMAGELIST hiList); +void khm_update_standard_toolbar(void); + +/* options for khui_add_action_to_toolbar */ +#define KHUI_TOOLBAR_ADD_TEXT 0x00000001 +#define KHUI_TOOLBAR_ADD_BITMAP 0x00000002 +#define KHUI_TOOLBAR_ADD_LONGTEXT 0x00000005 +#define KHUI_TOOLBAR_ADD_DROPDOWN 0x00000008 +#define KHUI_TOOLBAR_ADD_SEP 0x00000010 +#define KHUI_TOOLBAR_VARSIZE 0x00000020 + +#define KHUI_TOOLBAR_IMAGE_WIDTH 29 +#define KHUI_TOOLBAR_IMAGE_HEIGHT 27 +#define KHUI_TOOLBAR_BGCOLOR RGB(0xd7,0xd7,0xd7) +#define KHUI_TOOLBAR_MAX_BTNS 64 + +#endif diff --git a/src/windows/identity/uilib/action.c b/src/windows/identity/uilib/action.c index ae017e1d0..d5556620d 100644 --- a/src/windows/identity/uilib/action.c +++ b/src/windows/identity/uilib/action.c @@ -1,1656 +1,1656 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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$ */ - -#define NOEXPORT -#include -#include -#include -#include - -#include - -khui_action_ref khui_main_menu[] = { - 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() -}; - -khui_action_ref khui_menu_file[] = { - MENU_ACTION(KHUI_ACTION_PROPERTIES), - MENU_SEP(), - MENU_ACTION(KHUI_ACTION_EXIT), - MENU_END() -}; - -khui_action_ref khui_menu_cred[] = { - MENU_ACTION(KHUI_ACTION_NEW_CRED), - MENU_SEP(), - MENU_SUBMENU(KHUI_MENU_RENEW_CRED), - MENU_ACTION(KHUI_ACTION_IMPORT), - MENU_SUBMENU(KHUI_MENU_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() -}; - -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() -}; - -khui_action_ref khui_menu_toolbars[] = { - MENU_ACTION(KHUI_ACTION_TB_STANDARD), - MENU_END() -}; - -khui_action_ref khui_menu_view[] = { - MENU_ACTION(KHUI_ACTION_LAYOUT_MINI), - 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() -}; - -khui_action_ref khui_menu_options[] = { - MENU_ACTION(KHUI_ACTION_OPT_KHIM), - MENU_ACTION(KHUI_ACTION_OPT_APPEAR), - MENU_ACTION(KHUI_ACTION_OPT_IDENTS), - MENU_ACTION(KHUI_ACTION_OPT_NOTIF), - MENU_ACTION(KHUI_ACTION_OPT_PLUGINS), - MENU_SEP(), - MENU_END() -}; - -khui_action_ref khui_menu_help[] = { - MENU_ACTION(KHUI_ACTION_HELP_CTX), - MENU_SEP(), - MENU_ACTION(KHUI_ACTION_HELP_INDEX), - MENU_SEP(), - MENU_ACTION(KHUI_ACTION_HELP_ABOUT), - MENU_END() -}; - -khui_action_ref khui_toolbar_standard[] = { - MENU_ACTION(KHUI_ACTION_NEW_CRED), - MENU_SUBMENU(KHUI_ACTION_RENEW_CRED), - MENU_ACTION(KHUI_ACTION_IMPORT), - MENU_SUBMENU(KHUI_ACTION_DESTROY_CRED), - MENU_SEP(), - MENU_ACTION(KHUI_ACTION_PASSWD_ID), - MENU_SEP(), - MENU_ACTION(KHUI_ACTION_VIEW_REFRESH), - MENU_ACTION(KHUI_PACTION_BLANK), - MENU_ACTION(KHUI_ACTION_HELP_CTX), - MENU_END() -}; - -khui_action_ref khui_menu_ident_ctx[] = { - MENU_ACTION(KHUI_ACTION_PROPERTIES), - MENU_SEP(), - MENU_ACTION(KHUI_ACTION_SET_DEF_ID), - MENU_ACTION(KHUI_ACTION_SET_SRCH_ID), - MENU_SEP(), - MENU_ACTION(KHUI_ACTION_NEW_CRED), - MENU_ACTION(KHUI_ACTION_RENEW_CRED), - MENU_ACTION(KHUI_ACTION_DESTROY_CRED), - MENU_END() -}; - -khui_action_ref khui_menu_tok_ctx[] = { - MENU_ACTION(KHUI_ACTION_PROPERTIES), - MENU_SEP(), - MENU_ACTION(KHUI_ACTION_NEW_CRED), - MENU_ACTION(KHUI_ACTION_RENEW_CRED), - MENU_ACTION(KHUI_ACTION_DESTROY_CRED), - MENU_END() -}; - -khui_action_ref khui_menu_ico_ctx_min[] = { - MENU_DEFACTION(KHUI_ACTION_OPEN_APP), - MENU_SEP(), - MENU_ACTION(KHUI_ACTION_NEW_CRED), - MENU_SUBMENU(KHUI_MENU_RENEW_CRED), - MENU_ACTION(KHUI_ACTION_IMPORT), - MENU_SUBMENU(KHUI_MENU_DESTROY_CRED), - MENU_SEP(), - MENU_ACTION(KHUI_ACTION_PASSWD_ID), - MENU_SEP(), - MENU_ACTION(KHUI_ACTION_HELP_CTX), - MENU_ACTION(KHUI_ACTION_HELP_ABOUT), - MENU_SEP(), - MENU_ACTION(KHUI_ACTION_EXIT), - MENU_END() -}; - -khui_action_ref khui_menu_ico_ctx_normal[] = { - MENU_DEFACTION(KHUI_ACTION_CLOSE_APP), - MENU_SEP(), - MENU_ACTION(KHUI_ACTION_NEW_CRED), - MENU_SUBMENU(KHUI_MENU_RENEW_CRED), - MENU_ACTION(KHUI_ACTION_IMPORT), - MENU_SUBMENU(KHUI_MENU_DESTROY_CRED), - MENU_SEP(), - MENU_ACTION(KHUI_ACTION_PASSWD_ID), - MENU_SEP(), - MENU_ACTION(KHUI_ACTION_HELP_CTX), - MENU_ACTION(KHUI_ACTION_HELP_ABOUT), - MENU_SEP(), - MENU_ACTION(KHUI_ACTION_EXIT), - 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_menu_destroy_cred[] = { - MENU_DEFACTION(KHUI_ACTION_DESTROY_ALL), - MENU_END() -}; - -khui_action_ref khui_menu_renew_cred[] = { - MENU_DEFACTION(KHUI_ACTION_RENEW_ALL), - MENU_END() -}; - -khui_action_ref khui_pmenu_tok_sel[] = { - MENU_ACTION(KHUI_ACTION_RENEW_CRED), - MENU_ACTION(KHUI_ACTION_DESTROY_CRED), - MENU_END() -}; - -khui_action_ref khui_pmenu_id_sel[] = { - MENU_ACTION(KHUI_ACTION_DESTROY_CRED), - MENU_ACTION(KHUI_ACTION_RENEW_CRED), - MENU_END() -}; - -/* all stock menus and toolbars */ -khui_menu_def khui_all_menus[] = { - 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), - CONSTMENU(KHUI_MENU_RENEW_CRED, KHUI_MENUSTATE_CONSTANT | KHUI_MENUSTATE_SYSTEM, khui_menu_renew_cred), - CONSTMENU(KHUI_MENU_DESTROY_CRED, KHUI_MENUSTATE_CONSTANT | KHUI_MENUSTATE_SYSTEM, khui_menu_destroy_cred), - - /* toolbars */ - 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), - CONSTMENU(KHUI_PMENU_ID_SEL, KHUI_MENUSTATE_CONSTANT, khui_pmenu_id_sel) -}; - -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); -} - -KHMEXP void KHMAPI -khui_exit_actions(void) { - DeleteCriticalSection(&cs_actions); -} - -KHMEXP void KHMAPI -khui_refresh_actions(void) { - kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); -} - -KHMEXP void KHMAPI -khui_action_lock(void) { - EnterCriticalSection(&cs_actions); -} - -KHMEXP void KHMAPI -khui_action_unlock(void) { - LeaveCriticalSection(&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 ((name && FAILED(StringCchLength(name, KHUI_MAXCCH_NAME, &s))) || - !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; - void * data; - - EnterCriticalSection(&cs_actions); - act = khui_find_action(action); - if (act == NULL || (act->state & KHUI_ACTIONSTATE_DELETED)) - data = NULL; - else - data = act->data; - LeaveCriticalSection(&cs_actions); - - return data; -} - -KHMEXP void KHMAPI -khui_action_delete(khm_int32 action) { - khui_action * act; - - EnterCriticalSection(&cs_actions); - - act = khui_find_action(action); - - if (act == NULL) { - LeaveCriticalSection(&cs_actions); - 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. */ - 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(khm_int32 action) -{ - khui_menu_def * d; - - d = PMALLOC(sizeof(*d)); - ZeroMemory(d, sizeof(*d)); - - d->cmd = action; - d->nc_items = MENU_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) -{ - khui_menu_def * d; - size_t i; - size_t n; - - EnterCriticalSection(&cs_actions); - - d = khui_menu_create(src->cmd); - - 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_insert_paction(d, -1, src->items[i].p_action, src->items[i].flags); - } else { - khui_menu_insert_action(d, -1, src->items[i].action, 0); - } - } - - LeaveCriticalSection(&cs_actions); - - return d; -} - -KHMEXP void KHMAPI -khui_menu_delete(khui_menu_def * d) -{ - int i; - - /* non-allocated menus are assumed to have no pointers to other - allocated blocks */ - 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; - } - } - - for(i=0; i< (int) d->n_items; i++) { - if(d->items[i].flags & KHUI_ACTIONREF_FREE_PACTION) - PFREE(d->items[i].p_action); - } - - if(d->items) - PFREE(d->items); - PFREE(d); - - LeaveCriticalSection(&cs_actions); -} - -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; - - d->nc_items = UBOUNDSS(n, MENU_NC_ITEMS, MENU_NC_ITEMS); - ni = PMALLOC(sizeof(*(d->items)) * d->nc_items); - memcpy(ni, d->items, sizeof(*(d->items)) * d->n_items); - PFREE(d->items); - d->items = ni; - } -} - -static void -menu_const_to_allocd(khui_menu_def * d) -{ - 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_insert_action(khui_menu_def * d, khm_size idx, khm_int32 action, khm_int32 flags) -{ - khm_size i; - - EnterCriticalSection(&cs_actions); - - 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++; - - /* only one action is allowed to have the KHUI_ACTIONREF_DEFAULT - flag */ - if (flags & KHUI_ACTIONREF_DEFAULT) { - for (i=0; i < d->n_items; i++) { - if (i != idx && (d->items[i].flags & KHUI_ACTIONREF_DEFAULT)) - d->items[i].flags &= ~KHUI_ACTIONREF_DEFAULT; - } - } - - LeaveCriticalSection(&cs_actions); -} - -KHMEXP void KHMAPI -khui_menu_insert_paction(khui_menu_def * d, khm_size idx, khui_action * paction, int flags) -{ - khm_size i; - - if (paction == NULL) - return; - - EnterCriticalSection(&cs_actions); - - 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++; - - /* only one action is allowed to have the KHUI_ACTIONREF_DEFAULT - flag */ - if (flags & KHUI_ACTIONREF_DEFAULT) { - for (i=0; i < d->n_items; i++) { - if (i != idx && (d->items[i].flags & KHUI_ACTIONREF_DEFAULT)) - d->items[i].flags &= ~KHUI_ACTIONREF_DEFAULT; - } - } - - LeaveCriticalSection(&cs_actions); -} - -KHMEXP void KHMAPI -khui_menu_remove_action(khui_menu_def * d, khm_size idx) { - - EnterCriticalSection(&cs_actions); - - if (!(d->state & KHUI_MENUSTATE_ALLOCD)) - menu_const_to_allocd(d); - - assert(d->state & KHUI_MENUSTATE_ALLOCD); - - if (idx >= 0 && idx < d->n_items) { - - 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--; - - } - - LeaveCriticalSection(&cs_actions); -} - -KHMEXP khm_size KHMAPI -khui_menu_get_size(khui_menu_def * d) { - - khm_size size; - - EnterCriticalSection(&cs_actions); - - if (d->state & KHUI_MENUSTATE_ALLOCD) - size = d->n_items; - else - size = khui_action_list_length(d->items); - - LeaveCriticalSection(&cs_actions); - - return size; -} - -KHMEXP khui_action_ref * -khui_menu_get_action(khui_menu_def * d, khm_size idx) { - - khui_action_ref * act = NULL; - khm_size n; - - EnterCriticalSection(&cs_actions); - - if (d->state & KHUI_MENUSTATE_ALLOCD) - n = d->n_items; - else - n = khui_action_list_length(d->items); - - if (idx < 0 || idx >= n) - act = NULL; - else - act = &d->items[idx]; - - LeaveCriticalSection(&cs_actions); - - return act; -} - -KHMEXP khui_menu_def * KHMAPI -khui_find_menu(khm_int32 id) { - khui_menu_def * d; - int i; - - if (id < KHUI_USERACTION_BASE) { - - /* the list of system menus are considered immutable. */ - - 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(khm_int32 id) { - khui_action * act; - int i; - - act = khui_actions; - for(i=0;i= 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(const wchar_t * name) { - int i; - khui_action * act; - khui_action ** pact; - - if(!name) - return NULL; - - act = khui_actions; - for(i=0;iname) - continue; - - if(!wcscmp(pact[i]->name, name)) { - - if (!(pact[i]->state & KHUI_ACTIONSTATE_DELETED)) { - act = pact[i]; - } - break; - } - } - - LeaveCriticalSection(&cs_actions); - - return act; -} - -KHMEXP size_t KHMAPI -khui_action_list_length(khui_action_ref * ref) { - size_t c = 0; - - EnterCriticalSection(&cs_actions); - - while(ref && ref->action != KHUI_MENU_END && - !(ref->flags & KHUI_ACTIONREF_END)) { - c++; - ref++; - } - - LeaveCriticalSection(&cs_actions); - - return c; -} - -KHMEXP void KHMAPI -khui_check_radio_action(khui_menu_def * d, khm_int32 cmd) -{ - khui_action_ref * r; - khui_action * act; - - EnterCriticalSection(&cs_actions); - - r = d->items; - 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 { - act = khui_find_action(r->action); - } - - if(act) { - if(act->cmd == cmd) - act->state |= KHUI_ACTIONSTATE_CHECKED; - else - act->state &= ~KHUI_ACTIONSTATE_CHECKED; - } - r++; - } - - LeaveCriticalSection(&cs_actions); - - kmq_post_message(KMSG_ACT, KMSG_ACT_CHECK, 0, 0); -} - -KHMEXP void KHMAPI -khui_check_action(khm_int32 cmd, khm_boolean check) { - khui_action * act; - - act = khui_find_action(cmd); - if (!act) - return; - - EnterCriticalSection(&cs_actions); - - if (check && !(act->state & KHUI_ACTIONSTATE_CHECKED)) - act->state |= KHUI_ACTIONSTATE_CHECKED; - else if (!check && (act->state & KHUI_ACTIONSTATE_CHECKED)) - act->state &= ~KHUI_ACTIONSTATE_CHECKED; - else { - LeaveCriticalSection(&cs_actions); - return; - } - - LeaveCriticalSection(&cs_actions); - - kmq_post_message(KMSG_ACT, KMSG_ACT_CHECK, 0, 0); -} - -KHMEXP void KHMAPI -khui_enable_actions(khui_menu_def * d, khm_boolean enable) -{ - khui_action_ref * r; - int delta = FALSE; - khui_action * act; - - EnterCriticalSection(&cs_actions); - - r = d->items; - 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 { - act = khui_find_action(r->action); - } - - if(act) { - int old_state = act->state; - - if(enable) - act->state &= ~KHUI_ACTIONSTATE_DISABLED; - else - act->state |= KHUI_ACTIONSTATE_DISABLED; - - if(old_state != act->state) - delta = TRUE; - } - r++; - } - - LeaveCriticalSection(&cs_actions); - - if(delta) { - kmq_post_message(KMSG_ACT, KMSG_ACT_ENABLE, 0, 0); - } -} - -KHMEXP void KHMAPI -khui_enable_action(khm_int32 cmd, khm_boolean enable) { - khui_action * act; - - act = khui_find_action(cmd); - if (!act) - return; - - EnterCriticalSection(&cs_actions); - - if (enable && (act->state & KHUI_ACTIONSTATE_DISABLED)) { - act->state &= ~KHUI_ACTIONSTATE_DISABLED; - } else if (!enable && !(act->state & KHUI_ACTIONSTATE_DISABLED)) { - act->state |= KHUI_ACTIONSTATE_DISABLED; - } else { - LeaveCriticalSection(&cs_actions); - return; - } - - LeaveCriticalSection(&cs_actions); - - kmq_post_message(KMSG_ACT, KMSG_ACT_ENABLE, 0, 0); -} - -KHMEXP HACCEL KHMAPI -khui_create_global_accel_table(void) { - int i; - ACCEL * accels; - HACCEL ha; - - accels = PMALLOC(sizeof(ACCEL) * khui_n_accel_global); - for(i=0;imod & FALT) { - if(FAILED(StringCbCat(buf, bufsiz, L"Alt+"))) - return FALSE; - } - - - if(def->mod & FCONTROL) { - if(FAILED(StringCbCat(buf, bufsiz, L"Ctrl+"))) - return FALSE; - } - - if(def->mod & FSHIFT) { - if(FAILED(StringCbCat(buf, bufsiz, L"Shift+"))) - return FALSE; - } - - if(def->mod & FVIRTKEY) { - wchar_t mbuf[6]; - wchar_t * ap = NULL; - switch(def->key) { - case VK_TAB: - ap = L"Tab"; - break; - - case VK_ESCAPE: - ap = L"Esc"; - break; - - case VK_RETURN: - 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_F11: - ap = L"F11"; - break; - - case VK_F12: - ap = L"F12"; - break; - - case VK_DELETE: - ap = L"Del"; - break; - - default: - if((def->key >= '0' && - def->key <= '9') || - (def->key >= 'A' && - def->key <= 'Z')) { - ap = mbuf; - mbuf[0] = (wchar_t) def->key; - mbuf[1] = L'\0'; - } - } - if(ap) { - if(FAILED(StringCbCat(buf, bufsiz, ap))) - return FALSE; - } - else { - if(FAILED(StringCbCat(buf, bufsiz,L"???"))) - return FALSE; - } - - } else { - wchar_t mbuf[2]; - - mbuf[0] = def->key; - mbuf[1] = L'\0'; - - if(FAILED(StringCbCat(buf, bufsiz, mbuf))) - return FALSE; - } - - return TRUE; -} - -/******************************************/ -/* contexts */ - -#define KHUI_ACTION_CONTEXT_MAGIC 0x39c49db5 - -static khm_int32 KHMAPI -khuiint_filter_selected(khm_handle cred, - khm_int32 vflags, - void * rock) { - khm_int32 flags; - if (KHM_SUCCEEDED(kcdb_cred_get_flags(cred, &flags)) && - (flags & KCDB_CRED_FLAG_SELECTED)) - return TRUE; - else - return FALSE; -} - -static void -khuiint_context_release(khui_action_context * ctx) { - ctx->scope = KHUI_SCOPE_NONE; - if (ctx->identity) - kcdb_identity_release(ctx->identity); - ctx->identity = NULL; - ctx->cred_type = KCDB_CREDTYPE_INVALID; - if (ctx->cred) - kcdb_cred_release(ctx->cred); - ctx->cred = NULL; - ctx->n_headers = 0; - if (ctx->credset) - kcdb_credset_flush(ctx->credset); - ctx->n_sel_creds = 0; - ctx->int_cb_used = 0; - ctx->vparam = NULL; - ctx->cb_vparam = 0; -} - -static void -khuiint_copy_context(khui_action_context * ctxdest, - const khui_action_context * ctxsrc) -{ - ctxdest->scope = ctxsrc->scope; - - if (ctxsrc->scope == KHUI_SCOPE_IDENT) { - ctxdest->identity = ctxsrc->identity; - kcdb_identity_hold(ctxsrc->identity); - } else if (ctxsrc->scope == KHUI_SCOPE_CREDTYPE) { - ctxdest->identity = ctxsrc->identity; - ctxdest->cred_type = ctxsrc->cred_type; - if (ctxsrc->identity != NULL) - kcdb_identity_hold(ctxsrc->identity); - } else if (ctxsrc->scope == KHUI_SCOPE_CRED) { - kcdb_cred_get_identity(ctxsrc->cred, &ctxdest->identity); - kcdb_cred_get_type(ctxsrc->cred, &ctxdest->cred_type); - ctxdest->cred = ctxsrc->cred; - kcdb_cred_hold(ctxsrc->cred); - } else if (ctxsrc->scope == KHUI_SCOPE_GROUP) { - khm_size cb_total; - int i; - - ctxdest->n_headers = ctxsrc->n_headers; - cb_total = 0; - for (i=0; i < (int) ctxsrc->n_headers; i++) { - cb_total += UBOUND32(ctxsrc->headers[i].cb_data); - } - - if (ctxdest->int_cb_buf < cb_total) { - - if (ctxdest->int_buf) - PFREE(ctxdest->int_buf); - - ctxdest->int_cb_buf = cb_total; - ctxdest->int_buf = PMALLOC(cb_total); - } - -#ifdef DEBUG - assert(ctxdest->int_buf || cb_total == 0); -#endif - ctxdest->int_cb_used = 0; - - for (i=0; i < (int) ctxsrc->n_headers; i++) { - ctxdest->headers[i].attr_id = ctxsrc->headers[i].attr_id; - ctxdest->headers[i].cb_data = ctxsrc->headers[i].cb_data; - if (ctxsrc->headers[i].cb_data > 0) { - ctxdest->headers[i].data = - BYTEOFFSET(ctxdest->int_buf, - ctxdest->int_cb_used); - memcpy(ctxdest->headers[i].data, - ctxsrc->headers[i].data, - ctxsrc->headers[i].cb_data); - ctxdest->int_cb_used += - UBOUND32(ctxsrc->headers[i].cb_data); - } else { - ctxdest->headers[i].data = NULL; - } - } - } - - if (ctxsrc->credset) { - - if (ctxdest->credset == NULL) - kcdb_credset_create(&ctxdest->credset); -#ifdef DEBUG - assert(ctxdest->credset != NULL); -#endif - - kcdb_credset_flush(ctxdest->credset); - - kcdb_credset_extract_filtered(ctxdest->credset, - ctxsrc->credset, - khuiint_filter_selected, - NULL); - - kcdb_credset_get_size(ctxdest->credset, - &ctxdest->n_sel_creds); - } else { - if (ctxdest->credset != NULL) - kcdb_credset_flush(ctxdest->credset); - ctxdest->n_sel_creds = 0; - } - - /* For now, we simply transfer the vparam buffer into the new - context. If we are copying, we also need to modify - khui_context_release() to free the allocated buffer */ -#if 0 - if (ctxsrc->vparam && ctxsrc->cb_vparam) { - ctxdest->vparam = PMALLOC(ctxsrc->cb_vparam); -#ifdef DEBUG - assert(ctxdest->vparam); -#endif - memcpy(ctxdest->vparam, ctxsrc->vparam, ctxsrc->cb_vparam); - ctxdest->cb_vparam = ctxsrc->cb_vparam; - } else { -#endif - ctxdest->vparam = ctxsrc->vparam; - ctxdest->cb_vparam = ctxsrc->cb_vparam; -#if 0 - } -#endif -} - -static void -khuiint_context_init(khui_action_context * ctx) { - ctx->magic = KHUI_ACTION_CONTEXT_MAGIC; - ctx->scope = KHUI_SCOPE_NONE; - ctx->identity = NULL; - ctx->cred_type = KCDB_CREDTYPE_INVALID; - ctx->cred = NULL; - ZeroMemory(ctx->headers, sizeof(ctx->headers)); - ctx->n_headers = 0; - ctx->credset = NULL; - ctx->n_sel_creds = 0; - ctx->int_buf = NULL; - ctx->int_cb_buf = 0; - ctx->int_cb_used = 0; - ctx->vparam = NULL; - ctx->cb_vparam = 0; -} - -khui_action_context khui_ctx = { - KHUI_ACTION_CONTEXT_MAGIC, - KHUI_SCOPE_NONE, - NULL, - KCDB_CREDTYPE_INVALID, - NULL, - { - {KCDB_ATTR_INVALID,NULL,0}, - {KCDB_ATTR_INVALID,NULL,0}, - {KCDB_ATTR_INVALID,NULL,0}, - {KCDB_ATTR_INVALID,NULL,0}, - {KCDB_ATTR_INVALID,NULL,0}, - {KCDB_ATTR_INVALID,NULL,0} - }, - 0, - NULL, - 0, - NULL, - 0, - 0, - NULL, - 0}; - -khm_int32 KHMAPI -set_cred_select_flag(khm_handle cred, void * rock) { - kcdb_cred_set_flags(cred, KCDB_CRED_FLAG_SELECTED, - KCDB_CRED_FLAG_SELECTED); - return KHM_ERROR_SUCCESS; -} - -KHMEXP void KHMAPI -khui_context_create(khui_action_context * ctx, - khui_scope scope, - khm_handle identity, - khm_int32 cred_type, - khm_handle cred) -{ - khui_action_context tctx; - - khuiint_context_init(&tctx); - khuiint_context_init(ctx); - - tctx.scope = scope; - tctx.identity = identity; - tctx.cred_type = cred_type; - tctx.cred = cred; - - /* fill up the credset based on the scope */ - if (scope != KHUI_SCOPE_NONE) { - if (tctx.credset == NULL) - kcdb_credset_create(&tctx.credset); - else - kcdb_credset_flush(tctx.credset); - - if (scope == KHUI_SCOPE_IDENT) { - kcdb_credset_extract(tctx.credset, - NULL, - tctx.identity, - KCDB_CREDTYPE_INVALID); - } else if (scope == KHUI_SCOPE_CREDTYPE) { - kcdb_credset_extract(tctx.credset, - NULL, - tctx.identity, - tctx.cred_type); - } else if (scope == KHUI_SCOPE_CRED) { - khm_handle dupcred = NULL; - kcdb_cred_dup(cred, &dupcred); - - kcdb_credset_add_cred(tctx.credset, dupcred, -1); - } else { -#ifdef DEBUG - /* KHUI_SCOPE_GROUP is not used with - khui_context_create() */ - assert(FALSE); -#endif - } - - kcdb_credset_apply(tctx.credset, set_cred_select_flag, - NULL); - - kcdb_credset_seal(tctx.credset); - } - - khuiint_copy_context(ctx, &tctx); -} - -KHMEXP void KHMAPI -khui_context_set(khui_scope scope, - khm_handle identity, - khm_int32 cred_type, - khm_handle cred, - khui_header *headers, - khm_size n_headers, - khm_handle cs_src) { - - khui_context_set_ex(scope, - identity, - cred_type, - cred, - headers, - n_headers, - cs_src, - NULL, - 0); -} - -KHMEXP void KHMAPI -khui_context_set_ex(khui_scope scope, - khm_handle identity, - khm_int32 cred_type, - khm_handle cred, - khui_header *headers, - khm_size n_headers, - khm_handle cs_src, - void * vparam, - khm_size cb_vparam) -{ - khui_action_context tctx; - - EnterCriticalSection(&cs_actions); - - khuiint_context_release(&khui_ctx); - - khuiint_context_init(&tctx); - - tctx.scope = scope; - tctx.identity = identity; - tctx.cred_type = cred_type; - tctx.cred = cred; - if (headers) { - tctx.n_headers = n_headers; - memcpy(tctx.headers, - headers, - sizeof(*headers) * n_headers); - } else { - tctx.n_headers = 0; - } - tctx.credset = cs_src; - tctx.n_sel_creds = 0; /* ignored */ - tctx.vparam = vparam; - tctx.cb_vparam = cb_vparam; - tctx.int_buf = NULL; - tctx.int_cb_buf = 0; - tctx.int_cb_used = 0; - - khuiint_copy_context(&khui_ctx, &tctx); - - khui_context_refresh(); - - 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; - - EnterCriticalSection(&cs_actions); - if (khui_ctx.identity) { - /* an identity is selected */ - - if (KHM_SUCCEEDED(kcdb_identity_get_flags(khui_ctx.identity, - &flags)) && - (flags & KCDB_IDENT_FLAG_DEFAULT)) { - khui_check_action(KHUI_ACTION_SET_DEF_ID, TRUE); - khui_enable_action(KHUI_ACTION_SET_DEF_ID, FALSE); - } else { - khui_check_action(KHUI_ACTION_SET_DEF_ID, FALSE); - khui_enable_action(KHUI_ACTION_SET_DEF_ID, TRUE); - } - } else { - khui_check_action(KHUI_ACTION_SET_DEF_ID, FALSE); - khui_enable_action(KHUI_ACTION_SET_DEF_ID, FALSE); - } - - if (khui_ctx.scope != KHUI_SCOPE_NONE) { - khui_enable_action(KHUI_ACTION_PROPERTIES, TRUE); - } else { - khui_enable_action(KHUI_ACTION_PROPERTIES, FALSE); - } - - LeaveCriticalSection(&cs_actions); - - kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); -} - -KHMEXP void KHMAPI -khui_context_get(khui_action_context * ctx) -{ - EnterCriticalSection(&cs_actions); - - khuiint_context_init(ctx); - khuiint_copy_context(ctx, &khui_ctx); - - if (ctx->credset) { - kcdb_credset_seal(ctx->credset); - } - - LeaveCriticalSection(&cs_actions); -} - -KHMEXP void KHMAPI -khui_context_release(khui_action_context * ctx) -{ -#ifdef DEBUG - assert(ctx->magic == KHUI_ACTION_CONTEXT_MAGIC); -#endif - - khuiint_context_release(ctx); - if (ctx->credset) { - kcdb_credset_unseal(ctx->credset); - kcdb_credset_delete(ctx->credset); - } - ctx->credset = NULL; - if (ctx->int_buf) - PFREE(ctx->int_buf); - ctx->int_buf = NULL; -#if 0 - if (ctx->vparam && ctx->cb_vparam > 0) { - PFREE(ctx->vparam); - ctx->vparam = NULL; - } - ctx->cb_vparam = 0; -#else - ctx->vparam = 0; - ctx->cb_vparam = 0; -#endif -} - -KHMEXP void KHMAPI -khui_context_reset(void) -{ - EnterCriticalSection(&cs_actions); - - khuiint_context_release(&khui_ctx); - - khui_context_refresh(); - - LeaveCriticalSection(&cs_actions); -} - -KHMEXP khm_int32 KHMAPI -khui_context_cursor_filter(khm_handle cred, - khm_int32 flags, - void * rock) { - khui_action_context * ctx = (khui_action_context *) rock; - khm_int32 rv; - - if (ctx->scope == KHUI_SCOPE_NONE) - return 0; - else if (ctx->scope == KHUI_SCOPE_IDENT) { - khm_handle c_ident; - - if (KHM_FAILED(kcdb_cred_get_identity(cred, &c_ident))) - return 0; - - rv = (c_ident == ctx->identity); - - kcdb_identity_release(c_ident); - - return rv; - } else if (ctx->scope == KHUI_SCOPE_CREDTYPE) { - khm_handle c_ident; - khm_int32 c_type; - - if (KHM_FAILED(kcdb_cred_get_type(cred, &c_type)) || - c_type != ctx->cred_type) - return 0; - - if (ctx->identity == NULL) - return 1; - - if (KHM_FAILED(kcdb_cred_get_identity(cred, &c_ident))) - return 0; - - rv = (c_ident == ctx->identity); - - kcdb_identity_release(c_ident); - - return rv; - } else if (ctx->scope == KHUI_SCOPE_CRED) { - return kcdb_creds_is_equal(cred, ctx->cred); - } else if (ctx->scope == KHUI_SCOPE_GROUP) { - int i; - - rv = 1; - - for (i=0; i < (int) ctx->n_headers && rv; i++) { - kcdb_attrib * pattr; - kcdb_type * ptype; - DWORD buffer[1024]; /* 4096 bytes */ - khm_size cb; - - if (kcdb_cred_get_attr(cred, ctx->headers[i].attr_id, - NULL, - NULL, - &cb) != KHM_ERROR_TOO_LONG) { - /* the header doesn't exist anyway */ - rv = (ctx->headers[i].cb_data == 0); - continue; - } -#ifdef DEBUG - assert(cb <= sizeof(buffer)); -#endif - cb = sizeof(buffer); - - if (KHM_FAILED(kcdb_cred_get_attr(cred, - ctx->headers[i].attr_id, - NULL, - (void *) buffer, - &cb))) { - rv = 0; - continue; - } - - if (KHM_FAILED(kcdb_attrib_get_info(ctx->headers[i].attr_id, - &pattr))) { - rv = 0; - continue; - } - - if (KHM_FAILED(kcdb_type_get_info(pattr->type, &ptype))) { - rv = 0; - kcdb_attrib_release_info(pattr); - continue; - } - - if ((*ptype->comp)(ctx->headers[i].data, - ctx->headers[i].cb_data, - (void *) buffer, - cb) != 0) - rv = 1; - - kcdb_type_release_info(ptype); - kcdb_attrib_release_info(pattr); - } - - return rv; - } else - return 0; -} +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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$ */ + +#define NOEXPORT +#include +#include +#include +#include + +#include + +khui_action_ref khui_main_menu[] = { + 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() +}; + +khui_action_ref khui_menu_file[] = { + MENU_ACTION(KHUI_ACTION_PROPERTIES), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_EXIT), + MENU_END() +}; + +khui_action_ref khui_menu_cred[] = { + MENU_ACTION(KHUI_ACTION_NEW_CRED), + MENU_SEP(), + MENU_SUBMENU(KHUI_MENU_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_IMPORT), + MENU_SUBMENU(KHUI_MENU_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() +}; + +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() +}; + +khui_action_ref khui_menu_toolbars[] = { + MENU_ACTION(KHUI_ACTION_TB_STANDARD), + MENU_END() +}; + +khui_action_ref khui_menu_view[] = { + MENU_ACTION(KHUI_ACTION_LAYOUT_MINI), + 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() +}; + +khui_action_ref khui_menu_options[] = { + MENU_ACTION(KHUI_ACTION_OPT_KHIM), + MENU_ACTION(KHUI_ACTION_OPT_APPEAR), + MENU_ACTION(KHUI_ACTION_OPT_IDENTS), + MENU_ACTION(KHUI_ACTION_OPT_NOTIF), + MENU_ACTION(KHUI_ACTION_OPT_PLUGINS), + MENU_SEP(), + MENU_END() +}; + +khui_action_ref khui_menu_help[] = { + MENU_ACTION(KHUI_ACTION_HELP_CTX), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_HELP_INDEX), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_HELP_ABOUT), + MENU_END() +}; + +khui_action_ref khui_toolbar_standard[] = { + MENU_ACTION(KHUI_ACTION_NEW_CRED), + MENU_SUBMENU(KHUI_ACTION_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_IMPORT), + MENU_SUBMENU(KHUI_ACTION_DESTROY_CRED), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_PASSWD_ID), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_VIEW_REFRESH), + MENU_ACTION(KHUI_PACTION_BLANK), + MENU_ACTION(KHUI_ACTION_HELP_CTX), + MENU_END() +}; + +khui_action_ref khui_menu_ident_ctx[] = { + MENU_ACTION(KHUI_ACTION_PROPERTIES), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_SET_DEF_ID), + MENU_ACTION(KHUI_ACTION_SET_SRCH_ID), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_NEW_CRED), + MENU_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_DESTROY_CRED), + MENU_END() +}; + +khui_action_ref khui_menu_tok_ctx[] = { + MENU_ACTION(KHUI_ACTION_PROPERTIES), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_NEW_CRED), + MENU_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_DESTROY_CRED), + MENU_END() +}; + +khui_action_ref khui_menu_ico_ctx_min[] = { + MENU_DEFACTION(KHUI_ACTION_OPEN_APP), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_NEW_CRED), + MENU_SUBMENU(KHUI_MENU_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_IMPORT), + MENU_SUBMENU(KHUI_MENU_DESTROY_CRED), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_PASSWD_ID), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_HELP_CTX), + MENU_ACTION(KHUI_ACTION_HELP_ABOUT), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_EXIT), + MENU_END() +}; + +khui_action_ref khui_menu_ico_ctx_normal[] = { + MENU_DEFACTION(KHUI_ACTION_CLOSE_APP), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_NEW_CRED), + MENU_SUBMENU(KHUI_MENU_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_IMPORT), + MENU_SUBMENU(KHUI_MENU_DESTROY_CRED), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_PASSWD_ID), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_HELP_CTX), + MENU_ACTION(KHUI_ACTION_HELP_ABOUT), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_EXIT), + 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_menu_destroy_cred[] = { + MENU_DEFACTION(KHUI_ACTION_DESTROY_ALL), + MENU_END() +}; + +khui_action_ref khui_menu_renew_cred[] = { + MENU_DEFACTION(KHUI_ACTION_RENEW_ALL), + MENU_END() +}; + +khui_action_ref khui_pmenu_tok_sel[] = { + MENU_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_DESTROY_CRED), + MENU_END() +}; + +khui_action_ref khui_pmenu_id_sel[] = { + MENU_ACTION(KHUI_ACTION_DESTROY_CRED), + MENU_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_END() +}; + +/* all stock menus and toolbars */ +khui_menu_def khui_all_menus[] = { + 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), + CONSTMENU(KHUI_MENU_RENEW_CRED, KHUI_MENUSTATE_CONSTANT | KHUI_MENUSTATE_SYSTEM, khui_menu_renew_cred), + CONSTMENU(KHUI_MENU_DESTROY_CRED, KHUI_MENUSTATE_CONSTANT | KHUI_MENUSTATE_SYSTEM, khui_menu_destroy_cred), + + /* toolbars */ + 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), + CONSTMENU(KHUI_PMENU_ID_SEL, KHUI_MENUSTATE_CONSTANT, khui_pmenu_id_sel) +}; + +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); +} + +KHMEXP void KHMAPI +khui_exit_actions(void) { + DeleteCriticalSection(&cs_actions); +} + +KHMEXP void KHMAPI +khui_refresh_actions(void) { + kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); +} + +KHMEXP void KHMAPI +khui_action_lock(void) { + EnterCriticalSection(&cs_actions); +} + +KHMEXP void KHMAPI +khui_action_unlock(void) { + LeaveCriticalSection(&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 ((name && FAILED(StringCchLength(name, KHUI_MAXCCH_NAME, &s))) || + !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; + void * data; + + EnterCriticalSection(&cs_actions); + act = khui_find_action(action); + if (act == NULL || (act->state & KHUI_ACTIONSTATE_DELETED)) + data = NULL; + else + data = act->data; + LeaveCriticalSection(&cs_actions); + + return data; +} + +KHMEXP void KHMAPI +khui_action_delete(khm_int32 action) { + khui_action * act; + + EnterCriticalSection(&cs_actions); + + act = khui_find_action(action); + + if (act == NULL) { + LeaveCriticalSection(&cs_actions); + 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. */ + 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(khm_int32 action) +{ + khui_menu_def * d; + + d = PMALLOC(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + + d->cmd = action; + d->nc_items = MENU_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) +{ + khui_menu_def * d; + size_t i; + size_t n; + + EnterCriticalSection(&cs_actions); + + d = khui_menu_create(src->cmd); + + 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_insert_paction(d, -1, src->items[i].p_action, src->items[i].flags); + } else { + khui_menu_insert_action(d, -1, src->items[i].action, 0); + } + } + + LeaveCriticalSection(&cs_actions); + + return d; +} + +KHMEXP void KHMAPI +khui_menu_delete(khui_menu_def * d) +{ + int i; + + /* non-allocated menus are assumed to have no pointers to other + allocated blocks */ + 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; + } + } + + for(i=0; i< (int) d->n_items; i++) { + if(d->items[i].flags & KHUI_ACTIONREF_FREE_PACTION) + PFREE(d->items[i].p_action); + } + + if(d->items) + PFREE(d->items); + PFREE(d); + + LeaveCriticalSection(&cs_actions); +} + +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; + + d->nc_items = UBOUNDSS(n, MENU_NC_ITEMS, MENU_NC_ITEMS); + ni = PMALLOC(sizeof(*(d->items)) * d->nc_items); + memcpy(ni, d->items, sizeof(*(d->items)) * d->n_items); + PFREE(d->items); + d->items = ni; + } +} + +static void +menu_const_to_allocd(khui_menu_def * d) +{ + 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_insert_action(khui_menu_def * d, khm_size idx, khm_int32 action, khm_int32 flags) +{ + khm_size i; + + EnterCriticalSection(&cs_actions); + + 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++; + + /* only one action is allowed to have the KHUI_ACTIONREF_DEFAULT + flag */ + if (flags & KHUI_ACTIONREF_DEFAULT) { + for (i=0; i < d->n_items; i++) { + if (i != idx && (d->items[i].flags & KHUI_ACTIONREF_DEFAULT)) + d->items[i].flags &= ~KHUI_ACTIONREF_DEFAULT; + } + } + + LeaveCriticalSection(&cs_actions); +} + +KHMEXP void KHMAPI +khui_menu_insert_paction(khui_menu_def * d, khm_size idx, khui_action * paction, int flags) +{ + khm_size i; + + if (paction == NULL) + return; + + EnterCriticalSection(&cs_actions); + + 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++; + + /* only one action is allowed to have the KHUI_ACTIONREF_DEFAULT + flag */ + if (flags & KHUI_ACTIONREF_DEFAULT) { + for (i=0; i < d->n_items; i++) { + if (i != idx && (d->items[i].flags & KHUI_ACTIONREF_DEFAULT)) + d->items[i].flags &= ~KHUI_ACTIONREF_DEFAULT; + } + } + + LeaveCriticalSection(&cs_actions); +} + +KHMEXP void KHMAPI +khui_menu_remove_action(khui_menu_def * d, khm_size idx) { + + EnterCriticalSection(&cs_actions); + + if (!(d->state & KHUI_MENUSTATE_ALLOCD)) + menu_const_to_allocd(d); + + assert(d->state & KHUI_MENUSTATE_ALLOCD); + + if (idx >= 0 && idx < d->n_items) { + + 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--; + + } + + LeaveCriticalSection(&cs_actions); +} + +KHMEXP khm_size KHMAPI +khui_menu_get_size(khui_menu_def * d) { + + khm_size size; + + EnterCriticalSection(&cs_actions); + + if (d->state & KHUI_MENUSTATE_ALLOCD) + size = d->n_items; + else + size = khui_action_list_length(d->items); + + LeaveCriticalSection(&cs_actions); + + return size; +} + +KHMEXP khui_action_ref * +khui_menu_get_action(khui_menu_def * d, khm_size idx) { + + khui_action_ref * act = NULL; + khm_size n; + + EnterCriticalSection(&cs_actions); + + if (d->state & KHUI_MENUSTATE_ALLOCD) + n = d->n_items; + else + n = khui_action_list_length(d->items); + + if (idx < 0 || idx >= n) + act = NULL; + else + act = &d->items[idx]; + + LeaveCriticalSection(&cs_actions); + + return act; +} + +KHMEXP khui_menu_def * KHMAPI +khui_find_menu(khm_int32 id) { + khui_menu_def * d; + int i; + + if (id < KHUI_USERACTION_BASE) { + + /* the list of system menus are considered immutable. */ + + 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(khm_int32 id) { + khui_action * act; + int i; + + act = khui_actions; + for(i=0;i= 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(const wchar_t * name) { + int i; + khui_action * act; + khui_action ** pact; + + if(!name) + return NULL; + + act = khui_actions; + for(i=0;iname) + continue; + + if(!wcscmp(pact[i]->name, name)) { + + if (!(pact[i]->state & KHUI_ACTIONSTATE_DELETED)) { + act = pact[i]; + } + break; + } + } + + LeaveCriticalSection(&cs_actions); + + return act; +} + +KHMEXP size_t KHMAPI +khui_action_list_length(khui_action_ref * ref) { + size_t c = 0; + + EnterCriticalSection(&cs_actions); + + while(ref && ref->action != KHUI_MENU_END && + !(ref->flags & KHUI_ACTIONREF_END)) { + c++; + ref++; + } + + LeaveCriticalSection(&cs_actions); + + return c; +} + +KHMEXP void KHMAPI +khui_check_radio_action(khui_menu_def * d, khm_int32 cmd) +{ + khui_action_ref * r; + khui_action * act; + + EnterCriticalSection(&cs_actions); + + r = d->items; + 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 { + act = khui_find_action(r->action); + } + + if(act) { + if(act->cmd == cmd) + act->state |= KHUI_ACTIONSTATE_CHECKED; + else + act->state &= ~KHUI_ACTIONSTATE_CHECKED; + } + r++; + } + + LeaveCriticalSection(&cs_actions); + + kmq_post_message(KMSG_ACT, KMSG_ACT_CHECK, 0, 0); +} + +KHMEXP void KHMAPI +khui_check_action(khm_int32 cmd, khm_boolean check) { + khui_action * act; + + act = khui_find_action(cmd); + if (!act) + return; + + EnterCriticalSection(&cs_actions); + + if (check && !(act->state & KHUI_ACTIONSTATE_CHECKED)) + act->state |= KHUI_ACTIONSTATE_CHECKED; + else if (!check && (act->state & KHUI_ACTIONSTATE_CHECKED)) + act->state &= ~KHUI_ACTIONSTATE_CHECKED; + else { + LeaveCriticalSection(&cs_actions); + return; + } + + LeaveCriticalSection(&cs_actions); + + kmq_post_message(KMSG_ACT, KMSG_ACT_CHECK, 0, 0); +} + +KHMEXP void KHMAPI +khui_enable_actions(khui_menu_def * d, khm_boolean enable) +{ + khui_action_ref * r; + int delta = FALSE; + khui_action * act; + + EnterCriticalSection(&cs_actions); + + r = d->items; + 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 { + act = khui_find_action(r->action); + } + + if(act) { + int old_state = act->state; + + if(enable) + act->state &= ~KHUI_ACTIONSTATE_DISABLED; + else + act->state |= KHUI_ACTIONSTATE_DISABLED; + + if(old_state != act->state) + delta = TRUE; + } + r++; + } + + LeaveCriticalSection(&cs_actions); + + if(delta) { + kmq_post_message(KMSG_ACT, KMSG_ACT_ENABLE, 0, 0); + } +} + +KHMEXP void KHMAPI +khui_enable_action(khm_int32 cmd, khm_boolean enable) { + khui_action * act; + + act = khui_find_action(cmd); + if (!act) + return; + + EnterCriticalSection(&cs_actions); + + if (enable && (act->state & KHUI_ACTIONSTATE_DISABLED)) { + act->state &= ~KHUI_ACTIONSTATE_DISABLED; + } else if (!enable && !(act->state & KHUI_ACTIONSTATE_DISABLED)) { + act->state |= KHUI_ACTIONSTATE_DISABLED; + } else { + LeaveCriticalSection(&cs_actions); + return; + } + + LeaveCriticalSection(&cs_actions); + + kmq_post_message(KMSG_ACT, KMSG_ACT_ENABLE, 0, 0); +} + +KHMEXP HACCEL KHMAPI +khui_create_global_accel_table(void) { + int i; + ACCEL * accels; + HACCEL ha; + + accels = PMALLOC(sizeof(ACCEL) * khui_n_accel_global); + for(i=0;imod & FALT) { + if(FAILED(StringCbCat(buf, bufsiz, L"Alt+"))) + return FALSE; + } + + + if(def->mod & FCONTROL) { + if(FAILED(StringCbCat(buf, bufsiz, L"Ctrl+"))) + return FALSE; + } + + if(def->mod & FSHIFT) { + if(FAILED(StringCbCat(buf, bufsiz, L"Shift+"))) + return FALSE; + } + + if(def->mod & FVIRTKEY) { + wchar_t mbuf[6]; + wchar_t * ap = NULL; + switch(def->key) { + case VK_TAB: + ap = L"Tab"; + break; + + case VK_ESCAPE: + ap = L"Esc"; + break; + + case VK_RETURN: + 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_F11: + ap = L"F11"; + break; + + case VK_F12: + ap = L"F12"; + break; + + case VK_DELETE: + ap = L"Del"; + break; + + default: + if((def->key >= '0' && + def->key <= '9') || + (def->key >= 'A' && + def->key <= 'Z')) { + ap = mbuf; + mbuf[0] = (wchar_t) def->key; + mbuf[1] = L'\0'; + } + } + if(ap) { + if(FAILED(StringCbCat(buf, bufsiz, ap))) + return FALSE; + } + else { + if(FAILED(StringCbCat(buf, bufsiz,L"???"))) + return FALSE; + } + + } else { + wchar_t mbuf[2]; + + mbuf[0] = def->key; + mbuf[1] = L'\0'; + + if(FAILED(StringCbCat(buf, bufsiz, mbuf))) + return FALSE; + } + + return TRUE; +} + +/******************************************/ +/* contexts */ + +#define KHUI_ACTION_CONTEXT_MAGIC 0x39c49db5 + +static khm_int32 KHMAPI +khuiint_filter_selected(khm_handle cred, + khm_int32 vflags, + void * rock) { + khm_int32 flags; + if (KHM_SUCCEEDED(kcdb_cred_get_flags(cred, &flags)) && + (flags & KCDB_CRED_FLAG_SELECTED)) + return TRUE; + else + return FALSE; +} + +static void +khuiint_context_release(khui_action_context * ctx) { + ctx->scope = KHUI_SCOPE_NONE; + if (ctx->identity) + kcdb_identity_release(ctx->identity); + ctx->identity = NULL; + ctx->cred_type = KCDB_CREDTYPE_INVALID; + if (ctx->cred) + kcdb_cred_release(ctx->cred); + ctx->cred = NULL; + ctx->n_headers = 0; + if (ctx->credset) + kcdb_credset_flush(ctx->credset); + ctx->n_sel_creds = 0; + ctx->int_cb_used = 0; + ctx->vparam = NULL; + ctx->cb_vparam = 0; +} + +static void +khuiint_copy_context(khui_action_context * ctxdest, + const khui_action_context * ctxsrc) +{ + ctxdest->scope = ctxsrc->scope; + + if (ctxsrc->scope == KHUI_SCOPE_IDENT) { + ctxdest->identity = ctxsrc->identity; + kcdb_identity_hold(ctxsrc->identity); + } else if (ctxsrc->scope == KHUI_SCOPE_CREDTYPE) { + ctxdest->identity = ctxsrc->identity; + ctxdest->cred_type = ctxsrc->cred_type; + if (ctxsrc->identity != NULL) + kcdb_identity_hold(ctxsrc->identity); + } else if (ctxsrc->scope == KHUI_SCOPE_CRED) { + kcdb_cred_get_identity(ctxsrc->cred, &ctxdest->identity); + kcdb_cred_get_type(ctxsrc->cred, &ctxdest->cred_type); + ctxdest->cred = ctxsrc->cred; + kcdb_cred_hold(ctxsrc->cred); + } else if (ctxsrc->scope == KHUI_SCOPE_GROUP) { + khm_size cb_total; + int i; + + ctxdest->n_headers = ctxsrc->n_headers; + cb_total = 0; + for (i=0; i < (int) ctxsrc->n_headers; i++) { + cb_total += UBOUND32(ctxsrc->headers[i].cb_data); + } + + if (ctxdest->int_cb_buf < cb_total) { + + if (ctxdest->int_buf) + PFREE(ctxdest->int_buf); + + ctxdest->int_cb_buf = cb_total; + ctxdest->int_buf = PMALLOC(cb_total); + } + +#ifdef DEBUG + assert(ctxdest->int_buf || cb_total == 0); +#endif + ctxdest->int_cb_used = 0; + + for (i=0; i < (int) ctxsrc->n_headers; i++) { + ctxdest->headers[i].attr_id = ctxsrc->headers[i].attr_id; + ctxdest->headers[i].cb_data = ctxsrc->headers[i].cb_data; + if (ctxsrc->headers[i].cb_data > 0) { + ctxdest->headers[i].data = + BYTEOFFSET(ctxdest->int_buf, + ctxdest->int_cb_used); + memcpy(ctxdest->headers[i].data, + ctxsrc->headers[i].data, + ctxsrc->headers[i].cb_data); + ctxdest->int_cb_used += + UBOUND32(ctxsrc->headers[i].cb_data); + } else { + ctxdest->headers[i].data = NULL; + } + } + } + + if (ctxsrc->credset) { + + if (ctxdest->credset == NULL) + kcdb_credset_create(&ctxdest->credset); +#ifdef DEBUG + assert(ctxdest->credset != NULL); +#endif + + kcdb_credset_flush(ctxdest->credset); + + kcdb_credset_extract_filtered(ctxdest->credset, + ctxsrc->credset, + khuiint_filter_selected, + NULL); + + kcdb_credset_get_size(ctxdest->credset, + &ctxdest->n_sel_creds); + } else { + if (ctxdest->credset != NULL) + kcdb_credset_flush(ctxdest->credset); + ctxdest->n_sel_creds = 0; + } + + /* For now, we simply transfer the vparam buffer into the new + context. If we are copying, we also need to modify + khui_context_release() to free the allocated buffer */ +#if 0 + if (ctxsrc->vparam && ctxsrc->cb_vparam) { + ctxdest->vparam = PMALLOC(ctxsrc->cb_vparam); +#ifdef DEBUG + assert(ctxdest->vparam); +#endif + memcpy(ctxdest->vparam, ctxsrc->vparam, ctxsrc->cb_vparam); + ctxdest->cb_vparam = ctxsrc->cb_vparam; + } else { +#endif + ctxdest->vparam = ctxsrc->vparam; + ctxdest->cb_vparam = ctxsrc->cb_vparam; +#if 0 + } +#endif +} + +static void +khuiint_context_init(khui_action_context * ctx) { + ctx->magic = KHUI_ACTION_CONTEXT_MAGIC; + ctx->scope = KHUI_SCOPE_NONE; + ctx->identity = NULL; + ctx->cred_type = KCDB_CREDTYPE_INVALID; + ctx->cred = NULL; + ZeroMemory(ctx->headers, sizeof(ctx->headers)); + ctx->n_headers = 0; + ctx->credset = NULL; + ctx->n_sel_creds = 0; + ctx->int_buf = NULL; + ctx->int_cb_buf = 0; + ctx->int_cb_used = 0; + ctx->vparam = NULL; + ctx->cb_vparam = 0; +} + +khui_action_context khui_ctx = { + KHUI_ACTION_CONTEXT_MAGIC, + KHUI_SCOPE_NONE, + NULL, + KCDB_CREDTYPE_INVALID, + NULL, + { + {KCDB_ATTR_INVALID,NULL,0}, + {KCDB_ATTR_INVALID,NULL,0}, + {KCDB_ATTR_INVALID,NULL,0}, + {KCDB_ATTR_INVALID,NULL,0}, + {KCDB_ATTR_INVALID,NULL,0}, + {KCDB_ATTR_INVALID,NULL,0} + }, + 0, + NULL, + 0, + NULL, + 0, + 0, + NULL, + 0}; + +khm_int32 KHMAPI +set_cred_select_flag(khm_handle cred, void * rock) { + kcdb_cred_set_flags(cred, KCDB_CRED_FLAG_SELECTED, + KCDB_CRED_FLAG_SELECTED); + return KHM_ERROR_SUCCESS; +} + +KHMEXP void KHMAPI +khui_context_create(khui_action_context * ctx, + khui_scope scope, + khm_handle identity, + khm_int32 cred_type, + khm_handle cred) +{ + khui_action_context tctx; + + khuiint_context_init(&tctx); + khuiint_context_init(ctx); + + tctx.scope = scope; + tctx.identity = identity; + tctx.cred_type = cred_type; + tctx.cred = cred; + + /* fill up the credset based on the scope */ + if (scope != KHUI_SCOPE_NONE) { + if (tctx.credset == NULL) + kcdb_credset_create(&tctx.credset); + else + kcdb_credset_flush(tctx.credset); + + if (scope == KHUI_SCOPE_IDENT) { + kcdb_credset_extract(tctx.credset, + NULL, + tctx.identity, + KCDB_CREDTYPE_INVALID); + } else if (scope == KHUI_SCOPE_CREDTYPE) { + kcdb_credset_extract(tctx.credset, + NULL, + tctx.identity, + tctx.cred_type); + } else if (scope == KHUI_SCOPE_CRED) { + khm_handle dupcred = NULL; + kcdb_cred_dup(cred, &dupcred); + + kcdb_credset_add_cred(tctx.credset, dupcred, -1); + } else { +#ifdef DEBUG + /* KHUI_SCOPE_GROUP is not used with + khui_context_create() */ + assert(FALSE); +#endif + } + + kcdb_credset_apply(tctx.credset, set_cred_select_flag, + NULL); + + kcdb_credset_seal(tctx.credset); + } + + khuiint_copy_context(ctx, &tctx); +} + +KHMEXP void KHMAPI +khui_context_set(khui_scope scope, + khm_handle identity, + khm_int32 cred_type, + khm_handle cred, + khui_header *headers, + khm_size n_headers, + khm_handle cs_src) { + + khui_context_set_ex(scope, + identity, + cred_type, + cred, + headers, + n_headers, + cs_src, + NULL, + 0); +} + +KHMEXP void KHMAPI +khui_context_set_ex(khui_scope scope, + khm_handle identity, + khm_int32 cred_type, + khm_handle cred, + khui_header *headers, + khm_size n_headers, + khm_handle cs_src, + void * vparam, + khm_size cb_vparam) +{ + khui_action_context tctx; + + EnterCriticalSection(&cs_actions); + + khuiint_context_release(&khui_ctx); + + khuiint_context_init(&tctx); + + tctx.scope = scope; + tctx.identity = identity; + tctx.cred_type = cred_type; + tctx.cred = cred; + if (headers) { + tctx.n_headers = n_headers; + memcpy(tctx.headers, + headers, + sizeof(*headers) * n_headers); + } else { + tctx.n_headers = 0; + } + tctx.credset = cs_src; + tctx.n_sel_creds = 0; /* ignored */ + tctx.vparam = vparam; + tctx.cb_vparam = cb_vparam; + tctx.int_buf = NULL; + tctx.int_cb_buf = 0; + tctx.int_cb_used = 0; + + khuiint_copy_context(&khui_ctx, &tctx); + + khui_context_refresh(); + + 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; + + EnterCriticalSection(&cs_actions); + if (khui_ctx.identity) { + /* an identity is selected */ + + if (KHM_SUCCEEDED(kcdb_identity_get_flags(khui_ctx.identity, + &flags)) && + (flags & KCDB_IDENT_FLAG_DEFAULT)) { + khui_check_action(KHUI_ACTION_SET_DEF_ID, TRUE); + khui_enable_action(KHUI_ACTION_SET_DEF_ID, FALSE); + } else { + khui_check_action(KHUI_ACTION_SET_DEF_ID, FALSE); + khui_enable_action(KHUI_ACTION_SET_DEF_ID, TRUE); + } + } else { + khui_check_action(KHUI_ACTION_SET_DEF_ID, FALSE); + khui_enable_action(KHUI_ACTION_SET_DEF_ID, FALSE); + } + + if (khui_ctx.scope != KHUI_SCOPE_NONE) { + khui_enable_action(KHUI_ACTION_PROPERTIES, TRUE); + } else { + khui_enable_action(KHUI_ACTION_PROPERTIES, FALSE); + } + + LeaveCriticalSection(&cs_actions); + + kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); +} + +KHMEXP void KHMAPI +khui_context_get(khui_action_context * ctx) +{ + EnterCriticalSection(&cs_actions); + + khuiint_context_init(ctx); + khuiint_copy_context(ctx, &khui_ctx); + + if (ctx->credset) { + kcdb_credset_seal(ctx->credset); + } + + LeaveCriticalSection(&cs_actions); +} + +KHMEXP void KHMAPI +khui_context_release(khui_action_context * ctx) +{ +#ifdef DEBUG + assert(ctx->magic == KHUI_ACTION_CONTEXT_MAGIC); +#endif + + khuiint_context_release(ctx); + if (ctx->credset) { + kcdb_credset_unseal(ctx->credset); + kcdb_credset_delete(ctx->credset); + } + ctx->credset = NULL; + if (ctx->int_buf) + PFREE(ctx->int_buf); + ctx->int_buf = NULL; +#if 0 + if (ctx->vparam && ctx->cb_vparam > 0) { + PFREE(ctx->vparam); + ctx->vparam = NULL; + } + ctx->cb_vparam = 0; +#else + ctx->vparam = 0; + ctx->cb_vparam = 0; +#endif +} + +KHMEXP void KHMAPI +khui_context_reset(void) +{ + EnterCriticalSection(&cs_actions); + + khuiint_context_release(&khui_ctx); + + khui_context_refresh(); + + LeaveCriticalSection(&cs_actions); +} + +KHMEXP khm_int32 KHMAPI +khui_context_cursor_filter(khm_handle cred, + khm_int32 flags, + void * rock) { + khui_action_context * ctx = (khui_action_context *) rock; + khm_int32 rv; + + if (ctx->scope == KHUI_SCOPE_NONE) + return 0; + else if (ctx->scope == KHUI_SCOPE_IDENT) { + khm_handle c_ident; + + if (KHM_FAILED(kcdb_cred_get_identity(cred, &c_ident))) + return 0; + + rv = (c_ident == ctx->identity); + + kcdb_identity_release(c_ident); + + return rv; + } else if (ctx->scope == KHUI_SCOPE_CREDTYPE) { + khm_handle c_ident; + khm_int32 c_type; + + if (KHM_FAILED(kcdb_cred_get_type(cred, &c_type)) || + c_type != ctx->cred_type) + return 0; + + if (ctx->identity == NULL) + return 1; + + if (KHM_FAILED(kcdb_cred_get_identity(cred, &c_ident))) + return 0; + + rv = (c_ident == ctx->identity); + + kcdb_identity_release(c_ident); + + return rv; + } else if (ctx->scope == KHUI_SCOPE_CRED) { + return kcdb_creds_is_equal(cred, ctx->cred); + } else if (ctx->scope == KHUI_SCOPE_GROUP) { + int i; + + rv = 1; + + for (i=0; i < (int) ctx->n_headers && rv; i++) { + kcdb_attrib * pattr; + kcdb_type * ptype; + DWORD buffer[1024]; /* 4096 bytes */ + khm_size cb; + + if (kcdb_cred_get_attr(cred, ctx->headers[i].attr_id, + NULL, + NULL, + &cb) != KHM_ERROR_TOO_LONG) { + /* the header doesn't exist anyway */ + rv = (ctx->headers[i].cb_data == 0); + continue; + } +#ifdef DEBUG + assert(cb <= sizeof(buffer)); +#endif + cb = sizeof(buffer); + + if (KHM_FAILED(kcdb_cred_get_attr(cred, + ctx->headers[i].attr_id, + NULL, + (void *) buffer, + &cb))) { + rv = 0; + continue; + } + + if (KHM_FAILED(kcdb_attrib_get_info(ctx->headers[i].attr_id, + &pattr))) { + rv = 0; + continue; + } + + if (KHM_FAILED(kcdb_type_get_info(pattr->type, &ptype))) { + rv = 0; + kcdb_attrib_release_info(pattr); + continue; + } + + if ((*ptype->comp)(ctx->headers[i].data, + ctx->headers[i].cb_data, + (void *) buffer, + cb) != 0) + rv = 1; + + kcdb_type_release_info(ptype); + kcdb_attrib_release_info(pattr); + } + + return rv; + } else + return 0; +} diff --git a/src/windows/identity/uilib/alert.c b/src/windows/identity/uilib/alert.c index e398690e9..376eab6e1 100644 --- a/src/windows/identity/uilib/alert.c +++ b/src/windows/identity/uilib/alert.c @@ -1,437 +1,437 @@ -/* - * 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 - -/*********************************************************************** - Alerter -***********************************************************************/ - -khui_alert * kh_alerts = NULL; -CRITICAL_SECTION cs_alerts; - -void -alert_init(void) -{ - InitializeCriticalSection(&cs_alerts); -} - -void -alert_exit(void) -{ - DeleteCriticalSection(&cs_alerts); -} - -KHMEXP khm_int32 KHMAPI -khui_alert_create_empty(khui_alert ** result) -{ - khui_alert * a; - - a = PMALLOC(sizeof(*a)); - ZeroMemory(a, sizeof(*a)); - - a->magic = KHUI_ALERT_MAGIC; - - /* set defaults */ - a->severity = KHERR_INFO; - a->flags = KHUI_ALERT_FLAG_FREE_STRUCT; - a->alert_type = KHUI_ALERTTYPE_NONE; - khui_context_create(&a->ctx, KHUI_SCOPE_NONE, - NULL, KCDB_CREDTYPE_INVALID, - NULL); - - khui_alert_hold(a); - EnterCriticalSection(&cs_alerts); - LPUSH(&kh_alerts, a); - LeaveCriticalSection(&cs_alerts); - - *result = a; - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_alert_create_simple(const wchar_t * title, - const wchar_t * message, - khm_int32 severity, - khui_alert ** result) -{ - khui_alert * a; - - khui_alert_create_empty(&a); - khui_alert_set_title(a, title); - khui_alert_set_message(a, message); - khui_alert_set_severity(a, severity); - - *result = a; - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_alert_set_title(khui_alert * alert, const wchar_t * title) -{ - size_t cb = 0; - - assert(alert->magic == KHUI_ALERT_MAGIC); - - if(title) { - if(FAILED(StringCbLength(title, - KHUI_MAXCB_TITLE, - &cb))) { - return KHM_ERROR_INVALID_PARAM; - } - cb += sizeof(wchar_t); - } - - EnterCriticalSection(&cs_alerts); - if(alert->title && (alert->flags & KHUI_ALERT_FLAG_FREE_TITLE)) { - PFREE(alert->title); - alert->title = NULL; - alert->flags &= ~KHUI_ALERT_FLAG_FREE_TITLE; - } - if(title) { - alert->title = PMALLOC(cb); - StringCbCopy(alert->title, cb, title); - alert->flags |= KHUI_ALERT_FLAG_FREE_TITLE; - } - LeaveCriticalSection(&cs_alerts); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_alert_set_flags(khui_alert * alert, khm_int32 mask, khm_int32 flags) -{ - assert(alert->magic == KHUI_ALERT_MAGIC); - - if (mask & ~KHUI_ALERT_FLAGMASK_RDWR) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_alerts); - alert->flags = - (alert->flags & ~mask) | - (flags & mask); - LeaveCriticalSection(&cs_alerts); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_alert_set_severity(khui_alert * alert, khm_int32 severity) -{ - - assert(alert->magic == KHUI_ALERT_MAGIC); - - EnterCriticalSection(&cs_alerts); - alert->severity = severity; - LeaveCriticalSection(&cs_alerts); - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_alert_set_suggestion(khui_alert * alert, - const wchar_t * suggestion) { - size_t cb = 0; - - assert(alert->magic == KHUI_ALERT_MAGIC); - - if(suggestion) { - if(FAILED(StringCbLength(suggestion, - KHUI_MAXCB_MESSAGE - sizeof(wchar_t), - &cb))) { - return KHM_ERROR_INVALID_PARAM; - } - cb += sizeof(wchar_t); - } - - EnterCriticalSection(&cs_alerts); - if(alert->suggestion && - (alert->flags & KHUI_ALERT_FLAG_FREE_SUGGEST)) { - - PFREE(alert->suggestion); - alert->suggestion = NULL; - alert->flags &= ~KHUI_ALERT_FLAG_FREE_SUGGEST; - - } - - if(suggestion) { - alert->suggestion = PMALLOC(cb); - StringCbCopy(alert->suggestion, cb, suggestion); - alert->flags |= KHUI_ALERT_FLAG_FREE_SUGGEST; - } - LeaveCriticalSection(&cs_alerts); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_alert_set_message(khui_alert * alert, const wchar_t * message) -{ - size_t cb = 0; - - assert(alert->magic == KHUI_ALERT_MAGIC); - - if(message) { - if(FAILED(StringCbLength(message, - KHUI_MAXCB_MESSAGE - sizeof(wchar_t), - &cb))) { - return KHM_ERROR_INVALID_PARAM; - } - cb += sizeof(wchar_t); - } - - EnterCriticalSection(&cs_alerts); - if(alert->message && - (alert->flags & KHUI_ALERT_FLAG_FREE_MESSAGE)) { - - PFREE(alert->message); - alert->flags &= ~KHUI_ALERT_FLAG_FREE_MESSAGE; - } - - alert->message = NULL; - - if(message) { - alert->message = PMALLOC(cb); - StringCbCopy(alert->message, cb, message); - alert->flags |= KHUI_ALERT_FLAG_FREE_MESSAGE; - } - LeaveCriticalSection(&cs_alerts); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_alert_clear_commands(khui_alert * alert) -{ - assert(alert->magic == KHUI_ALERT_MAGIC); - - EnterCriticalSection(&cs_alerts); - alert->n_alert_commands = 0; - LeaveCriticalSection(&cs_alerts); - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_alert_add_command(khui_alert * alert, khm_int32 command_id) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - - assert(alert->magic == KHUI_ALERT_MAGIC); - - EnterCriticalSection(&cs_alerts); - if(alert->n_alert_commands >= KHUI_MAX_ALERT_COMMANDS) - rv = KHM_ERROR_NO_RESOURCES; - else { - alert->alert_commands[alert->n_alert_commands++] = command_id; - } - LeaveCriticalSection(&cs_alerts); - - return rv; -} - -KHMEXP khm_int32 KHMAPI -khui_alert_set_type(khui_alert * alert, khui_alert_type alert_type) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - - assert(alert->magic == KHUI_ALERT_MAGIC); - - EnterCriticalSection(&cs_alerts); - alert->alert_type = alert_type; - LeaveCriticalSection(&cs_alerts); - - return rv; -} - -KHMEXP khm_int32 KHMAPI -khui_alert_set_ctx(khui_alert * alert, - khui_scope scope, - khm_handle identity, - khm_int32 cred_type, - khm_handle cred) -{ - khm_int32 rv = KHM_ERROR_SUCCESS; - - assert(alert->magic == KHUI_ALERT_MAGIC); - - EnterCriticalSection(&cs_alerts); - khui_context_release(&alert->ctx); - khui_context_create(&alert->ctx, - scope, - identity, - cred_type, - cred); - LeaveCriticalSection(&cs_alerts); - - return rv; -} - -KHMEXP khm_int32 KHMAPI -khui_alert_get_response(khui_alert * alert) -{ - khm_int32 response = 0; - - assert(alert->magic == KHUI_ALERT_MAGIC); - - EnterCriticalSection(&cs_alerts); - response = alert->response; - LeaveCriticalSection(&cs_alerts); - - return response; -} - -KHMEXP khm_int32 KHMAPI -khui_alert_show(khui_alert * alert) -{ - assert(alert->magic == KHUI_ALERT_MAGIC); - - khui_alert_hold(alert); - /* the alert will be released when the message is processed */ - kmq_post_message(KMSG_ALERT, KMSG_ALERT_SHOW, 0, (void *) 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) -{ - assert(alert->magic == KHUI_ALERT_MAGIC); - - khui_alert_hold(alert); - kmq_post_message(KMSG_ALERT, KMSG_ALERT_QUEUE, 0, (void *) alert); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_alert_show_simple(const wchar_t * title, - const wchar_t * message, - khm_int32 severity) -{ - khui_alert * a = NULL; - khm_int32 rv; - - rv = khui_alert_create_simple(title, message, severity, &a); - - if(KHM_FAILED(rv)) - return rv; - - rv = khui_alert_show(a); - - khui_alert_release(a); - - return rv; -} - -KHMEXP khm_int32 KHMAPI -khui_alert_hold(khui_alert * alert) -{ - assert(alert->magic == KHUI_ALERT_MAGIC); - - EnterCriticalSection(&cs_alerts); - alert->refcount++; - LeaveCriticalSection(&cs_alerts); - return KHM_ERROR_SUCCESS; -} - -/* called with cs_alert held */ -static void -free_alert(khui_alert * alert) -{ - assert(alert->magic == KHUI_ALERT_MAGIC); - - LDELETE(&kh_alerts, alert); - - if(alert->flags & KHUI_ALERT_FLAG_FREE_TITLE) { - assert(alert->title); - PFREE(alert->title); - alert->title = NULL; - alert->flags &= ~KHUI_ALERT_FLAG_FREE_TITLE; - } - if(alert->flags & KHUI_ALERT_FLAG_FREE_MESSAGE) { - assert(alert->message); - PFREE(alert->message); - alert->message = NULL; - alert->flags &= ~KHUI_ALERT_FLAG_FREE_MESSAGE; - } - if(alert->flags & KHUI_ALERT_FLAG_FREE_SUGGEST) { - assert(alert->suggestion); - PFREE(alert->suggestion); - alert->suggestion = NULL; - alert->flags &= ~KHUI_ALERT_FLAG_FREE_SUGGEST; - } - - khui_context_release(&alert->ctx); - - if(alert->flags & KHUI_ALERT_FLAG_FREE_STRUCT) { - alert->flags &= ~KHUI_ALERT_FLAG_FREE_STRUCT; - alert->magic = 0; - PFREE(alert); - } -} - -KHMEXP khm_int32 KHMAPI -khui_alert_release(khui_alert * alert) -{ - assert(alert->magic == KHUI_ALERT_MAGIC); - - EnterCriticalSection(&cs_alerts); - if((--(alert->refcount)) == 0) { - free_alert(alert); - } - LeaveCriticalSection(&cs_alerts); - return KHM_ERROR_SUCCESS; -} - -KHMEXP void KHMAPI khui_alert_lock(khui_alert * alert) -{ - EnterCriticalSection(&cs_alerts); -} - -KHMEXP void KHMAPI khui_alert_unlock(khui_alert * alert) -{ - LeaveCriticalSection(&cs_alerts); -} +/* + * 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 + +/*********************************************************************** + Alerter +***********************************************************************/ + +khui_alert * kh_alerts = NULL; +CRITICAL_SECTION cs_alerts; + +void +alert_init(void) +{ + InitializeCriticalSection(&cs_alerts); +} + +void +alert_exit(void) +{ + DeleteCriticalSection(&cs_alerts); +} + +KHMEXP khm_int32 KHMAPI +khui_alert_create_empty(khui_alert ** result) +{ + khui_alert * a; + + a = PMALLOC(sizeof(*a)); + ZeroMemory(a, sizeof(*a)); + + a->magic = KHUI_ALERT_MAGIC; + + /* set defaults */ + a->severity = KHERR_INFO; + a->flags = KHUI_ALERT_FLAG_FREE_STRUCT; + a->alert_type = KHUI_ALERTTYPE_NONE; + khui_context_create(&a->ctx, KHUI_SCOPE_NONE, + NULL, KCDB_CREDTYPE_INVALID, + NULL); + + khui_alert_hold(a); + EnterCriticalSection(&cs_alerts); + LPUSH(&kh_alerts, a); + LeaveCriticalSection(&cs_alerts); + + *result = a; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_create_simple(const wchar_t * title, + const wchar_t * message, + khm_int32 severity, + khui_alert ** result) +{ + khui_alert * a; + + khui_alert_create_empty(&a); + khui_alert_set_title(a, title); + khui_alert_set_message(a, message); + khui_alert_set_severity(a, severity); + + *result = a; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_set_title(khui_alert * alert, const wchar_t * title) +{ + size_t cb = 0; + + assert(alert->magic == KHUI_ALERT_MAGIC); + + if(title) { + if(FAILED(StringCbLength(title, + KHUI_MAXCB_TITLE, + &cb))) { + return KHM_ERROR_INVALID_PARAM; + } + cb += sizeof(wchar_t); + } + + EnterCriticalSection(&cs_alerts); + if(alert->title && (alert->flags & KHUI_ALERT_FLAG_FREE_TITLE)) { + PFREE(alert->title); + alert->title = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_TITLE; + } + if(title) { + alert->title = PMALLOC(cb); + StringCbCopy(alert->title, cb, title); + alert->flags |= KHUI_ALERT_FLAG_FREE_TITLE; + } + LeaveCriticalSection(&cs_alerts); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_set_flags(khui_alert * alert, khm_int32 mask, khm_int32 flags) +{ + assert(alert->magic == KHUI_ALERT_MAGIC); + + if (mask & ~KHUI_ALERT_FLAGMASK_RDWR) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_alerts); + alert->flags = + (alert->flags & ~mask) | + (flags & mask); + LeaveCriticalSection(&cs_alerts); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_set_severity(khui_alert * alert, khm_int32 severity) +{ + + assert(alert->magic == KHUI_ALERT_MAGIC); + + EnterCriticalSection(&cs_alerts); + alert->severity = severity; + LeaveCriticalSection(&cs_alerts); + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_set_suggestion(khui_alert * alert, + const wchar_t * suggestion) { + size_t cb = 0; + + assert(alert->magic == KHUI_ALERT_MAGIC); + + if(suggestion) { + if(FAILED(StringCbLength(suggestion, + KHUI_MAXCB_MESSAGE - sizeof(wchar_t), + &cb))) { + return KHM_ERROR_INVALID_PARAM; + } + cb += sizeof(wchar_t); + } + + EnterCriticalSection(&cs_alerts); + if(alert->suggestion && + (alert->flags & KHUI_ALERT_FLAG_FREE_SUGGEST)) { + + PFREE(alert->suggestion); + alert->suggestion = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_SUGGEST; + + } + + if(suggestion) { + alert->suggestion = PMALLOC(cb); + StringCbCopy(alert->suggestion, cb, suggestion); + alert->flags |= KHUI_ALERT_FLAG_FREE_SUGGEST; + } + LeaveCriticalSection(&cs_alerts); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_set_message(khui_alert * alert, const wchar_t * message) +{ + size_t cb = 0; + + assert(alert->magic == KHUI_ALERT_MAGIC); + + if(message) { + if(FAILED(StringCbLength(message, + KHUI_MAXCB_MESSAGE - sizeof(wchar_t), + &cb))) { + return KHM_ERROR_INVALID_PARAM; + } + cb += sizeof(wchar_t); + } + + EnterCriticalSection(&cs_alerts); + if(alert->message && + (alert->flags & KHUI_ALERT_FLAG_FREE_MESSAGE)) { + + PFREE(alert->message); + alert->flags &= ~KHUI_ALERT_FLAG_FREE_MESSAGE; + } + + alert->message = NULL; + + if(message) { + alert->message = PMALLOC(cb); + StringCbCopy(alert->message, cb, message); + alert->flags |= KHUI_ALERT_FLAG_FREE_MESSAGE; + } + LeaveCriticalSection(&cs_alerts); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_clear_commands(khui_alert * alert) +{ + assert(alert->magic == KHUI_ALERT_MAGIC); + + EnterCriticalSection(&cs_alerts); + alert->n_alert_commands = 0; + LeaveCriticalSection(&cs_alerts); + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_add_command(khui_alert * alert, khm_int32 command_id) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + assert(alert->magic == KHUI_ALERT_MAGIC); + + EnterCriticalSection(&cs_alerts); + if(alert->n_alert_commands >= KHUI_MAX_ALERT_COMMANDS) + rv = KHM_ERROR_NO_RESOURCES; + else { + alert->alert_commands[alert->n_alert_commands++] = command_id; + } + LeaveCriticalSection(&cs_alerts); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_set_type(khui_alert * alert, khui_alert_type alert_type) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + assert(alert->magic == KHUI_ALERT_MAGIC); + + EnterCriticalSection(&cs_alerts); + alert->alert_type = alert_type; + LeaveCriticalSection(&cs_alerts); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_set_ctx(khui_alert * alert, + khui_scope scope, + khm_handle identity, + khm_int32 cred_type, + khm_handle cred) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + assert(alert->magic == KHUI_ALERT_MAGIC); + + EnterCriticalSection(&cs_alerts); + khui_context_release(&alert->ctx); + khui_context_create(&alert->ctx, + scope, + identity, + cred_type, + cred); + LeaveCriticalSection(&cs_alerts); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_get_response(khui_alert * alert) +{ + khm_int32 response = 0; + + assert(alert->magic == KHUI_ALERT_MAGIC); + + EnterCriticalSection(&cs_alerts); + response = alert->response; + LeaveCriticalSection(&cs_alerts); + + return response; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_show(khui_alert * alert) +{ + assert(alert->magic == KHUI_ALERT_MAGIC); + + khui_alert_hold(alert); + /* the alert will be released when the message is processed */ + kmq_post_message(KMSG_ALERT, KMSG_ALERT_SHOW, 0, (void *) 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) +{ + assert(alert->magic == KHUI_ALERT_MAGIC); + + khui_alert_hold(alert); + kmq_post_message(KMSG_ALERT, KMSG_ALERT_QUEUE, 0, (void *) alert); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_show_simple(const wchar_t * title, + const wchar_t * message, + khm_int32 severity) +{ + khui_alert * a = NULL; + khm_int32 rv; + + rv = khui_alert_create_simple(title, message, severity, &a); + + if(KHM_FAILED(rv)) + return rv; + + rv = khui_alert_show(a); + + khui_alert_release(a); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_hold(khui_alert * alert) +{ + assert(alert->magic == KHUI_ALERT_MAGIC); + + EnterCriticalSection(&cs_alerts); + alert->refcount++; + LeaveCriticalSection(&cs_alerts); + return KHM_ERROR_SUCCESS; +} + +/* called with cs_alert held */ +static void +free_alert(khui_alert * alert) +{ + assert(alert->magic == KHUI_ALERT_MAGIC); + + LDELETE(&kh_alerts, alert); + + if(alert->flags & KHUI_ALERT_FLAG_FREE_TITLE) { + assert(alert->title); + PFREE(alert->title); + alert->title = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_TITLE; + } + if(alert->flags & KHUI_ALERT_FLAG_FREE_MESSAGE) { + assert(alert->message); + PFREE(alert->message); + alert->message = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_MESSAGE; + } + if(alert->flags & KHUI_ALERT_FLAG_FREE_SUGGEST) { + assert(alert->suggestion); + PFREE(alert->suggestion); + alert->suggestion = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_SUGGEST; + } + + khui_context_release(&alert->ctx); + + if(alert->flags & KHUI_ALERT_FLAG_FREE_STRUCT) { + alert->flags &= ~KHUI_ALERT_FLAG_FREE_STRUCT; + alert->magic = 0; + PFREE(alert); + } +} + +KHMEXP khm_int32 KHMAPI +khui_alert_release(khui_alert * alert) +{ + assert(alert->magic == KHUI_ALERT_MAGIC); + + EnterCriticalSection(&cs_alerts); + if((--(alert->refcount)) == 0) { + free_alert(alert); + } + LeaveCriticalSection(&cs_alerts); + return KHM_ERROR_SUCCESS; +} + +KHMEXP void KHMAPI khui_alert_lock(khui_alert * alert) +{ + EnterCriticalSection(&cs_alerts); +} + +KHMEXP void KHMAPI khui_alert_unlock(khui_alert * alert) +{ + LeaveCriticalSection(&cs_alerts); +} diff --git a/src/windows/identity/uilib/configui.c b/src/windows/identity/uilib/configui.c index c8c61f5cb..3de2573ea 100644 --- a/src/windows/identity/uilib/configui.c +++ b/src/windows/identity/uilib/configui.c @@ -1,1085 +1,1085 @@ -/* - * 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 - -#include - -khm_int32 cfgui_node_serial; -LONG init_once = 0; -CRITICAL_SECTION cs_cfgui; -khui_config_node_i * cfgui_root_config; -HWND hwnd_cfgui = NULL; - -static khui_config_node_i * -cfgui_create_new_node(void) { - khui_config_node_i * node; - - node = PMALLOC(sizeof(*node)); -#ifdef DEBUG - assert(node); -#endif - ZeroMemory(node, sizeof(*node)); - node->magic = KHUI_CONFIG_NODE_MAGIC; - - EnterCriticalSection(&cs_cfgui); - node->id = ++cfgui_node_serial; - LeaveCriticalSection(&cs_cfgui); - - return node; -} - -/* called with cs_cfgui held */ -static void -cfgui_free_node(khui_config_node_i * node) { - if (!cfgui_is_valid_node(node)) - return; - - if (node->reg.name) - PFREE((void *) node->reg.name); - - if (node->reg.short_desc) - PFREE((void *) node->reg.short_desc); - - if (node->reg.long_desc) - PFREE((void *) node->reg.long_desc); - - node->magic = 0; - - if (node->owner) - kmm_release_plugin(node->owner); - - ZeroMemory(node, sizeof(*node)); - - PFREE(node); -} - - -static void -cfgui_hold_node(khui_config_node_i * node) { - EnterCriticalSection(&cs_cfgui); - node->refcount++; - LeaveCriticalSection(&cs_cfgui); -} - - -static void -cfgui_release_node(khui_config_node_i * node) { - EnterCriticalSection(&cs_cfgui); - node->refcount--; - if (node->refcount == 0 && - (node->flags & KHUI_CN_FLAG_DELETED)) { - khui_config_node_i * parent; - parent = TPARENT(node); -#ifdef DEBUG - assert(TFIRSTCHILD(node) == NULL); - assert(parent != NULL); -#endif - TDELCHILD(parent, node); - cfgui_free_node(node); - cfgui_release_node(parent); - } - LeaveCriticalSection(&cs_cfgui); -} - -static void -cfgui_init_once(void) { - if (init_once == 0 && - InterlockedIncrement(&init_once) == 1) { - InitializeCriticalSection(&cs_cfgui); - cfgui_root_config = cfgui_create_new_node(); - cfgui_node_serial = 0; - hwnd_cfgui = NULL; - } -} - -KHMEXP khm_int32 KHMAPI -khui_cfg_register(khui_config_node vparent, - const khui_config_node_reg * reg) { - - size_t cb_name; - size_t cb_short_desc; - size_t cb_long_desc; - khui_config_node_i * node; - khui_config_node_i * parent; - khui_config_node t; - wchar_t * name; - wchar_t * short_desc; - wchar_t * long_desc; - - cfgui_init_once(); - - if (!reg || - FAILED(StringCbLength(reg->name, - KHUI_MAXCB_NAME, - &cb_name)) || - FAILED(StringCbLength(reg->short_desc, - KHUI_MAXCB_SHORT_DESC, - &cb_short_desc)) || - FAILED(StringCbLength(reg->long_desc, - KHUI_MAXCB_LONG_DESC, - &cb_long_desc)) || - (vparent && - !cfgui_is_valid_node_handle(vparent))) - return KHM_ERROR_INVALID_PARAM; - - if (KHM_SUCCEEDED(khui_cfg_open(vparent, - reg->name, - &t))) { - khui_cfg_release(t); - return KHM_ERROR_DUPLICATE; - } - - cb_name += sizeof(wchar_t); - cb_short_desc += sizeof(wchar_t); - cb_long_desc += sizeof(wchar_t); - - node = cfgui_create_new_node(); - - node->reg = *reg; - node->reg.flags &= KHUI_CNFLAGMASK_STATIC; - - name = PMALLOC(cb_name); - StringCbCopy(name, cb_name, reg->name); - short_desc = PMALLOC(cb_short_desc); - StringCbCopy(short_desc, cb_short_desc, reg->short_desc); - long_desc = PMALLOC(cb_long_desc); - StringCbCopy(long_desc, cb_long_desc, reg->long_desc); - - node->reg.name = name; - node->reg.short_desc = short_desc; - node->reg.long_desc = long_desc; - node->flags = node->reg.flags; - - if (vparent == NULL) { - parent = cfgui_root_config; - } else { - parent = cfgui_node_i_from_handle(vparent); - } - - /* 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); - - if (hwnd_cfgui) { - SendMessage(hwnd_cfgui, KHUI_WM_CFG_NOTIFY, - MAKEWPARAM(0, WMCFG_SYNC_NODE_LIST), 0); - } - - 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; -} - -KHMEXP khm_int32 KHMAPI -khui_cfg_open(khui_config_node vparent, - const wchar_t * name, - khui_config_node * result) { - khui_config_node_i * parent; - khui_config_node_i * c; - size_t sz; - - cfgui_init_once(); - - if ((vparent && - !cfgui_is_valid_node_handle(vparent)) || - FAILED(StringCbLength(name, KHUI_MAXCCH_NAME, &sz)) || - !result) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_cfgui); - if (vparent) - parent = cfgui_node_i_from_handle(vparent); - else - parent = cfgui_root_config; - - c = TFIRSTCHILD(parent); - while(c) { - if (!(c->flags & KHUI_CN_FLAG_DELETED) && - !wcscmp(c->reg.name, name)) - break; - c = LNEXT(c); - } - - if (c) { - *result = cfgui_handle_from_node_i(c); - cfgui_hold_node(c); - } else { - *result = NULL; - } - LeaveCriticalSection(&cs_cfgui); - - if (*result) - return KHM_ERROR_SUCCESS; - else - return KHM_ERROR_NOT_FOUND; -} - -KHMEXP khm_int32 KHMAPI -khui_cfg_remove(khui_config_node vnode) { - khui_config_node_i * node; - if (!cfgui_is_valid_node_handle(vnode)) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_cfgui); - node = cfgui_node_i_from_handle(vnode); - node->flags |= KHUI_CN_FLAG_DELETED; - - if (hwnd_cfgui) { - SendMessage(hwnd_cfgui, KHUI_WM_CFG_NOTIFY, - MAKEWPARAM(0, WMCFG_SYNC_NODE_LIST), 0); - } - - LeaveCriticalSection(&cs_cfgui); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_cfg_hold(khui_config_node vnode) { - if (!cfgui_is_valid_node_handle(vnode)) - return KHM_ERROR_INVALID_PARAM; - - cfgui_hold_node(cfgui_node_i_from_handle(vnode)); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_cfg_release(khui_config_node vnode) { - if (!cfgui_is_valid_node_handle(vnode)) - return KHM_ERROR_INVALID_PARAM; - - cfgui_release_node(cfgui_node_i_from_handle(vnode)); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_cfg_get_parent(khui_config_node vnode, - khui_config_node * result) { - - khui_config_node_i * node; - khui_config_node_i * parent; - - if(!cfgui_is_valid_node_handle(vnode) || - !result) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode)) { - node = cfgui_node_i_from_handle(vnode); - parent = TPARENT(node); - if (parent == cfgui_root_config) - parent = NULL; - } else { - parent = NULL; - } - if (parent) { - cfgui_hold_node(parent); - } - LeaveCriticalSection(&cs_cfgui); - - *result = parent; - - if (parent) - return KHM_ERROR_SUCCESS; - else - return KHM_ERROR_NOT_FOUND; -} - -KHMEXP khm_int32 KHMAPI -khui_cfg_get_first_child(khui_config_node vparent, - khui_config_node * result) { - khui_config_node_i * parent; - khui_config_node_i * c; - - cfgui_init_once(); - - if((vparent && !cfgui_is_valid_node_handle(vparent)) || - !result) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vparent)) { - parent = cfgui_node_i_from_handle(vparent); - } else if (!vparent) { - parent = cfgui_root_config; - } else { - parent = NULL; - } - - if (parent) { - for(c = TFIRSTCHILD(parent); - c && - ((c->reg.flags & KHUI_CNFLAG_SUBPANEL) || - (c->flags & KHUI_CN_FLAG_DELETED)); - c = LNEXT(c)); - } else { - c = NULL; - } - - if (c) - cfgui_hold_node(c); - LeaveCriticalSection(&cs_cfgui); - - *result = c; - - if (c) - return KHM_ERROR_SUCCESS; - else - return KHM_ERROR_NOT_FOUND; -} - -KHMEXP khm_int32 KHMAPI -khui_cfg_get_first_subpanel(khui_config_node vparent, - khui_config_node * result) { - khui_config_node_i * parent; - khui_config_node_i * c; - - cfgui_init_once(); - - if((vparent && !cfgui_is_valid_node_handle(vparent)) || - !result) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vparent)) { - parent = cfgui_node_i_from_handle(vparent); - } else if (!vparent) { - parent = cfgui_root_config; - } else { - parent = NULL; - } - - if (parent) { - for(c = TFIRSTCHILD(parent); - c && - (!(c->reg.flags & KHUI_CNFLAG_SUBPANEL) || - (c->flags & KHUI_CN_FLAG_DELETED)); - c = LNEXT(c)); - } else { - c = NULL; - } - - if (c) - cfgui_hold_node(c); - LeaveCriticalSection(&cs_cfgui); - - *result = c; - - if (c) - return KHM_ERROR_SUCCESS; - else - return KHM_ERROR_NOT_FOUND; -} - - -KHMEXP khm_int32 KHMAPI -khui_cfg_get_next(khui_config_node vnode, - khui_config_node * result) { - - khui_config_node_i * node; - khui_config_node_i * nxt_node; - - if (!cfgui_is_valid_node_handle(vnode) || - !result) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode)) { - node = cfgui_node_i_from_handle(vnode); - for(nxt_node = LNEXT(node); - nxt_node && - ((node->reg.flags ^ nxt_node->reg.flags) & - KHUI_CNFLAG_SUBPANEL); - nxt_node = LNEXT(nxt_node)); - if (nxt_node) - cfgui_hold_node(nxt_node); - } else { - nxt_node = NULL; - } - LeaveCriticalSection(&cs_cfgui); - - *result = cfgui_handle_from_node_i(nxt_node); - - if (nxt_node) - return KHM_ERROR_SUCCESS; - else - return KHM_ERROR_NOT_FOUND; -} - -KHMEXP khm_int32 KHMAPI -khui_cfg_get_next_release(khui_config_node * pvnode) { - - khui_config_node_i * node; - khui_config_node_i * nxt_node; - - if (!pvnode || - !cfgui_is_valid_node_handle(*pvnode)) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(*pvnode)) { - node = cfgui_node_i_from_handle(*pvnode); - for(nxt_node = LNEXT(node); - nxt_node && - (((node->reg.flags ^ nxt_node->reg.flags) & - KHUI_CNFLAG_SUBPANEL) || - (nxt_node->flags & KHUI_CN_FLAG_DELETED)); - nxt_node = LNEXT(nxt_node)); - if (nxt_node) - cfgui_hold_node(nxt_node); - cfgui_release_node(node); - } else { - nxt_node = NULL; - } - LeaveCriticalSection(&cs_cfgui); - - *pvnode = cfgui_handle_from_node_i(nxt_node); - - if (nxt_node) - return KHM_ERROR_SUCCESS; - else - return KHM_ERROR_NOT_FOUND; -} - -KHMEXP khm_int32 KHMAPI -khui_cfg_get_reg(khui_config_node vnode, - khui_config_node_reg * reg) { - - khui_config_node_i * node; - - cfgui_init_once(); - - if ((vnode && !cfgui_is_valid_node_handle(vnode)) || - !reg) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode)) { - node = cfgui_node_i_from_handle(vnode); - *reg = node->reg; - } else if (!vnode) { - node = cfgui_root_config; - *reg = node->reg; - } else { - node = NULL; - ZeroMemory(reg, sizeof(*reg)); - } - LeaveCriticalSection(&cs_cfgui); - - if (node) - return KHM_ERROR_SUCCESS; - else - return KHM_ERROR_INVALID_PARAM; -} - -KHMEXP HWND KHMAPI -khui_cfg_get_hwnd(khui_config_node vnode) { - khui_config_node_i * node; - HWND hwnd; - - cfgui_init_once(); - - if (vnode && - !cfgui_is_valid_node_handle(vnode)) - return NULL; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode)) - node = cfgui_node_i_from_handle(vnode); - else if (!vnode) - node = cfgui_root_config; - else - node = NULL; - - if (node) - hwnd = node->hwnd; - else - hwnd = NULL; - LeaveCriticalSection(&cs_cfgui); - - return hwnd; -} - -KHMEXP LPARAM KHMAPI -khui_cfg_get_param(khui_config_node vnode) { - khui_config_node_i * node; - LPARAM param; - - cfgui_init_once(); - - if (vnode && - !cfgui_is_valid_node_handle(vnode)) - return 0; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode)) - node = cfgui_node_i_from_handle(vnode); - else if (!vnode) - node = cfgui_root_config; - else - node = NULL; - - if (node) - param = node->param; - else - param = 0; - LeaveCriticalSection(&cs_cfgui); - - return param; -} - -KHMEXP void KHMAPI -khui_cfg_set_hwnd(khui_config_node vnode, HWND hwnd) { - khui_config_node_i * node; - - cfgui_init_once(); - - if (vnode && - !cfgui_is_valid_node_handle(vnode)) - return; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode)) - node = cfgui_node_i_from_handle(vnode); - else if (!vnode) - node = cfgui_root_config; - else - node = NULL; - - if (node) - node->hwnd = hwnd; - LeaveCriticalSection(&cs_cfgui); -} - -KHMEXP void KHMAPI -khui_cfg_set_param(khui_config_node vnode, LPARAM param) { - khui_config_node_i * node; - - cfgui_init_once(); - - if (vnode && - !cfgui_is_valid_node_handle(vnode)) - return; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode)) - node = cfgui_node_i_from_handle(vnode); - else if (!vnode) - node = cfgui_root_config; - else - node = NULL; - - if (node) - node->param = 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, - khm_boolean create) { - khm_size i; - - for (i=0; in_data; i++) { - if (node->data[i].key == key) - return &(node->data[i]); - } - - if (!create) - return NULL; - - if (node->n_data + 1 > node->nc_data) { - cfg_node_data * newdata; - - node->nc_data = UBOUNDSS((node->n_data + 1), - KHUI_NODEDATA_ALLOC_INCR, - KHUI_NODEDATA_ALLOC_INCR); -#ifdef DEBUG - assert(node->nc_data >= node->n_data + 1); -#endif - newdata = PMALLOC(sizeof(*newdata) * node->nc_data); -#ifdef DEBUG - assert(newdata); -#endif - ZeroMemory(newdata, sizeof(*newdata) * node->nc_data); - - if (node->data && node->n_data > 0) { - memcpy(newdata, node->data, node->n_data * sizeof(*newdata)); - PFREE(node->data); - } - node->data = newdata; - } - - 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]); -} - -KHMEXP HWND KHMAPI -khui_cfg_get_hwnd_inst(khui_config_node vnode, - khui_config_node noderef) { - khui_config_node_i * node; - cfg_node_data * data; - HWND hwnd; - - cfgui_init_once(); - - if (vnode && - !cfgui_is_valid_node_handle(vnode)) - return NULL; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode)) - node = cfgui_node_i_from_handle(vnode); - else if (!vnode) - node = cfgui_root_config; - else - node = NULL; - - if (node) { - data = get_node_data(node, noderef, FALSE); - if (data) - hwnd = data->hwnd; - else - hwnd = NULL; - } else - hwnd = NULL; - LeaveCriticalSection(&cs_cfgui); - - return hwnd; -} - -KHMEXP LPARAM KHMAPI -khui_cfg_get_param_inst(khui_config_node vnode, - khui_config_node noderef) { - khui_config_node_i * node; - cfg_node_data * data; - LPARAM lParam; - - cfgui_init_once(); - - if (vnode && - !cfgui_is_valid_node_handle(vnode)) - return 0; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode)) - node = cfgui_node_i_from_handle(vnode); - else if (!vnode) - node = cfgui_root_config; - else - node = NULL; - - if (node) { - data = get_node_data(node, noderef, FALSE); - if (data) - lParam = data->param; - else - lParam = 0; - } else - lParam = 0; - LeaveCriticalSection(&cs_cfgui); - - return lParam; -} - -KHMEXP void KHMAPI -khui_cfg_set_hwnd_inst(khui_config_node vnode, - khui_config_node noderef, - HWND hwnd) { - khui_config_node_i * node; - cfg_node_data * data; - - cfgui_init_once(); - - if (vnode && - !cfgui_is_valid_node_handle(vnode)) - return; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode)) - node = cfgui_node_i_from_handle(vnode); - else if (!vnode) - node = cfgui_root_config; - else - node = NULL; - - if (node) { - data = get_node_data(node, noderef, TRUE); - if (data) - data->hwnd = hwnd; - } - LeaveCriticalSection(&cs_cfgui); -} - -KHMEXP void KHMAPI -khui_cfg_set_param_inst(khui_config_node vnode, - khui_config_node noderef, - LPARAM param) { - khui_config_node_i * node; - cfg_node_data * data; - - cfgui_init_once(); - - if (vnode && - !cfgui_is_valid_node_handle(vnode)) - return; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode)) - node = cfgui_node_i_from_handle(vnode); - else if (!vnode) - node = cfgui_root_config; - else - node = NULL; - - if (node) { - data = get_node_data(node, noderef, TRUE); - if (data) - data->param = param; - } - LeaveCriticalSection(&cs_cfgui); -} - - -/* called with cs_cfgui held */ -static void -cfgui_clear_params(khui_config_node_i * node) { - khui_config_node_i * c; - - node->hwnd = NULL; - node->param = 0; - node->flags &= KHUI_CNFLAGMASK_STATIC; - clear_node_data(node); - - c = TFIRSTCHILD(node); - while(c) { - cfgui_clear_params(c); - c = LNEXT(c); - } -} - -KHMEXP void KHMAPI -khui_cfg_clear_params(void) { - - cfgui_init_once(); - - EnterCriticalSection(&cs_cfgui); - cfgui_clear_params(cfgui_root_config); - LeaveCriticalSection(&cs_cfgui); -} - -KHMEXP void KHMAPI -khui_cfg_set_configui_handle(HWND hwnd) { - EnterCriticalSection(&cs_cfgui); - hwnd_cfgui = hwnd; - LeaveCriticalSection(&cs_cfgui); -} - -KHMEXP void KHMAPI -khui_cfg_set_flags(khui_config_node vnode, - khm_int32 flags, - khm_int32 mask) { - khui_config_node_i * node; - khm_int32 newflags; - - if (vnode && - !cfgui_is_valid_node_handle(vnode)) - return; - - mask &= KHUI_CNFLAGMASK_DYNAMIC; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode)) { - - node = cfgui_node_i_from_handle(vnode); - - newflags = - (flags & mask) | - (node->flags & ~mask); - - if (newflags != node->flags) { - node->flags = newflags; - - if (hwnd_cfgui) - PostMessage(hwnd_cfgui, KHUI_WM_CFG_NOTIFY, - MAKEWPARAM((WORD)newflags, WMCFG_UPDATE_STATE), - (LPARAM) vnode); - } - } - LeaveCriticalSection(&cs_cfgui); -} - -/* called with cs_cfgui held */ -static void -recalc_node_flags(khui_config_node vnode, khm_boolean plural) { - khui_config_node_i * node; - khui_config_node_i * parent; - khui_config_node_i * subpanel; - cfg_node_data * data; - khm_int32 flags; - -#ifdef DEBUG - assert(cfgui_is_valid_node_handle(vnode)); -#endif - - node = cfgui_node_i_from_handle(vnode); - - if (plural) - parent = TPARENT(node); - else - parent = node; -#ifdef DEBUG - assert(parent); -#endif - - flags = 0; - - for(subpanel = TFIRSTCHILD(parent); subpanel; - subpanel = LNEXT(subpanel)) { - if (!(subpanel->reg.flags & KHUI_CNFLAG_SUBPANEL) || - (plural && !(subpanel->reg.flags & KHUI_CNFLAG_PLURAL)) || - (!plural && (subpanel->reg.flags & KHUI_CNFLAG_PLURAL))) - continue; - - data = get_node_data(subpanel, - vnode, - FALSE); - - if (data) { - flags |= data->flags; - } - } - - flags &= KHUI_CNFLAGMASK_DYNAMIC; - - if ((node->flags & KHUI_CNFLAGMASK_DYNAMIC) == flags) - return; - - node->flags = (node->flags & ~KHUI_CNFLAGMASK_DYNAMIC) | flags; - - if (hwnd_cfgui) - PostMessage(hwnd_cfgui, KHUI_WM_CFG_NOTIFY, - MAKEWPARAM((WORD) node->flags, WMCFG_UPDATE_STATE), - (LPARAM) vnode); -} - -KHMEXP void KHMAPI -khui_cfg_set_flags_inst(khui_config_init_data * d, - khm_int32 flags, - khm_int32 mask) { - khui_config_node_i * node; - cfg_node_data * data; - - cfgui_init_once(); - if (!cfgui_is_valid_node_handle(d->this_node)) - return; - - mask &= KHUI_CNFLAGMASK_DYNAMIC; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(d->this_node)) - node = cfgui_node_i_from_handle(d->this_node); - else - node = NULL; - - if (node) { - data = get_node_data(node, d->ctx_node, TRUE); - if (data) { - khm_int32 new_flags; - - new_flags = (flags & mask) | - (data->flags & ~mask); - - if (new_flags != data->flags) { - data->flags = new_flags; - - if (d->ctx_node != d->ref_node) - recalc_node_flags(d->ctx_node, TRUE); - else - recalc_node_flags(d->ctx_node, FALSE); - } - } - } - LeaveCriticalSection(&cs_cfgui); -} - -KHMEXP khm_int32 KHMAPI -khui_cfg_get_flags(khui_config_node vnode) { - khui_config_node_i * node; - khm_int32 flags = 0; - - if (vnode && - !cfgui_is_valid_node_handle(vnode)) - return 0; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode)) { - - node = cfgui_node_i_from_handle(vnode); - - flags = node->flags; - } - LeaveCriticalSection(&cs_cfgui); - - return flags; -} - -KHMEXP khm_int32 KHMAPI -khui_cfg_get_name(khui_config_node vnode, - wchar_t * buf, - khm_size * cb_buf) { - khui_config_node_i * node; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if (!cb_buf || - !cfgui_is_valid_node_handle(vnode)) - return KHM_ERROR_INVALID_PARAM; - - EnterCriticalSection(&cs_cfgui); - if (cfgui_is_valid_node_handle(vnode)) { - khm_size cb; - - node = cfgui_node_i_from_handle(vnode); - - StringCbLength(node->reg.name, KHUI_MAXCCH_NAME, &cb); - - if (buf == NULL || cb > *cb_buf) { - *cb_buf = cb; - rv = KHM_ERROR_TOO_LONG; - } else { - StringCbCopy(buf, *cb_buf, node->reg.name); - *cb_buf = cb; - } - } else { - rv = KHM_ERROR_INVALID_PARAM; - } - LeaveCriticalSection(&cs_cfgui); - - return rv; -} - -KHMEXP khm_int32 KHMAPI -khui_cfg_init_dialog_data(HWND hwnd_dlg, - const khui_config_init_data * data, - khm_size cb_extra, - khui_config_init_data ** new_data, - void ** extra) { - khm_size cb; - khui_config_init_data * d; - - cb = sizeof(khui_config_init_data) + cb_extra; - d = PMALLOC(cb); -#ifdef DEBUG - assert(d); -#endif - ZeroMemory(d, cb); - - *d = *data; - - if (d->ctx_node) - khui_cfg_hold(d->ctx_node); - if (d->this_node) - khui_cfg_hold(d->this_node); - if (d->ref_node) - khui_cfg_hold(d->ref_node); - -#pragma warning(push) -#pragma warning(disable: 4244) - SetWindowLongPtr(hwnd_dlg, DWLP_USER, (LONG_PTR) d); -#pragma warning(pop) - - if (new_data) - *new_data = d; - if (extra) - *extra = (void *) (d + 1); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_cfg_get_dialog_data(HWND hwnd_dlg, - khui_config_init_data ** data, - void ** extra) { - khui_config_init_data * d; - - d = (khui_config_init_data *) (LONG_PTR) GetWindowLongPtr(hwnd_dlg, - DWLP_USER); -#ifdef DEBUG - assert(d); -#endif - - *data = d; - if (extra) - *extra = (void *) (d + 1); - - return (d)?KHM_ERROR_SUCCESS: KHM_ERROR_NOT_FOUND; -} - -KHMEXP khm_int32 KHMAPI -khui_cfg_free_dialog_data(HWND hwnd_dlg) { - khui_config_init_data * d; - - d = (khui_config_init_data *) (LONG_PTR) GetWindowLongPtr(hwnd_dlg, - DWLP_USER); -#ifdef DEBUG - assert(d); -#endif - - if (d) { - PFREE(d); - } - - return (d)?KHM_ERROR_SUCCESS: KHM_ERROR_NOT_FOUND; -} +/* + * 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 + +#include + +khm_int32 cfgui_node_serial; +LONG init_once = 0; +CRITICAL_SECTION cs_cfgui; +khui_config_node_i * cfgui_root_config; +HWND hwnd_cfgui = NULL; + +static khui_config_node_i * +cfgui_create_new_node(void) { + khui_config_node_i * node; + + node = PMALLOC(sizeof(*node)); +#ifdef DEBUG + assert(node); +#endif + ZeroMemory(node, sizeof(*node)); + node->magic = KHUI_CONFIG_NODE_MAGIC; + + EnterCriticalSection(&cs_cfgui); + node->id = ++cfgui_node_serial; + LeaveCriticalSection(&cs_cfgui); + + return node; +} + +/* called with cs_cfgui held */ +static void +cfgui_free_node(khui_config_node_i * node) { + if (!cfgui_is_valid_node(node)) + return; + + if (node->reg.name) + PFREE((void *) node->reg.name); + + if (node->reg.short_desc) + PFREE((void *) node->reg.short_desc); + + if (node->reg.long_desc) + PFREE((void *) node->reg.long_desc); + + node->magic = 0; + + if (node->owner) + kmm_release_plugin(node->owner); + + ZeroMemory(node, sizeof(*node)); + + PFREE(node); +} + + +static void +cfgui_hold_node(khui_config_node_i * node) { + EnterCriticalSection(&cs_cfgui); + node->refcount++; + LeaveCriticalSection(&cs_cfgui); +} + + +static void +cfgui_release_node(khui_config_node_i * node) { + EnterCriticalSection(&cs_cfgui); + node->refcount--; + if (node->refcount == 0 && + (node->flags & KHUI_CN_FLAG_DELETED)) { + khui_config_node_i * parent; + parent = TPARENT(node); +#ifdef DEBUG + assert(TFIRSTCHILD(node) == NULL); + assert(parent != NULL); +#endif + TDELCHILD(parent, node); + cfgui_free_node(node); + cfgui_release_node(parent); + } + LeaveCriticalSection(&cs_cfgui); +} + +static void +cfgui_init_once(void) { + if (init_once == 0 && + InterlockedIncrement(&init_once) == 1) { + InitializeCriticalSection(&cs_cfgui); + cfgui_root_config = cfgui_create_new_node(); + cfgui_node_serial = 0; + hwnd_cfgui = NULL; + } +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_register(khui_config_node vparent, + const khui_config_node_reg * reg) { + + size_t cb_name; + size_t cb_short_desc; + size_t cb_long_desc; + khui_config_node_i * node; + khui_config_node_i * parent; + khui_config_node t; + wchar_t * name; + wchar_t * short_desc; + wchar_t * long_desc; + + cfgui_init_once(); + + if (!reg || + FAILED(StringCbLength(reg->name, + KHUI_MAXCB_NAME, + &cb_name)) || + FAILED(StringCbLength(reg->short_desc, + KHUI_MAXCB_SHORT_DESC, + &cb_short_desc)) || + FAILED(StringCbLength(reg->long_desc, + KHUI_MAXCB_LONG_DESC, + &cb_long_desc)) || + (vparent && + !cfgui_is_valid_node_handle(vparent))) + return KHM_ERROR_INVALID_PARAM; + + if (KHM_SUCCEEDED(khui_cfg_open(vparent, + reg->name, + &t))) { + khui_cfg_release(t); + return KHM_ERROR_DUPLICATE; + } + + cb_name += sizeof(wchar_t); + cb_short_desc += sizeof(wchar_t); + cb_long_desc += sizeof(wchar_t); + + node = cfgui_create_new_node(); + + node->reg = *reg; + node->reg.flags &= KHUI_CNFLAGMASK_STATIC; + + name = PMALLOC(cb_name); + StringCbCopy(name, cb_name, reg->name); + short_desc = PMALLOC(cb_short_desc); + StringCbCopy(short_desc, cb_short_desc, reg->short_desc); + long_desc = PMALLOC(cb_long_desc); + StringCbCopy(long_desc, cb_long_desc, reg->long_desc); + + node->reg.name = name; + node->reg.short_desc = short_desc; + node->reg.long_desc = long_desc; + node->flags = node->reg.flags; + + if (vparent == NULL) { + parent = cfgui_root_config; + } else { + parent = cfgui_node_i_from_handle(vparent); + } + + /* 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); + + if (hwnd_cfgui) { + SendMessage(hwnd_cfgui, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(0, WMCFG_SYNC_NODE_LIST), 0); + } + + 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; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_open(khui_config_node vparent, + const wchar_t * name, + khui_config_node * result) { + khui_config_node_i * parent; + khui_config_node_i * c; + size_t sz; + + cfgui_init_once(); + + if ((vparent && + !cfgui_is_valid_node_handle(vparent)) || + FAILED(StringCbLength(name, KHUI_MAXCCH_NAME, &sz)) || + !result) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + if (vparent) + parent = cfgui_node_i_from_handle(vparent); + else + parent = cfgui_root_config; + + c = TFIRSTCHILD(parent); + while(c) { + if (!(c->flags & KHUI_CN_FLAG_DELETED) && + !wcscmp(c->reg.name, name)) + break; + c = LNEXT(c); + } + + if (c) { + *result = cfgui_handle_from_node_i(c); + cfgui_hold_node(c); + } else { + *result = NULL; + } + LeaveCriticalSection(&cs_cfgui); + + if (*result) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_remove(khui_config_node vnode) { + khui_config_node_i * node; + if (!cfgui_is_valid_node_handle(vnode)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + node = cfgui_node_i_from_handle(vnode); + node->flags |= KHUI_CN_FLAG_DELETED; + + if (hwnd_cfgui) { + SendMessage(hwnd_cfgui, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(0, WMCFG_SYNC_NODE_LIST), 0); + } + + LeaveCriticalSection(&cs_cfgui); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_hold(khui_config_node vnode) { + if (!cfgui_is_valid_node_handle(vnode)) + return KHM_ERROR_INVALID_PARAM; + + cfgui_hold_node(cfgui_node_i_from_handle(vnode)); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_release(khui_config_node vnode) { + if (!cfgui_is_valid_node_handle(vnode)) + return KHM_ERROR_INVALID_PARAM; + + cfgui_release_node(cfgui_node_i_from_handle(vnode)); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_parent(khui_config_node vnode, + khui_config_node * result) { + + khui_config_node_i * node; + khui_config_node_i * parent; + + if(!cfgui_is_valid_node_handle(vnode) || + !result) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) { + node = cfgui_node_i_from_handle(vnode); + parent = TPARENT(node); + if (parent == cfgui_root_config) + parent = NULL; + } else { + parent = NULL; + } + if (parent) { + cfgui_hold_node(parent); + } + LeaveCriticalSection(&cs_cfgui); + + *result = parent; + + if (parent) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_first_child(khui_config_node vparent, + khui_config_node * result) { + khui_config_node_i * parent; + khui_config_node_i * c; + + cfgui_init_once(); + + if((vparent && !cfgui_is_valid_node_handle(vparent)) || + !result) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vparent)) { + parent = cfgui_node_i_from_handle(vparent); + } else if (!vparent) { + parent = cfgui_root_config; + } else { + parent = NULL; + } + + if (parent) { + for(c = TFIRSTCHILD(parent); + c && + ((c->reg.flags & KHUI_CNFLAG_SUBPANEL) || + (c->flags & KHUI_CN_FLAG_DELETED)); + c = LNEXT(c)); + } else { + c = NULL; + } + + if (c) + cfgui_hold_node(c); + LeaveCriticalSection(&cs_cfgui); + + *result = c; + + if (c) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_first_subpanel(khui_config_node vparent, + khui_config_node * result) { + khui_config_node_i * parent; + khui_config_node_i * c; + + cfgui_init_once(); + + if((vparent && !cfgui_is_valid_node_handle(vparent)) || + !result) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vparent)) { + parent = cfgui_node_i_from_handle(vparent); + } else if (!vparent) { + parent = cfgui_root_config; + } else { + parent = NULL; + } + + if (parent) { + for(c = TFIRSTCHILD(parent); + c && + (!(c->reg.flags & KHUI_CNFLAG_SUBPANEL) || + (c->flags & KHUI_CN_FLAG_DELETED)); + c = LNEXT(c)); + } else { + c = NULL; + } + + if (c) + cfgui_hold_node(c); + LeaveCriticalSection(&cs_cfgui); + + *result = c; + + if (c) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_next(khui_config_node vnode, + khui_config_node * result) { + + khui_config_node_i * node; + khui_config_node_i * nxt_node; + + if (!cfgui_is_valid_node_handle(vnode) || + !result) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) { + node = cfgui_node_i_from_handle(vnode); + for(nxt_node = LNEXT(node); + nxt_node && + ((node->reg.flags ^ nxt_node->reg.flags) & + KHUI_CNFLAG_SUBPANEL); + nxt_node = LNEXT(nxt_node)); + if (nxt_node) + cfgui_hold_node(nxt_node); + } else { + nxt_node = NULL; + } + LeaveCriticalSection(&cs_cfgui); + + *result = cfgui_handle_from_node_i(nxt_node); + + if (nxt_node) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_next_release(khui_config_node * pvnode) { + + khui_config_node_i * node; + khui_config_node_i * nxt_node; + + if (!pvnode || + !cfgui_is_valid_node_handle(*pvnode)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(*pvnode)) { + node = cfgui_node_i_from_handle(*pvnode); + for(nxt_node = LNEXT(node); + nxt_node && + (((node->reg.flags ^ nxt_node->reg.flags) & + KHUI_CNFLAG_SUBPANEL) || + (nxt_node->flags & KHUI_CN_FLAG_DELETED)); + nxt_node = LNEXT(nxt_node)); + if (nxt_node) + cfgui_hold_node(nxt_node); + cfgui_release_node(node); + } else { + nxt_node = NULL; + } + LeaveCriticalSection(&cs_cfgui); + + *pvnode = cfgui_handle_from_node_i(nxt_node); + + if (nxt_node) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_reg(khui_config_node vnode, + khui_config_node_reg * reg) { + + khui_config_node_i * node; + + cfgui_init_once(); + + if ((vnode && !cfgui_is_valid_node_handle(vnode)) || + !reg) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) { + node = cfgui_node_i_from_handle(vnode); + *reg = node->reg; + } else if (!vnode) { + node = cfgui_root_config; + *reg = node->reg; + } else { + node = NULL; + ZeroMemory(reg, sizeof(*reg)); + } + LeaveCriticalSection(&cs_cfgui); + + if (node) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_INVALID_PARAM; +} + +KHMEXP HWND KHMAPI +khui_cfg_get_hwnd(khui_config_node vnode) { + khui_config_node_i * node; + HWND hwnd; + + cfgui_init_once(); + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return NULL; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) + node = cfgui_node_i_from_handle(vnode); + else if (!vnode) + node = cfgui_root_config; + else + node = NULL; + + if (node) + hwnd = node->hwnd; + else + hwnd = NULL; + LeaveCriticalSection(&cs_cfgui); + + return hwnd; +} + +KHMEXP LPARAM KHMAPI +khui_cfg_get_param(khui_config_node vnode) { + khui_config_node_i * node; + LPARAM param; + + cfgui_init_once(); + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return 0; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) + node = cfgui_node_i_from_handle(vnode); + else if (!vnode) + node = cfgui_root_config; + else + node = NULL; + + if (node) + param = node->param; + else + param = 0; + LeaveCriticalSection(&cs_cfgui); + + return param; +} + +KHMEXP void KHMAPI +khui_cfg_set_hwnd(khui_config_node vnode, HWND hwnd) { + khui_config_node_i * node; + + cfgui_init_once(); + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) + node = cfgui_node_i_from_handle(vnode); + else if (!vnode) + node = cfgui_root_config; + else + node = NULL; + + if (node) + node->hwnd = hwnd; + LeaveCriticalSection(&cs_cfgui); +} + +KHMEXP void KHMAPI +khui_cfg_set_param(khui_config_node vnode, LPARAM param) { + khui_config_node_i * node; + + cfgui_init_once(); + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) + node = cfgui_node_i_from_handle(vnode); + else if (!vnode) + node = cfgui_root_config; + else + node = NULL; + + if (node) + node->param = 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, + khm_boolean create) { + khm_size i; + + for (i=0; in_data; i++) { + if (node->data[i].key == key) + return &(node->data[i]); + } + + if (!create) + return NULL; + + if (node->n_data + 1 > node->nc_data) { + cfg_node_data * newdata; + + node->nc_data = UBOUNDSS((node->n_data + 1), + KHUI_NODEDATA_ALLOC_INCR, + KHUI_NODEDATA_ALLOC_INCR); +#ifdef DEBUG + assert(node->nc_data >= node->n_data + 1); +#endif + newdata = PMALLOC(sizeof(*newdata) * node->nc_data); +#ifdef DEBUG + assert(newdata); +#endif + ZeroMemory(newdata, sizeof(*newdata) * node->nc_data); + + if (node->data && node->n_data > 0) { + memcpy(newdata, node->data, node->n_data * sizeof(*newdata)); + PFREE(node->data); + } + node->data = newdata; + } + + 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]); +} + +KHMEXP HWND KHMAPI +khui_cfg_get_hwnd_inst(khui_config_node vnode, + khui_config_node noderef) { + khui_config_node_i * node; + cfg_node_data * data; + HWND hwnd; + + cfgui_init_once(); + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return NULL; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) + node = cfgui_node_i_from_handle(vnode); + else if (!vnode) + node = cfgui_root_config; + else + node = NULL; + + if (node) { + data = get_node_data(node, noderef, FALSE); + if (data) + hwnd = data->hwnd; + else + hwnd = NULL; + } else + hwnd = NULL; + LeaveCriticalSection(&cs_cfgui); + + return hwnd; +} + +KHMEXP LPARAM KHMAPI +khui_cfg_get_param_inst(khui_config_node vnode, + khui_config_node noderef) { + khui_config_node_i * node; + cfg_node_data * data; + LPARAM lParam; + + cfgui_init_once(); + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return 0; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) + node = cfgui_node_i_from_handle(vnode); + else if (!vnode) + node = cfgui_root_config; + else + node = NULL; + + if (node) { + data = get_node_data(node, noderef, FALSE); + if (data) + lParam = data->param; + else + lParam = 0; + } else + lParam = 0; + LeaveCriticalSection(&cs_cfgui); + + return lParam; +} + +KHMEXP void KHMAPI +khui_cfg_set_hwnd_inst(khui_config_node vnode, + khui_config_node noderef, + HWND hwnd) { + khui_config_node_i * node; + cfg_node_data * data; + + cfgui_init_once(); + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) + node = cfgui_node_i_from_handle(vnode); + else if (!vnode) + node = cfgui_root_config; + else + node = NULL; + + if (node) { + data = get_node_data(node, noderef, TRUE); + if (data) + data->hwnd = hwnd; + } + LeaveCriticalSection(&cs_cfgui); +} + +KHMEXP void KHMAPI +khui_cfg_set_param_inst(khui_config_node vnode, + khui_config_node noderef, + LPARAM param) { + khui_config_node_i * node; + cfg_node_data * data; + + cfgui_init_once(); + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) + node = cfgui_node_i_from_handle(vnode); + else if (!vnode) + node = cfgui_root_config; + else + node = NULL; + + if (node) { + data = get_node_data(node, noderef, TRUE); + if (data) + data->param = param; + } + LeaveCriticalSection(&cs_cfgui); +} + + +/* called with cs_cfgui held */ +static void +cfgui_clear_params(khui_config_node_i * node) { + khui_config_node_i * c; + + node->hwnd = NULL; + node->param = 0; + node->flags &= KHUI_CNFLAGMASK_STATIC; + clear_node_data(node); + + c = TFIRSTCHILD(node); + while(c) { + cfgui_clear_params(c); + c = LNEXT(c); + } +} + +KHMEXP void KHMAPI +khui_cfg_clear_params(void) { + + cfgui_init_once(); + + EnterCriticalSection(&cs_cfgui); + cfgui_clear_params(cfgui_root_config); + LeaveCriticalSection(&cs_cfgui); +} + +KHMEXP void KHMAPI +khui_cfg_set_configui_handle(HWND hwnd) { + EnterCriticalSection(&cs_cfgui); + hwnd_cfgui = hwnd; + LeaveCriticalSection(&cs_cfgui); +} + +KHMEXP void KHMAPI +khui_cfg_set_flags(khui_config_node vnode, + khm_int32 flags, + khm_int32 mask) { + khui_config_node_i * node; + khm_int32 newflags; + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return; + + mask &= KHUI_CNFLAGMASK_DYNAMIC; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) { + + node = cfgui_node_i_from_handle(vnode); + + newflags = + (flags & mask) | + (node->flags & ~mask); + + if (newflags != node->flags) { + node->flags = newflags; + + if (hwnd_cfgui) + PostMessage(hwnd_cfgui, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM((WORD)newflags, WMCFG_UPDATE_STATE), + (LPARAM) vnode); + } + } + LeaveCriticalSection(&cs_cfgui); +} + +/* called with cs_cfgui held */ +static void +recalc_node_flags(khui_config_node vnode, khm_boolean plural) { + khui_config_node_i * node; + khui_config_node_i * parent; + khui_config_node_i * subpanel; + cfg_node_data * data; + khm_int32 flags; + +#ifdef DEBUG + assert(cfgui_is_valid_node_handle(vnode)); +#endif + + node = cfgui_node_i_from_handle(vnode); + + if (plural) + parent = TPARENT(node); + else + parent = node; +#ifdef DEBUG + assert(parent); +#endif + + flags = 0; + + for(subpanel = TFIRSTCHILD(parent); subpanel; + subpanel = LNEXT(subpanel)) { + if (!(subpanel->reg.flags & KHUI_CNFLAG_SUBPANEL) || + (plural && !(subpanel->reg.flags & KHUI_CNFLAG_PLURAL)) || + (!plural && (subpanel->reg.flags & KHUI_CNFLAG_PLURAL))) + continue; + + data = get_node_data(subpanel, + vnode, + FALSE); + + if (data) { + flags |= data->flags; + } + } + + flags &= KHUI_CNFLAGMASK_DYNAMIC; + + if ((node->flags & KHUI_CNFLAGMASK_DYNAMIC) == flags) + return; + + node->flags = (node->flags & ~KHUI_CNFLAGMASK_DYNAMIC) | flags; + + if (hwnd_cfgui) + PostMessage(hwnd_cfgui, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM((WORD) node->flags, WMCFG_UPDATE_STATE), + (LPARAM) vnode); +} + +KHMEXP void KHMAPI +khui_cfg_set_flags_inst(khui_config_init_data * d, + khm_int32 flags, + khm_int32 mask) { + khui_config_node_i * node; + cfg_node_data * data; + + cfgui_init_once(); + if (!cfgui_is_valid_node_handle(d->this_node)) + return; + + mask &= KHUI_CNFLAGMASK_DYNAMIC; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(d->this_node)) + node = cfgui_node_i_from_handle(d->this_node); + else + node = NULL; + + if (node) { + data = get_node_data(node, d->ctx_node, TRUE); + if (data) { + khm_int32 new_flags; + + new_flags = (flags & mask) | + (data->flags & ~mask); + + if (new_flags != data->flags) { + data->flags = new_flags; + + if (d->ctx_node != d->ref_node) + recalc_node_flags(d->ctx_node, TRUE); + else + recalc_node_flags(d->ctx_node, FALSE); + } + } + } + LeaveCriticalSection(&cs_cfgui); +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_flags(khui_config_node vnode) { + khui_config_node_i * node; + khm_int32 flags = 0; + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return 0; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) { + + node = cfgui_node_i_from_handle(vnode); + + flags = node->flags; + } + LeaveCriticalSection(&cs_cfgui); + + return flags; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_name(khui_config_node vnode, + wchar_t * buf, + khm_size * cb_buf) { + khui_config_node_i * node; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if (!cb_buf || + !cfgui_is_valid_node_handle(vnode)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) { + khm_size cb; + + node = cfgui_node_i_from_handle(vnode); + + StringCbLength(node->reg.name, KHUI_MAXCCH_NAME, &cb); + + if (buf == NULL || cb > *cb_buf) { + *cb_buf = cb; + rv = KHM_ERROR_TOO_LONG; + } else { + StringCbCopy(buf, *cb_buf, node->reg.name); + *cb_buf = cb; + } + } else { + rv = KHM_ERROR_INVALID_PARAM; + } + LeaveCriticalSection(&cs_cfgui); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_init_dialog_data(HWND hwnd_dlg, + const khui_config_init_data * data, + khm_size cb_extra, + khui_config_init_data ** new_data, + void ** extra) { + khm_size cb; + khui_config_init_data * d; + + cb = sizeof(khui_config_init_data) + cb_extra; + d = PMALLOC(cb); +#ifdef DEBUG + assert(d); +#endif + ZeroMemory(d, cb); + + *d = *data; + + if (d->ctx_node) + khui_cfg_hold(d->ctx_node); + if (d->this_node) + khui_cfg_hold(d->this_node); + if (d->ref_node) + khui_cfg_hold(d->ref_node); + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd_dlg, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + if (new_data) + *new_data = d; + if (extra) + *extra = (void *) (d + 1); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_dialog_data(HWND hwnd_dlg, + khui_config_init_data ** data, + void ** extra) { + khui_config_init_data * d; + + d = (khui_config_init_data *) (LONG_PTR) GetWindowLongPtr(hwnd_dlg, + DWLP_USER); +#ifdef DEBUG + assert(d); +#endif + + *data = d; + if (extra) + *extra = (void *) (d + 1); + + return (d)?KHM_ERROR_SUCCESS: KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_free_dialog_data(HWND hwnd_dlg) { + khui_config_init_data * d; + + d = (khui_config_init_data *) (LONG_PTR) GetWindowLongPtr(hwnd_dlg, + DWLP_USER); +#ifdef DEBUG + assert(d); +#endif + + if (d) { + PFREE(d); + } + + return (d)?KHM_ERROR_SUCCESS: KHM_ERROR_NOT_FOUND; +} diff --git a/src/windows/identity/uilib/configui.h b/src/windows/identity/uilib/configui.h index c7ff88bdb..bd3a13e8e 100644 --- a/src/windows/identity/uilib/configui.h +++ b/src/windows/identity/uilib/configui.h @@ -1,74 +1,74 @@ -/* - * 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_CONFIGUI_H -#define __KHIMAIRA_CONFIGUI_H - -typedef struct tag_cfg_node_data { - void * key; - HWND hwnd; - LPARAM param; - khm_int32 flags; -} cfg_node_data; - -typedef struct tag_khui_config_node_i { - khm_int32 magic; - - khui_config_node_reg reg; - kmm_plugin owner; - khm_int32 id; - - HWND hwnd; - LPARAM param; - - cfg_node_data * data; - khm_size n_data; - khm_size nc_data; - - khm_int32 refcount; - khm_int32 flags; - TDCL(struct tag_khui_config_node_i); -} khui_config_node_i; - -#define KHUI_CONFIG_NODE_MAGIC 0x38f4cb52 - -#define KHUI_NODEDATA_ALLOC_INCR 8 - -#define KHUI_CN_FLAG_DELETED 0x0008 - -#define cfgui_is_valid_node_handle(v) \ -((v) && ((khui_config_node_i *) (v))->magic == KHUI_CONFIG_NODE_MAGIC) - -#define cfgui_is_valid_node(n) \ -((n)->magic == KHUI_CONFIG_NODE_MAGIC) - -#define cfgui_node_i_from_handle(v) \ -((khui_config_node_i *) v) - -#define cfgui_handle_from_node_i(n) \ -((khui_config_node) n) - -#endif +/* + * 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_CONFIGUI_H +#define __KHIMAIRA_CONFIGUI_H + +typedef struct tag_cfg_node_data { + void * key; + HWND hwnd; + LPARAM param; + khm_int32 flags; +} cfg_node_data; + +typedef struct tag_khui_config_node_i { + khm_int32 magic; + + khui_config_node_reg reg; + kmm_plugin owner; + khm_int32 id; + + HWND hwnd; + LPARAM param; + + cfg_node_data * data; + khm_size n_data; + khm_size nc_data; + + khm_int32 refcount; + khm_int32 flags; + TDCL(struct tag_khui_config_node_i); +} khui_config_node_i; + +#define KHUI_CONFIG_NODE_MAGIC 0x38f4cb52 + +#define KHUI_NODEDATA_ALLOC_INCR 8 + +#define KHUI_CN_FLAG_DELETED 0x0008 + +#define cfgui_is_valid_node_handle(v) \ +((v) && ((khui_config_node_i *) (v))->magic == KHUI_CONFIG_NODE_MAGIC) + +#define cfgui_is_valid_node(n) \ +((n)->magic == KHUI_CONFIG_NODE_MAGIC) + +#define cfgui_node_i_from_handle(v) \ +((khui_config_node_i *) v) + +#define cfgui_handle_from_node_i(n) \ +((khui_config_node) n) + +#endif diff --git a/src/windows/identity/uilib/creddlg.c b/src/windows/identity/uilib/creddlg.c index c89a44620..08b0a149d 100644 --- a/src/windows/identity/uilib/creddlg.c +++ b/src/windows/identity/uilib/creddlg.c @@ -1,718 +1,718 @@ -/* - * 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 - -#define CW_ALLOC_INCR 8 - -static void cw_free_prompts(khui_new_creds * c); - -static void cw_free_prompt(khui_new_creds_prompt * p); - -static khui_new_creds_prompt * -cw_create_prompt( - khm_size idx, - khm_int32 type, - wchar_t * prompt, - wchar_t * def, - khm_int32 flags); - -KHMEXP khm_int32 KHMAPI -khui_cw_create_cred_blob(khui_new_creds ** ppnc) -{ - khui_new_creds * c; - - c = PMALLOC(sizeof(*c)); - ZeroMemory(c, sizeof(*c)); - - c->magic = KHUI_NC_MAGIC; - InitializeCriticalSection(&c->cs); - c->result = KHUI_NC_RESULT_CANCEL; - c->mode = KHUI_NC_MODE_MINI; - - khui_context_create(&c->ctx, KHUI_SCOPE_NONE, NULL, KCDB_CREDTYPE_INVALID, NULL); - - *ppnc = c; - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_cw_destroy_cred_blob(khui_new_creds *c) -{ - khm_size i; - size_t len; - EnterCriticalSection(&c->cs); - for(i=0;in_identities;i++) { - kcdb_identity_release(c->identities[i]); - } - cw_free_prompts(c); - khui_context_release(&c->ctx); - LeaveCriticalSection(&c->cs); - DeleteCriticalSection(&c->cs); - - if (c->password) { - len = wcslen(c->password); - SecureZeroMemory(c->password, sizeof(wchar_t) * len); - PFREE(c->password); - } - - if (c->identities) - PFREE(c->identities); - - if (c->types) - PFREE(c->types); - - if (c->type_subs) - PFREE(c->type_subs); - - if (c->window_title) - PFREE(c->window_title); - - PFREE(c); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_cw_lock_nc(khui_new_creds * c) -{ - EnterCriticalSection(&c->cs); - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_cw_unlock_nc(khui_new_creds * c) -{ - LeaveCriticalSection(&c->cs); - return KHM_ERROR_SUCCESS; -} - -#define NC_N_IDENTITIES 4 - -KHMEXP khm_int32 KHMAPI -khui_cw_add_identity(khui_new_creds * c, - khm_handle id) -{ - if(id == NULL) - return KHM_ERROR_SUCCESS; /* we return success because adding - a NULL id is equivalent to adding - nothing. */ - EnterCriticalSection(&(c->cs)); - - if(c->identities == NULL) { - c->nc_identities = NC_N_IDENTITIES; - c->identities = PMALLOC(sizeof(*(c->identities)) * - c->nc_identities); - c->n_identities = 0; - } else if(c->n_identities + 1 > c->nc_identities) { - khm_handle * ni; - - c->nc_identities = UBOUNDSS(c->n_identities + 1, - NC_N_IDENTITIES, - NC_N_IDENTITIES); - ni = PMALLOC(sizeof(*(c->identities)) * c->nc_identities); - memcpy(ni, c->identities, - sizeof(*(c->identities)) * c->n_identities); - PFREE(c->identities); - c->identities = ni; - } - - kcdb_identity_hold(id); - c->identities[c->n_identities++] = id; - LeaveCriticalSection(&(c->cs)); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_cw_set_primary_id(khui_new_creds * c, - khm_handle id) -{ - khm_size i; - khm_int32 rv; - - EnterCriticalSection(&c->cs); - - /* no change */ - if((c->n_identities > 0 && c->identities[0] == id) || - (c->n_identities == 0 && id == NULL)) { - LeaveCriticalSection(&c->cs); - return KHM_ERROR_SUCCESS; - } - - for(i=0; in_identities; i++) { - kcdb_identity_release(c->identities[i]); - } - c->n_identities = 0; - - LeaveCriticalSection(&(c->cs)); - rv = khui_cw_add_identity(c,id); - if(c->hwnd != NULL) { - PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, - MAKEWPARAM(0, WMNC_IDENTITY_CHANGE), 0); - } - return rv; -} - -KHMEXP khm_int32 KHMAPI -khui_cw_add_type(khui_new_creds * c, - khui_new_creds_by_type * t) -{ - EnterCriticalSection(&c->cs); - - if(c->n_types >= KHUI_MAX_NCTYPES) { - LeaveCriticalSection(&c->cs); - return KHM_ERROR_OUT_OF_BOUNDS; - } - - if(c->types == NULL) { - c->nc_types = CW_ALLOC_INCR; - c->types = PMALLOC(sizeof(*(c->types)) * c->nc_types); - c->type_subs = PMALLOC(sizeof(*(c->type_subs)) * c->nc_types); - c->n_types = 0; - } - - if(c->nc_types < c->n_types + 1) { - void * t; - khm_size n; - - n = UBOUNDSS(c->n_types + 1, CW_ALLOC_INCR, CW_ALLOC_INCR); - - t = PMALLOC(sizeof(*(c->types)) * n); - memcpy(t, (void *) c->types, sizeof(*(c->types)) * c->n_types); - PFREE(c->types); - c->types = t; - - t = PMALLOC(sizeof(*(c->type_subs)) * n); - memcpy(t, (void *) c->type_subs, sizeof(*(c->type_subs)) * c->n_types); - PFREE(c->type_subs); - c->type_subs = t; - - c->nc_types = n; - } - - c->type_subs[c->n_types] = kcdb_credtype_get_sub(t->type); - c->types[c->n_types++] = t; - t->nc = c; - LeaveCriticalSection(&c->cs); - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_cw_del_type(khui_new_creds * c, - khm_int32 type_id) -{ - khm_size i; - - EnterCriticalSection(&c->cs); - for(i=0; i < c->n_types; i++) { - if(c->types[i]->type == type_id) - break; - } - if(i >= c->n_types) { - LeaveCriticalSection(&c->cs); - return KHM_ERROR_NOT_FOUND; - } - c->n_types--; - for(;i < c->n_types; i++) { - c->types[i] = c->types[i+1]; - c->type_subs[i] = c->type_subs[i+1]; - } - LeaveCriticalSection(&c->cs); - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_cw_find_type(khui_new_creds * c, - khm_int32 type, - khui_new_creds_by_type **t) -{ - khm_size i; - - EnterCriticalSection(&c->cs); - *t = NULL; - for(i=0;in_types;i++) { - if(c->types[i]->type == type) { - *t = c->types[i]; - break; - } - } - LeaveCriticalSection(&c->cs); - - if(*t) - return KHM_ERROR_SUCCESS; - return KHM_ERROR_NOT_FOUND; -} - - -KHMEXP khm_int32 KHMAPI -khui_cw_enable_type(khui_new_creds * c, - khm_int32 type, - khm_boolean enable) -{ - khui_new_creds_by_type * t = NULL; - BOOL delta = FALSE; - - EnterCriticalSection(&c->cs); - if(KHM_SUCCEEDED(khui_cw_find_type(c, type, &t))) { - if(enable) { - delta = t->flags & KHUI_NCT_FLAG_DISABLED; - t->flags &= ~KHUI_NCT_FLAG_DISABLED; - } - else { - delta = !(t->flags & KHUI_NCT_FLAG_DISABLED); - t->flags |= KHUI_NCT_FLAG_DISABLED; - } - } - LeaveCriticalSection(&c->cs); - - if(delta) - PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0,WMNC_TYPE_STATE), (LPARAM) type); - - return (t)?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND; -} - -KHMEXP khm_boolean KHMAPI -khui_cw_type_succeeded(khui_new_creds * c, - khm_int32 type) -{ - khui_new_creds_by_type * t; - khm_boolean s; - - EnterCriticalSection(&c->cs); - if(KHM_SUCCEEDED(khui_cw_find_type(c, type, &t))) { - s = (t->flags & KHUI_NCT_FLAG_PROCESSED) && !(t->flags & KHUI_NC_RESPONSE_FAILED); - } else { - s = FALSE; - } - LeaveCriticalSection(&c->cs); - - return s; -} - -static khui_new_creds_prompt * -cw_create_prompt(khm_size idx, - khm_int32 type, - wchar_t * prompt, - wchar_t * def, - khm_int32 flags) -{ - khui_new_creds_prompt * p; - size_t cb_prompt = 0; - size_t cb_def = 0; - - if(prompt && FAILED(StringCbLength(prompt, KHUI_MAXCB_PROMPT, &cb_prompt))) - return NULL; - if(def && FAILED(StringCbLength(def, KHUI_MAXCB_PROMPT_VALUE, &cb_def))) - return NULL; - - p = PMALLOC(sizeof(*p)); - ZeroMemory(p, sizeof(*p)); - - if(prompt) { - cb_prompt += sizeof(wchar_t); - p->prompt = PMALLOC(cb_prompt); - StringCbCopy(p->prompt, cb_prompt, prompt); - } - - if(def && cb_def > 0) { - cb_def += sizeof(wchar_t); - p->def = PMALLOC(cb_def); - StringCbCopy(p->def, cb_def, def); - } - - p->value = PMALLOC(KHUI_MAXCB_PROMPT_VALUE); - ZeroMemory(p->value, KHUI_MAXCB_PROMPT_VALUE); - - p->type = type; - p->flags = flags; - p->index = idx; - - return p; -} - -static void -cw_free_prompt(khui_new_creds_prompt * p) { - size_t cb; - - if(p->prompt) { - if(SUCCEEDED(StringCbLength(p->prompt, KHUI_MAXCB_PROMPT, &cb))) - SecureZeroMemory(p->prompt, cb); - PFREE(p->prompt); - } - - if(p->def) { - if(SUCCEEDED(StringCbLength(p->def, KHUI_MAXCB_PROMPT, &cb))) - SecureZeroMemory(p->def, cb); - PFREE(p->def); - } - - if(p->value) { - if(SUCCEEDED(StringCbLength(p->value, KHUI_MAXCB_PROMPT_VALUE, &cb))) - SecureZeroMemory(p->value, cb); - PFREE(p->value); - } - - PFREE(p); -} - -static void -cw_free_prompts(khui_new_creds * c) -{ - khm_size i; - - if(c->banner != NULL) { - PFREE(c->banner); - c->banner = NULL; - } - - if(c->pname != NULL) { - PFREE(c->pname); - c->pname = NULL; - } - - for(i=0;i < c->n_prompts; i++) { - if(c->prompts[i]) { - cw_free_prompt(c->prompts[i]); - c->prompts[i] = NULL; - } - } - - if(c->prompts != NULL) { - PFREE(c->prompts); - c->prompts = NULL; - } - - c->nc_prompts = 0; - c->n_prompts = 0; -} - -KHMEXP khm_int32 KHMAPI -khui_cw_clear_prompts(khui_new_creds * c) -{ - /* the WMNC_CLEAR_PROMPT message needs to be sent before freeing - the prompts, because the prompts structure still holds the - window handles for the custom prompt controls. */ - SendMessage(c->hwnd, KHUI_WM_NC_NOTIFY, - MAKEWPARAM(0,WMNC_CLEAR_PROMPTS), (LPARAM) c); - - EnterCriticalSection(&c->cs); - cw_free_prompts(c); - LeaveCriticalSection(&c->cs); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_cw_begin_custom_prompts(khui_new_creds * c, - khm_size n_prompts, - wchar_t * banner, - wchar_t * pname) -{ - size_t cb; - - PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, - MAKEWPARAM(0,WMNC_CLEAR_PROMPTS), (LPARAM) c); - - EnterCriticalSection(&c->cs); -#ifdef DEBUG - assert(c->n_prompts == 0); -#endif - cw_free_prompts(c); - - if(SUCCEEDED(StringCbLength(banner, KHUI_MAXCB_BANNER, &cb)) && - cb > 0) { - cb += sizeof(wchar_t); - c->banner = PMALLOC(cb); - StringCbCopy(c->banner, cb, banner); - } else { - c->banner = NULL; - } - - if(SUCCEEDED(StringCbLength(pname, KHUI_MAXCB_PNAME, &cb)) && - cb > 0) { - - cb += sizeof(wchar_t); - c->pname = PMALLOC(cb); - StringCbCopy(c->pname, cb, pname); - - } else { - - c->pname = NULL; - - } - - if(n_prompts > 0) { - c->prompts = PMALLOC(sizeof(*(c->prompts)) * n_prompts); - ZeroMemory(c->prompts, sizeof(*(c->prompts)) * n_prompts); - c->nc_prompts = n_prompts; - c->n_prompts = 0; - - } else { - - c->prompts = NULL; - c->n_prompts = 0; - c->nc_prompts = 0; - - PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, - MAKEWPARAM(0, WMNC_SET_PROMPTS), (LPARAM) c); - } - - LeaveCriticalSection(&c->cs); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_cw_add_prompt(khui_new_creds * c, - khm_int32 type, - wchar_t * prompt, - wchar_t * def, - khm_int32 flags) -{ - khui_new_creds_prompt * p; - - if(c->nc_prompts == 0 || - c->n_prompts == c->nc_prompts) - return KHM_ERROR_INVALID_OPERATION; - -#ifdef DEBUG - assert(c->prompts != NULL); -#endif - - EnterCriticalSection(&c->cs); - p = cw_create_prompt(c->n_prompts, type, prompt, def, flags); - if(p == NULL) { - LeaveCriticalSection(&c->cs); - return KHM_ERROR_INVALID_PARAM; - } - c->prompts[c->n_prompts++] = p; - LeaveCriticalSection(&c->cs); - - if(c->n_prompts == c->nc_prompts) { - PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, - MAKEWPARAM(0, WMNC_SET_PROMPTS), (LPARAM) c); - /* once we are done adding prompts, switch to the auth - panel */ -#if 0 - /* Actually, don't. Doing so can mean an unexpected panel - switch if fiddling on some other panel causes a change in - custom prompts. */ - SendMessage(c->hwnd, KHUI_WM_NC_NOTIFY, - MAKEWPARAM(0, WMNC_DIALOG_SWITCH_PANEL), - (LPARAM) c); -#endif - } - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_cw_get_prompt_count(khui_new_creds * c, - khm_size * np) { - - EnterCriticalSection(&c->cs); - *np = c->n_prompts; - LeaveCriticalSection(&c->cs); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_cw_get_prompt(khui_new_creds * c, - khm_size idx, - khui_new_creds_prompt ** prompt) -{ - khm_int32 rv; - - EnterCriticalSection(&c->cs); - if(c->n_prompts <= idx || - c->prompts == NULL) { - - rv = KHM_ERROR_OUT_OF_BOUNDS; - *prompt = NULL; - } else { - - *prompt = c->prompts[idx]; - rv = KHM_ERROR_SUCCESS; - } - LeaveCriticalSection(&c->cs); - - return rv; -} - -void -khuiint_trim_str(wchar_t * s, khm_size cch) { - wchar_t * c, * last_ws; - - for (c = s; *c && iswspace(*c) && ((khm_size)(c - s)) < cch; c++); - - if (((khm_size)(c - s)) >= cch) - return; - - if (c != s && ((khm_size)(c - s)) < cch) { -#if _MSC_VER >= 1400 - wmemmove_s(s, cch, c, cch - ((khm_size)(c - s))); -#else - memmove(s, c, (cch - ((khm_size)(c - s)))* sizeof(wchar_t)); -#endif - } - - last_ws = NULL; - for (c = s; *c && ((khm_size)(c - s)) < cch; c++) { - if (!iswspace(*c)) - last_ws = NULL; - else if (last_ws == NULL) - last_ws = c; - } - - if (last_ws) - *last_ws = L'\0'; -} - -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); - redo_loop: - n = c->n_prompts; - for(i=0; iprompts[i]; - if(p->hwnd_edit) { - hw = p->hwnd_edit; - LeaveCriticalSection(&c->cs); - - GetWindowText(hw, tmpbuf, ARRAYLENGTH(tmpbuf)); - khuiint_trim_str(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); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_cw_get_prompt_value(khui_new_creds * c, - khm_size idx, - wchar_t * buf, - khm_size *cbbuf) -{ - khui_new_creds_prompt * p; - khm_int32 rv; - size_t cb; - - rv = khui_cw_get_prompt(c, idx, &p); - if(KHM_FAILED(rv)) - return rv; - - EnterCriticalSection(&c->cs); - - if(FAILED(StringCbLength(p->value, KHUI_MAXCB_PROMPT_VALUE, &cb))) { - *cbbuf = 0; - if(buf != NULL) - *buf = 0; - LeaveCriticalSection(&c->cs); - return KHM_ERROR_SUCCESS; - } - cb += sizeof(wchar_t); - - if(buf == NULL || *cbbuf < cb) { - *cbbuf = cb; - LeaveCriticalSection(&c->cs); - return KHM_ERROR_TOO_LONG; - } - - StringCbCopy(buf, *cbbuf, p->value); - *cbbuf = cb; - LeaveCriticalSection(&c->cs); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_cw_set_response(khui_new_creds * c, - khm_int32 type, - khm_int32 response) -{ - khui_new_creds_by_type * t = NULL; - EnterCriticalSection(&c->cs); - khui_cw_find_type(c, type, &t); - c->response |= response & KHUI_NCMASK_RESPONSE; - if(t) { - t->flags &= ~KHUI_NCMASK_RESULT; - t->flags |= (response & KHUI_NCMASK_RESULT); - - if (!(response & KHUI_NC_RESPONSE_NOEXIT) && - !(response & KHUI_NC_RESPONSE_PENDING)) - t->flags |= KHUI_NC_RESPONSE_COMPLETED; - } - LeaveCriticalSection(&c->cs); - return KHM_ERROR_SUCCESS; -} - -/* only called from a identity provider callback */ -KHMEXP khm_int32 KHMAPI -khui_cw_add_control_row(khui_new_creds * c, - HWND label, - HWND input, - khui_control_size size) -{ - if (c && c->hwnd) { - khui_control_row row; - - row.label = label; - row.input = input; - row.size = size; - - SendMessage(c->hwnd, - KHUI_WM_NC_NOTIFY, - MAKEWPARAM(0, WMNC_ADD_CONTROL_ROW), - (LPARAM) &row); - - return KHM_ERROR_SUCCESS; - } else { - return KHM_ERROR_INVALID_PARAM; - } -} +/* + * 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 + +#define CW_ALLOC_INCR 8 + +static void cw_free_prompts(khui_new_creds * c); + +static void cw_free_prompt(khui_new_creds_prompt * p); + +static khui_new_creds_prompt * +cw_create_prompt( + khm_size idx, + khm_int32 type, + wchar_t * prompt, + wchar_t * def, + khm_int32 flags); + +KHMEXP khm_int32 KHMAPI +khui_cw_create_cred_blob(khui_new_creds ** ppnc) +{ + khui_new_creds * c; + + c = PMALLOC(sizeof(*c)); + ZeroMemory(c, sizeof(*c)); + + c->magic = KHUI_NC_MAGIC; + InitializeCriticalSection(&c->cs); + c->result = KHUI_NC_RESULT_CANCEL; + c->mode = KHUI_NC_MODE_MINI; + + khui_context_create(&c->ctx, KHUI_SCOPE_NONE, NULL, KCDB_CREDTYPE_INVALID, NULL); + + *ppnc = c; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_destroy_cred_blob(khui_new_creds *c) +{ + khm_size i; + size_t len; + EnterCriticalSection(&c->cs); + for(i=0;in_identities;i++) { + kcdb_identity_release(c->identities[i]); + } + cw_free_prompts(c); + khui_context_release(&c->ctx); + LeaveCriticalSection(&c->cs); + DeleteCriticalSection(&c->cs); + + if (c->password) { + len = wcslen(c->password); + SecureZeroMemory(c->password, sizeof(wchar_t) * len); + PFREE(c->password); + } + + if (c->identities) + PFREE(c->identities); + + if (c->types) + PFREE(c->types); + + if (c->type_subs) + PFREE(c->type_subs); + + if (c->window_title) + PFREE(c->window_title); + + PFREE(c); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_lock_nc(khui_new_creds * c) +{ + EnterCriticalSection(&c->cs); + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_unlock_nc(khui_new_creds * c) +{ + LeaveCriticalSection(&c->cs); + return KHM_ERROR_SUCCESS; +} + +#define NC_N_IDENTITIES 4 + +KHMEXP khm_int32 KHMAPI +khui_cw_add_identity(khui_new_creds * c, + khm_handle id) +{ + if(id == NULL) + return KHM_ERROR_SUCCESS; /* we return success because adding + a NULL id is equivalent to adding + nothing. */ + EnterCriticalSection(&(c->cs)); + + if(c->identities == NULL) { + c->nc_identities = NC_N_IDENTITIES; + c->identities = PMALLOC(sizeof(*(c->identities)) * + c->nc_identities); + c->n_identities = 0; + } else if(c->n_identities + 1 > c->nc_identities) { + khm_handle * ni; + + c->nc_identities = UBOUNDSS(c->n_identities + 1, + NC_N_IDENTITIES, + NC_N_IDENTITIES); + ni = PMALLOC(sizeof(*(c->identities)) * c->nc_identities); + memcpy(ni, c->identities, + sizeof(*(c->identities)) * c->n_identities); + PFREE(c->identities); + c->identities = ni; + } + + kcdb_identity_hold(id); + c->identities[c->n_identities++] = id; + LeaveCriticalSection(&(c->cs)); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_set_primary_id(khui_new_creds * c, + khm_handle id) +{ + khm_size i; + khm_int32 rv; + + EnterCriticalSection(&c->cs); + + /* no change */ + if((c->n_identities > 0 && c->identities[0] == id) || + (c->n_identities == 0 && id == NULL)) { + LeaveCriticalSection(&c->cs); + return KHM_ERROR_SUCCESS; + } + + for(i=0; in_identities; i++) { + kcdb_identity_release(c->identities[i]); + } + c->n_identities = 0; + + LeaveCriticalSection(&(c->cs)); + rv = khui_cw_add_identity(c,id); + if(c->hwnd != NULL) { + PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_IDENTITY_CHANGE), 0); + } + return rv; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_add_type(khui_new_creds * c, + khui_new_creds_by_type * t) +{ + EnterCriticalSection(&c->cs); + + if(c->n_types >= KHUI_MAX_NCTYPES) { + LeaveCriticalSection(&c->cs); + return KHM_ERROR_OUT_OF_BOUNDS; + } + + if(c->types == NULL) { + c->nc_types = CW_ALLOC_INCR; + c->types = PMALLOC(sizeof(*(c->types)) * c->nc_types); + c->type_subs = PMALLOC(sizeof(*(c->type_subs)) * c->nc_types); + c->n_types = 0; + } + + if(c->nc_types < c->n_types + 1) { + void * t; + khm_size n; + + n = UBOUNDSS(c->n_types + 1, CW_ALLOC_INCR, CW_ALLOC_INCR); + + t = PMALLOC(sizeof(*(c->types)) * n); + memcpy(t, (void *) c->types, sizeof(*(c->types)) * c->n_types); + PFREE(c->types); + c->types = t; + + t = PMALLOC(sizeof(*(c->type_subs)) * n); + memcpy(t, (void *) c->type_subs, sizeof(*(c->type_subs)) * c->n_types); + PFREE(c->type_subs); + c->type_subs = t; + + c->nc_types = n; + } + + c->type_subs[c->n_types] = kcdb_credtype_get_sub(t->type); + c->types[c->n_types++] = t; + t->nc = c; + LeaveCriticalSection(&c->cs); + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_del_type(khui_new_creds * c, + khm_int32 type_id) +{ + khm_size i; + + EnterCriticalSection(&c->cs); + for(i=0; i < c->n_types; i++) { + if(c->types[i]->type == type_id) + break; + } + if(i >= c->n_types) { + LeaveCriticalSection(&c->cs); + return KHM_ERROR_NOT_FOUND; + } + c->n_types--; + for(;i < c->n_types; i++) { + c->types[i] = c->types[i+1]; + c->type_subs[i] = c->type_subs[i+1]; + } + LeaveCriticalSection(&c->cs); + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_find_type(khui_new_creds * c, + khm_int32 type, + khui_new_creds_by_type **t) +{ + khm_size i; + + EnterCriticalSection(&c->cs); + *t = NULL; + for(i=0;in_types;i++) { + if(c->types[i]->type == type) { + *t = c->types[i]; + break; + } + } + LeaveCriticalSection(&c->cs); + + if(*t) + return KHM_ERROR_SUCCESS; + return KHM_ERROR_NOT_FOUND; +} + + +KHMEXP khm_int32 KHMAPI +khui_cw_enable_type(khui_new_creds * c, + khm_int32 type, + khm_boolean enable) +{ + khui_new_creds_by_type * t = NULL; + BOOL delta = FALSE; + + EnterCriticalSection(&c->cs); + if(KHM_SUCCEEDED(khui_cw_find_type(c, type, &t))) { + if(enable) { + delta = t->flags & KHUI_NCT_FLAG_DISABLED; + t->flags &= ~KHUI_NCT_FLAG_DISABLED; + } + else { + delta = !(t->flags & KHUI_NCT_FLAG_DISABLED); + t->flags |= KHUI_NCT_FLAG_DISABLED; + } + } + LeaveCriticalSection(&c->cs); + + if(delta) + PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0,WMNC_TYPE_STATE), (LPARAM) type); + + return (t)?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_boolean KHMAPI +khui_cw_type_succeeded(khui_new_creds * c, + khm_int32 type) +{ + khui_new_creds_by_type * t; + khm_boolean s; + + EnterCriticalSection(&c->cs); + if(KHM_SUCCEEDED(khui_cw_find_type(c, type, &t))) { + s = (t->flags & KHUI_NCT_FLAG_PROCESSED) && !(t->flags & KHUI_NC_RESPONSE_FAILED); + } else { + s = FALSE; + } + LeaveCriticalSection(&c->cs); + + return s; +} + +static khui_new_creds_prompt * +cw_create_prompt(khm_size idx, + khm_int32 type, + wchar_t * prompt, + wchar_t * def, + khm_int32 flags) +{ + khui_new_creds_prompt * p; + size_t cb_prompt = 0; + size_t cb_def = 0; + + if(prompt && FAILED(StringCbLength(prompt, KHUI_MAXCB_PROMPT, &cb_prompt))) + return NULL; + if(def && FAILED(StringCbLength(def, KHUI_MAXCB_PROMPT_VALUE, &cb_def))) + return NULL; + + p = PMALLOC(sizeof(*p)); + ZeroMemory(p, sizeof(*p)); + + if(prompt) { + cb_prompt += sizeof(wchar_t); + p->prompt = PMALLOC(cb_prompt); + StringCbCopy(p->prompt, cb_prompt, prompt); + } + + if(def && cb_def > 0) { + cb_def += sizeof(wchar_t); + p->def = PMALLOC(cb_def); + StringCbCopy(p->def, cb_def, def); + } + + p->value = PMALLOC(KHUI_MAXCB_PROMPT_VALUE); + ZeroMemory(p->value, KHUI_MAXCB_PROMPT_VALUE); + + p->type = type; + p->flags = flags; + p->index = idx; + + return p; +} + +static void +cw_free_prompt(khui_new_creds_prompt * p) { + size_t cb; + + if(p->prompt) { + if(SUCCEEDED(StringCbLength(p->prompt, KHUI_MAXCB_PROMPT, &cb))) + SecureZeroMemory(p->prompt, cb); + PFREE(p->prompt); + } + + if(p->def) { + if(SUCCEEDED(StringCbLength(p->def, KHUI_MAXCB_PROMPT, &cb))) + SecureZeroMemory(p->def, cb); + PFREE(p->def); + } + + if(p->value) { + if(SUCCEEDED(StringCbLength(p->value, KHUI_MAXCB_PROMPT_VALUE, &cb))) + SecureZeroMemory(p->value, cb); + PFREE(p->value); + } + + PFREE(p); +} + +static void +cw_free_prompts(khui_new_creds * c) +{ + khm_size i; + + if(c->banner != NULL) { + PFREE(c->banner); + c->banner = NULL; + } + + if(c->pname != NULL) { + PFREE(c->pname); + c->pname = NULL; + } + + for(i=0;i < c->n_prompts; i++) { + if(c->prompts[i]) { + cw_free_prompt(c->prompts[i]); + c->prompts[i] = NULL; + } + } + + if(c->prompts != NULL) { + PFREE(c->prompts); + c->prompts = NULL; + } + + c->nc_prompts = 0; + c->n_prompts = 0; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_clear_prompts(khui_new_creds * c) +{ + /* the WMNC_CLEAR_PROMPT message needs to be sent before freeing + the prompts, because the prompts structure still holds the + window handles for the custom prompt controls. */ + SendMessage(c->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_CLEAR_PROMPTS), (LPARAM) c); + + EnterCriticalSection(&c->cs); + cw_free_prompts(c); + LeaveCriticalSection(&c->cs); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_begin_custom_prompts(khui_new_creds * c, + khm_size n_prompts, + wchar_t * banner, + wchar_t * pname) +{ + size_t cb; + + PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_CLEAR_PROMPTS), (LPARAM) c); + + EnterCriticalSection(&c->cs); +#ifdef DEBUG + assert(c->n_prompts == 0); +#endif + cw_free_prompts(c); + + if(SUCCEEDED(StringCbLength(banner, KHUI_MAXCB_BANNER, &cb)) && + cb > 0) { + cb += sizeof(wchar_t); + c->banner = PMALLOC(cb); + StringCbCopy(c->banner, cb, banner); + } else { + c->banner = NULL; + } + + if(SUCCEEDED(StringCbLength(pname, KHUI_MAXCB_PNAME, &cb)) && + cb > 0) { + + cb += sizeof(wchar_t); + c->pname = PMALLOC(cb); + StringCbCopy(c->pname, cb, pname); + + } else { + + c->pname = NULL; + + } + + if(n_prompts > 0) { + c->prompts = PMALLOC(sizeof(*(c->prompts)) * n_prompts); + ZeroMemory(c->prompts, sizeof(*(c->prompts)) * n_prompts); + c->nc_prompts = n_prompts; + c->n_prompts = 0; + + } else { + + c->prompts = NULL; + c->n_prompts = 0; + c->nc_prompts = 0; + + PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_SET_PROMPTS), (LPARAM) c); + } + + LeaveCriticalSection(&c->cs); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_add_prompt(khui_new_creds * c, + khm_int32 type, + wchar_t * prompt, + wchar_t * def, + khm_int32 flags) +{ + khui_new_creds_prompt * p; + + if(c->nc_prompts == 0 || + c->n_prompts == c->nc_prompts) + return KHM_ERROR_INVALID_OPERATION; + +#ifdef DEBUG + assert(c->prompts != NULL); +#endif + + EnterCriticalSection(&c->cs); + p = cw_create_prompt(c->n_prompts, type, prompt, def, flags); + if(p == NULL) { + LeaveCriticalSection(&c->cs); + return KHM_ERROR_INVALID_PARAM; + } + c->prompts[c->n_prompts++] = p; + LeaveCriticalSection(&c->cs); + + if(c->n_prompts == c->nc_prompts) { + PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_SET_PROMPTS), (LPARAM) c); + /* once we are done adding prompts, switch to the auth + panel */ +#if 0 + /* Actually, don't. Doing so can mean an unexpected panel + switch if fiddling on some other panel causes a change in + custom prompts. */ + SendMessage(c->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_SWITCH_PANEL), + (LPARAM) c); +#endif + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_get_prompt_count(khui_new_creds * c, + khm_size * np) { + + EnterCriticalSection(&c->cs); + *np = c->n_prompts; + LeaveCriticalSection(&c->cs); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_get_prompt(khui_new_creds * c, + khm_size idx, + khui_new_creds_prompt ** prompt) +{ + khm_int32 rv; + + EnterCriticalSection(&c->cs); + if(c->n_prompts <= idx || + c->prompts == NULL) { + + rv = KHM_ERROR_OUT_OF_BOUNDS; + *prompt = NULL; + } else { + + *prompt = c->prompts[idx]; + rv = KHM_ERROR_SUCCESS; + } + LeaveCriticalSection(&c->cs); + + return rv; +} + +void +khuiint_trim_str(wchar_t * s, khm_size cch) { + wchar_t * c, * last_ws; + + for (c = s; *c && iswspace(*c) && ((khm_size)(c - s)) < cch; c++); + + if (((khm_size)(c - s)) >= cch) + return; + + if (c != s && ((khm_size)(c - s)) < cch) { +#if _MSC_VER >= 1400 + wmemmove_s(s, cch, c, cch - ((khm_size)(c - s))); +#else + memmove(s, c, (cch - ((khm_size)(c - s)))* sizeof(wchar_t)); +#endif + } + + last_ws = NULL; + for (c = s; *c && ((khm_size)(c - s)) < cch; c++) { + if (!iswspace(*c)) + last_ws = NULL; + else if (last_ws == NULL) + last_ws = c; + } + + if (last_ws) + *last_ws = L'\0'; +} + +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); + redo_loop: + n = c->n_prompts; + for(i=0; iprompts[i]; + if(p->hwnd_edit) { + hw = p->hwnd_edit; + LeaveCriticalSection(&c->cs); + + GetWindowText(hw, tmpbuf, ARRAYLENGTH(tmpbuf)); + khuiint_trim_str(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); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_get_prompt_value(khui_new_creds * c, + khm_size idx, + wchar_t * buf, + khm_size *cbbuf) +{ + khui_new_creds_prompt * p; + khm_int32 rv; + size_t cb; + + rv = khui_cw_get_prompt(c, idx, &p); + if(KHM_FAILED(rv)) + return rv; + + EnterCriticalSection(&c->cs); + + if(FAILED(StringCbLength(p->value, KHUI_MAXCB_PROMPT_VALUE, &cb))) { + *cbbuf = 0; + if(buf != NULL) + *buf = 0; + LeaveCriticalSection(&c->cs); + return KHM_ERROR_SUCCESS; + } + cb += sizeof(wchar_t); + + if(buf == NULL || *cbbuf < cb) { + *cbbuf = cb; + LeaveCriticalSection(&c->cs); + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buf, *cbbuf, p->value); + *cbbuf = cb; + LeaveCriticalSection(&c->cs); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_set_response(khui_new_creds * c, + khm_int32 type, + khm_int32 response) +{ + khui_new_creds_by_type * t = NULL; + EnterCriticalSection(&c->cs); + khui_cw_find_type(c, type, &t); + c->response |= response & KHUI_NCMASK_RESPONSE; + if(t) { + t->flags &= ~KHUI_NCMASK_RESULT; + t->flags |= (response & KHUI_NCMASK_RESULT); + + if (!(response & KHUI_NC_RESPONSE_NOEXIT) && + !(response & KHUI_NC_RESPONSE_PENDING)) + t->flags |= KHUI_NC_RESPONSE_COMPLETED; + } + LeaveCriticalSection(&c->cs); + return KHM_ERROR_SUCCESS; +} + +/* only called from a identity provider callback */ +KHMEXP khm_int32 KHMAPI +khui_cw_add_control_row(khui_new_creds * c, + HWND label, + HWND input, + khui_control_size size) +{ + if (c && c->hwnd) { + khui_control_row row; + + row.label = label; + row.input = input; + row.size = size; + + SendMessage(c->hwnd, + KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_ADD_CONTROL_ROW), + (LPARAM) &row); + + return KHM_ERROR_SUCCESS; + } else { + return KHM_ERROR_INVALID_PARAM; + } +} diff --git a/src/windows/identity/uilib/intaction.h b/src/windows/identity/uilib/intaction.h index 44348b9bb..2b7aa973a 100644 --- a/src/windows/identity/uilib/intaction.h +++ b/src/windows/identity/uilib/intaction.h @@ -1,108 +1,108 @@ -/* - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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_ACTION_H_INTERNAL -#define __NETIDMGR_ACTION_H_INTERNAL - -/* Internal declarations for exports and data structured used in - nidmgr32.dll and netidmgr.exe */ - -extern HWND khui_hwnd_main; - -typedef struct tag_khui_ui_callback_data { - khm_int32 magic; - khm_ui_callback cb; - void * rock; - khm_int32 rv; -} khui_ui_callback_data; - -#define KHUI_UICBDATA_MAGIC 0x8a08572a - -/*! \addtogroup khui_actions -@{ */ - -/*! \brief An action */ -typedef struct tag_khui_action { - 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; - -/*@}*/ - -#endif +/* + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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_ACTION_H_INTERNAL +#define __NETIDMGR_ACTION_H_INTERNAL + +/* Internal declarations for exports and data structured used in + nidmgr32.dll and netidmgr.exe */ + +extern HWND khui_hwnd_main; + +typedef struct tag_khui_ui_callback_data { + khm_int32 magic; + khm_ui_callback cb; + void * rock; + khm_int32 rv; +} khui_ui_callback_data; + +#define KHUI_UICBDATA_MAGIC 0x8a08572a + +/*! \addtogroup khui_actions +@{ */ + +/*! \brief An action */ +typedef struct tag_khui_action { + 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; + +/*@}*/ + +#endif diff --git a/src/windows/identity/uilib/khaction.h b/src/windows/identity/uilib/khaction.h index 92fa7b0fa..8182682c4 100644 --- a/src/windows/identity/uilib/khaction.h +++ b/src/windows/identity/uilib/khaction.h @@ -1,1005 +1,1005 @@ -/* - * 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_ACTION_H -#define __KHIMAIRA_ACTION_H - -/*! \addtogroup khui - @{*/ -/*! \defgroup khui_actions Actions - @{*/ - -struct tag_khui_action; -typedef struct tag_khui_action khui_action; - -/*! \brief Unknown action type - - Unknown action type. - */ -#define KHUI_ACTIONTYPE_NONE 0 - -/*! \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 - - A toggle type action typically changes the CHECKED state of the - action each time it is invoked. - */ -#define KHUI_ACTIONTYPE_TOGGLE 2 - -/*! \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 - over a UI element representing the 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,NULL,0,0,0,0,0,cap,des,top,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0} - -#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,NULL,inormal,ihot,idis,isml,ismld,cap,des,top,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0} -#endif - -/*! \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; /*!< A combination of KHUI_ACTIONREF_* */ - union { - 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. - - Only one action is allowed to have this flag set. When an action - is added to a menu using khui_menu_insert_action() or - khui_menu_insert_paction() and this flag is set, all other menu - items will be stripped of this flag. - */ -#define KHUI_ACTIONREF_DEFAULT 0x20 - -#ifdef NOEXPORT -#define MENU_ACTION(c) {0,c} -#define MENU_DEFACTION(c) {KHUI_ACTIONREF_DEFAULT, c} -#define MENU_SUBMENU(s) {KHUI_ACTIONREF_SUBMENU,s} -#define MENU_SEP() {KHUI_ACTIONREF_SEP,KHUI_MENU_SEP} -#define MENU_END() {KHUI_ACTIONREF_END,KHUI_MENU_END} -#endif - -/*! \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 { - 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_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. 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; - int mod; - int key; - int scope; -} khui_accel_def; - -#define KHUI_ACCEL_SCOPE_GLOBAL 0 - -extern khui_accel_def khui_accel_global[]; -extern int khui_n_accel_global; - -extern khui_action khui_actions[]; -extern int khui_n_actions; - -extern khui_menu_def khui_all_menus[]; -extern int khui_n_all_menus; - -#endif /* NOEXPORT */ - -/* functions */ - -/*! \brief Refresh the global action table - - Changes to system menus and toolbars may not be immediately - reflected in the user interface. Calling this function forces the - UI to reparse the action tables and menus and refresh the - application menu bar and toolbars. - - */ -KHMEXP void KHMAPI -khui_refresh_actions(void); - -/*! \brief Lock the action and menu tables - - This function, along with khui_action_unlock() is used to prevent - changes from being made to shared menus and actions while they are - being updated. In particular, changes to shared menus usually - need to be done in a batch and may suffer corruption of other - threads access or modify the menu while one thread is updating it. - Operations on shared menus should always be done with the actions - locked. -*/ -KHMEXP void KHMAPI -khui_action_lock(void); - -/*! \brief Unlock the action and menu tables - - Unlocks the action and menu tables after a call to - khui_action_lock(). - - \see khui_action_lock() - */ -KHMEXP void KHMAPI -khui_action_unlock(void); - -/*! \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. If ::KHUI_ACTIONREF_DEFAULT is - specified, then all other items in the menu will be stripped - of that flag leaving this action as the only one with that - flag set. - */ -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. If - ::KHUI_ACTIONREF_DEFAULT is specified, then all other items in - the menu will be stripped of that flag leaving this action as - the only one with that flag set. -*/ -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. - - */ -KHMEXP khui_action_ref * -khui_menu_get_action(khui_menu_def * d, khm_size idx); - -/*! \brief Action scope identifiers - - The scope identifier is a value which describes the scope of the - cursor context. See documentation on individual scope identifiers - for details. - - The role of the scope identifier is to provide a summary of the - current cursor context. Specifically, these identify several - special cases of credential selection, such as the selection of an - entire identity, a credential type or a single credential. If - none of these are applicable, then the generic scope identifier - ::KHUI_SCOPE_GROUP is set or ::KHUI_SCOPE_NONE if there is nothing - selected. - - Note that the scope typically only apply to cursor contexts and - not the selection context. Please see - \ref khui_context "UI Contexts" for more information. - - \see \ref khui_context "UI Contexts" -*/ -typedef enum tag_khui_scope { - KHUI_SCOPE_NONE, - /*!< No context. Nothing is selected. */ - - KHUI_SCOPE_IDENT, - /*!< Identity. The selection is the entire identity specified in - the \a identity field of the context. */ - - KHUI_SCOPE_CREDTYPE, - /*!< A credentials type. The selection is an entire credentials - type. If \a identity is non-NULL, then the scope is all the - credentials of type \a cred_type which belong to \a identity. - Otherwise, the selection is all credentials of type \a - cred_type. - - \note The \a identity can be non-NULL even for the case where - all credentials of type \a cred_type under \a identity is the - same scope as all credentials of type \a cred_type under all - identities. */ - - KHUI_SCOPE_GROUP, - /*!< A grouping of credentials. The scope is a group of - credentials which can not be simplified using one of the other - context identifiers. The \a headers array contains \a n_headers - elements describing the outline level that has been selected. - - \see ::khui_header - \see \ref khui_context_sel_ctx_grp "KHUI_SCOPE_GROUP description" */ - - KHUI_SCOPE_CRED - /*!< A single credential. Only a single credential was - selected. The \a cred field of the context specifies the - credential. The \a identity and \a cred_type fields specify the - identity and the credential type respectively. */ -} khui_scope; - - -/*! \brief Outline header - - Describes an outline header in the user interface. - - \see \ref khui_context_sel_ctx_grp "KHUI_SCOPE_GROUP description" - */ -typedef struct tag_khui_header { - khm_int32 attr_id; /*!< Attribute ID */ - void * data; /*!< Value of attribute */ - khm_size cb_data; /*!< Size of the value */ -} khui_header; - -/*! \brief Maximum number of outline headers - - This is the maximum number of fields that the credentials view can - be grouped by. - */ -#define KHUI_MAX_HEADERS 6 - -/*! \brief Action context - - Represents the UI context for an action. - */ -typedef struct tag_khui_action_context { - khm_int32 magic; /*!< Internal. */ - khui_scope scope; /*!< Context scope. One of ::khui_scope*/ - khm_handle identity; /*!< Identity */ - khm_int32 cred_type; /*!< Credential type ID */ - khm_handle cred; /*!< Credential */ - - khui_header headers[KHUI_MAX_HEADERS]; - /*!< The ordered set of outline - headers which define the current - cursor location. */ - - khm_size n_headers; /*!< Number of actual headers defined - above */ - - khm_handle credset; /*!< Handle to a credential set - containing the currently selected - credentials. When the context is - obtained through khui_context_get(), - this credential is returned in a - sealed state. */ - - khm_size n_sel_creds; /*!< Number of selected credentials */ - - void * int_buf; /*!< Internal. Do not use. */ - khm_size int_cb_buf; /*!< Internal. Do not use. */ - khm_size int_cb_used; /*!< Internal. Do not use. */ - - void * vparam; /*!< Optional data */ - khm_size cb_vparam; /*!< Size of optional data */ -} khui_action_context; - -/*! \brief Set the current context - - Changes the UI context to that represented by the parameters to - the function. Note that specifying a valid \a identity or \a cred - parameter will result in an automatic hold on the respective - object. The hold will stay until another call to - khui_context_set() overwrites the identity or credential handle or - a call to khui_context_reset() is made. - - While this API is available, it is only called from the main - NetIDMgr application. Plugins do not have a good reason to call - this API directly and should not do so. - - \param[in] scope The new context scope - - \param[in] identity A handle to an identity. If this is not NULL, - then it should be a valid handle to an identity. Required if - \a scope specifies ::KHUI_SCOPE_IDENT. Optional if \a scope - specifies ::KHUI_SCOPE_CREDTYPE. Ignored otherwise. - - \param[in] cred_type A credentials type. Specify - ::KCDB_CREDTYPE_INVALID if this parameter is not given or not - relevant. Required if \a scope specifies - ::KHUI_SCOPE_CREDTYPE. Ignored otherwise. - - \param[in] cred A handle to a credential. If this parameter is - not NULL it is expected to be a valid handle to a credential. - Required if \a scope specifies ::KHUI_SCOPE_CRED. Ignored - otherwise. - - \param[in] headers An array of headers. The \a n_headers - parameter specifies the number of elements in the array. Set - to NULL if not specified. Required if \a scope specifies - ::KHUI_SCOPE_GROUP. - - \param[in] n_headers Number of elements in \a headers. Must be - less than or equal to ::KHUI_MAX_HEADERS. Required if \a - headers is not NULL. Ignored otherwise. - - \param[in] cs_src A handle to a credential set from which the - selected credentials will be extracted. The credentials that - are selected must have the ::KCDB_CRED_FLAG_SELECTED flag set. - - \note This function should only be called from the UI thread. - */ -KHMEXP void KHMAPI -khui_context_set(khui_scope scope, - khm_handle identity, - khm_int32 cred_type, - khm_handle cred, - khui_header *headers, - khm_size n_headers, - khm_handle cs_src); - -/*! \brief Set the current context - - Changes the UI context to that represented by the parameters to - the function. Note that specifying a valid \a identity or \a cred - parameter will result in an automatic hold on the respective - object. The hold will stay until another call to - khui_context_set() overwrites the identity or credential handle or - a call to khui_context_reset() is made. - - While this API is available, it is only called from the main - NetIDMgr application. Plugins do not have a good reason to call - this API directly and should not do so. - - \param[in] scope The new context scope - - \param[in] identity A handle to an identity. If this is not NULL, - then it should be a valid handle to an identity. Required if - \a scope specifies ::KHUI_SCOPE_IDENT. Optional if \a scope - specifies ::KHUI_SCOPE_CREDTYPE. Ignored otherwise. - - \param[in] cred_type A credentials type. Specify - ::KCDB_CREDTYPE_INVALID if this parameter is not given or not - relevant. Required if \a scope specifies - ::KHUI_SCOPE_CREDTYPE. Ignored otherwise. - - \param[in] cred A handle to a credential. If this parameter is - not NULL it is expected to be a valid handle to a credential. - Required if \a scope specifies ::KHUI_SCOPE_CRED. Ignored - otherwise. - - \param[in] headers An array of headers. The \a n_headers - parameter specifies the number of elements in the array. Set - to NULL if not specified. Required if \a scope specifies - ::KHUI_SCOPE_GROUP. - - \param[in] n_headers Number of elements in \a headers. Must be - less than or equal to ::KHUI_MAX_HEADERS. Required if \a - headers is not NULL. Ignored otherwise. - - \param[in] cs_src A handle to a credential set from which the - selected credentials will be extracted. The credentials that - are selected must have the ::KCDB_CRED_FLAG_SELECTED flag set. - - \param[in] vparam Optional parameter blob - - \param[in] cb_vparam Size of parameter blob - - \note This function should only be called from the UI thread. - */ -KHMEXP void KHMAPI -khui_context_set_ex(khui_scope scope, - khm_handle identity, - khm_int32 cred_type, - khm_handle cred, - khui_header *headers, - khm_size n_headers, - khm_handle cs_src, - 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 - context. If the context contains an identity or a credential - handle, a hold will be obtained on the relevant object. Use - khui_context_release() to release the holds obtained in a prior - call to khui_context_get(). - - \note The returned context should not be modified prior to calling - khui_context_release(). -*/ -KHMEXP void KHMAPI -khui_context_get(khui_action_context * ctx); - -/*! \brief Create a new UI context - - The created context does not have any relation to the current UI - context. This function is provided for use in situations where an - application needs to provide a scope description through a - ::khui_action_context structure. - - Once the application is done with the context, it should call - khui_context_release() to release the created context. - */ -KHMEXP void KHMAPI -khui_context_create(khui_action_context * ctx, - khui_scope scope, - khm_handle identity, - khm_int32 cred_type, - khm_handle cred); - -/*! \brief Release a context obtained using khui_context_get() - - Releases all holds obtained on related objects in a prior call to - khui_context_get() and nullifies the context. - - \note The context should not have been modified between calling - khui_context_get() and khui_context_release() - */ -KHMEXP void KHMAPI -khui_context_release(khui_action_context * ctx); - -/*! \brief Reset the UI context - - Nullifies the current UI context and releases any holds obtained - on objects related to the previous context. -*/ -KHMEXP void KHMAPI -khui_context_reset(void); - -/*! \brief Refresh context data - - Setting the UI context involves other side effects such as - activation of or disabling certain actions based on the selection. - If an operation is performed which may affect the side effects, - khui_context_refresh() is called to refresh them. - - An example is when setting the default identity. The state of the - action ::KHUI_ACTION_SET_DEF_ID depends on whether the currently - selected identity is the default. However, if the currently - selected identity becomes the default after selection, then - khui_context_refresh() should be called to adjust the state of the - ::KHUI_ACTION_SET_DEF_ID action. - */ -KHMEXP void KHMAPI -khui_context_refresh(void); - -/*! \brief A filter function that filters for credentials in the cursor context - - This is a function of type ::kcdb_cred_filter_func which can be - used to filter for credentials that are included in the cursor - context. - - The \a rock parameter should be a pointer to a - ::khui_action_context structure which will be used as the filter. - - For example, the following code will extract the cursor context - credentials into the credential set \a my_credset based on the UI - context \a my context: - - \code - kcdb_credset_extract_filtered(my_credset, - NULL, - khui_context_cursor_filter, - (void *) my_context); - \endcode -*/ -KHMEXP khm_int32 KHMAPI -khui_context_cursor_filter(khm_handle cred, - khm_int32 flags, - void * rock); - -/*! \brief Get a string representation of an accelerator - - \param[in] cmd Command for which to obtain the accelerator string for - \param[out] buf Buffer to receive the accelerator string - \param[in] bufsiz Size of the buffer in bytes. Note that the size of the - buffer must be sufficient to hold at least one character and a - NULL terminator. - - \return TRUE if the operation was successful. FALSE otherwise. - */ -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 - - 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 - - Creates a new custom action. The created custom action can be - added to menus, toolbars and can be triggered by - khui_action_trigger(). - - When the action is triggered as a result of the user selecting a - menu item, a toolbar item or as a result of calling - khui_action_trigger(), the subscription identified by \a hsub will - received a message of type ::KMSG_ACT, subtype - ::KMSG_ACT_ACTIVATE. The \a uparam for the message will be the - action identifier that was returned by khui_action_create(). The - \a vparam of the message will currently be set to \a NULL. - - Actions can optionally be named. The name is not actively used by - the Network Identity Manager framework, but can be used to label - actions so that they can be looked up later using - khui_find_named_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.) - See \a note below for additional restrictions on the name of - the 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] userdata A custom value. - - \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] hsub The subscription that is notified when the action - is triggered. (Optional) The subscription must be created with - kmq_create_subscription(). The handle will be released when - it is no longer needed. Hence, the caller should not release - it. - - \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(const wchar_t * name); - -/*! \brief Enables or disables a group of actions - - The group of actions are specified by the menu definition. All - valid action entries in the menu are marked as enabled or disabled - according to the value of \a enable. - */ -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 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(khm_int32 action, khm_boolean enable); - -/*! \brief Check an action in an action group - - 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] 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 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 - - \note Only called by the NetIDMgr application - */ -KHMEXP void KHMAPI khui_init_actions(void); - -/*! \brief Exit actions - - \note Only called by the NetIDMgr application - */ -KHMEXP void KHMAPI khui_exit_actions(void); - -/*! \endcond */ -#endif - -/*@}*/ -/*@}*/ -#endif +/* + * 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_ACTION_H +#define __KHIMAIRA_ACTION_H + +/*! \addtogroup khui + @{*/ +/*! \defgroup khui_actions Actions + @{*/ + +struct tag_khui_action; +typedef struct tag_khui_action khui_action; + +/*! \brief Unknown action type + + Unknown action type. + */ +#define KHUI_ACTIONTYPE_NONE 0 + +/*! \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 + + A toggle type action typically changes the CHECKED state of the + action each time it is invoked. + */ +#define KHUI_ACTIONTYPE_TOGGLE 2 + +/*! \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 + over a UI element representing the 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,NULL,0,0,0,0,0,cap,des,top,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0} + +#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,NULL,inormal,ihot,idis,isml,ismld,cap,des,top,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0} +#endif + +/*! \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; /*!< A combination of KHUI_ACTIONREF_* */ + union { + 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. + + Only one action is allowed to have this flag set. When an action + is added to a menu using khui_menu_insert_action() or + khui_menu_insert_paction() and this flag is set, all other menu + items will be stripped of this flag. + */ +#define KHUI_ACTIONREF_DEFAULT 0x20 + +#ifdef NOEXPORT +#define MENU_ACTION(c) {0,c} +#define MENU_DEFACTION(c) {KHUI_ACTIONREF_DEFAULT, c} +#define MENU_SUBMENU(s) {KHUI_ACTIONREF_SUBMENU,s} +#define MENU_SEP() {KHUI_ACTIONREF_SEP,KHUI_MENU_SEP} +#define MENU_END() {KHUI_ACTIONREF_END,KHUI_MENU_END} +#endif + +/*! \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 { + 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_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. 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; + int mod; + int key; + int scope; +} khui_accel_def; + +#define KHUI_ACCEL_SCOPE_GLOBAL 0 + +extern khui_accel_def khui_accel_global[]; +extern int khui_n_accel_global; + +extern khui_action khui_actions[]; +extern int khui_n_actions; + +extern khui_menu_def khui_all_menus[]; +extern int khui_n_all_menus; + +#endif /* NOEXPORT */ + +/* functions */ + +/*! \brief Refresh the global action table + + Changes to system menus and toolbars may not be immediately + reflected in the user interface. Calling this function forces the + UI to reparse the action tables and menus and refresh the + application menu bar and toolbars. + + */ +KHMEXP void KHMAPI +khui_refresh_actions(void); + +/*! \brief Lock the action and menu tables + + This function, along with khui_action_unlock() is used to prevent + changes from being made to shared menus and actions while they are + being updated. In particular, changes to shared menus usually + need to be done in a batch and may suffer corruption of other + threads access or modify the menu while one thread is updating it. + Operations on shared menus should always be done with the actions + locked. +*/ +KHMEXP void KHMAPI +khui_action_lock(void); + +/*! \brief Unlock the action and menu tables + + Unlocks the action and menu tables after a call to + khui_action_lock(). + + \see khui_action_lock() + */ +KHMEXP void KHMAPI +khui_action_unlock(void); + +/*! \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. If ::KHUI_ACTIONREF_DEFAULT is + specified, then all other items in the menu will be stripped + of that flag leaving this action as the only one with that + flag set. + */ +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. If + ::KHUI_ACTIONREF_DEFAULT is specified, then all other items in + the menu will be stripped of that flag leaving this action as + the only one with that flag set. +*/ +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. + + */ +KHMEXP khui_action_ref * +khui_menu_get_action(khui_menu_def * d, khm_size idx); + +/*! \brief Action scope identifiers + + The scope identifier is a value which describes the scope of the + cursor context. See documentation on individual scope identifiers + for details. + + The role of the scope identifier is to provide a summary of the + current cursor context. Specifically, these identify several + special cases of credential selection, such as the selection of an + entire identity, a credential type or a single credential. If + none of these are applicable, then the generic scope identifier + ::KHUI_SCOPE_GROUP is set or ::KHUI_SCOPE_NONE if there is nothing + selected. + + Note that the scope typically only apply to cursor contexts and + not the selection context. Please see + \ref khui_context "UI Contexts" for more information. + + \see \ref khui_context "UI Contexts" +*/ +typedef enum tag_khui_scope { + KHUI_SCOPE_NONE, + /*!< No context. Nothing is selected. */ + + KHUI_SCOPE_IDENT, + /*!< Identity. The selection is the entire identity specified in + the \a identity field of the context. */ + + KHUI_SCOPE_CREDTYPE, + /*!< A credentials type. The selection is an entire credentials + type. If \a identity is non-NULL, then the scope is all the + credentials of type \a cred_type which belong to \a identity. + Otherwise, the selection is all credentials of type \a + cred_type. + + \note The \a identity can be non-NULL even for the case where + all credentials of type \a cred_type under \a identity is the + same scope as all credentials of type \a cred_type under all + identities. */ + + KHUI_SCOPE_GROUP, + /*!< A grouping of credentials. The scope is a group of + credentials which can not be simplified using one of the other + context identifiers. The \a headers array contains \a n_headers + elements describing the outline level that has been selected. + + \see ::khui_header + \see \ref khui_context_sel_ctx_grp "KHUI_SCOPE_GROUP description" */ + + KHUI_SCOPE_CRED + /*!< A single credential. Only a single credential was + selected. The \a cred field of the context specifies the + credential. The \a identity and \a cred_type fields specify the + identity and the credential type respectively. */ +} khui_scope; + + +/*! \brief Outline header + + Describes an outline header in the user interface. + + \see \ref khui_context_sel_ctx_grp "KHUI_SCOPE_GROUP description" + */ +typedef struct tag_khui_header { + khm_int32 attr_id; /*!< Attribute ID */ + void * data; /*!< Value of attribute */ + khm_size cb_data; /*!< Size of the value */ +} khui_header; + +/*! \brief Maximum number of outline headers + + This is the maximum number of fields that the credentials view can + be grouped by. + */ +#define KHUI_MAX_HEADERS 6 + +/*! \brief Action context + + Represents the UI context for an action. + */ +typedef struct tag_khui_action_context { + khm_int32 magic; /*!< Internal. */ + khui_scope scope; /*!< Context scope. One of ::khui_scope*/ + khm_handle identity; /*!< Identity */ + khm_int32 cred_type; /*!< Credential type ID */ + khm_handle cred; /*!< Credential */ + + khui_header headers[KHUI_MAX_HEADERS]; + /*!< The ordered set of outline + headers which define the current + cursor location. */ + + khm_size n_headers; /*!< Number of actual headers defined + above */ + + khm_handle credset; /*!< Handle to a credential set + containing the currently selected + credentials. When the context is + obtained through khui_context_get(), + this credential is returned in a + sealed state. */ + + khm_size n_sel_creds; /*!< Number of selected credentials */ + + void * int_buf; /*!< Internal. Do not use. */ + khm_size int_cb_buf; /*!< Internal. Do not use. */ + khm_size int_cb_used; /*!< Internal. Do not use. */ + + void * vparam; /*!< Optional data */ + khm_size cb_vparam; /*!< Size of optional data */ +} khui_action_context; + +/*! \brief Set the current context + + Changes the UI context to that represented by the parameters to + the function. Note that specifying a valid \a identity or \a cred + parameter will result in an automatic hold on the respective + object. The hold will stay until another call to + khui_context_set() overwrites the identity or credential handle or + a call to khui_context_reset() is made. + + While this API is available, it is only called from the main + NetIDMgr application. Plugins do not have a good reason to call + this API directly and should not do so. + + \param[in] scope The new context scope + + \param[in] identity A handle to an identity. If this is not NULL, + then it should be a valid handle to an identity. Required if + \a scope specifies ::KHUI_SCOPE_IDENT. Optional if \a scope + specifies ::KHUI_SCOPE_CREDTYPE. Ignored otherwise. + + \param[in] cred_type A credentials type. Specify + ::KCDB_CREDTYPE_INVALID if this parameter is not given or not + relevant. Required if \a scope specifies + ::KHUI_SCOPE_CREDTYPE. Ignored otherwise. + + \param[in] cred A handle to a credential. If this parameter is + not NULL it is expected to be a valid handle to a credential. + Required if \a scope specifies ::KHUI_SCOPE_CRED. Ignored + otherwise. + + \param[in] headers An array of headers. The \a n_headers + parameter specifies the number of elements in the array. Set + to NULL if not specified. Required if \a scope specifies + ::KHUI_SCOPE_GROUP. + + \param[in] n_headers Number of elements in \a headers. Must be + less than or equal to ::KHUI_MAX_HEADERS. Required if \a + headers is not NULL. Ignored otherwise. + + \param[in] cs_src A handle to a credential set from which the + selected credentials will be extracted. The credentials that + are selected must have the ::KCDB_CRED_FLAG_SELECTED flag set. + + \note This function should only be called from the UI thread. + */ +KHMEXP void KHMAPI +khui_context_set(khui_scope scope, + khm_handle identity, + khm_int32 cred_type, + khm_handle cred, + khui_header *headers, + khm_size n_headers, + khm_handle cs_src); + +/*! \brief Set the current context + + Changes the UI context to that represented by the parameters to + the function. Note that specifying a valid \a identity or \a cred + parameter will result in an automatic hold on the respective + object. The hold will stay until another call to + khui_context_set() overwrites the identity or credential handle or + a call to khui_context_reset() is made. + + While this API is available, it is only called from the main + NetIDMgr application. Plugins do not have a good reason to call + this API directly and should not do so. + + \param[in] scope The new context scope + + \param[in] identity A handle to an identity. If this is not NULL, + then it should be a valid handle to an identity. Required if + \a scope specifies ::KHUI_SCOPE_IDENT. Optional if \a scope + specifies ::KHUI_SCOPE_CREDTYPE. Ignored otherwise. + + \param[in] cred_type A credentials type. Specify + ::KCDB_CREDTYPE_INVALID if this parameter is not given or not + relevant. Required if \a scope specifies + ::KHUI_SCOPE_CREDTYPE. Ignored otherwise. + + \param[in] cred A handle to a credential. If this parameter is + not NULL it is expected to be a valid handle to a credential. + Required if \a scope specifies ::KHUI_SCOPE_CRED. Ignored + otherwise. + + \param[in] headers An array of headers. The \a n_headers + parameter specifies the number of elements in the array. Set + to NULL if not specified. Required if \a scope specifies + ::KHUI_SCOPE_GROUP. + + \param[in] n_headers Number of elements in \a headers. Must be + less than or equal to ::KHUI_MAX_HEADERS. Required if \a + headers is not NULL. Ignored otherwise. + + \param[in] cs_src A handle to a credential set from which the + selected credentials will be extracted. The credentials that + are selected must have the ::KCDB_CRED_FLAG_SELECTED flag set. + + \param[in] vparam Optional parameter blob + + \param[in] cb_vparam Size of parameter blob + + \note This function should only be called from the UI thread. + */ +KHMEXP void KHMAPI +khui_context_set_ex(khui_scope scope, + khm_handle identity, + khm_int32 cred_type, + khm_handle cred, + khui_header *headers, + khm_size n_headers, + khm_handle cs_src, + 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 + context. If the context contains an identity or a credential + handle, a hold will be obtained on the relevant object. Use + khui_context_release() to release the holds obtained in a prior + call to khui_context_get(). + + \note The returned context should not be modified prior to calling + khui_context_release(). +*/ +KHMEXP void KHMAPI +khui_context_get(khui_action_context * ctx); + +/*! \brief Create a new UI context + + The created context does not have any relation to the current UI + context. This function is provided for use in situations where an + application needs to provide a scope description through a + ::khui_action_context structure. + + Once the application is done with the context, it should call + khui_context_release() to release the created context. + */ +KHMEXP void KHMAPI +khui_context_create(khui_action_context * ctx, + khui_scope scope, + khm_handle identity, + khm_int32 cred_type, + khm_handle cred); + +/*! \brief Release a context obtained using khui_context_get() + + Releases all holds obtained on related objects in a prior call to + khui_context_get() and nullifies the context. + + \note The context should not have been modified between calling + khui_context_get() and khui_context_release() + */ +KHMEXP void KHMAPI +khui_context_release(khui_action_context * ctx); + +/*! \brief Reset the UI context + + Nullifies the current UI context and releases any holds obtained + on objects related to the previous context. +*/ +KHMEXP void KHMAPI +khui_context_reset(void); + +/*! \brief Refresh context data + + Setting the UI context involves other side effects such as + activation of or disabling certain actions based on the selection. + If an operation is performed which may affect the side effects, + khui_context_refresh() is called to refresh them. + + An example is when setting the default identity. The state of the + action ::KHUI_ACTION_SET_DEF_ID depends on whether the currently + selected identity is the default. However, if the currently + selected identity becomes the default after selection, then + khui_context_refresh() should be called to adjust the state of the + ::KHUI_ACTION_SET_DEF_ID action. + */ +KHMEXP void KHMAPI +khui_context_refresh(void); + +/*! \brief A filter function that filters for credentials in the cursor context + + This is a function of type ::kcdb_cred_filter_func which can be + used to filter for credentials that are included in the cursor + context. + + The \a rock parameter should be a pointer to a + ::khui_action_context structure which will be used as the filter. + + For example, the following code will extract the cursor context + credentials into the credential set \a my_credset based on the UI + context \a my context: + + \code + kcdb_credset_extract_filtered(my_credset, + NULL, + khui_context_cursor_filter, + (void *) my_context); + \endcode +*/ +KHMEXP khm_int32 KHMAPI +khui_context_cursor_filter(khm_handle cred, + khm_int32 flags, + void * rock); + +/*! \brief Get a string representation of an accelerator + + \param[in] cmd Command for which to obtain the accelerator string for + \param[out] buf Buffer to receive the accelerator string + \param[in] bufsiz Size of the buffer in bytes. Note that the size of the + buffer must be sufficient to hold at least one character and a + NULL terminator. + + \return TRUE if the operation was successful. FALSE otherwise. + */ +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 + + 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 + + Creates a new custom action. The created custom action can be + added to menus, toolbars and can be triggered by + khui_action_trigger(). + + When the action is triggered as a result of the user selecting a + menu item, a toolbar item or as a result of calling + khui_action_trigger(), the subscription identified by \a hsub will + received a message of type ::KMSG_ACT, subtype + ::KMSG_ACT_ACTIVATE. The \a uparam for the message will be the + action identifier that was returned by khui_action_create(). The + \a vparam of the message will currently be set to \a NULL. + + Actions can optionally be named. The name is not actively used by + the Network Identity Manager framework, but can be used to label + actions so that they can be looked up later using + khui_find_named_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.) + See \a note below for additional restrictions on the name of + the 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] userdata A custom value. + + \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] hsub The subscription that is notified when the action + is triggered. (Optional) The subscription must be created with + kmq_create_subscription(). The handle will be released when + it is no longer needed. Hence, the caller should not release + it. + + \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(const wchar_t * name); + +/*! \brief Enables or disables a group of actions + + The group of actions are specified by the menu definition. All + valid action entries in the menu are marked as enabled or disabled + according to the value of \a enable. + */ +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 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(khm_int32 action, khm_boolean enable); + +/*! \brief Check an action in an action group + + 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] 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 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 + + \note Only called by the NetIDMgr application + */ +KHMEXP void KHMAPI khui_init_actions(void); + +/*! \brief Exit actions + + \note Only called by the NetIDMgr application + */ +KHMEXP void KHMAPI khui_exit_actions(void); + +/*! \endcond */ +#endif + +/*@}*/ +/*@}*/ +#endif diff --git a/src/windows/identity/uilib/khactiondef.h b/src/windows/identity/uilib/khactiondef.h index 87e2355f1..08dbad2ad 100644 --- a/src/windows/identity/uilib/khactiondef.h +++ b/src/windows/identity/uilib/khactiondef.h @@ -1,168 +1,168 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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_ACTIONDEF_H -#define __KHIMAIRA_ACTIONDEF_H - -/*! \ingroup khui_actions - @{*/ -/*! \defgroup khui_std_actions Standard Actions -@{ */ - -/*!\name Standard actions - @{*/ -#define KHUI_ACTION_BASE 50000 - -#define KHUI_ACTION_PROPERTIES (KHUI_ACTION_BASE + 0) -#define KHUI_ACTION_EXIT (KHUI_ACTION_BASE + 1) -#define KHUI_ACTION_SET_DEF_ID (KHUI_ACTION_BASE + 3) -#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_DEBUG_WINDOW (KHUI_ACTION_BASE + 10) -#define KHUI_ACTION_VIEW_REFRESH (KHUI_ACTION_BASE + 11) -#define KHUI_ACTION_LAYOUT_ID (KHUI_ACTION_BASE + 12) -#define KHUI_ACTION_LAYOUT_TYPE (KHUI_ACTION_BASE + 13) -#define KHUI_ACTION_LAYOUT_LOC (KHUI_ACTION_BASE + 14) -#define KHUI_ACTION_TB_STANDARD (KHUI_ACTION_BASE + 15) -#define KHUI_ACTION_OPT_KHIM (KHUI_ACTION_BASE + 16) -#define KHUI_ACTION_OPT_IDENTS (KHUI_ACTION_BASE + 17) -#define KHUI_ACTION_OPT_NOTIF (KHUI_ACTION_BASE + 18) -#define KHUI_ACTION_HELP_CTX (KHUI_ACTION_BASE + 19) -#define KHUI_ACTION_HELP_CONTENTS (KHUI_ACTION_BASE + 20) -#define KHUI_ACTION_HELP_INDEX (KHUI_ACTION_BASE + 21) -#define KHUI_ACTION_HELP_ABOUT (KHUI_ACTION_BASE + 22) -#define KHUI_ACTION_DESTROY_CRED (KHUI_ACTION_BASE + 23) -#define KHUI_ACTION_RENEW_CRED (KHUI_ACTION_BASE + 24) -#define KHUI_ACTION_OPEN_APP (KHUI_ACTION_BASE + 25) -#define KHUI_ACTION_MENU_ACTIVATE (KHUI_ACTION_BASE + 26) -#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) -#define KHUI_ACTION_OPT_APPEAR (KHUI_ACTION_BASE + 31) -#define KHUI_ACTION_LAYOUT_RELOAD (KHUI_ACTION_BASE + 32) -#define KHUI_ACTION_RENEW_ALL (KHUI_ACTION_BASE + 33) -#define KHUI_ACTION_DESTROY_ALL (KHUI_ACTION_BASE + 34) -#define KHUI_ACTION_UICB (KHUI_ACTION_BASE + 35) -#define KHUI_ACTION_LAYOUT_MINI (KHUI_ACTION_BASE + 36) -/*@}*/ - -/*! \name Pseudo actions - -Pseudo actions do not trigger any specific function, but acts as a -signal of some generic event which will be interpreted based on -context. - -@{*/ -#define KHUI_PACTION_BASE (KHUI_ACTION_BASE + 500) - -#define KHUI_PACTION_MENU (KHUI_PACTION_BASE + 0) -#define KHUI_PACTION_UP (KHUI_PACTION_BASE + 1) -#define KHUI_PACTION_DOWN (KHUI_PACTION_BASE + 2) -#define KHUI_PACTION_LEFT (KHUI_PACTION_BASE + 3) -#define KHUI_PACTION_RIGHT (KHUI_PACTION_BASE + 4) -#define KHUI_PACTION_ENTER (KHUI_PACTION_BASE + 5) -#define KHUI_PACTION_ESC (KHUI_PACTION_BASE + 6) -#define KHUI_PACTION_OK (KHUI_PACTION_BASE + 7) -#define KHUI_PACTION_CANCEL (KHUI_PACTION_BASE + 8) -#define KHUI_PACTION_CLOSE (KHUI_PACTION_BASE + 9) -#define KHUI_PACTION_DELETE (KHUI_PACTION_BASE + 10) -#define KHUI_PACTION_UP_EXTEND (KHUI_PACTION_BASE + 11) -#define KHUI_PACTION_UP_TOGGLE (KHUI_PACTION_BASE + 12) -#define KHUI_PACTION_DOWN_EXTEND (KHUI_PACTION_BASE + 13) -#define KHUI_PACTION_DOWN_TOGGLE (KHUI_PACTION_BASE + 14) -#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 - -Stock menus. - -@{*/ -#define KHUI_MENU_BASE (KHUI_ACTION_BASE + 1000) - -#define KHUI_MENU_MAIN (KHUI_MENU_BASE + 0) -#define KHUI_MENU_FILE (KHUI_MENU_BASE + 1) -#define KHUI_MENU_CRED (KHUI_MENU_BASE + 2) -#define KHUI_MENU_VIEW (KHUI_MENU_BASE + 3) -#define KHUI_MENU_OPTIONS (KHUI_MENU_BASE + 4) -#define KHUI_MENU_HELP (KHUI_MENU_BASE + 5) - -#define KHUI_MENU_LAYOUT (KHUI_MENU_BASE + 6) -#define KHUI_MENU_TOOLBARS (KHUI_MENU_BASE + 7) - -#define KHUI_MENU_IDENT_CTX (KHUI_MENU_BASE + 8) -#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) - -#define KHUI_MENU_DESTROY_CRED (KHUI_MENU_BASE + 16) -#define KHUI_MENU_RENEW_CRED (KHUI_MENU_BASE + 17) - -/*@}*/ - -/*! \name Toolbars -@{*/ -#define KHUI_TOOLBAR_BASE (KHUI_ACTION_BASE + 2000) - -#define KHUI_TOOLBAR_STANDARD (KHUI_TOOLBAR_BASE + 0) -/*@}*/ - -/*! \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) -/*@}*/ -/*@}*/ - -#endif +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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_ACTIONDEF_H +#define __KHIMAIRA_ACTIONDEF_H + +/*! \ingroup khui_actions + @{*/ +/*! \defgroup khui_std_actions Standard Actions +@{ */ + +/*!\name Standard actions + @{*/ +#define KHUI_ACTION_BASE 50000 + +#define KHUI_ACTION_PROPERTIES (KHUI_ACTION_BASE + 0) +#define KHUI_ACTION_EXIT (KHUI_ACTION_BASE + 1) +#define KHUI_ACTION_SET_DEF_ID (KHUI_ACTION_BASE + 3) +#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_DEBUG_WINDOW (KHUI_ACTION_BASE + 10) +#define KHUI_ACTION_VIEW_REFRESH (KHUI_ACTION_BASE + 11) +#define KHUI_ACTION_LAYOUT_ID (KHUI_ACTION_BASE + 12) +#define KHUI_ACTION_LAYOUT_TYPE (KHUI_ACTION_BASE + 13) +#define KHUI_ACTION_LAYOUT_LOC (KHUI_ACTION_BASE + 14) +#define KHUI_ACTION_TB_STANDARD (KHUI_ACTION_BASE + 15) +#define KHUI_ACTION_OPT_KHIM (KHUI_ACTION_BASE + 16) +#define KHUI_ACTION_OPT_IDENTS (KHUI_ACTION_BASE + 17) +#define KHUI_ACTION_OPT_NOTIF (KHUI_ACTION_BASE + 18) +#define KHUI_ACTION_HELP_CTX (KHUI_ACTION_BASE + 19) +#define KHUI_ACTION_HELP_CONTENTS (KHUI_ACTION_BASE + 20) +#define KHUI_ACTION_HELP_INDEX (KHUI_ACTION_BASE + 21) +#define KHUI_ACTION_HELP_ABOUT (KHUI_ACTION_BASE + 22) +#define KHUI_ACTION_DESTROY_CRED (KHUI_ACTION_BASE + 23) +#define KHUI_ACTION_RENEW_CRED (KHUI_ACTION_BASE + 24) +#define KHUI_ACTION_OPEN_APP (KHUI_ACTION_BASE + 25) +#define KHUI_ACTION_MENU_ACTIVATE (KHUI_ACTION_BASE + 26) +#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) +#define KHUI_ACTION_OPT_APPEAR (KHUI_ACTION_BASE + 31) +#define KHUI_ACTION_LAYOUT_RELOAD (KHUI_ACTION_BASE + 32) +#define KHUI_ACTION_RENEW_ALL (KHUI_ACTION_BASE + 33) +#define KHUI_ACTION_DESTROY_ALL (KHUI_ACTION_BASE + 34) +#define KHUI_ACTION_UICB (KHUI_ACTION_BASE + 35) +#define KHUI_ACTION_LAYOUT_MINI (KHUI_ACTION_BASE + 36) +/*@}*/ + +/*! \name Pseudo actions + +Pseudo actions do not trigger any specific function, but acts as a +signal of some generic event which will be interpreted based on +context. + +@{*/ +#define KHUI_PACTION_BASE (KHUI_ACTION_BASE + 500) + +#define KHUI_PACTION_MENU (KHUI_PACTION_BASE + 0) +#define KHUI_PACTION_UP (KHUI_PACTION_BASE + 1) +#define KHUI_PACTION_DOWN (KHUI_PACTION_BASE + 2) +#define KHUI_PACTION_LEFT (KHUI_PACTION_BASE + 3) +#define KHUI_PACTION_RIGHT (KHUI_PACTION_BASE + 4) +#define KHUI_PACTION_ENTER (KHUI_PACTION_BASE + 5) +#define KHUI_PACTION_ESC (KHUI_PACTION_BASE + 6) +#define KHUI_PACTION_OK (KHUI_PACTION_BASE + 7) +#define KHUI_PACTION_CANCEL (KHUI_PACTION_BASE + 8) +#define KHUI_PACTION_CLOSE (KHUI_PACTION_BASE + 9) +#define KHUI_PACTION_DELETE (KHUI_PACTION_BASE + 10) +#define KHUI_PACTION_UP_EXTEND (KHUI_PACTION_BASE + 11) +#define KHUI_PACTION_UP_TOGGLE (KHUI_PACTION_BASE + 12) +#define KHUI_PACTION_DOWN_EXTEND (KHUI_PACTION_BASE + 13) +#define KHUI_PACTION_DOWN_TOGGLE (KHUI_PACTION_BASE + 14) +#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 + +Stock menus. + +@{*/ +#define KHUI_MENU_BASE (KHUI_ACTION_BASE + 1000) + +#define KHUI_MENU_MAIN (KHUI_MENU_BASE + 0) +#define KHUI_MENU_FILE (KHUI_MENU_BASE + 1) +#define KHUI_MENU_CRED (KHUI_MENU_BASE + 2) +#define KHUI_MENU_VIEW (KHUI_MENU_BASE + 3) +#define KHUI_MENU_OPTIONS (KHUI_MENU_BASE + 4) +#define KHUI_MENU_HELP (KHUI_MENU_BASE + 5) + +#define KHUI_MENU_LAYOUT (KHUI_MENU_BASE + 6) +#define KHUI_MENU_TOOLBARS (KHUI_MENU_BASE + 7) + +#define KHUI_MENU_IDENT_CTX (KHUI_MENU_BASE + 8) +#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) + +#define KHUI_MENU_DESTROY_CRED (KHUI_MENU_BASE + 16) +#define KHUI_MENU_RENEW_CRED (KHUI_MENU_BASE + 17) + +/*@}*/ + +/*! \name Toolbars +@{*/ +#define KHUI_TOOLBAR_BASE (KHUI_ACTION_BASE + 2000) + +#define KHUI_TOOLBAR_STANDARD (KHUI_TOOLBAR_BASE + 0) +/*@}*/ + +/*! \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) +/*@}*/ +/*@}*/ + +#endif diff --git a/src/windows/identity/uilib/khalerts.h b/src/windows/identity/uilib/khalerts.h index 7f0e624b4..751abce01 100644 --- a/src/windows/identity/uilib/khalerts.h +++ b/src/windows/identity/uilib/khalerts.h @@ -1,403 +1,403 @@ -/* - * 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_KHALERTS_H -#define __KHIMAIRA_KHALERTS_H - -/********************************************************************* - Alerter and error reporting -**********************************************************************/ - -/*! \addtogroup khui -@{ */ - -/*!\defgroup khui_alert Alerter and Error Reporting -@{*/ - -struct tag_khui_alert; -typedef struct tag_khui_alert khui_alert; - -#define KHUI_MAX_ALERT_COMMANDS 4 - -/*! \brief Maximum number of characters in title including terminating NULL - */ -#define KHUI_MAXCCH_TITLE 256 - -/*! \brief Maximum number of bytes in title including terminating NULL - */ -#define KHUI_MAXCB_TITLE (KHUI_MAXCCH_TITLE * sizeof(wchar_t)) - -/*! \brief Maximum number of characters in message including terminating NULL - */ -#define KHUI_MAXCCH_MESSAGE 1024 - -/*! \brief Maximum number of bytes in message including terminating NULL - */ -#define KHUI_MAXCB_MESSAGE (KHUI_MAXCCH_MESSAGE * sizeof(wchar_t)) - -/*! \brief Maxumum number of characters in a suggestion including terminating NULL */ -#define KHUI_MAXCCH_SUGGESTION 1024 - -/*! \brief Maximum number of bytes in a suggestion, including terminating NULL */ -#define KHUI_MAXCB_SUGGESTION (KHUI_MAXCCH_SUGGESTION * sizeof(wchar_t)) - -/*! \brief Flags for an alert */ -enum khui_alert_flags { - KHUI_ALERT_FLAG_FREE_STRUCT =0x00000001, - /*!< Internal. Free the structure once the alert is done. */ - - KHUI_ALERT_FLAG_FREE_TITLE =0x00000002, - /*!< Internal. Free the \a title field when the alert is done.*/ - - KHUI_ALERT_FLAG_FREE_MESSAGE =0x00000004, - /*!< Internal. Free the \a message field when the alert is done. */ - - KHUI_ALERT_FLAG_FREE_SUGGEST =0x00000008, - /*!< Internal. Free the \a suggest field when the alert is done */ - - KHUI_ALERT_FLAG_DEFACTION =0x00000010, - /*!< If the message is displayed as a balloon prompt, then perform - the default action when it is clicked. The default action is - the first action added to the alert. Cannot be used if there - are no actions or if ::KHUI_ALERT_FLAG_REQUEST_WINDOW is - specified.*/ - - KHUI_ALERT_FLAG_DISPATCH_CMD =0x00000020, - /*!< If the message has commands, when the user clicks on one of - the command buttons, the corresponding command will be - immediately dispatched as if khui_action_trigger() is called - with a NULL UI context. Otherwise, the selected command will be - stored in the alert and can be retrieved via a call to - khui_alert_get_response(). */ - - KHUI_ALERT_FLAG_VALID_TARGET =0x00010000, - /*!< Internal. There is a valid target for the alert */ - - KHUI_ALERT_FLAG_VALID_ERROR =0x00020000, - /*!< Internal. There is a valid error context associated with the alert */ - - KHUI_ALERT_FLAG_DISPLAY_WINDOW =0x01000000, - /*!< The alert has been displayed in a window */ - - KHUI_ALERT_FLAG_DISPLAY_BALLOON =0x02000000, - /*!< The alert has been displayed in a ballon */ - - KHUI_ALERT_FLAG_REQUEST_WINDOW =0x04000000, - /*!< The alert should be displayed in a window */ - - KHUI_ALERT_FLAG_REQUEST_BALLOON =0x08000000, - /*!< The alert should be displayed in a balloon */ - - KHUI_ALERT_FLAG_MODAL =0x10000000, - /*!< Internal. Modal alert. Do not set direclty. */ - - KHUI_ALERT_FLAGMASK_RDWR =0x0C000030, - /*!< Bit mask of flags that can be set by khui_alert_set_flags() */ -}; - -/*! \brief Alert types - - These types can be set with khui_alert_set_type() to indicate - which type of alert this is. The types defined here are - identified by the Network Identity Manager and will receive - special handling whereever appropriate. - - The type is a hint to the application and will not guarantee a - particular behavior. - */ -typedef enum tag_khui_alert_types { - KHUI_ALERTTYPE_NONE = 0, /*!< No specific alert type */ - KHUI_ALERTTYPE_PLUGIN, /*!< Plug-in or module load related - alert */ - KHUI_ALERTTYPE_EXPIRE, /*!< Credential or identity expiration - warning */ - KHUI_ALERTTYPE_RENEWFAIL, /*!< Failed to renew credentials */ - KHUI_ALERTTYPE_ACQUIREFAIL, /*!< Failed to acquire credentials */ - KHUI_ALERTTYPE_CHPW, /*!< Failed to change password */ -} khui_alert_type; - -/*! \brief Create an empty alert object - - The returned result is a held pointer to a ::khui_alert object. - Use khui_alert_release() to release the object. - */ -KHMEXP khm_int32 KHMAPI -khui_alert_create_empty(khui_alert ** result); - -/*! \brief Create a simple alert object - - The returned result is a held pointer to a ::khui_alert object. - Use khui_alert_release() to release the object. - - \param[in] title The title of the alert. (Required, Localized) - Limited by ::KHUI_MAXCCH_TITLE. - - \param[in] message The message. (Required. Localized). Limited - by ::KHUI_MAXCCH_MESSAGE. - - \param[in] severity One of ::tag_kherr_severity - - \param[out] result Receives a held pointer to a ::khui_alert - object upon successful completion. - */ -KHMEXP khm_int32 KHMAPI -khui_alert_create_simple(const wchar_t * title, - const wchar_t * message, - khm_int32 severity, - khui_alert ** result); - -/*! \brief Set the title of an alert object - - The title is limited by ::KHUI_MAXCCH_TITLE. - */ -KHMEXP khm_int32 KHMAPI -khui_alert_set_title(khui_alert * alert, - const wchar_t * title); - -/*! \brief Set the message of an alert object - - The message is limited by ::KHUI_MAXCCH_MESSAGE. - */ -KHMEXP khm_int32 KHMAPI -khui_alert_set_message(khui_alert * alert, - const wchar_t * message); - -/*! \brief Set the suggestion of an alert object - - The suggestion is limited by ::KHUI_MAXCCH_SUGGESTION - */ -KHMEXP khm_int32 KHMAPI -khui_alert_set_suggestion(khui_alert * alert, - const wchar_t * suggestion); - -/*! \brief Set the severity of the alert object - - The severity value is one of ::tag_kherr_severity - */ -KHMEXP khm_int32 KHMAPI -khui_alert_set_severity(khui_alert * alert, - khm_int32 severity); - -/*! \brief Sets the flags of the alert - - The flags are as defined in ::khui_alert_flags. The bits that are - on in \a mask will be set to the corresponding values in \a flags. - Only the bits specified in ::KHUI_ALERT_FLAGMASK_RDWR can be - specified in \a mask. - */ -KHMEXP khm_int32 KHMAPI -khui_alert_set_flags(khui_alert * alert, khm_int32 mask, khm_int32 flags); - -/*! \brief Clear all the commands from an alert object - - \see khui_alert_add_command() - */ -KHMEXP khm_int32 KHMAPI -khui_alert_clear_commands(khui_alert * alert); - -/*! \brief Add a command to an alert object - - The command ID should be a valid registered action. - */ -KHMEXP khm_int32 KHMAPI -khui_alert_add_command(khui_alert * alert, - khm_int32 command_id); - -/*! \brief Set the type of alert - */ -KHMEXP khm_int32 KHMAPI -khui_alert_set_type(khui_alert * alert, - khui_alert_type type); - -/*! \brief Set the action context for the alert */ -KHMEXP khm_int32 KHMAPI -khui_alert_set_ctx(khui_alert * alert, - khui_scope scope, - khm_handle identity, - khm_int32 cred_type, - khm_handle cred); - -/*! \brief Get the response code from an alert - - Once an alert has been displayed to the user, the user may choose - a command from the list of commands provided in the alert (see - khui_alert_add_command() ). This function can retrieve the - selected command from the alert. - - \return The selected command or \a 0 if no commands were selected. - */ -KHMEXP khm_int32 KHMAPI -khui_alert_get_response(khui_alert * alert); - - -/*! \brief Display an alert - - The alert must have a valid \a severity, \a title and a \a message - to be displayed. Otherwise the function immediately returns with - a failure code. - - The method used to display the alert is as follows: - - - A balloon alert will be shown if one of the following is true: - - The NetIDMgr application is minimized or in the background. - - ::KHUI_ALERT_FLAG_REQUEST_BALLOON is specified in \a flags. - - Otherwise an alert window will be shown. - - If the message, title of the alert is too long to fit in a balloon - prompt, there's a suggestion or if there are custom commands then - a placeholder balloon prompt will be shown which when clicked on, - shows the actual alert in an alert window. - - An exception is when ::KHUI_ALERT_FLAG_DEFACTION is specified in - flags. In this case instead of a placeholder balloon prompt, one - will be shown with the actual title and message (truncated if - necessary). Clicking on the balloon will cause the first command - in the command list to be performed. - - The placeholder balloon prompt will have a title derived from the - first 63 characters of the \a title field in the alert and a - message notifying the user that they should click the balloon - prompt for more information. - - To this end, it is beneficial to limit the length of the title to - 63 characters (64 counting the terminating NULL). This limit is - enforced on Windows. Also, try to make the title descriptive. - - User interaction with the alert will be as follows: - - - If the alert contains no commands, then the alert will be - displayed to the user as described above. A 'close' button will - be added to the alert if the alert is being displayed in a - window. - - - If the alert contains commands, has the - ::KHUI_ALERT_FLAG_DEFACTION flag set and is displayed in a - balloon and the user clicks on it, the first command in the - command list will be executed. - - - If the alert contains commands and does not have the - ::KHUI_ALERT_FLAG_DEFACTION and has the - ::KHUI_ALERT_FLAG_DISPATCH_CMD flag set, then when the user - selects one of the command buttons, the corresponding command - will immediately be dispatched. (see - ::KHUI_ALERT_FLAG_DISPATCH_CMD). - - - If the alert contains command and have neither - ::KHUI_ALERT_FLAG_DEFACTION nor ::KHUI_ALERT_FLAG_DISPATCH_CMD, - then when the user selects one of the command buttons, the - selected command will be stored along with the alert. It can be - retrieved via a call to khui_alert_get_response(). - - */ -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). - - */ -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 - and the status bar updated to notify the user that there is a - pending alert. Once the user activates the pending alert, it will - be displayed as if khui_alert_show() was called. - */ -KHMEXP khm_int32 KHMAPI -khui_alert_queue(khui_alert * alert); - -/*! \brief Display a simple alert - - \see khui_alert_show() - */ -KHMEXP khm_int32 KHMAPI -khui_alert_show_simple(const wchar_t * title, - const wchar_t * message, - khm_int32 severity); - -/*! \brief Obtain a hold on the alert - - An alert structure is only considered valid for the duration that - there is a hold on it. - - Use khui_alert_release() to release the hold. - */ -KHMEXP khm_int32 KHMAPI -khui_alert_hold(khui_alert * alert); - -/*! \brief Release the hold on the alert - - Holds obtained on an alert using any of the functions that either - return a held pointer to an alert or implicitly obtains a hold on - it need to be undone through a call to khui_alert_release(). - */ -KHMEXP khm_int32 KHMAPI -khui_alert_release(khui_alert * alert); - -/*! \brief Lock an alert - - Locking an alert disallows any other thread from accessing the - alert at the same time. NetIDMgr keeps a global list of all alert - objects and the user interface may access any of them at various - points in time. Locking the alert allows a thread to modify an - alert without causing another thread to be exposed to an - inconsistent state. - - Once a thread obtains a lock on the alert, it must call - khui_alert_unlock() to unlock it. Otherwise no other thread will - be able to access the alert. - - \note Currently the alert lock is global. Locking one alert - disallows access to all other alerts as well. - - \note Calling khui_alert_lock() is only necessary if you are - accessing the ::khui_alert structure directly. Calling any of - the khui_alert_* functions to modify the alert does not - require obtaining a lock, as they perform synchronization - internally. -*/ -KHMEXP void KHMAPI -khui_alert_lock(khui_alert * alert); - -/*! \brief Unlock an alert - - \see khui_alert_lock() -*/ -KHMEXP void KHMAPI -khui_alert_unlock(khui_alert * alert); - -/*!@}*/ -/*!@}*/ - -#endif +/* + * 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_KHALERTS_H +#define __KHIMAIRA_KHALERTS_H + +/********************************************************************* + Alerter and error reporting +**********************************************************************/ + +/*! \addtogroup khui +@{ */ + +/*!\defgroup khui_alert Alerter and Error Reporting +@{*/ + +struct tag_khui_alert; +typedef struct tag_khui_alert khui_alert; + +#define KHUI_MAX_ALERT_COMMANDS 4 + +/*! \brief Maximum number of characters in title including terminating NULL + */ +#define KHUI_MAXCCH_TITLE 256 + +/*! \brief Maximum number of bytes in title including terminating NULL + */ +#define KHUI_MAXCB_TITLE (KHUI_MAXCCH_TITLE * sizeof(wchar_t)) + +/*! \brief Maximum number of characters in message including terminating NULL + */ +#define KHUI_MAXCCH_MESSAGE 1024 + +/*! \brief Maximum number of bytes in message including terminating NULL + */ +#define KHUI_MAXCB_MESSAGE (KHUI_MAXCCH_MESSAGE * sizeof(wchar_t)) + +/*! \brief Maxumum number of characters in a suggestion including terminating NULL */ +#define KHUI_MAXCCH_SUGGESTION 1024 + +/*! \brief Maximum number of bytes in a suggestion, including terminating NULL */ +#define KHUI_MAXCB_SUGGESTION (KHUI_MAXCCH_SUGGESTION * sizeof(wchar_t)) + +/*! \brief Flags for an alert */ +enum khui_alert_flags { + KHUI_ALERT_FLAG_FREE_STRUCT =0x00000001, + /*!< Internal. Free the structure once the alert is done. */ + + KHUI_ALERT_FLAG_FREE_TITLE =0x00000002, + /*!< Internal. Free the \a title field when the alert is done.*/ + + KHUI_ALERT_FLAG_FREE_MESSAGE =0x00000004, + /*!< Internal. Free the \a message field when the alert is done. */ + + KHUI_ALERT_FLAG_FREE_SUGGEST =0x00000008, + /*!< Internal. Free the \a suggest field when the alert is done */ + + KHUI_ALERT_FLAG_DEFACTION =0x00000010, + /*!< If the message is displayed as a balloon prompt, then perform + the default action when it is clicked. The default action is + the first action added to the alert. Cannot be used if there + are no actions or if ::KHUI_ALERT_FLAG_REQUEST_WINDOW is + specified.*/ + + KHUI_ALERT_FLAG_DISPATCH_CMD =0x00000020, + /*!< If the message has commands, when the user clicks on one of + the command buttons, the corresponding command will be + immediately dispatched as if khui_action_trigger() is called + with a NULL UI context. Otherwise, the selected command will be + stored in the alert and can be retrieved via a call to + khui_alert_get_response(). */ + + KHUI_ALERT_FLAG_VALID_TARGET =0x00010000, + /*!< Internal. There is a valid target for the alert */ + + KHUI_ALERT_FLAG_VALID_ERROR =0x00020000, + /*!< Internal. There is a valid error context associated with the alert */ + + KHUI_ALERT_FLAG_DISPLAY_WINDOW =0x01000000, + /*!< The alert has been displayed in a window */ + + KHUI_ALERT_FLAG_DISPLAY_BALLOON =0x02000000, + /*!< The alert has been displayed in a ballon */ + + KHUI_ALERT_FLAG_REQUEST_WINDOW =0x04000000, + /*!< The alert should be displayed in a window */ + + KHUI_ALERT_FLAG_REQUEST_BALLOON =0x08000000, + /*!< The alert should be displayed in a balloon */ + + KHUI_ALERT_FLAG_MODAL =0x10000000, + /*!< Internal. Modal alert. Do not set direclty. */ + + KHUI_ALERT_FLAGMASK_RDWR =0x0C000030, + /*!< Bit mask of flags that can be set by khui_alert_set_flags() */ +}; + +/*! \brief Alert types + + These types can be set with khui_alert_set_type() to indicate + which type of alert this is. The types defined here are + identified by the Network Identity Manager and will receive + special handling whereever appropriate. + + The type is a hint to the application and will not guarantee a + particular behavior. + */ +typedef enum tag_khui_alert_types { + KHUI_ALERTTYPE_NONE = 0, /*!< No specific alert type */ + KHUI_ALERTTYPE_PLUGIN, /*!< Plug-in or module load related + alert */ + KHUI_ALERTTYPE_EXPIRE, /*!< Credential or identity expiration + warning */ + KHUI_ALERTTYPE_RENEWFAIL, /*!< Failed to renew credentials */ + KHUI_ALERTTYPE_ACQUIREFAIL, /*!< Failed to acquire credentials */ + KHUI_ALERTTYPE_CHPW, /*!< Failed to change password */ +} khui_alert_type; + +/*! \brief Create an empty alert object + + The returned result is a held pointer to a ::khui_alert object. + Use khui_alert_release() to release the object. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_create_empty(khui_alert ** result); + +/*! \brief Create a simple alert object + + The returned result is a held pointer to a ::khui_alert object. + Use khui_alert_release() to release the object. + + \param[in] title The title of the alert. (Required, Localized) + Limited by ::KHUI_MAXCCH_TITLE. + + \param[in] message The message. (Required. Localized). Limited + by ::KHUI_MAXCCH_MESSAGE. + + \param[in] severity One of ::tag_kherr_severity + + \param[out] result Receives a held pointer to a ::khui_alert + object upon successful completion. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_create_simple(const wchar_t * title, + const wchar_t * message, + khm_int32 severity, + khui_alert ** result); + +/*! \brief Set the title of an alert object + + The title is limited by ::KHUI_MAXCCH_TITLE. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_set_title(khui_alert * alert, + const wchar_t * title); + +/*! \brief Set the message of an alert object + + The message is limited by ::KHUI_MAXCCH_MESSAGE. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_set_message(khui_alert * alert, + const wchar_t * message); + +/*! \brief Set the suggestion of an alert object + + The suggestion is limited by ::KHUI_MAXCCH_SUGGESTION + */ +KHMEXP khm_int32 KHMAPI +khui_alert_set_suggestion(khui_alert * alert, + const wchar_t * suggestion); + +/*! \brief Set the severity of the alert object + + The severity value is one of ::tag_kherr_severity + */ +KHMEXP khm_int32 KHMAPI +khui_alert_set_severity(khui_alert * alert, + khm_int32 severity); + +/*! \brief Sets the flags of the alert + + The flags are as defined in ::khui_alert_flags. The bits that are + on in \a mask will be set to the corresponding values in \a flags. + Only the bits specified in ::KHUI_ALERT_FLAGMASK_RDWR can be + specified in \a mask. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_set_flags(khui_alert * alert, khm_int32 mask, khm_int32 flags); + +/*! \brief Clear all the commands from an alert object + + \see khui_alert_add_command() + */ +KHMEXP khm_int32 KHMAPI +khui_alert_clear_commands(khui_alert * alert); + +/*! \brief Add a command to an alert object + + The command ID should be a valid registered action. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_add_command(khui_alert * alert, + khm_int32 command_id); + +/*! \brief Set the type of alert + */ +KHMEXP khm_int32 KHMAPI +khui_alert_set_type(khui_alert * alert, + khui_alert_type type); + +/*! \brief Set the action context for the alert */ +KHMEXP khm_int32 KHMAPI +khui_alert_set_ctx(khui_alert * alert, + khui_scope scope, + khm_handle identity, + khm_int32 cred_type, + khm_handle cred); + +/*! \brief Get the response code from an alert + + Once an alert has been displayed to the user, the user may choose + a command from the list of commands provided in the alert (see + khui_alert_add_command() ). This function can retrieve the + selected command from the alert. + + \return The selected command or \a 0 if no commands were selected. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_get_response(khui_alert * alert); + + +/*! \brief Display an alert + + The alert must have a valid \a severity, \a title and a \a message + to be displayed. Otherwise the function immediately returns with + a failure code. + + The method used to display the alert is as follows: + + - A balloon alert will be shown if one of the following is true: + - The NetIDMgr application is minimized or in the background. + - ::KHUI_ALERT_FLAG_REQUEST_BALLOON is specified in \a flags. + - Otherwise an alert window will be shown. + + If the message, title of the alert is too long to fit in a balloon + prompt, there's a suggestion or if there are custom commands then + a placeholder balloon prompt will be shown which when clicked on, + shows the actual alert in an alert window. + + An exception is when ::KHUI_ALERT_FLAG_DEFACTION is specified in + flags. In this case instead of a placeholder balloon prompt, one + will be shown with the actual title and message (truncated if + necessary). Clicking on the balloon will cause the first command + in the command list to be performed. + + The placeholder balloon prompt will have a title derived from the + first 63 characters of the \a title field in the alert and a + message notifying the user that they should click the balloon + prompt for more information. + + To this end, it is beneficial to limit the length of the title to + 63 characters (64 counting the terminating NULL). This limit is + enforced on Windows. Also, try to make the title descriptive. + + User interaction with the alert will be as follows: + + - If the alert contains no commands, then the alert will be + displayed to the user as described above. A 'close' button will + be added to the alert if the alert is being displayed in a + window. + + - If the alert contains commands, has the + ::KHUI_ALERT_FLAG_DEFACTION flag set and is displayed in a + balloon and the user clicks on it, the first command in the + command list will be executed. + + - If the alert contains commands and does not have the + ::KHUI_ALERT_FLAG_DEFACTION and has the + ::KHUI_ALERT_FLAG_DISPATCH_CMD flag set, then when the user + selects one of the command buttons, the corresponding command + will immediately be dispatched. (see + ::KHUI_ALERT_FLAG_DISPATCH_CMD). + + - If the alert contains command and have neither + ::KHUI_ALERT_FLAG_DEFACTION nor ::KHUI_ALERT_FLAG_DISPATCH_CMD, + then when the user selects one of the command buttons, the + selected command will be stored along with the alert. It can be + retrieved via a call to khui_alert_get_response(). + + */ +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). + + */ +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 + and the status bar updated to notify the user that there is a + pending alert. Once the user activates the pending alert, it will + be displayed as if khui_alert_show() was called. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_queue(khui_alert * alert); + +/*! \brief Display a simple alert + + \see khui_alert_show() + */ +KHMEXP khm_int32 KHMAPI +khui_alert_show_simple(const wchar_t * title, + const wchar_t * message, + khm_int32 severity); + +/*! \brief Obtain a hold on the alert + + An alert structure is only considered valid for the duration that + there is a hold on it. + + Use khui_alert_release() to release the hold. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_hold(khui_alert * alert); + +/*! \brief Release the hold on the alert + + Holds obtained on an alert using any of the functions that either + return a held pointer to an alert or implicitly obtains a hold on + it need to be undone through a call to khui_alert_release(). + */ +KHMEXP khm_int32 KHMAPI +khui_alert_release(khui_alert * alert); + +/*! \brief Lock an alert + + Locking an alert disallows any other thread from accessing the + alert at the same time. NetIDMgr keeps a global list of all alert + objects and the user interface may access any of them at various + points in time. Locking the alert allows a thread to modify an + alert without causing another thread to be exposed to an + inconsistent state. + + Once a thread obtains a lock on the alert, it must call + khui_alert_unlock() to unlock it. Otherwise no other thread will + be able to access the alert. + + \note Currently the alert lock is global. Locking one alert + disallows access to all other alerts as well. + + \note Calling khui_alert_lock() is only necessary if you are + accessing the ::khui_alert structure directly. Calling any of + the khui_alert_* functions to modify the alert does not + require obtaining a lock, as they perform synchronization + internally. +*/ +KHMEXP void KHMAPI +khui_alert_lock(khui_alert * alert); + +/*! \brief Unlock an alert + + \see khui_alert_lock() +*/ +KHMEXP void KHMAPI +khui_alert_unlock(khui_alert * alert); + +/*!@}*/ +/*!@}*/ + +#endif diff --git a/src/windows/identity/uilib/khconfigui.h b/src/windows/identity/uilib/khconfigui.h index efe14789d..bbc712a36 100644 --- a/src/windows/identity/uilib/khconfigui.h +++ b/src/windows/identity/uilib/khconfigui.h @@ -1,627 +1,627 @@ -/* - * 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_KHCONFIGUI_H -#define __KHIMAIRA_KHCONFIGUI_H - -/*! \addtogroup khui -@{ */ - -/*! \defgroup khui_cfg Configuration Panels - - Configuration panels are the primary means from which the user is - presented with an interface to change NetIDMgr and plugin - configuration. - -@{ */ - -/*! \brief Configuration window notification message - - This is the message that will be used to notify dialog panels. - - The format of the message is : - - uMsg : KHUI_WM_CFG_NOTIFY - - HIWORD(wParam) : one of ::khui_wm_cfg_notifications - - \note This is the same as ::KHUI_WM_NC_NOTIFY - */ -#define KHUI_WM_CFG_NOTIFY (WM_APP + 0x101) - -/*! \brief Configuration notifications - - These are sent thorugh a ::KHUI_WM_CFG_NOTIFY message. - - The format of the message is : - - uMsg : KHUI_WM_CFG_NOTIFY - - HIWORD(wParam) : one of ::khui_wm_cfg_notifications - */ -enum khui_wm_cfg_notifications { - WMCFG_SHOW_NODE = 1, - /*!< Sent to the configuration dialog to request that the panel - for the specified node be shown. The \a lParam message - parameter will contain a held ::khui_config_node handle. The - sender of the mssage is responsible for releasing the handle.*/ - - WMCFG_UPDATE_STATE = 2, - /*!< Sent to the configuration dialog to indicate that the state - flags for the specified configuration node have changed. - - - LOWORD(wParam) : new flags - - lParam : ::khui_config_node for the node*/ - - WMCFG_APPLY = 3, - /*!< Sent to all the configuration panels when the user clicks the - 'Apply' button or the 'Ok' button. The panels are responsible - for applying the configuration changes and updating their flags - using khui_cfg_set_flags(). */ - - WMCFG_SYNC_NODE_LIST = 4, - /*!< Sent from the UI library to the configuration window to - notify the window that the node list has changed. This message - is sent synchronously before the node is removed. */ -}; - -/*! \brief Registration information for a configuration node - - \see khui_cfg_register_node() -*/ -typedef struct tag_khui_config_node_reg { - const wchar_t * name; /*!< Internal identifier - (not-localized, required). The name - is required to be unique among - sibling nodes. However it is not - required to be unique globally. The - size of the name is constrained by - ::KHUI_MAXCCH_NAME*/ - - const wchar_t * short_desc; /*!< Short description (Localized, - required). This is the name which - identifies the node within a - collection of siblings. The size of - the string is constrained by - ::KHUI_MAXCCH_SHORT_DESC*/ - - const wchar_t * long_desc; /*!< Global name of the node. - (Localized, required). This - uniquely identifies the node in the - collection of all configuration - nodes. The size of the string is - constrained by - ::KHUI_MAXCCH_LONG_DESC.*/ - - HMODULE h_module; /*!< Module which contains the dialog - resource specified in \a - dlg_template */ - - LPWSTR dlg_template; /*!< Dialog template for the - configuration window */ - - DLGPROC dlg_proc; /*!< Dialog procedure */ - - khm_int32 flags; /*!< Flags. Can be a combination of - ::KHUI_CNFLAG_SORT_CHILDREN and - ::KHUI_CNFLAG_SUBPANEL*/ - -} khui_config_node_reg; - -/*! \brief Sort the child nodes by short description */ -#define KHUI_CNFLAG_SORT_CHILDREN 0x0001 - -/*! \brief Is a subpanel */ -#define KHUI_CNFLAG_SUBPANEL 0x0002 - -/*! \brief Node represents a panel that is replicated for all child nodes */ -#define KHUI_CNFLAG_PLURAL 0x0004 - -/*! \brief System node - - \note For internal use by the NetIDMgr application. Do not use. -*/ -#define KHUI_CNFLAG_SYSTEM 0x0010 - -/*! \brief Settings have been modified - - Settings for this configuration panel have been modified. This - flag should be cleared once the settings have been successfully - applied. - */ -#define KHUI_CNFLAG_MODIFIED 0x0100 - -/*! \brief Settings have been applied - - Set once any modified settings were successfully applied. - */ -#define KHUI_CNFLAG_APPLIED 0x0200 - -#define KHUI_CNFLAGMASK_STATIC 0x00ff -#define KHUI_CNFLAGMASK_DYNAMIC 0x0f00 - -/*! \brief Maximum length of the name in characters - - The length includes the terminating NULL - */ -#define KHUI_MAXCCH_NAME 256 - -/*! \brief Maximum length of the name in bytes - - The length includes the terminating NULL - */ -#define KHUI_MAXCB_NAME (KHUI_MAXCCH_NAME * sizeof(wchar_t)) - -/*! \brief Maximum length of the long description in characters - - The length includes the terminating NULL - */ -#define KHUI_MAXCCH_LONG_DESC 1024 - -/*! \brief Maximum length of the long description in bytes - - The length includes the terminating NULL - */ -#define KHUI_MAXCB_LONG_DESC (KHUI_MAXCCH_LONG_DESC * sizeof(wchar_t)) - -/*! \brief Maximum length of the short description in chracters - - The length includes the terminating NULL - */ -#define KHUI_MAXCCH_SHORT_DESC 256 - -/*! \brief Maximum length of the short description in bytes - - The length includes the terminating NULL - */ -#define KHUI_MAXCB_SHORT_DESC (KHUI_MAXCCH_SHORT_DESC * sizeof(wchar_t)) - -/*! \brief Width of a configuration dialog in dialog units - - ::CFGDLG_WIDTH and ::CFGDLG_HEIGHT specify the dimensions of a - configuration dialog width and height in dialog units. The dialog - will be created as a child of the configuration dialog and placed - within it. - */ -#define CFGDLG_WIDTH 255 - -/*! \brief Height of a configuration dialog in dialog units - - \see ::CFGDLG_WIDTH -*/ -#define CFGDLG_HEIGHT 182 - -/*! \brief Width of a configuration tab dialog in dialog units - - ::CFGDLG_TAB_WIDTH and ::CFGDLG_TAB_HEIGHT specify the dimensions - (in dialog units) of a dialog that will be placed within a tab - control for dialogs where multiple display panels need to be - shown. - */ -#define CFGDLG_TAB_WIDTH 235 - -/*! \brief Height of configuration tab dialog in dialog units - - \see ::CFGDLG_TAB_WIDTH - */ -#define CFGDLG_TAB_HEIGHT 151 - -/*! \brief A handle to a configuration node - - \see khui_cfg_open_node(), khui_cfg_close_node() -*/ -typedef khm_handle khui_config_node; - -/*! \brief Initialization data passed in to a subpanel - - When creating a subpanel, a pointer to the following strucutred - will be passed in as the creation parameter for the dialog. -*/ -typedef struct tag_khui_config_init_data { - khui_config_node ctx_node; /*!< The node under which the current - dialog subpanel is being created. */ - - khui_config_node this_node; /*!< The node which provided the - registration information for the - creation of the subpanel. */ - - khui_config_node ref_node; /*!< The parent node of the subpanel - node. In nodes which have the - ::KHUI_CNFLAG_PLURAL, this would be - different from the \a node. This is - the node under which the subpanel - was registered. */ -} khui_config_init_data; - -/*! \brief Register a configuration node - - The caller fills the registration information in the - ::khui_config_node_reg structre. If the call succeeds, the - function will return KHM_ERROR_SUCCESS. - - \param[in] parent Parent of the node to be registered. Set to - NULL if the parent is the root node. - - \param[in] reg Registration information - - \param[out] new_id Receives the new unique identifier of the - configuration node. Pass in NULL if the new identifier is not - required. - - \retval KHM_ERROR_SUCCESS Success - \retval KHM_ERROR_INVALID_PARAM One or more parameters, or fields - 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, - const khui_config_node_reg * reg); - -/*!\brief Open a configuration node by name - - If successful, the \a result parameter will receive a handle to - the configuration node. Use khui_cfg_release() to release - the handle. - - \param[in] parent Parent node. Set to NULL to specify root node. - */ -KHMEXP khm_int32 KHMAPI -khui_cfg_open(khui_config_node parent, - const wchar_t * name, - khui_config_node * result); - -/*! \brief Remove a configuration node - - Marks a configuration node as deleted. Once all the handles, - including the handle specified in \a node have been released, it - will be deleted. - */ -KHMEXP khm_int32 KHMAPI -khui_cfg_remove(khui_config_node node); - -/*! \brief Hold a handle to a configuration node - - Obtains an additional hold on the handle specified by \a node. - The hold must be released with a call to \a - khui_cfg_release() - */ -KHMEXP khm_int32 KHMAPI -khui_cfg_hold(khui_config_node node); - -/*! \brief Release a handle to a configuration node - - \see khui_cfg_hold() - */ -KHMEXP khm_int32 KHMAPI -khui_cfg_release(khui_config_node node); - -/*! \brief Get the parent of a node - - Returns a held handle to the parent of the node, or NULL if the - current node is a top level node. The returned handle must be - released with khui_cfg_release(). - - \retval KHM_ERROR_SUCCESS The handle to the parent node is in \a result - \retval KHM_ERROR_NOT_FOUND The node is a top level node - */ -KHMEXP khm_int32 KHMAPI -khui_cfg_get_parent(khui_config_node vnode, - khui_config_node * result); - -/*! \brief Get a handle to the first child node - - If the call is successful, \a result will receieve a handle to the - first child node of the specified node. The returned handle must - be released with a call to khui_cfg_release() - - If \a parent does not have any child nodes, the function will - return KHM_ERROR_NOT_FOUND and set \a result to NULL. - - \param[in] parent Parent node. Set to NULL to specify root node. - \param[out] result Receives a held handle to the first child node. - - \see khui_cfg_get_next() - */ -KHMEXP khm_int32 KHMAPI -khui_cfg_get_first_child(khui_config_node parent, - khui_config_node * result); - -/*! \brief Get a handle to the first subpanel - - If the call is successful, \a result will receieve a handle to the - first subpanel node of the specified node. The returned handle - must be released with a call to khui_cfg_release() - - If \a parent does not have any subpanels, the function will return - KHM_ERROR_NOT_FOUND and set \a result to NULL. - - A subpanel node is a node which has the ::KHUI_CNFLAG_SUBPANEL - flag set. - - \param[in] parent Parent node. Set to NULL to specify root node. - \param[out] result Receives a held handle to the first subpanel node. - - \see khui_cfg_get_next() - */ -KHMEXP khm_int32 KHMAPI -khui_cfg_get_first_subpanel(khui_config_node vparent, - khui_config_node * result); - -/*! \brief Get a handle to the next sibling node - - If the call is successful, \a result will receive a held handle to - the next sibling node. The returned handle must be released with - a call to khui_cfg_release(). - - If there are no more sibling nodes, then the function return - KHM_ERROR_NOT_FOUND and set \a result to NULL. - - This function can be used to traverse a list of child nodes as - well as a list of subpanel nodes. - - */ -KHMEXP khm_int32 KHMAPI -khui_cfg_get_next(khui_config_node node, - khui_config_node * result); - -/*! \brief Get a handle to the next sibling node - - Similar to khui_cfg_get_next(), but implicitly releases the handle - that was supplied. Equivalent to doing : - - \code - khui_cfg_get_next(node, &next); - khui_cfg_release(node); - node = next; - \endcode - - \param[in,out] node On entry, specifies the node whose sibling - needs to be fetched. On exit, will have either NULL or a held - handle to the sibling node. The handle which was supplied to - the function is released. - - \retval KHM_ERROR_SUCCESS The next node is now in \a node - \retval KHM_ERROR_INVALID_PARAM \a node was not a valid handle - \retval KHM_ERROR_NOT_FOUND There are no more siblings. \a node - is set to NULL. - - \note Even if there are no more siblings, the handle specified in - \a node on entry is released. - */ -KHMEXP khm_int32 KHMAPI -khui_cfg_get_next_release(khui_config_node * node); - -/*! \brief Get the name of a configuration node - - Gets the name (not the short description or the long description) - of the given configuration node. -*/ -KHMEXP khm_int32 KHMAPI -khui_cfg_get_name(khui_config_node node, - wchar_t * buf, - khm_size * cb_buf); - -/*! \brief Get registration information for a node - - The registration information that is returned is a shallow copy of - the data kept by NetIDMgr. In particular, the strings that will - be returned actually point to internal buffers and should not be - modified. - - No further action is necessary to release the information. - However, the returned data ceases to be valid when \a node is - released with a call to khui_cfg_release(). - - \param[in] node Node for which information is requested. Can be NULL if requesting information about the root node. - \param[out] reg Pointer to a ::khui_config_node_reg structure. - */ -KHMEXP khm_int32 KHMAPI -khui_cfg_get_reg(khui_config_node node, - khui_config_node_reg * reg); - -/*! \brief Internal use - - This function is used internally by NetIDMgr. Do not use. -*/ -KHMEXP HWND KHMAPI -khui_cfg_get_hwnd_inst(khui_config_node node, - khui_config_node noderef); - -/*! \brief Internal use - - This function is used internally by NetIDMgr. Do not use. -*/ -KHMEXP LPARAM KHMAPI -khui_cfg_get_param_inst(khui_config_node node, - khui_config_node noderef); - -/*! \brief Internal use - - This function is used internally by NetIDMgr. Do not use. -*/ -KHMEXP void KHMAPI -khui_cfg_set_hwnd_inst(khui_config_node node, - khui_config_node noderef, - HWND hwnd); - -/*! \brief Internal use - - This function is used internally by NetIDMgr. Do not use. -*/ -KHMEXP void KHMAPI -khui_cfg_set_param_inst(khui_config_node node, - khui_config_node noderef, - LPARAM param); - -/*! \brief Internal use - - This function is used internally by NetIDMgr. Do not use. -*/ -KHMEXP HWND KHMAPI -khui_cfg_get_hwnd(khui_config_node node); - -/*! \brief Internal use - - This function is used internally by NetIDMgr. Do not use. -*/ -KHMEXP LPARAM KHMAPI -khui_cfg_get_param(khui_config_node node); - -/*! \brief Internal use - - This function is used internally by NetIDMgr. Do not use. -*/ -KHMEXP void KHMAPI -khui_cfg_set_hwnd(khui_config_node node, HWND hwnd); - -/*! \brief Internal use - - This function is used internally by NetIDMgr. Do not use. -*/ -KHMEXP void KHMAPI -khui_cfg_set_param(khui_config_node node, LPARAM param); - -/*! \brief Internal use - - This function is used internally by NetIDMgr. Do not use. -*/ -KHMEXP void KHMAPI -khui_cfg_clear_params(void); - -/*! \brief Internal use - - This function is used internally by NetIDMgr. Do not use. -*/ -KHMEXP void KHMAPI -khui_cfg_set_configui_handle(HWND hwnd); - -/*! \brief Update the state for the specified node - - \param[in] node ::khui_config_node handle for the configuration node. - - \param[in] flags New flags. Combination of ::KHUI_CNFLAG_APPLIED and ::KHUI_CNFLAG_MODIFIED - - \param[in] mask Valid bits in \a flags - - \note Should only be called from within the dialog procedure for - the configuration node. - */ -KHMEXP void KHMAPI -khui_cfg_set_flags(khui_config_node vnode, khm_int32 flags, khm_int32 mask); - -/*! \brief Retrieve the state flags for the configuration node - - \see khui_cfg_set_flags() - */ -KHMEXP khm_int32 KHMAPI -khui_cfg_get_flags(khui_config_node vnode); - -/*! \brief Utility function: Initialize dialog box window data - - This function initializes the dialog box window data using the - ::khui_config_init_data that was passed into the WM_INITDIALOG - message. - - A new block of memory will be alocated to store the dialog data as - well as any extra space specified. A pointer to this memory block - will be stored in the \a DWLP_USER slot in the dialog box. - - The allocated block of memory must be freed by a call to - khui_cfg_free_dialog_data(). While handling other messages, the - dialog data can be retrieved using khui_cfg_get_dialog_data(). - - \param[in] hwnd_dlg Handle to the dialog box - - \param[in] data Pointer to the ::khui_config_init_data that was - passed in to WM_INITDIALOG (this is the value of \a lParam) - - \param[in] cb_extra Number of extra bytes to allocate, along with - the space required to store the contents of - ::khui_config_init_data. The extra space will be initialized - to zero. - - \param[out] new_data Receives a pointer to the copy of the - initialization data that was allocated. Optional. Pass in - NULL if this value is not required. - - \param[out] extra Receives a pointer to the block of extra memory - allocated as specified in \a cb_extra. If \a cb_extra is 0, - then this receives a NULL. - - \see khui_cfg_get_dialog_data(), khui_cfg_free_dialog_data() - */ -KHMEXP khm_int32 KHMAPI -khui_cfg_init_dialog_data(HWND hwnd_dlg, - const khui_config_init_data * data, - khm_size cb_extra, - khui_config_init_data ** new_data, - void ** extra); - -/*! \brief Utility function: Retrieves dialog data - - Retrieves the dialog data previoulsy stored using - khui_cfg_init_dialog_data(). - - \param[in] hwnd_dlg Handle to the dialog box - - \param[out] data Receives a pointer to the ::khui_config_init_data - block. - - \param[out] extra Receives a pointer to the extra memory - allocated. Optional (set to NULL if this value is not needed). -*/ -KHMEXP khm_int32 KHMAPI -khui_cfg_get_dialog_data(HWND hwnd_dlg, - khui_config_init_data ** data, - void ** extra); - -/*! \brief Utility function: Free dialog data - - Deallocates the memory allcated in a previous call to - khui_cfg_init_dialog_data() - */ -KHMEXP khm_int32 KHMAPI -khui_cfg_free_dialog_data(HWND hwnd_dlg); - -/*! \brief Sets the instance flags for a subpanel - - Since there can be more than one subpanel in a configuration - panel, they shouldn't modify the flags of the configuration node - directly. Instead, they should call this function to set the - instance flags. - - The instance flags will be merged with the flags for the - configuration node automatically. - */ -KHMEXP void KHMAPI -khui_cfg_set_flags_inst(khui_config_init_data * d, - khm_int32 flags, - khm_int32 mask); - -/*!@} */ -/*!@} */ -#endif +/* + * 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_KHCONFIGUI_H +#define __KHIMAIRA_KHCONFIGUI_H + +/*! \addtogroup khui +@{ */ + +/*! \defgroup khui_cfg Configuration Panels + + Configuration panels are the primary means from which the user is + presented with an interface to change NetIDMgr and plugin + configuration. + +@{ */ + +/*! \brief Configuration window notification message + + This is the message that will be used to notify dialog panels. + + The format of the message is : + - uMsg : KHUI_WM_CFG_NOTIFY + - HIWORD(wParam) : one of ::khui_wm_cfg_notifications + + \note This is the same as ::KHUI_WM_NC_NOTIFY + */ +#define KHUI_WM_CFG_NOTIFY (WM_APP + 0x101) + +/*! \brief Configuration notifications + + These are sent thorugh a ::KHUI_WM_CFG_NOTIFY message. + + The format of the message is : + - uMsg : KHUI_WM_CFG_NOTIFY + - HIWORD(wParam) : one of ::khui_wm_cfg_notifications + */ +enum khui_wm_cfg_notifications { + WMCFG_SHOW_NODE = 1, + /*!< Sent to the configuration dialog to request that the panel + for the specified node be shown. The \a lParam message + parameter will contain a held ::khui_config_node handle. The + sender of the mssage is responsible for releasing the handle.*/ + + WMCFG_UPDATE_STATE = 2, + /*!< Sent to the configuration dialog to indicate that the state + flags for the specified configuration node have changed. + + - LOWORD(wParam) : new flags + - lParam : ::khui_config_node for the node*/ + + WMCFG_APPLY = 3, + /*!< Sent to all the configuration panels when the user clicks the + 'Apply' button or the 'Ok' button. The panels are responsible + for applying the configuration changes and updating their flags + using khui_cfg_set_flags(). */ + + WMCFG_SYNC_NODE_LIST = 4, + /*!< Sent from the UI library to the configuration window to + notify the window that the node list has changed. This message + is sent synchronously before the node is removed. */ +}; + +/*! \brief Registration information for a configuration node + + \see khui_cfg_register_node() +*/ +typedef struct tag_khui_config_node_reg { + const wchar_t * name; /*!< Internal identifier + (not-localized, required). The name + is required to be unique among + sibling nodes. However it is not + required to be unique globally. The + size of the name is constrained by + ::KHUI_MAXCCH_NAME*/ + + const wchar_t * short_desc; /*!< Short description (Localized, + required). This is the name which + identifies the node within a + collection of siblings. The size of + the string is constrained by + ::KHUI_MAXCCH_SHORT_DESC*/ + + const wchar_t * long_desc; /*!< Global name of the node. + (Localized, required). This + uniquely identifies the node in the + collection of all configuration + nodes. The size of the string is + constrained by + ::KHUI_MAXCCH_LONG_DESC.*/ + + HMODULE h_module; /*!< Module which contains the dialog + resource specified in \a + dlg_template */ + + LPWSTR dlg_template; /*!< Dialog template for the + configuration window */ + + DLGPROC dlg_proc; /*!< Dialog procedure */ + + khm_int32 flags; /*!< Flags. Can be a combination of + ::KHUI_CNFLAG_SORT_CHILDREN and + ::KHUI_CNFLAG_SUBPANEL*/ + +} khui_config_node_reg; + +/*! \brief Sort the child nodes by short description */ +#define KHUI_CNFLAG_SORT_CHILDREN 0x0001 + +/*! \brief Is a subpanel */ +#define KHUI_CNFLAG_SUBPANEL 0x0002 + +/*! \brief Node represents a panel that is replicated for all child nodes */ +#define KHUI_CNFLAG_PLURAL 0x0004 + +/*! \brief System node + + \note For internal use by the NetIDMgr application. Do not use. +*/ +#define KHUI_CNFLAG_SYSTEM 0x0010 + +/*! \brief Settings have been modified + + Settings for this configuration panel have been modified. This + flag should be cleared once the settings have been successfully + applied. + */ +#define KHUI_CNFLAG_MODIFIED 0x0100 + +/*! \brief Settings have been applied + + Set once any modified settings were successfully applied. + */ +#define KHUI_CNFLAG_APPLIED 0x0200 + +#define KHUI_CNFLAGMASK_STATIC 0x00ff +#define KHUI_CNFLAGMASK_DYNAMIC 0x0f00 + +/*! \brief Maximum length of the name in characters + + The length includes the terminating NULL + */ +#define KHUI_MAXCCH_NAME 256 + +/*! \brief Maximum length of the name in bytes + + The length includes the terminating NULL + */ +#define KHUI_MAXCB_NAME (KHUI_MAXCCH_NAME * sizeof(wchar_t)) + +/*! \brief Maximum length of the long description in characters + + The length includes the terminating NULL + */ +#define KHUI_MAXCCH_LONG_DESC 1024 + +/*! \brief Maximum length of the long description in bytes + + The length includes the terminating NULL + */ +#define KHUI_MAXCB_LONG_DESC (KHUI_MAXCCH_LONG_DESC * sizeof(wchar_t)) + +/*! \brief Maximum length of the short description in chracters + + The length includes the terminating NULL + */ +#define KHUI_MAXCCH_SHORT_DESC 256 + +/*! \brief Maximum length of the short description in bytes + + The length includes the terminating NULL + */ +#define KHUI_MAXCB_SHORT_DESC (KHUI_MAXCCH_SHORT_DESC * sizeof(wchar_t)) + +/*! \brief Width of a configuration dialog in dialog units + + ::CFGDLG_WIDTH and ::CFGDLG_HEIGHT specify the dimensions of a + configuration dialog width and height in dialog units. The dialog + will be created as a child of the configuration dialog and placed + within it. + */ +#define CFGDLG_WIDTH 255 + +/*! \brief Height of a configuration dialog in dialog units + + \see ::CFGDLG_WIDTH +*/ +#define CFGDLG_HEIGHT 182 + +/*! \brief Width of a configuration tab dialog in dialog units + + ::CFGDLG_TAB_WIDTH and ::CFGDLG_TAB_HEIGHT specify the dimensions + (in dialog units) of a dialog that will be placed within a tab + control for dialogs where multiple display panels need to be + shown. + */ +#define CFGDLG_TAB_WIDTH 235 + +/*! \brief Height of configuration tab dialog in dialog units + + \see ::CFGDLG_TAB_WIDTH + */ +#define CFGDLG_TAB_HEIGHT 151 + +/*! \brief A handle to a configuration node + + \see khui_cfg_open_node(), khui_cfg_close_node() +*/ +typedef khm_handle khui_config_node; + +/*! \brief Initialization data passed in to a subpanel + + When creating a subpanel, a pointer to the following strucutred + will be passed in as the creation parameter for the dialog. +*/ +typedef struct tag_khui_config_init_data { + khui_config_node ctx_node; /*!< The node under which the current + dialog subpanel is being created. */ + + khui_config_node this_node; /*!< The node which provided the + registration information for the + creation of the subpanel. */ + + khui_config_node ref_node; /*!< The parent node of the subpanel + node. In nodes which have the + ::KHUI_CNFLAG_PLURAL, this would be + different from the \a node. This is + the node under which the subpanel + was registered. */ +} khui_config_init_data; + +/*! \brief Register a configuration node + + The caller fills the registration information in the + ::khui_config_node_reg structre. If the call succeeds, the + function will return KHM_ERROR_SUCCESS. + + \param[in] parent Parent of the node to be registered. Set to + NULL if the parent is the root node. + + \param[in] reg Registration information + + \param[out] new_id Receives the new unique identifier of the + configuration node. Pass in NULL if the new identifier is not + required. + + \retval KHM_ERROR_SUCCESS Success + \retval KHM_ERROR_INVALID_PARAM One or more parameters, or fields + 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, + const khui_config_node_reg * reg); + +/*!\brief Open a configuration node by name + + If successful, the \a result parameter will receive a handle to + the configuration node. Use khui_cfg_release() to release + the handle. + + \param[in] parent Parent node. Set to NULL to specify root node. + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_open(khui_config_node parent, + const wchar_t * name, + khui_config_node * result); + +/*! \brief Remove a configuration node + + Marks a configuration node as deleted. Once all the handles, + including the handle specified in \a node have been released, it + will be deleted. + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_remove(khui_config_node node); + +/*! \brief Hold a handle to a configuration node + + Obtains an additional hold on the handle specified by \a node. + The hold must be released with a call to \a + khui_cfg_release() + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_hold(khui_config_node node); + +/*! \brief Release a handle to a configuration node + + \see khui_cfg_hold() + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_release(khui_config_node node); + +/*! \brief Get the parent of a node + + Returns a held handle to the parent of the node, or NULL if the + current node is a top level node. The returned handle must be + released with khui_cfg_release(). + + \retval KHM_ERROR_SUCCESS The handle to the parent node is in \a result + \retval KHM_ERROR_NOT_FOUND The node is a top level node + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_parent(khui_config_node vnode, + khui_config_node * result); + +/*! \brief Get a handle to the first child node + + If the call is successful, \a result will receieve a handle to the + first child node of the specified node. The returned handle must + be released with a call to khui_cfg_release() + + If \a parent does not have any child nodes, the function will + return KHM_ERROR_NOT_FOUND and set \a result to NULL. + + \param[in] parent Parent node. Set to NULL to specify root node. + \param[out] result Receives a held handle to the first child node. + + \see khui_cfg_get_next() + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_first_child(khui_config_node parent, + khui_config_node * result); + +/*! \brief Get a handle to the first subpanel + + If the call is successful, \a result will receieve a handle to the + first subpanel node of the specified node. The returned handle + must be released with a call to khui_cfg_release() + + If \a parent does not have any subpanels, the function will return + KHM_ERROR_NOT_FOUND and set \a result to NULL. + + A subpanel node is a node which has the ::KHUI_CNFLAG_SUBPANEL + flag set. + + \param[in] parent Parent node. Set to NULL to specify root node. + \param[out] result Receives a held handle to the first subpanel node. + + \see khui_cfg_get_next() + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_first_subpanel(khui_config_node vparent, + khui_config_node * result); + +/*! \brief Get a handle to the next sibling node + + If the call is successful, \a result will receive a held handle to + the next sibling node. The returned handle must be released with + a call to khui_cfg_release(). + + If there are no more sibling nodes, then the function return + KHM_ERROR_NOT_FOUND and set \a result to NULL. + + This function can be used to traverse a list of child nodes as + well as a list of subpanel nodes. + + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_next(khui_config_node node, + khui_config_node * result); + +/*! \brief Get a handle to the next sibling node + + Similar to khui_cfg_get_next(), but implicitly releases the handle + that was supplied. Equivalent to doing : + + \code + khui_cfg_get_next(node, &next); + khui_cfg_release(node); + node = next; + \endcode + + \param[in,out] node On entry, specifies the node whose sibling + needs to be fetched. On exit, will have either NULL or a held + handle to the sibling node. The handle which was supplied to + the function is released. + + \retval KHM_ERROR_SUCCESS The next node is now in \a node + \retval KHM_ERROR_INVALID_PARAM \a node was not a valid handle + \retval KHM_ERROR_NOT_FOUND There are no more siblings. \a node + is set to NULL. + + \note Even if there are no more siblings, the handle specified in + \a node on entry is released. + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_next_release(khui_config_node * node); + +/*! \brief Get the name of a configuration node + + Gets the name (not the short description or the long description) + of the given configuration node. +*/ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_name(khui_config_node node, + wchar_t * buf, + khm_size * cb_buf); + +/*! \brief Get registration information for a node + + The registration information that is returned is a shallow copy of + the data kept by NetIDMgr. In particular, the strings that will + be returned actually point to internal buffers and should not be + modified. + + No further action is necessary to release the information. + However, the returned data ceases to be valid when \a node is + released with a call to khui_cfg_release(). + + \param[in] node Node for which information is requested. Can be NULL if requesting information about the root node. + \param[out] reg Pointer to a ::khui_config_node_reg structure. + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_reg(khui_config_node node, + khui_config_node_reg * reg); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP HWND KHMAPI +khui_cfg_get_hwnd_inst(khui_config_node node, + khui_config_node noderef); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP LPARAM KHMAPI +khui_cfg_get_param_inst(khui_config_node node, + khui_config_node noderef); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP void KHMAPI +khui_cfg_set_hwnd_inst(khui_config_node node, + khui_config_node noderef, + HWND hwnd); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP void KHMAPI +khui_cfg_set_param_inst(khui_config_node node, + khui_config_node noderef, + LPARAM param); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP HWND KHMAPI +khui_cfg_get_hwnd(khui_config_node node); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP LPARAM KHMAPI +khui_cfg_get_param(khui_config_node node); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP void KHMAPI +khui_cfg_set_hwnd(khui_config_node node, HWND hwnd); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP void KHMAPI +khui_cfg_set_param(khui_config_node node, LPARAM param); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP void KHMAPI +khui_cfg_clear_params(void); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP void KHMAPI +khui_cfg_set_configui_handle(HWND hwnd); + +/*! \brief Update the state for the specified node + + \param[in] node ::khui_config_node handle for the configuration node. + + \param[in] flags New flags. Combination of ::KHUI_CNFLAG_APPLIED and ::KHUI_CNFLAG_MODIFIED + + \param[in] mask Valid bits in \a flags + + \note Should only be called from within the dialog procedure for + the configuration node. + */ +KHMEXP void KHMAPI +khui_cfg_set_flags(khui_config_node vnode, khm_int32 flags, khm_int32 mask); + +/*! \brief Retrieve the state flags for the configuration node + + \see khui_cfg_set_flags() + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_flags(khui_config_node vnode); + +/*! \brief Utility function: Initialize dialog box window data + + This function initializes the dialog box window data using the + ::khui_config_init_data that was passed into the WM_INITDIALOG + message. + + A new block of memory will be alocated to store the dialog data as + well as any extra space specified. A pointer to this memory block + will be stored in the \a DWLP_USER slot in the dialog box. + + The allocated block of memory must be freed by a call to + khui_cfg_free_dialog_data(). While handling other messages, the + dialog data can be retrieved using khui_cfg_get_dialog_data(). + + \param[in] hwnd_dlg Handle to the dialog box + + \param[in] data Pointer to the ::khui_config_init_data that was + passed in to WM_INITDIALOG (this is the value of \a lParam) + + \param[in] cb_extra Number of extra bytes to allocate, along with + the space required to store the contents of + ::khui_config_init_data. The extra space will be initialized + to zero. + + \param[out] new_data Receives a pointer to the copy of the + initialization data that was allocated. Optional. Pass in + NULL if this value is not required. + + \param[out] extra Receives a pointer to the block of extra memory + allocated as specified in \a cb_extra. If \a cb_extra is 0, + then this receives a NULL. + + \see khui_cfg_get_dialog_data(), khui_cfg_free_dialog_data() + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_init_dialog_data(HWND hwnd_dlg, + const khui_config_init_data * data, + khm_size cb_extra, + khui_config_init_data ** new_data, + void ** extra); + +/*! \brief Utility function: Retrieves dialog data + + Retrieves the dialog data previoulsy stored using + khui_cfg_init_dialog_data(). + + \param[in] hwnd_dlg Handle to the dialog box + + \param[out] data Receives a pointer to the ::khui_config_init_data + block. + + \param[out] extra Receives a pointer to the extra memory + allocated. Optional (set to NULL if this value is not needed). +*/ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_dialog_data(HWND hwnd_dlg, + khui_config_init_data ** data, + void ** extra); + +/*! \brief Utility function: Free dialog data + + Deallocates the memory allcated in a previous call to + khui_cfg_init_dialog_data() + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_free_dialog_data(HWND hwnd_dlg); + +/*! \brief Sets the instance flags for a subpanel + + Since there can be more than one subpanel in a configuration + panel, they shouldn't modify the flags of the configuration node + directly. Instead, they should call this function to set the + instance flags. + + The instance flags will be merged with the flags for the + configuration node automatically. + */ +KHMEXP void KHMAPI +khui_cfg_set_flags_inst(khui_config_init_data * d, + khm_int32 flags, + khm_int32 mask); + +/*!@} */ +/*!@} */ +#endif diff --git a/src/windows/identity/uilib/khhtlink.h b/src/windows/identity/uilib/khhtlink.h index 1246923e2..be6abb21c 100644 --- a/src/windows/identity/uilib/khhtlink.h +++ b/src/windows/identity/uilib/khhtlink.h @@ -1,77 +1,77 @@ -/* - * 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_KHHTLINK_H -#define __KHIMAIRA_KHHTLINK_H - -/*! \addtogroup khui -@{ */ - -/*! \defgroup khui_hyperlink Hyperlink -@{*/ - -/*! \brief A hyperlink - - When a link in a hypertext window is clicked, this structure is - passed along with the message. - - The link text fields do to point to NULL terminated strings. - Instead, the length fields should be used to extract the string. - */ -typedef struct tag_khui_htwnd_link { - RECT r; /*!< The enclosing rectangle of the - hyperlink. Units are screen units - and the coordinates are relative to - the top left hand corner of the - hypertext area. */ - wchar_t * id; /*!< The value of the \a id attribute - of the link or \a NULL if there was - no \a id attribute. This does not - point to a \a NULL terminated - string. The length of the string is - given by the \a id_len field. */ - int id_len; /*!< The length of the string pointed - to by \a id in characters. - Undefined if \a id is \a NULL. */ - wchar_t * param; /*!< The value of the \a param - attribute of the link or \a NULL if - there was no \a param attribute. - This does not point to a \a NULL - terminated string. The length of - the string is given by the \a - param_len field.*/ - int param_len; /*!< Length of the string pointed to - by \a param in characters. - Undefined if \a param is \a NULL. */ -} khui_htwnd_link; - -#define KHUI_MAXCCH_HTLINK_FIELD 256 -#define KHUI_MAXCB_HTLINK_FIELD (KHUI_MAXCCH_HTLINK_FIELD * sizeof(wchar_t)) - -/*!@}*/ -/*!@}*/ - -#endif +/* + * 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_KHHTLINK_H +#define __KHIMAIRA_KHHTLINK_H + +/*! \addtogroup khui +@{ */ + +/*! \defgroup khui_hyperlink Hyperlink +@{*/ + +/*! \brief A hyperlink + + When a link in a hypertext window is clicked, this structure is + passed along with the message. + + The link text fields do to point to NULL terminated strings. + Instead, the length fields should be used to extract the string. + */ +typedef struct tag_khui_htwnd_link { + RECT r; /*!< The enclosing rectangle of the + hyperlink. Units are screen units + and the coordinates are relative to + the top left hand corner of the + hypertext area. */ + wchar_t * id; /*!< The value of the \a id attribute + of the link or \a NULL if there was + no \a id attribute. This does not + point to a \a NULL terminated + string. The length of the string is + given by the \a id_len field. */ + int id_len; /*!< The length of the string pointed + to by \a id in characters. + Undefined if \a id is \a NULL. */ + wchar_t * param; /*!< The value of the \a param + attribute of the link or \a NULL if + there was no \a param attribute. + This does not point to a \a NULL + terminated string. The length of + the string is given by the \a + param_len field.*/ + int param_len; /*!< Length of the string pointed to + by \a param in characters. + Undefined if \a param is \a NULL. */ +} khui_htwnd_link; + +#define KHUI_MAXCCH_HTLINK_FIELD 256 +#define KHUI_MAXCB_HTLINK_FIELD (KHUI_MAXCCH_HTLINK_FIELD * sizeof(wchar_t)) + +/*!@}*/ +/*!@}*/ + +#endif diff --git a/src/windows/identity/uilib/khnewcred.h b/src/windows/identity/uilib/khnewcred.h index e22e1f77f..c3ef5dabf 100644 --- a/src/windows/identity/uilib/khnewcred.h +++ b/src/windows/identity/uilib/khnewcred.h @@ -1,985 +1,985 @@ -/* - * 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_KHNEWCRED_H -#define __KHIMAIRA_KHNEWCRED_H - -/******************************************************************** - New credentials windows -*********************************************************************/ - -/*! \addtogroup khui -@{ */ - -/*! \defgroup khui_cred Credentials acquisition - - Declarations associated with credentials acquisition. - -@{ */ - -/*! \brief Window message sent to credentials type panels - - This message is sent to the child windows. - - The format of the message is : - - uMsg : KHUI_WM_NC_NOTIFY - - HIWORD(wParam) : one of ::khui_wm_nc_notifications - - LPARAM : pointer to the ::khui_new_creds structure -*/ -#define KHUI_WM_NC_NOTIFY (WM_APP + 0x101) - -/*! \brief The first control ID that may be used by an identity provider */ -#define KHUI_CW_ID_MIN 8016 - -/*! \brief The maximum number of controls that may be created by an identity provider*/ -#define KHUI_CW_MAX_CTRLS 8 - -/*! \brief The maximum control ID that may be used by an identity provider */ -#define KHUI_CW_ID_MAX (KHUI_CW_ID_MIN + KHUI_CW_MAX_CTRLS - 1) - - -/*! \brief Credentials dialog notifications - - These notifications will be sent to the individual dialog - procedures of the credential type panels as a ::KHUI_WM_NC_NOTIFY - message. -*/ -enum khui_wm_nc_notifications { - WMNC_DIALOG_EXPAND = 1, - /*!< The dialog is switching from basic to advanced mode or vice - versa. - - This message is sent to the new creds dialog to set the dialog - to expanded mode. In expanded mode, all credentials type panels - are visible as opposed to the compressed mode where they are not - visible. The message is not sent to credentials type panels.*/ - - WMNC_DIALOG_SETUP, - /*!< Sent by NetIDMgr to the new creds window to notify it that - the dialog should create all the type configuration panels. - - Until this message is issued, none of the credentials type - panels exist. The credentials type panels will receive - WM_INITDIALOG etc as per the normal dialog creation process. */ - - WMNC_DIALOG_ACTIVATE, - /*!< Sent by NetIDMgr to the new creds window to notify it that - the dialog should do final initialization work and activate. */ - - WMNC_DIALOG_MOVE, - /*!< Sent by the new creds widnow to all the panels notifying them - that the NC window is moving. */ - - WMNC_DIALOG_SWITCH_PANEL, - /*!< Sent to the new creds window to cause it to switch to the - panel identified by LOWORD(wParam). - - Does nothing if the specified panel is already the current - panel. If the dialog is in compact mode and making the - specified panel visible requires switching to expanded mode, the - dialog will do so. */ - - WMNC_UPDATE_CREDTEXT, - /*!< Sent to all the credential type panels for a credentials - window to request them to update the credential text. - - When sent to the new credentials window, causes it to send the - WMNC_UPDATE_CREDTEXT message to all the credential type panels - and update the cred text window.*/ - - WMNC_CREDTEXT_LINK, - /*!< Sent to a panel dialog proc when a user clicks a credtext - embedded link that belongs to that panel. The \a lParam - parameter of the message is a pointer to a ::khui_htwnd_link - structure describing the link. */ - - WMNC_IDENTITY_CHANGE, - /*!< The primary identity has changed */ - - WMNC_CLEAR_PROMPTS, - /*!< Sent to the new creds window to clear any custom prompts */ - - WMNC_SET_PROMPTS, - /*!< Sent to the new creds window to set custom prompts */ - - WMNC_DIALOG_PREPROCESS, - /*!< Sent to all the credentials type panels to notify them that - the dialog is about to be processed */ - - WMNC_DIALOG_PROCESS, - /*!< Process the dialog and signal whether to exit the dialog or - not */ - - WMNC_DIALOG_PROCESS_COMPLETE, - /*!< Sent to the new creds window to indicate that the all the - threads have completed processing.*/ - - WMNC_TYPE_STATE, - /*!< Sent to the new creds window as notification that a - particular credentials type has changed state from enabled to - disabled or vice versa. The LPARAM member of the message - specifies the credentials type identifier for the changed - type */ - - WMNC_ADD_CONTROL_ROW, - /*!< Add a row of controls to a new cred dialog. This is an - internal message. */ - - WMNC_UPDATE_LAYOUT, - /*!< Update the layout of a dialog or window. This is an internal - message. */ -}; - -/*! \brief Plugins can use WMNC_NOTIFY message codes from here on up - - \see ::KHUI_WM_NC_NOTIFY - */ -#define WMNC_USER 2048 - -/*! \brief Notifications to the identity provider - - These notifications are sent through to the identity provider's UI - callback that was obtained using a ::KMSG_IDENT_GET_UI_CB message. - - The callback routine is called from the context of the UI thread - and is expected to not make any blocking calls. One of the - following commands will be passed in as the \a cmd parameter to - the callback. - */ -enum khui_wm_nc_ident_notify { - WMNC_IDENT_INIT, - /*!< Initialize an identity selector for a new credentials - dialog. The \a lParam parameter contains a handle to the - dialog window which will contain the identity selector - controls. The identity provider may make use of the \a - ident_aux field of the ::khui_new_creds structure to hold any - data pertaining to the credentials acquisition dialog.*/ - - WMNC_IDENT_WMSG, - /*!< Windows message. Presumably sent from one of the controls - that was created by the identity provider. The callback is - expected to return TRUE if it processed the message or FALSE - if it did not. The \a uMsg, \a wParam and \a lParam - parameters are set to the values passed in by Windows. */ - - WMNC_IDENT_EXIT, - /*!< Terminate a credentials acquisition dialog. Sent just before - the dialog is terminated. */ -}; - -/*! \name Standard credtext link IDs -@{*/ - -/*! \brief Switch the panel - - The \a id attribute of the link specifies the ordinal of the panel - to switch to. -*/ -#define CTLINKID_SWITCH_PANEL L"SwitchPanel" - -/*@}*/ - -/*forward dcl*/ -struct tag_khui_new_creds_by_type; -typedef struct tag_khui_new_creds_by_type khui_new_creds_by_type; -struct tag_khui_new_creds_prompt; -typedef struct tag_khui_new_creds_prompt khui_new_creds_prompt; -struct tag_khui_new_creds; -typedef struct tag_khui_new_creds khui_new_creds; - -typedef LRESULT -(KHMAPI *khui_ident_new_creds_cb)(khui_new_creds * nc, - UINT cmd, - HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -/*! \brief New credentials acquisition blob - - A pointer to an object of this type is passed in along with the - credentials acquisition messages. - - \see \ref cred_acq for more information -*/ -typedef struct tag_khui_new_creds { - khm_int32 magic; /*!< Internal use */ - - khm_int32 subtype; /*!< Subtype of the request that is - being handled through this object. - One of ::KMSG_CRED_NEW_CREDS, - ::KMSG_CRED_RENEW_CREDS or - ::KMSG_CRED_PASSWORD */ - - CRITICAL_SECTION cs; /*!< Internal use */ - - khm_boolean set_default; /*!< After a successfull credentials - acquisition, set the primary - identity as the default. */ - - khm_handle *identities; /*!< The list of identities associated - with this request. The first - identity in this list (\a - identities[0]) is the primary - identity. */ - - khm_size n_identities; /*!< Number of identities in the list - \a identities */ - - khm_size nc_identities; /*!< Internal use */ - - khui_action_context ctx; /*!< An action context specifying the - context in which the credentials - acquisition operation was - launced. */ - - khm_int32 mode; /*!< The mode of the user interface. - One of ::KHUI_NC_MODE_MINI or - ::KHUI_NC_MODE_EXPANDED. */ - - HWND hwnd; /*!< Handle to the new credentials - window. */ - - struct tag_khui_new_creds_by_type **types; - /*!< Internal use */ - khm_handle *type_subs; /*!< Internal use */ - khm_size n_types; /*!< Internal use */ - khm_size nc_types; /*!< Internal use */ - - khm_int32 result; /*!< One of ::KHUI_NC_RESULT_CANCEL or - ::KHUI_NC_RESULT_PROCESS indicating - the result of the dialog with the - user */ - - khm_int32 response; /*!< Response. See individual message - documentation for info on what to do - with this field */ - - wchar_t *password; /*!< Not used. */ - - /* UI stuff */ - - wchar_t *banner; /*!< Internal use */ - wchar_t *pname; /*!< Internal use */ - khm_size n_prompts; /*!< Internal use */ - khm_size nc_prompts; /*!< Internal use */ - struct tag_khui_new_creds_prompt ** prompts; /*!< Internal use */ - - khui_ident_new_creds_cb ident_cb; /*!< Internal use */ - - wchar_t *window_title; /*!< Internal use */ - - LPARAM ident_aux; /*!< Auxilliary field which is - reserved for use by the identity - provider during the course of - conducting this dialog. */ - -} khui_new_creds; - -#define KHUI_NC_MAGIC 0x84270427 - -/*!\name Result values for khui_new_creds_t::result - @{*/ -#define KHUI_NC_RESULT_PROCESS 0 -#define KHUI_NC_RESULT_CANCEL 1 -/*@}*/ - -/*!\name Mode values for khui_new_creds_t::mode - @{*/ -#define KHUI_NC_MODE_MINI 0 -#define KHUI_NC_MODE_EXPANDED 1 -/*@}*/ - -/*!\name Response values for khui_new_creds_t::response - @{*/ -/*!\brief No known response */ -#define KHUI_NC_RESPONSE_NONE 0 - -/*!\brief It is okay to exit the dialog now - - This is the default, which is why it has a value of zero. In - order to prevent the dialog from exiting, set the - KHUI_NC_RESPONSE_NOEXIT response bit. */ -#define KHUI_NC_RESPONSE_EXIT 0 - -/*!\brief It is NOT okay to exit the dialog now - - Used to indicate that further user-interaction is necessary to - process the dialog. Usually this is accompanied by setting - necessary custom prompts and notifications so the user knows why - the dialog is prompting for more information. - */ -#define KHUI_NC_RESPONSE_NOEXIT 0x00000002 - -/*!\brief The dialog was processed successfully - - Since this is the default response, the value is zero. Use one of - KHUI_NC_RESPONSE_FAILED or KHUI_NC_RESPONSE_PENDING to indicate an - error or pending status. - */ -#define KHUI_NC_RESPONSE_SUCCESS 0 - -/*!\brief The processing of the dialog failed - - Self explanatory. More information about the failure should have - been reported using the khlog API, however, this response value - indicates to other credential types that depend on this credential - type that whatever it was that this credential type was supposed - to do didn't happen. -*/ -#define KHUI_NC_RESPONSE_FAILED 0x00000008 - -/*!\brief Further interaction required - - Set along with KHUI_NC_RESPONSE_NOEXIT although it is not - required. Setting this bit will automatically add the - KHUI_NC_RESPONSE_NOEXIT. - - If this bit is set, all dependent plugins will be set on hold - until another round of processing clears the pending bit. - */ -#define KHUI_NC_RESPONSE_PENDING 0x00000010 - -/*! \brief Completed - - This is automatically set if the plugin sets a response which does - not indicate either KHUI_NC_RESPONSE_NOEXIT or - KHUI_NC_RESPONSE_PENDING, which is considered to mean that the - plugin is completed processing. - - This flag cannot be explicitly specified in a response. - */ -#define KHUI_NC_RESPONSE_COMPLETED 0x00000020 - -/*! \brief Processing - - This is an internal flag set while the credentials acquisition - process is executing. - */ -#define KHUI_NC_RESPONSE_PROCESSING 0x00010000 - -#define KHUI_NCMASK_RESPONSE (KHUI_NC_RESPONSE_EXIT|KHUI_NC_RESPONSE_NOEXIT) -#define KHUI_NCMASK_RESULT (KHUI_NC_RESPONSE_SUCCESS|KHUI_NC_RESPONSE_FAILED|KHUI_NC_RESPONSE_PENDING) -/*@}*/ - -/*!\brief Maximum number of dependencies for a credentials type */ -#define KHUI_MAX_TYPE_DEPS 8 - -/*!\brief Maximum number of credential types for a new creds window */ -#define KHUI_MAX_NCTYPES 16 - -/*!\brief Maximum number of characters in a password - - Length includes the termininating NULL -*/ -#define KHUI_MAXCCH_PASSWORD 512 - -/*! \brief Maximum number of bytes in a password - - Includes terminating NULL -*/ -#define KHUI_MAXCB_PASSWORD (KHUI_MAXCCH_PASSWORD * sizeof(wchar_t)) - -/*! \brief Maximum number of characters in a custom banner - - Length includes terminating NULL -*/ -#define KHUI_MAXCCH_BANNER 256 - - -/*! \brief Maximum number of bytes in a custom banner - - Length includes terminating NULL -*/ -#define KHUI_MAXCB_BANNER (KHUI_MAXCCH_BANNER * sizeof(wchar_t)) - -/*! \brief Maximum number of characters in a panel name - - Length includes terminating NULL -*/ -#define KHUI_MAXCCH_PNAME 256 - -/*! \brief Maximum number of bytes in a panel name - - Length includes terminating NULL -*/ -#define KHUI_MAXCB_PNAME (KHUI_MAXCCH_PNAME * sizeof(wchar_t)) - -/*! \brief A descriptor of a panel in the new credentials acquisition tab - - When processing certain credentials messages such as - ::KMSG_CRED_PASSWORD, ::KMSG_CRED_NEW_CREDS, - ::KMSG_CRED_RENEW_CREDS, a pointer to a ::khui_new_creds structure - will be passed in to the message handler. If the handler of the - message needs to add one or more credentials types as participants - of the operation, the handler will need to call khui_cw_add_type() - and specify a ::khui_new_creds_by_type structure. - - Note that the memory address passed in to the call to - khui_cw_add_type() will not be copied. Therefore, the block of - memory should remain as-is for the lifetime of the - ::khui_new_creds structure or until it is removed with a call to - khui_cw_del_type(). - - Some of the credentials messages that require specifying a - ::khui_new_creds_by_type structure require providing a - user-interface. In these cases, the fields marked for providing a - UI may be required to hold valid values. If the message does not - require providing a UI, these fields will be ignored. -*/ -typedef struct tag_khui_new_creds_by_type { - khui_new_creds * nc; /*!< Internal use. Do not set */ - khm_int32 flags; /*!< Internal use. Do not set */ - - khm_int32 type; /*!< The identifier of the credentials - type. This is a credentials type - identifier allocated with a call to - kcdb_credtype_register(). */ - - khm_int32 type_deps[KHUI_MAX_TYPE_DEPS]; - /*!< credentials types that this - credential type depends on. Each - element defines a credentials type - identifier that this type depends - on for this operation. The number - of valid values in this array - should be specified in the \a - n_type_deps field. */ - - khm_size n_type_deps; /*!< Number of dependencies listed - above. Should be between 0 and - ::KHUI_MAX_TYPE_DEPS. Specify 0 if - there are no dependencies. */ - - khm_size ordinal; /*!< The requested ordinal. The UI - would attempt to place this panel at - the reqested order in the list of - panels. Set to -1 if the order does - not matter. Once the dialog is - activated this field will be updated - to reflect the actual ordinal of the - panel. */ - - wchar_t *name; /*!< Name of the panel (localized, - optional). If NULL, the localized - name of the credentials type is - used. Only used if providing a - user-interface. */ - - HICON icon; /*!< Icon for the panel (optional). - Only used if providing a - user-interface. */ - - wchar_t *tooltip; /*!< Tooltip for the panel (localized, - optional). If NULL, no tooltip will - be assigned for the panel. Only - used if providing a - user-interface. */ - - HMODULE h_module; /*!< Handle to the module containing - the dialog resource. Only used if - providing a user-interface. */ - - LPWSTR dlg_template; /*!< The dialog resource. Only used - if providing a user-interface. */ - DLGPROC dlg_proc; /*!< The dialog procedure. Only used - if providing a user-interface. */ - - HWND hwnd_panel; /*!< The dialog window. Once the - dialog panel is created, a handle to - the panel will be assigned here. - Note that the handle is assigned - after a successful call to - CreateDialogParam and hence would - not be available when handling the - WM_INITDIALOG message from the - dialog procedure. Only used of - providing a user-interface. */ - - HWND hwnd_tc; /*!< Internal use. Do not set */ - - wchar_t *credtext; /*!< A brief description of the - current state of this cred - type. (localized, optional). Only - used if providing a - user-interface. If this field is - non-NULL, then it should point to a - NULL terminated string that does not - exceed ::KHUI_MAXCCH_LONG_DESC - characters in length including the - terminating NULL. - - \see \ref khui_htwnd for information - on how to format the string for this - field. - */ - - LPARAM aux; /*!< auxilliary field. For use by the - plug-in. */ -} khui_new_creds_by_type; - -/*!\name Flags for khui_new_creds_by_type - - Note that KHUI_NC_RESPONSE_SUCCESS, KHUI_NC_RESPONSE_FAILED, - KHUI_NC_RESPONSE_PENDING are also stored in the flags. - -@{*/ -#define KHUI_NCT_FLAG_PROCESSED 1024 -#define KHUI_NCT_FLAG_DISABLED 2048 -/*@}*/ - -/*! \brief Width of a new creds dialog panel in dialog units*/ -#define NCDLG_WIDTH 300 -/*! \brief Height of a new creds dialog panel in dialog units*/ -#define NCDLG_HEIGHT 166 - -/*! \brief A custom prompt */ -typedef struct tag_khui_new_creds_prompt { - khm_size index; /*!< Set to the zero based index - of this prompt. */ - - khm_int32 type; /*!< one of KHUI_NCPROMPT_TYPE_* */ - wchar_t * prompt; /*!< prompt string. Cannot exceed - KHUI_MAXCCH_PROMPT */ - wchar_t * def; /*!< default value. Cannot exceed - KHUI_MAXCCH_PROMPT_VALUE */ - wchar_t * value; /*!< On completion, this is set to the - value that the user entered. Will - not exceed - KHUI_MAXCCH_PROMPT_VALUE */ - - khm_int32 flags; /*!< Combination of - KHUI_NCPROMPT_FLAG_* */ - - HWND hwnd_static; /* internal use */ - HWND hwnd_edit; /* internal use */ -} khui_new_creds_prompt; - -/*! \brief The prompt input is hidden - - The input is hidden for prompts which accept passwords. The - control which represents the input will display an asterisk or a - small circle corresponding to each character typed in, but will - not show the actual character. - */ -#define KHUI_NCPROMPT_FLAG_HIDDEN 1 - -/*! \brief Internal use */ -#define KHUI_NCPROMPT_FLAG_STOCK 2 - -/*! \brief Maximum number of characters in a prompt - - Refers to the prompt text that accompanies an input control. THe - length includes the terminating NULL. - */ -#define KHUI_MAXCCH_PROMPT 256 - -/*! \brief Maximum number of bytes in a prompt - - Refers to the prompt text that accompanies an input control. THe - length includes the terminating NULL. - */ -#define KHUI_MAXCB_PROMPT (KHUI_MAXCCH_PROMPT * sizeof(wchar_t)) - -/*! \brief Maximum number of characters that can be entered in an input control - - Refers to the input control of a prompt. The length includes the - terminating NULL. - */ -#define KHUI_MAXCCH_PROMPT_VALUE 256 - -/*! \brief Maximum number of bytes that can be entered in an input control - - Refers to the input control of a prompt. The length includes the - terminating NULL. - */ -#define KHUI_MAXCB_PROMPT_VALUE (KHUI_MAXCCH_PROMPT_VALUE * sizeof(wchar_t)) - -/* from krb5.h. Redefining here because we don't want to depend on - krb5.h for all credential types */ - -/*! \brief A password control */ -#define KHUI_NCPROMPT_TYPE_PASSWORD 1 - -/*! \brief New password control - - Used when changing the password - */ -#define KHUI_NCPROMPT_TYPE_NEW_PASSWORD 2 - -/*! \brief New password again control - - Used when changing the password - */ -#define KHUI_NCPROMPT_TYPE_NEW_PASSWORD_AGAIN 3 - -/*! \brief Preauthentication (reserved) */ -#define KHUI_NCPROMPT_TYPE_PREAUTH 4 - -/*! \brief Control sizes */ -typedef enum tag_khui_control_size { - KHUI_CTRLSIZE_SMALL, - /*!< A small control fits in about 1/5 the width of the new - credentials panel */ - KHUI_CTRLSIZE_HALF, - /*!< Half size controls fit in 1/2 the width of the new - credentials panel */ - KHUI_CTRLSIZE_FULL, - /*!< Takes up the whole width of the crednetials panel */ -} khui_control_size; - -/*! \brief Internal use */ -typedef struct tag_khui_control_row { - HWND label; - HWND input; - khui_control_size size; -} khui_control_row; - -/*! \brief Create a ::khui_new_creds object - - Creates and initializes a ::khui_new_creds object. The created - object must be destroyed using the khui_cw_destroy_cred_blob() - function. - - \note Plugins should not call this function directly. The - necessary ::khui_new_creds objects will be created by - NetIDMgr. - - \see khui_cw_destroy_cred_blob() - */ -KHMEXP khm_int32 KHMAPI -khui_cw_create_cred_blob(khui_new_creds ** c); - -/*! \brief Destroy a ::khui_new_creds object - - Destroys a ::khui_new_creds object that was fomerly created using - a call to khui_cw_create_cred_blob(). - - \note Plugins should not call this function directly. The - necessary ::khui_new_creds objects will be created by - NetIDMgr. - - \see khui_cw_create_cred_blob() -*/ -KHMEXP khm_int32 KHMAPI -khui_cw_destroy_cred_blob(khui_new_creds *c); - -/*! \brief Lock the new_creds object - - When a plugin is accessing the fields of a ::khui_new_creds - object, it must first obtain a lock on the object so that other - threads will not modify the fields at the same time. Locking the - object ensures that the fields of the object will be consistent. - - Use khui_cw_unlock_nc() to undo the lock obtained through a call - to khui_cw_lock_nc(). - - It is not necessary to lock a new credentials object when - modifying it using the NetIDMgr API. - */ -KHMEXP khm_int32 KHMAPI -khui_cw_lock_nc(khui_new_creds * c); - -/*! \brief Unlock a new_creds object - - \see khui_cw_lock_nc() - */ -KHMEXP khm_int32 KHMAPI -khui_cw_unlock_nc(khui_new_creds * c); - -/*! \brief Add a new panel to a new credentials acquisition window - - See the description of ::khui_new_cred_panel for information on - how to populate it to describe a credentials type panel. - - Note that the structure pointed to by \a t is added by reference. - The memory pointed to by \a t is not copied. Hence, the block of - memory and any other blocks pointed to by the - ::khui_new_creds_by_type structure located there should remain - intact for the lifetime of the ::khui_new_creds structure pointed - to by \a c or until the credentials type panel is removed from the - ::khui_new_creds structure with a call to khui_cw_del_type(). - - Generally, a plug-in that calls this function should allocate a - block of memory to contain the ::khui_new_creds_by_type structure, - fill it in and then pass in the address in a call to - khui_cw_add_type() while handling a ::KMSG_CRED_PASSWORD, - ::KMSG_CRED_NEW_CREDS or ::KMSG_CRED_RENEW_CREDS message. Then - the plug-in should remove the reference with a call to - khui_cw_del_type() while processing ::KMSG_CRED_END. - - \see khui_cw_del_type() - \see \ref cred_acq_panel_spec - \see ::khui_new_cred_panel - \see ::khui_new_creds -*/ -KHMEXP khm_int32 KHMAPI -khui_cw_add_type(khui_new_creds * c, - khui_new_creds_by_type * t); - -/*! \brief Remove a panel from a new credentials acquisition window - - \see khui_cw_add_type() - */ -KHMEXP khm_int32 KHMAPI -khui_cw_del_type(khui_new_creds * c, - khm_int32 type); - -/*! \brief Find the panel belonging to a particular credentials type - - This panel would have been added to the new credentials window - using khui_cw_add_type(). - - \see khui_cw_add_type() - */ -KHMEXP khm_int32 KHMAPI -khui_cw_find_type(khui_new_creds * c, - khm_int32 type, - khui_new_creds_by_type **t); - -/*! \brief Enable/disable a particular credentials type - - Enables or disables the panel associated with a particular - credentials type. Does not preclude the credentials type from - participating in the new credentials acquisition. However, the - user will be prevented from interacting with the specific panel. - */ -KHMEXP khm_int32 KHMAPI -khui_cw_enable_type(khui_new_creds * c, - khm_int32 type, - khm_boolean enable); - -/*! \brief Set the primary identity in a new credentials acuisition - - The primary identity dictates many of the defaults and the - semantics associated with the credentials acquision process. - Setting the primary identity also triggers the - ::WMNC_IDENTITY_CHANGE notification which will be sent to all the - credentials type panels. - - Has no effect if the primary identity is already the same as the - one specified in \a id. Specify NULL for \a id if the current - primary identity is to be cleared. - - If the primary identity is changed, then all the additional - identities associated with the new credentials acquisition dialog - will also be discarded. - */ -KHMEXP khm_int32 KHMAPI -khui_cw_set_primary_id(khui_new_creds * c, - khm_handle id); - -/*! \brief Add an additional identity to the new credentials acquisition - - Individual plugins are free to decide how to handle additional - identities. Generally, they would attempt to obtain credentials - for the primary and additional identities, but would not consider - it an error if an additional identity failed to obtain - credentials. - - Calling this function with \a id of NULL does nothing. -*/ -KHMEXP khm_int32 KHMAPI -khui_cw_add_identity(khui_new_creds * c, - khm_handle id); - -/*! \brief Clear all custom prompts - - Removes all the custom prompts from the new credentials dialog. - */ -KHMEXP khm_int32 KHMAPI -khui_cw_clear_prompts(khui_new_creds * c); - -/*! \brief Synchronize custom prompt values - - It is important to synchronize the values before accessing their - values. The controls associated with custom prompts update the - values in the ::khui_new_creds object periodically. However, the - values may lose sync intermittently. - */ -KHMEXP khm_int32 KHMAPI -khui_cw_sync_prompt_values(khui_new_creds * c); - -/*! \brief Begin custom prompting - - Begins the process of defining custom prompts. Implicity removes - all the custom prompts that are currently being displayed. The \a - banner and \a name will be displayed in separate controls above - the set of new custom prompts. - - The controls associated with the prompts will not actually be - created until all the prompts have been added using - khui_cw_add_prompt(). The number of promtps that can be added - will be exactly \a n_prompts. - */ -KHMEXP khm_int32 KHMAPI -khui_cw_begin_custom_prompts(khui_new_creds * c, - khm_size n_prompts, - wchar_t * banner, - wchar_t * name); - -/*! \brief Add a custom prompt - - After khui_cw_begin_custom_prompts() is called, the plugin should - call khui_cw_add_prompt() to add the actual prompts. The number - of prompts that can be added is the \a n_prompts value specified - in the earlier call to \a khui_cw_begin_custom_prompts(). - - Once \a n_prompts prompts have been added, the new prompts will - automatically be created and shown in the user interface. - However, if less than that prompts are added, nothing is displayed - to the user. - - \param[in] c Pointer to ::khui_new_creds structure - - \param[in] type Type of prompt. One of - ::KHUI_NCPROMPT_TYPE_PREAUTH, ::KHUI_NCPROMPT_TYPE_PASSWORD, - ::KHUI_NCPROMPT_TYPE_NEW_PASSWORD, - ::KHUI_NCPROMPT_TYPE_NEW_PASSWORD_AGAIN - - \param[in] prompt Text of the prompt. Constrained by - ::KHUI_MAXCCH_PROMPT. (Localized, required) - - \param[in] def Default value. (optional). Constrained by - ::KHUI_MAXCCH_PROMPT_VALUE. Set to NULL if not provided. - - \param[in] flags Flags. Combination of - ::KHUI_NCPROMPT_FLAG_HIDDEN - */ -KHMEXP khm_int32 KHMAPI -khui_cw_add_prompt(khui_new_creds * c, - khm_int32 type, - wchar_t * prompt, - wchar_t * def, - khm_int32 flags); - -/*! \brief Retrieve a custom prompt - - Retrieves an individual prompt. The \a idx parameter is a - zero-based index of the prompt to retrieve. The ordering is the - same as the order in which khui_cw_add_prompt() was called. - */ -KHMEXP khm_int32 KHMAPI -khui_cw_get_prompt(khui_new_creds * c, - khm_size idx, - khui_new_creds_prompt ** prompt); - -/*! \brief Get the number of custom prompts - - Retrieves the number of custom prompts currently displayed. If - this function is called between calling - khui_cw_begin_custom_prompts() and adding all the prompts, the - number returned will be the number of prompts that is expected to - be registered (i.e. the \a n_prompts parameter passed to - khui_cw_begin_custom_prompts()). - */ -KHMEXP khm_int32 KHMAPI -khui_cw_get_prompt_count(khui_new_creds * c, - khm_size * np); - - -/*! \brief Get the value of a custom prompt - - Retrieve the value of a specific prompt. The value is the string - that was typed into the input control associated with a custom - prompt. The \a idx parameter is the zero-based index of the - prompt from which to retrieve the value from. The ordering is the - same as the order in which khui_cw_add_prompt() was called. - - It is important to call khui_cw_sync_prompt_values() before - starting to call khui_cw_get_prompt_value() so that the values - returned are up-to-date. - */ -KHMEXP khm_int32 KHMAPI -khui_cw_get_prompt_value(khui_new_creds * c, - khm_size idx, - wchar_t * buf, - khm_size *cbbuf); - -/*! \brief Set the response for a plugin - - When handling ::KMSG_CRED_DIALOG_PROCESS from within the plugin - thread, it is important to set the response by calling this - function. The response can be used to signal whether the plugin - successfully obtained credentials or whether further interaction - is required, or the credentials acquisition failed. - - The response is a combination of : - - ::KHUI_NC_RESPONSE_PENDING - - ::KHUI_NC_RESPONSE_FAILED - - ::KHUI_NC_RESPONSE_PENDING - - ::KHUI_NC_RESPONSE_SUCCESS - - ::KHUI_NC_RESPONSE_NOEXIT - - ::KHUI_NC_RESPONSE_EXIT - */ -KHMEXP khm_int32 KHMAPI -khui_cw_set_response(khui_new_creds * c, - khm_int32 type, - khm_int32 response); - -/*! \brief Check whether a specified credential type panel succeeded - - This is called during the processing of ::KMSG_CRED_DIALOG_PROCESS - to determine whether a specified credential type succeeded in - obtaining credentials. The credential type that is being queried - should have also been listed as a dependency when adding the - current credentials type, otherwise the type queried may not have - been invoked yet. - - \return TRUE iff the queried type has reported that it successfully - completed the credentials acquision operation. - */ -KHMEXP khm_boolean KHMAPI -khui_cw_type_succeeded(khui_new_creds * c, - khm_int32 type); - -/*! \brief Add a row of controls to the identity specifier area - - Only for use by identity provider callbacks that wish to add an - identity selector control. A row of controls consist of a label - control and some input control. - - When the ::WMNC_IDENT_INIT message is sent to the identity - provider, it receives a handle to the dialog panel in the \a - lParam parameter which should be the parent window of both the - windows specified here. The control ID for any controls created - must fall within the ::KHUI_CW_ID_MIN and ::KHUI_CW_ID_MAX range. - - Both controls will be resized to fit in the row. - - If \a long_label is TRUE then the size of the label will be larger - than normal and will accomodate more text. - */ -KHMEXP khm_int32 KHMAPI -khui_cw_add_control_row(khui_new_creds * c, - HWND label, - HWND input, - khui_control_size size); - -/*!@}*/ /* Credentials acquisition */ -/*!@}*/ - -#endif +/* + * 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_KHNEWCRED_H +#define __KHIMAIRA_KHNEWCRED_H + +/******************************************************************** + New credentials windows +*********************************************************************/ + +/*! \addtogroup khui +@{ */ + +/*! \defgroup khui_cred Credentials acquisition + + Declarations associated with credentials acquisition. + +@{ */ + +/*! \brief Window message sent to credentials type panels + + This message is sent to the child windows. + + The format of the message is : + - uMsg : KHUI_WM_NC_NOTIFY + - HIWORD(wParam) : one of ::khui_wm_nc_notifications + - LPARAM : pointer to the ::khui_new_creds structure +*/ +#define KHUI_WM_NC_NOTIFY (WM_APP + 0x101) + +/*! \brief The first control ID that may be used by an identity provider */ +#define KHUI_CW_ID_MIN 8016 + +/*! \brief The maximum number of controls that may be created by an identity provider*/ +#define KHUI_CW_MAX_CTRLS 8 + +/*! \brief The maximum control ID that may be used by an identity provider */ +#define KHUI_CW_ID_MAX (KHUI_CW_ID_MIN + KHUI_CW_MAX_CTRLS - 1) + + +/*! \brief Credentials dialog notifications + + These notifications will be sent to the individual dialog + procedures of the credential type panels as a ::KHUI_WM_NC_NOTIFY + message. +*/ +enum khui_wm_nc_notifications { + WMNC_DIALOG_EXPAND = 1, + /*!< The dialog is switching from basic to advanced mode or vice + versa. + + This message is sent to the new creds dialog to set the dialog + to expanded mode. In expanded mode, all credentials type panels + are visible as opposed to the compressed mode where they are not + visible. The message is not sent to credentials type panels.*/ + + WMNC_DIALOG_SETUP, + /*!< Sent by NetIDMgr to the new creds window to notify it that + the dialog should create all the type configuration panels. + + Until this message is issued, none of the credentials type + panels exist. The credentials type panels will receive + WM_INITDIALOG etc as per the normal dialog creation process. */ + + WMNC_DIALOG_ACTIVATE, + /*!< Sent by NetIDMgr to the new creds window to notify it that + the dialog should do final initialization work and activate. */ + + WMNC_DIALOG_MOVE, + /*!< Sent by the new creds widnow to all the panels notifying them + that the NC window is moving. */ + + WMNC_DIALOG_SWITCH_PANEL, + /*!< Sent to the new creds window to cause it to switch to the + panel identified by LOWORD(wParam). + + Does nothing if the specified panel is already the current + panel. If the dialog is in compact mode and making the + specified panel visible requires switching to expanded mode, the + dialog will do so. */ + + WMNC_UPDATE_CREDTEXT, + /*!< Sent to all the credential type panels for a credentials + window to request them to update the credential text. + + When sent to the new credentials window, causes it to send the + WMNC_UPDATE_CREDTEXT message to all the credential type panels + and update the cred text window.*/ + + WMNC_CREDTEXT_LINK, + /*!< Sent to a panel dialog proc when a user clicks a credtext + embedded link that belongs to that panel. The \a lParam + parameter of the message is a pointer to a ::khui_htwnd_link + structure describing the link. */ + + WMNC_IDENTITY_CHANGE, + /*!< The primary identity has changed */ + + WMNC_CLEAR_PROMPTS, + /*!< Sent to the new creds window to clear any custom prompts */ + + WMNC_SET_PROMPTS, + /*!< Sent to the new creds window to set custom prompts */ + + WMNC_DIALOG_PREPROCESS, + /*!< Sent to all the credentials type panels to notify them that + the dialog is about to be processed */ + + WMNC_DIALOG_PROCESS, + /*!< Process the dialog and signal whether to exit the dialog or + not */ + + WMNC_DIALOG_PROCESS_COMPLETE, + /*!< Sent to the new creds window to indicate that the all the + threads have completed processing.*/ + + WMNC_TYPE_STATE, + /*!< Sent to the new creds window as notification that a + particular credentials type has changed state from enabled to + disabled or vice versa. The LPARAM member of the message + specifies the credentials type identifier for the changed + type */ + + WMNC_ADD_CONTROL_ROW, + /*!< Add a row of controls to a new cred dialog. This is an + internal message. */ + + WMNC_UPDATE_LAYOUT, + /*!< Update the layout of a dialog or window. This is an internal + message. */ +}; + +/*! \brief Plugins can use WMNC_NOTIFY message codes from here on up + + \see ::KHUI_WM_NC_NOTIFY + */ +#define WMNC_USER 2048 + +/*! \brief Notifications to the identity provider + + These notifications are sent through to the identity provider's UI + callback that was obtained using a ::KMSG_IDENT_GET_UI_CB message. + + The callback routine is called from the context of the UI thread + and is expected to not make any blocking calls. One of the + following commands will be passed in as the \a cmd parameter to + the callback. + */ +enum khui_wm_nc_ident_notify { + WMNC_IDENT_INIT, + /*!< Initialize an identity selector for a new credentials + dialog. The \a lParam parameter contains a handle to the + dialog window which will contain the identity selector + controls. The identity provider may make use of the \a + ident_aux field of the ::khui_new_creds structure to hold any + data pertaining to the credentials acquisition dialog.*/ + + WMNC_IDENT_WMSG, + /*!< Windows message. Presumably sent from one of the controls + that was created by the identity provider. The callback is + expected to return TRUE if it processed the message or FALSE + if it did not. The \a uMsg, \a wParam and \a lParam + parameters are set to the values passed in by Windows. */ + + WMNC_IDENT_EXIT, + /*!< Terminate a credentials acquisition dialog. Sent just before + the dialog is terminated. */ +}; + +/*! \name Standard credtext link IDs +@{*/ + +/*! \brief Switch the panel + + The \a id attribute of the link specifies the ordinal of the panel + to switch to. +*/ +#define CTLINKID_SWITCH_PANEL L"SwitchPanel" + +/*@}*/ + +/*forward dcl*/ +struct tag_khui_new_creds_by_type; +typedef struct tag_khui_new_creds_by_type khui_new_creds_by_type; +struct tag_khui_new_creds_prompt; +typedef struct tag_khui_new_creds_prompt khui_new_creds_prompt; +struct tag_khui_new_creds; +typedef struct tag_khui_new_creds khui_new_creds; + +typedef LRESULT +(KHMAPI *khui_ident_new_creds_cb)(khui_new_creds * nc, + UINT cmd, + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +/*! \brief New credentials acquisition blob + + A pointer to an object of this type is passed in along with the + credentials acquisition messages. + + \see \ref cred_acq for more information +*/ +typedef struct tag_khui_new_creds { + khm_int32 magic; /*!< Internal use */ + + khm_int32 subtype; /*!< Subtype of the request that is + being handled through this object. + One of ::KMSG_CRED_NEW_CREDS, + ::KMSG_CRED_RENEW_CREDS or + ::KMSG_CRED_PASSWORD */ + + CRITICAL_SECTION cs; /*!< Internal use */ + + khm_boolean set_default; /*!< After a successfull credentials + acquisition, set the primary + identity as the default. */ + + khm_handle *identities; /*!< The list of identities associated + with this request. The first + identity in this list (\a + identities[0]) is the primary + identity. */ + + khm_size n_identities; /*!< Number of identities in the list + \a identities */ + + khm_size nc_identities; /*!< Internal use */ + + khui_action_context ctx; /*!< An action context specifying the + context in which the credentials + acquisition operation was + launced. */ + + khm_int32 mode; /*!< The mode of the user interface. + One of ::KHUI_NC_MODE_MINI or + ::KHUI_NC_MODE_EXPANDED. */ + + HWND hwnd; /*!< Handle to the new credentials + window. */ + + struct tag_khui_new_creds_by_type **types; + /*!< Internal use */ + khm_handle *type_subs; /*!< Internal use */ + khm_size n_types; /*!< Internal use */ + khm_size nc_types; /*!< Internal use */ + + khm_int32 result; /*!< One of ::KHUI_NC_RESULT_CANCEL or + ::KHUI_NC_RESULT_PROCESS indicating + the result of the dialog with the + user */ + + khm_int32 response; /*!< Response. See individual message + documentation for info on what to do + with this field */ + + wchar_t *password; /*!< Not used. */ + + /* UI stuff */ + + wchar_t *banner; /*!< Internal use */ + wchar_t *pname; /*!< Internal use */ + khm_size n_prompts; /*!< Internal use */ + khm_size nc_prompts; /*!< Internal use */ + struct tag_khui_new_creds_prompt ** prompts; /*!< Internal use */ + + khui_ident_new_creds_cb ident_cb; /*!< Internal use */ + + wchar_t *window_title; /*!< Internal use */ + + LPARAM ident_aux; /*!< Auxilliary field which is + reserved for use by the identity + provider during the course of + conducting this dialog. */ + +} khui_new_creds; + +#define KHUI_NC_MAGIC 0x84270427 + +/*!\name Result values for khui_new_creds_t::result + @{*/ +#define KHUI_NC_RESULT_PROCESS 0 +#define KHUI_NC_RESULT_CANCEL 1 +/*@}*/ + +/*!\name Mode values for khui_new_creds_t::mode + @{*/ +#define KHUI_NC_MODE_MINI 0 +#define KHUI_NC_MODE_EXPANDED 1 +/*@}*/ + +/*!\name Response values for khui_new_creds_t::response + @{*/ +/*!\brief No known response */ +#define KHUI_NC_RESPONSE_NONE 0 + +/*!\brief It is okay to exit the dialog now + + This is the default, which is why it has a value of zero. In + order to prevent the dialog from exiting, set the + KHUI_NC_RESPONSE_NOEXIT response bit. */ +#define KHUI_NC_RESPONSE_EXIT 0 + +/*!\brief It is NOT okay to exit the dialog now + + Used to indicate that further user-interaction is necessary to + process the dialog. Usually this is accompanied by setting + necessary custom prompts and notifications so the user knows why + the dialog is prompting for more information. + */ +#define KHUI_NC_RESPONSE_NOEXIT 0x00000002 + +/*!\brief The dialog was processed successfully + + Since this is the default response, the value is zero. Use one of + KHUI_NC_RESPONSE_FAILED or KHUI_NC_RESPONSE_PENDING to indicate an + error or pending status. + */ +#define KHUI_NC_RESPONSE_SUCCESS 0 + +/*!\brief The processing of the dialog failed + + Self explanatory. More information about the failure should have + been reported using the khlog API, however, this response value + indicates to other credential types that depend on this credential + type that whatever it was that this credential type was supposed + to do didn't happen. +*/ +#define KHUI_NC_RESPONSE_FAILED 0x00000008 + +/*!\brief Further interaction required + + Set along with KHUI_NC_RESPONSE_NOEXIT although it is not + required. Setting this bit will automatically add the + KHUI_NC_RESPONSE_NOEXIT. + + If this bit is set, all dependent plugins will be set on hold + until another round of processing clears the pending bit. + */ +#define KHUI_NC_RESPONSE_PENDING 0x00000010 + +/*! \brief Completed + + This is automatically set if the plugin sets a response which does + not indicate either KHUI_NC_RESPONSE_NOEXIT or + KHUI_NC_RESPONSE_PENDING, which is considered to mean that the + plugin is completed processing. + + This flag cannot be explicitly specified in a response. + */ +#define KHUI_NC_RESPONSE_COMPLETED 0x00000020 + +/*! \brief Processing + + This is an internal flag set while the credentials acquisition + process is executing. + */ +#define KHUI_NC_RESPONSE_PROCESSING 0x00010000 + +#define KHUI_NCMASK_RESPONSE (KHUI_NC_RESPONSE_EXIT|KHUI_NC_RESPONSE_NOEXIT) +#define KHUI_NCMASK_RESULT (KHUI_NC_RESPONSE_SUCCESS|KHUI_NC_RESPONSE_FAILED|KHUI_NC_RESPONSE_PENDING) +/*@}*/ + +/*!\brief Maximum number of dependencies for a credentials type */ +#define KHUI_MAX_TYPE_DEPS 8 + +/*!\brief Maximum number of credential types for a new creds window */ +#define KHUI_MAX_NCTYPES 16 + +/*!\brief Maximum number of characters in a password + + Length includes the termininating NULL +*/ +#define KHUI_MAXCCH_PASSWORD 512 + +/*! \brief Maximum number of bytes in a password + + Includes terminating NULL +*/ +#define KHUI_MAXCB_PASSWORD (KHUI_MAXCCH_PASSWORD * sizeof(wchar_t)) + +/*! \brief Maximum number of characters in a custom banner + + Length includes terminating NULL +*/ +#define KHUI_MAXCCH_BANNER 256 + + +/*! \brief Maximum number of bytes in a custom banner + + Length includes terminating NULL +*/ +#define KHUI_MAXCB_BANNER (KHUI_MAXCCH_BANNER * sizeof(wchar_t)) + +/*! \brief Maximum number of characters in a panel name + + Length includes terminating NULL +*/ +#define KHUI_MAXCCH_PNAME 256 + +/*! \brief Maximum number of bytes in a panel name + + Length includes terminating NULL +*/ +#define KHUI_MAXCB_PNAME (KHUI_MAXCCH_PNAME * sizeof(wchar_t)) + +/*! \brief A descriptor of a panel in the new credentials acquisition tab + + When processing certain credentials messages such as + ::KMSG_CRED_PASSWORD, ::KMSG_CRED_NEW_CREDS, + ::KMSG_CRED_RENEW_CREDS, a pointer to a ::khui_new_creds structure + will be passed in to the message handler. If the handler of the + message needs to add one or more credentials types as participants + of the operation, the handler will need to call khui_cw_add_type() + and specify a ::khui_new_creds_by_type structure. + + Note that the memory address passed in to the call to + khui_cw_add_type() will not be copied. Therefore, the block of + memory should remain as-is for the lifetime of the + ::khui_new_creds structure or until it is removed with a call to + khui_cw_del_type(). + + Some of the credentials messages that require specifying a + ::khui_new_creds_by_type structure require providing a + user-interface. In these cases, the fields marked for providing a + UI may be required to hold valid values. If the message does not + require providing a UI, these fields will be ignored. +*/ +typedef struct tag_khui_new_creds_by_type { + khui_new_creds * nc; /*!< Internal use. Do not set */ + khm_int32 flags; /*!< Internal use. Do not set */ + + khm_int32 type; /*!< The identifier of the credentials + type. This is a credentials type + identifier allocated with a call to + kcdb_credtype_register(). */ + + khm_int32 type_deps[KHUI_MAX_TYPE_DEPS]; + /*!< credentials types that this + credential type depends on. Each + element defines a credentials type + identifier that this type depends + on for this operation. The number + of valid values in this array + should be specified in the \a + n_type_deps field. */ + + khm_size n_type_deps; /*!< Number of dependencies listed + above. Should be between 0 and + ::KHUI_MAX_TYPE_DEPS. Specify 0 if + there are no dependencies. */ + + khm_size ordinal; /*!< The requested ordinal. The UI + would attempt to place this panel at + the reqested order in the list of + panels. Set to -1 if the order does + not matter. Once the dialog is + activated this field will be updated + to reflect the actual ordinal of the + panel. */ + + wchar_t *name; /*!< Name of the panel (localized, + optional). If NULL, the localized + name of the credentials type is + used. Only used if providing a + user-interface. */ + + HICON icon; /*!< Icon for the panel (optional). + Only used if providing a + user-interface. */ + + wchar_t *tooltip; /*!< Tooltip for the panel (localized, + optional). If NULL, no tooltip will + be assigned for the panel. Only + used if providing a + user-interface. */ + + HMODULE h_module; /*!< Handle to the module containing + the dialog resource. Only used if + providing a user-interface. */ + + LPWSTR dlg_template; /*!< The dialog resource. Only used + if providing a user-interface. */ + DLGPROC dlg_proc; /*!< The dialog procedure. Only used + if providing a user-interface. */ + + HWND hwnd_panel; /*!< The dialog window. Once the + dialog panel is created, a handle to + the panel will be assigned here. + Note that the handle is assigned + after a successful call to + CreateDialogParam and hence would + not be available when handling the + WM_INITDIALOG message from the + dialog procedure. Only used of + providing a user-interface. */ + + HWND hwnd_tc; /*!< Internal use. Do not set */ + + wchar_t *credtext; /*!< A brief description of the + current state of this cred + type. (localized, optional). Only + used if providing a + user-interface. If this field is + non-NULL, then it should point to a + NULL terminated string that does not + exceed ::KHUI_MAXCCH_LONG_DESC + characters in length including the + terminating NULL. + + \see \ref khui_htwnd for information + on how to format the string for this + field. + */ + + LPARAM aux; /*!< auxilliary field. For use by the + plug-in. */ +} khui_new_creds_by_type; + +/*!\name Flags for khui_new_creds_by_type + + Note that KHUI_NC_RESPONSE_SUCCESS, KHUI_NC_RESPONSE_FAILED, + KHUI_NC_RESPONSE_PENDING are also stored in the flags. + +@{*/ +#define KHUI_NCT_FLAG_PROCESSED 1024 +#define KHUI_NCT_FLAG_DISABLED 2048 +/*@}*/ + +/*! \brief Width of a new creds dialog panel in dialog units*/ +#define NCDLG_WIDTH 300 +/*! \brief Height of a new creds dialog panel in dialog units*/ +#define NCDLG_HEIGHT 166 + +/*! \brief A custom prompt */ +typedef struct tag_khui_new_creds_prompt { + khm_size index; /*!< Set to the zero based index + of this prompt. */ + + khm_int32 type; /*!< one of KHUI_NCPROMPT_TYPE_* */ + wchar_t * prompt; /*!< prompt string. Cannot exceed + KHUI_MAXCCH_PROMPT */ + wchar_t * def; /*!< default value. Cannot exceed + KHUI_MAXCCH_PROMPT_VALUE */ + wchar_t * value; /*!< On completion, this is set to the + value that the user entered. Will + not exceed + KHUI_MAXCCH_PROMPT_VALUE */ + + khm_int32 flags; /*!< Combination of + KHUI_NCPROMPT_FLAG_* */ + + HWND hwnd_static; /* internal use */ + HWND hwnd_edit; /* internal use */ +} khui_new_creds_prompt; + +/*! \brief The prompt input is hidden + + The input is hidden for prompts which accept passwords. The + control which represents the input will display an asterisk or a + small circle corresponding to each character typed in, but will + not show the actual character. + */ +#define KHUI_NCPROMPT_FLAG_HIDDEN 1 + +/*! \brief Internal use */ +#define KHUI_NCPROMPT_FLAG_STOCK 2 + +/*! \brief Maximum number of characters in a prompt + + Refers to the prompt text that accompanies an input control. THe + length includes the terminating NULL. + */ +#define KHUI_MAXCCH_PROMPT 256 + +/*! \brief Maximum number of bytes in a prompt + + Refers to the prompt text that accompanies an input control. THe + length includes the terminating NULL. + */ +#define KHUI_MAXCB_PROMPT (KHUI_MAXCCH_PROMPT * sizeof(wchar_t)) + +/*! \brief Maximum number of characters that can be entered in an input control + + Refers to the input control of a prompt. The length includes the + terminating NULL. + */ +#define KHUI_MAXCCH_PROMPT_VALUE 256 + +/*! \brief Maximum number of bytes that can be entered in an input control + + Refers to the input control of a prompt. The length includes the + terminating NULL. + */ +#define KHUI_MAXCB_PROMPT_VALUE (KHUI_MAXCCH_PROMPT_VALUE * sizeof(wchar_t)) + +/* from krb5.h. Redefining here because we don't want to depend on + krb5.h for all credential types */ + +/*! \brief A password control */ +#define KHUI_NCPROMPT_TYPE_PASSWORD 1 + +/*! \brief New password control + + Used when changing the password + */ +#define KHUI_NCPROMPT_TYPE_NEW_PASSWORD 2 + +/*! \brief New password again control + + Used when changing the password + */ +#define KHUI_NCPROMPT_TYPE_NEW_PASSWORD_AGAIN 3 + +/*! \brief Preauthentication (reserved) */ +#define KHUI_NCPROMPT_TYPE_PREAUTH 4 + +/*! \brief Control sizes */ +typedef enum tag_khui_control_size { + KHUI_CTRLSIZE_SMALL, + /*!< A small control fits in about 1/5 the width of the new + credentials panel */ + KHUI_CTRLSIZE_HALF, + /*!< Half size controls fit in 1/2 the width of the new + credentials panel */ + KHUI_CTRLSIZE_FULL, + /*!< Takes up the whole width of the crednetials panel */ +} khui_control_size; + +/*! \brief Internal use */ +typedef struct tag_khui_control_row { + HWND label; + HWND input; + khui_control_size size; +} khui_control_row; + +/*! \brief Create a ::khui_new_creds object + + Creates and initializes a ::khui_new_creds object. The created + object must be destroyed using the khui_cw_destroy_cred_blob() + function. + + \note Plugins should not call this function directly. The + necessary ::khui_new_creds objects will be created by + NetIDMgr. + + \see khui_cw_destroy_cred_blob() + */ +KHMEXP khm_int32 KHMAPI +khui_cw_create_cred_blob(khui_new_creds ** c); + +/*! \brief Destroy a ::khui_new_creds object + + Destroys a ::khui_new_creds object that was fomerly created using + a call to khui_cw_create_cred_blob(). + + \note Plugins should not call this function directly. The + necessary ::khui_new_creds objects will be created by + NetIDMgr. + + \see khui_cw_create_cred_blob() +*/ +KHMEXP khm_int32 KHMAPI +khui_cw_destroy_cred_blob(khui_new_creds *c); + +/*! \brief Lock the new_creds object + + When a plugin is accessing the fields of a ::khui_new_creds + object, it must first obtain a lock on the object so that other + threads will not modify the fields at the same time. Locking the + object ensures that the fields of the object will be consistent. + + Use khui_cw_unlock_nc() to undo the lock obtained through a call + to khui_cw_lock_nc(). + + It is not necessary to lock a new credentials object when + modifying it using the NetIDMgr API. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_lock_nc(khui_new_creds * c); + +/*! \brief Unlock a new_creds object + + \see khui_cw_lock_nc() + */ +KHMEXP khm_int32 KHMAPI +khui_cw_unlock_nc(khui_new_creds * c); + +/*! \brief Add a new panel to a new credentials acquisition window + + See the description of ::khui_new_cred_panel for information on + how to populate it to describe a credentials type panel. + + Note that the structure pointed to by \a t is added by reference. + The memory pointed to by \a t is not copied. Hence, the block of + memory and any other blocks pointed to by the + ::khui_new_creds_by_type structure located there should remain + intact for the lifetime of the ::khui_new_creds structure pointed + to by \a c or until the credentials type panel is removed from the + ::khui_new_creds structure with a call to khui_cw_del_type(). + + Generally, a plug-in that calls this function should allocate a + block of memory to contain the ::khui_new_creds_by_type structure, + fill it in and then pass in the address in a call to + khui_cw_add_type() while handling a ::KMSG_CRED_PASSWORD, + ::KMSG_CRED_NEW_CREDS or ::KMSG_CRED_RENEW_CREDS message. Then + the plug-in should remove the reference with a call to + khui_cw_del_type() while processing ::KMSG_CRED_END. + + \see khui_cw_del_type() + \see \ref cred_acq_panel_spec + \see ::khui_new_cred_panel + \see ::khui_new_creds +*/ +KHMEXP khm_int32 KHMAPI +khui_cw_add_type(khui_new_creds * c, + khui_new_creds_by_type * t); + +/*! \brief Remove a panel from a new credentials acquisition window + + \see khui_cw_add_type() + */ +KHMEXP khm_int32 KHMAPI +khui_cw_del_type(khui_new_creds * c, + khm_int32 type); + +/*! \brief Find the panel belonging to a particular credentials type + + This panel would have been added to the new credentials window + using khui_cw_add_type(). + + \see khui_cw_add_type() + */ +KHMEXP khm_int32 KHMAPI +khui_cw_find_type(khui_new_creds * c, + khm_int32 type, + khui_new_creds_by_type **t); + +/*! \brief Enable/disable a particular credentials type + + Enables or disables the panel associated with a particular + credentials type. Does not preclude the credentials type from + participating in the new credentials acquisition. However, the + user will be prevented from interacting with the specific panel. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_enable_type(khui_new_creds * c, + khm_int32 type, + khm_boolean enable); + +/*! \brief Set the primary identity in a new credentials acuisition + + The primary identity dictates many of the defaults and the + semantics associated with the credentials acquision process. + Setting the primary identity also triggers the + ::WMNC_IDENTITY_CHANGE notification which will be sent to all the + credentials type panels. + + Has no effect if the primary identity is already the same as the + one specified in \a id. Specify NULL for \a id if the current + primary identity is to be cleared. + + If the primary identity is changed, then all the additional + identities associated with the new credentials acquisition dialog + will also be discarded. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_set_primary_id(khui_new_creds * c, + khm_handle id); + +/*! \brief Add an additional identity to the new credentials acquisition + + Individual plugins are free to decide how to handle additional + identities. Generally, they would attempt to obtain credentials + for the primary and additional identities, but would not consider + it an error if an additional identity failed to obtain + credentials. + + Calling this function with \a id of NULL does nothing. +*/ +KHMEXP khm_int32 KHMAPI +khui_cw_add_identity(khui_new_creds * c, + khm_handle id); + +/*! \brief Clear all custom prompts + + Removes all the custom prompts from the new credentials dialog. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_clear_prompts(khui_new_creds * c); + +/*! \brief Synchronize custom prompt values + + It is important to synchronize the values before accessing their + values. The controls associated with custom prompts update the + values in the ::khui_new_creds object periodically. However, the + values may lose sync intermittently. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_sync_prompt_values(khui_new_creds * c); + +/*! \brief Begin custom prompting + + Begins the process of defining custom prompts. Implicity removes + all the custom prompts that are currently being displayed. The \a + banner and \a name will be displayed in separate controls above + the set of new custom prompts. + + The controls associated with the prompts will not actually be + created until all the prompts have been added using + khui_cw_add_prompt(). The number of promtps that can be added + will be exactly \a n_prompts. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_begin_custom_prompts(khui_new_creds * c, + khm_size n_prompts, + wchar_t * banner, + wchar_t * name); + +/*! \brief Add a custom prompt + + After khui_cw_begin_custom_prompts() is called, the plugin should + call khui_cw_add_prompt() to add the actual prompts. The number + of prompts that can be added is the \a n_prompts value specified + in the earlier call to \a khui_cw_begin_custom_prompts(). + + Once \a n_prompts prompts have been added, the new prompts will + automatically be created and shown in the user interface. + However, if less than that prompts are added, nothing is displayed + to the user. + + \param[in] c Pointer to ::khui_new_creds structure + + \param[in] type Type of prompt. One of + ::KHUI_NCPROMPT_TYPE_PREAUTH, ::KHUI_NCPROMPT_TYPE_PASSWORD, + ::KHUI_NCPROMPT_TYPE_NEW_PASSWORD, + ::KHUI_NCPROMPT_TYPE_NEW_PASSWORD_AGAIN + + \param[in] prompt Text of the prompt. Constrained by + ::KHUI_MAXCCH_PROMPT. (Localized, required) + + \param[in] def Default value. (optional). Constrained by + ::KHUI_MAXCCH_PROMPT_VALUE. Set to NULL if not provided. + + \param[in] flags Flags. Combination of + ::KHUI_NCPROMPT_FLAG_HIDDEN + */ +KHMEXP khm_int32 KHMAPI +khui_cw_add_prompt(khui_new_creds * c, + khm_int32 type, + wchar_t * prompt, + wchar_t * def, + khm_int32 flags); + +/*! \brief Retrieve a custom prompt + + Retrieves an individual prompt. The \a idx parameter is a + zero-based index of the prompt to retrieve. The ordering is the + same as the order in which khui_cw_add_prompt() was called. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_get_prompt(khui_new_creds * c, + khm_size idx, + khui_new_creds_prompt ** prompt); + +/*! \brief Get the number of custom prompts + + Retrieves the number of custom prompts currently displayed. If + this function is called between calling + khui_cw_begin_custom_prompts() and adding all the prompts, the + number returned will be the number of prompts that is expected to + be registered (i.e. the \a n_prompts parameter passed to + khui_cw_begin_custom_prompts()). + */ +KHMEXP khm_int32 KHMAPI +khui_cw_get_prompt_count(khui_new_creds * c, + khm_size * np); + + +/*! \brief Get the value of a custom prompt + + Retrieve the value of a specific prompt. The value is the string + that was typed into the input control associated with a custom + prompt. The \a idx parameter is the zero-based index of the + prompt from which to retrieve the value from. The ordering is the + same as the order in which khui_cw_add_prompt() was called. + + It is important to call khui_cw_sync_prompt_values() before + starting to call khui_cw_get_prompt_value() so that the values + returned are up-to-date. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_get_prompt_value(khui_new_creds * c, + khm_size idx, + wchar_t * buf, + khm_size *cbbuf); + +/*! \brief Set the response for a plugin + + When handling ::KMSG_CRED_DIALOG_PROCESS from within the plugin + thread, it is important to set the response by calling this + function. The response can be used to signal whether the plugin + successfully obtained credentials or whether further interaction + is required, or the credentials acquisition failed. + + The response is a combination of : + - ::KHUI_NC_RESPONSE_PENDING + - ::KHUI_NC_RESPONSE_FAILED + - ::KHUI_NC_RESPONSE_PENDING + - ::KHUI_NC_RESPONSE_SUCCESS + - ::KHUI_NC_RESPONSE_NOEXIT + - ::KHUI_NC_RESPONSE_EXIT + */ +KHMEXP khm_int32 KHMAPI +khui_cw_set_response(khui_new_creds * c, + khm_int32 type, + khm_int32 response); + +/*! \brief Check whether a specified credential type panel succeeded + + This is called during the processing of ::KMSG_CRED_DIALOG_PROCESS + to determine whether a specified credential type succeeded in + obtaining credentials. The credential type that is being queried + should have also been listed as a dependency when adding the + current credentials type, otherwise the type queried may not have + been invoked yet. + + \return TRUE iff the queried type has reported that it successfully + completed the credentials acquision operation. + */ +KHMEXP khm_boolean KHMAPI +khui_cw_type_succeeded(khui_new_creds * c, + khm_int32 type); + +/*! \brief Add a row of controls to the identity specifier area + + Only for use by identity provider callbacks that wish to add an + identity selector control. A row of controls consist of a label + control and some input control. + + When the ::WMNC_IDENT_INIT message is sent to the identity + provider, it receives a handle to the dialog panel in the \a + lParam parameter which should be the parent window of both the + windows specified here. The control ID for any controls created + must fall within the ::KHUI_CW_ID_MIN and ::KHUI_CW_ID_MAX range. + + Both controls will be resized to fit in the row. + + If \a long_label is TRUE then the size of the label will be larger + than normal and will accomodate more text. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_add_control_row(khui_new_creds * c, + HWND label, + HWND input, + khui_control_size size); + +/*!@}*/ /* Credentials acquisition */ +/*!@}*/ + +#endif diff --git a/src/windows/identity/uilib/khprops.h b/src/windows/identity/uilib/khprops.h index c0977b80c..a00c65f7f 100644 --- a/src/windows/identity/uilib/khprops.h +++ b/src/windows/identity/uilib/khprops.h @@ -1,209 +1,209 @@ -/* - * 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_KHPROPS_H -#define __KHIMAIRA_KHPROPS_H - -#include - -/********************************************************************* - Property sheets -**********************************************************************/ - -/*! \addtogroup khui - -@{*/ - -/*!\defgroup khui_pp Property sheets -@{*/ - -/* forward dcl */ -struct tag_khui_property_page; - -/*! \brief A property sheet - */ -typedef struct tag_khui_property_sheet { - PROPSHEETHEADER header; /*!< property sheet header */ - khm_int32 status; /*!< status of property sheet. One of - ::KHUI_PS_STATUS_NONE, - ::KHUI_PS_STATUS_RUNNING or - ::KHUI_PS_STATUS_DONE */ - - HWND hwnd; /*!< handle to the property sheet window. - Only valid when \a status is NOT - ::KHUI_PS_STATUS_NONE */ - - HWND hwnd_page; /*!< handle to the current page in the - property sheet. Only valid when \a - status is ::KHUI_PS_STATUS_RUNNING */ - - khui_action_context ctx; /*!< Context for the property sheet. See - documentation for - ::khui_action_context */ - - khm_handle identity; /*!< Handle to the associated identity, - if applicable */ - khm_int32 credtype; /*!< Type ID of the credentials type, if - applicable */ - khm_handle cred; /*!< Handle to the associated credential, - if applicable */ - - khm_int32 n_pages; /*!< Number of property pages. - Upperbound of ::KHUI_PS_MAX_PSP */ - - QDCL(struct tag_khui_property_page); -} khui_property_sheet; - -/*! \brief The property sheet hasn't been created yet */ -#define KHUI_PS_STATUS_NONE 0 - -/*! \brief The property sheet is visible and running */ -#define KHUI_PS_STATUS_RUNNING 1 - -/*! \brief The property sheet has completed running. - - At this point, it is safe to call khui_ps_destroy_sheet() to - destroy the property sheet. -*/ -#define KHUI_PS_STATUS_DONE 2 - -/*! \brief The property sheet is in the process of being destroyed - */ -#define KHUI_PS_STATUS_DESTROY 3 - -/*! \brief Maximum number of property sheet pages in a property sheet */ -#define KHUI_PS_MAX_PSP 16 - - -/*! \brief A property sheet page - */ -typedef struct tag_khui_property_page { - HPROPSHEETPAGE h_page; - LPPROPSHEETPAGE p_page; - HWND hwnd; - khm_int32 credtype; - khm_int32 ordinal; - - LDCL(struct tag_khui_property_page); -} khui_property_page; - -/*! \brief Special pseudo credtype for identity page - */ -#define KHUI_PPCT_IDENTITY (-8) - -/*! \brief Special pseudo credtype for credential page - */ -#define KHUI_PPCT_CREDENTIAL (-9) - -/*! \brief Create a property sheet - - \note Only called by the NetIDMgr application. - */ -KHMEXP khm_int32 KHMAPI -khui_ps_create_sheet(khui_property_sheet ** sheet); - -/*! \brief Add a page to a property sheet - - Called by a plugin or the NetIDMgr application to add a page to a - property sheet. - - Pages can only be added before the property sheet is made visible - to the user. - - \param[in] sheet The property sheet to add the page to - - \param[in] credtype The credentials type ID of the owner of the - property page. This should be set to ::KCDB_CREDTYPE_INVALID - if the type is not relevant. - - \param[in] ordinal Requested ordinal. A positive integer which is - used to order the pages in a property sheet. The pages are - ordered based on ordinal first and then alphabetically by - credentials type name. If the type is unavailable, then the - ordering is undefined. Ordinals for credential type property - pages can be in the range from 0 to 127. Ordinals 128 and - above are reserved. Passing in 0 will work for credentials - providers unless they provide more than one property page per - credential, in which case the ordinal should be used to - enforce an order. - - \param[in] ppage Pointer to structure that will be passed to - CreatePropertySheetPage() to create the property page. The - structure is not managed by NetIDMgr at all, and must exist - until the status of the property sheet changes to - ::KHUI_PS_STATUS_RUNNING. The same pointer will be found in - the \a p_page member of the ::khui_property_page structure. - - \param[out] page A pointer will be returned here that will point - to the newly created khui_property_page structure. Specify - NULL if this value is not required. You can use - khui_ps_find_page() to retrieve a pointer to the structure - later. - */ -KHMEXP khm_int32 KHMAPI -khui_ps_add_page(khui_property_sheet * sheet, - khm_int32 credtype, - khm_int32 ordinal, - LPPROPSHEETPAGE ppage, - khui_property_page ** page); - -/*! \brief Retrieve a property page structure from a property sheet - */ -KHMEXP khm_int32 KHMAPI -khui_ps_find_page(khui_property_sheet * sheet, - khm_int32 credtype, - khui_property_page ** page); - -/*! \brief Display the property sheet - - \note Only called by the NetIDMgr application - */ -KHMEXP HWND KHMAPI -khui_ps_show_sheet(HWND parent, - khui_property_sheet * sheet); - -/*! \brief Check if the given message belongs to the property sheet - - \note Only called by the NetIDMgr application - */ -KHMEXP LRESULT KHMAPI -khui_ps_check_message(khui_property_sheet * sheet, - PMSG msg); - -/*! \brief Destroy a property sheet and all associated data structures. - - \note Only called by the NetIDMgr application. -*/ -KHMEXP khm_int32 KHMAPI -khui_ps_destroy_sheet(khui_property_sheet * sheet); - -KHMEXP khm_int32 KHMAPI -khui_property_wnd_set_record(HWND hwnd_pwnd, khm_handle record); - -/*!@}*/ -/*!@}*/ - -#endif +/* + * 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_KHPROPS_H +#define __KHIMAIRA_KHPROPS_H + +#include + +/********************************************************************* + Property sheets +**********************************************************************/ + +/*! \addtogroup khui + +@{*/ + +/*!\defgroup khui_pp Property sheets +@{*/ + +/* forward dcl */ +struct tag_khui_property_page; + +/*! \brief A property sheet + */ +typedef struct tag_khui_property_sheet { + PROPSHEETHEADER header; /*!< property sheet header */ + khm_int32 status; /*!< status of property sheet. One of + ::KHUI_PS_STATUS_NONE, + ::KHUI_PS_STATUS_RUNNING or + ::KHUI_PS_STATUS_DONE */ + + HWND hwnd; /*!< handle to the property sheet window. + Only valid when \a status is NOT + ::KHUI_PS_STATUS_NONE */ + + HWND hwnd_page; /*!< handle to the current page in the + property sheet. Only valid when \a + status is ::KHUI_PS_STATUS_RUNNING */ + + khui_action_context ctx; /*!< Context for the property sheet. See + documentation for + ::khui_action_context */ + + khm_handle identity; /*!< Handle to the associated identity, + if applicable */ + khm_int32 credtype; /*!< Type ID of the credentials type, if + applicable */ + khm_handle cred; /*!< Handle to the associated credential, + if applicable */ + + khm_int32 n_pages; /*!< Number of property pages. + Upperbound of ::KHUI_PS_MAX_PSP */ + + QDCL(struct tag_khui_property_page); +} khui_property_sheet; + +/*! \brief The property sheet hasn't been created yet */ +#define KHUI_PS_STATUS_NONE 0 + +/*! \brief The property sheet is visible and running */ +#define KHUI_PS_STATUS_RUNNING 1 + +/*! \brief The property sheet has completed running. + + At this point, it is safe to call khui_ps_destroy_sheet() to + destroy the property sheet. +*/ +#define KHUI_PS_STATUS_DONE 2 + +/*! \brief The property sheet is in the process of being destroyed + */ +#define KHUI_PS_STATUS_DESTROY 3 + +/*! \brief Maximum number of property sheet pages in a property sheet */ +#define KHUI_PS_MAX_PSP 16 + + +/*! \brief A property sheet page + */ +typedef struct tag_khui_property_page { + HPROPSHEETPAGE h_page; + LPPROPSHEETPAGE p_page; + HWND hwnd; + khm_int32 credtype; + khm_int32 ordinal; + + LDCL(struct tag_khui_property_page); +} khui_property_page; + +/*! \brief Special pseudo credtype for identity page + */ +#define KHUI_PPCT_IDENTITY (-8) + +/*! \brief Special pseudo credtype for credential page + */ +#define KHUI_PPCT_CREDENTIAL (-9) + +/*! \brief Create a property sheet + + \note Only called by the NetIDMgr application. + */ +KHMEXP khm_int32 KHMAPI +khui_ps_create_sheet(khui_property_sheet ** sheet); + +/*! \brief Add a page to a property sheet + + Called by a plugin or the NetIDMgr application to add a page to a + property sheet. + + Pages can only be added before the property sheet is made visible + to the user. + + \param[in] sheet The property sheet to add the page to + + \param[in] credtype The credentials type ID of the owner of the + property page. This should be set to ::KCDB_CREDTYPE_INVALID + if the type is not relevant. + + \param[in] ordinal Requested ordinal. A positive integer which is + used to order the pages in a property sheet. The pages are + ordered based on ordinal first and then alphabetically by + credentials type name. If the type is unavailable, then the + ordering is undefined. Ordinals for credential type property + pages can be in the range from 0 to 127. Ordinals 128 and + above are reserved. Passing in 0 will work for credentials + providers unless they provide more than one property page per + credential, in which case the ordinal should be used to + enforce an order. + + \param[in] ppage Pointer to structure that will be passed to + CreatePropertySheetPage() to create the property page. The + structure is not managed by NetIDMgr at all, and must exist + until the status of the property sheet changes to + ::KHUI_PS_STATUS_RUNNING. The same pointer will be found in + the \a p_page member of the ::khui_property_page structure. + + \param[out] page A pointer will be returned here that will point + to the newly created khui_property_page structure. Specify + NULL if this value is not required. You can use + khui_ps_find_page() to retrieve a pointer to the structure + later. + */ +KHMEXP khm_int32 KHMAPI +khui_ps_add_page(khui_property_sheet * sheet, + khm_int32 credtype, + khm_int32 ordinal, + LPPROPSHEETPAGE ppage, + khui_property_page ** page); + +/*! \brief Retrieve a property page structure from a property sheet + */ +KHMEXP khm_int32 KHMAPI +khui_ps_find_page(khui_property_sheet * sheet, + khm_int32 credtype, + khui_property_page ** page); + +/*! \brief Display the property sheet + + \note Only called by the NetIDMgr application + */ +KHMEXP HWND KHMAPI +khui_ps_show_sheet(HWND parent, + khui_property_sheet * sheet); + +/*! \brief Check if the given message belongs to the property sheet + + \note Only called by the NetIDMgr application + */ +KHMEXP LRESULT KHMAPI +khui_ps_check_message(khui_property_sheet * sheet, + PMSG msg); + +/*! \brief Destroy a property sheet and all associated data structures. + + \note Only called by the NetIDMgr application. +*/ +KHMEXP khm_int32 KHMAPI +khui_ps_destroy_sheet(khui_property_sheet * sheet); + +KHMEXP khm_int32 KHMAPI +khui_property_wnd_set_record(HWND hwnd_pwnd, khm_handle record); + +/*!@}*/ +/*!@}*/ + +#endif diff --git a/src/windows/identity/uilib/khremote.h b/src/windows/identity/uilib/khremote.h index 5de877da6..3a79d6555 100644 --- a/src/windows/identity/uilib/khremote.h +++ b/src/windows/identity/uilib/khremote.h @@ -1,84 +1,84 @@ -/* - * 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_REMOTE_H -#define __KHIMAIRA_REMOTE_H - -/*! \addtogroup khui - @{*/ -/*! \defgroup khui_remote Connecting to NetIDMgr from another process - @{*/ - -/* Leash compatibility */ -#define ID_OBTAIN_TGT_WITH_LPARAM 32810 - -#define KHUI_REQDAEMONWND_CLASS L"IDMgrRequestDaemonCls" -#define KHUI_REQDAEMONWND_NAME L"IDMgrRequestDaemon" - -#define KHUI_REQD_MAPPING_FORMAT L"Local\\NetIDMgr_DlgInfo_%lu" - -#define NETID_USERNAME_SZ 128 -#define NETID_REALM_SZ 192 -#define NETID_TITLE_SZ 256 -#define NETID_CCACHE_NAME_SZ 264 - -#define NETID_DLGTYPE_TGT 0 -#define NETID_DLGTYPE_CHPASSWD 1 -typedef struct { - DWORD size; - DWORD dlgtype; - // Tells whether dialog box is in change pwd mode or init ticket mode - struct { - WCHAR title[NETID_TITLE_SZ]; - WCHAR username[NETID_USERNAME_SZ]; - WCHAR realm[NETID_REALM_SZ]; - WCHAR ccache[NETID_CCACHE_NAME_SZ]; - DWORD use_defaults; - DWORD forwardable; - DWORD noaddresses; - DWORD lifetime; - DWORD renew_till; - DWORD proxiable; - DWORD publicip; - DWORD must_use_specified_principal; - } in; - struct { - WCHAR username[NETID_USERNAME_SZ]; - WCHAR realm[NETID_REALM_SZ]; - WCHAR ccache[NETID_CCACHE_NAME_SZ]; - } out; - // Version 1 of this structure ends here -} NETID_DLGINFO, *LPNETID_DLGINFO; - -#define NETID_DLGINFO_V1_SZ (10 * sizeof(DWORD) \ - + sizeof(WCHAR) * (NETID_TITLE_SZ + \ - 2 * NETID_USERNAME_SZ + 2 * NETID_REALM_SZ + \ - 2 * NETID_CCACHE_NAME_SZ)) - -/*!@} */ -/*!@} */ - -#endif +/* + * 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_REMOTE_H +#define __KHIMAIRA_REMOTE_H + +/*! \addtogroup khui + @{*/ +/*! \defgroup khui_remote Connecting to NetIDMgr from another process + @{*/ + +/* Leash compatibility */ +#define ID_OBTAIN_TGT_WITH_LPARAM 32810 + +#define KHUI_REQDAEMONWND_CLASS L"IDMgrRequestDaemonCls" +#define KHUI_REQDAEMONWND_NAME L"IDMgrRequestDaemon" + +#define KHUI_REQD_MAPPING_FORMAT L"Local\\NetIDMgr_DlgInfo_%lu" + +#define NETID_USERNAME_SZ 128 +#define NETID_REALM_SZ 192 +#define NETID_TITLE_SZ 256 +#define NETID_CCACHE_NAME_SZ 264 + +#define NETID_DLGTYPE_TGT 0 +#define NETID_DLGTYPE_CHPASSWD 1 +typedef struct { + DWORD size; + DWORD dlgtype; + // Tells whether dialog box is in change pwd mode or init ticket mode + struct { + WCHAR title[NETID_TITLE_SZ]; + WCHAR username[NETID_USERNAME_SZ]; + WCHAR realm[NETID_REALM_SZ]; + WCHAR ccache[NETID_CCACHE_NAME_SZ]; + DWORD use_defaults; + DWORD forwardable; + DWORD noaddresses; + DWORD lifetime; + DWORD renew_till; + DWORD proxiable; + DWORD publicip; + DWORD must_use_specified_principal; + } in; + struct { + WCHAR username[NETID_USERNAME_SZ]; + WCHAR realm[NETID_REALM_SZ]; + WCHAR ccache[NETID_CCACHE_NAME_SZ]; + } out; + // Version 1 of this structure ends here +} NETID_DLGINFO, *LPNETID_DLGINFO; + +#define NETID_DLGINFO_V1_SZ (10 * sizeof(DWORD) \ + + sizeof(WCHAR) * (NETID_TITLE_SZ + \ + 2 * NETID_USERNAME_SZ + 2 * NETID_REALM_SZ + \ + 2 * NETID_CCACHE_NAME_SZ)) + +/*!@} */ +/*!@} */ + +#endif diff --git a/src/windows/identity/uilib/khrescache.h b/src/windows/identity/uilib/khrescache.h index eeb4f6585..63baa1f72 100644 --- a/src/windows/identity/uilib/khrescache.h +++ b/src/windows/identity/uilib/khrescache.h @@ -1,100 +1,100 @@ -/* - * 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_RESCACHE_H -#define __KHIMAIRA_RESCACHE_H - -#include - -KHMEXP void KHMAPI -khui_init_rescache(void); - -KHMEXP void KHMAPI -khui_exit_rescache(void); - -KHMEXP void KHMAPI -khui_cache_bitmap(UINT id, HBITMAP hbm); - -KHMEXP HBITMAP KHMAPI -khui_get_cached_bitmap(UINT id); - -typedef struct khui_ilist_t { - int cx; - int cy; - int n; - int ng; - int nused; - HBITMAP img; - HBITMAP mask; - int *idlist; -} khui_ilist; - -typedef struct khui_bitmap_t { - HBITMAP hbmp; - int cx; - int cy; -} khui_bitmap; - -KHMEXP void KHMAPI -khui_bitmap_from_hbmp(khui_bitmap * kbm, HBITMAP hbm); - -KHMEXP void KHMAPI -khui_delete_bitmap(khui_bitmap * kbm); - -KHMEXP void KHMAPI -khui_draw_bitmap(HDC hdc, int x, int y, khui_bitmap * kbm); - -/* image lists */ -KHMEXP khui_ilist * KHMAPI -khui_create_ilist(int cx, int cy, int n, int ng, int opt); - -KHMEXP BOOL KHMAPI -khui_delete_ilist(khui_ilist * il); - -KHMEXP int KHMAPI -khui_ilist_add_masked(khui_ilist * il, HBITMAP hbm, COLORREF cbkg); - -KHMEXP int KHMAPI -khui_ilist_add_masked_id(khui_ilist *il, HBITMAP hbm, - COLORREF cbkg, int id); - -KHMEXP int KHMAPI -khui_ilist_lookup_id(khui_ilist *il, int id); - -KHMEXP void KHMAPI -khui_ilist_draw(khui_ilist * il, int idx, HDC dc, int x, int y, int opt); - -KHMEXP void KHMAPI -khui_ilist_draw_bg(khui_ilist * il, int idx, HDC dc, int x, int y, - int opt, COLORREF bgcolor); - -#define khui_ilist_draw_id(il, id, dc, x, y, opt) \ - khui_ilist_draw((il),khui_ilist_lookup_id((il),(id)),(dc),(x),(y),(opt)) - -#define KHUI_SMICON_CX 16 -#define KHUI_SMICON_CY 16 - -#endif +/* + * 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_RESCACHE_H +#define __KHIMAIRA_RESCACHE_H + +#include + +KHMEXP void KHMAPI +khui_init_rescache(void); + +KHMEXP void KHMAPI +khui_exit_rescache(void); + +KHMEXP void KHMAPI +khui_cache_bitmap(UINT id, HBITMAP hbm); + +KHMEXP HBITMAP KHMAPI +khui_get_cached_bitmap(UINT id); + +typedef struct khui_ilist_t { + int cx; + int cy; + int n; + int ng; + int nused; + HBITMAP img; + HBITMAP mask; + int *idlist; +} khui_ilist; + +typedef struct khui_bitmap_t { + HBITMAP hbmp; + int cx; + int cy; +} khui_bitmap; + +KHMEXP void KHMAPI +khui_bitmap_from_hbmp(khui_bitmap * kbm, HBITMAP hbm); + +KHMEXP void KHMAPI +khui_delete_bitmap(khui_bitmap * kbm); + +KHMEXP void KHMAPI +khui_draw_bitmap(HDC hdc, int x, int y, khui_bitmap * kbm); + +/* image lists */ +KHMEXP khui_ilist * KHMAPI +khui_create_ilist(int cx, int cy, int n, int ng, int opt); + +KHMEXP BOOL KHMAPI +khui_delete_ilist(khui_ilist * il); + +KHMEXP int KHMAPI +khui_ilist_add_masked(khui_ilist * il, HBITMAP hbm, COLORREF cbkg); + +KHMEXP int KHMAPI +khui_ilist_add_masked_id(khui_ilist *il, HBITMAP hbm, + COLORREF cbkg, int id); + +KHMEXP int KHMAPI +khui_ilist_lookup_id(khui_ilist *il, int id); + +KHMEXP void KHMAPI +khui_ilist_draw(khui_ilist * il, int idx, HDC dc, int x, int y, int opt); + +KHMEXP void KHMAPI +khui_ilist_draw_bg(khui_ilist * il, int idx, HDC dc, int x, int y, + int opt, COLORREF bgcolor); + +#define khui_ilist_draw_id(il, id, dc, x, y, opt) \ + khui_ilist_draw((il),khui_ilist_lookup_id((il),(id)),(dc),(x),(y),(opt)) + +#define KHUI_SMICON_CX 16 +#define KHUI_SMICON_CY 16 + +#endif diff --git a/src/windows/identity/uilib/khtracker.h b/src/windows/identity/uilib/khtracker.h index c12cd4fac..38be29a13 100644 --- a/src/windows/identity/uilib/khtracker.h +++ b/src/windows/identity/uilib/khtracker.h @@ -1,114 +1,114 @@ -/* - * 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_TRACKERWND_H -#define __KHIMAIRA_TRACKERWND_H - -#include - -/*! \addtogroup khui - -@{ */ - -/*!\defgroup khui_trk Duration sliders - -The duration sliders in the UI are pseudo-log-scaled. This is based -on the assumption that people don't really need 1 minute accuracy when -setting a duration that's several hours long. As a result, it is -easier to hone in on the duration that you want without having -wizardly mouse maneuvering skillz. - -Following are the duration ranges and the granularity that is offered -in each range: - - - - - - - - - - -
Range Increment
0..5m 1 min
5m..1hr 5 min
1hr..4hr 15 min
4hr..10hr 30 min
10hr..24hr 1 hr
24hr..4d 6 hr
4d.. 1 day
- -We don't really adjust for durations over 4 days. The ranges we are -concerned with don't get much larger. - -For the purpose of writing this piece of code, I have chosen the term -"tick" to refer to a period of granularity. The number of periods of -granularity (inclusive) within a certain duration interval is referred -to as the number of ticks in the interval. For example, there are 4 -ticks between the interval of 3 minutes to 10 minutes. Each occuring -at the start of 3min, 4, 5 and 10mins. And thusly the slider control -will display 4 ticks if it is displaying the interval 3-10mins. - -@{*/ - -/*! \brief Tracker data */ -typedef struct tag_khui_tracker { - WNDPROC fn_edit; - WNDPROC fn_tracker; - HWND hw_slider; - HWND hw_edit; - int lbl_y; - int lbl_lx; - int lbl_rx; - DWORD act_time; - - time_t current; /*!< Current selection */ - time_t min; /*!< Minimum (inclusive) */ - time_t max; /*!< Maximum (inclusive) */ -} khui_tracker; - -/*! \brief Install a tracker into an edit control - - Once installed, the edit control becomes a duration editor. The - tracker data structure that is supplied should remain as is for - the lifetime of the edit control. - - The tracker strucutre should have been initialized with a call to - khui_tracker_initialize() and should have valid values in the \a - min, \a max and \a current fields. - */ -KHMEXP void KHMAPI -khui_tracker_install(HWND hwnd_edit, khui_tracker * tc); - -KHMEXP void KHMAPI -khui_tracker_reposition(khui_tracker * tc); - -KHMEXP void KHMAPI -khui_tracker_initialize(khui_tracker * tc); - -KHMEXP void KHMAPI -khui_tracker_refresh(khui_tracker * tc); - -KHMEXP void KHMAPI -khui_tracker_kill_controls(khui_tracker * tc); -/*!@}*/ -/*!@}*/ - -#endif +/* + * 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_TRACKERWND_H +#define __KHIMAIRA_TRACKERWND_H + +#include + +/*! \addtogroup khui + +@{ */ + +/*!\defgroup khui_trk Duration sliders + +The duration sliders in the UI are pseudo-log-scaled. This is based +on the assumption that people don't really need 1 minute accuracy when +setting a duration that's several hours long. As a result, it is +easier to hone in on the duration that you want without having +wizardly mouse maneuvering skillz. + +Following are the duration ranges and the granularity that is offered +in each range: + + + + + + + + + + +
Range Increment
0..5m 1 min
5m..1hr 5 min
1hr..4hr 15 min
4hr..10hr 30 min
10hr..24hr 1 hr
24hr..4d 6 hr
4d.. 1 day
+ +We don't really adjust for durations over 4 days. The ranges we are +concerned with don't get much larger. + +For the purpose of writing this piece of code, I have chosen the term +"tick" to refer to a period of granularity. The number of periods of +granularity (inclusive) within a certain duration interval is referred +to as the number of ticks in the interval. For example, there are 4 +ticks between the interval of 3 minutes to 10 minutes. Each occuring +at the start of 3min, 4, 5 and 10mins. And thusly the slider control +will display 4 ticks if it is displaying the interval 3-10mins. + +@{*/ + +/*! \brief Tracker data */ +typedef struct tag_khui_tracker { + WNDPROC fn_edit; + WNDPROC fn_tracker; + HWND hw_slider; + HWND hw_edit; + int lbl_y; + int lbl_lx; + int lbl_rx; + DWORD act_time; + + time_t current; /*!< Current selection */ + time_t min; /*!< Minimum (inclusive) */ + time_t max; /*!< Maximum (inclusive) */ +} khui_tracker; + +/*! \brief Install a tracker into an edit control + + Once installed, the edit control becomes a duration editor. The + tracker data structure that is supplied should remain as is for + the lifetime of the edit control. + + The tracker strucutre should have been initialized with a call to + khui_tracker_initialize() and should have valid values in the \a + min, \a max and \a current fields. + */ +KHMEXP void KHMAPI +khui_tracker_install(HWND hwnd_edit, khui_tracker * tc); + +KHMEXP void KHMAPI +khui_tracker_reposition(khui_tracker * tc); + +KHMEXP void KHMAPI +khui_tracker_initialize(khui_tracker * tc); + +KHMEXP void KHMAPI +khui_tracker_refresh(khui_tracker * tc); + +KHMEXP void KHMAPI +khui_tracker_kill_controls(khui_tracker * tc); +/*!@}*/ +/*!@}*/ + +#endif diff --git a/src/windows/identity/uilib/khuidefs.h b/src/windows/identity/uilib/khuidefs.h index 9b3855614..16c4474f7 100644 --- a/src/windows/identity/uilib/khuidefs.h +++ b/src/windows/identity/uilib/khuidefs.h @@ -1,146 +1,146 @@ -/* - * Copyright (c) 2005 Massachusetts Institute of Technology - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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 - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef NOEXPORT -#include -#endif - -#include - -/*! \internal */ -KHMEXP void KHMAPI -khm_version_init(void); - -/*! \defgroup khui User Interface - - Functions and data structures for interacting with the user - interface. - -@{*/ - -/*! \brief Get the version of the NetIDMgr library - - \param[out] libver Receives the version of the library. - - \param[out] apiver Receives the API version of the library. - Optional. Set to NULL if this value is not required. - - \note When the NetIDMgr framework loads a plugin, it checks the - version information of the plugin against the version of the - library to determine if the plugin is compatible. - */ -KHMEXP void KHMAPI -khm_get_lib_version(khm_version * libver, khm_ui_4 * apiver); - -/*! \brief Return the version of Common Control library - - Can be used to check the version of the Windows Common Control - library that is currently loaded. The return value of the - function is the packed version value obatained by the macro : - - \code - MAKELONG(vesion->dwMinorVersion, version->dwMajorVersion); - \endcode - - The \a pdvi parameter is optional. Specify NULL if this is not - required. - */ -KHMEXP khm_ui_4 KHMAPI -khm_get_commctl_version(khm_version * pdvi); - -/*! \brief UI callback function - - Used with khui_request_UI_callback(). - - \see khui_request_UI_callback() - */ -typedef khm_int32 -(KHMAPI *khm_ui_callback)(HWND hwnd_main_wnd, void * rock); - -/*! \brief Request a UI callback - - In general, plug-ins in Network Identity Manager run in their own - thread and will not be able to interact with the user directly by - creating windows of its own. There are exceptions to this, such - as when the plug-in is responding to a new credentials request or - if the plug-in provides configuration panels. However, if a - plug-in needs to provide a user interface to the user outside of - the provisions already provided by Network Identity Manager, it - needs to do so from within the user interface thread. - - To do so, a plug-in would provide a callback function of the type - ::khm_ui_callback to this function. The Network Identity Manager - will then call the callback function from within the user - interface thread. At this point, the callback function can create - any windows it wishes to create and interact with the user - directly. - - The callback function would be called synchronously. - khui_request_UI_callback() will not return until the user - interface processes the request and calls the callback function. - The return code of khui_request_UI_callback() will be the return - code of the callback. - - \param[in] cb The callback function which will be called from the - user interface thread. - - \param[in] rock An arbitrary parameter which will be passed into - the callback function. - - \return The return value of \a cb. - - \note When the plug-in creates any windows, it should specify the - window handle provided via the \a hwnd_main_wnd parameter as - the parent window. - - \see ::khm_ui_callback - */ -KHMEXP khm_int32 KHMAPI -khui_request_UI_callback(khm_ui_callback cb, void * rock); - -/*!@}*/ - -#endif +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef NOEXPORT +#include +#endif + +#include + +/*! \internal */ +KHMEXP void KHMAPI +khm_version_init(void); + +/*! \defgroup khui User Interface + + Functions and data structures for interacting with the user + interface. + +@{*/ + +/*! \brief Get the version of the NetIDMgr library + + \param[out] libver Receives the version of the library. + + \param[out] apiver Receives the API version of the library. + Optional. Set to NULL if this value is not required. + + \note When the NetIDMgr framework loads a plugin, it checks the + version information of the plugin against the version of the + library to determine if the plugin is compatible. + */ +KHMEXP void KHMAPI +khm_get_lib_version(khm_version * libver, khm_ui_4 * apiver); + +/*! \brief Return the version of Common Control library + + Can be used to check the version of the Windows Common Control + library that is currently loaded. The return value of the + function is the packed version value obatained by the macro : + + \code + MAKELONG(vesion->dwMinorVersion, version->dwMajorVersion); + \endcode + + The \a pdvi parameter is optional. Specify NULL if this is not + required. + */ +KHMEXP khm_ui_4 KHMAPI +khm_get_commctl_version(khm_version * pdvi); + +/*! \brief UI callback function + + Used with khui_request_UI_callback(). + + \see khui_request_UI_callback() + */ +typedef khm_int32 +(KHMAPI *khm_ui_callback)(HWND hwnd_main_wnd, void * rock); + +/*! \brief Request a UI callback + + In general, plug-ins in Network Identity Manager run in their own + thread and will not be able to interact with the user directly by + creating windows of its own. There are exceptions to this, such + as when the plug-in is responding to a new credentials request or + if the plug-in provides configuration panels. However, if a + plug-in needs to provide a user interface to the user outside of + the provisions already provided by Network Identity Manager, it + needs to do so from within the user interface thread. + + To do so, a plug-in would provide a callback function of the type + ::khm_ui_callback to this function. The Network Identity Manager + will then call the callback function from within the user + interface thread. At this point, the callback function can create + any windows it wishes to create and interact with the user + directly. + + The callback function would be called synchronously. + khui_request_UI_callback() will not return until the user + interface processes the request and calls the callback function. + The return code of khui_request_UI_callback() will be the return + code of the callback. + + \param[in] cb The callback function which will be called from the + user interface thread. + + \param[in] rock An arbitrary parameter which will be passed into + the callback function. + + \return The return value of \a cb. + + \note When the plug-in creates any windows, it should specify the + window handle provided via the \a hwnd_main_wnd parameter as + the parent window. + + \see ::khm_ui_callback + */ +KHMEXP khm_int32 KHMAPI +khui_request_UI_callback(khm_ui_callback cb, void * rock); + +/*!@}*/ + +#endif diff --git a/src/windows/identity/uilib/propsheet.c b/src/windows/identity/uilib/propsheet.c index 705dd96a3..55c6cbb1b 100644 --- a/src/windows/identity/uilib/propsheet.c +++ b/src/windows/identity/uilib/propsheet.c @@ -1,230 +1,230 @@ -/* - * 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 -#ifdef DEBUG -#include -#endif - -CRITICAL_SECTION cs_props; - -void -ps_init(void) { - InitializeCriticalSection(&cs_props); -} - -void -ps_exit(void) { - DeleteCriticalSection(&cs_props); -} - -KHMEXP khm_int32 KHMAPI -khui_ps_create_sheet(khui_property_sheet ** sheet) -{ - khui_property_sheet * ps; - - ps = PMALLOC(sizeof(*ps)); - ZeroMemory(ps, sizeof(*ps)); - - ps->header.dwSize = sizeof(ps->header); - ps->header.dwFlags = PSH_MODELESS | PSH_PROPTITLE; - ps->status = KHUI_PS_STATUS_NONE; - - *sheet = ps; - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_ps_add_page(khui_property_sheet * sheet, - khm_int32 credtype, - khm_int32 ordinal, - LPPROPSHEETPAGE ppage, - khui_property_page ** page) -{ - khui_property_page * p; - - p = PMALLOC(sizeof(*p)); - ZeroMemory(p, sizeof(*p)); - - p->credtype = credtype; - p->ordinal = ordinal; - p->p_page = ppage; - - EnterCriticalSection(&cs_props); - QPUT(sheet, p); - sheet->n_pages++; - LeaveCriticalSection(&cs_props); - - if(page) - *page = p; - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -khui_ps_find_page(khui_property_sheet * sheet, - khm_int32 credtype, - khui_property_page ** page) -{ - khui_property_page * p; - - EnterCriticalSection(&cs_props); - p = QTOP(sheet); - - while(p) { - if(p->credtype == credtype) - break; - p = QNEXT(p); - } - LeaveCriticalSection(&cs_props); - - if(p) { - *page = p; - return KHM_ERROR_SUCCESS; - } else { - *page = NULL; - return KHM_ERROR_NOT_FOUND; - } -} - -int __cdecl -ps_order_func(const void *l, const void * r) { - khui_property_page * lp; - khui_property_page * rp; - - lp = *(khui_property_page **)l; - rp = *(khui_property_page **)r; - - if (lp->ordinal == rp->ordinal) - return lp->credtype - rp->credtype; - else - return lp->ordinal - rp->ordinal; -} - -KHMEXP HWND KHMAPI -khui_ps_show_sheet(HWND parent, khui_property_sheet * s) -{ - khui_property_page * p; - HPROPSHEETPAGE phpsp[KHUI_PS_MAX_PSP]; - khui_property_page * ppgs[KHUI_PS_MAX_PSP]; - int i; - INT_PTR prv; - HWND hw; - - EnterCriticalSection(&cs_props); - - s->header.hwndParent = parent; - s->header.nPages = s->n_pages; - - p = QTOP(s); - i = 0; - while(p) { - p->h_page = CreatePropertySheetPage(p->p_page); -#ifdef DEBUG - assert(p->h_page); -#endif - ppgs[i++] = p; - p = QNEXT(p); - } - -#ifdef DEBUG - assert(i == s->n_pages); -#endif - - qsort(ppgs, s->n_pages, sizeof(ppgs[0]), ps_order_func); - - for (i=0; i < s->n_pages; i++) { - phpsp[i] = ppgs[i]->h_page; - } - - s->header.phpage = phpsp; - - prv = PropertySheet(&s->header); - - s->header.phpage = NULL; - - if(prv <= 0) { -#ifdef DEBUG - assert(FALSE); -#endif - /*TODO: better handling for this */ - hw = NULL; - } else { - s->status = KHUI_PS_STATUS_RUNNING; - - hw = (HWND) prv; - s->hwnd = hw; - s->hwnd_page = PropSheet_GetCurrentPageHwnd(hw); - } - LeaveCriticalSection(&cs_props); - - return hw; -} - -KHMEXP LRESULT KHMAPI -khui_ps_check_message(khui_property_sheet * sheet, - PMSG pmsg) -{ - LRESULT lr; - - if(sheet->hwnd == NULL) - return FALSE; - - lr = PropSheet_IsDialogMessage(sheet->hwnd, pmsg); - if(lr) { - sheet->hwnd_page = PropSheet_GetCurrentPageHwnd(sheet->hwnd); - if(sheet->hwnd_page == NULL && - sheet->status == KHUI_PS_STATUS_RUNNING) - - sheet->status = KHUI_PS_STATUS_DONE; - } - - return lr; -} - -KHMEXP khm_int32 KHMAPI -khui_ps_destroy_sheet(khui_property_sheet * sheet) -{ - khui_property_page * p; - - EnterCriticalSection(&cs_props); - - DestroyWindow(sheet->hwnd); - sheet->hwnd = NULL; - - QGET(sheet, &p); - while(p) { - PFREE(p); - QGET(sheet, &p); - } - PFREE(sheet); - - LeaveCriticalSection(&cs_props); - - return KHM_ERROR_SUCCESS; -} +/* + * 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 +#ifdef DEBUG +#include +#endif + +CRITICAL_SECTION cs_props; + +void +ps_init(void) { + InitializeCriticalSection(&cs_props); +} + +void +ps_exit(void) { + DeleteCriticalSection(&cs_props); +} + +KHMEXP khm_int32 KHMAPI +khui_ps_create_sheet(khui_property_sheet ** sheet) +{ + khui_property_sheet * ps; + + ps = PMALLOC(sizeof(*ps)); + ZeroMemory(ps, sizeof(*ps)); + + ps->header.dwSize = sizeof(ps->header); + ps->header.dwFlags = PSH_MODELESS | PSH_PROPTITLE; + ps->status = KHUI_PS_STATUS_NONE; + + *sheet = ps; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_ps_add_page(khui_property_sheet * sheet, + khm_int32 credtype, + khm_int32 ordinal, + LPPROPSHEETPAGE ppage, + khui_property_page ** page) +{ + khui_property_page * p; + + p = PMALLOC(sizeof(*p)); + ZeroMemory(p, sizeof(*p)); + + p->credtype = credtype; + p->ordinal = ordinal; + p->p_page = ppage; + + EnterCriticalSection(&cs_props); + QPUT(sheet, p); + sheet->n_pages++; + LeaveCriticalSection(&cs_props); + + if(page) + *page = p; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_ps_find_page(khui_property_sheet * sheet, + khm_int32 credtype, + khui_property_page ** page) +{ + khui_property_page * p; + + EnterCriticalSection(&cs_props); + p = QTOP(sheet); + + while(p) { + if(p->credtype == credtype) + break; + p = QNEXT(p); + } + LeaveCriticalSection(&cs_props); + + if(p) { + *page = p; + return KHM_ERROR_SUCCESS; + } else { + *page = NULL; + return KHM_ERROR_NOT_FOUND; + } +} + +int __cdecl +ps_order_func(const void *l, const void * r) { + khui_property_page * lp; + khui_property_page * rp; + + lp = *(khui_property_page **)l; + rp = *(khui_property_page **)r; + + if (lp->ordinal == rp->ordinal) + return lp->credtype - rp->credtype; + else + return lp->ordinal - rp->ordinal; +} + +KHMEXP HWND KHMAPI +khui_ps_show_sheet(HWND parent, khui_property_sheet * s) +{ + khui_property_page * p; + HPROPSHEETPAGE phpsp[KHUI_PS_MAX_PSP]; + khui_property_page * ppgs[KHUI_PS_MAX_PSP]; + int i; + INT_PTR prv; + HWND hw; + + EnterCriticalSection(&cs_props); + + s->header.hwndParent = parent; + s->header.nPages = s->n_pages; + + p = QTOP(s); + i = 0; + while(p) { + p->h_page = CreatePropertySheetPage(p->p_page); +#ifdef DEBUG + assert(p->h_page); +#endif + ppgs[i++] = p; + p = QNEXT(p); + } + +#ifdef DEBUG + assert(i == s->n_pages); +#endif + + qsort(ppgs, s->n_pages, sizeof(ppgs[0]), ps_order_func); + + for (i=0; i < s->n_pages; i++) { + phpsp[i] = ppgs[i]->h_page; + } + + s->header.phpage = phpsp; + + prv = PropertySheet(&s->header); + + s->header.phpage = NULL; + + if(prv <= 0) { +#ifdef DEBUG + assert(FALSE); +#endif + /*TODO: better handling for this */ + hw = NULL; + } else { + s->status = KHUI_PS_STATUS_RUNNING; + + hw = (HWND) prv; + s->hwnd = hw; + s->hwnd_page = PropSheet_GetCurrentPageHwnd(hw); + } + LeaveCriticalSection(&cs_props); + + return hw; +} + +KHMEXP LRESULT KHMAPI +khui_ps_check_message(khui_property_sheet * sheet, + PMSG pmsg) +{ + LRESULT lr; + + if(sheet->hwnd == NULL) + return FALSE; + + lr = PropSheet_IsDialogMessage(sheet->hwnd, pmsg); + if(lr) { + sheet->hwnd_page = PropSheet_GetCurrentPageHwnd(sheet->hwnd); + if(sheet->hwnd_page == NULL && + sheet->status == KHUI_PS_STATUS_RUNNING) + + sheet->status = KHUI_PS_STATUS_DONE; + } + + return lr; +} + +KHMEXP khm_int32 KHMAPI +khui_ps_destroy_sheet(khui_property_sheet * sheet) +{ + khui_property_page * p; + + EnterCriticalSection(&cs_props); + + DestroyWindow(sheet->hwnd); + sheet->hwnd = NULL; + + QGET(sheet, &p); + while(p) { + PFREE(p); + QGET(sheet, &p); + } + PFREE(sheet); + + LeaveCriticalSection(&cs_props); + + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/uilib/propwnd.c b/src/windows/identity/uilib/propwnd.c index 5ae93a7a5..2116f5ed4 100644 --- a/src/windows/identity/uilib/propwnd.c +++ b/src/windows/identity/uilib/propwnd.c @@ -1,37 +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$ */ - -#include - - -#define PW_WM_SET_RECORD WM_USER - -KHMEXP khm_int32 KHMAPI khui_property_wnd_set_record(HWND hwnd_pwnd, khm_handle record) -{ - SendMessage(hwnd_pwnd, PW_WM_SET_RECORD, 0, (LPARAM) record); - - return KHM_ERROR_SUCCESS; -} +/* + * 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 + + +#define PW_WM_SET_RECORD WM_USER + +KHMEXP khm_int32 KHMAPI khui_property_wnd_set_record(HWND hwnd_pwnd, khm_handle record) +{ + SendMessage(hwnd_pwnd, PW_WM_SET_RECORD, 0, (LPARAM) record); + + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/uilib/rescache.c b/src/windows/identity/uilib/rescache.c index b84608a8e..3134df825 100644 --- a/src/windows/identity/uilib/rescache.c +++ b/src/windows/identity/uilib/rescache.c @@ -1,303 +1,303 @@ -/* - * 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$ */ - -#define NOEXPORT - -#include -#include - -hashtable * h_bitmaps; - -khm_int32 -hash_id(const void *p) { -#pragma warning(push) -#pragma warning(disable: 4311) - return (khm_int32) p; -#pragma warning(pop) -} - -khm_int32 -comp_id(const void *p1, const void *p2) { -#pragma warning(push) -#pragma warning(disable: 4311) - return ((khm_int32)p1) - ((khm_int32)p2); -#pragma warning(pop) -} - -void -del_ref_object(const void *k, void * data) { - DeleteObject((HGDIOBJ) data); -} - -KHMEXP void KHMAPI -khui_init_rescache(void) { - h_bitmaps = hash_new_hashtable(127, hash_id, comp_id, NULL, - del_ref_object); -} - -KHMEXP void KHMAPI -khui_exit_rescache(void) { - hash_del_hashtable(h_bitmaps); -} - -KHMEXP void KHMAPI -khui_cache_bitmap(UINT id, HBITMAP hbm) { - hash_add(h_bitmaps, (void *)(size_t) id, (void *) hbm); -} - -KHMEXP HBITMAP KHMAPI -khui_get_cached_bitmap(UINT id) { - return (HBITMAP) hash_lookup(h_bitmaps, (void *)(size_t) id); -} - -KHMEXP khui_ilist * KHMAPI -khui_create_ilist(int cx, int cy, int n, int ng, int opt) { - BITMAPV5HEADER head; - HDC hdc; - - khui_ilist * il = PMALLOC(sizeof(khui_ilist)); - il->cx = cx; - il->cy = cy; - il->n = n; - il->ng = ng; - il->nused = 0; - hdc = GetDC(NULL); - head.bV5Size = sizeof(head); - head.bV5Width = cx * n; - head.bV5Height = cy; - head.bV5Planes = 1; - head.bV5BitCount = 24; - head.bV5Compression = BI_RGB; - head.bV5SizeImage = 0; - head.bV5XPelsPerMeter = 2835; - head.bV5YPelsPerMeter = 2835; - head.bV5ClrUsed = 0; - head.bV5ClrImportant = 0; - head.bV5AlphaMask = 0; - head.bV5CSType = LCS_WINDOWS_COLOR_SPACE; - head.bV5Intent = LCS_GM_GRAPHICS; - head.bV5ProfileData = 0; - head.bV5ProfileSize = 0; - head.bV5Reserved = 0; - il->img = CreateDIBitmap(hdc, (BITMAPINFOHEADER *) &head, 0, NULL, NULL, DIB_RGB_COLORS); - il->mask = CreateBitmap(cx * n, cy, 1, 1, NULL); - il->idlist = PMALLOC(sizeof(int) * n); - - return il; -} - -KHMEXP BOOL KHMAPI -khui_delete_ilist(khui_ilist * il) { - DeleteObject(il->img); - DeleteObject(il->mask); - PFREE(il->idlist); - PFREE(il); - - return TRUE; -} - -KHMEXP int KHMAPI -khui_ilist_add_masked_id(khui_ilist *il, - HBITMAP hbm, - COLORREF cbkg, - int id) { - int idx; - - idx = khui_ilist_add_masked(il,hbm,cbkg); - if(idx >= 0) { - il->idlist[idx] = id; - } - - return idx; -} - -KHMEXP int KHMAPI -khui_ilist_lookup_id(khui_ilist *il, int id) { - int i; - - for(i=0;inused;i++) { - if(il->idlist[i] == id) - return i; - } - - return -1; -} - -KHMEXP int KHMAPI -khui_ilist_add_masked(khui_ilist * il, HBITMAP hbm, COLORREF cbkg) { - HDC dcr,dci,dct,dcb; - HBITMAP hb_oldb, hb_oldi, hb_oldt; - int sx, i; - int x,y; - - dcr = GetDC(NULL); - dci = CreateCompatibleDC(dcr); - dct = CreateCompatibleDC(dcr); - dcb = CreateCompatibleDC(dcr); - ReleaseDC(NULL,dcr); - - i = il->nused++; - il->idlist[i] = -1; - sx = i * il->cx; - - hb_oldb = SelectObject(dcb, hbm); - hb_oldi = SelectObject(dci, il->img); - hb_oldt = SelectObject(dct, il->mask); - - SetBkColor(dct, RGB(0,0,0)); - SetTextColor(dct, RGB(255,255,255)); - - BitBlt(dci, sx, 0, il->cx, il->cy, dcb, 0, 0, SRCCOPY); - for(y=0;y < il->cy; y++) - for(x=0; xcx; x++) { - COLORREF c = GetPixel(dcb, x, y); - if(c==cbkg) { - SetPixel(dct, sx + x, y, RGB(255,255,255)); - SetPixel(dci, sx + x, y, RGB(0,0,0)); - } else { - SetPixel(dct, sx + x, y, RGB(0,0,0)); - } - } - - SelectObject(dct, hb_oldt); - SelectObject(dci, hb_oldi); - SelectObject(dcb, hb_oldb); - - DeleteDC(dcb); - DeleteDC(dct); - DeleteDC(dci); - - return i; -} - -KHMEXP void KHMAPI -khui_ilist_draw(khui_ilist * il, - int idx, - HDC dc, - int x, - int y, - int opt) { - HDC dci; - HBITMAP hb_oldi; - - if(idx < 0) - return; - - dci = CreateCompatibleDC(dc); - - hb_oldi = SelectObject(dci, il->img); - - /*BitBlt(dc, x, y, il->cx, il->cy, dci, idx*il->cx, 0, SRCCOPY); */ - MaskBlt(dc, x, y, il->cx, il->cy, dci, idx * il->cx, 0, il->mask, idx * il->cx, 0, MAKEROP4(SRCPAINT, SRCCOPY)); -/* MaskBlt(dc, x, y, il->cx, il->cy, dci, idx * il->cx, 0, il->mask, idx * il->cx, 0, MAKEROP4(SRCINVERT, SRCCOPY)); */ - - SelectObject(dci, hb_oldi); - - DeleteDC(dci); -} - -KHMEXP void KHMAPI -khui_ilist_draw_bg(khui_ilist * il, - int idx, - HDC dc, - int x, - int y, - int opt, - COLORREF bgcolor) { - HDC dcm; - HBITMAP hb_oldm, hb_mem; - HBRUSH hbr; - RECT r; - - dcm = CreateCompatibleDC(dc); - - hb_mem = CreateCompatibleBitmap(dc, il->cx, il->cy); - - hb_oldm = SelectObject(dcm, hb_mem); - - hbr = CreateSolidBrush(bgcolor); - - r.left = 0; - r.top = 0; - r.right = il->cx; - r.bottom = il->cy; - - FillRect(dcm, &r, hbr); - - khui_ilist_draw(il,idx,dcm,0,0,opt); - - BitBlt(dc,x,y,il->cx,il->cy,dcm,0,0,SRCCOPY); - - SelectObject(dcm, hb_oldm); - - DeleteObject(hb_mem); - DeleteObject(hbr); - - DeleteDC(dcm); -} - - -KHMEXP void KHMAPI -khui_bitmap_from_hbmp(khui_bitmap * kbm, HBITMAP hbm) -{ - HDC hdc; - BITMAPINFO bmi; - - hdc = CreateCompatibleDC(NULL); - - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - - kbm->hbmp = hbm; - - if(GetDIBits(hdc, hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS)) { - kbm->cx = bmi.bmiHeader.biWidth; - kbm->cy = bmi.bmiHeader.biHeight; - } else { - kbm->cx = -1; - kbm->cy = -1; - } - - DeleteDC(hdc); -} - -KHMEXP void KHMAPI -khui_delete_bitmap(khui_bitmap * kbm) { - if (kbm->hbmp) - DeleteObject(kbm->hbmp); - kbm->hbmp = NULL; -} - -KHMEXP void KHMAPI -khui_draw_bitmap(HDC hdc, int x, int y, khui_bitmap * kbm) { - HDC hdcb = CreateCompatibleDC(hdc); - HBITMAP hbmold = SelectObject(hdcb, kbm->hbmp); - - BitBlt(hdc, x, y, kbm->cx, kbm->cy, - hdcb, 0, 0, SRCCOPY); - - SelectObject(hdcb, hbmold); - DeleteDC(hdcb); -} +/* + * 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$ */ + +#define NOEXPORT + +#include +#include + +hashtable * h_bitmaps; + +khm_int32 +hash_id(const void *p) { +#pragma warning(push) +#pragma warning(disable: 4311) + return (khm_int32) p; +#pragma warning(pop) +} + +khm_int32 +comp_id(const void *p1, const void *p2) { +#pragma warning(push) +#pragma warning(disable: 4311) + return ((khm_int32)p1) - ((khm_int32)p2); +#pragma warning(pop) +} + +void +del_ref_object(const void *k, void * data) { + DeleteObject((HGDIOBJ) data); +} + +KHMEXP void KHMAPI +khui_init_rescache(void) { + h_bitmaps = hash_new_hashtable(127, hash_id, comp_id, NULL, + del_ref_object); +} + +KHMEXP void KHMAPI +khui_exit_rescache(void) { + hash_del_hashtable(h_bitmaps); +} + +KHMEXP void KHMAPI +khui_cache_bitmap(UINT id, HBITMAP hbm) { + hash_add(h_bitmaps, (void *)(size_t) id, (void *) hbm); +} + +KHMEXP HBITMAP KHMAPI +khui_get_cached_bitmap(UINT id) { + return (HBITMAP) hash_lookup(h_bitmaps, (void *)(size_t) id); +} + +KHMEXP khui_ilist * KHMAPI +khui_create_ilist(int cx, int cy, int n, int ng, int opt) { + BITMAPV5HEADER head; + HDC hdc; + + khui_ilist * il = PMALLOC(sizeof(khui_ilist)); + il->cx = cx; + il->cy = cy; + il->n = n; + il->ng = ng; + il->nused = 0; + hdc = GetDC(NULL); + head.bV5Size = sizeof(head); + head.bV5Width = cx * n; + head.bV5Height = cy; + head.bV5Planes = 1; + head.bV5BitCount = 24; + head.bV5Compression = BI_RGB; + head.bV5SizeImage = 0; + head.bV5XPelsPerMeter = 2835; + head.bV5YPelsPerMeter = 2835; + head.bV5ClrUsed = 0; + head.bV5ClrImportant = 0; + head.bV5AlphaMask = 0; + head.bV5CSType = LCS_WINDOWS_COLOR_SPACE; + head.bV5Intent = LCS_GM_GRAPHICS; + head.bV5ProfileData = 0; + head.bV5ProfileSize = 0; + head.bV5Reserved = 0; + il->img = CreateDIBitmap(hdc, (BITMAPINFOHEADER *) &head, 0, NULL, NULL, DIB_RGB_COLORS); + il->mask = CreateBitmap(cx * n, cy, 1, 1, NULL); + il->idlist = PMALLOC(sizeof(int) * n); + + return il; +} + +KHMEXP BOOL KHMAPI +khui_delete_ilist(khui_ilist * il) { + DeleteObject(il->img); + DeleteObject(il->mask); + PFREE(il->idlist); + PFREE(il); + + return TRUE; +} + +KHMEXP int KHMAPI +khui_ilist_add_masked_id(khui_ilist *il, + HBITMAP hbm, + COLORREF cbkg, + int id) { + int idx; + + idx = khui_ilist_add_masked(il,hbm,cbkg); + if(idx >= 0) { + il->idlist[idx] = id; + } + + return idx; +} + +KHMEXP int KHMAPI +khui_ilist_lookup_id(khui_ilist *il, int id) { + int i; + + for(i=0;inused;i++) { + if(il->idlist[i] == id) + return i; + } + + return -1; +} + +KHMEXP int KHMAPI +khui_ilist_add_masked(khui_ilist * il, HBITMAP hbm, COLORREF cbkg) { + HDC dcr,dci,dct,dcb; + HBITMAP hb_oldb, hb_oldi, hb_oldt; + int sx, i; + int x,y; + + dcr = GetDC(NULL); + dci = CreateCompatibleDC(dcr); + dct = CreateCompatibleDC(dcr); + dcb = CreateCompatibleDC(dcr); + ReleaseDC(NULL,dcr); + + i = il->nused++; + il->idlist[i] = -1; + sx = i * il->cx; + + hb_oldb = SelectObject(dcb, hbm); + hb_oldi = SelectObject(dci, il->img); + hb_oldt = SelectObject(dct, il->mask); + + SetBkColor(dct, RGB(0,0,0)); + SetTextColor(dct, RGB(255,255,255)); + + BitBlt(dci, sx, 0, il->cx, il->cy, dcb, 0, 0, SRCCOPY); + for(y=0;y < il->cy; y++) + for(x=0; xcx; x++) { + COLORREF c = GetPixel(dcb, x, y); + if(c==cbkg) { + SetPixel(dct, sx + x, y, RGB(255,255,255)); + SetPixel(dci, sx + x, y, RGB(0,0,0)); + } else { + SetPixel(dct, sx + x, y, RGB(0,0,0)); + } + } + + SelectObject(dct, hb_oldt); + SelectObject(dci, hb_oldi); + SelectObject(dcb, hb_oldb); + + DeleteDC(dcb); + DeleteDC(dct); + DeleteDC(dci); + + return i; +} + +KHMEXP void KHMAPI +khui_ilist_draw(khui_ilist * il, + int idx, + HDC dc, + int x, + int y, + int opt) { + HDC dci; + HBITMAP hb_oldi; + + if(idx < 0) + return; + + dci = CreateCompatibleDC(dc); + + hb_oldi = SelectObject(dci, il->img); + + /*BitBlt(dc, x, y, il->cx, il->cy, dci, idx*il->cx, 0, SRCCOPY); */ + MaskBlt(dc, x, y, il->cx, il->cy, dci, idx * il->cx, 0, il->mask, idx * il->cx, 0, MAKEROP4(SRCPAINT, SRCCOPY)); +/* MaskBlt(dc, x, y, il->cx, il->cy, dci, idx * il->cx, 0, il->mask, idx * il->cx, 0, MAKEROP4(SRCINVERT, SRCCOPY)); */ + + SelectObject(dci, hb_oldi); + + DeleteDC(dci); +} + +KHMEXP void KHMAPI +khui_ilist_draw_bg(khui_ilist * il, + int idx, + HDC dc, + int x, + int y, + int opt, + COLORREF bgcolor) { + HDC dcm; + HBITMAP hb_oldm, hb_mem; + HBRUSH hbr; + RECT r; + + dcm = CreateCompatibleDC(dc); + + hb_mem = CreateCompatibleBitmap(dc, il->cx, il->cy); + + hb_oldm = SelectObject(dcm, hb_mem); + + hbr = CreateSolidBrush(bgcolor); + + r.left = 0; + r.top = 0; + r.right = il->cx; + r.bottom = il->cy; + + FillRect(dcm, &r, hbr); + + khui_ilist_draw(il,idx,dcm,0,0,opt); + + BitBlt(dc,x,y,il->cx,il->cy,dcm,0,0,SRCCOPY); + + SelectObject(dcm, hb_oldm); + + DeleteObject(hb_mem); + DeleteObject(hbr); + + DeleteDC(dcm); +} + + +KHMEXP void KHMAPI +khui_bitmap_from_hbmp(khui_bitmap * kbm, HBITMAP hbm) +{ + HDC hdc; + BITMAPINFO bmi; + + hdc = CreateCompatibleDC(NULL); + + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + + kbm->hbmp = hbm; + + if(GetDIBits(hdc, hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS)) { + kbm->cx = bmi.bmiHeader.biWidth; + kbm->cy = bmi.bmiHeader.biHeight; + } else { + kbm->cx = -1; + kbm->cy = -1; + } + + DeleteDC(hdc); +} + +KHMEXP void KHMAPI +khui_delete_bitmap(khui_bitmap * kbm) { + if (kbm->hbmp) + DeleteObject(kbm->hbmp); + kbm->hbmp = NULL; +} + +KHMEXP void KHMAPI +khui_draw_bitmap(HDC hdc, int x, int y, khui_bitmap * kbm) { + HDC hdcb = CreateCompatibleDC(hdc); + HBITMAP hbmold = SelectObject(hdcb, kbm->hbmp); + + BitBlt(hdc, x, y, kbm->cx, kbm->cy, + hdcb, 0, 0, SRCCOPY); + + SelectObject(hdcb, hbmold); + DeleteDC(hdcb); +} diff --git a/src/windows/identity/uilib/trackerwnd.c b/src/windows/identity/uilib/trackerwnd.c index b0da7d15d..1ec2fda28 100644 --- a/src/windows/identity/uilib/trackerwnd.c +++ b/src/windows/identity/uilib/trackerwnd.c @@ -1,474 +1,474 @@ -/* - * 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 - -#define K5_SLIDER_WIDTH 208 -#define K5_SLIDER_HEIGHT 40 - -#define K5_SLIDER_LBL_HPAD 5 -#define K5_SLIDER_LBL_VPAD 22 - -#define KHUI_TRACKER_PROP L"KhmTrackerData" - - -/* Count the number of ticks between tmin and tmax, inclusive -*/ -int time_t_to_ticks(time_t tmin, time_t tmax) -{ - int c = 0; - time_t lo, hi; - - tmin -= tmin % 60; /* our smallest gran is 1 min */ - if(tmax % 60) - tmax += 60 - (tmax % 60); - - lo = tmin; - -#define TFORWARD(limit,gran) \ - if(lo < limit && lo < tmax) { \ - hi = min(tmax, limit); \ - c += (int)((hi - lo) / (gran)); \ - lo = hi; \ - } - - TFORWARD(300,60); - TFORWARD(3600,300); - TFORWARD(3600*4, 60*15); - TFORWARD(3600*10,60*30); - TFORWARD(3600*24,3600); - TFORWARD(3600*24*4,3600*6); - TFORWARD(((time_t)(INFINITE & INT_MAX)),3600*24); - -#undef TFORWARD - - return c; -} - -/* Compute tmax given tmin and ticks such that there are ticks ticks - between tmin and tmax - */ -time_t ticks_to_time_t(int ticks, time_t tmin) -{ - int c = 0; - tmin -= tmin % 60; /* our smallest gran is 1 min */ - -#define SFORWARD(limit,gran) \ - if(tmin < limit && ticks > 0) { \ - c = (int) min(ticks, (limit - tmin) / (gran)); \ - tmin += c * gran; \ - ticks -= c; \ - } - - SFORWARD(300,60); - SFORWARD(3600,300); - SFORWARD(3600*4,60*15); - SFORWARD(3600*10,60*30); - SFORWARD(3600*24,3600); - SFORWARD(3600*24*4,3600*6); - SFORWARD(((time_t)(INFINITE & INT_MAX)),3600*24); - -#undef SFORWARD - - return tmin; -} - -/* Prep a tracker control which works in conjunction with the - duration edit control. - - NOTE: Runs in the context of the UI thread -*/ -void -initialize_tracker(HWND hwnd, - khui_tracker * tc) -{ - RECT r; - FILETIME ft; - wchar_t wbuf[256]; - khm_size cbbuf; - - SendMessage(tc->hw_slider, TBM_SETRANGE, 0, MAKELONG(0, time_t_to_ticks(tc->min, tc->max))); - SendMessage(tc->hw_slider, TBM_SETPOS, TRUE, (LPARAM) time_t_to_ticks(tc->min, tc->current)); - - r.left = K5_SLIDER_LBL_HPAD; - r.top = K5_SLIDER_LBL_VPAD; - r.right = K5_SLIDER_WIDTH - K5_SLIDER_LBL_HPAD; - r.bottom = r.top; - - MapDialogRect(hwnd, &r); - - tc->lbl_y = r.top; - tc->lbl_lx = r.left; - tc->lbl_rx = r.right; - - TimetToFileTimeInterval(tc->current, &ft); - cbbuf = sizeof(wbuf); - FtIntervalToString(&ft, wbuf, &cbbuf); - - SendMessage(tc->hw_edit, WM_SETTEXT, 0, (LPARAM)wbuf); -} - - -/* We instance-subclass each tracker control to provide the - functionality that we need. This is the replacement window - procedure - - NOTE: Runs in the context of the UI thread - */ -LRESULT CALLBACK -duration_tracker_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - khui_tracker * tc; - - tc = (khui_tracker *) GetProp(hwnd, KHUI_TRACKER_PROP); -#ifdef DEBUG - assert(tc != NULL); -#endif - - switch(uMsg) { - case WM_PAINT: - { - HDC hdc; - HFONT hf, hfold; - LRESULT lr; - FILETIME ft; - wchar_t buf[256]; - khm_size cbbuf; - - lr = CallWindowProc(tc->fn_tracker, hwnd, uMsg, wParam, lParam); - - /* Can't use BeginPaint here, since we already called the - window proc */ - hdc = GetWindowDC(hwnd); - - hf = (HFONT) SendMessage(tc->hw_edit, WM_GETFONT, 0, 0); - - hfold = ((HFONT) SelectObject((hdc), (HGDIOBJ)(HFONT)(hf))); - - TimetToFileTimeInterval(tc->min, &ft); - cbbuf = sizeof(buf); - FtIntervalToString(&ft, buf, &cbbuf); - - SetTextColor(hdc, RGB(0,0,0)); - SetBkMode(hdc, TRANSPARENT); - - SetTextAlign(hdc, TA_LEFT | TA_TOP | TA_NOUPDATECP); - TextOut(hdc, tc->lbl_lx, tc->lbl_y, buf, (int) wcslen(buf)); - - TimetToFileTimeInterval(tc->max, &ft); - cbbuf = sizeof(buf); - FtIntervalToString(&ft, buf, &cbbuf); - - SetTextAlign(hdc, TA_RIGHT | TA_TOP | TA_NOUPDATECP); - TextOut(hdc, tc->lbl_rx, tc->lbl_y, buf, (int) wcslen(buf)); - - ((HFONT) SelectObject((hdc), (HGDIOBJ)(HFONT)(hfold))); - - ReleaseDC(hwnd, hdc); - - return lr; - } - break; - - case WM_KILLFOCUS: - { - if((HWND)wParam != tc->hw_edit) - ShowWindow(hwnd, SW_HIDE); - } - break; - - case WM_LBUTTONUP: - case WM_MOUSEMOVE: - { - LRESULT lr; - - lr = CallWindowProc(tc->fn_tracker, hwnd, uMsg, wParam, lParam); - - if(wParam & MK_LBUTTON) { - int c = (int) SendMessage(hwnd, TBM_GETPOS, 0, 0); - time_t t = ticks_to_time_t(c, tc->min); - - if(t != tc->current) { - wchar_t buf[256]; - FILETIME ft; - khm_size cbbuf; - - tc->current = t; - //d->dirty = TRUE; - cbbuf = sizeof(buf); - TimetToFileTimeInterval(t, &ft); - FtIntervalToString(&ft, buf, &cbbuf); - SendMessage(tc->hw_edit, WM_SETTEXT, 0, (LPARAM) buf); - } - } - return lr; - } - } - - return CallWindowProc(tc->fn_tracker, hwnd, uMsg, wParam, lParam); -} - - -/* Create the subclassed duration slider on behalf of an edit control */ -void -create_edit_sliders(HWND hwnd, - HWND hwnd_dlg, - khui_tracker * tc) -{ - RECT r; - RECT rs; - - GetWindowRect(hwnd, &r); - - rs.top = 0; - rs.left = 0; - rs.right = K5_SLIDER_WIDTH; - rs.bottom = K5_SLIDER_HEIGHT; - MapDialogRect(hwnd_dlg, &rs); - rs.right -= rs.left; - rs.bottom -= rs.top; - - tc->hw_slider = - CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, - TRACKBAR_CLASS, - L"NetIDMgrTimeTickerTrackbar", - WS_POPUP | TBS_AUTOTICKS | TBS_BOTTOM | -#if (_WIN32_IE >= 0x0501) - TBS_DOWNISLEFT | -#endif - TBS_HORZ | WS_CLIPCHILDREN, - r.left,r.bottom,rs.right,rs.bottom, - hwnd, - NULL, - (HINSTANCE)(DWORD_PTR) - GetWindowLongPtr(hwnd, GWLP_HINSTANCE), - NULL); - - SetProp(tc->hw_slider, KHUI_TRACKER_PROP, - (HANDLE) tc); - -#pragma warning(push) -#pragma warning(disable: 4244) - tc->fn_tracker = (WNDPROC)(LONG_PTR) SetWindowLongPtr(tc->hw_slider, GWLP_WNDPROC, (LONG_PTR) duration_tracker_proc); -#pragma warning(pop) -} - -/* An edit control is instance-subclassed to create an edit control - that holds a duration. Welcome to the window procedure. - - NOTE: Runs in the context of the UI thread - */ -LRESULT CALLBACK -duration_edit_proc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - khui_tracker * tc; - - tc = (khui_tracker *) GetProp(hwnd, KHUI_TRACKER_PROP); - -#ifdef DEBUG - assert(tc != NULL); -#endif - - switch(uMsg) { - case WM_SETFOCUS: - { - HWND p; - - p = GetParent(hwnd); - - /* 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(); - } - break; - - case WM_KILLFOCUS: - { - wchar_t wbuf[256]; - FILETIME ft; - khm_size cbbuf; - - if((HWND) wParam != tc->hw_slider) - ShowWindow(tc->hw_slider, SW_HIDE); - - TimetToFileTimeInterval(tc->current, &ft); - cbbuf = sizeof(wbuf); - FtIntervalToString(&ft, wbuf, &cbbuf); - - SendMessage(tc->hw_edit, WM_SETTEXT, 0, (LPARAM)wbuf); - } - break; - - case KHUI_WM_NC_NOTIFY: - if(HIWORD(wParam) == WMNC_DIALOG_SETUP) { - HWND p; - - p = GetParent(hwnd); - - if(tc->hw_slider == NULL) { - create_edit_sliders(hwnd,p,tc); - } - - initialize_tracker(p, tc); - } - return TRUE; - - case WM_LBUTTONUP: - if (IsWindowVisible(tc->hw_slider)) { - DWORD tm; - - tm = GetTickCount(); - if (tm - tc->act_time > 000) - ShowWindow(tc->hw_slider, SW_HIDE); - } else { - ShowWindow(tc->hw_slider, SW_SHOWNOACTIVATE); - } - break; - - /* these messages can potentially change the text in the edit - control. We intercept them and see what changed. We may - need to grab and handle them */ - case EM_REPLACESEL: - case EM_UNDO: - case WM_UNDO: - case WM_CHAR: -#if (_WIN32_WINNT >= 0x0501) - case WM_UNICHAR: -#endif - { - wchar_t buf[256]; - size_t nchars; - time_t ts; - FILETIME ft; - BOOL modified; - LRESULT lr = CallWindowProc(tc->fn_edit, hwnd, uMsg, wParam, lParam); - - modified = (BOOL) SendMessage(hwnd, EM_GETMODIFY, 0, 0); - if(modified) { - /* parse the string */ - if(nchars = (size_t) SendMessage(hwnd, WM_GETTEXT, ARRAYLENGTH(buf), (LPARAM) buf)) { - buf[nchars] = 0; - - if(KHM_SUCCEEDED(IntervalStringToFt(&ft, buf))) { - ts = FtIntervalToSeconds(&ft); - if(ts >= tc->min && ts <= tc->max) { - tc->current = ts; - //d->dirty = TRUE; - if(tc->hw_slider != NULL) - SendMessage(tc->hw_slider, TBM_SETPOS, TRUE, (LPARAM) time_t_to_ticks(tc->min, tc->current)); - } - } - } - SendMessage(hwnd, EM_SETMODIFY, FALSE, 0); - } - - return lr; - } - } - - return CallWindowProc(tc->fn_edit, hwnd, uMsg, wParam, lParam); -} - -KHMEXP void KHMAPI -khui_tracker_install(HWND hwnd_edit, khui_tracker * tc) { -#ifdef DEBUG - assert(hwnd_edit); - assert(tc); -#endif - - tc->hw_edit = hwnd_edit; - - SetProp(hwnd_edit, KHUI_TRACKER_PROP, (HANDLE) tc); - -#pragma warning(push) -#pragma warning(disable: 4244) - tc->fn_edit = (WNDPROC)(LONG_PTR) - SetWindowLongPtr(hwnd_edit, GWLP_WNDPROC, - (LONG_PTR) duration_edit_proc); -#pragma warning(pop) -} - -KHMEXP void KHMAPI -khui_tracker_reposition(khui_tracker * tc) { - RECT r; - - if(tc->hw_slider && tc->hw_edit) { - GetWindowRect(tc->hw_edit, &r); - SetWindowPos(tc->hw_slider, - NULL, - r.left, r.bottom, - 0, 0, - SWP_NOOWNERZORDER | SWP_NOSIZE | - SWP_NOZORDER | SWP_NOACTIVATE); - } -} - -KHMEXP void KHMAPI -khui_tracker_initialize(khui_tracker * tc) { - ZeroMemory(tc, sizeof(*tc)); -} - -KHMEXP void KHMAPI -khui_tracker_refresh(khui_tracker * tc) { - if (!tc->hw_edit) - return; - - SendMessage(tc->hw_edit, - KHUI_WM_NC_NOTIFY, - MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0); -} - -KHMEXP void KHMAPI -khui_tracker_kill_controls(khui_tracker * tc) { - if (tc->hw_slider) - DestroyWindow(tc->hw_slider); - if (tc->hw_edit) - DestroyWindow(tc->hw_edit); - tc->hw_slider = NULL; - tc->hw_edit = NULL; - tc->fn_edit = NULL; - tc->fn_tracker = NULL; -} - - +/* + * 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 + +#define K5_SLIDER_WIDTH 208 +#define K5_SLIDER_HEIGHT 40 + +#define K5_SLIDER_LBL_HPAD 5 +#define K5_SLIDER_LBL_VPAD 22 + +#define KHUI_TRACKER_PROP L"KhmTrackerData" + + +/* Count the number of ticks between tmin and tmax, inclusive +*/ +int time_t_to_ticks(time_t tmin, time_t tmax) +{ + int c = 0; + time_t lo, hi; + + tmin -= tmin % 60; /* our smallest gran is 1 min */ + if(tmax % 60) + tmax += 60 - (tmax % 60); + + lo = tmin; + +#define TFORWARD(limit,gran) \ + if(lo < limit && lo < tmax) { \ + hi = min(tmax, limit); \ + c += (int)((hi - lo) / (gran)); \ + lo = hi; \ + } + + TFORWARD(300,60); + TFORWARD(3600,300); + TFORWARD(3600*4, 60*15); + TFORWARD(3600*10,60*30); + TFORWARD(3600*24,3600); + TFORWARD(3600*24*4,3600*6); + TFORWARD(((time_t)(INFINITE & INT_MAX)),3600*24); + +#undef TFORWARD + + return c; +} + +/* Compute tmax given tmin and ticks such that there are ticks ticks + between tmin and tmax + */ +time_t ticks_to_time_t(int ticks, time_t tmin) +{ + int c = 0; + tmin -= tmin % 60; /* our smallest gran is 1 min */ + +#define SFORWARD(limit,gran) \ + if(tmin < limit && ticks > 0) { \ + c = (int) min(ticks, (limit - tmin) / (gran)); \ + tmin += c * gran; \ + ticks -= c; \ + } + + SFORWARD(300,60); + SFORWARD(3600,300); + SFORWARD(3600*4,60*15); + SFORWARD(3600*10,60*30); + SFORWARD(3600*24,3600); + SFORWARD(3600*24*4,3600*6); + SFORWARD(((time_t)(INFINITE & INT_MAX)),3600*24); + +#undef SFORWARD + + return tmin; +} + +/* Prep a tracker control which works in conjunction with the + duration edit control. + + NOTE: Runs in the context of the UI thread +*/ +void +initialize_tracker(HWND hwnd, + khui_tracker * tc) +{ + RECT r; + FILETIME ft; + wchar_t wbuf[256]; + khm_size cbbuf; + + SendMessage(tc->hw_slider, TBM_SETRANGE, 0, MAKELONG(0, time_t_to_ticks(tc->min, tc->max))); + SendMessage(tc->hw_slider, TBM_SETPOS, TRUE, (LPARAM) time_t_to_ticks(tc->min, tc->current)); + + r.left = K5_SLIDER_LBL_HPAD; + r.top = K5_SLIDER_LBL_VPAD; + r.right = K5_SLIDER_WIDTH - K5_SLIDER_LBL_HPAD; + r.bottom = r.top; + + MapDialogRect(hwnd, &r); + + tc->lbl_y = r.top; + tc->lbl_lx = r.left; + tc->lbl_rx = r.right; + + TimetToFileTimeInterval(tc->current, &ft); + cbbuf = sizeof(wbuf); + FtIntervalToString(&ft, wbuf, &cbbuf); + + SendMessage(tc->hw_edit, WM_SETTEXT, 0, (LPARAM)wbuf); +} + + +/* We instance-subclass each tracker control to provide the + functionality that we need. This is the replacement window + procedure + + NOTE: Runs in the context of the UI thread + */ +LRESULT CALLBACK +duration_tracker_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + khui_tracker * tc; + + tc = (khui_tracker *) GetProp(hwnd, KHUI_TRACKER_PROP); +#ifdef DEBUG + assert(tc != NULL); +#endif + + switch(uMsg) { + case WM_PAINT: + { + HDC hdc; + HFONT hf, hfold; + LRESULT lr; + FILETIME ft; + wchar_t buf[256]; + khm_size cbbuf; + + lr = CallWindowProc(tc->fn_tracker, hwnd, uMsg, wParam, lParam); + + /* Can't use BeginPaint here, since we already called the + window proc */ + hdc = GetWindowDC(hwnd); + + hf = (HFONT) SendMessage(tc->hw_edit, WM_GETFONT, 0, 0); + + hfold = ((HFONT) SelectObject((hdc), (HGDIOBJ)(HFONT)(hf))); + + TimetToFileTimeInterval(tc->min, &ft); + cbbuf = sizeof(buf); + FtIntervalToString(&ft, buf, &cbbuf); + + SetTextColor(hdc, RGB(0,0,0)); + SetBkMode(hdc, TRANSPARENT); + + SetTextAlign(hdc, TA_LEFT | TA_TOP | TA_NOUPDATECP); + TextOut(hdc, tc->lbl_lx, tc->lbl_y, buf, (int) wcslen(buf)); + + TimetToFileTimeInterval(tc->max, &ft); + cbbuf = sizeof(buf); + FtIntervalToString(&ft, buf, &cbbuf); + + SetTextAlign(hdc, TA_RIGHT | TA_TOP | TA_NOUPDATECP); + TextOut(hdc, tc->lbl_rx, tc->lbl_y, buf, (int) wcslen(buf)); + + ((HFONT) SelectObject((hdc), (HGDIOBJ)(HFONT)(hfold))); + + ReleaseDC(hwnd, hdc); + + return lr; + } + break; + + case WM_KILLFOCUS: + { + if((HWND)wParam != tc->hw_edit) + ShowWindow(hwnd, SW_HIDE); + } + break; + + case WM_LBUTTONUP: + case WM_MOUSEMOVE: + { + LRESULT lr; + + lr = CallWindowProc(tc->fn_tracker, hwnd, uMsg, wParam, lParam); + + if(wParam & MK_LBUTTON) { + int c = (int) SendMessage(hwnd, TBM_GETPOS, 0, 0); + time_t t = ticks_to_time_t(c, tc->min); + + if(t != tc->current) { + wchar_t buf[256]; + FILETIME ft; + khm_size cbbuf; + + tc->current = t; + //d->dirty = TRUE; + cbbuf = sizeof(buf); + TimetToFileTimeInterval(t, &ft); + FtIntervalToString(&ft, buf, &cbbuf); + SendMessage(tc->hw_edit, WM_SETTEXT, 0, (LPARAM) buf); + } + } + return lr; + } + } + + return CallWindowProc(tc->fn_tracker, hwnd, uMsg, wParam, lParam); +} + + +/* Create the subclassed duration slider on behalf of an edit control */ +void +create_edit_sliders(HWND hwnd, + HWND hwnd_dlg, + khui_tracker * tc) +{ + RECT r; + RECT rs; + + GetWindowRect(hwnd, &r); + + rs.top = 0; + rs.left = 0; + rs.right = K5_SLIDER_WIDTH; + rs.bottom = K5_SLIDER_HEIGHT; + MapDialogRect(hwnd_dlg, &rs); + rs.right -= rs.left; + rs.bottom -= rs.top; + + tc->hw_slider = + CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, + TRACKBAR_CLASS, + L"NetIDMgrTimeTickerTrackbar", + WS_POPUP | TBS_AUTOTICKS | TBS_BOTTOM | +#if (_WIN32_IE >= 0x0501) + TBS_DOWNISLEFT | +#endif + TBS_HORZ | WS_CLIPCHILDREN, + r.left,r.bottom,rs.right,rs.bottom, + hwnd, + NULL, + (HINSTANCE)(DWORD_PTR) + GetWindowLongPtr(hwnd, GWLP_HINSTANCE), + NULL); + + SetProp(tc->hw_slider, KHUI_TRACKER_PROP, + (HANDLE) tc); + +#pragma warning(push) +#pragma warning(disable: 4244) + tc->fn_tracker = (WNDPROC)(LONG_PTR) SetWindowLongPtr(tc->hw_slider, GWLP_WNDPROC, (LONG_PTR) duration_tracker_proc); +#pragma warning(pop) +} + +/* An edit control is instance-subclassed to create an edit control + that holds a duration. Welcome to the window procedure. + + NOTE: Runs in the context of the UI thread + */ +LRESULT CALLBACK +duration_edit_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + khui_tracker * tc; + + tc = (khui_tracker *) GetProp(hwnd, KHUI_TRACKER_PROP); + +#ifdef DEBUG + assert(tc != NULL); +#endif + + switch(uMsg) { + case WM_SETFOCUS: + { + HWND p; + + p = GetParent(hwnd); + + /* 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(); + } + break; + + case WM_KILLFOCUS: + { + wchar_t wbuf[256]; + FILETIME ft; + khm_size cbbuf; + + if((HWND) wParam != tc->hw_slider) + ShowWindow(tc->hw_slider, SW_HIDE); + + TimetToFileTimeInterval(tc->current, &ft); + cbbuf = sizeof(wbuf); + FtIntervalToString(&ft, wbuf, &cbbuf); + + SendMessage(tc->hw_edit, WM_SETTEXT, 0, (LPARAM)wbuf); + } + break; + + case KHUI_WM_NC_NOTIFY: + if(HIWORD(wParam) == WMNC_DIALOG_SETUP) { + HWND p; + + p = GetParent(hwnd); + + if(tc->hw_slider == NULL) { + create_edit_sliders(hwnd,p,tc); + } + + initialize_tracker(p, tc); + } + return TRUE; + + case WM_LBUTTONUP: + if (IsWindowVisible(tc->hw_slider)) { + DWORD tm; + + tm = GetTickCount(); + if (tm - tc->act_time > 000) + ShowWindow(tc->hw_slider, SW_HIDE); + } else { + ShowWindow(tc->hw_slider, SW_SHOWNOACTIVATE); + } + break; + + /* these messages can potentially change the text in the edit + control. We intercept them and see what changed. We may + need to grab and handle them */ + case EM_REPLACESEL: + case EM_UNDO: + case WM_UNDO: + case WM_CHAR: +#if (_WIN32_WINNT >= 0x0501) + case WM_UNICHAR: +#endif + { + wchar_t buf[256]; + size_t nchars; + time_t ts; + FILETIME ft; + BOOL modified; + LRESULT lr = CallWindowProc(tc->fn_edit, hwnd, uMsg, wParam, lParam); + + modified = (BOOL) SendMessage(hwnd, EM_GETMODIFY, 0, 0); + if(modified) { + /* parse the string */ + if(nchars = (size_t) SendMessage(hwnd, WM_GETTEXT, ARRAYLENGTH(buf), (LPARAM) buf)) { + buf[nchars] = 0; + + if(KHM_SUCCEEDED(IntervalStringToFt(&ft, buf))) { + ts = FtIntervalToSeconds(&ft); + if(ts >= tc->min && ts <= tc->max) { + tc->current = ts; + //d->dirty = TRUE; + if(tc->hw_slider != NULL) + SendMessage(tc->hw_slider, TBM_SETPOS, TRUE, (LPARAM) time_t_to_ticks(tc->min, tc->current)); + } + } + } + SendMessage(hwnd, EM_SETMODIFY, FALSE, 0); + } + + return lr; + } + } + + return CallWindowProc(tc->fn_edit, hwnd, uMsg, wParam, lParam); +} + +KHMEXP void KHMAPI +khui_tracker_install(HWND hwnd_edit, khui_tracker * tc) { +#ifdef DEBUG + assert(hwnd_edit); + assert(tc); +#endif + + tc->hw_edit = hwnd_edit; + + SetProp(hwnd_edit, KHUI_TRACKER_PROP, (HANDLE) tc); + +#pragma warning(push) +#pragma warning(disable: 4244) + tc->fn_edit = (WNDPROC)(LONG_PTR) + SetWindowLongPtr(hwnd_edit, GWLP_WNDPROC, + (LONG_PTR) duration_edit_proc); +#pragma warning(pop) +} + +KHMEXP void KHMAPI +khui_tracker_reposition(khui_tracker * tc) { + RECT r; + + if(tc->hw_slider && tc->hw_edit) { + GetWindowRect(tc->hw_edit, &r); + SetWindowPos(tc->hw_slider, + NULL, + r.left, r.bottom, + 0, 0, + SWP_NOOWNERZORDER | SWP_NOSIZE | + SWP_NOZORDER | SWP_NOACTIVATE); + } +} + +KHMEXP void KHMAPI +khui_tracker_initialize(khui_tracker * tc) { + ZeroMemory(tc, sizeof(*tc)); +} + +KHMEXP void KHMAPI +khui_tracker_refresh(khui_tracker * tc) { + if (!tc->hw_edit) + return; + + SendMessage(tc->hw_edit, + KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0); +} + +KHMEXP void KHMAPI +khui_tracker_kill_controls(khui_tracker * tc) { + if (tc->hw_slider) + DestroyWindow(tc->hw_slider); + if (tc->hw_edit) + DestroyWindow(tc->hw_edit); + tc->hw_slider = NULL; + tc->hw_edit = NULL; + tc->fn_edit = NULL; + tc->fn_tracker = NULL; +} + + diff --git a/src/windows/identity/uilib/uibind.c b/src/windows/identity/uilib/uibind.c index 11da4e4bf..be183b68f 100644 --- a/src/windows/identity/uilib/uibind.c +++ b/src/windows/identity/uilib/uibind.c @@ -1,59 +1,59 @@ -/* - * Copyright (c) 2007 Secure Endpoints Inc. - * - * 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 - -#ifdef DEBUG -#include -#endif - -KHMEXP khm_int32 KHMAPI -khui_request_UI_callback(khm_ui_callback cb, void * rock) { - - khui_ui_callback_data cbdata; - -#ifdef DEBUG - assert(khui_hwnd_main); -#endif - - if (khui_hwnd_main == NULL) - return KHM_ERROR_NOT_READY; - - ZeroMemory(&cbdata, sizeof(cbdata)); - cbdata.magic = KHUI_UICBDATA_MAGIC; - cbdata.cb = cb; - cbdata.rock = rock; - cbdata.rv = KHM_ERROR_NOT_IMPLEMENTED; - - SendMessage(khui_hwnd_main, WM_COMMAND, - MAKEWPARAM(KHUI_ACTION_UICB, 0), - (LPARAM) &cbdata); - - return cbdata.rv; -} - - +/* + * Copyright (c) 2007 Secure Endpoints Inc. + * + * 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 + +#ifdef DEBUG +#include +#endif + +KHMEXP khm_int32 KHMAPI +khui_request_UI_callback(khm_ui_callback cb, void * rock) { + + khui_ui_callback_data cbdata; + +#ifdef DEBUG + assert(khui_hwnd_main); +#endif + + if (khui_hwnd_main == NULL) + return KHM_ERROR_NOT_READY; + + ZeroMemory(&cbdata, sizeof(cbdata)); + cbdata.magic = KHUI_UICBDATA_MAGIC; + cbdata.cb = cb; + cbdata.rock = rock; + cbdata.rv = KHM_ERROR_NOT_IMPLEMENTED; + + SendMessage(khui_hwnd_main, WM_COMMAND, + MAKEWPARAM(KHUI_ACTION_UICB, 0), + (LPARAM) &cbdata); + + return cbdata.rv; +} + + diff --git a/src/windows/identity/uilib/uilibmain.c b/src/windows/identity/uilib/uilibmain.c index 4d0b012f1..5c13ad424 100644 --- a/src/windows/identity/uilib/uilibmain.c +++ b/src/windows/identity/uilib/uilibmain.c @@ -1,44 +1,44 @@ -/* - * 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 - -extern void alert_init(void); -extern void alert_exit(void); -extern void ps_init(void); -extern void ps_exit(void); - -void -uilib_process_attach(void) { - alert_init(); - ps_init(); -} - -void -uilib_process_detach(void) { - ps_exit(); - alert_exit(); -} +/* + * 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 + +extern void alert_init(void); +extern void alert_exit(void); +extern void ps_init(void); +extern void ps_exit(void); + +void +uilib_process_attach(void) { + alert_init(); + ps_init(); +} + +void +uilib_process_detach(void) { + ps_exit(); + alert_exit(); +} diff --git a/src/windows/identity/uilib/version.c b/src/windows/identity/uilib/version.c index cf7f702bf..6e3e48fe6 100644 --- a/src/windows/identity/uilib/version.c +++ b/src/windows/identity/uilib/version.c @@ -1,83 +1,83 @@ -/* - * 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 - -DLLVERSIONINFO ver_commctl; - -static void -get_dll_version(wchar_t * dllname, DLLVERSIONINFO * pdvi) { - HINSTANCE hdll; - - hdll = LoadLibrary(dllname); - - ZeroMemory(pdvi, sizeof(*pdvi)); - - if(hdll) { - DLLGETVERSIONPROC pDllGetVersion; - - pDllGetVersion = (DLLGETVERSIONPROC) GetProcAddress(hdll, "DllGetVersion"); - if(pDllGetVersion) { - pdvi->cbSize = sizeof(*pdvi); - - (*pDllGetVersion)(pdvi); - } - FreeLibrary(hdll); - } -} - -KHMEXP void KHMAPI -khm_version_init(void) { - get_dll_version(L"comctl32.dll", &ver_commctl); -} - -KHMEXP void KHMAPI -khm_get_lib_version(khm_version * libver, khm_ui_4 * apiver) { - if (!libver) - return; - - libver->major = KH_VERSION_MAJOR; - libver->minor = KH_VERSION_MINOR; - libver->patch = KH_VERSION_PATCH; - libver->aux = KH_VERSION_AUX; - - if (apiver) - *apiver = KH_VERSION_API; -} - -KHMEXP khm_ui_4 KHMAPI -khm_get_commctl_version(khm_version * pdvi) { - if (pdvi) { - pdvi->major = (khm_ui_2) ver_commctl.dwMajorVersion; - pdvi->minor = (khm_ui_2) ver_commctl.dwMinorVersion; - pdvi->patch = (khm_ui_2) ver_commctl.dwBuildNumber; - pdvi->aux = (khm_ui_2) ver_commctl.dwPlatformID; - } - - return MAKELONG(ver_commctl.dwMinorVersion, ver_commctl.dwMajorVersion); -} +/* + * 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 + +DLLVERSIONINFO ver_commctl; + +static void +get_dll_version(wchar_t * dllname, DLLVERSIONINFO * pdvi) { + HINSTANCE hdll; + + hdll = LoadLibrary(dllname); + + ZeroMemory(pdvi, sizeof(*pdvi)); + + if(hdll) { + DLLGETVERSIONPROC pDllGetVersion; + + pDllGetVersion = (DLLGETVERSIONPROC) GetProcAddress(hdll, "DllGetVersion"); + if(pDllGetVersion) { + pdvi->cbSize = sizeof(*pdvi); + + (*pDllGetVersion)(pdvi); + } + FreeLibrary(hdll); + } +} + +KHMEXP void KHMAPI +khm_version_init(void) { + get_dll_version(L"comctl32.dll", &ver_commctl); +} + +KHMEXP void KHMAPI +khm_get_lib_version(khm_version * libver, khm_ui_4 * apiver) { + if (!libver) + return; + + libver->major = KH_VERSION_MAJOR; + libver->minor = KH_VERSION_MINOR; + libver->patch = KH_VERSION_PATCH; + libver->aux = KH_VERSION_AUX; + + if (apiver) + *apiver = KH_VERSION_API; +} + +KHMEXP khm_ui_4 KHMAPI +khm_get_commctl_version(khm_version * pdvi) { + if (pdvi) { + pdvi->major = (khm_ui_2) ver_commctl.dwMajorVersion; + pdvi->minor = (khm_ui_2) ver_commctl.dwMinorVersion; + pdvi->patch = (khm_ui_2) ver_commctl.dwBuildNumber; + pdvi->aux = (khm_ui_2) ver_commctl.dwPlatformID; + } + + return MAKELONG(ver_commctl.dwMinorVersion, ver_commctl.dwMajorVersion); +} diff --git a/src/windows/identity/util/hashtable.c b/src/windows/identity/util/hashtable.c index ddf7b1bf8..5773d8021 100644 --- a/src/windows/identity/util/hashtable.c +++ b/src/windows/identity/util/hashtable.c @@ -1,171 +1,171 @@ -/* - * 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 - -KHMEXP hashtable * KHMAPI hash_new_hashtable(khm_int32 n, - hash_function_t hash, - comp_function_t comp, - add_ref_function_t addr, - del_ref_function_t delr) -{ - hashtable * h; - - h = PMALLOC(sizeof(hashtable)); - - h->n = n; - h->addr = addr; - h->comp = comp; - h->delr = delr; - h->hash = hash; - - h->bins = PCALLOC(sizeof(hash_bin *), n); - - return h; -} - -KHMEXP void KHMAPI hash_del_hashtable(hashtable * h) { - hash_bin * b; - int i; - - for(i=0;in;i++) { - LPOP(&h->bins[i], &b); - while(b) { - if(h->delr) - h->delr(b->key, b->data); - PFREE(b); - LPOP(&h->bins[i], &b); - } - } - - if (h->bins) - PFREE(h->bins); - - PFREE(h); -} - -KHMEXP void KHMAPI hash_add(hashtable * h, const void * key, void * data) { - int hv; - hash_bin * b; - - hv = h->hash(key) % h->n; - b = h->bins[hv]; - while(b) { - if(!h->comp(b->key, key)) { - /* found an existing value */ - if(h->delr) - h->delr(b->key, b->data); - b->key = key; - b->data = data; - if(h->addr) - h->addr(b->key, b->data); - break; - } - b = LNEXT(b); - } - - if(!b) { - b = PMALLOC(sizeof(hash_bin)); - b->data = data; - b->key = key; - LINIT(b); - LPUSH(&h->bins[hv], b); - if(h->addr) - h->addr(b->key, b->data); - } -} - -KHMEXP void KHMAPI hash_del(hashtable * h, const void * key) { - hash_bin * b; - int hv; - - hv = h->hash(key) % h->n; - - b = h->bins[hv]; - while(b) { - if(!h->comp(b->key, key)) { - /* found it */ - LDELETE(&h->bins[hv], b); - if(h->delr) - h->delr(b->key, b->data); - PFREE(b); - break; - } - b = LNEXT(b); - } -} - -KHMEXP void * KHMAPI hash_lookup(hashtable * h, const void * key) { - hash_bin * b; - int hv; - - hv = h->hash(key) % h->n; - - b = h->bins[hv]; - - while(b) { - if(!h->comp(b->key, key)) { - return b->data; - } - b = LNEXT(b); - } - - return NULL; -} - -KHMEXP khm_boolean KHMAPI hash_exist(hashtable * h, const void * key) { - hash_bin * b; - int hv; - - hv = h->hash(key) % h->n; - b = h->bins[hv]; - while(b) { - if(!h->comp(b->key, key)) - return 1; - b = LNEXT(b); - } - - return 0; -} - -KHMEXP khm_int32 hash_string(const void *vs) { - /* DJB algorithm */ - - khm_int32 hv = 13331; - wchar_t * c; - - for(c = (wchar_t *) vs; *c; c++) { - hv = ((hv<<5) + hv) + (khm_int32) *c; - } - - return (hv & KHM_INT32_MAX); -} - -KHMEXP khm_int32 hash_string_comp(const void *vs1, const void *vs2) { - return wcscmp((const wchar_t *) vs1, (const wchar_t *) vs2); -} +/* + * 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 + +KHMEXP hashtable * KHMAPI hash_new_hashtable(khm_int32 n, + hash_function_t hash, + comp_function_t comp, + add_ref_function_t addr, + del_ref_function_t delr) +{ + hashtable * h; + + h = PMALLOC(sizeof(hashtable)); + + h->n = n; + h->addr = addr; + h->comp = comp; + h->delr = delr; + h->hash = hash; + + h->bins = PCALLOC(sizeof(hash_bin *), n); + + return h; +} + +KHMEXP void KHMAPI hash_del_hashtable(hashtable * h) { + hash_bin * b; + int i; + + for(i=0;in;i++) { + LPOP(&h->bins[i], &b); + while(b) { + if(h->delr) + h->delr(b->key, b->data); + PFREE(b); + LPOP(&h->bins[i], &b); + } + } + + if (h->bins) + PFREE(h->bins); + + PFREE(h); +} + +KHMEXP void KHMAPI hash_add(hashtable * h, const void * key, void * data) { + int hv; + hash_bin * b; + + hv = h->hash(key) % h->n; + b = h->bins[hv]; + while(b) { + if(!h->comp(b->key, key)) { + /* found an existing value */ + if(h->delr) + h->delr(b->key, b->data); + b->key = key; + b->data = data; + if(h->addr) + h->addr(b->key, b->data); + break; + } + b = LNEXT(b); + } + + if(!b) { + b = PMALLOC(sizeof(hash_bin)); + b->data = data; + b->key = key; + LINIT(b); + LPUSH(&h->bins[hv], b); + if(h->addr) + h->addr(b->key, b->data); + } +} + +KHMEXP void KHMAPI hash_del(hashtable * h, const void * key) { + hash_bin * b; + int hv; + + hv = h->hash(key) % h->n; + + b = h->bins[hv]; + while(b) { + if(!h->comp(b->key, key)) { + /* found it */ + LDELETE(&h->bins[hv], b); + if(h->delr) + h->delr(b->key, b->data); + PFREE(b); + break; + } + b = LNEXT(b); + } +} + +KHMEXP void * KHMAPI hash_lookup(hashtable * h, const void * key) { + hash_bin * b; + int hv; + + hv = h->hash(key) % h->n; + + b = h->bins[hv]; + + while(b) { + if(!h->comp(b->key, key)) { + return b->data; + } + b = LNEXT(b); + } + + return NULL; +} + +KHMEXP khm_boolean KHMAPI hash_exist(hashtable * h, const void * key) { + hash_bin * b; + int hv; + + hv = h->hash(key) % h->n; + b = h->bins[hv]; + while(b) { + if(!h->comp(b->key, key)) + return 1; + b = LNEXT(b); + } + + return 0; +} + +KHMEXP khm_int32 hash_string(const void *vs) { + /* DJB algorithm */ + + khm_int32 hv = 13331; + wchar_t * c; + + for(c = (wchar_t *) vs; *c; c++) { + hv = ((hv<<5) + hv) + (khm_int32) *c; + } + + return (hv & KHM_INT32_MAX); +} + +KHMEXP khm_int32 hash_string_comp(const void *vs1, const void *vs2) { + return wcscmp((const wchar_t *) vs1, (const wchar_t *) vs2); +} diff --git a/src/windows/identity/util/hashtable.h b/src/windows/identity/util/hashtable.h index 1a3fb4b86..72fff2294 100644 --- a/src/windows/identity/util/hashtable.h +++ b/src/windows/identity/util/hashtable.h @@ -1,231 +1,231 @@ -/* - * 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_HASHTABLE_H -#define __KHIMAIRA_HASHTABLE_H - -/*! \addtogroup util - @{ */ - -/*! \defgroup util_ht Hashtable - @{*/ - -#include -#include - -/*! \brief A hash function - - The function should take a key as a parameter and return an - khm_int32 that serves as the hash of the key. - */ -typedef khm_int32 (*hash_function_t)(const void *key); - -/*! \brief A comparison function - - The function takes two keys and returns a value indicating the - relative ordering of the two keys. - - The return value should be: - - \b Zero if \a key1 == \a key2 - - \b Negative if \a key1 < \a key2 - - \b Positive if \a key1 > \a key2 - */ -typedef khm_int32 (*comp_function_t)(const void *key1, const void *key2); - -/*! \brief Add-reference function - - When an object is successfully added to a hashtable, this function - will be called with the \a key and \a data used to add the object. - The function is allowed to modify \a data, however, the - modification should not alter the \a key or the relationship - between \a key and \a data. - */ -typedef void (*add_ref_function_t)(const void *key, void *data); - -/*! \brief Delete-reference function - - When an object is successfully removed from the hashtable, this - function will be called. As with the add-ref function, the object - can be modified, but the \a key and the relationship between \a - key and \a data should remain intact. - - An object is removed if it is explicitly removed from the - hashtable or another object with the same \a key is added to the - hashtable. There should be a 1-1 correspondence with keys and - objects in the hashtable. The delete-reference function will be - called on all the remaining objects in the hashtable when the - hashtable is deleted. - */ -typedef void (*del_ref_function_t)(const void *key, void *data); - -typedef struct tag_hash_bin { - void * data; - const void * key; - - LDCL(struct tag_hash_bin); -} hash_bin; - -typedef struct hashtable_t { - khm_int32 n; - hash_function_t hash; - comp_function_t comp; - add_ref_function_t addr; - del_ref_function_t delr; - hash_bin ** bins; -} hashtable; - -/*! \brief Create a new hashtable - - \param[in] n Number of bins in hashtable. - \param[in] hash A hash function. Required. - \param[in] comp A comparator. Required. - \param[in] addr An add-ref function. Optional; can be NULL. - \param[in] delr A del-ref function. Optional; can be NULL. - - */ -KHMEXP hashtable * KHMAPI hash_new_hashtable(khm_int32 n, - hash_function_t hash, - comp_function_t comp, - add_ref_function_t addr, - del_ref_function_t delr); - -/*! \brief Delete a hashtable - - \note Not thread-safe. Applications must serialize calls that - reference the same hashtable. - */ -KHMEXP void KHMAPI hash_del_hashtable(hashtable * h); - -/*! \brief Add an object to a hashtable - - Creates an association between the \a key and \a data in the - hashtable \a h. If there is an add-ref function defined for the - hashtable, it will be called with \a key and \data after the - object is added. If there is already an object with the same key - in the hashtable, that object will be removed (and the del-ref - function called, if appilcable) before adding the new object and - before the add-ref function is called for the new object. - - Note that two keys \a key1 and \a key2 are equal (or same) in a - hashtable if the comparator returns zero when called with \a key1 - and \a key2. - - Also note that all additions and removals to the hashtable are - done by reference. No data is copied. Any objects pointed to are - expected to exist for the duration that the object and key are - contained in the hashtable. - - \param[in] h Hashtable - \param[in] key A key. If \a key points to a location in memory, - it should be within the object pointed to by \a data, or be a - constant. Can be NULL. - \param[in] data Data. Cannot be NULL. - - \note Not thread-safe. Applications must serialize calls that - reference the same hashtable. - */ -KHMEXP void KHMAPI hash_add(hashtable * h, const void * key, void * data); - -/*! \brief Delete an object from a hashtable - - Deletes the object in the hashtable \a h that is associated with - key \a key. An object is associated with key \a key if the key \a - key_o that the object is associated with is the same as \a key as - determined by the comparator. If the del-ref function is defined - for the hash-table, it will be called with the \a key_o and \a - data that was used to add the object. - - \note Not thread-safe. Applications must serialize calls that - reference the same hashtable. - */ -KHMEXP void KHMAPI hash_del(hashtable * h, const void * key); - -/*! \brief Resolve and association - - Return the object that is associated with key \a key in hashtable - \a h. An object \a data is associated with key \a key in \a h if - the key \a key_o that was used to add \a data to \a h is equal to - \a key as determined by the comparator. - - Returns NULL if no association is found. - - \note Not thread-safe. Applications must serialize calls that - reference the same hashtable. - */ -KHMEXP void * KHMAPI hash_lookup(hashtable * h, const void * key); - -/*! \brief Check for the presence of an association - - Returns non-zero if there exists an association between key \a key - and some object in hashtable \a h. See hash_lookup() for - definition of "association". - - Returns zero if there is no association. - - \note (hash_lookup(h,key) == NULL) iff (hash_exist(h,key)==0) - - \note Not thead-safe. Application must serialize calls that - reference the same hashtable. - */ -KHMEXP khm_boolean KHMAPI hash_exist(hashtable * h, const void * key); - -/*! \brief Compute a hashvalue for a unicode string - - The hash value is computed using DJB with parameter 13331. - - This function is suitable for use as the hash function for a - hashtable if the keys are NULL terminated safe unicode strings - that are either part of the data objects or are constants. - - \param[in] str A pointer to a NULL terminated wchar_t string cast - as (void *). - - \note This function does not check the length of the string \a - str. If the string is not \a NULL terminated, the behavior is - undefined. - */ -KHMEXP khm_int32 hash_string(const void *str); - -/*! \brief Compare two strings - - Compares two strings are returns a value that is in accordance - with the comparator for a hashtable. - - \param[in] vs1 A pointer to a NULL terminated wchar_t string cast - as (void *). - \param[in] vs2 A pointer to a NULL terminated wchar_t string cast - as (void *). - - \note This function does not check the length of the strings \a - vs1 and \a vs2. If the strings are not NULL terminated, the - behavior is undefined. - */ -KHMEXP khm_int32 hash_string_comp(const void *vs1, const void *vs2); - -/*@}*/ -/*@}*/ - -#endif +/* + * 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_HASHTABLE_H +#define __KHIMAIRA_HASHTABLE_H + +/*! \addtogroup util + @{ */ + +/*! \defgroup util_ht Hashtable + @{*/ + +#include +#include + +/*! \brief A hash function + + The function should take a key as a parameter and return an + khm_int32 that serves as the hash of the key. + */ +typedef khm_int32 (*hash_function_t)(const void *key); + +/*! \brief A comparison function + + The function takes two keys and returns a value indicating the + relative ordering of the two keys. + + The return value should be: + - \b Zero if \a key1 == \a key2 + - \b Negative if \a key1 < \a key2 + - \b Positive if \a key1 > \a key2 + */ +typedef khm_int32 (*comp_function_t)(const void *key1, const void *key2); + +/*! \brief Add-reference function + + When an object is successfully added to a hashtable, this function + will be called with the \a key and \a data used to add the object. + The function is allowed to modify \a data, however, the + modification should not alter the \a key or the relationship + between \a key and \a data. + */ +typedef void (*add_ref_function_t)(const void *key, void *data); + +/*! \brief Delete-reference function + + When an object is successfully removed from the hashtable, this + function will be called. As with the add-ref function, the object + can be modified, but the \a key and the relationship between \a + key and \a data should remain intact. + + An object is removed if it is explicitly removed from the + hashtable or another object with the same \a key is added to the + hashtable. There should be a 1-1 correspondence with keys and + objects in the hashtable. The delete-reference function will be + called on all the remaining objects in the hashtable when the + hashtable is deleted. + */ +typedef void (*del_ref_function_t)(const void *key, void *data); + +typedef struct tag_hash_bin { + void * data; + const void * key; + + LDCL(struct tag_hash_bin); +} hash_bin; + +typedef struct hashtable_t { + khm_int32 n; + hash_function_t hash; + comp_function_t comp; + add_ref_function_t addr; + del_ref_function_t delr; + hash_bin ** bins; +} hashtable; + +/*! \brief Create a new hashtable + + \param[in] n Number of bins in hashtable. + \param[in] hash A hash function. Required. + \param[in] comp A comparator. Required. + \param[in] addr An add-ref function. Optional; can be NULL. + \param[in] delr A del-ref function. Optional; can be NULL. + + */ +KHMEXP hashtable * KHMAPI hash_new_hashtable(khm_int32 n, + hash_function_t hash, + comp_function_t comp, + add_ref_function_t addr, + del_ref_function_t delr); + +/*! \brief Delete a hashtable + + \note Not thread-safe. Applications must serialize calls that + reference the same hashtable. + */ +KHMEXP void KHMAPI hash_del_hashtable(hashtable * h); + +/*! \brief Add an object to a hashtable + + Creates an association between the \a key and \a data in the + hashtable \a h. If there is an add-ref function defined for the + hashtable, it will be called with \a key and \data after the + object is added. If there is already an object with the same key + in the hashtable, that object will be removed (and the del-ref + function called, if appilcable) before adding the new object and + before the add-ref function is called for the new object. + + Note that two keys \a key1 and \a key2 are equal (or same) in a + hashtable if the comparator returns zero when called with \a key1 + and \a key2. + + Also note that all additions and removals to the hashtable are + done by reference. No data is copied. Any objects pointed to are + expected to exist for the duration that the object and key are + contained in the hashtable. + + \param[in] h Hashtable + \param[in] key A key. If \a key points to a location in memory, + it should be within the object pointed to by \a data, or be a + constant. Can be NULL. + \param[in] data Data. Cannot be NULL. + + \note Not thread-safe. Applications must serialize calls that + reference the same hashtable. + */ +KHMEXP void KHMAPI hash_add(hashtable * h, const void * key, void * data); + +/*! \brief Delete an object from a hashtable + + Deletes the object in the hashtable \a h that is associated with + key \a key. An object is associated with key \a key if the key \a + key_o that the object is associated with is the same as \a key as + determined by the comparator. If the del-ref function is defined + for the hash-table, it will be called with the \a key_o and \a + data that was used to add the object. + + \note Not thread-safe. Applications must serialize calls that + reference the same hashtable. + */ +KHMEXP void KHMAPI hash_del(hashtable * h, const void * key); + +/*! \brief Resolve and association + + Return the object that is associated with key \a key in hashtable + \a h. An object \a data is associated with key \a key in \a h if + the key \a key_o that was used to add \a data to \a h is equal to + \a key as determined by the comparator. + + Returns NULL if no association is found. + + \note Not thread-safe. Applications must serialize calls that + reference the same hashtable. + */ +KHMEXP void * KHMAPI hash_lookup(hashtable * h, const void * key); + +/*! \brief Check for the presence of an association + + Returns non-zero if there exists an association between key \a key + and some object in hashtable \a h. See hash_lookup() for + definition of "association". + + Returns zero if there is no association. + + \note (hash_lookup(h,key) == NULL) iff (hash_exist(h,key)==0) + + \note Not thead-safe. Application must serialize calls that + reference the same hashtable. + */ +KHMEXP khm_boolean KHMAPI hash_exist(hashtable * h, const void * key); + +/*! \brief Compute a hashvalue for a unicode string + + The hash value is computed using DJB with parameter 13331. + + This function is suitable for use as the hash function for a + hashtable if the keys are NULL terminated safe unicode strings + that are either part of the data objects or are constants. + + \param[in] str A pointer to a NULL terminated wchar_t string cast + as (void *). + + \note This function does not check the length of the string \a + str. If the string is not \a NULL terminated, the behavior is + undefined. + */ +KHMEXP khm_int32 hash_string(const void *str); + +/*! \brief Compare two strings + + Compares two strings are returns a value that is in accordance + with the comparator for a hashtable. + + \param[in] vs1 A pointer to a NULL terminated wchar_t string cast + as (void *). + \param[in] vs2 A pointer to a NULL terminated wchar_t string cast + as (void *). + + \note This function does not check the length of the strings \a + vs1 and \a vs2. If the strings are not NULL terminated, the + behavior is undefined. + */ +KHMEXP khm_int32 hash_string_comp(const void *vs1, const void *vs2); + +/*@}*/ +/*@}*/ + +#endif diff --git a/src/windows/identity/util/mstring.c b/src/windows/identity/util/mstring.c index b642d1af8..d9eb9d350 100644 --- a/src/windows/identity/util/mstring.c +++ b/src/windows/identity/util/mstring.c @@ -1,510 +1,510 @@ -/* -* 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 - -#define TRUE 1 -#define FALSE 0 - -KHMEXP khm_int32 KHMAPI -multi_string_init(wchar_t * ms, - khm_size cb_ms) { - if (!ms || cb_ms < sizeof(wchar_t) * 2) - return KHM_ERROR_INVALID_PARAM; - - memset(ms, 0, cb_ms); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -multi_string_append(wchar_t * ms, - khm_size * pcb_ms, - const wchar_t * str) -{ - wchar_t * s; - size_t cch_s; - size_t cch_t; - size_t cch_r; - - if(!ms || !pcb_ms || !str) - return KHM_ERROR_INVALID_PARAM; - - if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s)) || cch_s == 0) - return KHM_ERROR_INVALID_PARAM; - cch_s++; - - s = ms; - - while(*s && ((s - ms) < KHM_MAXCCH_STRING)) { - if(FAILED(StringCchLength(s, KHM_MAXCB_STRING, &cch_t))) - return KHM_ERROR_INVALID_PARAM; - s += cch_t + 1; - } - - if(*s || (s - ms) >= KHM_MAXCCH_STRING) { - return KHM_ERROR_INVALID_PARAM; - } - - /* now s points to the second NULL of the terminating double NULL */ - - cch_r = ((s - ms) + cch_s + 1) * sizeof(wchar_t); - if(*pcb_ms < cch_r) { - *pcb_ms = cch_r; - return KHM_ERROR_TOO_LONG; - } - - *pcb_ms = cch_r; - - StringCchCopy(s, cch_s, str); - s += cch_s; - *s = 0; - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -multi_string_prepend(wchar_t * ms, - khm_size * pcb_ms, - const wchar_t * str) -{ - size_t cch_s; - size_t cch_t; - size_t cch_r; - khm_size cb_r; - - if(!ms || !pcb_ms || !str) - return KHM_ERROR_INVALID_PARAM; - - if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s)) || cch_s == 0) - return KHM_ERROR_INVALID_PARAM; - cch_s++; - - if(KHM_FAILED(multi_string_length_cch(ms, - KHM_MAXCCH_STRING, - &cch_r))) - return KHM_ERROR_INVALID_PARAM; - - cch_t = cch_s + cch_r; - cb_r = cch_t * sizeof(wchar_t); - - if (*pcb_ms < cb_r) { - *pcb_ms = cb_r; - return KHM_ERROR_TOO_LONG; - } - - memmove(ms + cch_s, ms, cch_r * sizeof(wchar_t)); - memcpy(ms, str, cch_s * sizeof(wchar_t)); - - *pcb_ms = cb_r; - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -multi_string_delete(wchar_t * ms, - const wchar_t * str, - const khm_int32 flags) -{ - wchar_t * s; - wchar_t * n; - wchar_t * e; - size_t cch; - - if(!ms || !str) - return KHM_ERROR_INVALID_PARAM; - - s = multi_string_find(ms, str, flags); - if(!s) - return KHM_ERROR_NOT_FOUND; - - e = s; - n = NULL; - while(*e && (e - s) < KHM_MAXCCH_STRING) { - if(FAILED(StringCchLength(e, KHM_MAXCCH_STRING, &cch))) - return KHM_ERROR_INVALID_PARAM; - e += cch + 1; - - if(!n) - n = e; - } - - if(*e || (e - s) >= KHM_MAXCCH_STRING) - return KHM_ERROR_INVALID_PARAM; - - if(e == s) - return KHM_ERROR_SUCCESS; - - memmove((void *) s, (void *) n, ((e - n) + 1) * sizeof(wchar_t)); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP wchar_t * KHMAPI -multi_string_find(const wchar_t * ms, - const wchar_t * str, - const khm_int32 flags) -{ - const wchar_t *s; - size_t cch; - size_t cch_s; - - if(!ms || !str) - return NULL; - - if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s))) - return NULL; - - s = ms; - - while(*s && (s - ms) < KHM_MAXCCH_STRING) { - if(FAILED(StringCchLength(s, KHM_MAXCCH_STRING, &cch))) - return NULL; - /* cch++ at end */ - - if(flags & KHM_PREFIX) { - if(((flags & KHM_CASE_SENSITIVE) && !wcsncmp(s, str, cch_s)) || - (!(flags & KHM_CASE_SENSITIVE) && !_wcsnicmp(s, str, cch_s))) - return (wchar_t *) s; - } else { - if((cch == cch_s) && - ((flags & KHM_CASE_SENSITIVE) && !wcsncmp(s, str, cch)) || - (!(flags & KHM_CASE_SENSITIVE) && !_wcsnicmp(s, str, cch))) - return (wchar_t *) s; - } - - s += cch + 1; - } - - return NULL; -} - -KHMEXP khm_int32 KHMAPI -multi_string_to_csv(wchar_t * csvbuf, - khm_size * pcb_csvbuf, - const wchar_t * ms) -{ - size_t cb; - size_t cbt; - const wchar_t * t; - wchar_t * d; - - if(!pcb_csvbuf || !ms) - return KHM_ERROR_INVALID_PARAM; - - /* dry run */ - cbt = 0; - t = ms; - while(*t && cbt <= KHM_MAXCB_STRING) { - khm_boolean quotes = FALSE; - - if(FAILED(StringCbLength(t, KHM_MAXCB_STRING, &cb))) - return KHM_ERROR_INVALID_PARAM; - cb += sizeof(wchar_t); - - cbt += cb; - - if(wcschr(t, L',')) - quotes = TRUE; - - d = (wchar_t *) t; - while(d = wcschr(d, L'"')) { - cbt += sizeof(wchar_t); /* '"'-> '""' */ - d++; - quotes = TRUE; - } - - if(quotes) - cbt += 2*sizeof(wchar_t); /* make room for quotes */ - - t += cb / sizeof(wchar_t); - } - - if(cbt > KHM_MAXCB_STRING) - return KHM_ERROR_INVALID_PARAM; - - /* happens if the multi string contained no strings */ - if(cbt == 0) - cbt = sizeof(wchar_t); - - if(!csvbuf || *pcb_csvbuf < cbt) - { - *pcb_csvbuf = cbt; - return KHM_ERROR_TOO_LONG; - } - - *pcb_csvbuf = cbt; - - /* wet run */ - t = ms; - d = csvbuf; - *csvbuf = 0; - while(*t) { - const wchar_t * s; - - StringCbLength(t, KHM_MAXCB_STRING, &cb); - cb += sizeof(wchar_t); - - if(d != csvbuf) - *d++ = L','; - if(wcschr(t, L',') || wcschr(t, L'"')) { - *d++ = L'"'; - s = t; - while(*s) { - if(*s == L'"') { - *d++ = L'"'; - *d++ = L'"'; - } else - *d++ = *s; - s++; - } - *d++ = L'"'; - *d = 0; - } else { - StringCbCopy(d, cbt - ((d - csvbuf) * sizeof(wchar_t)), t); - d += cb / sizeof(wchar_t) - 1; - } - t += cb / sizeof(wchar_t); - } - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -csv_to_multi_string(wchar_t * ms, - khm_size * pcb_ms, - const wchar_t * csv) -{ - const wchar_t * t; - wchar_t * p; - size_t cchr; - int field = 1; - - - if(!pcb_ms || !csv) - return KHM_ERROR_INVALID_PARAM; - - cchr = 0; - - /* dry run */ - t = csv; - while(*t && (t - csv) < KHM_MAXCCH_STRING) { - if(field && *t == L'"') { - t++; - while(*t && (t - csv) < KHM_MAXCCH_STRING) { - if(*t == L'"') { - t++; - if(*t != L'"') - break; - } - cchr++; - t++; - } - } - - if(*t) { - cchr++; - if(*t == L',') - field = 1; - else - field = 0; - - t++; - } - } - - if((t - csv) >= KHM_MAXCCH_STRING) - return KHM_ERROR_INVALID_PARAM; - - cchr++; /* last string ends */ - cchr++; /* double NULL */ - - if(!ms || *pcb_ms < (cchr * sizeof(wchar_t))) { - *pcb_ms = cchr * sizeof(wchar_t); - return KHM_ERROR_TOO_LONG; - } - - /* wet run */ - t = csv; - p = ms; - field = 1; - while(*t) { - if(field && *t == L'"') { - t++; - while(*t) { - if(*t == L'"') { - t++; - if(*t != L'"') - break; - } - *p++ = *t; - t++; - } - } - - if(*t == L',') { - *p++ = 0; - field = 1; - t++; - } else if(*t) { - *p++ = *t; - field = 0; - t++; - } - } - - *p++ = 0; /* last string ends */ - *p++ = 0; /* double NULL */ - - *pcb_ms = (p - ms) * sizeof(wchar_t); - - return KHM_ERROR_SUCCESS; -} - -KHMEXP wchar_t * KHMAPI -multi_string_next(const wchar_t * str) -{ - size_t cch; - - if(*str) { - if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch))) - return NULL; - str += cch + 1; - if(*str) - return (wchar_t *) str; - else - return NULL; - } else { - return NULL; - } -} - -KHMEXP khm_size KHMAPI -multi_string_length_n(const wchar_t * str) -{ - size_t n = 0; - const wchar_t * c = str; - - while(c) { - n++; - c = multi_string_next(c); - } - - return n; -} - -KHMEXP khm_int32 KHMAPI -multi_string_length_cb(const wchar_t * str, - khm_size max_cb, - khm_size * len_cb) -{ - khm_size cch; - khm_int32 rv; - - rv = multi_string_length_cch(str, max_cb / sizeof(wchar_t), &cch); - - if(KHM_FAILED(rv)) - return rv; - - if(len_cb) - *len_cb = cch * sizeof(wchar_t); - - return rv; -} - -KHMEXP khm_int32 KHMAPI -multi_string_length_cch(const wchar_t * str, - khm_size max_cch, - khm_size * len_cch) -{ - const wchar_t * s; - khm_size cch; - size_t tcch; - - if(!str) - return KHM_ERROR_INVALID_PARAM; - - s = str; - cch = 0; - while(*s && (cch < max_cch)) { - if(FAILED(StringCchLength(s, max_cch, &tcch))) - return KHM_ERROR_TOO_LONG; - cch += ++tcch; - s += tcch; - } - - if(cch >= max_cch) - return KHM_ERROR_TOO_LONG; - - if(len_cch) { - *len_cch = ++cch; - } - - return KHM_ERROR_SUCCESS; -} - -KHMEXP khm_int32 KHMAPI -multi_string_copy_cb(wchar_t * s_dest, - khm_size max_cb_dest, - const wchar_t * src) -{ - khm_size cb_dest; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!s_dest) - return KHM_ERROR_INVALID_PARAM; - - rv = multi_string_length_cb(src, max_cb_dest, &cb_dest); - if(KHM_FAILED(rv)) - return rv; - - memmove(s_dest, src, cb_dest); - - return rv; -} - -KHMEXP khm_int32 KHMAPI -multi_string_copy_cch(wchar_t * s_dest, - khm_size max_cch_dest, - const wchar_t * src) -{ - khm_size cch_dest; - khm_int32 rv = KHM_ERROR_SUCCESS; - - if(!s_dest) - return KHM_ERROR_INVALID_PARAM; - - rv = multi_string_length_cch(src, max_cch_dest, &cch_dest); - if(KHM_FAILED(rv)) - return rv; - - memmove(s_dest, src, cch_dest * sizeof(wchar_t)); - - return rv; -} +/* +* 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 + +#define TRUE 1 +#define FALSE 0 + +KHMEXP khm_int32 KHMAPI +multi_string_init(wchar_t * ms, + khm_size cb_ms) { + if (!ms || cb_ms < sizeof(wchar_t) * 2) + return KHM_ERROR_INVALID_PARAM; + + memset(ms, 0, cb_ms); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +multi_string_append(wchar_t * ms, + khm_size * pcb_ms, + const wchar_t * str) +{ + wchar_t * s; + size_t cch_s; + size_t cch_t; + size_t cch_r; + + if(!ms || !pcb_ms || !str) + return KHM_ERROR_INVALID_PARAM; + + if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s)) || cch_s == 0) + return KHM_ERROR_INVALID_PARAM; + cch_s++; + + s = ms; + + while(*s && ((s - ms) < KHM_MAXCCH_STRING)) { + if(FAILED(StringCchLength(s, KHM_MAXCB_STRING, &cch_t))) + return KHM_ERROR_INVALID_PARAM; + s += cch_t + 1; + } + + if(*s || (s - ms) >= KHM_MAXCCH_STRING) { + return KHM_ERROR_INVALID_PARAM; + } + + /* now s points to the second NULL of the terminating double NULL */ + + cch_r = ((s - ms) + cch_s + 1) * sizeof(wchar_t); + if(*pcb_ms < cch_r) { + *pcb_ms = cch_r; + return KHM_ERROR_TOO_LONG; + } + + *pcb_ms = cch_r; + + StringCchCopy(s, cch_s, str); + s += cch_s; + *s = 0; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +multi_string_prepend(wchar_t * ms, + khm_size * pcb_ms, + const wchar_t * str) +{ + size_t cch_s; + size_t cch_t; + size_t cch_r; + khm_size cb_r; + + if(!ms || !pcb_ms || !str) + return KHM_ERROR_INVALID_PARAM; + + if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s)) || cch_s == 0) + return KHM_ERROR_INVALID_PARAM; + cch_s++; + + if(KHM_FAILED(multi_string_length_cch(ms, + KHM_MAXCCH_STRING, + &cch_r))) + return KHM_ERROR_INVALID_PARAM; + + cch_t = cch_s + cch_r; + cb_r = cch_t * sizeof(wchar_t); + + if (*pcb_ms < cb_r) { + *pcb_ms = cb_r; + return KHM_ERROR_TOO_LONG; + } + + memmove(ms + cch_s, ms, cch_r * sizeof(wchar_t)); + memcpy(ms, str, cch_s * sizeof(wchar_t)); + + *pcb_ms = cb_r; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +multi_string_delete(wchar_t * ms, + const wchar_t * str, + const khm_int32 flags) +{ + wchar_t * s; + wchar_t * n; + wchar_t * e; + size_t cch; + + if(!ms || !str) + return KHM_ERROR_INVALID_PARAM; + + s = multi_string_find(ms, str, flags); + if(!s) + return KHM_ERROR_NOT_FOUND; + + e = s; + n = NULL; + while(*e && (e - s) < KHM_MAXCCH_STRING) { + if(FAILED(StringCchLength(e, KHM_MAXCCH_STRING, &cch))) + return KHM_ERROR_INVALID_PARAM; + e += cch + 1; + + if(!n) + n = e; + } + + if(*e || (e - s) >= KHM_MAXCCH_STRING) + return KHM_ERROR_INVALID_PARAM; + + if(e == s) + return KHM_ERROR_SUCCESS; + + memmove((void *) s, (void *) n, ((e - n) + 1) * sizeof(wchar_t)); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP wchar_t * KHMAPI +multi_string_find(const wchar_t * ms, + const wchar_t * str, + const khm_int32 flags) +{ + const wchar_t *s; + size_t cch; + size_t cch_s; + + if(!ms || !str) + return NULL; + + if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s))) + return NULL; + + s = ms; + + while(*s && (s - ms) < KHM_MAXCCH_STRING) { + if(FAILED(StringCchLength(s, KHM_MAXCCH_STRING, &cch))) + return NULL; + /* cch++ at end */ + + if(flags & KHM_PREFIX) { + if(((flags & KHM_CASE_SENSITIVE) && !wcsncmp(s, str, cch_s)) || + (!(flags & KHM_CASE_SENSITIVE) && !_wcsnicmp(s, str, cch_s))) + return (wchar_t *) s; + } else { + if((cch == cch_s) && + ((flags & KHM_CASE_SENSITIVE) && !wcsncmp(s, str, cch)) || + (!(flags & KHM_CASE_SENSITIVE) && !_wcsnicmp(s, str, cch))) + return (wchar_t *) s; + } + + s += cch + 1; + } + + return NULL; +} + +KHMEXP khm_int32 KHMAPI +multi_string_to_csv(wchar_t * csvbuf, + khm_size * pcb_csvbuf, + const wchar_t * ms) +{ + size_t cb; + size_t cbt; + const wchar_t * t; + wchar_t * d; + + if(!pcb_csvbuf || !ms) + return KHM_ERROR_INVALID_PARAM; + + /* dry run */ + cbt = 0; + t = ms; + while(*t && cbt <= KHM_MAXCB_STRING) { + khm_boolean quotes = FALSE; + + if(FAILED(StringCbLength(t, KHM_MAXCB_STRING, &cb))) + return KHM_ERROR_INVALID_PARAM; + cb += sizeof(wchar_t); + + cbt += cb; + + if(wcschr(t, L',')) + quotes = TRUE; + + d = (wchar_t *) t; + while(d = wcschr(d, L'"')) { + cbt += sizeof(wchar_t); /* '"'-> '""' */ + d++; + quotes = TRUE; + } + + if(quotes) + cbt += 2*sizeof(wchar_t); /* make room for quotes */ + + t += cb / sizeof(wchar_t); + } + + if(cbt > KHM_MAXCB_STRING) + return KHM_ERROR_INVALID_PARAM; + + /* happens if the multi string contained no strings */ + if(cbt == 0) + cbt = sizeof(wchar_t); + + if(!csvbuf || *pcb_csvbuf < cbt) + { + *pcb_csvbuf = cbt; + return KHM_ERROR_TOO_LONG; + } + + *pcb_csvbuf = cbt; + + /* wet run */ + t = ms; + d = csvbuf; + *csvbuf = 0; + while(*t) { + const wchar_t * s; + + StringCbLength(t, KHM_MAXCB_STRING, &cb); + cb += sizeof(wchar_t); + + if(d != csvbuf) + *d++ = L','; + if(wcschr(t, L',') || wcschr(t, L'"')) { + *d++ = L'"'; + s = t; + while(*s) { + if(*s == L'"') { + *d++ = L'"'; + *d++ = L'"'; + } else + *d++ = *s; + s++; + } + *d++ = L'"'; + *d = 0; + } else { + StringCbCopy(d, cbt - ((d - csvbuf) * sizeof(wchar_t)), t); + d += cb / sizeof(wchar_t) - 1; + } + t += cb / sizeof(wchar_t); + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +csv_to_multi_string(wchar_t * ms, + khm_size * pcb_ms, + const wchar_t * csv) +{ + const wchar_t * t; + wchar_t * p; + size_t cchr; + int field = 1; + + + if(!pcb_ms || !csv) + return KHM_ERROR_INVALID_PARAM; + + cchr = 0; + + /* dry run */ + t = csv; + while(*t && (t - csv) < KHM_MAXCCH_STRING) { + if(field && *t == L'"') { + t++; + while(*t && (t - csv) < KHM_MAXCCH_STRING) { + if(*t == L'"') { + t++; + if(*t != L'"') + break; + } + cchr++; + t++; + } + } + + if(*t) { + cchr++; + if(*t == L',') + field = 1; + else + field = 0; + + t++; + } + } + + if((t - csv) >= KHM_MAXCCH_STRING) + return KHM_ERROR_INVALID_PARAM; + + cchr++; /* last string ends */ + cchr++; /* double NULL */ + + if(!ms || *pcb_ms < (cchr * sizeof(wchar_t))) { + *pcb_ms = cchr * sizeof(wchar_t); + return KHM_ERROR_TOO_LONG; + } + + /* wet run */ + t = csv; + p = ms; + field = 1; + while(*t) { + if(field && *t == L'"') { + t++; + while(*t) { + if(*t == L'"') { + t++; + if(*t != L'"') + break; + } + *p++ = *t; + t++; + } + } + + if(*t == L',') { + *p++ = 0; + field = 1; + t++; + } else if(*t) { + *p++ = *t; + field = 0; + t++; + } + } + + *p++ = 0; /* last string ends */ + *p++ = 0; /* double NULL */ + + *pcb_ms = (p - ms) * sizeof(wchar_t); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP wchar_t * KHMAPI +multi_string_next(const wchar_t * str) +{ + size_t cch; + + if(*str) { + if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch))) + return NULL; + str += cch + 1; + if(*str) + return (wchar_t *) str; + else + return NULL; + } else { + return NULL; + } +} + +KHMEXP khm_size KHMAPI +multi_string_length_n(const wchar_t * str) +{ + size_t n = 0; + const wchar_t * c = str; + + while(c) { + n++; + c = multi_string_next(c); + } + + return n; +} + +KHMEXP khm_int32 KHMAPI +multi_string_length_cb(const wchar_t * str, + khm_size max_cb, + khm_size * len_cb) +{ + khm_size cch; + khm_int32 rv; + + rv = multi_string_length_cch(str, max_cb / sizeof(wchar_t), &cch); + + if(KHM_FAILED(rv)) + return rv; + + if(len_cb) + *len_cb = cch * sizeof(wchar_t); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +multi_string_length_cch(const wchar_t * str, + khm_size max_cch, + khm_size * len_cch) +{ + const wchar_t * s; + khm_size cch; + size_t tcch; + + if(!str) + return KHM_ERROR_INVALID_PARAM; + + s = str; + cch = 0; + while(*s && (cch < max_cch)) { + if(FAILED(StringCchLength(s, max_cch, &tcch))) + return KHM_ERROR_TOO_LONG; + cch += ++tcch; + s += tcch; + } + + if(cch >= max_cch) + return KHM_ERROR_TOO_LONG; + + if(len_cch) { + *len_cch = ++cch; + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +multi_string_copy_cb(wchar_t * s_dest, + khm_size max_cb_dest, + const wchar_t * src) +{ + khm_size cb_dest; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!s_dest) + return KHM_ERROR_INVALID_PARAM; + + rv = multi_string_length_cb(src, max_cb_dest, &cb_dest); + if(KHM_FAILED(rv)) + return rv; + + memmove(s_dest, src, cb_dest); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +multi_string_copy_cch(wchar_t * s_dest, + khm_size max_cch_dest, + const wchar_t * src) +{ + khm_size cch_dest; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!s_dest) + return KHM_ERROR_INVALID_PARAM; + + rv = multi_string_length_cch(src, max_cch_dest, &cch_dest); + if(KHM_FAILED(rv)) + return rv; + + memmove(s_dest, src, cch_dest * sizeof(wchar_t)); + + return rv; +} diff --git a/src/windows/identity/util/mstring.h b/src/windows/identity/util/mstring.h index a7f6cf523..497cb777d 100644 --- a/src/windows/identity/util/mstring.h +++ b/src/windows/identity/util/mstring.h @@ -1,361 +1,361 @@ -/* - * 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_MSTRING_H -#define __KHIMAIRA_MSTRING_H - -#include - -/*! \addtogroup util - @{ */ - -/*! \defgroup util_mstring Multi String and CSV functions - @{*/ - -#define KHM_PREFIX 8 - -#define KHM_CASE_SENSITIVE 16 - -#define KHM_MAXCCH_STRING 16384 - -#define KHM_MAXCB_STRING (KHM_MAXCCH_STRING * sizeof(wchar_t)) - -/*! \brief Initialize a multi-string - */ -KHMEXP khm_int32 KHMAPI -multi_string_init(wchar_t * ms, - khm_size cb_ms); - -/*! \brief Prepend a string to a multi string - - Adds the string \a str to the beginning of multi-string \a ms. - - \param[in,out] ms The multi-string to be modified. - - \param[in,out] pcb_ms A pointer to the size of the multistring. - On entry this specifies the size of the buffer pointed to by - \a ms. If the call is successful, on exit this will receive - the new size of the multi string in bytes. If the buffer is - insufficient, the function will return KHM_ERROR_TOO_LONG and - set this to the required size of the buffer in bytes. - - \param[in] str The string to prepend to \a ms. This cannot be - longer than KHM_MAXCCH_STRING in characters including the - terminating NULL. - */ -KHMEXP khm_int32 KHMAPI -multi_string_prepend(wchar_t * ms, - khm_size * pcb_ms, - const wchar_t * str); - -/*! \brief Append a string to a multi-string - - Appends the string specified by \a str to the multi string - specified by \a ms. The size of the multi string in characters - including terminating NULLs after appending \a str can not exceed - KHM_MAXCCH_STRING. - - \param[in] ms The buffer containing the multi string - - \param[in,out] pcb_ms Points to a khm_int32 indicating the size of - the buffer pointed to by \a ms. On entry this contains the - size (in bytes) of the buffer pointed to by \a ms. On exit, - contains the new size of the multi string in bytes. - - \param[in] str The string to append to the multi string. This - string cannot be NULL or an empty (zero length) string. The - length of \a str cannot exceed KHM_MAXCCH_STRING in - characters including terminating NULL. - - \retval KHM_ERROR_SUCCESS The string was appended to the multi string - - \retval KHM_ERROR_TOO_LONG The buffer pointed to by \a ms was - insufficient. The required size of the buffer is in \a pcb_ms - - \retval KHM_ERROR_INVALID_PARAM One of more of the parameters were invalid. - */ -KHMEXP khm_int32 KHMAPI -multi_string_append(wchar_t * ms, - khm_size * pcb_ms, - const wchar_t * str); - -/*! \brief Deletes a string from a multi string - - Deletes the string specified by \a str from the multi string - specified by \a ms. How the string is matched to the strings in - \a ms is determined by \a flags. If more than one match is found, - then only the first match is deleted. - - \param[in] ms The multi string to modify. The length of the multi - string in characters cannot exceed KHM_MAXCCH_STRING. - - \param[in] str The string to search for - - \param[in] flags How \a str is to be matched to existing strings - in \a ms. This could be a combination of KHM_PREFIX and - KHM_CASE_SENSITIVE. If KHM_PREFIX is used, then \a ms is - searched for a string that begins with \a str. Otherwise, \a - str must match the an entire string in the multi string. If - KHM_CASE_SENSITIVE is specified, then a case sensitive match - is performed. The defualt is to use a case insensitive - search. - - \retval KHM_ERROR_SUCCESS A string was matched and deleted from \a ms - - \retval KHM_ERROR_NOT_FOUND No matches were found - - \retval KHM_ERROR_INVALID_PARAM One or more parameters were incorrect. - - \note The search for the existing string is done with - multi_string_find() - */ -KHMEXP khm_int32 KHMAPI -multi_string_delete(wchar_t * ms, - const wchar_t * str, - const khm_int32 flags); - -/*! \brief Search a multi string for a string - - Searches the string specified by \a ms for a string that matches - \a str. How the match is performed is determined by \a flags. - Returns a poitner to the start of the matched string in \a ms. If - more than one string in \a ms matches \a str, then only the first - match is returned. - - \param[in] ms The multi string to search in. The length of the - multi string cannot exceed KHM_MAXCCH_STRING in characters. - - \param[in] str The string to search for - - \param[in] flags How \a str is to be matched to existing strings - in \a ms. This could be a combination of KHM_PREFIX and - KHM_CASE_SENSITIVE. If KHM_PREFIX is used, then \a ms is - searched for a string that begins with \a str. Otherwise, \a - str must match the an entire string in the multi string. If - KHM_CASE_SENSITIVE is specified, then a case sensitive match - is performed. The defualt is to use a case insensitive - search. - - \return A pointer to the start of the first matched string or - NULL if no matches were found. - - */ -KHMEXP wchar_t * KHMAPI -multi_string_find(const wchar_t * ms, - const wchar_t * str, - const khm_int32 flags); - -/*! \brief Convert a multi string to CSV - - Converts a multi string to a comma separated value string based on - the following rules. - - - Each string in the multi string is treated an individual field - - - A field is quoted if it has double quotes or commas - - - Double quotes within quoted fields are escaped by two - consecutive double quotes. - - For example: - - \code - multi_string = L"foo\0bar\0baz,quux\0ab\"cd\0"; - csv_string = L"foo,bar,\"baz,quux\",\"ab\"\"cd\""; - \endcode - - If multi_string_to_csv() is called on \a multi_string above, - you would obtain \a csv_string. - - \param[out] csvbuf The buffer to place the CSV string in. Can be - NULL if only teh size of the needed buffer is required. - - \param[in,out] pcb_csvbuf On entry, points to a khm_int32 that - holds the size of the buffer pointed to by \a csvbuf. On - exit, gets the number of bytes writted to \a csvbuf or the - required size of \a csvbuf if the buffer is too small or \a - csvbuf is NULL. - - \param[in] ms The mutli string to convert to a CSV. - - \retval KHM_ERROR_SUCCESS The multi string was successfully - converted to a CSV string. The number of bytes written is in - \a pcb_csvbuf. The count includes the terminating NULL. - - \retval KHM_ERROR_TOO_LONG The buffer was too small or \a csvbuf - was NULL. The required number of bytes in the buffer is in \a - pcb_csvbuf. - - \retval KHM_ERROR_INVALID_PARAM One or more parameters were ivnalid. - - \see csv_to_multi_string() -*/ -KHMEXP khm_int32 KHMAPI -multi_string_to_csv(wchar_t * csvbuf, - khm_size * pcb_csvbuf, - const wchar_t * ms); - -/*! \brief Converts a CSV to a multi string - - Undoes what multi_string_to_csv() does. - - \param[out] ms The buffer that recieves the multi string. This - can be NULL if only the size of the buffer is requried. - - \param[in,out] pcb_ms On entry contains the number of bytes ni the - buffer poitned to by \a ms. On exit contains the number of - bytes that were copied to \a ms including terminating NULLs, - or if the buffer was too small or \a ms was NULL, holds the - size in bytes of the requied buffer. - - \param[in] csv The CSV string. - - \retval KHM_ERROR_SUCCESS The CSV string was successfully - converted. The number of bytes written is in \a pcb_ms. - - \retval KHM_ERROR_TOO_LONG The provided buffer was too small or \a - ms was NULL. The required size of the buffer in bytes is in \a - pcb_ms. - - \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid. - - */ -KHMEXP khm_int32 KHMAPI -csv_to_multi_string(wchar_t * ms, - khm_size * pcb_ms, - const wchar_t * csv); - -/*! \brief Get the next string in a multi string - - When \a str is pointing to a string that is in a multi string, - this function returns a pointer to the next string in the multi - string. - - Typically, one would start by having \a str point to the start of - the multi string (which is the first string in the multi string), - and then call this function repeatedly, until it returns NULL, at - which point the end of the multi string has been reached. - - \param[in] str Pointer to a string in a multi string. Each string - in a multi string cannot exceed KHM_MAXCCH_STRING in charaters - including the terminating NULL. - - \return A pointer to the start of the next string in the multi - string or NULL if there is no more strings. - */ -KHMEXP wchar_t * KHMAPI -multi_string_next(const wchar_t * str); - -/*! \brief Get the length of a multi string in bytes - - The returned length includes the trailing double \a NULL and any - other \a NULL inbetween. - - \param[in] str Pointer to a multi string. - \param[in] max_cb Maximum size that the str can be. This can not - be larger than KHM_MAXCB_STRING. - \param[out] len_cb The length of the string in bytes if the call - is successful. - - \retval KHM_ERROR_SUCCESS The length of the string is in \a len_cb - \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid - \retval KHM_ERROR_TOO_LONG The multi string is longer than \a - max_cb bytes. - */ -KHMEXP khm_int32 KHMAPI -multi_string_length_cb(const wchar_t * str, - khm_size max_cb, - khm_size * len_cb); - -/*! \brief Get the length of a multi string in characters - - The returned length includes the trailing double \a NULL and any - other \a NULL inbetween. - - \param[in] str Pointer to a multi string. - \param[in] max_cch Maximum size that the str can be. This can not - be larger than KHM_MAXCCH_STRING. - \param[out] len_cch The length of the string in characters if the call - is successful. - - \retval KHM_ERROR_SUCCESS The length of the string is in \a len_cch - \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid - \retval KHM_ERROR_TOO_LONG The multi string is longer than \a - max_cch characters. - */ -KHMEXP khm_int32 KHMAPI -multi_string_length_cch(const wchar_t * str, - khm_size max_cch, - khm_size * len_cch); - -/*! \brief Get the number of strings in a multi string - */ -KHMEXP khm_size KHMAPI -multi_string_length_n(const wchar_t * str); - -/*! \brief Copy a multi string with byte counts - - Copy a multi string from one location to another. - - \param[out] s_dest Receives a copy of the multi string - \param[in] max_cb_dest Number of bytes in the buffer pointed to by - \a s_dest. - \param[in] src The source multi string - - \retval KHM_ERROR_SUCCESS The multi string was copied successfully - \retval KHM_ERROR_INVALID_PARAM One or more parameters were - invalid. - \retval KHM_ERROR_TOO_LONG The size of the destination buffer was - insufficient. - */ -KHMEXP khm_int32 KHMAPI -multi_string_copy_cb(wchar_t * s_dest, - khm_size max_cb_dest, - const wchar_t * src); - -/*! \brief Copy a multi string with character count - - Copy a multi string from one location to another. - - \param[out] s_dest Receives a copy of the multi string - \param[in] max_cb_dest Number of characters in the buffer pointed - to by \a s_dest. - \param[in] src The source multi string - - \retval KHM_ERROR_SUCCESS The multi string was copied successfully - \retval KHM_ERROR_INVALID_PARAM One or more parameters were - invalid. - \retval KHM_ERROR_TOO_LONG The size of the destination buffer was - insufficient. - */ -KHMEXP khm_int32 KHMAPI -multi_string_copy_cch(wchar_t * s_dest, - khm_size max_cch_dest, - const wchar_t * src); - -/*@}*/ - -#endif +/* + * 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_MSTRING_H +#define __KHIMAIRA_MSTRING_H + +#include + +/*! \addtogroup util + @{ */ + +/*! \defgroup util_mstring Multi String and CSV functions + @{*/ + +#define KHM_PREFIX 8 + +#define KHM_CASE_SENSITIVE 16 + +#define KHM_MAXCCH_STRING 16384 + +#define KHM_MAXCB_STRING (KHM_MAXCCH_STRING * sizeof(wchar_t)) + +/*! \brief Initialize a multi-string + */ +KHMEXP khm_int32 KHMAPI +multi_string_init(wchar_t * ms, + khm_size cb_ms); + +/*! \brief Prepend a string to a multi string + + Adds the string \a str to the beginning of multi-string \a ms. + + \param[in,out] ms The multi-string to be modified. + + \param[in,out] pcb_ms A pointer to the size of the multistring. + On entry this specifies the size of the buffer pointed to by + \a ms. If the call is successful, on exit this will receive + the new size of the multi string in bytes. If the buffer is + insufficient, the function will return KHM_ERROR_TOO_LONG and + set this to the required size of the buffer in bytes. + + \param[in] str The string to prepend to \a ms. This cannot be + longer than KHM_MAXCCH_STRING in characters including the + terminating NULL. + */ +KHMEXP khm_int32 KHMAPI +multi_string_prepend(wchar_t * ms, + khm_size * pcb_ms, + const wchar_t * str); + +/*! \brief Append a string to a multi-string + + Appends the string specified by \a str to the multi string + specified by \a ms. The size of the multi string in characters + including terminating NULLs after appending \a str can not exceed + KHM_MAXCCH_STRING. + + \param[in] ms The buffer containing the multi string + + \param[in,out] pcb_ms Points to a khm_int32 indicating the size of + the buffer pointed to by \a ms. On entry this contains the + size (in bytes) of the buffer pointed to by \a ms. On exit, + contains the new size of the multi string in bytes. + + \param[in] str The string to append to the multi string. This + string cannot be NULL or an empty (zero length) string. The + length of \a str cannot exceed KHM_MAXCCH_STRING in + characters including terminating NULL. + + \retval KHM_ERROR_SUCCESS The string was appended to the multi string + + \retval KHM_ERROR_TOO_LONG The buffer pointed to by \a ms was + insufficient. The required size of the buffer is in \a pcb_ms + + \retval KHM_ERROR_INVALID_PARAM One of more of the parameters were invalid. + */ +KHMEXP khm_int32 KHMAPI +multi_string_append(wchar_t * ms, + khm_size * pcb_ms, + const wchar_t * str); + +/*! \brief Deletes a string from a multi string + + Deletes the string specified by \a str from the multi string + specified by \a ms. How the string is matched to the strings in + \a ms is determined by \a flags. If more than one match is found, + then only the first match is deleted. + + \param[in] ms The multi string to modify. The length of the multi + string in characters cannot exceed KHM_MAXCCH_STRING. + + \param[in] str The string to search for + + \param[in] flags How \a str is to be matched to existing strings + in \a ms. This could be a combination of KHM_PREFIX and + KHM_CASE_SENSITIVE. If KHM_PREFIX is used, then \a ms is + searched for a string that begins with \a str. Otherwise, \a + str must match the an entire string in the multi string. If + KHM_CASE_SENSITIVE is specified, then a case sensitive match + is performed. The defualt is to use a case insensitive + search. + + \retval KHM_ERROR_SUCCESS A string was matched and deleted from \a ms + + \retval KHM_ERROR_NOT_FOUND No matches were found + + \retval KHM_ERROR_INVALID_PARAM One or more parameters were incorrect. + + \note The search for the existing string is done with + multi_string_find() + */ +KHMEXP khm_int32 KHMAPI +multi_string_delete(wchar_t * ms, + const wchar_t * str, + const khm_int32 flags); + +/*! \brief Search a multi string for a string + + Searches the string specified by \a ms for a string that matches + \a str. How the match is performed is determined by \a flags. + Returns a poitner to the start of the matched string in \a ms. If + more than one string in \a ms matches \a str, then only the first + match is returned. + + \param[in] ms The multi string to search in. The length of the + multi string cannot exceed KHM_MAXCCH_STRING in characters. + + \param[in] str The string to search for + + \param[in] flags How \a str is to be matched to existing strings + in \a ms. This could be a combination of KHM_PREFIX and + KHM_CASE_SENSITIVE. If KHM_PREFIX is used, then \a ms is + searched for a string that begins with \a str. Otherwise, \a + str must match the an entire string in the multi string. If + KHM_CASE_SENSITIVE is specified, then a case sensitive match + is performed. The defualt is to use a case insensitive + search. + + \return A pointer to the start of the first matched string or + NULL if no matches were found. + + */ +KHMEXP wchar_t * KHMAPI +multi_string_find(const wchar_t * ms, + const wchar_t * str, + const khm_int32 flags); + +/*! \brief Convert a multi string to CSV + + Converts a multi string to a comma separated value string based on + the following rules. + + - Each string in the multi string is treated an individual field + + - A field is quoted if it has double quotes or commas + + - Double quotes within quoted fields are escaped by two + consecutive double quotes. + + For example: + + \code + multi_string = L"foo\0bar\0baz,quux\0ab\"cd\0"; + csv_string = L"foo,bar,\"baz,quux\",\"ab\"\"cd\""; + \endcode + + If multi_string_to_csv() is called on \a multi_string above, + you would obtain \a csv_string. + + \param[out] csvbuf The buffer to place the CSV string in. Can be + NULL if only teh size of the needed buffer is required. + + \param[in,out] pcb_csvbuf On entry, points to a khm_int32 that + holds the size of the buffer pointed to by \a csvbuf. On + exit, gets the number of bytes writted to \a csvbuf or the + required size of \a csvbuf if the buffer is too small or \a + csvbuf is NULL. + + \param[in] ms The mutli string to convert to a CSV. + + \retval KHM_ERROR_SUCCESS The multi string was successfully + converted to a CSV string. The number of bytes written is in + \a pcb_csvbuf. The count includes the terminating NULL. + + \retval KHM_ERROR_TOO_LONG The buffer was too small or \a csvbuf + was NULL. The required number of bytes in the buffer is in \a + pcb_csvbuf. + + \retval KHM_ERROR_INVALID_PARAM One or more parameters were ivnalid. + + \see csv_to_multi_string() +*/ +KHMEXP khm_int32 KHMAPI +multi_string_to_csv(wchar_t * csvbuf, + khm_size * pcb_csvbuf, + const wchar_t * ms); + +/*! \brief Converts a CSV to a multi string + + Undoes what multi_string_to_csv() does. + + \param[out] ms The buffer that recieves the multi string. This + can be NULL if only the size of the buffer is requried. + + \param[in,out] pcb_ms On entry contains the number of bytes ni the + buffer poitned to by \a ms. On exit contains the number of + bytes that were copied to \a ms including terminating NULLs, + or if the buffer was too small or \a ms was NULL, holds the + size in bytes of the requied buffer. + + \param[in] csv The CSV string. + + \retval KHM_ERROR_SUCCESS The CSV string was successfully + converted. The number of bytes written is in \a pcb_ms. + + \retval KHM_ERROR_TOO_LONG The provided buffer was too small or \a + ms was NULL. The required size of the buffer in bytes is in \a + pcb_ms. + + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid. + + */ +KHMEXP khm_int32 KHMAPI +csv_to_multi_string(wchar_t * ms, + khm_size * pcb_ms, + const wchar_t * csv); + +/*! \brief Get the next string in a multi string + + When \a str is pointing to a string that is in a multi string, + this function returns a pointer to the next string in the multi + string. + + Typically, one would start by having \a str point to the start of + the multi string (which is the first string in the multi string), + and then call this function repeatedly, until it returns NULL, at + which point the end of the multi string has been reached. + + \param[in] str Pointer to a string in a multi string. Each string + in a multi string cannot exceed KHM_MAXCCH_STRING in charaters + including the terminating NULL. + + \return A pointer to the start of the next string in the multi + string or NULL if there is no more strings. + */ +KHMEXP wchar_t * KHMAPI +multi_string_next(const wchar_t * str); + +/*! \brief Get the length of a multi string in bytes + + The returned length includes the trailing double \a NULL and any + other \a NULL inbetween. + + \param[in] str Pointer to a multi string. + \param[in] max_cb Maximum size that the str can be. This can not + be larger than KHM_MAXCB_STRING. + \param[out] len_cb The length of the string in bytes if the call + is successful. + + \retval KHM_ERROR_SUCCESS The length of the string is in \a len_cb + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + \retval KHM_ERROR_TOO_LONG The multi string is longer than \a + max_cb bytes. + */ +KHMEXP khm_int32 KHMAPI +multi_string_length_cb(const wchar_t * str, + khm_size max_cb, + khm_size * len_cb); + +/*! \brief Get the length of a multi string in characters + + The returned length includes the trailing double \a NULL and any + other \a NULL inbetween. + + \param[in] str Pointer to a multi string. + \param[in] max_cch Maximum size that the str can be. This can not + be larger than KHM_MAXCCH_STRING. + \param[out] len_cch The length of the string in characters if the call + is successful. + + \retval KHM_ERROR_SUCCESS The length of the string is in \a len_cch + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + \retval KHM_ERROR_TOO_LONG The multi string is longer than \a + max_cch characters. + */ +KHMEXP khm_int32 KHMAPI +multi_string_length_cch(const wchar_t * str, + khm_size max_cch, + khm_size * len_cch); + +/*! \brief Get the number of strings in a multi string + */ +KHMEXP khm_size KHMAPI +multi_string_length_n(const wchar_t * str); + +/*! \brief Copy a multi string with byte counts + + Copy a multi string from one location to another. + + \param[out] s_dest Receives a copy of the multi string + \param[in] max_cb_dest Number of bytes in the buffer pointed to by + \a s_dest. + \param[in] src The source multi string + + \retval KHM_ERROR_SUCCESS The multi string was copied successfully + \retval KHM_ERROR_INVALID_PARAM One or more parameters were + invalid. + \retval KHM_ERROR_TOO_LONG The size of the destination buffer was + insufficient. + */ +KHMEXP khm_int32 KHMAPI +multi_string_copy_cb(wchar_t * s_dest, + khm_size max_cb_dest, + const wchar_t * src); + +/*! \brief Copy a multi string with character count + + Copy a multi string from one location to another. + + \param[out] s_dest Receives a copy of the multi string + \param[in] max_cb_dest Number of characters in the buffer pointed + to by \a s_dest. + \param[in] src The source multi string + + \retval KHM_ERROR_SUCCESS The multi string was copied successfully + \retval KHM_ERROR_INVALID_PARAM One or more parameters were + invalid. + \retval KHM_ERROR_TOO_LONG The size of the destination buffer was + insufficient. + */ +KHMEXP khm_int32 KHMAPI +multi_string_copy_cch(wchar_t * s_dest, + khm_size max_cch_dest, + const wchar_t * src); + +/*@}*/ + +#endif diff --git a/src/windows/identity/util/perfstat.c b/src/windows/identity/util/perfstat.c index cc27d93bd..6a9dd8103 100644 --- a/src/windows/identity/util/perfstat.c +++ b/src/windows/identity/util/perfstat.c @@ -1,411 +1,411 @@ -/* - * 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 -#include - -#define HASHSIZE 1151 -#define ALLOCBLOCK 1024 - -#define HASHPTR(p) (((size_t) (p)) % HASHSIZE) - -typedef struct tag_allocation { - const char * file; - int line; - size_t size; - void * ptr; -#ifdef _WIN32 - DWORD thread; -#endif - - LDCL(struct tag_allocation); -} allocation; - -static allocation * ht[HASHSIZE]; - -static allocation * next_alloc = NULL; -static size_t idx_next_alloc = 0; -static allocation * free_alloc = NULL; - -typedef struct tag_thread_info { -#ifdef _WIN32 - DWORD thread; -#else -#error Unsupported platform -#endif - wchar_t name[128]; - wchar_t creator[128]; - - const char * file; - int line; - - LDCL(struct tag_thread_info); -} thread_info; - -static thread_info * threads = NULL; - -static hashtable fn_hash; - -static CRITICAL_SECTION cs_alloc; -static LONG ctr = 0; -static int perf_ready = 0; - -static DWORD init_thread = 0; - -static khm_int32 hash_stringA(const void * vs) { - /* DJB algorithm */ - - khm_int32 hv = 13331; - char * c; - - for (c = (char *) vs; *c; c++) { - hv = ((hv << 5) + hv) + (khm_int32) *c; - } - - return (hv & KHM_INT32_MAX); -} - -static khm_int32 hash_string_compA(const void * vs1, - const void * vs2) { - return strcmp((const char *) vs1, (const char *) vs2); -} - -static void perf_once(void) { - if (InterlockedIncrement(&ctr) == 1) { - InitializeCriticalSection(&cs_alloc); - ZeroMemory(ht, sizeof(ht)); - - next_alloc = malloc(sizeof(allocation) * ALLOCBLOCK); - assert(next_alloc); - idx_next_alloc = 0; - free_alloc = NULL; - - ZeroMemory(&fn_hash, sizeof(fn_hash)); - fn_hash.n = 13; - fn_hash.hash = hash_stringA; - fn_hash.comp = hash_string_compA; - fn_hash.bins = calloc(sizeof(hash_bin *), fn_hash.n); - - perf_ready = 1; - } else { - DWORD this_thread = GetCurrentThreadId(); - - while(!perf_ready && - init_thread != this_thread) { - Sleep(0); /* relinquish control to the thread - that is initializing the alloc - data. */ - } - } -} - -static allocation * get_allocation(void) { - allocation * a; - - LPOP(&free_alloc, &a); - if (!a) { - if (idx_next_alloc == ALLOCBLOCK) { - next_alloc = malloc(sizeof(allocation) * ALLOCBLOCK); - assert(next_alloc); - idx_next_alloc = 0; - } - - a = &next_alloc[idx_next_alloc]; - idx_next_alloc++; - } - - return a; -} - -#define MAXCB_STR 32768 - -KHMEXP wchar_t * -perf_wcsdup(const char * file, int line, const wchar_t * str) { - size_t cb; - wchar_t * dest; - - if (FAILED(StringCbLength(str, MAXCB_STR, &cb))) - return NULL; - cb += sizeof(wchar_t); - - dest = (wchar_t *) perf_malloc(file, line, cb); - StringCbCopy(dest, cb, str); - - return dest; -} - -KHMEXP char * -perf_strdup(const char * file, int line, const char * str) { - size_t cb; - char * dest; - - if (FAILED(StringCbLengthA(str, MAXCB_STR, &cb))) - return NULL; - cb += sizeof(char); - - dest = (char *) perf_malloc(file, line, cb); - StringCbCopyA(dest, cb, str); - - return dest; -} - -KHMEXP void * -perf_calloc(const char * file, int line, size_t num, size_t size) { - void * ptr; - size_t tsize; - - tsize = num * size; - - ptr = perf_malloc(file,line,tsize); - - if (ptr) { - ZeroMemory(ptr, tsize); - } - - return ptr; -} - -KHMEXP void * -perf_malloc(const char * file, int line, size_t s) { - allocation * a; - void * ptr; - size_t h; - char * fn_copy = NULL; - - perf_once(); - - assert(s > 0); - - EnterCriticalSection(&cs_alloc); - a = get_allocation(); - - ptr = malloc(s); - - assert(ptr); /* TODO: handle this gracefully */ - - if (file[0] == '.' && file[1] == '\\') - file += 2; - - fn_copy = hash_lookup(&fn_hash, file); - if (fn_copy == NULL) { - - size_t cblen = 0; - if (FAILED(StringCbLengthA(file, MAX_PATH * sizeof(char), - &cblen))) - fn_copy = NULL; - else { - fn_copy = malloc(cblen + sizeof(char)); - if (fn_copy) { - hash_bin * b; - int hv; - - StringCbCopyA(fn_copy, cblen + sizeof(char), file); - - hv = fn_hash.hash(fn_copy) % fn_hash.n; - - b = malloc(sizeof(*b)); - b->data = fn_copy; - b->key = fn_copy; - LINIT(b); - LPUSH(&fn_hash.bins[hv], b); - } - } - } - - a->file = fn_copy; - a->line = line; - a->size = s; - a->ptr = ptr; -#ifdef _WIN32 - a->thread = GetCurrentThreadId(); -#endif - - h = HASHPTR(ptr); - - LPUSH(&ht[h], a); - LeaveCriticalSection(&cs_alloc); - - return ptr; -} - -KHMEXP void * -perf_realloc(const char * file, int line, void * data, size_t s) { - void * n_data; - allocation * a; - size_t h; - - if (data == NULL) - return perf_malloc(file, line, s); - - perf_once(); - h = HASHPTR(data); - - n_data = realloc(data, s); - - assert(n_data); - - EnterCriticalSection(&cs_alloc); - for (a = ht[h]; a; a = LNEXT(a)) { - if (a->ptr == data) - break; - } - - assert(a); - - LDELETE(&ht[h], a); - - a->size = s; - a->ptr = n_data; - - h = HASHPTR(n_data); - LPUSH(&ht[h], a); - LeaveCriticalSection(&cs_alloc); - - return n_data; -} - -KHMEXP void -perf_free (void * b) { - size_t h; - allocation * a; - - perf_once(); - h = HASHPTR(b); - - EnterCriticalSection(&cs_alloc); - for(a = ht[h]; a; a = LNEXT(a)) { - if (a->ptr == b) - break; - } - - assert(a); - - LDELETE(&ht[h], a); - LPUSH(&free_alloc, a); - LeaveCriticalSection(&cs_alloc); -} - -KHMEXP void KHMAPI -perf_dump(FILE * f) { - size_t i; - allocation * a; - size_t total = 0; - thread_info * t; - - perf_once(); - - EnterCriticalSection(&cs_alloc); - - fprintf(f, "p00\t*** Threads ***\n"); - fprintf(f, "p00\tFile\tLine\tThread\tName\tCreated by\n"); - - for (t = threads; t; t = LNEXT(t)) { - fprintf(f, "p01\t%s\t%6d\t%6d\t%S\t%S\n", - t->file, t->line, t->thread, - t->name, t->creator); - } - - fprintf(f, "p02\t--- End Threads ---\n"); - - fprintf(f, "p10\t*** Leaked allocations list ***\n"); - fprintf(f, "p11\tFile\tLine\tThread\tSize\tAddress\n"); - - for (i=0; i < HASHSIZE; i++) { - for (a = ht[i]; a; a = LNEXT(a)) { - fprintf(f, "p12\t%s\t%6d\t%6d\t%6d\t0x%p\n", a->file, a->line, - a->thread, a->size, a->ptr); - total += a->size; - } - } - - fprintf(f, "p20\t----------------------------------------\n"); - fprintf(f, "p21\tTotal\t\t%d\n", total); - fprintf(f, "p22\t----------------- End ------------------\n"); - - LeaveCriticalSection(&cs_alloc); -} - -KHMEXP void -perf_set_thread_desc(const char * file, int line, - const wchar_t * name, const wchar_t * creator) { - thread_info * t; - char * fn_copy; - - perf_once(); - - t = malloc(sizeof(*t)); - ZeroMemory(t, sizeof(*t)); - -#ifdef _WIN32 - t->thread = GetCurrentThreadId(); -#else -#error Unsupported platform -#endif - - StringCbCopy(t->name, sizeof(t->name), name); - if (creator) - StringCbCopy(t->creator, sizeof(t->creator), creator); - - if (file[0] == '.' && file[1] == '\\') - file += 2; - - EnterCriticalSection(&cs_alloc); - - fn_copy = hash_lookup(&fn_hash, file); - if (fn_copy == NULL) { - size_t cblen = 0; - if (FAILED(StringCbLengthA(file, MAX_PATH * sizeof(char), - &cblen))) - fn_copy = NULL; - else { - fn_copy = malloc(cblen + sizeof(char)); - if (fn_copy) { - hash_bin * b; - int hv; - - StringCbCopyA(fn_copy, cblen + sizeof(char), file); - - hv = fn_hash.hash(fn_copy) % fn_hash.n; - - b = malloc(sizeof(*b)); - b->data = fn_copy; - b->key = fn_copy; - LINIT(b); - LPUSH(&fn_hash.bins[hv], b); - } - } - } - - t->file = fn_copy; - t->line = line; - - LPUSH(&threads, t); - LeaveCriticalSection(&cs_alloc); -} +/* + * 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 +#include + +#define HASHSIZE 1151 +#define ALLOCBLOCK 1024 + +#define HASHPTR(p) (((size_t) (p)) % HASHSIZE) + +typedef struct tag_allocation { + const char * file; + int line; + size_t size; + void * ptr; +#ifdef _WIN32 + DWORD thread; +#endif + + LDCL(struct tag_allocation); +} allocation; + +static allocation * ht[HASHSIZE]; + +static allocation * next_alloc = NULL; +static size_t idx_next_alloc = 0; +static allocation * free_alloc = NULL; + +typedef struct tag_thread_info { +#ifdef _WIN32 + DWORD thread; +#else +#error Unsupported platform +#endif + wchar_t name[128]; + wchar_t creator[128]; + + const char * file; + int line; + + LDCL(struct tag_thread_info); +} thread_info; + +static thread_info * threads = NULL; + +static hashtable fn_hash; + +static CRITICAL_SECTION cs_alloc; +static LONG ctr = 0; +static int perf_ready = 0; + +static DWORD init_thread = 0; + +static khm_int32 hash_stringA(const void * vs) { + /* DJB algorithm */ + + khm_int32 hv = 13331; + char * c; + + for (c = (char *) vs; *c; c++) { + hv = ((hv << 5) + hv) + (khm_int32) *c; + } + + return (hv & KHM_INT32_MAX); +} + +static khm_int32 hash_string_compA(const void * vs1, + const void * vs2) { + return strcmp((const char *) vs1, (const char *) vs2); +} + +static void perf_once(void) { + if (InterlockedIncrement(&ctr) == 1) { + InitializeCriticalSection(&cs_alloc); + ZeroMemory(ht, sizeof(ht)); + + next_alloc = malloc(sizeof(allocation) * ALLOCBLOCK); + assert(next_alloc); + idx_next_alloc = 0; + free_alloc = NULL; + + ZeroMemory(&fn_hash, sizeof(fn_hash)); + fn_hash.n = 13; + fn_hash.hash = hash_stringA; + fn_hash.comp = hash_string_compA; + fn_hash.bins = calloc(sizeof(hash_bin *), fn_hash.n); + + perf_ready = 1; + } else { + DWORD this_thread = GetCurrentThreadId(); + + while(!perf_ready && + init_thread != this_thread) { + Sleep(0); /* relinquish control to the thread + that is initializing the alloc + data. */ + } + } +} + +static allocation * get_allocation(void) { + allocation * a; + + LPOP(&free_alloc, &a); + if (!a) { + if (idx_next_alloc == ALLOCBLOCK) { + next_alloc = malloc(sizeof(allocation) * ALLOCBLOCK); + assert(next_alloc); + idx_next_alloc = 0; + } + + a = &next_alloc[idx_next_alloc]; + idx_next_alloc++; + } + + return a; +} + +#define MAXCB_STR 32768 + +KHMEXP wchar_t * +perf_wcsdup(const char * file, int line, const wchar_t * str) { + size_t cb; + wchar_t * dest; + + if (FAILED(StringCbLength(str, MAXCB_STR, &cb))) + return NULL; + cb += sizeof(wchar_t); + + dest = (wchar_t *) perf_malloc(file, line, cb); + StringCbCopy(dest, cb, str); + + return dest; +} + +KHMEXP char * +perf_strdup(const char * file, int line, const char * str) { + size_t cb; + char * dest; + + if (FAILED(StringCbLengthA(str, MAXCB_STR, &cb))) + return NULL; + cb += sizeof(char); + + dest = (char *) perf_malloc(file, line, cb); + StringCbCopyA(dest, cb, str); + + return dest; +} + +KHMEXP void * +perf_calloc(const char * file, int line, size_t num, size_t size) { + void * ptr; + size_t tsize; + + tsize = num * size; + + ptr = perf_malloc(file,line,tsize); + + if (ptr) { + ZeroMemory(ptr, tsize); + } + + return ptr; +} + +KHMEXP void * +perf_malloc(const char * file, int line, size_t s) { + allocation * a; + void * ptr; + size_t h; + char * fn_copy = NULL; + + perf_once(); + + assert(s > 0); + + EnterCriticalSection(&cs_alloc); + a = get_allocation(); + + ptr = malloc(s); + + assert(ptr); /* TODO: handle this gracefully */ + + if (file[0] == '.' && file[1] == '\\') + file += 2; + + fn_copy = hash_lookup(&fn_hash, file); + if (fn_copy == NULL) { + + size_t cblen = 0; + if (FAILED(StringCbLengthA(file, MAX_PATH * sizeof(char), + &cblen))) + fn_copy = NULL; + else { + fn_copy = malloc(cblen + sizeof(char)); + if (fn_copy) { + hash_bin * b; + int hv; + + StringCbCopyA(fn_copy, cblen + sizeof(char), file); + + hv = fn_hash.hash(fn_copy) % fn_hash.n; + + b = malloc(sizeof(*b)); + b->data = fn_copy; + b->key = fn_copy; + LINIT(b); + LPUSH(&fn_hash.bins[hv], b); + } + } + } + + a->file = fn_copy; + a->line = line; + a->size = s; + a->ptr = ptr; +#ifdef _WIN32 + a->thread = GetCurrentThreadId(); +#endif + + h = HASHPTR(ptr); + + LPUSH(&ht[h], a); + LeaveCriticalSection(&cs_alloc); + + return ptr; +} + +KHMEXP void * +perf_realloc(const char * file, int line, void * data, size_t s) { + void * n_data; + allocation * a; + size_t h; + + if (data == NULL) + return perf_malloc(file, line, s); + + perf_once(); + h = HASHPTR(data); + + n_data = realloc(data, s); + + assert(n_data); + + EnterCriticalSection(&cs_alloc); + for (a = ht[h]; a; a = LNEXT(a)) { + if (a->ptr == data) + break; + } + + assert(a); + + LDELETE(&ht[h], a); + + a->size = s; + a->ptr = n_data; + + h = HASHPTR(n_data); + LPUSH(&ht[h], a); + LeaveCriticalSection(&cs_alloc); + + return n_data; +} + +KHMEXP void +perf_free (void * b) { + size_t h; + allocation * a; + + perf_once(); + h = HASHPTR(b); + + EnterCriticalSection(&cs_alloc); + for(a = ht[h]; a; a = LNEXT(a)) { + if (a->ptr == b) + break; + } + + assert(a); + + LDELETE(&ht[h], a); + LPUSH(&free_alloc, a); + LeaveCriticalSection(&cs_alloc); +} + +KHMEXP void KHMAPI +perf_dump(FILE * f) { + size_t i; + allocation * a; + size_t total = 0; + thread_info * t; + + perf_once(); + + EnterCriticalSection(&cs_alloc); + + fprintf(f, "p00\t*** Threads ***\n"); + fprintf(f, "p00\tFile\tLine\tThread\tName\tCreated by\n"); + + for (t = threads; t; t = LNEXT(t)) { + fprintf(f, "p01\t%s\t%6d\t%6d\t%S\t%S\n", + t->file, t->line, t->thread, + t->name, t->creator); + } + + fprintf(f, "p02\t--- End Threads ---\n"); + + fprintf(f, "p10\t*** Leaked allocations list ***\n"); + fprintf(f, "p11\tFile\tLine\tThread\tSize\tAddress\n"); + + for (i=0; i < HASHSIZE; i++) { + for (a = ht[i]; a; a = LNEXT(a)) { + fprintf(f, "p12\t%s\t%6d\t%6d\t%6d\t0x%p\n", a->file, a->line, + a->thread, a->size, a->ptr); + total += a->size; + } + } + + fprintf(f, "p20\t----------------------------------------\n"); + fprintf(f, "p21\tTotal\t\t%d\n", total); + fprintf(f, "p22\t----------------- End ------------------\n"); + + LeaveCriticalSection(&cs_alloc); +} + +KHMEXP void +perf_set_thread_desc(const char * file, int line, + const wchar_t * name, const wchar_t * creator) { + thread_info * t; + char * fn_copy; + + perf_once(); + + t = malloc(sizeof(*t)); + ZeroMemory(t, sizeof(*t)); + +#ifdef _WIN32 + t->thread = GetCurrentThreadId(); +#else +#error Unsupported platform +#endif + + StringCbCopy(t->name, sizeof(t->name), name); + if (creator) + StringCbCopy(t->creator, sizeof(t->creator), creator); + + if (file[0] == '.' && file[1] == '\\') + file += 2; + + EnterCriticalSection(&cs_alloc); + + fn_copy = hash_lookup(&fn_hash, file); + if (fn_copy == NULL) { + size_t cblen = 0; + if (FAILED(StringCbLengthA(file, MAX_PATH * sizeof(char), + &cblen))) + fn_copy = NULL; + else { + fn_copy = malloc(cblen + sizeof(char)); + if (fn_copy) { + hash_bin * b; + int hv; + + StringCbCopyA(fn_copy, cblen + sizeof(char), file); + + hv = fn_hash.hash(fn_copy) % fn_hash.n; + + b = malloc(sizeof(*b)); + b->data = fn_copy; + b->key = fn_copy; + LINIT(b); + LPUSH(&fn_hash.bins[hv], b); + } + } + } + + t->file = fn_copy; + t->line = line; + + LPUSH(&threads, t); + LeaveCriticalSection(&cs_alloc); +} diff --git a/src/windows/identity/util/perfstat.h b/src/windows/identity/util/perfstat.h index a4a0f2750..816a13681 100644 --- a/src/windows/identity/util/perfstat.h +++ b/src/windows/identity/util/perfstat.h @@ -1,74 +1,74 @@ -/* - * 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_PERFSTAT_H -#define __KHIMAIRA_PERFSTAT_H - -#include - -#ifdef DEBUG -#define PMALLOC(s) perf_malloc(__FILE__,__LINE__,s) -#define PCALLOC(n,s) perf_calloc(__FILE__,__LINE__,n,s) -#define PREALLOC(d,s) perf_realloc(__FILE__,__LINE__,d,s) -#define PFREE(p) perf_free(p) -#define PDUMP(f) perf_dump(f) -#define PWCSDUP(s) perf_wcsdup(__FILE__,__LINE__,s) -#define PSTRDUP(s) perf_strdup(__FILE__,__LINE__,s) -#define PDESCTHREAD(n,c) perf_set_thread_desc(__FILE__,__LINE__,n,c); -#else -#define PMALLOC(s) malloc(s) -#define PCALLOC(n,s) calloc(n,s) -#define PREALLOC(d,s) realloc(d,s) -#define PFREE(p) free(p) -#define PDUMP(f) ((void) 0) -#define PWCSDUP(s) wcsdup(s) -#define PSTRDUP(s) strdup(s) -#define PDESCTHREAD(n,c) -#endif - -KHMEXP void * -perf_malloc(const char * file, int line, size_t s); - -KHMEXP void * -perf_realloc(const char * file, int line, void * data, size_t s); - -KHMEXP void -perf_free (void * b); - -KHMEXP wchar_t * -perf_wcsdup(const char * file, int line, const wchar_t * str); - -KHMEXP char * -perf_strdup(const char * file, int line, const char * str); - -KHMEXP void * -perf_calloc(const char * file, int line, size_t num, size_t size); - -KHMEXP void -perf_set_thread_desc(const char * file, int line, - const wchar_t * name, const wchar_t * creator); - -#endif +/* + * 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_PERFSTAT_H +#define __KHIMAIRA_PERFSTAT_H + +#include + +#ifdef DEBUG +#define PMALLOC(s) perf_malloc(__FILE__,__LINE__,s) +#define PCALLOC(n,s) perf_calloc(__FILE__,__LINE__,n,s) +#define PREALLOC(d,s) perf_realloc(__FILE__,__LINE__,d,s) +#define PFREE(p) perf_free(p) +#define PDUMP(f) perf_dump(f) +#define PWCSDUP(s) perf_wcsdup(__FILE__,__LINE__,s) +#define PSTRDUP(s) perf_strdup(__FILE__,__LINE__,s) +#define PDESCTHREAD(n,c) perf_set_thread_desc(__FILE__,__LINE__,n,c); +#else +#define PMALLOC(s) malloc(s) +#define PCALLOC(n,s) calloc(n,s) +#define PREALLOC(d,s) realloc(d,s) +#define PFREE(p) free(p) +#define PDUMP(f) ((void) 0) +#define PWCSDUP(s) wcsdup(s) +#define PSTRDUP(s) strdup(s) +#define PDESCTHREAD(n,c) +#endif + +KHMEXP void * +perf_malloc(const char * file, int line, size_t s); + +KHMEXP void * +perf_realloc(const char * file, int line, void * data, size_t s); + +KHMEXP void +perf_free (void * b); + +KHMEXP wchar_t * +perf_wcsdup(const char * file, int line, const wchar_t * str); + +KHMEXP char * +perf_strdup(const char * file, int line, const char * str); + +KHMEXP void * +perf_calloc(const char * file, int line, size_t num, size_t size); + +KHMEXP void +perf_set_thread_desc(const char * file, int line, + const wchar_t * name, const wchar_t * creator); + +#endif diff --git a/src/windows/identity/util/sync.c b/src/windows/identity/util/sync.c index d811eb99d..c829ada7c 100644 --- a/src/windows/identity/util/sync.c +++ b/src/windows/identity/util/sync.c @@ -1,130 +1,130 @@ -/* - * 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 - -#define LOCK_OPEN 0 -#define LOCK_READING 1 -#define LOCK_WRITING 2 - -KHMEXP void KHMAPI InitializeRwLock(PRWLOCK pLock) -{ - pLock->locks = 0; - pLock->status = LOCK_OPEN; - InitializeCriticalSection(&(pLock->cs)); - pLock->writewx = CreateEvent(NULL, - FALSE, /* Manual reset */ - TRUE, /* Initial state */ - NULL); - pLock->readwx = CreateEvent(NULL, - TRUE, /* Manual reset */ - TRUE, /* Initial state */ - NULL); -} - -KHMEXP void KHMAPI DeleteRwLock(PRWLOCK pLock) -{ - EnterCriticalSection(&pLock->cs); - - CloseHandle(pLock->readwx); - CloseHandle(pLock->writewx); - pLock->readwx = NULL; - pLock->writewx = NULL; - - LeaveCriticalSection(&pLock->cs); - DeleteCriticalSection(&(pLock->cs)); -} - -KHMEXP void KHMAPI LockObtainRead(PRWLOCK pLock) -{ - while(1) { - WaitForSingleObject(pLock->readwx, INFINITE); - EnterCriticalSection(&pLock->cs); - if(pLock->status == LOCK_WRITING) { - LeaveCriticalSection(&(pLock->cs)); - continue; - } else - break; - } - pLock->locks ++; - pLock->status = LOCK_READING; - ResetEvent(pLock->writewx); - LeaveCriticalSection(&(pLock->cs)); -} - -KHMEXP void KHMAPI LockReleaseRead(PRWLOCK pLock) -{ - EnterCriticalSection(&(pLock->cs)); - assert(pLock->status == LOCK_READING); - pLock->locks--; - if(!pLock->locks) { - pLock->status = LOCK_OPEN; - SetEvent(pLock->readwx); - SetEvent(pLock->writewx); - } - LeaveCriticalSection(&(pLock->cs)); -} - -KHMEXP void KHMAPI LockObtainWrite(PRWLOCK pLock) -{ - EnterCriticalSection(&(pLock->cs)); - if(pLock->status == LOCK_WRITING && - pLock->writer == GetCurrentThreadId()) { - pLock->locks++; - LeaveCriticalSection(&(pLock->cs)); - return; - } - LeaveCriticalSection(&(pLock->cs)); - while(1) { - WaitForSingleObject(pLock->writewx, INFINITE); - EnterCriticalSection(&(pLock->cs)); - if(pLock->status == LOCK_OPEN) - break; - LeaveCriticalSection(&(pLock->cs)); - } - pLock->status = LOCK_WRITING; - pLock->locks++; - pLock->writer = GetCurrentThreadId(); - ResetEvent(pLock->readwx); - ResetEvent(pLock->writewx); - LeaveCriticalSection(&(pLock->cs)); -} - -KHMEXP void KHMAPI LockReleaseWrite(PRWLOCK pLock) -{ - EnterCriticalSection(&(pLock->cs)); - assert(pLock->status == LOCK_WRITING); - pLock->locks--; - if(!pLock->locks) { - pLock->status = LOCK_OPEN; - pLock->writer = 0; - SetEvent(pLock->readwx); - SetEvent(pLock->writewx); - } - LeaveCriticalSection(&(pLock->cs)); -} +/* + * 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 + +#define LOCK_OPEN 0 +#define LOCK_READING 1 +#define LOCK_WRITING 2 + +KHMEXP void KHMAPI InitializeRwLock(PRWLOCK pLock) +{ + pLock->locks = 0; + pLock->status = LOCK_OPEN; + InitializeCriticalSection(&(pLock->cs)); + pLock->writewx = CreateEvent(NULL, + FALSE, /* Manual reset */ + TRUE, /* Initial state */ + NULL); + pLock->readwx = CreateEvent(NULL, + TRUE, /* Manual reset */ + TRUE, /* Initial state */ + NULL); +} + +KHMEXP void KHMAPI DeleteRwLock(PRWLOCK pLock) +{ + EnterCriticalSection(&pLock->cs); + + CloseHandle(pLock->readwx); + CloseHandle(pLock->writewx); + pLock->readwx = NULL; + pLock->writewx = NULL; + + LeaveCriticalSection(&pLock->cs); + DeleteCriticalSection(&(pLock->cs)); +} + +KHMEXP void KHMAPI LockObtainRead(PRWLOCK pLock) +{ + while(1) { + WaitForSingleObject(pLock->readwx, INFINITE); + EnterCriticalSection(&pLock->cs); + if(pLock->status == LOCK_WRITING) { + LeaveCriticalSection(&(pLock->cs)); + continue; + } else + break; + } + pLock->locks ++; + pLock->status = LOCK_READING; + ResetEvent(pLock->writewx); + LeaveCriticalSection(&(pLock->cs)); +} + +KHMEXP void KHMAPI LockReleaseRead(PRWLOCK pLock) +{ + EnterCriticalSection(&(pLock->cs)); + assert(pLock->status == LOCK_READING); + pLock->locks--; + if(!pLock->locks) { + pLock->status = LOCK_OPEN; + SetEvent(pLock->readwx); + SetEvent(pLock->writewx); + } + LeaveCriticalSection(&(pLock->cs)); +} + +KHMEXP void KHMAPI LockObtainWrite(PRWLOCK pLock) +{ + EnterCriticalSection(&(pLock->cs)); + if(pLock->status == LOCK_WRITING && + pLock->writer == GetCurrentThreadId()) { + pLock->locks++; + LeaveCriticalSection(&(pLock->cs)); + return; + } + LeaveCriticalSection(&(pLock->cs)); + while(1) { + WaitForSingleObject(pLock->writewx, INFINITE); + EnterCriticalSection(&(pLock->cs)); + if(pLock->status == LOCK_OPEN) + break; + LeaveCriticalSection(&(pLock->cs)); + } + pLock->status = LOCK_WRITING; + pLock->locks++; + pLock->writer = GetCurrentThreadId(); + ResetEvent(pLock->readwx); + ResetEvent(pLock->writewx); + LeaveCriticalSection(&(pLock->cs)); +} + +KHMEXP void KHMAPI LockReleaseWrite(PRWLOCK pLock) +{ + EnterCriticalSection(&(pLock->cs)); + assert(pLock->status == LOCK_WRITING); + pLock->locks--; + if(!pLock->locks) { + pLock->status = LOCK_OPEN; + pLock->writer = 0; + SetEvent(pLock->readwx); + SetEvent(pLock->writewx); + } + LeaveCriticalSection(&(pLock->cs)); +} diff --git a/src/windows/identity/util/sync.h b/src/windows/identity/util/sync.h index e423e6766..a95db207e 100644 --- a/src/windows/identity/util/sync.h +++ b/src/windows/identity/util/sync.h @@ -1,128 +1,128 @@ -/* - * 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_SYNC_H -#define __KHIMAIRA_SYNC_H - -#include - -/*! \addtogroup util - @{ */ - -/*! \defgroup util_sync Synchronization - @{*/ - -/*! \brief A read/write lock - - A classic read/write lock. Allows multiple readers or a single - writer to access a protected object. Readers will wait for any - pending writer to release the lock, while a writer will wait for - any pending readers to release the lock. -*/ -typedef struct tag_rwlock { - int locks; - int status; - CRITICAL_SECTION cs; - HANDLE readwx; - HANDLE writewx; - - DWORD writer; /* TID of writer thread */ -} rw_lock_t; - -typedef rw_lock_t RWLOCK, *PRWLOCK; - -/*! \brief Initialize a read/write lock. - - A lock must be initialized before it can be used. - Initializing the lock does not grant the caller any locks on the - object. -*/ -KHMEXP void KHMAPI InitializeRwLock(PRWLOCK pLock); - -/*! \brief Delete a read/write lock - - Once the application is done using the read/write lock, it must be - deleted with a call to DeleteRwLock() -*/ -KHMEXP void KHMAPI DeleteRwLock(PRWLOCK pLock); - -/*! \brief Obtains a read lock on the read/write lock - - Multiple readers can obtain read locks on the same r/w lock. - However, if any thread attempts to obtain a write lock on the - object, it will wait until all readers have released the read - locks. - - Call LockReleaseRead() to release the read lock. While the same - thread may obtain multiple read locks on the same object, each - call to LockObtainRead() must have a corresponding call to - LockReleaseRead() to properly relinquish the lock. - - \see LockReleaseRead() -*/ -KHMEXP void KHMAPI LockObtainRead(PRWLOCK pLock); - -/*! \brief Relase a read lock obtained on a read/write lock - - Each call to LockObtainRead() must have a corresponding call to - LockReleaseRead(). Once all read locks are released, any threads - waiting on write locks on the object will be woken and assigned a - write lock. - - \see LockObtainRead() -*/ -KHMEXP void KHMAPI LockReleaseRead(PRWLOCK pLock); - -/*! \brief Obtains a write lock on the read/write lock - - Only a single writer is allowed to lock a single r/w lock. - However, if any thread attempts to obtain a read lock on the - object, it will wait until the writer has released the lock. - - Call LockReleaseWrite() to release the write lock. While the same - thread may obtain multiple write locks on the same object, each - call to LockObtainWrite() must have a corresponding call to - LockReleaseWrite() to properly relinquish the lock. - - \see LockReleaseWrite() -*/ -KHMEXP void KHMAPI LockObtainWrite(PRWLOCK pLock); - -/*! \brief Relase a write lock obtained on a read/write lock - - Each call to LockObtainWrite() must have a corresponding call to - LockReleaseWrite(). Once the write lock is released, any threads - waiting for read or write locks on the object will be woken and - assigned the proper lock. - - \see LockObtainWrite() -*/ -KHMEXP void KHMAPI LockReleaseWrite(PRWLOCK pLock); - -/*@}*/ -/*@}*/ - -#endif +/* + * 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_SYNC_H +#define __KHIMAIRA_SYNC_H + +#include + +/*! \addtogroup util + @{ */ + +/*! \defgroup util_sync Synchronization + @{*/ + +/*! \brief A read/write lock + + A classic read/write lock. Allows multiple readers or a single + writer to access a protected object. Readers will wait for any + pending writer to release the lock, while a writer will wait for + any pending readers to release the lock. +*/ +typedef struct tag_rwlock { + int locks; + int status; + CRITICAL_SECTION cs; + HANDLE readwx; + HANDLE writewx; + + DWORD writer; /* TID of writer thread */ +} rw_lock_t; + +typedef rw_lock_t RWLOCK, *PRWLOCK; + +/*! \brief Initialize a read/write lock. + + A lock must be initialized before it can be used. + Initializing the lock does not grant the caller any locks on the + object. +*/ +KHMEXP void KHMAPI InitializeRwLock(PRWLOCK pLock); + +/*! \brief Delete a read/write lock + + Once the application is done using the read/write lock, it must be + deleted with a call to DeleteRwLock() +*/ +KHMEXP void KHMAPI DeleteRwLock(PRWLOCK pLock); + +/*! \brief Obtains a read lock on the read/write lock + + Multiple readers can obtain read locks on the same r/w lock. + However, if any thread attempts to obtain a write lock on the + object, it will wait until all readers have released the read + locks. + + Call LockReleaseRead() to release the read lock. While the same + thread may obtain multiple read locks on the same object, each + call to LockObtainRead() must have a corresponding call to + LockReleaseRead() to properly relinquish the lock. + + \see LockReleaseRead() +*/ +KHMEXP void KHMAPI LockObtainRead(PRWLOCK pLock); + +/*! \brief Relase a read lock obtained on a read/write lock + + Each call to LockObtainRead() must have a corresponding call to + LockReleaseRead(). Once all read locks are released, any threads + waiting on write locks on the object will be woken and assigned a + write lock. + + \see LockObtainRead() +*/ +KHMEXP void KHMAPI LockReleaseRead(PRWLOCK pLock); + +/*! \brief Obtains a write lock on the read/write lock + + Only a single writer is allowed to lock a single r/w lock. + However, if any thread attempts to obtain a read lock on the + object, it will wait until the writer has released the lock. + + Call LockReleaseWrite() to release the write lock. While the same + thread may obtain multiple write locks on the same object, each + call to LockObtainWrite() must have a corresponding call to + LockReleaseWrite() to properly relinquish the lock. + + \see LockReleaseWrite() +*/ +KHMEXP void KHMAPI LockObtainWrite(PRWLOCK pLock); + +/*! \brief Relase a write lock obtained on a read/write lock + + Each call to LockObtainWrite() must have a corresponding call to + LockReleaseWrite(). Once the write lock is released, any threads + waiting for read or write locks on the object will be woken and + assigned the proper lock. + + \see LockObtainWrite() +*/ +KHMEXP void KHMAPI LockReleaseWrite(PRWLOCK pLock); + +/*@}*/ +/*@}*/ + +#endif diff --git a/src/windows/identity/util/utils.h b/src/windows/identity/util/utils.h index 4ba86f6ed..4c3bef52f 100644 --- a/src/windows/identity/util/utils.h +++ b/src/windows/identity/util/utils.h @@ -1,37 +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 __KHIMAIRA_UTIL_H -#define __KHIMAIRA_UTIL_H - -/*! \defgroup util Utilities - */ -#include -#include -#include -#include - -#endif +/* + * 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_UTIL_H +#define __KHIMAIRA_UTIL_H + +/*! \defgroup util Utilities + */ +#include +#include +#include +#include + +#endif diff --git a/src/windows/kfwlogon/kfwcommon.c b/src/windows/kfwlogon/kfwcommon.c index ea9410ea6..c07bd81c3 100644 --- a/src/windows/kfwlogon/kfwcommon.c +++ b/src/windows/kfwlogon/kfwcommon.c @@ -1,1352 +1,1352 @@ -/* -Copyright 2005,2006 by the Massachusetts Institute of Technology -Copyright 2007 by Secure Endpoints Inc. - -All rights reserved. - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of the Massachusetts -Institute of Technology (M.I.T.) not be used in advertising or publicity -pertaining to distribution of the software without specific, written -prior permission. - -M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -*/ - -#include "kfwlogon.h" -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - - -/* Function Pointer Declarations for Delayed Loading */ -// CCAPI -DECL_FUNC_PTR(cc_initialize); -DECL_FUNC_PTR(cc_shutdown); -DECL_FUNC_PTR(cc_get_NC_info); -DECL_FUNC_PTR(cc_free_NC_info); - -// leash functions -DECL_FUNC_PTR(Leash_get_default_lifetime); -DECL_FUNC_PTR(Leash_get_default_forwardable); -DECL_FUNC_PTR(Leash_get_default_renew_till); -DECL_FUNC_PTR(Leash_get_default_noaddresses); -DECL_FUNC_PTR(Leash_get_default_proxiable); -DECL_FUNC_PTR(Leash_get_default_publicip); -DECL_FUNC_PTR(Leash_get_default_use_krb4); -DECL_FUNC_PTR(Leash_get_default_life_min); -DECL_FUNC_PTR(Leash_get_default_life_max); -DECL_FUNC_PTR(Leash_get_default_renew_min); -DECL_FUNC_PTR(Leash_get_default_renew_max); -DECL_FUNC_PTR(Leash_get_default_renewable); -DECL_FUNC_PTR(Leash_get_default_mslsa_import); - -// krb5 functions -DECL_FUNC_PTR(krb5_change_password); -DECL_FUNC_PTR(krb5_get_init_creds_opt_init); -DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life); -DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); -DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable); -DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable); -DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list); -DECL_FUNC_PTR(krb5_get_init_creds_password); -DECL_FUNC_PTR(krb5_build_principal_ext); -DECL_FUNC_PTR(krb5_cc_get_name); -DECL_FUNC_PTR(krb5_cc_resolve); -DECL_FUNC_PTR(krb5_cc_default); -DECL_FUNC_PTR(krb5_cc_default_name); -DECL_FUNC_PTR(krb5_cc_set_default_name); -DECL_FUNC_PTR(krb5_cc_initialize); -DECL_FUNC_PTR(krb5_cc_destroy); -DECL_FUNC_PTR(krb5_cc_close); -DECL_FUNC_PTR(krb5_cc_store_cred); -DECL_FUNC_PTR(krb5_cc_copy_creds); -DECL_FUNC_PTR(krb5_cc_retrieve_cred); -DECL_FUNC_PTR(krb5_cc_get_principal); -DECL_FUNC_PTR(krb5_cc_start_seq_get); -DECL_FUNC_PTR(krb5_cc_next_cred); -DECL_FUNC_PTR(krb5_cc_end_seq_get); -DECL_FUNC_PTR(krb5_cc_remove_cred); -DECL_FUNC_PTR(krb5_cc_set_flags); -DECL_FUNC_PTR(krb5_cc_get_type); -DECL_FUNC_PTR(krb5_free_context); -DECL_FUNC_PTR(krb5_free_cred_contents); -DECL_FUNC_PTR(krb5_free_principal); -DECL_FUNC_PTR(krb5_get_in_tkt_with_password); -DECL_FUNC_PTR(krb5_init_context); -DECL_FUNC_PTR(krb5_parse_name); -DECL_FUNC_PTR(krb5_timeofday); -DECL_FUNC_PTR(krb5_timestamp_to_sfstring); -DECL_FUNC_PTR(krb5_unparse_name); -DECL_FUNC_PTR(krb5_get_credentials); -DECL_FUNC_PTR(krb5_mk_req); -DECL_FUNC_PTR(krb5_sname_to_principal); -DECL_FUNC_PTR(krb5_get_credentials_renew); -DECL_FUNC_PTR(krb5_free_data); -DECL_FUNC_PTR(krb5_free_data_contents); -DECL_FUNC_PTR(krb5_free_unparsed_name); -DECL_FUNC_PTR(krb5_os_localaddr); -DECL_FUNC_PTR(krb5_copy_keyblock_contents); -DECL_FUNC_PTR(krb5_copy_data); -DECL_FUNC_PTR(krb5_free_creds); -DECL_FUNC_PTR(krb5_build_principal); -DECL_FUNC_PTR(krb5_get_renewed_creds); -DECL_FUNC_PTR(krb5_get_default_config_files); -DECL_FUNC_PTR(krb5_free_config_files); -DECL_FUNC_PTR(krb5_get_default_realm); -DECL_FUNC_PTR(krb5_free_default_realm); -DECL_FUNC_PTR(krb5_free_ticket); -DECL_FUNC_PTR(krb5_decode_ticket); -DECL_FUNC_PTR(krb5_get_host_realm); -DECL_FUNC_PTR(krb5_free_host_realm); -DECL_FUNC_PTR(krb5_free_addresses); -DECL_FUNC_PTR(krb5_c_random_make_octets); - -// ComErr functions -DECL_FUNC_PTR(com_err); -DECL_FUNC_PTR(error_message); - -// Profile functions -DECL_FUNC_PTR(profile_init); -DECL_FUNC_PTR(profile_release); -DECL_FUNC_PTR(profile_get_subsection_names); -DECL_FUNC_PTR(profile_free_list); -DECL_FUNC_PTR(profile_get_string); -DECL_FUNC_PTR(profile_release_string); - -// Service functions -DECL_FUNC_PTR(OpenSCManagerA); -DECL_FUNC_PTR(OpenServiceA); -DECL_FUNC_PTR(QueryServiceStatus); -DECL_FUNC_PTR(CloseServiceHandle); -DECL_FUNC_PTR(LsaNtStatusToWinError); - -// LSA Functions -DECL_FUNC_PTR(LsaConnectUntrusted); -DECL_FUNC_PTR(LsaLookupAuthenticationPackage); -DECL_FUNC_PTR(LsaCallAuthenticationPackage); -DECL_FUNC_PTR(LsaFreeReturnBuffer); -DECL_FUNC_PTR(LsaGetLogonSessionData); - -// CCAPI -FUNC_INFO ccapi_fi[] = { - MAKE_FUNC_INFO(cc_initialize), - MAKE_FUNC_INFO(cc_shutdown), - MAKE_FUNC_INFO(cc_get_NC_info), - MAKE_FUNC_INFO(cc_free_NC_info), - END_FUNC_INFO -}; - -FUNC_INFO leash_fi[] = { - MAKE_FUNC_INFO(Leash_get_default_lifetime), - MAKE_FUNC_INFO(Leash_get_default_renew_till), - MAKE_FUNC_INFO(Leash_get_default_forwardable), - MAKE_FUNC_INFO(Leash_get_default_noaddresses), - MAKE_FUNC_INFO(Leash_get_default_proxiable), - MAKE_FUNC_INFO(Leash_get_default_publicip), - MAKE_FUNC_INFO(Leash_get_default_use_krb4), - MAKE_FUNC_INFO(Leash_get_default_life_min), - MAKE_FUNC_INFO(Leash_get_default_life_max), - MAKE_FUNC_INFO(Leash_get_default_renew_min), - MAKE_FUNC_INFO(Leash_get_default_renew_max), - MAKE_FUNC_INFO(Leash_get_default_renewable), - END_FUNC_INFO -}; - -FUNC_INFO leash_opt_fi[] = { - MAKE_FUNC_INFO(Leash_get_default_mslsa_import), - END_FUNC_INFO -}; - -FUNC_INFO k5_fi[] = { - MAKE_FUNC_INFO(krb5_change_password), - MAKE_FUNC_INFO(krb5_get_init_creds_opt_init), - MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life), - MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life), - MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable), - MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable), - MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list), - MAKE_FUNC_INFO(krb5_get_init_creds_password), - MAKE_FUNC_INFO(krb5_build_principal_ext), - MAKE_FUNC_INFO(krb5_cc_get_name), - MAKE_FUNC_INFO(krb5_cc_resolve), - MAKE_FUNC_INFO(krb5_cc_default), - MAKE_FUNC_INFO(krb5_cc_default_name), - MAKE_FUNC_INFO(krb5_cc_set_default_name), - MAKE_FUNC_INFO(krb5_cc_initialize), - MAKE_FUNC_INFO(krb5_cc_destroy), - MAKE_FUNC_INFO(krb5_cc_close), - MAKE_FUNC_INFO(krb5_cc_copy_creds), - MAKE_FUNC_INFO(krb5_cc_store_cred), - MAKE_FUNC_INFO(krb5_cc_retrieve_cred), - MAKE_FUNC_INFO(krb5_cc_get_principal), - MAKE_FUNC_INFO(krb5_cc_start_seq_get), - MAKE_FUNC_INFO(krb5_cc_next_cred), - MAKE_FUNC_INFO(krb5_cc_end_seq_get), - MAKE_FUNC_INFO(krb5_cc_remove_cred), - MAKE_FUNC_INFO(krb5_cc_set_flags), - MAKE_FUNC_INFO(krb5_cc_get_type), - MAKE_FUNC_INFO(krb5_free_context), - MAKE_FUNC_INFO(krb5_free_cred_contents), - MAKE_FUNC_INFO(krb5_free_principal), - MAKE_FUNC_INFO(krb5_get_in_tkt_with_password), - MAKE_FUNC_INFO(krb5_init_context), - MAKE_FUNC_INFO(krb5_parse_name), - MAKE_FUNC_INFO(krb5_timeofday), - MAKE_FUNC_INFO(krb5_timestamp_to_sfstring), - MAKE_FUNC_INFO(krb5_unparse_name), - MAKE_FUNC_INFO(krb5_get_credentials), - MAKE_FUNC_INFO(krb5_mk_req), - MAKE_FUNC_INFO(krb5_sname_to_principal), - MAKE_FUNC_INFO(krb5_get_credentials_renew), - MAKE_FUNC_INFO(krb5_free_data), - MAKE_FUNC_INFO(krb5_free_data_contents), - MAKE_FUNC_INFO(krb5_free_unparsed_name), - MAKE_FUNC_INFO(krb5_os_localaddr), - MAKE_FUNC_INFO(krb5_copy_keyblock_contents), - MAKE_FUNC_INFO(krb5_copy_data), - MAKE_FUNC_INFO(krb5_free_creds), - MAKE_FUNC_INFO(krb5_build_principal), - MAKE_FUNC_INFO(krb5_get_renewed_creds), - MAKE_FUNC_INFO(krb5_free_addresses), - MAKE_FUNC_INFO(krb5_get_default_config_files), - MAKE_FUNC_INFO(krb5_free_config_files), - MAKE_FUNC_INFO(krb5_get_default_realm), - MAKE_FUNC_INFO(krb5_free_default_realm), - MAKE_FUNC_INFO(krb5_free_ticket), - MAKE_FUNC_INFO(krb5_decode_ticket), - MAKE_FUNC_INFO(krb5_get_host_realm), - MAKE_FUNC_INFO(krb5_free_host_realm), - MAKE_FUNC_INFO(krb5_free_addresses), - MAKE_FUNC_INFO(krb5_c_random_make_octets), - END_FUNC_INFO -}; - -FUNC_INFO profile_fi[] = { - MAKE_FUNC_INFO(profile_init), - MAKE_FUNC_INFO(profile_release), - MAKE_FUNC_INFO(profile_get_subsection_names), - MAKE_FUNC_INFO(profile_free_list), - MAKE_FUNC_INFO(profile_get_string), - MAKE_FUNC_INFO(profile_release_string), - END_FUNC_INFO -}; - -FUNC_INFO ce_fi[] = { - MAKE_FUNC_INFO(com_err), - MAKE_FUNC_INFO(error_message), - END_FUNC_INFO -}; - -FUNC_INFO service_fi[] = { - MAKE_FUNC_INFO(OpenSCManagerA), - MAKE_FUNC_INFO(OpenServiceA), - MAKE_FUNC_INFO(QueryServiceStatus), - MAKE_FUNC_INFO(CloseServiceHandle), - MAKE_FUNC_INFO(LsaNtStatusToWinError), - END_FUNC_INFO -}; - -FUNC_INFO lsa_fi[] = { - MAKE_FUNC_INFO(LsaConnectUntrusted), - MAKE_FUNC_INFO(LsaLookupAuthenticationPackage), - MAKE_FUNC_INFO(LsaCallAuthenticationPackage), - MAKE_FUNC_INFO(LsaFreeReturnBuffer), - MAKE_FUNC_INFO(LsaGetLogonSessionData), - END_FUNC_INFO -}; - -/* Static Declarations */ -static int inited = 0; -static HINSTANCE hKrb5 = 0; -static HINSTANCE hKrb524 = 0; -static HINSTANCE hSecur32 = 0; -static HINSTANCE hAdvApi32 = 0; -static HINSTANCE hComErr = 0; -static HINSTANCE hService = 0; -static HINSTANCE hProfile = 0; -static HINSTANCE hLeash = 0; -static HINSTANCE hLeashOpt = 0; -static HINSTANCE hCCAPI = 0; - -static DWORD TraceOption = 0; -static HANDLE hDLL; - -BOOL IsDebugLogging(void) -{ - DWORD LSPsize; - HKEY NPKey; - DWORD dwDebug = FALSE; - - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, - "System\\CurrentControlSet\\Services\\MIT Kerberos\\NetworkProvider", - 0, KEY_QUERY_VALUE, &NPKey) == ERROR_SUCCESS) - { - LSPsize=sizeof(dwDebug); - if (RegQueryValueEx(NPKey, "Debug", NULL, NULL, (LPBYTE)&dwDebug, &LSPsize) != ERROR_SUCCESS) - { - dwDebug = FALSE; - } - RegCloseKey (NPKey); - } - - return(dwDebug ? TRUE : FALSE); -} - -void DebugEvent0(char *a) -{ - HANDLE h; char *ptbuf[1]; - - if (IsDebugLogging()) { - h = RegisterEventSource(NULL, KFW_LOGON_EVENT_NAME); - if (h) { - ptbuf[0] = a; - ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL); - DeregisterEventSource(h); - } - } -} - -#define MAXBUF_ 512 -void DebugEvent(char *b,...) -{ - HANDLE h; char *ptbuf[1],buf[MAXBUF_+1]; - va_list marker; - - if (IsDebugLogging()) { - h = RegisterEventSource(NULL, KFW_LOGON_EVENT_NAME); - if (h) { - va_start(marker,b); - StringCbVPrintf(buf, MAXBUF_+1,b,marker); - buf[MAXBUF_] = '\0'; - ptbuf[0] = buf; - ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL); - DeregisterEventSource(h); - va_end(marker); - } - } -} - -void -UnloadFuncs( - FUNC_INFO fi[], - HINSTANCE h - ) -{ - int n; - if (fi) - for (n = 0; fi[n].func_ptr_var; n++) - *(fi[n].func_ptr_var) = 0; - if (h) FreeLibrary(h); -} - -int -LoadFuncs( - const char* dll_name, - FUNC_INFO fi[], - HINSTANCE* ph, // [out, optional] - DLL handle - int* pindex, // [out, optional] - index of last func loaded (-1 if none) - int cleanup, // cleanup function pointers and unload on error - int go_on, // continue loading even if some functions cannot be loaded - int silent // do not pop-up a system dialog if DLL cannot be loaded - ) -{ - HINSTANCE h; - int i, n, last_i; - int error = 0; - UINT em; - - if (ph) *ph = 0; - if (pindex) *pindex = -1; - - for (n = 0; fi[n].func_ptr_var; n++) - *(fi[n].func_ptr_var) = 0; - - if (silent) - em = SetErrorMode(SEM_FAILCRITICALERRORS); - h = LoadLibrary(dll_name); - if (silent) - SetErrorMode(em); - - if (!h) - return 0; - - last_i = -1; - for (i = 0; (go_on || !error) && (i < n); i++) - { - void* p = (void*)GetProcAddress(h, fi[i].func_name); - if (!p) - error = 1; - else - { - last_i = i; - *(fi[i].func_ptr_var) = p; - } - } - if (pindex) *pindex = last_i; - if (error && cleanup && !go_on) { - for (i = 0; i < n; i++) { - *(fi[i].func_ptr_var) = 0; - } - FreeLibrary(h); - return 0; - } - if (ph) *ph = h; - if (error) return 0; - return 1; -} - -static HANDLE hInitMutex = NULL; -static BOOL bInit = FALSE; - -/* KFW_initialize cannot be called from DllEntryPoint */ -void -KFW_initialize(void) -{ - static int inited = 0; - - if ( !inited ) { - char mutexName[MAX_PATH]; - HANDLE hMutex = NULL; - - sprintf(mutexName, "AFS KFW Init pid=%d", getpid()); - - hMutex = CreateMutex( NULL, TRUE, mutexName ); - if ( GetLastError() == ERROR_ALREADY_EXISTS ) { - if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) { - return; - } - } - if ( !inited ) { - inited = 1; - LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0); - LoadFuncs(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(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0); - LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0); - LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0); - LoadFuncs(LEASH_DLL, leash_opt_fi, &hLeashOpt, 0, 1, 0, 0); - } - ReleaseMutex(hMutex); - CloseHandle(hMutex); - } -} - -void -KFW_cleanup(void) -{ - if (hLeashOpt) - FreeLibrary(hLeashOpt); - if (hCCAPI) - FreeLibrary(hCCAPI); - if (hLeash) - FreeLibrary(hLeash); - if (hKrb524) - FreeLibrary(hKrb524); - if (hSecur32) - FreeLibrary(hSecur32); - if (hService) - FreeLibrary(hService); - if (hComErr) - FreeLibrary(hComErr); - if (hProfile) - FreeLibrary(hProfile); - if (hKrb5) - FreeLibrary(hKrb5); -} - - -int -KFW_is_available(void) -{ - KFW_initialize(); - if ( hKrb5 && hComErr && hService && -#ifdef USE_MS2MIT - hSecur32 && -#endif /* USE_MS2MIT */ - hProfile && hLeash && hCCAPI ) - return TRUE; - - return FALSE; -} - -/* Given a principal return an existing ccache or create one and return */ -int -KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc) -{ - krb5_context ctx; - char * pname = 0; - char * ccname = 0; - krb5_error_code code; - - if (!pkrb5_init_context) - return 0; - - if ( alt_ctx ) { - ctx = alt_ctx; - } else { - code = pkrb5_init_context(&ctx); - if (code) goto cleanup; - } - - if ( principal ) { - code = pkrb5_unparse_name(ctx, principal, &pname); - if (code) goto cleanup; - - ccname = (char *)malloc(strlen(pname) + 5); - sprintf(ccname,"API:%s",pname); - - DebugEvent0(ccname); - code = pkrb5_cc_resolve(ctx, ccname, cc); - } else { - code = pkrb5_cc_default(ctx, cc); - if (code) goto cleanup; - } - - cleanup: - if (ccname) - free(ccname); - if (pname) - pkrb5_free_unparsed_name(ctx,pname); - if (ctx && (ctx != alt_ctx)) - pkrb5_free_context(ctx); - return(code); -} - - -int -KFW_kinit( krb5_context alt_ctx, - krb5_ccache alt_cc, - HWND hParent, - char *principal_name, - char *password, - krb5_deltat lifetime, - DWORD forwardable, - DWORD proxiable, - krb5_deltat renew_life, - DWORD addressless, - DWORD publicIP - ) -{ - krb5_error_code code = 0; - krb5_context ctx = 0; - krb5_ccache cc = 0; - krb5_principal me = 0; - char* name = 0; - krb5_creds my_creds; - krb5_get_init_creds_opt options; - krb5_address ** addrs = NULL; - int i = 0, addr_count = 0; - - if (!pkrb5_init_context) - return 0; - - pkrb5_get_init_creds_opt_init(&options); - memset(&my_creds, 0, sizeof(my_creds)); - - if (alt_ctx) - { - ctx = alt_ctx; - } - else - { - code = pkrb5_init_context(&ctx); - if (code) goto cleanup; - } - - if ( alt_cc ) { - cc = alt_cc; - } else { - code = pkrb5_cc_default(ctx, &cc); - if (code) goto cleanup; - } - - code = pkrb5_parse_name(ctx, principal_name, &me); - if (code) - goto cleanup; - - code = pkrb5_unparse_name(ctx, me, &name); - if (code) - goto cleanup; - - if (lifetime == 0) - lifetime = pLeash_get_default_lifetime(); - lifetime *= 60; - - if (renew_life > 0) - renew_life *= 60; - - if (lifetime) - pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime); - pkrb5_get_init_creds_opt_set_forwardable(&options, - forwardable ? 1 : 0); - pkrb5_get_init_creds_opt_set_proxiable(&options, - proxiable ? 1 : 0); - pkrb5_get_init_creds_opt_set_renew_life(&options, - renew_life); - if (addressless) - pkrb5_get_init_creds_opt_set_address_list(&options,NULL); - else { - if (publicIP) - { - // we are going to add the public IP address specified by the user - // to the list provided by the operating system - krb5_address ** local_addrs=NULL; - DWORD netIPAddr; - - pkrb5_os_localaddr(ctx, &local_addrs); - while ( local_addrs[i++] ); - addr_count = i + 1; - - addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *)); - if ( !addrs ) { - pkrb5_free_addresses(ctx, local_addrs); - goto cleanup; - } - memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1)); - i = 0; - while ( local_addrs[i] ) { - addrs[i] = (krb5_address *)malloc(sizeof(krb5_address)); - if (addrs[i] == NULL) { - pkrb5_free_addresses(ctx, local_addrs); - goto cleanup; - } - - addrs[i]->magic = local_addrs[i]->magic; - addrs[i]->addrtype = local_addrs[i]->addrtype; - addrs[i]->length = local_addrs[i]->length; - addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length); - if (!addrs[i]->contents) { - pkrb5_free_addresses(ctx, local_addrs); - goto cleanup; - } - - memcpy(addrs[i]->contents,local_addrs[i]->contents, - local_addrs[i]->length); /* safe */ - i++; - } - pkrb5_free_addresses(ctx, local_addrs); - - addrs[i] = (krb5_address *)malloc(sizeof(krb5_address)); - if (addrs[i] == NULL) - goto cleanup; - - addrs[i]->magic = KV5M_ADDRESS; - addrs[i]->addrtype = AF_INET; - addrs[i]->length = 4; - addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length); - if (!addrs[i]->contents) - goto cleanup; - - netIPAddr = htonl(publicIP); - memcpy(addrs[i]->contents,&netIPAddr,4); - - pkrb5_get_init_creds_opt_set_address_list(&options,addrs); - - } - } - - code = pkrb5_get_init_creds_password(ctx, - &my_creds, - me, - password, // password - NULL, // no prompter - hParent, // prompter data - 0, // start time - 0, // service name - &options); - if (code) - goto cleanup; - - code = pkrb5_cc_initialize(ctx, cc, me); - if (code) - goto cleanup; - - code = pkrb5_cc_store_cred(ctx, cc, &my_creds); - if (code) - goto cleanup; - - cleanup: - if ( addrs ) { - for ( i=0;icontents ) - free(addrs[i]->contents); - free(addrs[i]); - } - } - } - if (my_creds.client == me) - my_creds.client = 0; - pkrb5_free_cred_contents(ctx, &my_creds); - if (name) - pkrb5_free_unparsed_name(ctx, name); - if (me) - pkrb5_free_principal(ctx, me); - if (cc && (cc != alt_cc)) - pkrb5_cc_close(ctx, cc); - if (ctx && (ctx != alt_ctx)) - pkrb5_free_context(ctx); - return(code); -} - - -int -KFW_get_cred( char * username, - char * password, - int lifetime, - char ** reasonP ) -{ - krb5_context ctx = 0; - krb5_ccache cc = 0; - char * realm = 0; - krb5_principal principal = 0; - char * pname = 0; - krb5_error_code code; - - if (!pkrb5_init_context || !username || !password || !password[0]) - return 0; - - DebugEvent0(username); - - code = pkrb5_init_context(&ctx); - if ( code ) goto cleanup; - - code = pkrb5_get_default_realm(ctx, &realm); - - if (realm) { - pname = malloc(strlen(username) + strlen(realm) + 2); - if (!pname) - goto cleanup; - strcpy(pname, username); - strcat(pname, "@"); - strcat(pname, realm); - } else { - goto cleanup; - } - - DebugEvent0(realm); - DebugEvent0(pname); - - code = pkrb5_parse_name(ctx, pname, &principal); - if ( code ) goto cleanup; - - DebugEvent0("parsed name"); - code = KFW_get_ccache(ctx, principal, &cc); - if ( code ) goto cleanup; - - DebugEvent0("got ccache"); - - if ( lifetime == 0 ) - lifetime = pLeash_get_default_lifetime(); - - DebugEvent0("got lifetime"); - - code = KFW_kinit( ctx, cc, HWND_DESKTOP, - pname, - password, - lifetime, - pLeash_get_default_forwardable(), - pLeash_get_default_proxiable(), - pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0, - pLeash_get_default_noaddresses(), - pLeash_get_default_publicip()); - DebugEvent0("kinit returned"); - if ( code ) goto cleanup; - - cleanup: - if ( pname ) - free(pname); - if ( realm ) - pkrb5_free_default_realm(ctx, realm); - if ( cc ) - pkrb5_cc_close(ctx, cc); - - if ( code && reasonP ) { - *reasonP = (char *)perror_message(code); - } - return(code); -} - -int KFW_set_ccache_dacl(char *filename, HANDLE hUserToken) -{ - // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY; - PSID pSystemSID = NULL; - DWORD SystemSIDlength = 0, UserSIDlength = 0; - PACL ccacheACL = NULL; - DWORD ccacheACLlength = 0; - PTOKEN_USER pTokenUser = NULL; - DWORD retLen; - DWORD gle; - int ret = 0; - - if (!filename) { - DebugEvent0("KFW_set_ccache_dacl - invalid parms"); - return 1; - } - - DebugEvent0("KFW_set_ccache_dacl"); - - /* Get System SID */ - if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) { - DebugEvent("KFW_set_ccache_dacl - ConvertStringSidToSid GLE = 0x%x", GetLastError()); - ret = 1; - goto cleanup; - } - - /* Create ACL */ - SystemSIDlength = GetLengthSid(pSystemSID); - ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) - + SystemSIDlength - sizeof(DWORD); - - if (hUserToken) { - if (!GetTokenInformation(hUserToken, TokenUser, NULL, 0, &retLen)) - { - if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) { - pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen); - - if (!GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen)) - { - DebugEvent("GetTokenInformation failed: GLE = %lX", GetLastError()); - } - } - } - - if (pTokenUser) { - UserSIDlength = GetLengthSid(pTokenUser->User.Sid); - - ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength - - sizeof(DWORD); - } - } - - ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength); - if (!ccacheACL) { - DebugEvent("KFW_set_ccache_dacl - LocalAlloc GLE = 0x%x", GetLastError()); - ret = 1; - goto cleanup; - } - - InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION); - AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0, - STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, - pSystemSID); - if (pTokenUser) { - AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0, - STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, - pTokenUser->User.Sid); - if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT, - DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, - NULL, - NULL, - ccacheACL, - NULL)) { - gle = GetLastError(); - DebugEvent("SetNamedSecurityInfo DACL (1) failed: GLE = 0x%lX", gle); - if (gle != ERROR_NO_TOKEN) - ret = 1; - } - if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT, - OWNER_SECURITY_INFORMATION, - pTokenUser->User.Sid, - NULL, - NULL, - NULL)) { - gle = GetLastError(); - DebugEvent("SetNamedSecurityInfo OWNER (2) failed: GLE = 0x%lX", gle); - if (gle != ERROR_NO_TOKEN) - ret = 1; - } - } else { - if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT, - DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, - NULL, - NULL, - ccacheACL, - NULL)) { - gle = GetLastError(); - DebugEvent("SetNamedSecurityInfo DACL (3) failed: GLE = 0x%lX", gle); - if (gle != ERROR_NO_TOKEN) - ret = 1; - } - } - - cleanup: - if (pSystemSID) - LocalFree(pSystemSID); - if (pTokenUser) - LocalFree(pTokenUser); - if (ccacheACL) - LocalFree(ccacheACL); - return ret; -} - -int KFW_set_ccache_dacl_with_user_sid(char *filename, PSID pUserSID) -{ - // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY; - PSID pSystemSID = NULL; - DWORD SystemSIDlength = 0, UserSIDlength = 0; - PACL ccacheACL = NULL; - DWORD ccacheACLlength = 0; - DWORD gle; - int ret = 0; - - if (!filename) { - DebugEvent0("KFW_set_ccache_dacl_with_user_sid - invalid parms"); - return 1; - } - - DebugEvent0("KFW_set_ccache_dacl_with_user_sid"); - - /* Get System SID */ - if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) { - DebugEvent("KFW_set_ccache_dacl - ConvertStringSidToSid GLE = 0x%x", GetLastError()); - ret = 1; - goto cleanup; - } - - /* Create ACL */ - SystemSIDlength = GetLengthSid(pSystemSID); - ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) - + SystemSIDlength - sizeof(DWORD); - - if (pUserSID) { - UserSIDlength = GetLengthSid(pUserSID); - - ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength - - sizeof(DWORD); - } - - ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength); - if (!ccacheACL) { - DebugEvent("KFW_set_ccache_dacl - LocalAlloc GLE = 0x%x", GetLastError()); - ret = 1; - goto cleanup; - } - - InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION); - AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0, - STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, - pSystemSID); - if (pUserSID) { - AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0, - STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, - pUserSID); - if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT, - DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, - NULL, - NULL, - ccacheACL, - NULL)) { - gle = GetLastError(); - DebugEvent("SetNamedSecurityInfo DACL (4) failed: GLE = 0x%lX", gle); - if (gle != ERROR_NO_TOKEN) - ret = 1; - } - if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT, - OWNER_SECURITY_INFORMATION, - pUserSID, - NULL, - NULL, - NULL)) { - gle = GetLastError(); - DebugEvent("SetNamedSecurityInfo OWNER (5) failed: GLE = 0x%lX", gle); - if (gle != ERROR_NO_TOKEN) - ret = 1; - } - } else { - if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT, - DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, - NULL, - NULL, - ccacheACL, - NULL)) { - gle = GetLastError(); - DebugEvent("SetNamedSecurityInfo DACL (6) failed: GLE = 0x%lX", gle); - if (gle != ERROR_NO_TOKEN) - ret = 1; - } - } - - cleanup: - if (pSystemSID) - LocalFree(pSystemSID); - if (ccacheACL) - LocalFree(ccacheACL); - return ret; -} - -int KFW_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size) -{ - int retval = 0; - DWORD dwSize = size-1; /* leave room for nul */ - DWORD dwLen = 0; - - if (!hUserToken || !newfilename || size <= 0) - return 1; - - *newfilename = '\0'; - - dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize); - if ( !dwLen || dwLen > dwSize ) - dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize); - if ( !dwLen || dwLen > dwSize ) - return 1; - - newfilename[dwSize] = '\0'; - return 0; -} - -void -KFW_copy_cache_to_system_file(const char * user, const char * filename) -{ - char cachename[MAX_PATH + 8] = "FILE:"; - krb5_context ctx = 0; - krb5_error_code code; - krb5_principal princ = 0; - krb5_ccache cc = 0; - krb5_ccache ncc = 0; - PSECURITY_ATTRIBUTES pSA = NULL; - - if (!pkrb5_init_context || !user || !filename) - return; - - strncat(cachename, filename, sizeof(cachename)); - cachename[sizeof(cachename)-1] = '\0'; - - DebugEvent("KFW_Logon_Event - ccache %s", cachename); - - DeleteFile(filename); - - code = pkrb5_init_context(&ctx); - if (code) goto cleanup; - - code = pkrb5_parse_name(ctx, user, &princ); - if (code) goto cleanup; - - code = KFW_get_ccache(ctx, princ, &cc); - if (code) goto cleanup; - - code = pkrb5_cc_resolve(ctx, cachename, &ncc); - if (code) goto cleanup; - - code = pkrb5_cc_initialize(ctx, ncc, princ); - if (code) goto cleanup; - - code = KFW_set_ccache_dacl(filename, NULL); - if (code) goto cleanup; - - code = pkrb5_cc_copy_creds(ctx,cc,ncc); - - cleanup: - if ( cc ) { - pkrb5_cc_close(ctx, cc); - cc = 0; - } - if ( ncc ) { - pkrb5_cc_close(ctx, ncc); - ncc = 0; - } - if ( princ ) { - pkrb5_free_principal(ctx, princ); - princ = 0; - } - - if (ctx) - pkrb5_free_context(ctx); -} - -int -KFW_copy_file_cache_to_default_cache(char * filename) -{ - char cachename[MAX_PATH + 8] = "FILE:"; - krb5_context ctx = 0; - krb5_error_code code; - krb5_principal princ = 0; - krb5_ccache cc = 0; - krb5_ccache ncc = 0; - int retval = 1; - - if (!pkrb5_init_context || !filename) - return 1; - - if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) ) - return 1; - - code = pkrb5_init_context(&ctx); - if (code) return 1; - - strcat(cachename, filename); - - code = pkrb5_cc_resolve(ctx, cachename, &cc); - if (code) { - DebugEvent0("kfwcpcc krb5_cc_resolve failed"); - goto cleanup; - } - - code = pkrb5_cc_get_principal(ctx, cc, &princ); - if (code) { - DebugEvent0("kfwcpcc krb5_cc_get_principal failed"); - goto cleanup; - } - - code = pkrb5_cc_default(ctx, &ncc); - if (code) { - DebugEvent0("kfwcpcc krb5_cc_default failed"); - goto cleanup; - } - if (!code) { - code = pkrb5_cc_initialize(ctx, ncc, princ); - - if (!code) - code = pkrb5_cc_copy_creds(ctx,cc,ncc); - if (code) { - DebugEvent0("kfwcpcc krb5_cc_copy_creds failed"); - goto cleanup; - } - } - if ( ncc ) { - pkrb5_cc_close(ctx, ncc); - ncc = 0; - } - - retval=0; /* success */ - - cleanup: - if ( cc ) { - pkrb5_cc_close(ctx, cc); - cc = 0; - } - - DeleteFile(filename); - - if ( princ ) { - pkrb5_free_principal(ctx, princ); - princ = 0; - } - - if (ctx) - pkrb5_free_context(ctx); - - return 0; -} - - -int -KFW_copy_file_cache_to_api_cache(char * filename) -{ - char cachename[MAX_PATH + 8] = "FILE:"; - krb5_context ctx = 0; - krb5_error_code code; - krb5_principal princ = 0; - krb5_ccache cc = 0; - krb5_ccache ncc = 0; - char *name = NULL; - int retval = 1; - - if (!pkrb5_init_context || !filename) - return 1; - - if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) ) - return 1; - - code = pkrb5_init_context(&ctx); - if (code) return 1; - - strcat(cachename, filename); - - code = pkrb5_cc_resolve(ctx, cachename, &cc); - if (code) { - DebugEvent0("kfwcpcc krb5_cc_resolve failed"); - goto cleanup; - } - - code = pkrb5_cc_get_principal(ctx, cc, &princ); - if (code) { - DebugEvent0("kfwcpcc krb5_cc_get_principal failed"); - goto cleanup; - } - - code = pkrb5_unparse_name(ctx, princ, &name); - if (code) { - DebugEvent0("kfwcpcc krb5_unparse_name failed"); - goto cleanup; - } - - sprintf(cachename, "API:%s", name); - - code = pkrb5_cc_resolve(ctx, cachename, &ncc); - if (code) { - DebugEvent0("kfwcpcc krb5_cc_default failed"); - goto cleanup; - } - if (!code) { - code = pkrb5_cc_initialize(ctx, ncc, princ); - - if (!code) - code = pkrb5_cc_copy_creds(ctx,cc,ncc); - if (code) { - DebugEvent0("kfwcpcc krb5_cc_copy_creds failed"); - goto cleanup; - } - } - if ( ncc ) { - pkrb5_cc_close(ctx, ncc); - ncc = 0; - } - - retval=0; /* success */ - - cleanup: - if (name) - pkrb5_free_unparsed_name(ctx, name); - - if ( cc ) { - pkrb5_cc_close(ctx, cc); - cc = 0; - } - - DeleteFile(filename); - - if ( princ ) { - pkrb5_free_principal(ctx, princ); - princ = 0; - } - - if (ctx) - pkrb5_free_context(ctx); - - return 0; -} - - -int -KFW_destroy_tickets_for_principal(char * user) -{ - krb5_context ctx = 0; - krb5_error_code code; - krb5_principal princ = 0; - krb5_ccache cc = 0; - - if (!pkrb5_init_context) - return 0; - - code = pkrb5_init_context(&ctx); - if (code) return 1; - - code = pkrb5_parse_name(ctx, user, &princ); - if (code) goto loop_cleanup; - - code = KFW_get_ccache(ctx, princ, &cc); - if (code) goto loop_cleanup; - - code = pkrb5_cc_destroy(ctx, cc); - if (!code) cc = 0; - - loop_cleanup: - if ( cc ) { - pkrb5_cc_close(ctx, cc); - cc = 0; - } - if ( princ ) { - pkrb5_free_principal(ctx, princ); - princ = 0; - } - - pkrb5_free_context(ctx); - return 0; -} - - -/* There are scenarios in which an interactive logon will not - * result in the LogonScript being executed. This will result - * in orphaned cache files being left in the Temp directory. - * This function will search for cache files in the Temp - * directory and delete any that are older than five minutes. - */ -void -KFW_cleanup_orphaned_caches(void) -{ - char * temppath = NULL; - char * curdir = NULL; - DWORD count, count2; - WIN32_FIND_DATA FindFileData; - HANDLE hFind = INVALID_HANDLE_VALUE; - FILETIME now; - ULARGE_INTEGER uli_now; - FILETIME expired; - - count = GetTempPath(0, NULL); - if (count <= 0) - return; - temppath = (char *) malloc(count); - if (!temppath) - goto cleanup; - count2 = GetTempPath(count, temppath); - if (count2 <= 0 || count2 > count) - goto cleanup; - - count = GetCurrentDirectory(0, NULL); - curdir = (char *)malloc(count); - if (!curdir) - goto cleanup; - count2 = GetCurrentDirectory(count, curdir); - if (count2 <= 0 || count2 > count) - goto cleanup; - - if (!SetCurrentDirectory(temppath)) - goto cleanup; - - GetSystemTimeAsFileTime(&now); - uli_now.u.LowPart = now.dwLowDateTime; - uli_now.u.HighPart = now.dwHighDateTime; - - uli_now.QuadPart -= 3000000000; /* 5 minutes == 3 billion 100 nano seconds */ - - expired.dwLowDateTime = uli_now.u.LowPart; - expired.dwHighDateTime = uli_now.u.HighPart; - - hFind = FindFirstFile("kfwlogon-*", &FindFileData); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if (CompareFileTime(&FindFileData.ftCreationTime, &expired) < 0) { - DebugEvent("Deleting orphaned cache file: \"%s\"", FindFileData.cFileName); - DeleteFile(FindFileData.cFileName); - } - } while ( FindNextFile(hFind, &FindFileData) ); - } - - SetCurrentDirectory(curdir); - - cleanup: - if (temppath) - free(temppath); - if (hFind != INVALID_HANDLE_VALUE) - FindClose(hFind); - if (curdir) - free(curdir); -} +/* +Copyright 2005,2006 by the Massachusetts Institute of Technology +Copyright 2007 by Secure Endpoints Inc. + +All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of the Massachusetts +Institute of Technology (M.I.T.) not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. + +M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ + +#include "kfwlogon.h" +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +/* Function Pointer Declarations for Delayed Loading */ +// CCAPI +DECL_FUNC_PTR(cc_initialize); +DECL_FUNC_PTR(cc_shutdown); +DECL_FUNC_PTR(cc_get_NC_info); +DECL_FUNC_PTR(cc_free_NC_info); + +// leash functions +DECL_FUNC_PTR(Leash_get_default_lifetime); +DECL_FUNC_PTR(Leash_get_default_forwardable); +DECL_FUNC_PTR(Leash_get_default_renew_till); +DECL_FUNC_PTR(Leash_get_default_noaddresses); +DECL_FUNC_PTR(Leash_get_default_proxiable); +DECL_FUNC_PTR(Leash_get_default_publicip); +DECL_FUNC_PTR(Leash_get_default_use_krb4); +DECL_FUNC_PTR(Leash_get_default_life_min); +DECL_FUNC_PTR(Leash_get_default_life_max); +DECL_FUNC_PTR(Leash_get_default_renew_min); +DECL_FUNC_PTR(Leash_get_default_renew_max); +DECL_FUNC_PTR(Leash_get_default_renewable); +DECL_FUNC_PTR(Leash_get_default_mslsa_import); + +// krb5 functions +DECL_FUNC_PTR(krb5_change_password); +DECL_FUNC_PTR(krb5_get_init_creds_opt_init); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list); +DECL_FUNC_PTR(krb5_get_init_creds_password); +DECL_FUNC_PTR(krb5_build_principal_ext); +DECL_FUNC_PTR(krb5_cc_get_name); +DECL_FUNC_PTR(krb5_cc_resolve); +DECL_FUNC_PTR(krb5_cc_default); +DECL_FUNC_PTR(krb5_cc_default_name); +DECL_FUNC_PTR(krb5_cc_set_default_name); +DECL_FUNC_PTR(krb5_cc_initialize); +DECL_FUNC_PTR(krb5_cc_destroy); +DECL_FUNC_PTR(krb5_cc_close); +DECL_FUNC_PTR(krb5_cc_store_cred); +DECL_FUNC_PTR(krb5_cc_copy_creds); +DECL_FUNC_PTR(krb5_cc_retrieve_cred); +DECL_FUNC_PTR(krb5_cc_get_principal); +DECL_FUNC_PTR(krb5_cc_start_seq_get); +DECL_FUNC_PTR(krb5_cc_next_cred); +DECL_FUNC_PTR(krb5_cc_end_seq_get); +DECL_FUNC_PTR(krb5_cc_remove_cred); +DECL_FUNC_PTR(krb5_cc_set_flags); +DECL_FUNC_PTR(krb5_cc_get_type); +DECL_FUNC_PTR(krb5_free_context); +DECL_FUNC_PTR(krb5_free_cred_contents); +DECL_FUNC_PTR(krb5_free_principal); +DECL_FUNC_PTR(krb5_get_in_tkt_with_password); +DECL_FUNC_PTR(krb5_init_context); +DECL_FUNC_PTR(krb5_parse_name); +DECL_FUNC_PTR(krb5_timeofday); +DECL_FUNC_PTR(krb5_timestamp_to_sfstring); +DECL_FUNC_PTR(krb5_unparse_name); +DECL_FUNC_PTR(krb5_get_credentials); +DECL_FUNC_PTR(krb5_mk_req); +DECL_FUNC_PTR(krb5_sname_to_principal); +DECL_FUNC_PTR(krb5_get_credentials_renew); +DECL_FUNC_PTR(krb5_free_data); +DECL_FUNC_PTR(krb5_free_data_contents); +DECL_FUNC_PTR(krb5_free_unparsed_name); +DECL_FUNC_PTR(krb5_os_localaddr); +DECL_FUNC_PTR(krb5_copy_keyblock_contents); +DECL_FUNC_PTR(krb5_copy_data); +DECL_FUNC_PTR(krb5_free_creds); +DECL_FUNC_PTR(krb5_build_principal); +DECL_FUNC_PTR(krb5_get_renewed_creds); +DECL_FUNC_PTR(krb5_get_default_config_files); +DECL_FUNC_PTR(krb5_free_config_files); +DECL_FUNC_PTR(krb5_get_default_realm); +DECL_FUNC_PTR(krb5_free_default_realm); +DECL_FUNC_PTR(krb5_free_ticket); +DECL_FUNC_PTR(krb5_decode_ticket); +DECL_FUNC_PTR(krb5_get_host_realm); +DECL_FUNC_PTR(krb5_free_host_realm); +DECL_FUNC_PTR(krb5_free_addresses); +DECL_FUNC_PTR(krb5_c_random_make_octets); + +// ComErr functions +DECL_FUNC_PTR(com_err); +DECL_FUNC_PTR(error_message); + +// Profile functions +DECL_FUNC_PTR(profile_init); +DECL_FUNC_PTR(profile_release); +DECL_FUNC_PTR(profile_get_subsection_names); +DECL_FUNC_PTR(profile_free_list); +DECL_FUNC_PTR(profile_get_string); +DECL_FUNC_PTR(profile_release_string); + +// Service functions +DECL_FUNC_PTR(OpenSCManagerA); +DECL_FUNC_PTR(OpenServiceA); +DECL_FUNC_PTR(QueryServiceStatus); +DECL_FUNC_PTR(CloseServiceHandle); +DECL_FUNC_PTR(LsaNtStatusToWinError); + +// LSA Functions +DECL_FUNC_PTR(LsaConnectUntrusted); +DECL_FUNC_PTR(LsaLookupAuthenticationPackage); +DECL_FUNC_PTR(LsaCallAuthenticationPackage); +DECL_FUNC_PTR(LsaFreeReturnBuffer); +DECL_FUNC_PTR(LsaGetLogonSessionData); + +// CCAPI +FUNC_INFO ccapi_fi[] = { + MAKE_FUNC_INFO(cc_initialize), + MAKE_FUNC_INFO(cc_shutdown), + MAKE_FUNC_INFO(cc_get_NC_info), + MAKE_FUNC_INFO(cc_free_NC_info), + END_FUNC_INFO +}; + +FUNC_INFO leash_fi[] = { + MAKE_FUNC_INFO(Leash_get_default_lifetime), + MAKE_FUNC_INFO(Leash_get_default_renew_till), + MAKE_FUNC_INFO(Leash_get_default_forwardable), + MAKE_FUNC_INFO(Leash_get_default_noaddresses), + MAKE_FUNC_INFO(Leash_get_default_proxiable), + MAKE_FUNC_INFO(Leash_get_default_publicip), + MAKE_FUNC_INFO(Leash_get_default_use_krb4), + MAKE_FUNC_INFO(Leash_get_default_life_min), + MAKE_FUNC_INFO(Leash_get_default_life_max), + MAKE_FUNC_INFO(Leash_get_default_renew_min), + MAKE_FUNC_INFO(Leash_get_default_renew_max), + MAKE_FUNC_INFO(Leash_get_default_renewable), + END_FUNC_INFO +}; + +FUNC_INFO leash_opt_fi[] = { + MAKE_FUNC_INFO(Leash_get_default_mslsa_import), + END_FUNC_INFO +}; + +FUNC_INFO k5_fi[] = { + MAKE_FUNC_INFO(krb5_change_password), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_init), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list), + MAKE_FUNC_INFO(krb5_get_init_creds_password), + MAKE_FUNC_INFO(krb5_build_principal_ext), + MAKE_FUNC_INFO(krb5_cc_get_name), + MAKE_FUNC_INFO(krb5_cc_resolve), + MAKE_FUNC_INFO(krb5_cc_default), + MAKE_FUNC_INFO(krb5_cc_default_name), + MAKE_FUNC_INFO(krb5_cc_set_default_name), + MAKE_FUNC_INFO(krb5_cc_initialize), + MAKE_FUNC_INFO(krb5_cc_destroy), + MAKE_FUNC_INFO(krb5_cc_close), + MAKE_FUNC_INFO(krb5_cc_copy_creds), + MAKE_FUNC_INFO(krb5_cc_store_cred), + MAKE_FUNC_INFO(krb5_cc_retrieve_cred), + MAKE_FUNC_INFO(krb5_cc_get_principal), + MAKE_FUNC_INFO(krb5_cc_start_seq_get), + MAKE_FUNC_INFO(krb5_cc_next_cred), + MAKE_FUNC_INFO(krb5_cc_end_seq_get), + MAKE_FUNC_INFO(krb5_cc_remove_cred), + MAKE_FUNC_INFO(krb5_cc_set_flags), + MAKE_FUNC_INFO(krb5_cc_get_type), + MAKE_FUNC_INFO(krb5_free_context), + MAKE_FUNC_INFO(krb5_free_cred_contents), + MAKE_FUNC_INFO(krb5_free_principal), + MAKE_FUNC_INFO(krb5_get_in_tkt_with_password), + MAKE_FUNC_INFO(krb5_init_context), + MAKE_FUNC_INFO(krb5_parse_name), + MAKE_FUNC_INFO(krb5_timeofday), + MAKE_FUNC_INFO(krb5_timestamp_to_sfstring), + MAKE_FUNC_INFO(krb5_unparse_name), + MAKE_FUNC_INFO(krb5_get_credentials), + MAKE_FUNC_INFO(krb5_mk_req), + MAKE_FUNC_INFO(krb5_sname_to_principal), + MAKE_FUNC_INFO(krb5_get_credentials_renew), + MAKE_FUNC_INFO(krb5_free_data), + MAKE_FUNC_INFO(krb5_free_data_contents), + MAKE_FUNC_INFO(krb5_free_unparsed_name), + MAKE_FUNC_INFO(krb5_os_localaddr), + MAKE_FUNC_INFO(krb5_copy_keyblock_contents), + MAKE_FUNC_INFO(krb5_copy_data), + MAKE_FUNC_INFO(krb5_free_creds), + MAKE_FUNC_INFO(krb5_build_principal), + MAKE_FUNC_INFO(krb5_get_renewed_creds), + MAKE_FUNC_INFO(krb5_free_addresses), + MAKE_FUNC_INFO(krb5_get_default_config_files), + MAKE_FUNC_INFO(krb5_free_config_files), + MAKE_FUNC_INFO(krb5_get_default_realm), + MAKE_FUNC_INFO(krb5_free_default_realm), + MAKE_FUNC_INFO(krb5_free_ticket), + MAKE_FUNC_INFO(krb5_decode_ticket), + MAKE_FUNC_INFO(krb5_get_host_realm), + MAKE_FUNC_INFO(krb5_free_host_realm), + MAKE_FUNC_INFO(krb5_free_addresses), + MAKE_FUNC_INFO(krb5_c_random_make_octets), + END_FUNC_INFO +}; + +FUNC_INFO profile_fi[] = { + MAKE_FUNC_INFO(profile_init), + MAKE_FUNC_INFO(profile_release), + MAKE_FUNC_INFO(profile_get_subsection_names), + MAKE_FUNC_INFO(profile_free_list), + MAKE_FUNC_INFO(profile_get_string), + MAKE_FUNC_INFO(profile_release_string), + END_FUNC_INFO +}; + +FUNC_INFO ce_fi[] = { + MAKE_FUNC_INFO(com_err), + MAKE_FUNC_INFO(error_message), + END_FUNC_INFO +}; + +FUNC_INFO service_fi[] = { + MAKE_FUNC_INFO(OpenSCManagerA), + MAKE_FUNC_INFO(OpenServiceA), + MAKE_FUNC_INFO(QueryServiceStatus), + MAKE_FUNC_INFO(CloseServiceHandle), + MAKE_FUNC_INFO(LsaNtStatusToWinError), + END_FUNC_INFO +}; + +FUNC_INFO lsa_fi[] = { + MAKE_FUNC_INFO(LsaConnectUntrusted), + MAKE_FUNC_INFO(LsaLookupAuthenticationPackage), + MAKE_FUNC_INFO(LsaCallAuthenticationPackage), + MAKE_FUNC_INFO(LsaFreeReturnBuffer), + MAKE_FUNC_INFO(LsaGetLogonSessionData), + END_FUNC_INFO +}; + +/* Static Declarations */ +static int inited = 0; +static HINSTANCE hKrb5 = 0; +static HINSTANCE hKrb524 = 0; +static HINSTANCE hSecur32 = 0; +static HINSTANCE hAdvApi32 = 0; +static HINSTANCE hComErr = 0; +static HINSTANCE hService = 0; +static HINSTANCE hProfile = 0; +static HINSTANCE hLeash = 0; +static HINSTANCE hLeashOpt = 0; +static HINSTANCE hCCAPI = 0; + +static DWORD TraceOption = 0; +static HANDLE hDLL; + +BOOL IsDebugLogging(void) +{ + DWORD LSPsize; + HKEY NPKey; + DWORD dwDebug = FALSE; + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, + "System\\CurrentControlSet\\Services\\MIT Kerberos\\NetworkProvider", + 0, KEY_QUERY_VALUE, &NPKey) == ERROR_SUCCESS) + { + LSPsize=sizeof(dwDebug); + if (RegQueryValueEx(NPKey, "Debug", NULL, NULL, (LPBYTE)&dwDebug, &LSPsize) != ERROR_SUCCESS) + { + dwDebug = FALSE; + } + RegCloseKey (NPKey); + } + + return(dwDebug ? TRUE : FALSE); +} + +void DebugEvent0(char *a) +{ + HANDLE h; char *ptbuf[1]; + + if (IsDebugLogging()) { + h = RegisterEventSource(NULL, KFW_LOGON_EVENT_NAME); + if (h) { + ptbuf[0] = a; + ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL); + DeregisterEventSource(h); + } + } +} + +#define MAXBUF_ 512 +void DebugEvent(char *b,...) +{ + HANDLE h; char *ptbuf[1],buf[MAXBUF_+1]; + va_list marker; + + if (IsDebugLogging()) { + h = RegisterEventSource(NULL, KFW_LOGON_EVENT_NAME); + if (h) { + va_start(marker,b); + StringCbVPrintf(buf, MAXBUF_+1,b,marker); + buf[MAXBUF_] = '\0'; + ptbuf[0] = buf; + ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL); + DeregisterEventSource(h); + va_end(marker); + } + } +} + +void +UnloadFuncs( + FUNC_INFO fi[], + HINSTANCE h + ) +{ + int n; + if (fi) + for (n = 0; fi[n].func_ptr_var; n++) + *(fi[n].func_ptr_var) = 0; + if (h) FreeLibrary(h); +} + +int +LoadFuncs( + const char* dll_name, + FUNC_INFO fi[], + HINSTANCE* ph, // [out, optional] - DLL handle + int* pindex, // [out, optional] - index of last func loaded (-1 if none) + int cleanup, // cleanup function pointers and unload on error + int go_on, // continue loading even if some functions cannot be loaded + int silent // do not pop-up a system dialog if DLL cannot be loaded + ) +{ + HINSTANCE h; + int i, n, last_i; + int error = 0; + UINT em; + + if (ph) *ph = 0; + if (pindex) *pindex = -1; + + for (n = 0; fi[n].func_ptr_var; n++) + *(fi[n].func_ptr_var) = 0; + + if (silent) + em = SetErrorMode(SEM_FAILCRITICALERRORS); + h = LoadLibrary(dll_name); + if (silent) + SetErrorMode(em); + + if (!h) + return 0; + + last_i = -1; + for (i = 0; (go_on || !error) && (i < n); i++) + { + void* p = (void*)GetProcAddress(h, fi[i].func_name); + if (!p) + error = 1; + else + { + last_i = i; + *(fi[i].func_ptr_var) = p; + } + } + if (pindex) *pindex = last_i; + if (error && cleanup && !go_on) { + for (i = 0; i < n; i++) { + *(fi[i].func_ptr_var) = 0; + } + FreeLibrary(h); + return 0; + } + if (ph) *ph = h; + if (error) return 0; + return 1; +} + +static HANDLE hInitMutex = NULL; +static BOOL bInit = FALSE; + +/* KFW_initialize cannot be called from DllEntryPoint */ +void +KFW_initialize(void) +{ + static int inited = 0; + + if ( !inited ) { + char mutexName[MAX_PATH]; + HANDLE hMutex = NULL; + + sprintf(mutexName, "AFS KFW Init pid=%d", getpid()); + + hMutex = CreateMutex( NULL, TRUE, mutexName ); + if ( GetLastError() == ERROR_ALREADY_EXISTS ) { + if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) { + return; + } + } + if ( !inited ) { + inited = 1; + LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0); + LoadFuncs(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(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0); + LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0); + LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0); + LoadFuncs(LEASH_DLL, leash_opt_fi, &hLeashOpt, 0, 1, 0, 0); + } + ReleaseMutex(hMutex); + CloseHandle(hMutex); + } +} + +void +KFW_cleanup(void) +{ + if (hLeashOpt) + FreeLibrary(hLeashOpt); + if (hCCAPI) + FreeLibrary(hCCAPI); + if (hLeash) + FreeLibrary(hLeash); + if (hKrb524) + FreeLibrary(hKrb524); + if (hSecur32) + FreeLibrary(hSecur32); + if (hService) + FreeLibrary(hService); + if (hComErr) + FreeLibrary(hComErr); + if (hProfile) + FreeLibrary(hProfile); + if (hKrb5) + FreeLibrary(hKrb5); +} + + +int +KFW_is_available(void) +{ + KFW_initialize(); + if ( hKrb5 && hComErr && hService && +#ifdef USE_MS2MIT + hSecur32 && +#endif /* USE_MS2MIT */ + hProfile && hLeash && hCCAPI ) + return TRUE; + + return FALSE; +} + +/* Given a principal return an existing ccache or create one and return */ +int +KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc) +{ + krb5_context ctx; + char * pname = 0; + char * ccname = 0; + krb5_error_code code; + + if (!pkrb5_init_context) + return 0; + + if ( alt_ctx ) { + ctx = alt_ctx; + } else { + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + } + + if ( principal ) { + code = pkrb5_unparse_name(ctx, principal, &pname); + if (code) goto cleanup; + + ccname = (char *)malloc(strlen(pname) + 5); + sprintf(ccname,"API:%s",pname); + + DebugEvent0(ccname); + code = pkrb5_cc_resolve(ctx, ccname, cc); + } else { + code = pkrb5_cc_default(ctx, cc); + if (code) goto cleanup; + } + + cleanup: + if (ccname) + free(ccname); + if (pname) + pkrb5_free_unparsed_name(ctx,pname); + if (ctx && (ctx != alt_ctx)) + pkrb5_free_context(ctx); + return(code); +} + + +int +KFW_kinit( krb5_context alt_ctx, + krb5_ccache alt_cc, + HWND hParent, + char *principal_name, + char *password, + krb5_deltat lifetime, + DWORD forwardable, + DWORD proxiable, + krb5_deltat renew_life, + DWORD addressless, + DWORD publicIP + ) +{ + krb5_error_code code = 0; + krb5_context ctx = 0; + krb5_ccache cc = 0; + krb5_principal me = 0; + char* name = 0; + krb5_creds my_creds; + krb5_get_init_creds_opt options; + krb5_address ** addrs = NULL; + int i = 0, addr_count = 0; + + if (!pkrb5_init_context) + return 0; + + pkrb5_get_init_creds_opt_init(&options); + memset(&my_creds, 0, sizeof(my_creds)); + + if (alt_ctx) + { + ctx = alt_ctx; + } + else + { + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + } + + if ( alt_cc ) { + cc = alt_cc; + } else { + code = pkrb5_cc_default(ctx, &cc); + if (code) goto cleanup; + } + + code = pkrb5_parse_name(ctx, principal_name, &me); + if (code) + goto cleanup; + + code = pkrb5_unparse_name(ctx, me, &name); + if (code) + goto cleanup; + + if (lifetime == 0) + lifetime = pLeash_get_default_lifetime(); + lifetime *= 60; + + if (renew_life > 0) + renew_life *= 60; + + if (lifetime) + pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime); + pkrb5_get_init_creds_opt_set_forwardable(&options, + forwardable ? 1 : 0); + pkrb5_get_init_creds_opt_set_proxiable(&options, + proxiable ? 1 : 0); + pkrb5_get_init_creds_opt_set_renew_life(&options, + renew_life); + if (addressless) + pkrb5_get_init_creds_opt_set_address_list(&options,NULL); + else { + if (publicIP) + { + // we are going to add the public IP address specified by the user + // to the list provided by the operating system + krb5_address ** local_addrs=NULL; + DWORD netIPAddr; + + pkrb5_os_localaddr(ctx, &local_addrs); + while ( local_addrs[i++] ); + addr_count = i + 1; + + addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *)); + if ( !addrs ) { + pkrb5_free_addresses(ctx, local_addrs); + goto cleanup; + } + memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1)); + i = 0; + while ( local_addrs[i] ) { + addrs[i] = (krb5_address *)malloc(sizeof(krb5_address)); + if (addrs[i] == NULL) { + pkrb5_free_addresses(ctx, local_addrs); + goto cleanup; + } + + addrs[i]->magic = local_addrs[i]->magic; + addrs[i]->addrtype = local_addrs[i]->addrtype; + addrs[i]->length = local_addrs[i]->length; + addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length); + if (!addrs[i]->contents) { + pkrb5_free_addresses(ctx, local_addrs); + goto cleanup; + } + + memcpy(addrs[i]->contents,local_addrs[i]->contents, + local_addrs[i]->length); /* safe */ + i++; + } + pkrb5_free_addresses(ctx, local_addrs); + + addrs[i] = (krb5_address *)malloc(sizeof(krb5_address)); + if (addrs[i] == NULL) + goto cleanup; + + addrs[i]->magic = KV5M_ADDRESS; + addrs[i]->addrtype = AF_INET; + addrs[i]->length = 4; + addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length); + if (!addrs[i]->contents) + goto cleanup; + + netIPAddr = htonl(publicIP); + memcpy(addrs[i]->contents,&netIPAddr,4); + + pkrb5_get_init_creds_opt_set_address_list(&options,addrs); + + } + } + + code = pkrb5_get_init_creds_password(ctx, + &my_creds, + me, + password, // password + NULL, // no prompter + hParent, // prompter data + 0, // start time + 0, // service name + &options); + if (code) + goto cleanup; + + code = pkrb5_cc_initialize(ctx, cc, me); + if (code) + goto cleanup; + + code = pkrb5_cc_store_cred(ctx, cc, &my_creds); + if (code) + goto cleanup; + + cleanup: + if ( addrs ) { + for ( i=0;icontents ) + free(addrs[i]->contents); + free(addrs[i]); + } + } + } + if (my_creds.client == me) + my_creds.client = 0; + pkrb5_free_cred_contents(ctx, &my_creds); + if (name) + pkrb5_free_unparsed_name(ctx, name); + if (me) + pkrb5_free_principal(ctx, me); + if (cc && (cc != alt_cc)) + pkrb5_cc_close(ctx, cc); + if (ctx && (ctx != alt_ctx)) + pkrb5_free_context(ctx); + return(code); +} + + +int +KFW_get_cred( char * username, + char * password, + int lifetime, + char ** reasonP ) +{ + krb5_context ctx = 0; + krb5_ccache cc = 0; + char * realm = 0; + krb5_principal principal = 0; + char * pname = 0; + krb5_error_code code; + + if (!pkrb5_init_context || !username || !password || !password[0]) + return 0; + + DebugEvent0(username); + + code = pkrb5_init_context(&ctx); + if ( code ) goto cleanup; + + code = pkrb5_get_default_realm(ctx, &realm); + + if (realm) { + pname = malloc(strlen(username) + strlen(realm) + 2); + if (!pname) + goto cleanup; + strcpy(pname, username); + strcat(pname, "@"); + strcat(pname, realm); + } else { + goto cleanup; + } + + DebugEvent0(realm); + DebugEvent0(pname); + + code = pkrb5_parse_name(ctx, pname, &principal); + if ( code ) goto cleanup; + + DebugEvent0("parsed name"); + code = KFW_get_ccache(ctx, principal, &cc); + if ( code ) goto cleanup; + + DebugEvent0("got ccache"); + + if ( lifetime == 0 ) + lifetime = pLeash_get_default_lifetime(); + + DebugEvent0("got lifetime"); + + code = KFW_kinit( ctx, cc, HWND_DESKTOP, + pname, + password, + lifetime, + pLeash_get_default_forwardable(), + pLeash_get_default_proxiable(), + pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0, + pLeash_get_default_noaddresses(), + pLeash_get_default_publicip()); + DebugEvent0("kinit returned"); + if ( code ) goto cleanup; + + cleanup: + if ( pname ) + free(pname); + if ( realm ) + pkrb5_free_default_realm(ctx, realm); + if ( cc ) + pkrb5_cc_close(ctx, cc); + + if ( code && reasonP ) { + *reasonP = (char *)perror_message(code); + } + return(code); +} + +int KFW_set_ccache_dacl(char *filename, HANDLE hUserToken) +{ + // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY; + PSID pSystemSID = NULL; + DWORD SystemSIDlength = 0, UserSIDlength = 0; + PACL ccacheACL = NULL; + DWORD ccacheACLlength = 0; + PTOKEN_USER pTokenUser = NULL; + DWORD retLen; + DWORD gle; + int ret = 0; + + if (!filename) { + DebugEvent0("KFW_set_ccache_dacl - invalid parms"); + return 1; + } + + DebugEvent0("KFW_set_ccache_dacl"); + + /* Get System SID */ + if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) { + DebugEvent("KFW_set_ccache_dacl - ConvertStringSidToSid GLE = 0x%x", GetLastError()); + ret = 1; + goto cleanup; + } + + /* Create ACL */ + SystemSIDlength = GetLengthSid(pSystemSID); + ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + + SystemSIDlength - sizeof(DWORD); + + if (hUserToken) { + if (!GetTokenInformation(hUserToken, TokenUser, NULL, 0, &retLen)) + { + if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) { + pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen); + + if (!GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen)) + { + DebugEvent("GetTokenInformation failed: GLE = %lX", GetLastError()); + } + } + } + + if (pTokenUser) { + UserSIDlength = GetLengthSid(pTokenUser->User.Sid); + + ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength + - sizeof(DWORD); + } + } + + ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength); + if (!ccacheACL) { + DebugEvent("KFW_set_ccache_dacl - LocalAlloc GLE = 0x%x", GetLastError()); + ret = 1; + goto cleanup; + } + + InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION); + AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0, + STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, + pSystemSID); + if (pTokenUser) { + AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0, + STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, + pTokenUser->User.Sid); + if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT, + DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, + NULL, + NULL, + ccacheACL, + NULL)) { + gle = GetLastError(); + DebugEvent("SetNamedSecurityInfo DACL (1) failed: GLE = 0x%lX", gle); + if (gle != ERROR_NO_TOKEN) + ret = 1; + } + if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION, + pTokenUser->User.Sid, + NULL, + NULL, + NULL)) { + gle = GetLastError(); + DebugEvent("SetNamedSecurityInfo OWNER (2) failed: GLE = 0x%lX", gle); + if (gle != ERROR_NO_TOKEN) + ret = 1; + } + } else { + if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT, + DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, + NULL, + NULL, + ccacheACL, + NULL)) { + gle = GetLastError(); + DebugEvent("SetNamedSecurityInfo DACL (3) failed: GLE = 0x%lX", gle); + if (gle != ERROR_NO_TOKEN) + ret = 1; + } + } + + cleanup: + if (pSystemSID) + LocalFree(pSystemSID); + if (pTokenUser) + LocalFree(pTokenUser); + if (ccacheACL) + LocalFree(ccacheACL); + return ret; +} + +int KFW_set_ccache_dacl_with_user_sid(char *filename, PSID pUserSID) +{ + // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY; + PSID pSystemSID = NULL; + DWORD SystemSIDlength = 0, UserSIDlength = 0; + PACL ccacheACL = NULL; + DWORD ccacheACLlength = 0; + DWORD gle; + int ret = 0; + + if (!filename) { + DebugEvent0("KFW_set_ccache_dacl_with_user_sid - invalid parms"); + return 1; + } + + DebugEvent0("KFW_set_ccache_dacl_with_user_sid"); + + /* Get System SID */ + if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) { + DebugEvent("KFW_set_ccache_dacl - ConvertStringSidToSid GLE = 0x%x", GetLastError()); + ret = 1; + goto cleanup; + } + + /* Create ACL */ + SystemSIDlength = GetLengthSid(pSystemSID); + ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + + SystemSIDlength - sizeof(DWORD); + + if (pUserSID) { + UserSIDlength = GetLengthSid(pUserSID); + + ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength + - sizeof(DWORD); + } + + ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength); + if (!ccacheACL) { + DebugEvent("KFW_set_ccache_dacl - LocalAlloc GLE = 0x%x", GetLastError()); + ret = 1; + goto cleanup; + } + + InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION); + AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0, + STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, + pSystemSID); + if (pUserSID) { + AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0, + STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, + pUserSID); + if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT, + DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, + NULL, + NULL, + ccacheACL, + NULL)) { + gle = GetLastError(); + DebugEvent("SetNamedSecurityInfo DACL (4) failed: GLE = 0x%lX", gle); + if (gle != ERROR_NO_TOKEN) + ret = 1; + } + if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION, + pUserSID, + NULL, + NULL, + NULL)) { + gle = GetLastError(); + DebugEvent("SetNamedSecurityInfo OWNER (5) failed: GLE = 0x%lX", gle); + if (gle != ERROR_NO_TOKEN) + ret = 1; + } + } else { + if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT, + DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, + NULL, + NULL, + ccacheACL, + NULL)) { + gle = GetLastError(); + DebugEvent("SetNamedSecurityInfo DACL (6) failed: GLE = 0x%lX", gle); + if (gle != ERROR_NO_TOKEN) + ret = 1; + } + } + + cleanup: + if (pSystemSID) + LocalFree(pSystemSID); + if (ccacheACL) + LocalFree(ccacheACL); + return ret; +} + +int KFW_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size) +{ + int retval = 0; + DWORD dwSize = size-1; /* leave room for nul */ + DWORD dwLen = 0; + + if (!hUserToken || !newfilename || size <= 0) + return 1; + + *newfilename = '\0'; + + dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize); + if ( !dwLen || dwLen > dwSize ) + dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize); + if ( !dwLen || dwLen > dwSize ) + return 1; + + newfilename[dwSize] = '\0'; + return 0; +} + +void +KFW_copy_cache_to_system_file(const char * user, const char * filename) +{ + char cachename[MAX_PATH + 8] = "FILE:"; + krb5_context ctx = 0; + krb5_error_code code; + krb5_principal princ = 0; + krb5_ccache cc = 0; + krb5_ccache ncc = 0; + PSECURITY_ATTRIBUTES pSA = NULL; + + if (!pkrb5_init_context || !user || !filename) + return; + + strncat(cachename, filename, sizeof(cachename)); + cachename[sizeof(cachename)-1] = '\0'; + + DebugEvent("KFW_Logon_Event - ccache %s", cachename); + + DeleteFile(filename); + + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + + code = pkrb5_parse_name(ctx, user, &princ); + if (code) goto cleanup; + + code = KFW_get_ccache(ctx, princ, &cc); + if (code) goto cleanup; + + code = pkrb5_cc_resolve(ctx, cachename, &ncc); + if (code) goto cleanup; + + code = pkrb5_cc_initialize(ctx, ncc, princ); + if (code) goto cleanup; + + code = KFW_set_ccache_dacl(filename, NULL); + if (code) goto cleanup; + + code = pkrb5_cc_copy_creds(ctx,cc,ncc); + + cleanup: + if ( cc ) { + pkrb5_cc_close(ctx, cc); + cc = 0; + } + if ( ncc ) { + pkrb5_cc_close(ctx, ncc); + ncc = 0; + } + if ( princ ) { + pkrb5_free_principal(ctx, princ); + princ = 0; + } + + if (ctx) + pkrb5_free_context(ctx); +} + +int +KFW_copy_file_cache_to_default_cache(char * filename) +{ + char cachename[MAX_PATH + 8] = "FILE:"; + krb5_context ctx = 0; + krb5_error_code code; + krb5_principal princ = 0; + krb5_ccache cc = 0; + krb5_ccache ncc = 0; + int retval = 1; + + if (!pkrb5_init_context || !filename) + return 1; + + if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) ) + return 1; + + code = pkrb5_init_context(&ctx); + if (code) return 1; + + strcat(cachename, filename); + + code = pkrb5_cc_resolve(ctx, cachename, &cc); + if (code) { + DebugEvent0("kfwcpcc krb5_cc_resolve failed"); + goto cleanup; + } + + code = pkrb5_cc_get_principal(ctx, cc, &princ); + if (code) { + DebugEvent0("kfwcpcc krb5_cc_get_principal failed"); + goto cleanup; + } + + code = pkrb5_cc_default(ctx, &ncc); + if (code) { + DebugEvent0("kfwcpcc krb5_cc_default failed"); + goto cleanup; + } + if (!code) { + code = pkrb5_cc_initialize(ctx, ncc, princ); + + if (!code) + code = pkrb5_cc_copy_creds(ctx,cc,ncc); + if (code) { + DebugEvent0("kfwcpcc krb5_cc_copy_creds failed"); + goto cleanup; + } + } + if ( ncc ) { + pkrb5_cc_close(ctx, ncc); + ncc = 0; + } + + retval=0; /* success */ + + cleanup: + if ( cc ) { + pkrb5_cc_close(ctx, cc); + cc = 0; + } + + DeleteFile(filename); + + if ( princ ) { + pkrb5_free_principal(ctx, princ); + princ = 0; + } + + if (ctx) + pkrb5_free_context(ctx); + + return 0; +} + + +int +KFW_copy_file_cache_to_api_cache(char * filename) +{ + char cachename[MAX_PATH + 8] = "FILE:"; + krb5_context ctx = 0; + krb5_error_code code; + krb5_principal princ = 0; + krb5_ccache cc = 0; + krb5_ccache ncc = 0; + char *name = NULL; + int retval = 1; + + if (!pkrb5_init_context || !filename) + return 1; + + if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) ) + return 1; + + code = pkrb5_init_context(&ctx); + if (code) return 1; + + strcat(cachename, filename); + + code = pkrb5_cc_resolve(ctx, cachename, &cc); + if (code) { + DebugEvent0("kfwcpcc krb5_cc_resolve failed"); + goto cleanup; + } + + code = pkrb5_cc_get_principal(ctx, cc, &princ); + if (code) { + DebugEvent0("kfwcpcc krb5_cc_get_principal failed"); + goto cleanup; + } + + code = pkrb5_unparse_name(ctx, princ, &name); + if (code) { + DebugEvent0("kfwcpcc krb5_unparse_name failed"); + goto cleanup; + } + + sprintf(cachename, "API:%s", name); + + code = pkrb5_cc_resolve(ctx, cachename, &ncc); + if (code) { + DebugEvent0("kfwcpcc krb5_cc_default failed"); + goto cleanup; + } + if (!code) { + code = pkrb5_cc_initialize(ctx, ncc, princ); + + if (!code) + code = pkrb5_cc_copy_creds(ctx,cc,ncc); + if (code) { + DebugEvent0("kfwcpcc krb5_cc_copy_creds failed"); + goto cleanup; + } + } + if ( ncc ) { + pkrb5_cc_close(ctx, ncc); + ncc = 0; + } + + retval=0; /* success */ + + cleanup: + if (name) + pkrb5_free_unparsed_name(ctx, name); + + if ( cc ) { + pkrb5_cc_close(ctx, cc); + cc = 0; + } + + DeleteFile(filename); + + if ( princ ) { + pkrb5_free_principal(ctx, princ); + princ = 0; + } + + if (ctx) + pkrb5_free_context(ctx); + + return 0; +} + + +int +KFW_destroy_tickets_for_principal(char * user) +{ + krb5_context ctx = 0; + krb5_error_code code; + krb5_principal princ = 0; + krb5_ccache cc = 0; + + if (!pkrb5_init_context) + return 0; + + code = pkrb5_init_context(&ctx); + if (code) return 1; + + code = pkrb5_parse_name(ctx, user, &princ); + if (code) goto loop_cleanup; + + code = KFW_get_ccache(ctx, princ, &cc); + if (code) goto loop_cleanup; + + code = pkrb5_cc_destroy(ctx, cc); + if (!code) cc = 0; + + loop_cleanup: + if ( cc ) { + pkrb5_cc_close(ctx, cc); + cc = 0; + } + if ( princ ) { + pkrb5_free_principal(ctx, princ); + princ = 0; + } + + pkrb5_free_context(ctx); + return 0; +} + + +/* There are scenarios in which an interactive logon will not + * result in the LogonScript being executed. This will result + * in orphaned cache files being left in the Temp directory. + * This function will search for cache files in the Temp + * directory and delete any that are older than five minutes. + */ +void +KFW_cleanup_orphaned_caches(void) +{ + char * temppath = NULL; + char * curdir = NULL; + DWORD count, count2; + WIN32_FIND_DATA FindFileData; + HANDLE hFind = INVALID_HANDLE_VALUE; + FILETIME now; + ULARGE_INTEGER uli_now; + FILETIME expired; + + count = GetTempPath(0, NULL); + if (count <= 0) + return; + temppath = (char *) malloc(count); + if (!temppath) + goto cleanup; + count2 = GetTempPath(count, temppath); + if (count2 <= 0 || count2 > count) + goto cleanup; + + count = GetCurrentDirectory(0, NULL); + curdir = (char *)malloc(count); + if (!curdir) + goto cleanup; + count2 = GetCurrentDirectory(count, curdir); + if (count2 <= 0 || count2 > count) + goto cleanup; + + if (!SetCurrentDirectory(temppath)) + goto cleanup; + + GetSystemTimeAsFileTime(&now); + uli_now.u.LowPart = now.dwLowDateTime; + uli_now.u.HighPart = now.dwHighDateTime; + + uli_now.QuadPart -= 3000000000; /* 5 minutes == 3 billion 100 nano seconds */ + + expired.dwLowDateTime = uli_now.u.LowPart; + expired.dwHighDateTime = uli_now.u.HighPart; + + hFind = FindFirstFile("kfwlogon-*", &FindFileData); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (CompareFileTime(&FindFileData.ftCreationTime, &expired) < 0) { + DebugEvent("Deleting orphaned cache file: \"%s\"", FindFileData.cFileName); + DeleteFile(FindFileData.cFileName); + } + } while ( FindNextFile(hFind, &FindFileData) ); + } + + SetCurrentDirectory(curdir); + + cleanup: + if (temppath) + free(temppath); + if (hFind != INVALID_HANDLE_VALUE) + FindClose(hFind); + if (curdir) + free(curdir); +} diff --git a/src/windows/kfwlogon/kfwcpcc.c b/src/windows/kfwlogon/kfwcpcc.c index 5ff778552..fb0861e47 100644 --- a/src/windows/kfwlogon/kfwcpcc.c +++ b/src/windows/kfwlogon/kfwcpcc.c @@ -1,39 +1,39 @@ -/* - -Copyright 2005 by the Massachusetts Institute of Technology - -All rights reserved. - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of the Massachusetts -Institute of Technology (M.I.T.) not be used in advertising or publicity -pertaining to distribution of the software without specific, written -prior permission. - -M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -*/ - -#include -#include "kfwlogon.h" - -int main(int argc, char *argv[]) -{ - if ( argc != 2 ) - return 1; - - KFW_initialize(); - - return KFW_copy_file_cache_to_api_cache(argv[1]); -} - - +/* + +Copyright 2005 by the Massachusetts Institute of Technology + +All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of the Massachusetts +Institute of Technology (M.I.T.) not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. + +M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ + +#include +#include "kfwlogon.h" + +int main(int argc, char *argv[]) +{ + if ( argc != 2 ) + return 1; + + KFW_initialize(); + + return KFW_copy_file_cache_to_api_cache(argv[1]); +} + + diff --git a/src/windows/kfwlogon/kfwlogon.c b/src/windows/kfwlogon/kfwlogon.c index 8422f58b1..54d7a5a1d 100644 --- a/src/windows/kfwlogon/kfwlogon.c +++ b/src/windows/kfwlogon/kfwlogon.c @@ -1,634 +1,634 @@ -/* -Copyright 2005,2006 by the Massachusetts Institute of Technology -Copyright 2007 by Secure Endpoints Inc. - -All rights reserved. - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of the Massachusetts -Institute of Technology (M.I.T.) not be used in advertising or publicity -pertaining to distribution of the software without specific, written -prior permission. - -M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -*/ - -#include "kfwlogon.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -static HANDLE hDLL; - -static HANDLE hInitMutex = NULL; -static BOOL bInit = FALSE; - - -BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved) -{ - hDLL = dll; - switch (reason) { - case DLL_PROCESS_ATTACH: - /* Initialization Mutex */ - hInitMutex = CreateMutex(NULL, FALSE, NULL); - break; - - case DLL_PROCESS_DETACH: - CloseHandle(hInitMutex); - break; - - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - default: - /* Everything else succeeds but does nothing. */ - break; - } - - return TRUE; -} - -DWORD APIENTRY NPGetCaps(DWORD index) -{ - switch (index) { - case WNNC_NET_TYPE: - /* We aren't a file system; We don't have our own type; use somebody else's. */ - return WNNC_NET_SUN_PC_NFS; - case WNNC_START: - /* Say we are already started, even though we might wait after we receive NPLogonNotify */ - return 1; - - default: - return 0; - } -} - - -static BOOL -WINAPI -UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen) -{ - CPINFO CodePageInfo; - - GetCPInfo(CP_ACP, &CodePageInfo); - - if (CodePageInfo.MaxCharSize > 1) - // Only supporting non-Unicode strings - return FALSE; - - if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0') - { - // Looks like unicode, better translate it - // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS - WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2, - lpszOutputString, nOutStringLen-1, NULL, NULL); - lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0'; - return TRUE; - } - - lpszOutputString[0] = '\0'; - return FALSE; -} // UnicodeStringToANSI - - -static BOOL -is_windows_vista(void) -{ - static BOOL fChecked = FALSE; - static BOOL fIsWinVista = FALSE; - - if (!fChecked) - { - OSVERSIONINFO Version; - - memset (&Version, 0x00, sizeof(Version)); - Version.dwOSVersionInfoSize = sizeof(Version); - - if (GetVersionEx (&Version)) - { - if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT && - Version.dwMajorVersion >= 6) - fIsWinVista = TRUE; - } - fChecked = TRUE; - } - - return fIsWinVista; -} - - -/* Construct a Logon Script that will cause the LogonEventHandler to be executed - * under in the logon session - */ - -#define RUNDLL32_CMDLINE "rundll32.exe kfwlogon.dll,LogonEventHandler " -VOID -ConfigureLogonScript(LPWSTR *lpLogonScript, char * filename) { - DWORD dwLogonScriptLen; - LPWSTR lpScript; - LPSTR lpTemp; - - if (!lpLogonScript) - return; - *lpLogonScript = NULL; - - if (!filename) - return; - - dwLogonScriptLen = strlen(RUNDLL32_CMDLINE) + strlen(filename) + 2; - lpTemp = (LPSTR) malloc(dwLogonScriptLen); - if (!lpTemp) - return; - - _snprintf(lpTemp, dwLogonScriptLen, "%s%s", RUNDLL32_CMDLINE, filename); - - SetLastError(0); - dwLogonScriptLen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpTemp, -1, NULL, 0); - DebugEvent("ConfigureLogonScript %s requires %d bytes gle=0x%x", lpTemp, dwLogonScriptLen, GetLastError()); - - lpScript = LocalAlloc(LMEM_ZEROINIT, dwLogonScriptLen * 2); - if (lpScript) { - if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpTemp, -1, lpScript, 2 * dwLogonScriptLen)) - *lpLogonScript = lpScript; - else { - DebugEvent("ConfigureLogonScript - MultiByteToWideChar failed gle = 0x%x", GetLastError()); - LocalFree(lpScript); - } - } else { - DebugEvent("LocalAlloc failed gle=0x%x", GetLastError()); - } - free(lpTemp); -} - - -DWORD APIENTRY NPLogonNotify( - PLUID lpLogonId, - LPCWSTR lpAuthentInfoType, - LPVOID lpAuthentInfo, - LPCWSTR lpPreviousAuthentInfoType, - LPVOID lpPreviousAuthentInfo, - LPWSTR lpStationName, - LPVOID StationHandle, - LPWSTR *lpLogonScript) -{ - char uname[MAX_USERNAME_LENGTH+1]=""; - char password[MAX_PASSWORD_LENGTH+1]=""; - char logonDomain[MAX_DOMAIN_LENGTH+1]=""; - - MSV1_0_INTERACTIVE_LOGON *IL; - - DWORD code = 0; - - char *reason; - char *ctemp; - - BOOLEAN interactive = TRUE; - HWND hwndOwner = (HWND)StationHandle; - BOOLEAN lowercased_name = TRUE; - - /* Can we load KFW binaries? */ - if ( !KFW_is_available() ) - return 0; - - DebugEvent0("NPLogonNotify start"); - - /* Remote Desktop / Terminal Server connections to existing sessions - * are interactive logons. Unfortunately, because the session already - * exists the logon script does not get executed and this prevents - * us from being able to execute the rundll32 entrypoint - * LogonEventHandlerA which would process the credential cache this - * routine will produce. Therefore, we must cleanup orphaned cache - * files from this routine. We will take care of it before doing - * anything else. - */ - KFW_cleanup_orphaned_caches(); - - /* Are we interactive? */ - if (lpStationName) - interactive = (wcsicmp(lpStationName, L"WinSta0") == 0); - - if ( !interactive ) { - char station[64]="station"; - DWORD rv; - - SetLastError(0); - rv = WideCharToMultiByte(CP_UTF8, 0, lpStationName, -1, - station, sizeof(station), NULL, NULL); - DebugEvent("Skipping NPLogonNotify- LoginId(%d,%d) - Interactive(%d:%s) - gle %d", - lpLogonId->HighPart, lpLogonId->LowPart, interactive, rv != 0 ? station : "failure", GetLastError()); - return 0; - } else - DebugEvent("NPLogonNotify - LoginId(%d,%d)", lpLogonId->HighPart, lpLogonId->LowPart); - - /* Initialize Logon Script to none */ - *lpLogonScript=NULL; - - /* MSV1_0_INTERACTIVE_LOGON and KERB_INTERACTIVE_LOGON are equivalent for - * our purposes */ - - if ( wcsicmp(lpAuthentInfoType,L"MSV1_0:Interactive") && - wcsicmp(lpAuthentInfoType,L"Kerberos:Interactive") ) - { - char msg[64]; - WideCharToMultiByte(CP_ACP, 0, lpAuthentInfoType, -1, - msg, sizeof(msg), NULL, NULL); - msg[sizeof(msg)-1]='\0'; - DebugEvent("NPLogonNotify - Unsupported Authentication Info Type: %s", msg); - return 0; - } - - IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo; - - /* Convert from Unicode to ANSI */ - - /*TODO: Use SecureZeroMemory to erase passwords */ - if (!UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH) || - !UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH) || - !UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH)) - return 0; - - /* Make sure AD-DOMAINS sent from login that is sent to us is stripped */ - ctemp = strchr(uname, '@'); - if (ctemp) *ctemp = 0; - - /* is the name all lowercase? */ - for ( ctemp = uname; *ctemp ; ctemp++) { - if ( !islower(*ctemp) ) { - lowercased_name = FALSE; - break; - } - } - - code = KFW_get_cred(uname, password, 0, &reason); - DebugEvent("NPLogonNotify - KFW_get_cred uname=[%s] code=[%d]",uname, code); - - /* remove any kerberos 5 tickets currently held by the SYSTEM account - * for this user - */ - if (!code) { - char filename[MAX_PATH+1] = ""; - char acctname[MAX_USERNAME_LENGTH+MAX_DOMAIN_LENGTH+3]=""; - PSID pUserSid = NULL; - LPTSTR pReferencedDomainName = NULL; - DWORD dwSidLen = 0, dwDomainLen = 0, count; - SID_NAME_USE eUse; - - if (_snprintf(acctname, sizeof(acctname), "%s\\%s", logonDomain, uname) < 0) { - code = -1; - goto cleanup; - } - - count = GetTempPath(sizeof(filename), filename); - if (count == 0 || count > (sizeof(filename)-1)) { - code = -1; - goto cleanup; - } - - if (_snprintf(filename, sizeof(filename), "%s\\kfwlogon-%x.%x", - filename, lpLogonId->HighPart, lpLogonId->LowPart) < 0) - { - code = -1; - goto cleanup; - } - - KFW_copy_cache_to_system_file(uname, filename); - - /* Need to determine the SID */ - - /* First get the size of the required buffers */ - LookupAccountName (NULL, - acctname, - pUserSid, - &dwSidLen, - pReferencedDomainName, - &dwDomainLen, - &eUse); - if(dwSidLen){ - pUserSid = (PSID) malloc (dwSidLen); - memset(pUserSid,0,dwSidLen); - } - - if(dwDomainLen){ - pReferencedDomainName = (LPTSTR) malloc (dwDomainLen * sizeof(TCHAR)); - memset(pReferencedDomainName,0,dwDomainLen * sizeof(TCHAR)); - } - - //Now get the SID and the domain name - if (pUserSid && LookupAccountName( NULL, - acctname, - pUserSid, - &dwSidLen, - pReferencedDomainName, - &dwDomainLen, - &eUse)) - { - DebugEvent("LookupAccountName obtained user %s sid in domain %s", acctname, pReferencedDomainName); - code = KFW_set_ccache_dacl_with_user_sid(filename, pUserSid); - -#ifdef USE_WINLOGON_EVENT - /* If we are on Vista, setup a LogonScript - * that will execute the LogonEventHandler entry point via rundll32.exe - */ - if (is_windows_vista()) { - ConfigureLogonScript(lpLogonScript, filename); - if (*lpLogonScript) - DebugEvent0("LogonScript assigned"); - else - DebugEvent0("No Logon Script"); - } -#else - ConfigureLogonScript(lpLogonScript, filename); - if (*lpLogonScript) - DebugEvent0("LogonScript assigned"); - else - DebugEvent0("No Logon Script"); -#endif - } else { - DebugEvent0("LookupAccountName failed"); - DeleteFile(filename); - code = -1; - } - - cleanup: - if (pUserSid) - free(pUserSid); - if (pReferencedDomainName) - free(pReferencedDomainName); - } - - KFW_destroy_tickets_for_principal(uname); - - if (code) { - char msg[128]; - HANDLE h; - char *ptbuf[1]; - - StringCbPrintf(msg, sizeof(msg), "Kerberos ticket acquisition failed: %s", reason); - - h = RegisterEventSource(NULL, KFW_LOGON_EVENT_NAME); - ptbuf[0] = msg; - ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL, 1, 0, ptbuf, NULL); - DeregisterEventSource(h); - SetLastError(code); - } - - if (code) - DebugEvent0("NPLogonNotify failure"); - else - DebugEvent0("NPLogonNotify success"); - - return code; -} - - -DWORD APIENTRY NPPasswordChangeNotify( - LPCWSTR lpAuthentInfoType, - LPVOID lpAuthentInfo, - LPCWSTR lpPreviousAuthentInfoType, - LPVOID lpPreviousAuthentInfo, - LPWSTR lpStationName, - LPVOID StationHandle, - DWORD dwChangeInfo) -{ - return 0; -} - -#include -#include - -#ifdef COMMENT -typedef struct _WLX_NOTIFICATION_INFO { - ULONG Size; - ULONG Flags; - PWSTR UserName; - PWSTR Domain; - PWSTR WindowStation; - HANDLE hToken; - HDESK hDesktop; - PFNMSGECALLBACK pStatusCallback; -} WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO; -#endif - -VOID KFW_Startup_Event( PWLX_NOTIFICATION_INFO pInfo ) -{ - DebugEvent0("KFW_Startup_Event"); -} - -static BOOL -GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData) -{ - NTSTATUS Status = 0; -#if 0 - HANDLE TokenHandle; -#endif - TOKEN_STATISTICS Stats; - DWORD ReqLen; - BOOL Success; - - if (!ppSessionData) - return FALSE; - *ppSessionData = NULL; - -#if 0 - Success = OpenProcessToken( HANDLE GetCurrentProcess(), TOKEN_QUERY, &TokenHandle ); - if ( !Success ) - return FALSE; -#endif - - Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen ); -#if 0 - CloseHandle( TokenHandle ); -#endif - if ( !Success ) - return FALSE; - - Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData ); - if ( FAILED(Status) || !ppSessionData ) - return FALSE; - - return TRUE; -} - -VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo ) -{ -#ifdef USE_WINLOGON_EVENT - WCHAR szUserW[128] = L""; - char szUserA[128] = ""; - char szPath[MAX_PATH] = ""; - char szLogonId[128] = ""; - DWORD count; - char filename[MAX_PATH] = ""; - char newfilename[MAX_PATH] = ""; - char commandline[MAX_PATH+256] = ""; - STARTUPINFO startupinfo; - PROCESS_INFORMATION procinfo; - HANDLE hf = NULL; - - LUID LogonId = {0, 0}; - PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL; - - HKEY hKey1 = NULL, hKey2 = NULL; - - DebugEvent0("KFW_Logon_Event - Start"); - - GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData ); - - if ( pLogonSessionData ) { - LogonId = pLogonSessionData->LogonId; - DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart); - - _snprintf(szLogonId, sizeof(szLogonId), "kfwlogon-%d.%d",LogonId.HighPart, LogonId.LowPart); - LsaFreeReturnBuffer( pLogonSessionData ); - } else { - DebugEvent0("KFW_Logon_Event - Unable to determine LogonId"); - return; - } - - count = GetEnvironmentVariable("TEMP", filename, sizeof(filename)); - if ( count > sizeof(filename) || count == 0 ) { - GetWindowsDirectory(filename, sizeof(filename)); - } - - if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) ) { - DebugEvent0("KFW_Logon_Event - filename too long"); - return; - } - - strcat(filename, "\\"); - strcat(filename, szLogonId); - - hf = CreateFile(filename, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); - if (hf == INVALID_HANDLE_VALUE) { - DebugEvent0("KFW_Logon_Event - file cannot be opened"); - return; - } - CloseHandle(hf); - - if (KFW_set_ccache_dacl(filename, pInfo->hToken)) { - DebugEvent0("KFW_Logon_Event - unable to set dacl"); - DeleteFile(filename); - return; - } - - if (KFW_obtain_user_temp_directory(pInfo->hToken, newfilename, sizeof(newfilename))) { - DebugEvent0("KFW_Logon_Event - unable to obtain temp directory"); - return; - } - - if ( strlen(newfilename) + strlen(szLogonId) + 2 > sizeof(newfilename) ) { - DebugEvent0("KFW_Logon_Event - new filename too long"); - return; - } - - strcat(newfilename, "\\"); - strcat(newfilename, szLogonId); - - if (!MoveFileEx(filename, newfilename, - MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { - DebugEvent("KFW_Logon_Event - MoveFileEx failed GLE = 0x%x", GetLastError()); - return; - } - - _snprintf(commandline, sizeof(commandline), "kfwcpcc.exe \"%s\"", newfilename); - - GetStartupInfo(&startupinfo); - if (CreateProcessAsUser( pInfo->hToken, - "kfwcpcc.exe", - commandline, - NULL, - NULL, - FALSE, - CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, - NULL, - NULL, - &startupinfo, - &procinfo)) - { - DebugEvent("KFW_Logon_Event - CommandLine %s", commandline); - - WaitForSingleObject(procinfo.hProcess, 30000); - - CloseHandle(procinfo.hThread); - CloseHandle(procinfo.hProcess); - } else { - DebugEvent0("KFW_Logon_Event - CreateProcessFailed"); - } - - DeleteFile(newfilename); - - DebugEvent0("KFW_Logon_Event - End"); -#endif /* USE_WINLOGON_EVENT */ -} - - -/* Documentation on the use of RunDll32 entrypoints can be found - * at http://support.microsoft.com/kb/164787 - */ -void CALLBACK -LogonEventHandlerA(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) -{ - HANDLE hf = NULL; - char commandline[MAX_PATH+256] = ""; - STARTUPINFO startupinfo; - PROCESS_INFORMATION procinfo; - - DebugEvent0("LogonEventHandler - Start"); - - /* Validate lpszCmdLine as a file */ - hf = CreateFile(lpszCmdLine, GENERIC_READ | DELETE, 0, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); - if (hf == INVALID_HANDLE_VALUE) { - DebugEvent("LogonEventHandler - \"%s\" cannot be opened", lpszCmdLine); - return; - } - CloseHandle(hf); - - - _snprintf(commandline, sizeof(commandline), "kfwcpcc.exe \"%s\"", lpszCmdLine); - - GetStartupInfo(&startupinfo); - SetLastError(0); - if (CreateProcess( NULL, - commandline, - NULL, - NULL, - FALSE, - CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, - NULL, - NULL, - &startupinfo, - &procinfo)) - { - DebugEvent("KFW_Logon_Event - CommandLine %s", commandline); - - WaitForSingleObject(procinfo.hProcess, 30000); - - CloseHandle(procinfo.hThread); - CloseHandle(procinfo.hProcess); - } else { - DebugEvent("KFW_Logon_Event - CreateProcessFailed \"%s\" GLE 0x%x", - commandline, GetLastError()); - DebugEvent("KFW_Logon_Event PATH %s", getenv("PATH")); - } - - DeleteFile(lpszCmdLine); - - DebugEvent0("KFW_Logon_Event - End"); -} +/* +Copyright 2005,2006 by the Massachusetts Institute of Technology +Copyright 2007 by Secure Endpoints Inc. + +All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of the Massachusetts +Institute of Technology (M.I.T.) not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. + +M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ + +#include "kfwlogon.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +static HANDLE hDLL; + +static HANDLE hInitMutex = NULL; +static BOOL bInit = FALSE; + + +BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved) +{ + hDLL = dll; + switch (reason) { + case DLL_PROCESS_ATTACH: + /* Initialization Mutex */ + hInitMutex = CreateMutex(NULL, FALSE, NULL); + break; + + case DLL_PROCESS_DETACH: + CloseHandle(hInitMutex); + break; + + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + default: + /* Everything else succeeds but does nothing. */ + break; + } + + return TRUE; +} + +DWORD APIENTRY NPGetCaps(DWORD index) +{ + switch (index) { + case WNNC_NET_TYPE: + /* We aren't a file system; We don't have our own type; use somebody else's. */ + return WNNC_NET_SUN_PC_NFS; + case WNNC_START: + /* Say we are already started, even though we might wait after we receive NPLogonNotify */ + return 1; + + default: + return 0; + } +} + + +static BOOL +WINAPI +UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen) +{ + CPINFO CodePageInfo; + + GetCPInfo(CP_ACP, &CodePageInfo); + + if (CodePageInfo.MaxCharSize > 1) + // Only supporting non-Unicode strings + return FALSE; + + if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0') + { + // Looks like unicode, better translate it + // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS + WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2, + lpszOutputString, nOutStringLen-1, NULL, NULL); + lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0'; + return TRUE; + } + + lpszOutputString[0] = '\0'; + return FALSE; +} // UnicodeStringToANSI + + +static BOOL +is_windows_vista(void) +{ + static BOOL fChecked = FALSE; + static BOOL fIsWinVista = FALSE; + + if (!fChecked) + { + OSVERSIONINFO Version; + + memset (&Version, 0x00, sizeof(Version)); + Version.dwOSVersionInfoSize = sizeof(Version); + + if (GetVersionEx (&Version)) + { + if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT && + Version.dwMajorVersion >= 6) + fIsWinVista = TRUE; + } + fChecked = TRUE; + } + + return fIsWinVista; +} + + +/* Construct a Logon Script that will cause the LogonEventHandler to be executed + * under in the logon session + */ + +#define RUNDLL32_CMDLINE "rundll32.exe kfwlogon.dll,LogonEventHandler " +VOID +ConfigureLogonScript(LPWSTR *lpLogonScript, char * filename) { + DWORD dwLogonScriptLen; + LPWSTR lpScript; + LPSTR lpTemp; + + if (!lpLogonScript) + return; + *lpLogonScript = NULL; + + if (!filename) + return; + + dwLogonScriptLen = strlen(RUNDLL32_CMDLINE) + strlen(filename) + 2; + lpTemp = (LPSTR) malloc(dwLogonScriptLen); + if (!lpTemp) + return; + + _snprintf(lpTemp, dwLogonScriptLen, "%s%s", RUNDLL32_CMDLINE, filename); + + SetLastError(0); + dwLogonScriptLen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpTemp, -1, NULL, 0); + DebugEvent("ConfigureLogonScript %s requires %d bytes gle=0x%x", lpTemp, dwLogonScriptLen, GetLastError()); + + lpScript = LocalAlloc(LMEM_ZEROINIT, dwLogonScriptLen * 2); + if (lpScript) { + if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpTemp, -1, lpScript, 2 * dwLogonScriptLen)) + *lpLogonScript = lpScript; + else { + DebugEvent("ConfigureLogonScript - MultiByteToWideChar failed gle = 0x%x", GetLastError()); + LocalFree(lpScript); + } + } else { + DebugEvent("LocalAlloc failed gle=0x%x", GetLastError()); + } + free(lpTemp); +} + + +DWORD APIENTRY NPLogonNotify( + PLUID lpLogonId, + LPCWSTR lpAuthentInfoType, + LPVOID lpAuthentInfo, + LPCWSTR lpPreviousAuthentInfoType, + LPVOID lpPreviousAuthentInfo, + LPWSTR lpStationName, + LPVOID StationHandle, + LPWSTR *lpLogonScript) +{ + char uname[MAX_USERNAME_LENGTH+1]=""; + char password[MAX_PASSWORD_LENGTH+1]=""; + char logonDomain[MAX_DOMAIN_LENGTH+1]=""; + + MSV1_0_INTERACTIVE_LOGON *IL; + + DWORD code = 0; + + char *reason; + char *ctemp; + + BOOLEAN interactive = TRUE; + HWND hwndOwner = (HWND)StationHandle; + BOOLEAN lowercased_name = TRUE; + + /* Can we load KFW binaries? */ + if ( !KFW_is_available() ) + return 0; + + DebugEvent0("NPLogonNotify start"); + + /* Remote Desktop / Terminal Server connections to existing sessions + * are interactive logons. Unfortunately, because the session already + * exists the logon script does not get executed and this prevents + * us from being able to execute the rundll32 entrypoint + * LogonEventHandlerA which would process the credential cache this + * routine will produce. Therefore, we must cleanup orphaned cache + * files from this routine. We will take care of it before doing + * anything else. + */ + KFW_cleanup_orphaned_caches(); + + /* Are we interactive? */ + if (lpStationName) + interactive = (wcsicmp(lpStationName, L"WinSta0") == 0); + + if ( !interactive ) { + char station[64]="station"; + DWORD rv; + + SetLastError(0); + rv = WideCharToMultiByte(CP_UTF8, 0, lpStationName, -1, + station, sizeof(station), NULL, NULL); + DebugEvent("Skipping NPLogonNotify- LoginId(%d,%d) - Interactive(%d:%s) - gle %d", + lpLogonId->HighPart, lpLogonId->LowPart, interactive, rv != 0 ? station : "failure", GetLastError()); + return 0; + } else + DebugEvent("NPLogonNotify - LoginId(%d,%d)", lpLogonId->HighPart, lpLogonId->LowPart); + + /* Initialize Logon Script to none */ + *lpLogonScript=NULL; + + /* MSV1_0_INTERACTIVE_LOGON and KERB_INTERACTIVE_LOGON are equivalent for + * our purposes */ + + if ( wcsicmp(lpAuthentInfoType,L"MSV1_0:Interactive") && + wcsicmp(lpAuthentInfoType,L"Kerberos:Interactive") ) + { + char msg[64]; + WideCharToMultiByte(CP_ACP, 0, lpAuthentInfoType, -1, + msg, sizeof(msg), NULL, NULL); + msg[sizeof(msg)-1]='\0'; + DebugEvent("NPLogonNotify - Unsupported Authentication Info Type: %s", msg); + return 0; + } + + IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo; + + /* Convert from Unicode to ANSI */ + + /*TODO: Use SecureZeroMemory to erase passwords */ + if (!UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH) || + !UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH) || + !UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH)) + return 0; + + /* Make sure AD-DOMAINS sent from login that is sent to us is stripped */ + ctemp = strchr(uname, '@'); + if (ctemp) *ctemp = 0; + + /* is the name all lowercase? */ + for ( ctemp = uname; *ctemp ; ctemp++) { + if ( !islower(*ctemp) ) { + lowercased_name = FALSE; + break; + } + } + + code = KFW_get_cred(uname, password, 0, &reason); + DebugEvent("NPLogonNotify - KFW_get_cred uname=[%s] code=[%d]",uname, code); + + /* remove any kerberos 5 tickets currently held by the SYSTEM account + * for this user + */ + if (!code) { + char filename[MAX_PATH+1] = ""; + char acctname[MAX_USERNAME_LENGTH+MAX_DOMAIN_LENGTH+3]=""; + PSID pUserSid = NULL; + LPTSTR pReferencedDomainName = NULL; + DWORD dwSidLen = 0, dwDomainLen = 0, count; + SID_NAME_USE eUse; + + if (_snprintf(acctname, sizeof(acctname), "%s\\%s", logonDomain, uname) < 0) { + code = -1; + goto cleanup; + } + + count = GetTempPath(sizeof(filename), filename); + if (count == 0 || count > (sizeof(filename)-1)) { + code = -1; + goto cleanup; + } + + if (_snprintf(filename, sizeof(filename), "%s\\kfwlogon-%x.%x", + filename, lpLogonId->HighPart, lpLogonId->LowPart) < 0) + { + code = -1; + goto cleanup; + } + + KFW_copy_cache_to_system_file(uname, filename); + + /* Need to determine the SID */ + + /* First get the size of the required buffers */ + LookupAccountName (NULL, + acctname, + pUserSid, + &dwSidLen, + pReferencedDomainName, + &dwDomainLen, + &eUse); + if(dwSidLen){ + pUserSid = (PSID) malloc (dwSidLen); + memset(pUserSid,0,dwSidLen); + } + + if(dwDomainLen){ + pReferencedDomainName = (LPTSTR) malloc (dwDomainLen * sizeof(TCHAR)); + memset(pReferencedDomainName,0,dwDomainLen * sizeof(TCHAR)); + } + + //Now get the SID and the domain name + if (pUserSid && LookupAccountName( NULL, + acctname, + pUserSid, + &dwSidLen, + pReferencedDomainName, + &dwDomainLen, + &eUse)) + { + DebugEvent("LookupAccountName obtained user %s sid in domain %s", acctname, pReferencedDomainName); + code = KFW_set_ccache_dacl_with_user_sid(filename, pUserSid); + +#ifdef USE_WINLOGON_EVENT + /* If we are on Vista, setup a LogonScript + * that will execute the LogonEventHandler entry point via rundll32.exe + */ + if (is_windows_vista()) { + ConfigureLogonScript(lpLogonScript, filename); + if (*lpLogonScript) + DebugEvent0("LogonScript assigned"); + else + DebugEvent0("No Logon Script"); + } +#else + ConfigureLogonScript(lpLogonScript, filename); + if (*lpLogonScript) + DebugEvent0("LogonScript assigned"); + else + DebugEvent0("No Logon Script"); +#endif + } else { + DebugEvent0("LookupAccountName failed"); + DeleteFile(filename); + code = -1; + } + + cleanup: + if (pUserSid) + free(pUserSid); + if (pReferencedDomainName) + free(pReferencedDomainName); + } + + KFW_destroy_tickets_for_principal(uname); + + if (code) { + char msg[128]; + HANDLE h; + char *ptbuf[1]; + + StringCbPrintf(msg, sizeof(msg), "Kerberos ticket acquisition failed: %s", reason); + + h = RegisterEventSource(NULL, KFW_LOGON_EVENT_NAME); + ptbuf[0] = msg; + ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL, 1, 0, ptbuf, NULL); + DeregisterEventSource(h); + SetLastError(code); + } + + if (code) + DebugEvent0("NPLogonNotify failure"); + else + DebugEvent0("NPLogonNotify success"); + + return code; +} + + +DWORD APIENTRY NPPasswordChangeNotify( + LPCWSTR lpAuthentInfoType, + LPVOID lpAuthentInfo, + LPCWSTR lpPreviousAuthentInfoType, + LPVOID lpPreviousAuthentInfo, + LPWSTR lpStationName, + LPVOID StationHandle, + DWORD dwChangeInfo) +{ + return 0; +} + +#include +#include + +#ifdef COMMENT +typedef struct _WLX_NOTIFICATION_INFO { + ULONG Size; + ULONG Flags; + PWSTR UserName; + PWSTR Domain; + PWSTR WindowStation; + HANDLE hToken; + HDESK hDesktop; + PFNMSGECALLBACK pStatusCallback; +} WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO; +#endif + +VOID KFW_Startup_Event( PWLX_NOTIFICATION_INFO pInfo ) +{ + DebugEvent0("KFW_Startup_Event"); +} + +static BOOL +GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData) +{ + NTSTATUS Status = 0; +#if 0 + HANDLE TokenHandle; +#endif + TOKEN_STATISTICS Stats; + DWORD ReqLen; + BOOL Success; + + if (!ppSessionData) + return FALSE; + *ppSessionData = NULL; + +#if 0 + Success = OpenProcessToken( HANDLE GetCurrentProcess(), TOKEN_QUERY, &TokenHandle ); + if ( !Success ) + return FALSE; +#endif + + Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen ); +#if 0 + CloseHandle( TokenHandle ); +#endif + if ( !Success ) + return FALSE; + + Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData ); + if ( FAILED(Status) || !ppSessionData ) + return FALSE; + + return TRUE; +} + +VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo ) +{ +#ifdef USE_WINLOGON_EVENT + WCHAR szUserW[128] = L""; + char szUserA[128] = ""; + char szPath[MAX_PATH] = ""; + char szLogonId[128] = ""; + DWORD count; + char filename[MAX_PATH] = ""; + char newfilename[MAX_PATH] = ""; + char commandline[MAX_PATH+256] = ""; + STARTUPINFO startupinfo; + PROCESS_INFORMATION procinfo; + HANDLE hf = NULL; + + LUID LogonId = {0, 0}; + PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL; + + HKEY hKey1 = NULL, hKey2 = NULL; + + DebugEvent0("KFW_Logon_Event - Start"); + + GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData ); + + if ( pLogonSessionData ) { + LogonId = pLogonSessionData->LogonId; + DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart); + + _snprintf(szLogonId, sizeof(szLogonId), "kfwlogon-%d.%d",LogonId.HighPart, LogonId.LowPart); + LsaFreeReturnBuffer( pLogonSessionData ); + } else { + DebugEvent0("KFW_Logon_Event - Unable to determine LogonId"); + return; + } + + count = GetEnvironmentVariable("TEMP", filename, sizeof(filename)); + if ( count > sizeof(filename) || count == 0 ) { + GetWindowsDirectory(filename, sizeof(filename)); + } + + if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) ) { + DebugEvent0("KFW_Logon_Event - filename too long"); + return; + } + + strcat(filename, "\\"); + strcat(filename, szLogonId); + + hf = CreateFile(filename, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (hf == INVALID_HANDLE_VALUE) { + DebugEvent0("KFW_Logon_Event - file cannot be opened"); + return; + } + CloseHandle(hf); + + if (KFW_set_ccache_dacl(filename, pInfo->hToken)) { + DebugEvent0("KFW_Logon_Event - unable to set dacl"); + DeleteFile(filename); + return; + } + + if (KFW_obtain_user_temp_directory(pInfo->hToken, newfilename, sizeof(newfilename))) { + DebugEvent0("KFW_Logon_Event - unable to obtain temp directory"); + return; + } + + if ( strlen(newfilename) + strlen(szLogonId) + 2 > sizeof(newfilename) ) { + DebugEvent0("KFW_Logon_Event - new filename too long"); + return; + } + + strcat(newfilename, "\\"); + strcat(newfilename, szLogonId); + + if (!MoveFileEx(filename, newfilename, + MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { + DebugEvent("KFW_Logon_Event - MoveFileEx failed GLE = 0x%x", GetLastError()); + return; + } + + _snprintf(commandline, sizeof(commandline), "kfwcpcc.exe \"%s\"", newfilename); + + GetStartupInfo(&startupinfo); + if (CreateProcessAsUser( pInfo->hToken, + "kfwcpcc.exe", + commandline, + NULL, + NULL, + FALSE, + CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, + NULL, + NULL, + &startupinfo, + &procinfo)) + { + DebugEvent("KFW_Logon_Event - CommandLine %s", commandline); + + WaitForSingleObject(procinfo.hProcess, 30000); + + CloseHandle(procinfo.hThread); + CloseHandle(procinfo.hProcess); + } else { + DebugEvent0("KFW_Logon_Event - CreateProcessFailed"); + } + + DeleteFile(newfilename); + + DebugEvent0("KFW_Logon_Event - End"); +#endif /* USE_WINLOGON_EVENT */ +} + + +/* Documentation on the use of RunDll32 entrypoints can be found + * at http://support.microsoft.com/kb/164787 + */ +void CALLBACK +LogonEventHandlerA(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) +{ + HANDLE hf = NULL; + char commandline[MAX_PATH+256] = ""; + STARTUPINFO startupinfo; + PROCESS_INFORMATION procinfo; + + DebugEvent0("LogonEventHandler - Start"); + + /* Validate lpszCmdLine as a file */ + hf = CreateFile(lpszCmdLine, GENERIC_READ | DELETE, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (hf == INVALID_HANDLE_VALUE) { + DebugEvent("LogonEventHandler - \"%s\" cannot be opened", lpszCmdLine); + return; + } + CloseHandle(hf); + + + _snprintf(commandline, sizeof(commandline), "kfwcpcc.exe \"%s\"", lpszCmdLine); + + GetStartupInfo(&startupinfo); + SetLastError(0); + if (CreateProcess( NULL, + commandline, + NULL, + NULL, + FALSE, + CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, + NULL, + NULL, + &startupinfo, + &procinfo)) + { + DebugEvent("KFW_Logon_Event - CommandLine %s", commandline); + + WaitForSingleObject(procinfo.hProcess, 30000); + + CloseHandle(procinfo.hThread); + CloseHandle(procinfo.hProcess); + } else { + DebugEvent("KFW_Logon_Event - CreateProcessFailed \"%s\" GLE 0x%x", + commandline, GetLastError()); + DebugEvent("KFW_Logon_Event PATH %s", getenv("PATH")); + } + + DeleteFile(lpszCmdLine); + + DebugEvent0("KFW_Logon_Event - End"); +} diff --git a/src/windows/kfwlogon/kfwlogon.h b/src/windows/kfwlogon/kfwlogon.h index cfbe4fd38..2f1a62b6e 100644 --- a/src/windows/kfwlogon/kfwlogon.h +++ b/src/windows/kfwlogon/kfwlogon.h @@ -1,215 +1,215 @@ -/* - -Copyright 2005,2006 by the Massachusetts Institute of Technology -Copyright 2007 by Secure Endpoints Inc. - -All rights reserved. - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of the Massachusetts -Institute of Technology (M.I.T.) not be used in advertising or publicity -pertaining to distribution of the software without specific, written -prior permission. - -M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -*/ - -/* We only support VC 1200 and above anyway */ -#pragma once - -/* _WIN32_WINNT must be 0x0501 or greater to pull in definition of - * all required LSA data types when the Vista SDK NtSecAPI.h is used. - */ -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#else -#if _WIN32_WINNT < 0x0501 -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif -#endif - -#include -#include -#define SECURITY_WIN32 -#include -#include -#include -#include - -typedef int errcode_t; - -#include -#include -#include -#include -#include -#include - -// service definitions -#define SERVICE_DLL "advapi32.dll" -typedef SC_HANDLE (WINAPI *FP_OpenSCManagerA)(char *, char *, DWORD); -typedef SC_HANDLE (WINAPI *FP_OpenServiceA)(SC_HANDLE, char *, DWORD); -typedef BOOL (WINAPI *FP_QueryServiceStatus)(SC_HANDLE, LPSERVICE_STATUS); -typedef BOOL (WINAPI *FP_CloseServiceHandle)(SC_HANDLE); - -/* In order to avoid including the private CCAPI headers */ -typedef int cc_int32; - -#define CC_API_VER_1 1 -#define CC_API_VER_2 2 - -#define CCACHE_API cc_int32 - -/* -** The Official Error Codes -*/ -#define CC_NOERROR 0 -#define CC_BADNAME 1 -#define CC_NOTFOUND 2 -#define CC_END 3 -#define CC_IO 4 -#define CC_WRITE 5 -#define CC_NOMEM 6 -#define CC_FORMAT 7 -#define CC_LOCKED 8 -#define CC_BAD_API_VERSION 9 -#define CC_NO_EXIST 10 -#define CC_NOT_SUPP 11 -#define CC_BAD_PARM 12 -#define CC_ERR_CACHE_ATTACH 13 -#define CC_ERR_CACHE_RELEASE 14 -#define CC_ERR_CACHE_FULL 15 -#define CC_ERR_CRED_VERSION 16 - -enum { - CC_CRED_VUNKNOWN = 0, // For validation - CC_CRED_V4 = 1, - CC_CRED_V5 = 2, - CC_CRED_VMAX = 3 // For validation -}; - -typedef struct opaque_dll_control_block_type* apiCB; -typedef struct _infoNC { - char* name; - char* principal; - cc_int32 vers; -} infoNC; - -TYPEDEF_FUNC( -CCACHE_API, -CALLCONV_C, -cc_initialize, - ( - apiCB** cc_ctx, // < DLL's primary control structure. - // returned here, passed everywhere else - cc_int32 api_version, // > ver supported by caller (use CC_API_VER_1) - cc_int32* api_supported, // < if ~NULL, max ver supported by DLL - const char** vendor // < if ~NULL, vendor name in read only C string - ) -); - -TYPEDEF_FUNC( -CCACHE_API, -CALLCONV_C, -cc_shutdown, - ( - apiCB** cc_ctx // <> DLL's primary control structure. NULL after - ) -); - -TYPEDEF_FUNC( -CCACHE_API, -CALLCONV_C, -cc_get_NC_info, - ( - apiCB* cc_ctx, // > DLL's primary control structure - struct _infoNC*** ppNCi // < (NULL before call) null terminated, - // list of a structs (free via cc_free_infoNC()) - ) -); - -TYPEDEF_FUNC( -CCACHE_API, -CALLCONV_C, -cc_free_NC_info, - ( - apiCB* cc_ctx, - struct _infoNC*** ppNCi // < free list of structs returned by - // cc_get_cache_names(). set to NULL on return - ) -); -/* End private ccapiv2 headers */ - -#define CCAPI_DLL "krbcc32.dll" - - -/* */ -#define MAX_USERNAME_LENGTH 256 -#define MAX_PASSWORD_LENGTH 256 -#define MAX_DOMAIN_LENGTH 256 - -#define KFW_LOGON_EVENT_NAME TEXT("MIT Kerberos") - -BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved); - -DWORD APIENTRY NPGetCaps(DWORD index); - -DWORD APIENTRY NPLogonNotify( - PLUID lpLogonId, - LPCWSTR lpAuthentInfoType, - LPVOID lpAuthentInfo, - LPCWSTR lpPreviousAuthentInfoType, - LPVOID lpPreviousAuthentInfo, - LPWSTR lpStationName, - LPVOID StationHandle, - LPWSTR *lpLogonScript); - -DWORD APIENTRY NPPasswordChangeNotify( - LPCWSTR lpAuthentInfoType, - LPVOID lpAuthentInfo, - LPCWSTR lpPreviousAuthentInfoType, - LPVOID lpPreviousAuthentInfo, - LPWSTR lpStationName, - LPVOID StationHandle, - DWORD dwChangeInfo); - -#ifdef __cplusplus -extern "C" { -#endif - -void UnloadFuncs(FUNC_INFO [], HINSTANCE); - -int LoadFuncs(const char*, FUNC_INFO [], HINSTANCE*, int*, int, int, int); - -void DebugEvent0(char *a); -void DebugEvent(char *b,...); - -DWORD MapAuthError(DWORD code); - -static BOOL WINAPI UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen); - -int KFW_is_available(void); -int KFW_get_cred( char * username, char * password, int lifetime, char ** reasonP ); -void KFW_copy_cache_to_system_file(const char * user, const char * filename); -int KFW_destroy_tickets_for_principal(char * user); -int KFW_set_ccache_dacl(char *filename, HANDLE hUserToken); -int KFW_set_ccache_dacl_with_user_sid(char *filename, PSID pUserSID); -int KFW_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size); -void KFW_cleanup_orphaned_caches(void); - -void CALLBACK LogonEventHandlerA(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow); - -#ifdef __cplusplus -} -#endif +/* + +Copyright 2005,2006 by the Massachusetts Institute of Technology +Copyright 2007 by Secure Endpoints Inc. + +All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of the Massachusetts +Institute of Technology (M.I.T.) not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. + +M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ + +/* We only support VC 1200 and above anyway */ +#pragma once + +/* _WIN32_WINNT must be 0x0501 or greater to pull in definition of + * all required LSA data types when the Vista SDK NtSecAPI.h is used. + */ +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#else +#if _WIN32_WINNT < 0x0501 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#endif + +#include +#include +#define SECURITY_WIN32 +#include +#include +#include +#include + +typedef int errcode_t; + +#include +#include +#include +#include +#include +#include + +// service definitions +#define SERVICE_DLL "advapi32.dll" +typedef SC_HANDLE (WINAPI *FP_OpenSCManagerA)(char *, char *, DWORD); +typedef SC_HANDLE (WINAPI *FP_OpenServiceA)(SC_HANDLE, char *, DWORD); +typedef BOOL (WINAPI *FP_QueryServiceStatus)(SC_HANDLE, LPSERVICE_STATUS); +typedef BOOL (WINAPI *FP_CloseServiceHandle)(SC_HANDLE); + +/* In order to avoid including the private CCAPI headers */ +typedef int cc_int32; + +#define CC_API_VER_1 1 +#define CC_API_VER_2 2 + +#define CCACHE_API cc_int32 + +/* +** The Official Error Codes +*/ +#define CC_NOERROR 0 +#define CC_BADNAME 1 +#define CC_NOTFOUND 2 +#define CC_END 3 +#define CC_IO 4 +#define CC_WRITE 5 +#define CC_NOMEM 6 +#define CC_FORMAT 7 +#define CC_LOCKED 8 +#define CC_BAD_API_VERSION 9 +#define CC_NO_EXIST 10 +#define CC_NOT_SUPP 11 +#define CC_BAD_PARM 12 +#define CC_ERR_CACHE_ATTACH 13 +#define CC_ERR_CACHE_RELEASE 14 +#define CC_ERR_CACHE_FULL 15 +#define CC_ERR_CRED_VERSION 16 + +enum { + CC_CRED_VUNKNOWN = 0, // For validation + CC_CRED_V4 = 1, + CC_CRED_V5 = 2, + CC_CRED_VMAX = 3 // For validation +}; + +typedef struct opaque_dll_control_block_type* apiCB; +typedef struct _infoNC { + char* name; + char* principal; + cc_int32 vers; +} infoNC; + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_initialize, + ( + apiCB** cc_ctx, // < DLL's primary control structure. + // returned here, passed everywhere else + cc_int32 api_version, // > ver supported by caller (use CC_API_VER_1) + cc_int32* api_supported, // < if ~NULL, max ver supported by DLL + const char** vendor // < if ~NULL, vendor name in read only C string + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_shutdown, + ( + apiCB** cc_ctx // <> DLL's primary control structure. NULL after + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_get_NC_info, + ( + apiCB* cc_ctx, // > DLL's primary control structure + struct _infoNC*** ppNCi // < (NULL before call) null terminated, + // list of a structs (free via cc_free_infoNC()) + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_free_NC_info, + ( + apiCB* cc_ctx, + struct _infoNC*** ppNCi // < free list of structs returned by + // cc_get_cache_names(). set to NULL on return + ) +); +/* End private ccapiv2 headers */ + +#define CCAPI_DLL "krbcc32.dll" + + +/* */ +#define MAX_USERNAME_LENGTH 256 +#define MAX_PASSWORD_LENGTH 256 +#define MAX_DOMAIN_LENGTH 256 + +#define KFW_LOGON_EVENT_NAME TEXT("MIT Kerberos") + +BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved); + +DWORD APIENTRY NPGetCaps(DWORD index); + +DWORD APIENTRY NPLogonNotify( + PLUID lpLogonId, + LPCWSTR lpAuthentInfoType, + LPVOID lpAuthentInfo, + LPCWSTR lpPreviousAuthentInfoType, + LPVOID lpPreviousAuthentInfo, + LPWSTR lpStationName, + LPVOID StationHandle, + LPWSTR *lpLogonScript); + +DWORD APIENTRY NPPasswordChangeNotify( + LPCWSTR lpAuthentInfoType, + LPVOID lpAuthentInfo, + LPCWSTR lpPreviousAuthentInfoType, + LPVOID lpPreviousAuthentInfo, + LPWSTR lpStationName, + LPVOID StationHandle, + DWORD dwChangeInfo); + +#ifdef __cplusplus +extern "C" { +#endif + +void UnloadFuncs(FUNC_INFO [], HINSTANCE); + +int LoadFuncs(const char*, FUNC_INFO [], HINSTANCE*, int*, int, int, int); + +void DebugEvent0(char *a); +void DebugEvent(char *b,...); + +DWORD MapAuthError(DWORD code); + +static BOOL WINAPI UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen); + +int KFW_is_available(void); +int KFW_get_cred( char * username, char * password, int lifetime, char ** reasonP ); +void KFW_copy_cache_to_system_file(const char * user, const char * filename); +int KFW_destroy_tickets_for_principal(char * user); +int KFW_set_ccache_dacl(char *filename, HANDLE hUserToken); +int KFW_set_ccache_dacl_with_user_sid(char *filename, PSID pUserSID); +int KFW_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size); +void KFW_cleanup_orphaned_caches(void); + +void CALLBACK LogonEventHandlerA(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow); + +#ifdef __cplusplus +} +#endif diff --git a/src/windows/winlevel.h b/src/windows/winlevel.h index 640e828b0..5cc9bbfd0 100644 --- a/src/windows/winlevel.h +++ b/src/windows/winlevel.h @@ -1,33 +1,33 @@ -/* - * winlevel.h - * - * Copyright (C) 2006 by the Massachusetts Institute of Technology. - * All rights reserved. - * - * Export of this software from the United States of America may - * require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. Furthermore if you modify this software you must label - * your software as modified software and not distribute it in such a - * fashion that it might be confused with the original M.I.T. software. - * M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - */ - -/* - * This is the slave file for Windows version stamping purposes. -/* This value should be an ever increasing number that is - * updated for each alpha, beta, final release. This will ensure - * that file identifiers are unique - */ -#define KRB5_BUILDLEVEL 10 +/* + * winlevel.h + * + * Copyright (C) 2006 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +/* + * This is the slave file for Windows version stamping purposes. +/* This value should be an ever increasing number that is + * updated for each alpha, beta, final release. This will ensure + * that file identifiers are unique + */ +#define KRB5_BUILDLEVEL 10 -- 2.26.2