From: Jeffrey Altman Date: Wed, 2 Nov 2005 01:14:30 +0000 (+0000) Subject: Initial Commit Network Identity Manager for Windows X-Git-Tag: ms-bug-test-20060525~77 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5c27b523150384dd8655e739d68f01be2e4ff5d4;p=thirdparty%2Fkrb5.git Initial Commit Network Identity Manager for Windows Initial commit of Network Identity Manager for KFW 3.0 Beta 1 ticket: new tags: pullup component: windows git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@17476 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/windows/Makefile.in b/src/windows/Makefile.in index ebfc6e3a7e..ae3c48f120 100644 --- a/src/windows/Makefile.in +++ b/src/windows/Makefile.in @@ -23,6 +23,11 @@ all-windows:: @echo Making in windows\ms2mit cd ..\ms2mit $(MAKE) -$(MFLAGS) +!if "$(KRB5_KFW_COMPILE)"=="1" + @echo Making in windows\identity + cd ..\identity + $(MAKE) -$(MFLAGS) +!endif cd .. clean-windows:: @@ -44,4 +49,9 @@ clean-windows:: @echo Making clean in windows\ms2mit cd ..\ms2mit $(MAKE) -$(MFLAGS) clean +!if "$(KRB5_KFW_COMPILE)"=="1" + @echo Making clean in windows\identity + cd ..\identity + $(MAKE) -$(MFLAGS) clean +!endif cd .. diff --git a/src/windows/identity/Makefile b/src/windows/identity/Makefile new file mode 100644 index 0000000000..3a79ee5f58 --- /dev/null +++ b/src/windows/identity/Makefile @@ -0,0 +1,179 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +!ifdef ETAGRUN +all: finale doc +!else +all: finale +!endif + +MODULE=all +!include + +!ifndef CLEANRUN +!ifndef TESTRUN +!ifndef ETAGRUN +RMAKE=$(MAKECMD) /nologo all +!else +RMAKE=$(MAKECMD) /nologo etag +!endif +!else +RMAKE=$(MAKECMD) /nologo test +!endif +!else +RMAKE=$(MAKECMD) /nologo clean +!endif + +start: + +config: start + $(ECHO) Entering $@: + $(CD) $@ + $(RMAKE) + $(CD) .. + $(ECHO) Done with $@ + +include: config + $(ECHO) Entering $@: + $(CD) $@ + $(RMAKE) + $(CD) .. + $(ECHO) Done with $@ + +util: include + $(ECHO) Entering $@: + $(CD) $@ + $(RMAKE) + $(CD) .. + $(ECHO) Done with $@ + +kherr: util + $(ECHO) Entering $@: + $(CD) $@ + $(RMAKE) + $(CD) .. + $(ECHO) Done with $@ + +kconfig: kherr + $(ECHO) Entering $@: + $(CD) $@ + $(RMAKE) + $(CD) .. + $(ECHO) Done with $@ + +kmq: kconfig + $(ECHO) Entering $@: + $(CD) $@ + $(RMAKE) + $(CD) .. + $(ECHO) Done with $@ + +kcreddb: kmq + $(ECHO) Entering $@: + $(CD) $@ + $(RMAKE) + $(CD) .. + $(ECHO) Done with $@ + +kmm: kcreddb + $(ECHO) Entering $@: + $(CD) $@ + $(RMAKE) + $(CD) .. + $(ECHO) Done with $@ + +help: kmm + $(ECHO) Entering $@: + $(CD) $@ + $(RMAKE) + $(CD) .. + $(ECHO) Done with $@ + +uilib: help + $(ECHO) Entering $@: + $(CD) $@ + $(RMAKE) + $(CD) .. + $(ECHO) Done with $@ + +nidmgrdll: uilib + $(ECHO) Entering $@ + $(CD) $@ + $(RMAKE) + $(CD) .. + $(ECHO) Done with $@ + +ui: nidmgrdll + $(ECHO) Entering $@: + $(CD) $@ + $(RMAKE) + $(CD) .. + $(ECHO) Done with $@ + +# Now build the plugins +plugincommon: ui + $(ECHO) Entering $@ + $(CD) plugins\common + $(RMAKE) + $(CD) ..\.. + $(ECHO) Done with $@ + +krb5plugin: plugincommon + $(ECHO) Entering $@ + $(CD) plugins\krb5 + $(RMAKE) + $(CD) ..\.. + $(ECHO) Done with $@ + +!ifndef NO_KRB4 +finale: krb4plugin + +krb4plugin: plugincommon + $(ECHO) Entering $@ + $(CD) plugins\krb4 + $(RMAKE) + $(CD) ..\.. + $(ECHO) Done with $@ +!endif + +finale: krb5plugin + $(ECHO) Done. + +pdoc: + +doc: pdoc + $(ECHO) Entering $@: + $(CD) $@ + $(RMAKE) + $(CD) .. + $(ECHO) Done with $@ + +clean:: + $(MAKECMD) /nologo CLEANRUN=1 + +test:: + $(MAKECMD) /nologo TESTRUN=1 + +etags:: + $(RM) $(TAGFILE) + $(MAKECMD) /nologo ETAGRUN=1 diff --git a/src/windows/identity/config/Makefile b/src/windows/identity/config/Makefile new file mode 100644 index 0000000000..686a044ce5 --- /dev/null +++ b/src/windows/identity/config/Makefile @@ -0,0 +1,133 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=config +!include + +all: mkalldirs mkversion + +mkalldirs: +! if !exist($(DESTROOT)) + -$(MKDIR) $(DESTROOT) +! endif +! if !exist($(OBJROOT)) + -$(MKDIR) $(OBJROOT) +! endif +! if !exist($(DESTDIR)) + -$(MKDIR) $(DESTDIR) +! endif +! if !exist($(OBJDIR)) + -$(MKDIR) $(OBJDIR) +! endif +! if !exist($(INCDIR)) + -$(MKDIR) $(INCDIR) +! endif +! if !exist($(BINDIR)) + -$(MKDIR) $(BINDIR) +! endif +! if !exist($(LIBDIR)) + -$(MKDIR) $(LIBDIR) +! endif +! if !exist($(DOCDIR)) + -$(MKDIR) $(DOCDIR) +! endif + $(ECHO) Done creating directories. + +VERSIONINC=$(INCDIR)\khimaira_version.h + +# Version related defines + +! if "$(KH_BUILD)"=="RETAIL" +kh_fileflags=0 +! else +kh_fileflags=VS_FF_DEBUG +! endif +! if "$(KH_RELEASE)"=="PRERELEASE" +kh_fileflags=$(kh_fileflags) | VS_FF_PRERELEASE +! elseif "$(KH_RELEASE)"=="PRIVATE" +kh_fileflags=$(kh_fileflags) | VS_FF_PRIVATEBUILD +! elseif "$(KH_RELEASE)"=="SPECIAL" +kh_fileflags=$(kh_fileflags) | VS_FF_SPECIALBUILD +! endif + +kh_fileos=VOS_NT_WINDOWS32 +kh_filetype_app=VFT_APP +kh_filetype_dll=VFT_DLL + +mkversion: $(VERSIONINC) + +$(VERSIONINC): Makefile + $(CP) << $(VERSIONINC) +/* + * This is an autogenerated file. Do not modify directly. + * + * File generated by running $(MAKE) in $(MAKEDIR) + * To regenerate, run "$(MAKE) clean" and "$(MAKE) all" on $(MAKEDIR) + */ +#ifndef __KHIMAIRA_VERSION_H +#define __KHIMAIRA_VERSION_H + +/* Version number macros */ +#define KH_VERSION_MAJOR $(KHIMAIRA_VERSION_MAJOR) +#define KH_VERSION_MINOR $(KHIMAIRA_VERSION_MINOR) +#define KH_VERSION_PATCH $(KHIMAIRA_VERSION_PATCH) +#define KH_VERSION_AUX $(KHIMAIRA_VERSION_AUX) +#define KH_VERSION_LIST $(KHIMAIRA_VERSIONC) +#define KH_VERSION_STRING "$(KHIMAIRA_VERSION)" +#define KH_VERSION_STRINGW L"$(KHIMAIRA_VERSION)" +#define KH_VERSION_STRINGC "$(KHIMAIRA_VERSIONC)" +#define KH_VERSION_STRINGCW L"$(KHIMAIRA_VERSIONC)" + +/* Version definition macros */ +#define KH_VER_FILEFLAGS $(kh_fileflags) +#define KH_VER_FILEOS $(kh_fileos) +#define KH_VER_FILETYPEDLL $(kh_filetype_dll) +#define KH_VER_FILETYPEAPP $(kh_filetype_app) + +/* Language specific version strings */ +#define KH_VERSTR_COMPANY_1033 "$(KHIMAIRA_SRC_COMPANY_1033)" +#define KH_VERSTR_COPYRIGHT_1033 "$(KHIMAIRA_SRC_COPYRIGHT_1033)" +#define KH_VERSTR_PRODUCT_1033 "$(KHIMAIRA_PRODUCT_1033)" +#define KH_VERSTR_VERSION_1033 "$(KHIMAIRA_VERSION_STR_1033)" + +!ifdef KHIMAIRA_COMMENT_STR_1033 +#define KH_VERSTR_COMMENT_1033 "$(KHIMAIRA_COMMENT_STR_1033)" +#define KH_VERSTR_BUILDINFO_1033 KH_VERSTR_COMMENT_1033 +!endif +!ifdef KHIMAIRA_PRIVATE_STR_1033 +#define KH_VERSTR_PRIVATE_1033 "$(KHIMAIRA_PRIVATE_STR_1033)" +#define KH_VERSTR_BUILDINFO_1033 KH_VERSTR_PRIVATE_1033 +!endif +!ifdef KHIMAIRA_SPECIAL_STR_1033 +#define KH_VERSTR_SPECIAL_1033 "$(KHIMAIRA_SPECIAL_STR_1033)" +#define KH_VERSTR_BUILDINFO_1033 KH_VERSTR_SPECIAL_1033 +!endif +#endif +<< + +clean:: +! if exist($(VERSIONINC)) + $(RM) $(VERSIONINC) +! endif + diff --git a/src/windows/identity/config/Makefile.w32 b/src/windows/identity/config/Makefile.w32 new file mode 100644 index 0000000000..1b862a9ad4 --- /dev/null +++ b/src/windows/identity/config/Makefile.w32 @@ -0,0 +1,278 @@ +# +# Khimaira : Win32 configuration makefile +# This file will be included by all the makefiles +# in the build tree. +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +!ifndef KHIMAIRA_WIN32_CONFIG +KHIMAIRA_WIN32_CONFIG=1 + +# Environment Variables +# The following environment variables MUST be set: +# KH_ROOT : Root of the source tree. +# KH_BUILD: One of DEBUG or RETAIL +# +# The following environment variables are optional: +# KH_RUNTIME: One of STATIC or DLL, specifies whether the CRT libs +# are linked statically or through MSVCRT.DLL. +# KH_AUXCFLAGS: Optional flags for CL +# KH_RELEASE: Release type. One of OFFICIAL, PRERELEASE, PRIVATE or SPECIAL. +# OFFICIAL : An official release of Khimaira +# PREPRELEASE: A beta/release candidate release +# PRIVATE : Private build +# SPECIAL : Special build. Typically one with non-mainline patches. + +# Version info +KHIMAIRA_VERSION_MAJOR=0 +KHIMAIRA_VERSION_MINOR=1 +KHIMAIRA_VERSION_PATCH=1 +KHIMAIRA_VERSION_AUX=0 +KHIMAIRA_VERSION=$(KHIMAIRA_VERSION_MAJOR).$(KHIMAIRA_VERSION_MINOR).$(KHIMAIRA_VERSION_PATCH).$(KHIMAIRA_VERSION_AUX) +KHIMAIRA_VERSIONC=$(KHIMAIRA_VERSION_MAJOR),$(KHIMAIRA_VERSION_MINOR),$(KHIMAIRA_VERSION_PATCH),$(KHIMAIRA_VERSION_AUX) + +# Source information +KHIMAIRA_SRC_COMPANY_1033=Massachusetts Institute of Technology + +KHIMAIRA_SRC_COPYRIGHT_1033=(C) 2005 Massachusetts Institute of Technology + +# Choose the default build type if one is not set +!if ("$(KH_BUILD)" != "DEBUG") && ("$(KH_BUILD)" != "RETAIL") +! if defined(NODEBUG) && "$(NODEBUG)"=="1" +KH_BUILD=RETAIL +! else +KH_BUILD=DEBUG +! endif +!endif + +!if "$(KH_BUILD)"=="DEBUG" && defined(NODEBUG) && "$(NODEBUG)"=="1" +! error The Khimaira build configuration is set for DEBUG while the Platform SDK build environment is set to RETAIL. +!endif + +# The default release type is PRIVATE is no other type is specified +!if ("$(KH_RELEASE)" != "OFFICIAL") && ("$(KH_RELEASE)" != "PRERELEASE") && ("$(KH_RELEASE)" != "PRIVATE") && ("$(KH_RELEASE)" != "SPECIAL") +KH_RELEASE=PRERELEASE +!endif + +# Version and build strings + +!if "$(KH_RELEASE)" == "OFFICIAL" +KHIMAIRA_VERSION_STR_1033=$(KHIMAIRA_VERSION) +KHIMAIRA_COMMENT_STR_1033=Official build. +!elseif "$(KH_RELEASE)" == "PRERELEASE" +KHIMAIRA_VERSION_STR_1033=$(KHIMAIRA_VERSION) Alpha +KHIMAIRA_COMMENT_STR_1033=Prerelease build. +!elseif "$(KH_RELEASE)" == "PRIVATE" +KHIMAIRA_VERSION_STR_1033=$(KHIMAIRA_VERSION).PRIVATE +KHIMAIRA_PRIVATE_STR_1033=Private build. +!elseif "$(KH_RELEASE)" == "SPECIAL" +KHIMAIRA_VERSION_STR_1033=$(KHIMAIRA_VERSION).SPECIAL +KHIMAIRA_SPECIAL_STR_1033=Special build. +!endif + +!if "$(KH_BUILD)" == "DEBUG" +KHIMAIRA_VERSION_STR_1033=$(KHIMAIRA_VERSION_STR_1033).DEBUG +!else +!endif + +KHIMAIRA_PRODUCT_1033=NetIDMgr $(KHIMAIRA_VERSION_STR_1033) + +# See what compiler we are using +# TODO: Update this to support other compilers +!if defined(MSVCVer) && "$(MSVCVer)"=="8.0" +KH_CLVER=vc8 +!else +KH_CLVER=vc7 +!endif + +# Check for required env vars +!ifndef MODULE +! error MODULE must be specified +!endif +!ifndef KH_ROOT +KH_ROOT=$(PISMERE)\athena\auth\krb5\src\windows\identity +!endif + +!ifdef NODEBUG +OUTPRE_DBG=rel +!else +OUTPRE_DBG=dbg +!endif +OUTPRE1=obj +OUTPRE2=$(OUTPRE1)\$(CPU) +OUTPRE3=$(OUTPRE2)\$(OUTPRE_DBG) +OUTPRE=$(OUTPRE3)^\ + + + +# Output directory structure +DESTROOT=$(KH_ROOT)\dest +OBJROOT=$(KH_ROOT)\obj +SRC=$(KH_ROOT) + +DESTDIR=$(DESTROOT)\$(CPU)\$(OUTPRE_DBG) +OBJDIR=$(OBJROOT)\$(CPU)\$(OUTPRE_DBG) + +OBJ=$(OBJDIR)\$(MODULE) +INCDIR=$(DESTDIR)\include +#BINDIR=$(DESTDIR)\bin +BINDIR=$(KH_ROOT)\$(OUTPRE) +#LIBDIR=$(DESTDIR)\lib +LIBDIR=$(KH_ROOT)\$(OUTPRE) +DOCDIR=$(DESTDIR)\doc + +# Source directories +CONFDIR=$(SRC)\config + +# Setup environment for win32.mak + +!if "$(KH_BUILD)" == "RETAIL" +NODEBUG=1 +!endif + +# Win32.mak +!include + +# Program macros + +CD=cd +RM=del /q +MKDIR=mkdir +RMDIR=rmdir +ECHO=echo +MAKECMD=nmake +CP=copy /y +LINK=link +CCSV=perl $(SRC)\config\ccsv.pl +MC=mc + +!ifdef KH_DOXYFULLPATH +DOXYGEN=$(KH_DOXYFULLPATH) +!else +DOXYGEN=doxygen +!endif + +!ifdef KH_HHCFULLPATH +HHC=$(KH_HHCFULLPATH) +!else +HHC=hhc +!endif + +!ifdef KH_KFWPATH +KFWINCDIR=$(KH_KFWPATH)\inc +kfwincflags = -I$(KFWINCDIR)\krb5 -I$(KFWINCDIR)\krb5\KerberosIV -I$(KFWINCDIR)\loadfuncs -I$(KFWINCDIR) +KFWLIBDIR=$(KH_KFWPATH)\lib\$(CPU) +!else +KFWINCDIR=$(PISMERE)\athena\auth\krb5\src\include +kfwincflags = -I$(KFWINCDIR) -I$(PISMERE)\athena\util\loadfuncs -I$(PISMERE)\athena\auth\krb5\src\include\kerberosIV -I$(PISMERE)\athena\auth\krb4\include +KFWLIBDIR=$(PISMERE)\target\lib\$(CPU)\$(OUTPRE_DBG) +!endif + +!ifdef KH_AFSPATH +AFSINCDIR=$(KH_AFSPATH)\include +AFSLIBDIR=$(KH_AFSPATH)\lib +afsincflags=-I$(AFSINCDIR) +!endif + +#EXTLIBDIR=$(SRC)\ext-lib\$(CPU) +#EXTINCDIR=-I$(SRC)\ext-inc + +incflags= -I$(INCDIR) -I$(SRC)\include -I. -I$(OBJ) $(kfwincflags) $(afsincflags) +rincflags= /i $(INCDIR) /i $(SRC)\include /i . +khdefines=-DUNICODE -D_UNICODE +khcwarn=/Wp64 +!ifndef KH_NO_WX +khcwarn=$(khcwarn) /WX +!endif + +khcflags=$(cdebug) $(cflags) $(incflags) $(khdefines) $(khcwarn) +khlguiflags=$(ldebug) $(guilflags) +khlconflags=$(ldebug) $(conlflags) +khldllguiflags=$(ldebug) $(dlllflags) +khldllconflags=$(ldebug) $(dlllflags) + +!if "$(KH_RUNTIME)" == "STATIC" +khcflags=$(khcflags) $(cvarsmt) +khlguiflags=$(khlguiflags) $(guilibsmt) +khlconflags=$(khlconflags) $(conlibsmt) +khldllguiflags=$(khldllguiflags) $(guilibsmt) +khldllconflags=$(khldllconflags) $(conlibsmt) +!else +khcflags=$(khcflags) $(cvarsdll) +khlguiflags=$(khlguiflags) $(guilibsdll) +khlconflags=$(khlconflags) $(conlibsdll) +khldllguiflags=$(khldllguiflags) $(guilibsdll) +khldllconflags=$(khldllconflags) $(conlibsdll) +!endif + +C2OBJ=$(CC) $(khcflags) $(KH_AUXCFLAGS) /Fo"$@" /c $** + +EXECONLINK=$(LINK) /NOLOGO $(khlconflags) /OUT:$@ $** + +EXEGUILINK=$(LINK) /NOLOGO $(khlguiflags) /OUT:$@ $** + +DLLCONLINK=$(LINK) /NOLOGO $(khldllconflags) /OUT:$@ /IMPLIB:$(LIBDIR)\$(@B).lib $** + +DLLGUILINK=$(LINK) /NOLOGO $(khldllguiflags) /OUT:$@ /IMPLIB:$(LIBDIR)\$(@B).lib $** + +DLLRESLINK=$(LINK) /NOLOGO /DLL /NOENTRY /MACHINE:$(PROCESSOR_ARCHITECTURE) /OUT:$@ $** + +RC2RES=$(RC) $(RFLAGS) $(rincflags) /fo $@ $** + +MC2RC=$(MC) $(MCFLAGS) -h $(OBJ)\ -m 1024 -r $(OBJ)\ -x $(OBJ)\ $** + +{}.c{$(OBJ)}.obj: + $(C2OBJ) + +{$(OBJ)}.c{$(OBJ)}.obj: + $(C2OBJ) + +{}.h{$(INCDIR)}.h: + $(CP) $** $@ + +{}.rc{$(OBJ)}.res: + $(RC2RES) + +{$(OBJ)}.rc{$(OBJ)}.res: + $(RC2RES) + +clean:: +!if exist($(OBJ)) + $(RM) $(OBJ)\ +!endif + +test:: + +mkdirs:: +!if !exist($(OBJ)) + $(MKDIR) $(OBJ) +!endif + +TAGFILE = $(SRC)\TAGS + +etag:: + etags -o $(TAGFILE) -a *.c *.h + +.SUFFIXES: .h + +!endif diff --git a/src/windows/identity/config/ccsv.pl b/src/windows/identity/config/ccsv.pl new file mode 100644 index 0000000000..c6c82814f2 --- /dev/null +++ b/src/windows/identity/config/ccsv.pl @@ -0,0 +1,124 @@ +#!/usr/bin/perl + +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + + +# This is a simple script that is used for generating C code from CSV +#files. We expect three arguments, the which is the .csv file +#to be parsed, a which is a configuration file and the +#. + +# The configuration file is a perl file which defines the following +#variables : + +# $skip_lines : the number of lines to skip in the csv. The default is 0 + +# @pquote : an array of boolean integers that specify whether or not +# to quote the specific field using double quotes. The default is to +# not quote anything. + +# $file_prefix : the prefix for the file + +# $record_prefix : the prefix for each record + +# $field_sep : the field separator. The default is ',' + +# $record_postfix : the postfix for each record + +# $record_sep : A record separator. Only shows up between records. + +# $file_postfix : the postfix for the entire file + +use Text::ParseWords; + +sub do_nothingus { +} + +if($#ARGV != 2) { + print "Usage: ccsv.pl \n"; + die; +} + +$infn=$ARGV[0]; +$cfgfn=$ARGV[1]; +$outfn=$ARGV[2]; + +$skip_lines = 0; +@pquote = {}; +$file_prefix = ""; +$record_prefix = ""; +$field_sep = ","; +$record_postfix = ""; +$record_sep = "\n"; +$file_postfix = ""; +$record_parser = \&do_nothingus; + +($inbase) = ($infn =~ m/^(\w*)/); + +do $cfgfn; + +open(IN, "<".$infn) or die "Can't open input file:".$infn; +open(OUT, ">".$outfn) or die "Can't open output file:".$outfn; + +print OUT $file_prefix; + +$first_line = 1; + +while() { + chomp $_; + if($skip_lines > 0) { + $skip_lines--; + } elsif (m/^\#/) { + # ignore + } else { + if($first_line == 0){ + print OUT $record_sep; + } else { + $first_line = 0; + } + + @fields = &parse_line(',',0,$_); + for(@fields) { + chomp; + s/^\s*//; + } + + &$record_parser(\@fields); + + print OUT $record_prefix; + for(my $i=0; $i <= $#fields; $i++) { + print OUT $field_sep if $i != 0; + print OUT 'L"' if $pquote[$i] == 1; + print OUT $fields[$i]; + print OUT '"' if $pquote[$i] == 1; + } + print OUT $record_postfix; + } +} + +print OUT $file_postfix; + +close INF; +close OUT; diff --git a/src/windows/identity/config/csvschema.cfg b/src/windows/identity/config/csvschema.cfg new file mode 100644 index 0000000000..ba3bf9bfce --- /dev/null +++ b/src/windows/identity/config/csvschema.cfg @@ -0,0 +1,67 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +$file_prefix = < + +kconf_schema schema_$inbase\[] = { +EOS + +$record_prefix = "{"; + +$record_sep = ",\n"; + +$record_postfix = "}"; + +$file_postfix = < + +CONFFILE=$(OBJ)\DoxyConf.cfg + +all: mkdirs docs + +docs: + $(DOXYGEN) << +@INCLUDE = doxyfile.cfg + +PROJECT_NUMBER = "$(KHIMAIRA_VERSION)" + +OUTPUT_DIRECTORY = "$(DOCDIR)" + +STRIP_FROM_PATH = "$(SRC)" + +INTERNAL_DOCS = NO + +WARN_LOGFILE = "$(OBJ)\doxywarnings.txt" + +INPUT = "$(SRC)\include" +INPUT += "$(SRC)\kconfig" +INPUT += "$(SRC)\kcreddb" +INPUT += "$(SRC)\khlog" +INPUT += "$(SRC)\kmq" +INPUT += "$(SRC)\ui" +INPUT += "$(SRC)\uilib" +INPUT += "$(SRC)\util" +INPUT += "$(SRC)\doc" +INPUT += "$(SRC)\kmm" +INPUT += "$(SRC)\kherr" + +IMAGE_PATH = "$(SRC)\doc\images" + +INCLUDE_PATH = "$(INCDIR)" "$(SRC)\include" + +CHM_FILE = "$(DOCDIR)\devdocs.chm" +<< + -$(HHC) $(DOCDIR)\html\index.hhp + +clean:: + $(RMDIR) /s $(DOCDIR)\html + $(RM) $(DOCDIR)\*.* diff --git a/src/windows/identity/doc/cred_aquisition.h b/src/windows/identity/doc/cred_aquisition.h new file mode 100644 index 0000000000..1adb3b8f58 --- /dev/null +++ b/src/windows/identity/doc/cred_aquisition.h @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! \page cred_acq Managed credential acquisition + + Credential providers and the identity provider must participate in + managed credential acquisition in order to respond to the user's + requests to obtain new credentials for an identity or to obtain + new credentials for an existing identity. + + There are two major processes that result in managed credential + acuqisition. One is the acquisition of initial credentials, while + the other is the acquisition of new crednetials. Both processes + acquire new credentials (or replace existing credentials with new + ones). The difference between the two processes lie in the way the + new credentials are obtained. Initial credentials are obtained + using user supplied username and password while new credentials + are obtained using other existing credentials. + + \section cred_acq_init Initial Credentials + + When a user initiates the process of initial credential + acquisition, NetIDMgr broadcasts a + <::KMSG_CRED,::KMSG_CRED_INITIAL_CREDS> message. Credential + providers which need to participate in the initial credential + acquisition should respond to this message as detailed in + \ref cred_acq_handle. + + \section cred_acq_new New Credentials + + When a user initiates the process of obtaining new credentials + based on existing credentials, NetIDMgr broadcasts a + <::KMSG_CRED,::KMSG_CRED_NEW_CREDS> message. Credential providers + which need to participate in the initial credential acquisition + 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 new credentials whether they are initial + credentials or not, happen as follows : + + - NetIDMgr creates a ::khui_new_creds object and a credentials + acquisition window. + + - <::KMSG_CRED,::KMSG_CRED_INITIAL_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. + + - <::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 completes, NetIDMgr sends + <::KMSG_CRED,::KMSG_CRED_DIALOG_END> message to all the + credentials providers. The UI portion ends here. The + individual dialog controls are destroyed as a result of the main + credentials acquisition window being destroyed. + + - NetIDMgr 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 + 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_INITIAL_CREDS> and <::KMSG_CRED, + ::KMSG_CRED_NEW_CREDS>. They are structured as follows : + + - \b type : ::KMSG_CRED + - \b subtype: ::KMSG_CRED_INITIAL_CREDS or ::KMSG_CRED_NEW_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 an + initial credentials acquisition or a new credentials acquisition + at any point. + + 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_cred_panel 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_cred_panel 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. 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. + + The \a hwnd_panel field is used to specify the handle to the + dialog or window of the panel. The parent of this window should + be set to the \a hwnd parameter of the ::khui_new_creds structure + which is passed in to the message handler. + + Following is a code snippet 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 = malloc(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"; + + t->hwnd_panel = CreateDialog( + my_hInstance, + MAKEINTRESOURCE(IDD_MY_PANEL), + c->hwnd, + my_dialog_proc); + + 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_DIALOG_PROCESS> 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 new file mode 100644 index 0000000000..3257520e1f --- /dev/null +++ b/src/windows/identity/doc/cred_data_types.h @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! \page cred_data_types Data types in NetIDMgr + + NetIDMgr'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 + + Pretty useless. This data type is used to indicate that the associated + object doesn't actually contain any data. + + \subsubsection kcdb_pg_idt_s 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 + + Dates and times in NetIDMgr are stored as \a FILETIME structures. Utility + functions are provided for converting from other formats such as \a time_t. + + \subsubsection kcdb_pg_idt_i 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 designate an interval of time. + + The special value _I64_MAX (which is defined in limits.h as + 0x7fffffffffffffff, or in otherwords, 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 + + A signed 32 bit integer. + + \subsubsection kcdb_pg_idt_i64 Int64 + + A signed 64 bit integer. + + \subsubsection kcdb_pg_idt_da 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 NetIDMgr Credentials Database are defined using + \a kcdb_type structures which 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 new file mode 100644 index 0000000000..e8f7d29993 --- /dev/null +++ b/src/windows/identity/doc/cred_main.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! \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 new file mode 100644 index 0000000000..a1b2c2cc27 --- /dev/null +++ b/src/windows/identity/doc/cred_msgs.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! \page cred_msgs Handling credentials provider messages + +A credentials provider plugin 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 plugin. 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 new file mode 100644 index 0000000000..5e844833f4 --- /dev/null +++ b/src/windows/identity/doc/cred_prop_pages.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! \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 NetIDMgr 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/doxyfile.cfg b/src/windows/identity/doc/doxyfile.cfg new file mode 100644 index 0000000000..7aac8021b5 --- /dev/null +++ b/src/windows/identity/doc/doxyfile.cfg @@ -0,0 +1,1000 @@ +# Doxyfile 1.2.18 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = NetIDMgr + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, +# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en +# (Japanese with english messages), Korean, Norwegian, Polish, Portuguese, +# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these class will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will +# prepend the brief description of a member or function before the +# detailed description. Note: if both HIDE_UNDOC_MEMBERS and +# BRIEF_MEMBER_DESC are set to NO, the brief descriptions will be +# completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show +# all inherited members of a class in the documentation of that class +# as if those members were ordinary class members. Constructors, +# destructors and assignment operators of the base classes will not be +# shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower case letters. If set to YES upper case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# users are adviced to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explict @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consist of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +SHOW_DIRECTORIES = NO + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp +# *.h++ *.idl *.odl + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = header.html + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = footer.html + +# The HTML_STYLESHEET tag can be used to specify a user defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = stylesheet.css + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = YES + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output dir. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non empty doxygen will try to run +# the html help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the Html help documentation and to the tree view. + +TOC_EXPAND = YES + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one +# that is generated for HTML Help). For this to work a browser that +# supports JavaScript and frames is required (for instance Mozilla, +# Netscape 4.0+, or Internet explorer 4.0+). Note that for large +# projects the tree generation can take a very long time. In such +# cases it is better to disable this feature. Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_XML = NO + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = _WIN32 \ + UNICODE \ + _UNICODE + +# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are +# alone on a line, have an all uppercase name, and do not end with a +# semicolon. Such function macros are typically used for boiler-plate +# code, and will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tagfiles. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. Note that this +# option is superceded by the HAVE_DOT option below. This is only a fallback. It is +# recommended to install and use dot, since it yield more powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermedate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. + +CGI_NAME = search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. + +CGI_URL = + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. + +DOC_URL = + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. + +DOC_ABSPATH = + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. + +BIN_ABSPATH = /usr/local/bin/ + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. + +EXT_DOC_PATHS = diff --git a/src/windows/identity/doc/footer.html b/src/windows/identity/doc/footer.html new file mode 100644 index 0000000000..13314c2b04 --- /dev/null +++ b/src/windows/identity/doc/footer.html @@ -0,0 +1,19 @@ +
+ + + + + + +
+
+ Generated on $datetime for $projectname $projectnumber by Doxygen $doxygenversion
+ © 2004 Massachusetts Institute of Technology. Contact khimaira@mit.edu
+
+
+
+ +
+ + + diff --git a/src/windows/identity/doc/header.html b/src/windows/identity/doc/header.html new file mode 100644 index 0000000000..4235468f36 --- /dev/null +++ b/src/windows/identity/doc/header.html @@ -0,0 +1,5 @@ + + +$title + + diff --git a/src/windows/identity/doc/images/Thumbs.db b/src/windows/identity/doc/images/Thumbs.db new file mode 100644 index 0000000000..371f5d62e6 Binary files /dev/null and b/src/windows/identity/doc/images/Thumbs.db differ diff --git a/src/windows/identity/doc/images/credview-select-outline.jpg b/src/windows/identity/doc/images/credview-select-outline.jpg new file mode 100644 index 0000000000..d06ca9f88c Binary files /dev/null and b/src/windows/identity/doc/images/credview-select-outline.jpg differ diff --git a/src/windows/identity/doc/images/khimaira_logo.png b/src/windows/identity/doc/images/khimaira_logo.png new file mode 100644 index 0000000000..26c338007d Binary files /dev/null and b/src/windows/identity/doc/images/khimaira_logo.png differ diff --git a/src/windows/identity/doc/images/khimaira_logo_old.jpg b/src/windows/identity/doc/images/khimaira_logo_old.jpg new file mode 100644 index 0000000000..10e8fde4db Binary files /dev/null and b/src/windows/identity/doc/images/khimaira_logo_old.jpg differ diff --git a/src/windows/identity/doc/images/khimaira_logo_small.png b/src/windows/identity/doc/images/khimaira_logo_small.png new file mode 100644 index 0000000000..26c338007d Binary files /dev/null and b/src/windows/identity/doc/images/khimaira_logo_small.png differ diff --git a/src/windows/identity/doc/images/khimaira_logo_small_old.jpg b/src/windows/identity/doc/images/khimaira_logo_small_old.jpg new file mode 100644 index 0000000000..94d8d19113 Binary files /dev/null and b/src/windows/identity/doc/images/khimaira_logo_small_old.jpg differ diff --git a/src/windows/identity/doc/main_page.h b/src/windows/identity/doc/main_page.h new file mode 100644 index 0000000000..545e9ee174 --- /dev/null +++ b/src/windows/identity/doc/main_page.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! \mainpage NetIDMgr + + \image html khimaira_logo.png + + \section main_dev Documentation for Developers + + NetIDMgr is a credentials manager, which currently manages + Kerberos IV, Kerberos V and AFS credentials. This document + describes the API that is implemented by the NetIDMgr system. + + See the following sections for more information : + - \subpage license + - \subpage bugs + - \subpage releases + + © 2004 Massachusetts Institute of Technology +*/ + +/*! + \page license License agreement and credits + + NetIDMgr is distributed under the MIT License. + + \section license_l MIT License + + Copyright © 2004 Massachusetts Institute of Technology + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + \section license_credits Credits + + NetIDMgr was developed at the Massachusetts Institute of + Technology. + + (Contributor list goes here) + + Information Services and + Technology at Massachusetts + Institute of Technology +*/ + +/*! \page bugs Reporting bugs + + NetIDMgr bugs can be reported to + khimaira@mit.edu for now. + + In the future, there will actually be a place to track NetIDMgr bugs. + + When reporting bugs, please include as much information as + possible to help diagnose the problem. More guidelines about + reporting bugs will appear here at some point in time. + + \image html khimaira_logo_small.png +*/ + +/*! \page releases Prior releases + + - 0.1.1 (Charles Manson) [soon]\n + First alpha release. As stable as Charles Manson, hence the + name. + + - 0.1.2 (tbd) [tbd]\n + First beta release. +*/ diff --git a/src/windows/identity/doc/plugin_framework.h b/src/windows/identity/doc/plugin_framework.h new file mode 100644 index 0000000000..dbf1600803 --- /dev/null +++ b/src/windows/identity/doc/plugin_framework.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! +\page pi_framework Plugin Framework + +\section pi_fw_pnm Plugins and Modules + +\subsection pi_fw_pnm_p Plugins + +A NetIDMgr plugin is a package that implements a defined API that will +perform credentials management or related tasks on behalf of NetIDMgr. +The core NetIDMgr codebase does not interact directly with Kerberos of +AFS or any other external entity directly. Instead, plugins are used +to abstract out this task. + +Each plugin has a name. The name should be unique among the loaded +plugins, or the plugin will fail to load. + +The method in which NetIDMgr communicates with a plugin depends on the +plugin type. For more information on each plugin type, please refer +to \ref pi_pt. + +Most plugin types rely on a message processor for communication. +During plugin registration, the module specifies the message processor +for the plugin, which acts as the only point of contact between the +NetIDMgr core and the plugin. Some other plugins require exporting +specific functions. + +\subsection pi_fw_pnw_m Modules + +One or more plugins can be bundled together into a module. A module +is essentially a dynamically loadable library which contain a specific +set of callbacks. Currently, the only two required callbacks for a +module are : + +- init_module(), and +- exit_module() + +\section pi_fw_pm Plugin/Module Manager + +The plugin manager maintains a separate thread for loading and +registering modules. When a module is successfully loaded and it +registers one or more plugins, a new thread is created for each +plugin. Plugin specific initialization and other callback functions +are called from within this new thread. This is to prevent one plugin +from "hanging" other plugins and the main NetIDMgr UI threads. + +Read more : +- \ref pi_structure + +\subsection pi_fw_pm_load Load sequence + +When kmm_load_module() is called, the following sequence of events +happen. + +- The standard system search path is used to locate the binary. + +- The binary is loaded into the address space of NetIDMgr along with + any dependencies not already loaded. + +- If the NetIDMgr 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. + +- init_module() for the loaded module is called. If this function + returns an error or if no plugins are registered, then the module is + 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 + plugins that it is implementing by calling kmm_register_plugin() for + each. + +- Once init_module() returns, each plugin is initialized. The method + by which a plugin is initialized depends on the plugin type. The + initialization code for the plugin may indicate that it didn't + initialize properly, in which case the plugin is immediately + unregistered. No further calls are made to the plugin. + +- If no plugin is successfully loaded, the module is unloaded. See + \ref pi_fw_pm_unload. + +- During normal operation, any registered plugins for a module can be + unloaded explicitly, or the plugin itself may signal that it should + be unloaded. If at anytime, all the plugins for the module are + unloaded, then the module itself is also unloaded. + +\subsection pi_fw_pm_unload Unload sequence + +- For each of the plugins that are registered for a module, the exit + code is invoked. The method by which this happens depends on the + plugin type. The plugin is not given a chance to object to the + decision to unload. Each plugin is responsible for performing + cleanup tasks, freeing resources and unsubscribing from any message + classes that it has subscribed to. + +- exit_module() is called for the module. + +- If any localized resource libraries were loaded for the module, they + are unloaded. + +- The module is unloaded. + + */ diff --git a/src/windows/identity/doc/plugin_locale.h b/src/windows/identity/doc/plugin_locale.h new file mode 100644 index 0000000000..3cb65a4221 --- /dev/null +++ b/src/windows/identity/doc/plugin_locale.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! +\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 plugin 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 plugin. + +\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 new file mode 100644 index 0000000000..ed8d038e20 --- /dev/null +++ b/src/windows/identity/doc/plugin_main.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! + +\page plugins NetIDMgr Modules and Plugins + +Plugins and localization are handled by the NetIDMgr Module Manager +API. Each plugin consists of a dynamically loadable library and zero +or more associated resource libraries. + +For more information about NetIDMgr Plugins, see the following +sections: + +- \subpage pi_framework +- \subpage pi_pt +- \subpage pi_structure +- \subpage pi_localization +*/ + +/*! \page pi_pt Plugin Types + +The types of plugins that are currently supported by NetIDMgr are : + +\section pi_pt_cred Credential Provider + +A credential provider plugin essentially acts as an interface between +NetIDMgr 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 NetIDMgr 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 plugins, <::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 plugin is assume to not be loaded and +immediately unregistered. + +The message processor is automatically subscribed to the following +message types: +- ::KMSG_SYSTEM +- ::KMSG_KCDB + +Although a plugin 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 plugins 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 plugin is to be removed, the module manager sends a +<::KMSG_SYSTEM,::KMSG_SYSTEM_EXIT> to the message processor. The +plugin 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 plugin if the plugin 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. + +\section pi_pt_conf Configuration Provider + +Provides configuration information. +[TODO: fill in] + +\subsection pi_pt_conf_comm Communication +[TODO: fill in] + +\subsection pi_pt_conf_init Initialization +[TODO: fill in] + +\subsection pi_pt_conf_exit Uninitialization +[TODO: fill in] + +\subsection pi_pt_conf_other Other Notes + +*/ + diff --git a/src/windows/identity/doc/plugin_structure.h b/src/windows/identity/doc/plugin_structure.h new file mode 100644 index 0000000000..8c57b0300e --- /dev/null +++ b/src/windows/identity/doc/plugin_structure.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! + +\page pi_structure Structure of a module + +A NetIDMgr module is essentially a dynamically loadable library with a +specific set of exported symbols. Each export symbol and general +notes about writing a plugin module are documented below. + +\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 NetIDMgr 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/stylesheet.css b/src/windows/identity/doc/stylesheet.css new file mode 100644 index 0000000000..fc3e0624db --- /dev/null +++ b/src/windows/identity/doc/stylesheet.css @@ -0,0 +1,271 @@ +BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Geneva, Arial, Helvetica, sans-serif; +} +H1 { + text-align: center; +} +CAPTION { font-weight: bold } +DIV.qindex { + width: 100%; + background-color: #000000; + border: 1px solid #000000; + margin: 2px; + padding: 2px; + line-height: 100%; + color: #ffffff +} +DIV.nav { + width: 100%; + background-color: #000000; + border: 1px solid #000000; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 100%; + color: #ffffff; +} +A.qindex { + text-decoration: none; + color: #ffffff; +} +A.qindex:visited { + text-decoration: none; + color: #ffffff; +} +A.qindex:hover { + text-decoration: none; + background-color: #ffffff; + color: #000000 +} +A.qindexHL { + text-decoration: none; + font-weight: bold; +} +A.qindexHL:hover { + text-decoration: none; + background-color: #333333; + color: #ffffff; +} +A.qindexHL:visited { text-decoration: none; background-color: #333333; color: #ffffff } +A.el { text-decoration: none; } +A.elRef { } +A.code:link { text-decoration: none; font-weight: normal; color: #0000FF} +A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF} +A.codeRef:link { font-weight: normal; color: #0000FF} +A.codeRef:visited { font-weight: normal; color: #0000FF} +A:hover { text-decoration: none; background-color: #cccccc } +DL.el { margin-left: -1cm } +.fragment { + font-family: monospace +} +PRE.fragment { + border: 1px solid #CCCCCC; + background-color: #f5f5f5; + margin-top: 4px; + margin-bottom: 4px; + margin-left: 2px; + margin-right: 8px; + padding-left: 6px; + padding-right: 6px; + padding-top: 4px; + padding-bottom: 4px; +} +DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } +TD.md { background-color: #cccccc; font-weight: bold; } +TD.mdname1 { background-color: #cccccc; font-weight: bold; color: #000000; } +TD.mdname { background-color: #cccccc; font-weight: bold; color: #000000; width: 600px; } +DIV.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; +} +DIV.groupText { margin-left: 16px; font-style: italic; font-size: 14px } +BODY { + background: white; + color: black; + margin-right: 20px; + margin-left: 20px; +} +TD.indexkey { + background-color: #cccccc; + font-weight: bold; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TD.indexvalue { + background-color: #cccccc; + font-style: italic; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TR.memlist { + background-color: #f0f0f0; +} +P.formulaDsp { text-align: center; } +IMG.formulaDsp { } +IMG.formulaInl { vertical-align: middle; } +SPAN.keyword { color: #008000 } +SPAN.keywordtype { color: #604020 } +SPAN.keywordflow { color: #e08000 } +SPAN.comment { color: #800000 } +SPAN.preprocessor { color: #806020 } +SPAN.stringliteral { color: #002080 } +SPAN.charliteral { color: #008080 } +.mdTable { + border: 1px solid #cccccc; + background-color: #cccccc; +} +.mdRow { + padding: 8px 10px; +} +.mdescLeft { + padding: 0px 8px 4px 8px; + font-size: 12px; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.mdescRight { + padding: 0px 8px 4px 8px; + font-size: 12px; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.memItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 12px; +} +.memItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 13px; +} +.memTemplItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 12px; +} +.memTemplItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 13px; +} +.memTemplParams { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + color: #606060; + background-color: #FAFAFA; + font-size: 12px; +} +.search { color: #003399; + font-weight: bold; +} +FORM.search { + margin-bottom: 0px; + margin-top: 0px; +} +INPUT.search { font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #ffcc99; +} +TD.tiny { font-size: 75%; +} +a { + color: #0000ff; +} +a:visited { + color: #0000ff; +} +.anchor { + color: #000000; +} \ No newline at end of file diff --git a/src/windows/identity/doc/ui_actions.h b/src/windows/identity/doc/ui_actions.h new file mode 100644 index 0000000000..ab3848ed3b --- /dev/null +++ b/src/windows/identity/doc/ui_actions.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! \page khui_actions Actions + + */ diff --git a/src/windows/identity/doc/ui_context.h b/src/windows/identity/doc/ui_context.h new file mode 100644 index 0000000000..8ef325049d --- /dev/null +++ b/src/windows/identity/doc/ui_context.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! \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 NetIDMgr 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 plugin 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 plugin 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 new file mode 100644 index 0000000000..0f9ab661c4 --- /dev/null +++ b/src/windows/identity/doc/ui_main.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! \page khui User Interface Topics + + \section khui_contents Contents + + - \subpage khui_actions + - \subpage khui_menus + - \subpage khui_context + */ diff --git a/src/windows/identity/doc/ui_menus.h b/src/windows/identity/doc/ui_menus.h new file mode 100644 index 0000000000..c7a95a3640 --- /dev/null +++ b/src/windows/identity/doc/ui_menus.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! \page khui_menus Menus + + */ diff --git a/src/windows/identity/help/Index.hhk b/src/windows/identity/help/Index.hhk new file mode 100644 index 0000000000..2e24f6f3ec --- /dev/null +++ b/src/windows/identity/help/Index.hhk @@ -0,0 +1,9 @@ + + + + + + +
    +
+ diff --git a/src/windows/identity/help/Makefile b/src/windows/identity/help/Makefile new file mode 100644 index 0000000000..2b823d85a6 --- /dev/null +++ b/src/windows/identity/help/Makefile @@ -0,0 +1,36 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=help +!include <..\config\Makefile.w32> + +CHMFILE=$(DOCDIR)\netidmgr.chm + +INCFILES=$(INCDIR)\khhelp.h + +all: mkdirs $(CHMFILE) $(INCFILES) + +$(CHMFILE): netidmgr.hhp + -hhc netidmgr.hhp + $(CP) netidmgr.chm $(CHMFILE) diff --git a/src/windows/identity/help/html/images/Thumbs.db b/src/windows/identity/help/html/images/Thumbs.db new file mode 100644 index 0000000000..01828e4deb Binary files /dev/null and b/src/windows/identity/help/html/images/Thumbs.db differ diff --git a/src/windows/identity/help/html/images/link.GIF b/src/windows/identity/help/html/images/link.GIF new file mode 100644 index 0000000000..1af792f08d Binary files /dev/null and b/src/windows/identity/help/html/images/link.GIF differ diff --git a/src/windows/identity/help/html/khm.css b/src/windows/identity/help/html/khm.css new file mode 100644 index 0000000000..82c4d57f76 --- /dev/null +++ b/src/windows/identity/help/html/khm.css @@ -0,0 +1,13 @@ +BODY { font-family:helvetica,sans-serif; + font-size:8pt; + font-style:normal; + background-color:white; } + +H1 { font-size: 10pt; + border:solid 1px black; + padding:5px; + background-color:lightgrey + } + +H2 { } + diff --git a/src/windows/identity/help/html/menu_exit.htm b/src/windows/identity/help/html/menu_exit.htm new file mode 100644 index 0000000000..2130df192f --- /dev/null +++ b/src/windows/identity/help/html/menu_exit.htm @@ -0,0 +1,9 @@ + + + title + + + + + + \ No newline at end of file diff --git a/src/windows/identity/help/html/menu_file.htm b/src/windows/identity/help/html/menu_file.htm new file mode 100644 index 0000000000..021f71f5a4 --- /dev/null +++ b/src/windows/identity/help/html/menu_file.htm @@ -0,0 +1,18 @@ + + + File menu + + + + + +

File menu

+ +

Menu items

+ + + + \ No newline at end of file diff --git a/src/windows/identity/help/html/menu_properties.htm b/src/windows/identity/help/html/menu_properties.htm new file mode 100644 index 0000000000..2130df192f --- /dev/null +++ b/src/windows/identity/help/html/menu_properties.htm @@ -0,0 +1,9 @@ + + + title + + + + + + \ No newline at end of file diff --git a/src/windows/identity/help/html/template.htm b/src/windows/identity/help/html/template.htm new file mode 100644 index 0000000000..2130df192f --- /dev/null +++ b/src/windows/identity/help/html/template.htm @@ -0,0 +1,9 @@ + + + title + + + + + + \ No newline at end of file diff --git a/src/windows/identity/help/html/welcome.htm b/src/windows/identity/help/html/welcome.htm new file mode 100644 index 0000000000..32d7d05b26 --- /dev/null +++ b/src/windows/identity/help/html/welcome.htm @@ -0,0 +1,24 @@ + + + Welcome to Khimaira + + + + + +

Welcome to Khimaira

+ +

Khimaira is a credentials manager that lets you manage Kerberos, +AFS and other types of credentials. +

+ +

The following web sites provide more information about Kerberos and +AFS:

+ + + + + \ No newline at end of file diff --git a/src/windows/identity/help/khhelp.h b/src/windows/identity/help/khhelp.h new file mode 100644 index 0000000000..4ffa6d8f59 --- /dev/null +++ b/src/windows/identity/help/khhelp.h @@ -0,0 +1,23 @@ + +#define IDH_WELCOME 1000 +#define IDH_MENU_FILE 1001 +#define IDH_MENU_CRED 1002 +#define IDH_MENU_VIEW 1003 +#define IDH_MENU_OPTIONS 1004 +#define IDH_MENU_HELP 1005 + +#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 diff --git a/src/windows/identity/help/netidmgr.hhp b/src/windows/identity/help/netidmgr.hhp new file mode 100644 index 0000000000..8e0d5a5979 --- /dev/null +++ b/src/windows/identity/help/netidmgr.hhp @@ -0,0 +1,21 @@ +[OPTIONS] +Auto Index=Yes +Compatibility=1.1 or later +Compiled file=netidmgr.chm +Contents file=toc.hhc +Default topic=html/welcome.htm +Display compile progress=No +Index file=Index.hhk +Language=0x409 English (United States) +Title=NetIDMgr + + +[MAP] +#include khhelp.h + +[INFOTYPES] +Category:Concepts +CategoryDesc:Authentication, authorization and related concepts. +Category:Usage +CategoryDesc:Usage instructions for NetIDMgr + diff --git a/src/windows/identity/help/toc.hhc b/src/windows/identity/help/toc.hhc new file mode 100644 index 0000000000..cde5119a3f --- /dev/null +++ b/src/windows/identity/help/toc.hhc @@ -0,0 +1,47 @@ + + + + + + + + + + + + + +
    +
  • + + + +
  • + + +
      +
    • + + +
        +
      • + + + +
      +
    • + + +
        +
      • + + + +
      • + + + +
      +
    +
+ diff --git a/src/windows/identity/include/Makefile b/src/windows/identity/include/Makefile new file mode 100644 index 0000000000..17182d57a1 --- /dev/null +++ b/src/windows/identity/include/Makefile @@ -0,0 +1,37 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=include +!include <../config/Makefile.w32> + +INCFILES= \ + $(INCDIR)\khdefs.h \ + $(INCDIR)\kherror.h \ + $(INCDIR)\khlist.h \ + $(INCDIR)\khmsgtypes.h + +all: $(INCFILES) + +clean:: + $(RM) $(INCFILES) diff --git a/src/windows/identity/include/khdefs.h b/src/windows/identity/include/khdefs.h new file mode 100644 index 0000000000..427926306b --- /dev/null +++ b/src/windows/identity/include/khdefs.h @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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 + */ + +#ifdef _WIN64 +typedef __int64 ssize_t; +#else +typedef _W64 int ssize_t; +#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 new file mode 100644 index 0000000000..d56fa7dc73 --- /dev/null +++ b/src/windows/identity/include/kherror.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* 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_PARM (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) + +/*@}*/ /*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 new file mode 100644 index 0000000000..330cfc498d --- /dev/null +++ b/src/windows/identity/include/khlist.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* 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 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) + +/* Trees with FIFO child lists */ +#define TQDCL(type) \ + LDCL(type); \ + QDCL(type); \ + type * parent + +#define TQINIT(pe) \ + do { \ + QINIT(pe); \ + (pe)->parent = NULL; } while(0) + +#define TQADDCHILD(pt,pe) \ + do { \ + QPUT((pt), (pe)); \ + (pe)->parent = (pt); } while(0) + +#define TQFIRSTCHILD(pt) ((pt)?QTOP(pt):NULL) + +#define TQPARENT(pe) ((pe)?(pe)->parent:NULL) + +#endif diff --git a/src/windows/identity/include/khmsgtypes.h b/src/windows/identity/include/khmsgtypes.h new file mode 100644 index 0000000000..8348bbf95e --- /dev/null +++ b/src/windows/identity/include/khmsgtypes.h @@ -0,0 +1,700 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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. + + \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 + +#define KMSG_ACT_BEGIN_CMDLINE 128 + +/*@}*/ + +/*! \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. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + */ +#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. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \see \ref cred_acq + */ +#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. + + Message parameters: + - \b vparam : Pointer to a khui_new_creds object + */ +#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 : poitner 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_GET_CREDS, 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 + + 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 + + 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 + */ +#define KMSG_CRED_PP_DESTROY 131 + +/*! \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_INITIAL_CREDS + - ::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 + +/*@}*/ + +/*! \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/khthread.h b/src/windows/identity/include/khthread.h new file mode 100644 index 0000000000..b7354c4688 --- /dev/null +++ b/src/windows/identity/include/khthread.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* Not exported */ +#ifndef __KHIMAIRA_KTHREAD_H +#define __KHIMAIRA_KTHREAD_H + +#ifdef _WIN32 +#define khm_mutex CRITICAL_SECTION + +#define khp_mutex_init(pcs) InitializeCriticalSection(pcs) +#define khp_mutex_destroy(pcs) DeleteCriticalSection(pcs) +#define khp_mutex_lock(pcs) EnterCriticalSection(pcs) +#define khp_mutex_unlock(pcs) LeaveCriticalSection(pcs) +#define khp_mutex_trylock(pcs) (!TryEnterCriticalSection(pcs)) + +#endif + +#endif \ No newline at end of file diff --git a/src/windows/identity/kconfig/Makefile b/src/windows/identity/kconfig/Makefile new file mode 100644 index 0000000000..26619c011c --- /dev/null +++ b/src/windows/identity/kconfig/Makefile @@ -0,0 +1,51 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=kconfig +!include <../config/Makefile.w32> + +INCFILES= \ + $(INCDIR)\kconfig.h + +OBJFILES= \ + $(OBJ)\kconfigmain.obj \ + $(OBJ)\api.obj + +all: mkdirs $(INCFILES) $(OBJFILES) + +clean:: + $(RM) $(INCFILES) + +# Tests + +test:: util_test + +util_test: $(OBJ)\utiltest.exe + $(OBJ)\utiltest.exe + +$(OBJ)\utiltest.exe: $(OBJ)\utiltest.obj + $(EXECONLINK) $(OBJFILES) + +$(OBJ)\utiltest.obj: test\utiltest.c + $(C2OBJ) diff --git a/src/windows/identity/kconfig/api.c b/src/windows/identity/kconfig/api.c new file mode 100644 index 0000000000..3d69c998e5 --- /dev/null +++ b/src/windows/identity/kconfig/api.c @@ -0,0 +1,2098 @@ +/* +* Copyright (c) 2004 Massachusetts Institute of Technology +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* $Id$ */ + +#include +#include + +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 = khc_create_empty_space(); + conf_root->name = wcsdup(L"Root"); + conf_root->regpath = wcsdup(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; + + khc_free_space(conf_root); + + EnterCriticalSection(&cs_conf_handle); + while(conf_free_handles) { + LPOP(&conf_free_handles, &h); + if(h) { + free(h); + } + } + + while(conf_handles) { + LPOP(&conf_handles, &h); + if(h) { + free(h); + } + } + LeaveCriticalSection(&cs_conf_handle); + DeleteCriticalSection(&cs_conf_handle); + + LeaveCriticalSection(&cs_conf_global); + DeleteCriticalSection(&cs_conf_global); + } +} + +kconf_handle * khc_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 = malloc(sizeof(kconf_handle)); + assert(h != NULL); + } + ZeroMemory((void *) h, sizeof(kconf_handle)); + + h->magic = KCONF_HANDLE_MAGIC; + khc_space_hold(s); + h->space = s; + h->flags = flags; + + LPUSH(&conf_handles, h); + LeaveCriticalSection(&cs_conf_handle); + + return h; +} + +/* must be called with cs_conf_global held */ +void khc_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(); + } + } +#endif + while(h) { + LDELETE(&conf_handles, h); + if(h->space) { + khc_space_release(h->space); + h->space = NULL; + } + lower = h->lower; + LPUSH(&conf_free_handles, h); + h = lower; + } + LeaveCriticalSection(&cs_conf_handle); +} + +kconf_handle * khc_handle_dup(kconf_handle * o) +{ + kconf_handle * h; + kconf_handle * r; + + r = khc_handle_from_space(o->space, o->flags); + h = r; + + while(o->lower) { + h->lower = khc_handle_from_space(o->lower->space, o->lower->flags); + + o = o->lower; + h = h->lower; + } + + return r; +} + +void khc_space_hold(kconf_conf_space * s) { + InterlockedIncrement(&(s->refcount)); +} + +void khc_space_release(kconf_conf_space * s) { + LONG l = InterlockedDecrement(&(s->refcount)); + if(!l) { + EnterCriticalSection(&cs_conf_global); + + if(s->regkey_machine) + RegCloseKey(s->regkey_machine); + if(s->regkey_user) + RegCloseKey(s->regkey_user); + s->regkey_machine = NULL; + s->regkey_user = NULL; + + 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; + const wchar_t * t; + LONG rv = ERROR_SUCCESS; + + hkp = hkey; + + /* descend down the components of the subkey */ + t = sSubKey; + 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; +} + +LONG +khcint_RegCreateKeyEx(HKEY hKey, + LPCTSTR lpSubKey, + DWORD Reserved, + LPTSTR 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; + 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; +} + + +HKEY khc_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; + } +} + +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)) + return KHM_ERROR_INVALID_PARM; + + h = (kconf_handle *) upper; + + EnterCriticalSection(&cs_conf_handle); + if(h->lower) { + LeaveCriticalSection(&cs_conf_handle); + EnterCriticalSection(&cs_conf_global); + khc_handle_free(h->lower); + LeaveCriticalSection(&cs_conf_global); + EnterCriticalSection(&cs_conf_handle); + h->lower = NULL; + } + + if(khc_is_handle(lower)) { + kconf_handle * l; + kconf_handle * lc; + + l = (kconf_handle *) lower; + LeaveCriticalSection(&cs_conf_handle); + lc = khc_handle_dup(l); + EnterCriticalSection(&cs_conf_handle); + h->lower = lc; + } + LeaveCriticalSection(&cs_conf_handle); + + return KHM_ERROR_SUCCESS; +} + +kconf_conf_space * khc_create_empty_space(void) { + kconf_conf_space * r; + + r = malloc(sizeof(kconf_conf_space)); + assert(r != NULL); + ZeroMemory(r,sizeof(kconf_conf_space)); + + return r; +} + +void khc_free_space(kconf_conf_space * r) { + kconf_conf_space * c; + + if(!r) + return; + + LPOP(&r->children, &c); + while(c) { + khc_free_space(c); + LPOP(&r->children, &c); + } + + if(r->name) + free(r->name); + + if(r->regpath) + free(r->regpath); + + if(r->regkey_machine) + RegCloseKey(r->regkey_machine); + + if(r->regkey_user) + RegCloseKey(r->regkey_user); + + free(r); +} + +khm_int32 khcint_open_space_int(kconf_conf_space * parent, 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]; + + if(!parent) + p = conf_root; + else + p = parent; + + if(n_sname >= KCONF_MAXCCH_NAME || n_sname <= 0) + return KHM_ERROR_INVALID_PARM; + + /*SAFE: buf: buffer size == KCONF_MAXCCH_NAME * wchar_t > + n_sname * wchar_t */ + wcsncpy(buf, sname, n_sname); + buf[n_sname] = L'\0'; + + /* 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) { + khc_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 = khc_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 = khc_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 = khc_create_empty_space(); + + /*SAFE: buf: is of known length < KCONF_MAXCCH_NAME */ + c->name = wcsdup(buf); + + /*SAFE: p->regpath: is valid since it was set using this same + function. */ + /*SAFE: buf: see above */ + c->regpath = malloc((wcslen(p->regpath) + wcslen(buf) + 2) * sizeof(wchar_t)); + + assert(c->regpath != NULL); + +#pragma warning( push ) +#pragma warning( disable: 4995 ) + /*SAFE: c->regpath: allocated above to be big enough */ + /*SAFE: p->regpath: see above */ + wcscpy(c->regpath, p->regpath); + wcscat(c->regpath, L"\\"); + /*SAFE: buf: see above */ + wcscat(c->regpath, buf); +#pragma warning( pop ) + + khc_space_hold(c); + + EnterCriticalSection(&cs_conf_global); + TADDCHILD(p,c); + LeaveCriticalSection(&cs_conf_global); + + *result = c; + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI khc_open_space(khm_handle parent, wchar_t * cspace, khm_int32 flags, khm_handle * result) { + kconf_handle * h; + kconf_conf_space * p; + kconf_conf_space * c = NULL; + size_t cbsize; + wchar_t * str; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) { + return KHM_ERROR_NOT_READY; + } + + if(!result || (parent && !khc_is_handle(parent))) + return KHM_ERROR_INVALID_PARM; + + if(!parent) + p = conf_root; + else { + h = (kconf_handle *) parent; + p = khc_space_from_handle(parent); + } + + khc_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) { + khc_space_release(p); + *result = (khm_handle) khc_handle_from_space(p, flags); + return KHM_ERROR_SUCCESS; + } + + if(FAILED(StringCbLength(cspace, KCONF_MAXCB_PATH, &cbsize))) { + khc_space_release(p); + *result = NULL; + return KHM_ERROR_INVALID_PARM; + } + + str = cspace; + while(TRUE) { + wchar_t * end = NULL; + + if (!(flags & KCONF_FLAG_NOPARSENAME)) { + + end = wcschr(str, L'\\'); /* safe because cspace was + validated above */ +#if 0 + if(!end) + end = wcschr(str, L'/'); /* safe because cspace was + validated above */ +#endif + } + + if(!end) { + if(flags & KCONF_FLAG_TRAILINGVALUE) { + /* we are at the value component */ + c = p; + khc_space_hold(c); + break; + } else + end = str + wcslen(str); /* safe because cspace was + validated above */ + } + + rv = khcint_open_space_int(p, str, end - str, flags, &c); + + if(KHM_SUCCEEDED(rv) && (*end == L'\\' +#if 0 + || *end == L'/' +#endif + )) { + khc_space_release(p); + p = c; + c = NULL; + str = end+1; + } + else + break; + } + + khc_space_release(p); + if(KHM_SUCCEEDED(rv)) { + *result = khc_handle_from_space(c, flags); + } else + *result = NULL; + + return rv; +} + +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)) + return KHM_ERROR_INVALID_PARM; + + khc_handle_free((kconf_handle *) csp); + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI khc_read_string(khm_handle pconf, + 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; + wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + DWORD size; + DWORD type; + LONG hr; + + int i; + + if(wcschr(pvalue, L'\\') +#if 0 + || wcschr(pvalue, L'/') +#endif + ) { + + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + goto _shadow; + + free_space = 1; +#if 0 + wchar_t * back, * forward; + + back = wcsrchr(pvalue, L'\\'); + forward = wcsrchr(pvalue, L'/'); + value = (back > forward)?back:forward; /* works for nulls too */ +#else + value = wcsrchr(pvalue, L'\\'); +#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 = khc_space_open_key(c, KHM_PERM_READ); + + if(khc_is_machine_handle(conf)) + hkm = khc_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; +} + +KHMEXP khm_int32 KHMAPI khc_read_int32(khm_handle pconf, 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_PARM; + + do { + DWORD size; + DWORD type; + LONG hr; + HKEY hku = NULL; + HKEY hkm = NULL; + + wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + int i; + + if(wcschr(pvalue, L'\\') +#if 0 + || wcschr(pvalue, L'/') +#endif + ) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + goto _shadow; + free_space = 1; +#if 0 + wchar_t * back, * forward; + + back = wcsrchr(pvalue, L'\\'); + forward = wcsrchr(pvalue, L'/'); + value = (back > forward)?back:forward; +#else + value = wcsrchr(pvalue, L'\\'); +#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 = khc_space_open_key(c, KHM_PERM_READ); + + if(khc_is_machine_handle(conf)) + hkm = khc_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; +} + +KHMEXP khm_int32 KHMAPI khc_read_int64(khm_handle pconf, 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; + + wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + int i; + + if(wcschr(pvalue, L'\\') +#if 0 + || wcschr(pvalue, L'/') +#endif + ) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + goto _shadow; + free_space = 1; +#if 0 + wchar_t * back, *forward; + + back = wcsrchr(pvalue, L'\\'); + forward = wcsrchr(pvalue, L'/'); + value = (back > forward)?back:forward; +#else + value = wcsrchr(pvalue, L'\\'); +#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 = khc_space_open_key(c, KHM_PERM_READ); + + if(khc_is_machine_handle(conf)) + hkm = khc_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; +} + +KHMEXP khm_int32 KHMAPI khc_read_binary(khm_handle pconf, 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; + + wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + if(wcschr(pvalue, L'\\') +#if 0 + || wcschr(pvalue, L'/') +#endif + ) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + goto _shadow; + free_space = 1; +#if 0 + wchar_t * back, *forward; + + back = wcsrchr(pvalue, L'\\'); + forward = wcsrchr(pvalue, L'/'); + value = (back > forward)?back:forward; +#else + value = wcsrchr(pvalue, L'\\'); +#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 = khc_space_open_key(c, KHM_PERM_READ); + + if(khc_is_machine_handle(conf)) + hkm = khc_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; +} + +KHMEXP khm_int32 KHMAPI khc_write_string( + khm_handle pconf, + wchar_t * pvalue, + wchar_t * buf) +{ + HKEY pk = NULL; + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + LONG hr; + size_t cbsize; + wchar_t * value = NULL; + int free_space; + 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(wcschr(pvalue, L'\\') +#if 0 + || wcschr(pvalue, L'/') +#endif + ) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + return KHM_ERROR_INVALID_PARM; + free_space = 1; +#if 0 + wchar_t * back, *forward; + + back = wcsrchr(pvalue, L'\\'); + forward = wcsrchr(pvalue, L'/'); + value = (back > forward)?back:forward; +#else + value = wcsrchr(pvalue, L'\\'); +#endif + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf) || !buf) { + rv = KHM_ERROR_INVALID_PARM; + goto _exit; + } + + c = khc_space_from_handle(conf); + + if(FAILED(StringCbLength(buf, KCONF_MAXCB_STRING, &cbsize))) { + rv = KHM_ERROR_INVALID_PARM; + goto _exit; + } + + cbsize += sizeof(wchar_t); + + if(khc_is_user_handle(conf)) { + pk = khc_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE); + } else { + pk = khc_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; +} + +KHMEXP khm_int32 KHMAPI khc_write_int32( + khm_handle pconf, + wchar_t * pvalue, + khm_int32 buf) +{ + HKEY pk = NULL; + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + LONG hr; + wchar_t * value = NULL; + int free_space; + 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(wcschr(pvalue, L'\\') +#if 0 + || wcschr(pvalue, L'/') +#endif + ) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + return KHM_ERROR_INVALID_PARM; + free_space = 1; +#if 0 + wchar_t * back, *forward; + + back = wcsrchr(pvalue, L'\\'); + forward = wcsrchr(pvalue, L'/'); + value = (back > forward)?back:forward; +#else + value = wcsrchr(pvalue, L'\\'); +#endif + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARM; + + c = khc_space_from_handle( conf); + + if(khc_is_user_handle(conf)) { + pk = khc_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE); + } else { + pk = khc_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; +} + +KHMEXP khm_int32 KHMAPI khc_write_int64(khm_handle pconf, wchar_t * pvalue, khm_int64 buf) { + HKEY pk = NULL; + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + LONG hr; + wchar_t * value = NULL; + int free_space; + 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(wcschr(pvalue, L'\\') +#if 0 + || wcschr(pvalue, L'/') +#endif + ) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + return KHM_ERROR_INVALID_PARM; + free_space = 1; +#if 0 + wchar_t * back, *forward; + + back = wcsrchr(pvalue, L'\\'); + forward = wcsrchr(pvalue, L'/'); + value = (back > forward)?back:forward; +#else + value = wcsrchr(pvalue, L'\\'); +#endif + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARM; + + c = khc_space_from_handle( conf); + + if(khc_is_user_handle(conf)) { + pk = khc_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE); + } else { + pk = khc_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; +} + +KHMEXP khm_int32 KHMAPI khc_write_binary(khm_handle pconf, wchar_t * pvalue, void * buf, khm_size bufsize) { + HKEY pk = NULL; + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + LONG hr; + wchar_t * value = NULL; + int free_space; + 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(wcschr(pvalue, L'\\') +#if 0 + || wcschr(pvalue, L'/') +#endif + ) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + return KHM_ERROR_INVALID_PARM; + free_space = 1; +#if 0 + wchar_t * back, *forward; + + back = wcsrchr(pvalue, L'\\'); + forward = wcsrchr(pvalue, L'/'); + value = (back > forward)?back:forward; +#else + value = wcsrchr(pvalue, L'\\'); +#endif + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARM; + + c = khc_space_from_handle(conf); + + if(khc_is_user_handle(conf)) { + pk = khc_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE); + } else { + pk = khc_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; +} + +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_PARM; + + 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; +} + +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_PARM; + + c = khc_space_from_handle(conf); + + if(c == conf_root || c->parent == conf_root) + *parent = NULL; + else + *parent = khc_handle_from_space(c->parent, khc_handle_flags(conf)); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI khc_get_type(khm_handle conf, wchar_t * value) { + HKEY hkm = NULL; + HKEY hku = NULL; + kconf_conf_space * c; + khm_int32 rv; + LONG hr; + DWORD type = 0; + + if(!khc_is_config_running()) + return KC_NONE; + + if(!khc_is_handle(conf)) + return KC_NONE; + + c = (kconf_conf_space *) conf; + + if(!khc_is_machine_handle(conf)) + hku = khc_space_open_key(c, KHM_PERM_READ); + hkm = khc_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; +} + +KHMEXP khm_int32 KHMAPI khc_value_exists(khm_handle conf, 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_PARM; + + c = khc_space_from_handle(conf); + + if(!khc_is_machine_handle(conf)) + hku = khc_space_open_key(c, KHM_PERM_READ); + hkm = khc_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) { + for(i=0; inSchema; i++) { + if(!wcscmp(c->schema[i].name, value)) { + rv |= KCONF_FLAG_SCHEMA; + break; + } + } + } + + return rv; +} + +khm_boolean khc_is_valid_name(wchar_t * name) +{ + size_t cbsize; + if(FAILED(StringCbLength(name, KCONF_MAXCB_NAME, &cbsize))) + return FALSE; + return TRUE; +} + +khm_int32 khc_validate_schema(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(!khc_is_valid_name(schema[i].name) || + schema[i].type != KC_SPACE) + return KHM_ERROR_INVALID_PARM; + state = 1; + break; + + case 1: /* we are inside a config space, in the values area */ + if(!khc_is_valid_name(schema[i].name)) + return KHM_ERROR_INVALID_PARM; + if(schema[i].type == KC_SPACE) { + if(KHM_FAILED(khc_validate_schema(schema, i, &i))) + return KHM_ERROR_INVALID_PARM; + 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_PARM; + } + break; + + case 2: /* we are inside a config space, in the subspace area */ + if(schema[i].type == KC_SPACE) { + if(KHM_FAILED(khc_validate_schema(schema, i, &i))) + return KHM_ERROR_INVALID_PARM; + } else if(schema[i].type == KC_ENDSPACE) { + end_found = 1; + if(end) + *end = i; + } else { + return KHM_ERROR_INVALID_PARM; + } + break; + + default: + /* unreachable */ + return KHM_ERROR_INVALID_PARM; + } + i++; + } + + return KHM_ERROR_SUCCESS; +} + +khm_int32 khc_load_schema_i(khm_handle parent, kconf_schema * schema, int begin, int * end) +{ + int i; + int state = 0; + int end_found = 0; + kconf_conf_space * thisconf = NULL; + khm_handle h; + + i=begin; + while(!end_found) { + switch(state) { + case 0: /* initial. this record should start a config space */ + if(KHM_FAILED(khc_open_space(parent, schema[i].name, KHM_FLAG_CREATE, &h))) + return KHM_ERROR_INVALID_PARM; + thisconf = khc_space_from_handle(h); + thisconf->schema = schema + (begin + 1); + 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(khc_load_schema_i(h, schema, i, &i))) + return KHM_ERROR_INVALID_PARM; + state = 2; + } else if(schema[i].type == KC_ENDSPACE) { + thisconf->nSchema = i - (begin + 1); + end_found = 1; + if(end) + *end = i; + khc_close_space(h); + } + break; + + case 2: /* we are inside a config space, in the subspace area */ + if(schema[i].type == KC_SPACE) { + if(KHM_FAILED(khc_load_schema_i(h, schema, i, &i))) + return KHM_ERROR_INVALID_PARM; + } else if(schema[i].type == KC_ENDSPACE) { + end_found = 1; + if(end) + *end = i; + khc_close_space(h); + } else { + return KHM_ERROR_INVALID_PARM; + } + break; + + default: + /* unreachable */ + return KHM_ERROR_INVALID_PARM; + } + i++; + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI khc_load_schema(khm_handle conf, 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_PARM; + + if(KHM_FAILED(khc_validate_schema(schema, 0, NULL))) + return KHM_ERROR_INVALID_PARM; + + EnterCriticalSection(&cs_conf_global); + rv = khc_load_schema_i(conf, schema, 0, NULL); + LeaveCriticalSection(&cs_conf_global); + + return rv; +} + +khm_int32 khc_unload_schema_i(khm_handle parent, kconf_schema * schema, int begin, int * end) +{ + int i; + int state = 0; + int end_found = 0; + kconf_conf_space * thisconf = NULL; + khm_handle h; + + i=begin; + while(!end_found) { + switch(state) { + case 0: /* initial. this record should start a config space */ + if(KHM_FAILED(khc_open_space(parent, schema[i].name, 0, &h))) + return KHM_ERROR_INVALID_PARM; + 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(khc_unload_schema_i(h, schema, i, &i))) + return KHM_ERROR_INVALID_PARM; + state = 2; + } else if(schema[i].type == KC_ENDSPACE) { + end_found = 1; + if(end) + *end = i; + khc_close_space(h); + } + break; + + case 2: /* we are inside a config space, in the subspace area */ + if(schema[i].type == KC_SPACE) { + if(KHM_FAILED(khc_unload_schema_i(h, schema, i, &i))) + return KHM_ERROR_INVALID_PARM; + } else if(schema[i].type == KC_ENDSPACE) { + end_found = 1; + if(end) + *end = i; + khc_close_space(h); + } else { + return KHM_ERROR_INVALID_PARM; + } + break; + + default: + /* unreachable */ + return KHM_ERROR_INVALID_PARM; + } + i++; + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI khc_unload_schema(khm_handle conf, 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_PARM; + + if(KHM_FAILED(khc_validate_schema(schema, 0, NULL))) + return KHM_ERROR_INVALID_PARM; + + EnterCriticalSection(&cs_conf_global); + rv = khc_unload_schema_i(conf, schema, 0, NULL); + LeaveCriticalSection(&cs_conf_global); + + return rv; +} + +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_PARM; + + 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 = khc_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 = khc_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 = khc_handle_from_space(c, khc_handle_flags(conf)); + rv = KHM_ERROR_SUCCESS; + } else { + *next = NULL; + rv = KHM_ERROR_NOT_FOUND; + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI khc_write_multi_string(khm_handle conf, wchar_t * value, wchar_t * buf) +{ + size_t cb; + 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_PARM; + + if(multi_string_to_csv(NULL, &cb, buf) != KHM_ERROR_TOO_LONG) + return KHM_ERROR_INVALID_PARM; + + tb = malloc(cb); + assert(tb != NULL); + multi_string_to_csv(tb, &cb, buf); + rv = khc_write_string(conf, value, tb); + + free(tb); + return rv; +} + +KHMEXP khm_int32 KHMAPI khc_read_multi_string(khm_handle conf, wchar_t * value, wchar_t * buf, khm_size * bufsize) +{ + 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_PARM; + + rv = khc_read_string(conf, value, NULL, &cbbuf); + if(rv != KHM_ERROR_TOO_LONG) + return rv; + + tb = malloc(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: + free(tb); + + return rv; +} diff --git a/src/windows/identity/kconfig/kconfig.h b/src/windows/identity/kconfig/kconfig.h new file mode 100644 index 0000000000..22d923bd6f --- /dev/null +++ b/src/windows/identity/kconfig/kconfig.h @@ -0,0 +1,823 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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 kconf_schema_t { + 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 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, 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 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. + + \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_PARM 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. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI khc_read_string( + khm_handle conf, + wchar_t * value, + wchar_t * buf, + khm_size * bufsize); + +/*! \brief Read a multi-string value from a configuration space + + The \a value 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. + + \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_PARM 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. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI khc_read_multi_string( + khm_handle conf, + wchar_t * value, + wchar_t * buf, + khm_size * bufsize); + +/*! \brief Read a 32 bit integer value from a configuration space + + The \a value 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. + + \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_PARM 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, + wchar_t * value, + khm_int32 * buf); + +/*! \brief Read a 64 bit integer value from a configuration space + + The \a value 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. + + \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_PARM 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, + wchar_t * value, + khm_int64 * buf); + +/*! \brief Read a binary value from a configuration space + + The \a value 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. + + \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_PARM One or more parameters were invalid. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI khc_read_binary( + khm_handle conf, + wchar_t * value, + void * buf, + khm_size * bufsize); + +/*! \brief Write a string value to a configuration space + + The \a value 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. + + \param[in] conf Handle to a configuration space + \param[in] value 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, + wchar_t * value, + wchar_t * buf); + +/*! \brief Write a multi-string value to a configuration space + + The \a value 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. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI khc_write_multi_string( + khm_handle conf, + wchar_t * value, + wchar_t * buf); + +/*! \brief Write a 32 bit integer value to a configuration space + + The \a value 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_int32( + khm_handle conf, + wchar_t * value, + khm_int32 buf); + +/*! \brief Write a 64 bit integer value to a configuration space + + The \a value 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_int64( + khm_handle conf, + wchar_t * value, + khm_int64 buf); + +/*! \brief Write a binary value to a configuration space + + The \a value 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, + wchar_t * value, + 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, wchar_t * value); + +/*! \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. + + \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, wchar_t * value); + +/*! \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, + kconf_schema * schema); + +/*! \brief Unload a schema from a configuration space + */ +KHMEXP khm_int32 KHMAPI khc_unload_schema( + khm_handle conf, + 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_PARM 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); + +/*@}*/ + +#endif diff --git a/src/windows/identity/kconfig/kconfiginternal.h b/src/windows/identity/kconfig/kconfiginternal.h new file mode 100644 index 0000000000..1b4b70170c --- /dev/null +++ b/src/windows/identity/kconfig/kconfiginternal.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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; + + kconf_schema * schema; + khm_int32 nSchema; + + TDCL(struct kconf_conf_space_t); +} kconf_conf_space; + +#define KCONF_SPACE_FLAG_SCHEMA 32 + +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 * khc_handle_from_space(kconf_conf_space * s, khm_int32 flags); +void khc_handle_free(kconf_handle * h); + +kconf_conf_space * khc_create_empty_space(void); +void khc_free_space(kconf_conf_space * r); + +void khc_space_hold(kconf_conf_space * s); +void khc_space_release(kconf_conf_space * s); + +HKEY khc_space_open_key(kconf_conf_space * s, khm_int32 flags); + +#endif diff --git a/src/windows/identity/kconfig/kconfigmain.c b/src/windows/identity/kconfig/kconfigmain.c new file mode 100644 index 0000000000..8a9d6578c9 --- /dev/null +++ b/src/windows/identity/kconfig/kconfigmain.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#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 new file mode 100644 index 0000000000..4a7b46682b --- /dev/null +++ b/src/windows/identity/kconfig/registry.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + diff --git a/src/windows/identity/kconfig/test/utiltest.c b/src/windows/identity/kconfig/test/utiltest.c new file mode 100644 index 0000000000..0652c63b98 --- /dev/null +++ b/src/windows/identity/kconfig/test/utiltest.c @@ -0,0 +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 + +INCFILES= \ + $(INCDIR)\kcreddb.h + +OBJFILES= \ + $(OBJ)\buf.obj \ + $(OBJ)\attrib.obj \ + $(OBJ)\credential.obj \ + $(OBJ)\credset.obj \ + $(OBJ)\credtype.obj \ + $(OBJ)\identity.obj \ + $(OBJ)\init.obj \ + $(OBJ)\kcreddbmain.obj \ + $(OBJ)\type.obj \ + $(OBJ)\kcdbconfig.obj + +$(OBJ)\kcdbconfig.c: kcdbconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +$(OBJ)\kcredres.res: lang\en_us\kcredres.rc + $(RC2RES) + +all: mkdirs $(INCFILES) $(OBJ)\kcredres.res $(OBJFILES) + +clean:: + $(RM) $(INCFILES) diff --git a/src/windows/identity/kcreddb/attrib.c b/src/windows/identity/kcreddb/attrib.c new file mode 100644 index 0000000000..e43540dc51 --- /dev/null +++ b/src/windows/identity/kcreddb/attrib.c @@ -0,0 +1,853 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +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_PARM; + + 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_PARM; + + 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: + { + /* we are going to make liberal use of __int64 here. It + is equivalent to FILETIME and also the MSDN docs say we + should use it if the compiler supports it */ + khm_int32 rv = KHM_ERROR_SUCCESS; + unsigned __int64 ftc; + SYSTEMTIME st; + + if(!buf || *pcb_buf < sizeof(__int64)) { + *pcb_buf = sizeof(__int64); + rv = KHM_ERROR_TOO_LONG; + } else if(!kcdb_cred_buf_exist(c,KCDB_ATTR_EXPIRE)) { + *pcb_buf = sizeof(__int64); + /* 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 */ + *((__int64 *) buf) = _I64_MAX; + } else { + GetSystemTime(&st); + SystemTimeToFileTime(&st, (LPFILETIME) &ftc); + *((__int64 *) buf) = + *((__int64 *) kcdb_cred_buf_get(c,KCDB_ATTR_EXPIRE)) - ftc; + } + + return rv; + } + + case KCDB_ATTR_RENEW_TIMELEFT: + { + /* we are going to make liberal use of __int64 here. It + is equivalent to FILETIME and also the MSDN docs say we + should use it if the compiler supports it */ + khm_int32 rv = KHM_ERROR_SUCCESS; + unsigned __int64 ftc; + SYSTEMTIME st; + + if(!buf || *pcb_buf < sizeof(__int64)) { + *pcb_buf = sizeof(__int64); + rv = KHM_ERROR_TOO_LONG; + } else if(!kcdb_cred_buf_exist(c,KCDB_ATTR_RENEW_EXPIRE)) { + *pcb_buf = sizeof(__int64); + /* 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 */ + *((__int64 *) buf) = _I64_MAX; + } else { + GetSystemTime(&st); + SystemTimeToFileTime(&st, (LPFILETIME) &ftc); + *((__int64 *) buf) = + *((__int64 *) kcdb_cred_buf_get(c,KCDB_ATTR_RENEW_EXPIRE)) - ftc; + } + + 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 = + malloc(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 = + malloc(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; + 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(__int64); + attrib.compute_max_cbsize = sizeof(__int64); + + 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(__int64); + attrib.compute_max_cbsize = sizeof(__int64); + + 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) + free(kcdb_attrib_tbl); + + if(kcdb_property_tbl) + free(kcdb_property_tbl); +} + +KHMEXP khm_int32 KHMAPI kcdb_attrib_get_id(wchar_t *name, khm_int32 * id) +{ + kcdb_attrib_i * ai; + + if(!name) + return KHM_ERROR_INVALID_PARM; + + 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(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_PARM; + + 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_PARM; + + if ((attrib->flags & KCDB_ATTR_FLAG_ALTVIEW) && + KHM_FAILED(kcdb_attrib_get_info(attrib->alt_id, + NULL))) + return KHM_ERROR_INVALID_PARM; + + 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 = malloc(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 = malloc(cb_name); + StringCbCopy(ai->attr.name, cb_name, attrib->name); + if(cb_short_desc) { + ai->attr.short_desc = malloc(cb_short_desc); + StringCbCopy(ai->attr.short_desc, cb_short_desc, attrib->short_desc); + } + if(cb_long_desc) { + ai->attr.long_desc = malloc(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_PARM; + + 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; + + if(!cbsize) + return KHM_ERROR_INVALID_PARM; + + 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; + + 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_PARM; + + 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_PARM; + + 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_PARM; + + 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_PARM; + + 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 new file mode 100644 index 0000000000..5199aec926 --- /dev/null +++ b/src/windows/identity/kcreddb/attrib.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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 \ No newline at end of file diff --git a/src/windows/identity/kcreddb/buf.c b/src/windows/identity/kcreddb/buf.c new file mode 100644 index 0000000000..0f50be25d0 --- /dev/null +++ b/src/windows/identity/kcreddb/buf.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +void kcdb_buf_new(kcdb_buf * buf, khm_size n_fields) +{ + buf->buffer = malloc(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 = malloc(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) + free(buf->buffer); + buf->buffer = NULL; + + buf->n_fields = 0; + buf->nc_fields = 0; + if(buf->fields) + free(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 = malloc(new_size); + assert(new_buf != NULL); + + memcpy(new_buf, buf->buffer, buf->cb_used); + free(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 = malloc(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)); + + free(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) { + int 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 = malloc(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 = malloc(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_PARM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_get_attrib( + khm_handle record, + 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_PARM; +} + +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_PARM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_get_attrib_string( + khm_handle record, + 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_PARM; +} + +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_PARM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_set_attrib( + khm_handle record, + 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_PARM; +} + +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_PARM; +} + +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_PARM; +} + diff --git a/src/windows/identity/kcreddb/buf.h b/src/windows/identity/kcreddb/buf.h new file mode 100644 index 0000000000..3ff1f041dd --- /dev/null +++ b/src/windows/identity/kcreddb/buf.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $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 new file mode 100644 index 0000000000..1fe1dcd973 --- /dev/null +++ b/src/windows/identity/kcreddb/credential.c @@ -0,0 +1,1047 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +/* 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( + 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_PARM; + } + + cb_name += sizeof(wchar_t); + + cred = malloc(sizeof(kcdb_cred)); + ZeroMemory(cred, sizeof(kcdb_cred)); + + cred->magic = KCDB_CRED_MAGIC; + cred->identity = identity; + cred->name = malloc(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); + } + } + + 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_PARM; + + *pnewcred = NULL; + + kcdb_cred_lock_write(); + + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARM; + 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_PARM; + + LockObtainRead(&l_creds); + + if(!kcdb_cred_is_active_cred(vcred)) { + LockReleaseRead(&l_creds); + return KHM_ERROR_INVALID_PARM; + } + + c = (kcdb_cred *) vcred; + + *pserial = c->id; + + LockReleaseRead(&l_creds); + + 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_PARM; + + kcdb_cred_lock_write(); + if(!kcdb_cred_is_active_cred(vcred)) { + kcdb_cred_unlock_write(); + return KHM_ERROR_INVALID_PARM; + } + + 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_PARM; + + LockObtainRead(&l_creds); + + if(!kcdb_cred_is_active_cred(vcred)) { + LockReleaseRead(&l_creds); + return KHM_ERROR_INVALID_PARM; + } + + c = (kcdb_cred *) vcred; + + *type = c->type; + + LockReleaseRead(&l_creds); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_set_attrib( + khm_handle cred, + 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_PARM; + + 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_PARM; + + kcdb_cred_lock_write(); + + if(!kcdb_cred_is_active_cred(vcred)) { + kcdb_cred_unlock_write(); + return KHM_ERROR_INVALID_PARM; + } + + cred = (kcdb_cred *) vcred; + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { + kcdb_cred_unlock_write(); + return KHM_ERROR_INVALID_PARM; + } + + 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_PARM; + } + + 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_PARM; + 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, + 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, + 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_PARM; + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { + return KHM_ERROR_INVALID_PARM; + } + + 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; + + LockObtainRead(&l_creds); + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARM; + 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: + LockReleaseRead(&l_creds); + 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_PARM; + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { + code = KHM_ERROR_INVALID_PARM; + goto _exit; + } + + if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { + code = KHM_ERROR_UNKNOWN; + goto _exit; + } + + LockObtainRead(&l_creds); + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARM; + 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) { + buf = malloc(cbbuf); + code = attrib->compute_cb( + vcred, + attr_id, + buf, + &cbbuf); + if(KHM_SUCCEEDED(code)) { + code = type->toString( + buf, + cbbuf, + buffer, + pcbbuf, + flags); + } + free(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: + LockReleaseRead(&l_creds); + 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_PARM; + + LockObtainRead(&l_creds); + + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARM; + 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: + + LockReleaseRead(&l_creds); + 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_PARM; + + LockObtainRead(&l_creds); + + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + kcdb_identity_hold((khm_handle) cred->identity); + + *identity = cred->identity; + +_exit: + LockReleaseRead(&l_creds); + 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_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARM; + 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_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARM; + 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; + + LockObtainRead(&l_creds); + if(!kcdb_cred_is_cred(vcred)) { + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + if(!(cred->flags & KCDB_CRED_FLAG_DELETED)) + goto _exit; + + if(cred->refcount) + goto _exit; + + LockReleaseRead(&l_creds); + 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); + free(cred->name); + free(cred); + + /*TODO: notifications */ + +_exit2: + kcdb_cred_unlock_write(); + return; + +_exit: + LockReleaseRead(&l_creds); +} + +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_PARM; + 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, + 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; + + LockObtainRead(&l_creds); + 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) { + 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) { + buf1 = malloc(cb1); + if(KHM_FAILED(attrib->compute_cb(vcred1, attr_id, buf1, &cb1))) + goto _exit_1; + } + if(cb2) { + buf2 = malloc(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) + free(buf1); + if(buf2) + free(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: + LockReleaseRead(&l_creds); + 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; + + LockObtainRead(&l_creds); + if(!kcdb_cred_is_active_cred(vcred1) || + !kcdb_cred_is_active_cred(vcred2)) + 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)) { + code = TRUE; + } + +_exit: + LockReleaseRead(&l_creds); + 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_PARM; + + LockObtainRead(&l_creds); + if (!kcdb_cred_is_active_cred(vcred)) { + *pflags = 0; + rv = KHM_ERROR_INVALID_PARM; + 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)) { + + khm_int64 ftc; + + GetSystemTimeAsFileTime((LPFILETIME) &ftc); + if (ftc > *((khm_int64 *) + kcdb_cred_buf_get(cred, KCDB_ATTR_EXPIRE))) + 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)) { + khm_int64 ftc; + + GetSystemTimeAsFileTime((LPFILETIME) &ftc); + if (ftc > *((khm_int64 *) kcdb_cred_buf_get(cred, KCDB_ATTR_RENEW_EXPIRE))) + 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) { + LockReleaseRead(&l_creds); + LockObtainWrite(&l_creds); + /* Did we lose a race? */ + if (kcdb_cred_is_active_cred(vcred)) + cred->flags = f; + else { + rv = KHM_ERROR_INVALID_PARM; + f = 0; + } + LockReleaseWrite(&l_creds); + release_lock = FALSE; + } +#endif + + *pflags = f; + + _exit: + if (release_lock) + LockReleaseRead(&l_creds); + + 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; + + LockObtainWrite(&l_creds); + if(!kcdb_cred_is_active_cred(vcred)) { + rv = KHM_ERROR_INVALID_PARM; + goto _exit; + } + + cred = vcred; + + flags &= ~(KCDB_CRED_FLAG_DELETED); + mask &= ~(KCDB_CRED_FLAG_DELETED); + + cred->flags = + (cred->flags & (~mask)) | + (flags & mask); + + _exit: + LockReleaseWrite(&l_creds); + return rv; +} diff --git a/src/windows/identity/kcreddb/credential.h b/src/windows/identity/kcreddb/credential.h new file mode 100644 index 0000000000..8104f686b4 --- /dev/null +++ b/src/windows/identity/kcreddb/credential.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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 new file mode 100644 index 0000000000..3a39d48a63 --- /dev/null +++ b/src/windows/identity/kcreddb/credset.c @@ -0,0 +1,1132 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +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 = malloc(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) +{ + free(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 = calloc(nclist, sizeof(kcdb_credset_credref)); + + memcpy(new_clist, cs->clist, cs->nclist * sizeof(kcdb_credset_credref)); + + free(cs->clist); + + cs->clist = new_clist; + } +} + +KHMEXP khm_int32 KHMAPI kcdb_credset_create(khm_handle * result) +{ + kcdb_credset * cs; + + cs = malloc(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_PARM; + } + + 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)); + + free(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 = malloc(sizeof(kcdb_cred *) * rcs->nclist); + if(cs->nclist > 0) + c_sel = malloc(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) + free(r_sel); + if(c_sel) + free(c_sel); + + 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_PARM; + + 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 = malloc(sizeof(kcdb_cred *) * rcs->nclist); + if(cs->nclist) + c_sel = malloc(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) + free(r_sel); + if(c_sel) + free(c_sel); + + 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_PARM; + + 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_PARM; + + if(sourcecredset) { + if(!kcdb_credset_is_credset(sourcecredset)) + return KHM_ERROR_INVALID_PARM; + } 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==KCDB_TYPE_INVALID || 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_PARM; + + if(sourcecredset) { + if(!kcdb_credset_is_credset(sourcecredset)) + return KHM_ERROR_INVALID_PARM; + } 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_PARM; + + 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_PARM; + + 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 || !cred)) + return KHM_ERROR_INVALID_PARM; + + 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) { + *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_PARM; + + if (!kcdb_cred_is_active_cred(vcred_src)) + return KHM_ERROR_INVALID_PARM; + + 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_PARM; + + 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_PARM; + 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_PARM; + + 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_PARM; + + 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_PARM; + + 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_PARM; + + 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_PARM; + + 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_PARM; + + 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. */ +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_PARM; + + 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 + + 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->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 pt; + + for(i=0; inFields; i++) { + if (o->fields[i].order & KCDB_CRED_COMP_INITIAL_FIRST) { + + kcdb_cred_get_flags(cred1, &f1); + kcdb_cred_get_flags(cred2, &f2); + + if (((f1 ^ f2) & KCDB_CRED_FLAG_INITIAL) == 0) { + kcdb_cred_get_type(cred1, &f1); + kcdb_cred_get_type(cred2, &f2); + kcdb_identity_get_type(&pt); + + if (f1 == f2) + r = 0; + else if (f1 == pt) + r = -1; + else if (f2 == pt) + r = 1; + else + 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 new file mode 100644 index 0000000000..c19246540d --- /dev/null +++ b/src/windows/identity/kcreddb/credset.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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 1024 +#define KCDB_CREDSET_GROWTH_FACTOR 1024 + +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 new file mode 100644 index 0000000000..dc2b7b85a0 --- /dev/null +++ b/src/windows/identity/kcreddb/credtype.c @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +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 = malloc(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 */ + free(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); + + free(ict->ct.name); + if(ict->ct.short_desc) + free(ict->ct.short_desc); + if(ict->ct.long_desc) + free(ict->ct.long_desc); + if(ict->ct.sub) + kmq_delete_subscription(ict->ct.sub); + + free(ict); + } +} + +KHMEXP khm_int32 KHMAPI kcdb_credtype_register(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_PARM; + + if(type->id >= KCDB_CREDTYPE_MAX_ID) + return KHM_ERROR_INVALID_PARM; + + 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_PARM; + + 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_PARM; + + 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 = malloc(sizeof(kcdb_credtype_i)); + ZeroMemory(ict, sizeof(kcdb_credtype_i)); + + ict->ct.name = malloc(cb_name); + StringCbCopy(ict->ct.name, cb_name, type->name); + + if(cb_short_desc) { + ict->ct.short_desc = malloc(cb_short_desc); + StringCbCopy(ict->ct.short_desc, cb_short_desc, type->short_desc); + } + + if(cb_long_desc) { + ict->ct.long_desc = malloc(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; + + 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_PARM; + + 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_PARM; + + 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_PARM; + + 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_PARM; + + 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 { +#pragma warning(push) +#pragma warning(disable:4995) + wcscpy(buf, str); /* str is one of the string fields in t->ct which has + been validated when the type was registered. */ +#pragma warning(pop) + *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_PARM; + + 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 { +#pragma warning(push) +#pragma warning(disable: 4995) + wcscpy(buf, t->ct.name); /* t->ct.name was validated when the type was registered */ +#pragma warning(pop) + *cbbuf = s; + } + } else { + *cbbuf = 0; + rv = KHM_ERROR_NOT_FOUND; + } + LeaveCriticalSection(&cs_credtype); + + return rv; +} + +KHMEXP khm_int32 KHMAPI kcdb_credtype_get_id( + wchar_t * name, + khm_int32 * id) +{ + int i; + + *id = 0; + if(!name) + return KHM_ERROR_INVALID_PARM; + + 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_PARM; + + 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_PARM; + + 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 new file mode 100644 index 0000000000..6e46db303e --- /dev/null +++ b/src/windows/identity/kcreddb/credtype.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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 \ No newline at end of file diff --git a/src/windows/identity/kcreddb/identity.c b/src/windows/identity/kcreddb/identity.c new file mode 100644 index 0000000000..d6ae129d6c --- /dev/null +++ b/src/windows/identity/kcreddb/identity.c @@ -0,0 +1,1537 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +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; + +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_post_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_post_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_PARM; + + 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); +} + +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; + kcdb_identity * id_tmp; + size_t namesize; + + if(!result || !name) + return KHM_ERROR_INVALID_PARM; + + *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))) { + /* can't specify this flag in create */ + return KHM_ERROR_INVALID_PARM; + } + + 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 = malloc(sizeof(kcdb_identity)); + ZeroMemory(id, sizeof(kcdb_identity)); + id->magic = KCDB_IDENT_MAGIC; + id->name = malloc(namesize); + StringCbCopy(id->name, namesize, name); + + id->flags = (flags & KCDB_IDENT_FLAGMASK_LOCAL); + id->flags |= KCDB_IDENT_FLAG_ACTIVE; + 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; + + free(id->name); + free(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_conifg() 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_PARM; + 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) + free(id->name); + free(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. */ + +#if 0 + EnterCriticalSection(&cs_ident); + if(id->refcount == 0) { + /*TODO: free up the identity */ + } +#endif + _exit: + LeaveCriticalSection(&cs_ident); + + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_flags(khm_handle vid, + khm_int32 flag) { + kcdb_identity * id; + khm_int32 oldflags; + khm_int32 newflags; + khm_int32 delta = 0; + khm_int32 rv; + + if(!kcdb_is_active_identity(vid)) + return KHM_ERROR_INVALID_PARM; + + id = (kcdb_identity *) vid; + + if((flag & ~(KCDB_IDENT_FLAGMASK_RDWR | KCDB_IDENT_FLAG_INVERT)) || + ((flag & KCDB_IDENT_FLAG_INVALID) && (flag & KCDB_IDENT_FLAG_VALID))) + return KHM_ERROR_INVALID_PARM; + + if(flag & KCDB_IDENT_FLAG_DEFAULT) { + /* kcdb_identity_set_default already does checking for + redundant transitions */ + rv = kcdb_identity_set_default((flag & KCDB_IDENT_FLAG_INVERT)?NULL: vid); + + if(KHM_FAILED(rv)) + return rv; + + flag &= ~KCDB_IDENT_FLAG_DEFAULT; + } + + if(flag & KCDB_IDENT_FLAG_SEARCHABLE) { + if(flag & KCDB_IDENT_FLAG_INVERT) { + EnterCriticalSection(&cs_ident); + 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; + } + } + LeaveCriticalSection(&cs_ident); + } else { + EnterCriticalSection(&cs_ident); + 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; + } + } + LeaveCriticalSection(&cs_ident); + } + + flag &= ~KCDB_IDENT_FLAG_SEARCHABLE; + } + + /* deal with every other flag */ + + EnterCriticalSection(&cs_ident); + oldflags = id->flags; + if(flag & KCDB_IDENT_FLAG_INVERT) { + flag &= ~KCDB_IDENT_FLAG_INVERT; + id->flags &= ~flag; + } else { + id->flags |= flag; + + if(flag & KCDB_IDENT_FLAG_VALID) + id->flags &= ~KCDB_IDENT_FLAG_INVALID; + if(flag & KCDB_IDENT_FLAG_INVALID) + id->flags &= ~KCDB_IDENT_FLAG_VALID; + } + 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_PARM; + + id = (kcdb_identity *) vid; + + *flags = id->flags; + + 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_PARM; + + 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_PARM; + + 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_PARM; + + 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) + 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_PARM; + } + + 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)) + 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; + if(kcdb_is_active_identity(vid)) { + id = vid; + InterlockedIncrement(&(id->refcount)); + } else + return KHM_ERROR_INVALID_PARM; + 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; + if(kcdb_is_identity(vid)) { + id = vid; + refcount = InterlockedDecrement(&(id->refcount)); + if(refcount == 0) { + EnterCriticalSection(&cs_ident); + /* We only delete identities which do not have a + configuration. */ + if (id->refcount == 0 && + !(id->flags & KCDB_IDENT_FLAG_CONFIG)) + kcdb_identity_delete(vid); + LeaveCriticalSection(&cs_ident); + } + } else + return KHM_ERROR_INVALID_PARM; + 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; + khm_int32 flags; + + EnterCriticalSection(&cs_ident); + + if (!kcdb_is_active_identity(vid)) { + code = KHM_ERROR_INVALID_PARM; + goto _exit; + } + + ident = (kcdb_identity *) vid; + + result.ident = ident; + result.flags = 0; + result.count = 0; + + 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_identity_get_flags(vid, &flags); + flags &= KCDB_IDENT_FLAGMASK_RDWR; + flags &= ~(KCDB_IDENT_FLAG_DEFAULT | + KCDB_IDENT_FLAG_SEARCHABLE); + flags ^= result.flags; + if (flags != 0) + kcdb_identity_set_flags(vid, flags | KCDB_IDENT_FLAG_INVERT); + + 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; + 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 = LNEXT(ident)) { + + if (!kcdb_is_active_identity(ident) || + ident->refresh_cycle == kcdb_ident_refresh_cycle) + continue; + + kcdb_identity_hold((khm_handle) ident); + + LeaveCriticalSection(&cs_ident); + kcdb_identity_refresh((khm_handle) ident); + EnterCriticalSection(&cs_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; + kcdb_attrib * attrib; + kcdb_type * type; + 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_PARM; + } + + 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_PARM; + } + +#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_PARM; + } + + 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_PARM; + 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, + 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_PARM; + + 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_PARM; + } + + 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_PARM; + 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); +#else + code = KHM_ERROR_INVALID_OPERATION; +#endif + } 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, + 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_PARM; + } + + 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_PARM; + 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); +#else + code = KHM_ERROR_INVALID_OPERATION; +#endif + } 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, + 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 */ + +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; + if(wcsspn(name, KCDB_IDENT_VALID_CHARS) != 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)); + + 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_PARM; + + 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)) || + wcsspn(name_in, KCDB_IDENT_VALID_CHARS) != 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; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + /* 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); + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + ZeroMemory(&namex, sizeof(namex)); + namex.name_src = name1; + namex.name_alt = name2; + + 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_PARM; + + 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_PARM; + + 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_PARM; + + 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_PARM; + + 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_PARM; + + 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; + + 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; + + if (KHM_SUCCEEDED(kcdb_identity_create(wname, + KCDB_IDENT_FLAG_CREATE, + &t_id))) + kcdb_identity_release(t_id); + } + + _config_check_cleanup: + if (h_kcdb) + khc_close_space(h_kcdb); + if (h_idents) + khc_close_space(h_idents); + + kcdb_checked_config = TRUE; + } + + 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 new file mode 100644 index 0000000000..6c7e26ee86 --- /dev/null +++ b/src/windows/identity/kcreddb/identity.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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; + struct kcdb_identity_t * next; + struct kcdb_identity_t * prev; +} kcdb_identity; + +#define KCDB_IDENT_MAGIC 0x31938d4f + +extern CRITICAL_SECTION cs_ident; +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 new file mode 100644 index 0000000000..2df3f3e3f9 --- /dev/null +++ b/src/windows/identity/kcreddb/init.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $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/kcdbconfig.csv b/src/windows/identity/kcreddb/kcdbconfig.csv new file mode 100644 index 0000000000..bd1fc6f330 --- /dev/null +++ b/src/windows/identity/kcreddb/kcdbconfig.csv @@ -0,0 +1,15 @@ +Name,Type,Value,Description +KCDB,KC_SPACE,0,Khimaira Configuration DB + Identity,KC_SPACE,0,Configuration space for identities + _Schema,KC_SPACE,0,Schema for identities + Sticky,KC_INT32,0,Boolean. Is this a sticky identity? + Monitor,KC_INT32,1,Boolean. Enables monitoring the identity + WarnThreshold,KC_INT32,900,In seconds + AllowWarn,KC_INT32,1,Boolean. Allow warning. + CriticalThreshold,KC_INT32,60,In seconds + AllowCritical,KC_INT32,1,Boolean. Allow critical. + AutoRenewThreshold,KC_INT32,60,In seconds + AllowAutoRenew,KC_INT32,1,Boolean. + _Schema,KC_ENDSPACE,0, + Identity,KC_ENDSPACE,0, +KCDB,KC_ENDSPACE,0, diff --git a/src/windows/identity/kcreddb/kcreddb.h b/src/windows/identity/kcreddb/kcreddb.h new file mode 100644 index 0000000000..e5be0f4629 --- /dev/null +++ b/src/windows/identity/kcreddb/kcreddb.h @@ -0,0 +1,3212 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._@-/" + +/*! +\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 Inverts the accompanying flags. + + \note Only to be used with kcdb_identity_set_flags() + \see kcdb_identity_set_flags() */ +#define KCDB_IDENT_FLAG_INVERT 0x40000000L + +/*! \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 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 0x04000000L + +/*! \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 Bit mask for local flags + + Local flags are those local to the KCDB. + */ +#define KCDB_IDENT_FLAGMASK_LOCAL 0x0000ffffL + +/*! \brief Read/write flags mask. + + A bitmask that correspond to all the read/write flags in the mask. +*/ +#define KCDB_IDENT_FLAGMASK_RDWR 0x000007ffL + +/*@}*/ + +/*! \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 flags parameter. The only exception is the + KCDB_IDENT_FLAG_INVERT flag which controls whether the flags are + to be set or reset. + + If the ::KCDB_IDENT_FLAG_INVERT flag is not specified in \a flags, + then any flags set in \a flags will also be set in the identity. + If the ::KCDB_IDENT_FLAG_INVERT is specified, then any flag set in + \a flags will be reset in the identity. + + 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. + + 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 (according to KCDB_IDENT_FLAG_INVERT setting) 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); + +/*! \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. As + an additional side effect, the notification <::KMSG_KCDB, + ::KMSG_KCDB_IDENT, ::KCDB_OP_NEW_DEFAULT> will also not be sent. + */ +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. + + \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 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, + 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, + 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_PARM 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, + 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_PARM 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() +*/ +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_TYPE_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_PARM 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 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(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. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_set_attrib(khm_handle cred, + 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, + 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_PARM 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, + 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, + 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_PARM 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_PARM 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(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. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_type_get_info(khm_int32 id, kcdb_type ** info); + +KHMEXP khm_int32 KHMAPI +kcdb_type_release_info(kcdb_type * info); + +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(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 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_PARM 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 + +#define KCDB_TYPE_VOID 0 +#define KCDB_TYPE_STRING 1 +#define KCDB_TYPE_DATE 2 +#define KCDB_TYPE_INTERVAL 3 +#define KCDB_TYPE_INT32 4 +#define KCDB_TYPE_INT64 5 +#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(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(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 +/*@}*/ + +/*! \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"Issed" +#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.*/ + +#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_PARM 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(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_PARM 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_PARM 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(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, + 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_PARM 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, + 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, + 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 + +/*@}*/ + +#endif diff --git a/src/windows/identity/kcreddb/kcreddbinternal.h b/src/windows/identity/kcreddb/kcreddbinternal.h new file mode 100644 index 0000000000..699954cf01 --- /dev/null +++ b/src/windows/identity/kcreddb/kcreddbinternal.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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 \ No newline at end of file diff --git a/src/windows/identity/kcreddb/kcreddbmain.c b/src/windows/identity/kcreddb/kcreddbmain.c new file mode 100644 index 0000000000..796084a995 --- /dev/null +++ b/src/windows/identity/kcreddb/kcreddbmain.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +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/lang/en_us/kcredres.rc b/src/windows/identity/kcreddb/lang/en_us/kcredres.rc new file mode 100644 index 0000000000..2f733199a7 --- /dev/null +++ b/src/windows/identity/kcreddb/lang/en_us/kcredres.rc @@ -0,0 +1,130 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\..\langres.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\..\\langres.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +1 TEXTINCLUDE +BEGIN + "..\\..\\langres.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_CREDDB "Khimaira Credentials Database" + IDS_NAME "Name" + IDS_IDENTITY "Identity" + IDS_ISSUED "Issued on" + IDS_EXPIRES "Expires on" + IDS_TIMELEFT "Time left" + IDS_LOCATION "Location" + IDS_PARENT "Parent" + IDS_TYPE "Type" + IDS_IVL_EXPIRED "(Expired)" + IDS_IVL_D_H "%I64u days %I64u hours" +END + +STRINGTABLE +BEGIN + IDS_IVL_H_M "%I64u hours %I64u mins" + IDS_IVL_M_S "%I64u mins %I64u secs" + IDS_IVL_S "%I64u seconds" + IDS_IVL_UNKNOWN "(Unknown)" + IDS_LIFETIME "Lifetime" + IDS_IVL_1D "1 day" + IDS_IVL_1H "1 hour" + IDS_IVL_1M "1 minute" + IDS_IVL_1S "1 second" + IDS_IVL_D "%I64u days" + IDS_IVL_H "%I64u hours" + IDS_IVL_M "%I64u minutes" + IDS_IVL_S_SPEC "s,sec,second,seconds,secs" + IDS_IVL_M_SPEC "m,min,mins,minutes" + IDS_IVL_H_SPEC "h,hrs,hours" + IDS_IVL_D_SPEC "d,day,days,ds" +END + +STRINGTABLE +BEGIN + IDS_IVl_W_SPEC "w,wk,wks,weeks" + IDS_FLAGS "Flags" + IDS_RENEW_TIMELEFT "Renewable Time left" + IDS_RENEW_EXPIRES "Renewable time expires" + IDS_RENEW_LIFETIME "Renewable lifetime" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/windows/identity/kcreddb/langres.h b/src/windows/identity/kcreddb/langres.h new file mode 100644 index 0000000000..ab6620cd51 --- /dev/null +++ b/src/windows/identity/kcreddb/langres.h @@ -0,0 +1,49 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by D:\work\khimaira\src\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_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 new file mode 100644 index 0000000000..dfb47e0d43 --- /dev/null +++ b/src/windows/identity/kcreddb/resource.h @@ -0,0 +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 diff --git a/src/windows/identity/kcreddb/type.c b/src/windows/identity/kcreddb/type.c new file mode 100644 index 0000000000..e41694544b --- /dev/null +++ b/src/windows/identity/kcreddb/type.c @@ -0,0 +1,1295 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +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_PARM; + + 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_PARM; + + *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_PARM; + + sd = (wchar_t *) d; + + if(FAILED(StringCbLength(sd, KCDB_TYPE_MAXCB, &cbsize))) + return KHM_ERROR_INVALID_PARM; + + 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_PARM; + + 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_PARM; + + 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 += sizeof(wchar_t); + } + + cbsize += GetTimeFormat( + LOCALE_USER_DEFAULT, + 0, + &st_dl, + NULL, + NULL, + 0) * sizeof(wchar_t); + + cbsize += 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; + long l; + + ms = *((__int64 *) pft) / 10000i64; + + if(ms < 0 || *((__int64 *) pft) == _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 { + 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; + wchar_t ibuf[256]; + wchar_t fbuf[256]; + wchar_t * t; + + if(!cb_buf) + return KHM_ERROR_INVALID_PARM; + s = *((__int64 *) data) / 10000000i64; + + m = s / 60; + h = s / 3600; + d = s / (3600*24); + + if(*((__int64 *) data) == _I64_MAX) { + LoadString(hinst_kcreddb, IDS_IVL_UNKNOWN, ibuf, sizeof(ibuf)/sizeof(wchar_t)); + } 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, ARRAYLENGTH(ibuf) - wcslen(ibuf)); + } else { + LoadString(hinst_kcreddb, IDS_IVL_H, fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(t, sizeof(ibuf) - wcslen(ibuf)*sizeof(wchar_t), fbuf, h); + } + } + } else if(h > 0) { + m = (s - (h * 3600)) / 60; + if(h == 1) { + LoadString(hinst_kcreddb, IDS_IVL_1H, ibuf, ARRAYLENGTH(ibuf)); + } else { + LoadString(hinst_kcreddb, IDS_IVL_H, fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(ibuf, sizeof(ibuf), fbuf, h); + } + if(m > 0) { + StringCbCat(ibuf, sizeof(ibuf), L" "); + t = ibuf + wcslen(ibuf); + if(m == 1) + { + LoadString(hinst_kcreddb, IDS_IVL_1M, t, ARRAYLENGTH(ibuf) - wcslen(ibuf)); + } else { + LoadString(hinst_kcreddb, IDS_IVL_M, fbuf, 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, ARRAYLENGTH(ibuf) - wcslen(ibuf)); + } else { + LoadString(hinst_kcreddb, IDS_IVL_S, fbuf, 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 = *((__int64 *) d1); + i2 = *((__int64 *) 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(__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; + } +} + +/* 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_PARM; + + 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_PARM; + + 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_PARM; + + 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, even if d is NULL */ + return TRUE; +} + +khm_int32 KHMAPI kcdb_type_data_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2) +{ + /* datas can not be compared */ + return 0; +} + +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) + return KHM_ERROR_INVALID_PARM; + + *cbd_dst = cbd_src; + + if(!d_dst || *cbd_dst < cbd_src) { + return KHM_ERROR_TOO_LONG; + } else { + 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 = malloc(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(__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_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_PARM; + + 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_PARM; + + 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); + free(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 */ + free(t->type.name); + free(t); + } + LeaveCriticalSection(&cs_type); +} + +KHMEXP khm_int32 KHMAPI kcdb_type_get_id(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_PARM; + } + + 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_PARM; + + 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_PARM; + + 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(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_PARM; + + if((type->flags & KCDB_TYPE_FLAG_CB_MIN) && + (type->cb_min < 0 || type->cb_min > KCDB_TYPE_MAXCB)) + { + return KHM_ERROR_INVALID_PARM; + } + + if((type->flags & KCDB_TYPE_FLAG_CB_MAX) && + (type->cb_max < 0 || type->cb_max > KCDB_TYPE_MAXCB)) + { + return KHM_ERROR_INVALID_PARM; + } + + 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_PARM; + } + + 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_PARM; + } 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 = malloc(sizeof(kcdb_type_i)); + ZeroMemory(t, sizeof(kcdb_type_i)); + + t->type.name = malloc(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_PARM; + + 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_PARM; + + /* 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 = Int32x32To64(t, 10000000) + 116444736000000000i64; + pft->dwLowDateTime = (DWORD) ll; + pft->dwHighDateTime = (DWORD) (ll >> 32); +} + +KHMEXP void KHMAPI TimetToFileTimeInterval(time_t t, LPFILETIME pft) +{ + LONGLONG ll = Int32x32To64(t, 10000000); + pft->dwLowDateTime = (DWORD) ll; + pft->dwHighDateTime = (DWORD) (ll >> 32); +} + +KHMEXP long KHMAPI FtIntervalToSeconds(LPFILETIME pft) +{ + __int64 i = *((__int64 *) pft); + return (long) (i / 10000000i64); +} + +KHMEXP long KHMAPI FtIntervalToMilliseconds(LPFILETIME pft) +{ + __int64 i = *((__int64 *) pft); + return (long) (i / 10000i64); +} + +KHMEXP long KHMAPI FtCompare(LPFILETIME pft1, LPFILETIME pft2) { + __int64 i1 = *((__int64 *) pft1); + __int64 i2 = *((__int64 *) pft2); + + if (i1 < i2) + return -1; + if (i1 == i2) + return 0; + return 1; +} + +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 *pr, t; + + pr = (__int64 *) pft; + *pr = 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_PARM; + + 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_PARM; + + 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_PARM; + + t += f * ivspecs[i].mul; + + b = e; + } + + *pr = t; + + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/kcreddb/type.h b/src/windows/identity/kcreddb/type.h new file mode 100644 index 0000000000..9d8b52e252 --- /dev/null +++ b/src/windows/identity/kcreddb/type.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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 \ No newline at end of file diff --git a/src/windows/identity/kherr/Makefile b/src/windows/identity/kherr/Makefile new file mode 100644 index 0000000000..84f9da5baa --- /dev/null +++ b/src/windows/identity/kherr/Makefile @@ -0,0 +1,43 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=kherr +!include <../config/Makefile.w32> + +INCFILES= \ + $(INCDIR)\kherr.h + +OBJFILES= \ + $(OBJ)\kherrmain.obj \ + $(OBJ)\kherr.obj + +LIBFILES= + +SDKLIBFILES= \ + strsafe.lib + +all: mkdirs $(INCFILES) $(OBJFILES) + +clean:: + $(RM) $(INCFILES) diff --git a/src/windows/identity/kherr/kherr.c b/src/windows/identity/kherr/kherr.c new file mode 100644 index 0000000000..04b45238b4 --- /dev/null +++ b/src/windows/identity/kherr/kherr.c @@ -0,0 +1,1164 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#ifdef Debug +#include +#endif + +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; + +khm_ui_4 ctx_serial = 0; + +#ifdef DEBUG +static void DebugPrintf(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) { + + assert(h); + + EnterCriticalSection(&cs_error); + if( ctx_handlers == NULL) { + nc_ctx_handlers = CTX_ALLOC_INCR; + n_ctx_handlers = 0; + ctx_handlers = malloc(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 = malloc(sizeof(*new_ctxs) * new_nc); + memmove(new_ctxs, ctx_handlers, n_ctx_handlers); + + free(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; + + ctx_handlers[n_ctx_handlers].h = h; + ctx_handlers[n_ctx_handlers].filter = filter; + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_remove_ctx_handler(kherr_ctx_handler h) { + khm_size i; + EnterCriticalSection(&cs_error); + + for (i=0 ; i < n_ctx_handlers; i++) { + if (ctx_handlers[i].h == h) { + 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; + + for (i=0; inc_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]); + } + free(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 = malloc(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; + + free(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 = malloc(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)); + free((void*) parm_data(e->p1)); + e->p1 = (kherr_param) 0; + } + if(parm_type(e->p2) == KEPT_STRINGT) { + assert((void *) parm_data(e->p2)); + free((void*) parm_data(e->p2)); + e->p2 = (kherr_param) 0; + } + if(parm_type(e->p3) == KEPT_STRINGT) { + assert((void *) parm_data(e->p3)); + free((void*) parm_data(e->p3)); + e->p3 = (kherr_param) 0; + } + if(parm_type(e->p4) == KEPT_STRINGT) { + assert((void *) parm_data(e->p4)); + free((void*) parm_data(e->p4)); + e->p4 = (kherr_param) 0; + } +} + +void free_event(kherr_event * e) { + assert(e->magic == KHERR_EVENT_MAGIC); + +#ifdef DEBUG + DebugPrintf(L"Freeing event 0x%x\n", e); + if (!(e->flags & KHERR_RF_STR_RESOLVED)) + resolve_event_strings(e); + if (e->short_desc) + DebugPrintf(L" Desc(S):[%s]\n", e->short_desc); + if (e->long_desc) + DebugPrintf(L" Desc(L):[%s]\n", e->long_desc); + if (e->suggestion) + DebugPrintf(L" Suggest:[%s]\n", e->suggestion); + if (e->facility) + DebugPrintf(L" Facility:[%s]\n", e->facility); +#endif + + if(e->flags & KHERR_RF_FREE_SHORT_DESC) { + assert(e->short_desc); + free((void *) e->short_desc); + } + if(e->flags & KHERR_RF_FREE_LONG_DESC) { + assert(e->long_desc); + free((void *) e->long_desc); + } + if(e->flags & KHERR_RF_FREE_SUGGEST) { + assert(e->suggestion); + free((void *) e->suggestion); + } + + free_event_params(e); + + ZeroMemory(e, sizeof(e)); + + EnterCriticalSection(&cs_error); + 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 = malloc(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 + DebugPrintf(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 + DebugPrintf(L"Done with context 0x%x\n", c); +#endif +} + + +void add_event(kherr_context * c, kherr_event * e) +{ + EnterCriticalSection(&cs_error); + 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 != 0) { + t = parm_type(p); + if (t == KEPT_INT32 || + t == KEPT_UINT32 || + t == KEPT_STRINGC || + t == KEPT_STRINGT) { + + *(*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; + size_t bytes; + + 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 = malloc(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; + size_t bytes; + 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 = malloc(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) { + free((void *) *str); + } + + e->flags &= ~mask; + + if (chars == 0) { + *str = 0; + } else { + wchar_t * s; + + bytes = (chars + 1) * sizeof(wchar_t); + s = malloc(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) { + 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 * 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. In terms of performance we are + assuming that this case doesn't happen that much. Har + har */ + 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 = wcsdup((wchar_t *)parm_data(p)); + return kherr_val(KEPT_STRINGT, 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; + + 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_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 (kherr_param) 0; + + if (FAILED(StringCbLength(s, KHERR_MAXCB_STRING, &cb_s))) + cb_s = KHERR_MAXCB_STRING; + else + cb_s += sizeof(wchar_t); + + dest = malloc(cb_s); + assert(dest != NULL); + dest[0] = L'\0'; + + StringCbCopy(dest, cb_s, s); + + return _tstr(dest); +} diff --git a/src/windows/identity/kherr/kherr.h b/src/windows/identity/kherr/kherr.h new file mode 100644 index 0000000000..7ccc6e5609 --- /dev/null +++ b/src/windows/identity/kherr/kherr.h @@ -0,0 +1,965 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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_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 */ +}; + +#ifdef _WIN32 +typedef khm_ui_8 kherr_param; +#else +#error kherr_param undefined +#endif + +/*! \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_3 = 64, /*!< Verbose debug level 3 (high) */ + KHERR_DEBUG_2 = 65, /*!< Verbose debug level 2 (medium) */ + KHERR_DEBUG_1 = 66, /*!< Verbose debug level 1 (low) */ + KHERR_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. */ +}; + +/*! \brief An error context +*/ +typedef struct tag_kherr_context { + khm_int32 magic; /*!< Magic number. Always set to + KHERR_CONTEXT_MAGIC */ + + khm_ui_4 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 */ +}; + +/*! \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 (*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. + + \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. + */ +KHMEXP void KHMAPI kherr_add_ctx_handler(kherr_ctx_handler h, + khm_int32 filter); + +/*! \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); + + +/*! \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 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); + +/* convenience macros for specifying parameters for kherr_report */ +#define kherr_val(type,val) \ + ((((kherr_param)(type)) << ((sizeof(kherr_param)-1)*8)) | (kherr_param) (val)) + +#define _int32(i) kherr_val(KEPT_INT32, i) +#define _uint32(ui) kherr_val(KEPT_UINT32, ui) +#define _int64(i) kherr_val(KEPT_INT64, i) +#define _uint64(ui) kherr_val(KEPT_UINT64, ui) +#define _cstr(cs) kherr_val(KEPT_STRINGC, cs) +#define _tstr(ts) kherr_val(KEPT_STRINGT, ts) +#define _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, 0, 0, 0, 0, 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, 0, 0, 0, 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, 0, 0, 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, 0, 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, 0, 0, 0, 0, 0, NULL) + +#define _report_cs1(severity, long_description, p1) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, 0, 0, 0, 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, 0, 0, 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, 0, 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, 0, 0, 0, 0, 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, 0, 0, 0, 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, 0, 0, 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, 0, 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, 0, 0, 0, 0, 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, 0, 0, 0, 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, 0, 0, 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, 0, 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, 0, 0, 0, 0, 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, 0, 0, 0, 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, 0, 0, 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, 0, 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 + becomes invalid. + + Use kherr_get_next_event() to obtain the other events. + */ +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 + becomes invalid. + */ +KHMEXP kherr_event * KHMAPI kherr_get_next_event(kherr_event * e); + +/*! \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 +/*@}*/ + +/*@}*/ + +#endif diff --git a/src/windows/identity/kherr/kherrinternal.h b/src/windows/identity/kherr/kherrinternal.h new file mode 100644 index 0000000000..e91cc3d018 --- /dev/null +++ b/src/windows/identity/kherr/kherrinternal.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KHERRORINTERNAL_H +#define __KHIMAIRA_KHERRORINTERNAL_H + +#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_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) ((int) (((p)>>((sizeof(kherr_param) - 1) * 8)) & 0xff)) +#define parm_data(p) ((p) & ~(((kherr_param)0xff)<<((sizeof(kherr_param) - 1) * 8))) + +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 new file mode 100644 index 0000000000..b108609db4 --- /dev/null +++ b/src/windows/identity/kherr/kherrmain.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +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/Makefile b/src/windows/identity/kmm/Makefile new file mode 100644 index 0000000000..6135cdc4f0 --- /dev/null +++ b/src/windows/identity/kmm/Makefile @@ -0,0 +1,54 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=kmm +!include <../config/Makefile.w32> + +INCFILES= \ + $(INCDIR)\kmm.h \ + $(INCDIR)\kplugin.h + +OBJFILES= \ + $(OBJ)\kmmmain.obj \ + $(OBJ)\kmm.obj \ + $(OBJ)\kmm_plugin.obj \ + $(OBJ)\kmm_module.obj \ + $(OBJ)\kmm_reg.obj \ + $(OBJ)\kmm_registrar.obj \ + $(OBJ)\kmmconfig.obj + +MSGRESFILE=$(OBJ)\kmm_msgs.res + +$(OBJ)\kmmconfig.c: kmmconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +$(MSGRESFILE): $(OBJ)\kmm_msgs.rc + +$(OBJ)\kmm_msgs.rc: lang\kmm_msgs.mc + $(MC2RC) + +all: mkdirs $(INCFILES) $(MSGRESFILE) $(OBJFILES) + +clean:: + $(RM) $(INCFILES) diff --git a/src/windows/identity/kmm/kmm.c b/src/windows/identity/kmm/kmm.c new file mode 100644 index 0000000000..af8419fdaa --- /dev/null +++ b/src/windows/identity/kmm/kmm.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +khm_boolean kmm_load_locale_lib(kmm_module_i * m, kmm_module_locale * l) +{ + HMODULE h; + + if(l->filename != NULL) { + h = LoadLibrary(l->filename); + 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_PARM; + + f = malloc(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 new file mode 100644 index 0000000000..8e487be73a --- /dev/null +++ b/src/windows/identity/kmm/kmm.h @@ -0,0 +1,1010 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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_MAXCB_NAME) + +/*! \brief Maximum number of dependencies per plugin +*/ +#define KMM_MAX_DEPENDENCIES 8 + +/*! \brief Maximum number of dependants per plugin + */ +#define KMM_MAX_DEPENDANTS 16 + +/*! \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 */ +} kmm_plugin_info; + +/*! \name Plugin types +@{*/ +/*! \brief A credentials provider + + \see \ref pi_pt_cred for more information. +*/ +#define KHM_PITYPE_CRED 1 + +/*! \brief A configuration provider + + \see \ref pi_pt_conf for more information. +*/ +#define KHM_PITYPE_CONFIG 2 + +/*@}*/ + +/*! \name Plugin flags +@{*/ + +/*! \brief The plugin is an identity provider +*/ +#define KHM_PIFLAG_IDENTITY_PROVIDER 1 +/*@}*/ + +/*! \brief Plugin states */ +enum _kmm_plugin_states { + 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 */ + + 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_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_PARM 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_PARM 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_PARM 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 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. All members are + required, however \a plugin_info can 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. + + \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 new file mode 100644 index 0000000000..e1f5292ce8 --- /dev/null +++ b/src/windows/identity/kmm/kmm_module.c @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +kmm_module_i * kmm_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 = malloc(sizeof(kmm_module_i)); + ZeroMemory(m, sizeof(kmm_module_i)); + + m->magic = KMM_MODULE_MAGIC; + m->name = malloc(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 * kmm_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 kmm_free_module(kmm_module_i * m) +{ + m->magic = 0; + + hash_del(hash_modules, m->name); + LDELETE(&kmm_all_modules, m); + + if (m->name) + free(m->name); + if (m->path) + free(m->path); + if (m->vendor) + free(m->vendor); + if (m->version_info) + free(m->version_info); + free(m); + + if (kmm_all_modules == NULL) + SetEvent(evt_exit); +} + +KHMEXP khm_int32 KHMAPI kmm_hold_module(kmm_module module) +{ + if(!kmm_is_module(module)) + return KHM_ERROR_INVALID_PARM; + 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_PARM; + + 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 */ + kmm_free_module(m); + } + LeaveCriticalSection(&cs_kmm); + return KHM_ERROR_SUCCESS; +} + +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_PARM; + cbsize += sizeof(wchar_t); + + EnterCriticalSection(&cs_kmm); + mi = kmm_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 = kmm_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_PARM; + 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; + 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_PARM; + + 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_int32 rv; + wchar_t * ll = NULL; + wchar_t *str; + 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(); + + rv = khc_read_multi_string(csm, KMM_VALNAME_LOADLIST, NULL, &s); + if(rv != KHM_ERROR_TOO_LONG) + goto _exit; + + ll = malloc(s); + rv = khc_read_multi_string(csm, KMM_VALNAME_LOADLIST, ll, &s); + if(KHM_FAILED(rv)) + goto _exit; + + kmmint_add_to_module_queue(); + + str = ll; + while(str && *str) { + if(SUCCEEDED(StringCbCopy(buf, sizeof(buf), str))) { + kmm_load_module(buf, 0, NULL); + } + str = multi_string_next(str); + } + + kmmint_remove_from_module_queue(); + +_exit: + if(ll) + free(ll); + 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 new file mode 100644 index 0000000000..f37eaa186c --- /dev/null +++ b/src/windows/identity/kmm/kmm_plugin.c @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +/* 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 * +kmm_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 = malloc(sizeof(kmm_plugin_i)); + ZeroMemory(p, sizeof(kmm_plugin_i)); + p->magic = KMM_PLUGIN_MAGIC; + p->p.name = malloc(cb); + StringCbCopy(p->p.name, cb, name); + p->state = KMM_PLUGIN_STATE_NONE; + + hash_add(hash_plugins, (void *) p->p.name, (void *) p); + kmm_list_plugin(p); + } + LeaveCriticalSection(&cs_kmm); + + return p; +} + +kmm_plugin_i * +kmm_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 +kmm_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 +kmm_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_PARM; + + EnterCriticalSection(&cs_kmm); + pi = kmm_plugin_from_handle(p); + pi->refcount++; + LeaveCriticalSection(&cs_kmm); + + return KHM_ERROR_SUCCESS; +} + +/* called with cs_kmm held */ +void +kmm_free_plugin(kmm_plugin_i * pi) +{ + int i; + pi->magic = 0; + + hash_del(hash_plugins, (void *) pi->p.name); + + kmm_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) + free(pi->p.name); + pi->p.name = NULL; + + if(pi->p.description) + free(pi->p.description); + pi->p.description = NULL; + + if(pi->p.dependencies) + free(pi->p.dependencies); + pi->p.dependencies = NULL; + + free(pi); +} + +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_PARM; + + EnterCriticalSection(&cs_kmm); + if (!kmm_is_plugin(p)) { + rv = KHM_ERROR_INVALID_PARM; + 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; + + info->h_plugin = p; + kmm_hold_plugin(p); + + _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_PARM; + + 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_PARM; + + EnterCriticalSection(&cs_kmm); + pi = kmm_plugin_from_handle(p); + pi->refcount--; + if(pi->refcount == 0) { + kmm_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_PARM; + } + + cb_name += sizeof(wchar_t); + cb_desc += sizeof(wchar_t); + + p = kmm_get_plugin_i(plugin->name); + + /* released below or in kmm_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 = malloc(cb_desc); + StringCbCopy(p->p.description, cb_desc, plugin->description); + } else + p->p.description = NULL; + + if(plugin->dependencies) { + p->p.dependencies = malloc(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; + + kmm_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 new file mode 100644 index 0000000000..ea13fc19bd --- /dev/null +++ b/src/windows/identity/kmm/kmm_reg.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +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_PARM; + + 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_PARM; + + 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 - 1, &cch)) || + (plugin->description && + FAILED(StringCchLength(plugin->description, KMM_MAXCCH_DESC - 1, &cch))) || + FAILED(StringCchLength(plugin->name, KMM_MAXCCH_NAME - 1, &cch))) + { + return KHM_ERROR_INVALID_PARM; + } + + /* 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"Flags", plugin->flags); + 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) + goto _exit; + + cb += cch * sizeof(wchar_t); + scb = cb; + + pl = malloc(cb); + + rv = khc_read_multi_string(csp_module, L"PluginList", NULL, &cb); + if(KHM_FAILED(rv)) { + if(pl) + free(pl); + goto _exit; + } + + 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); + } + + free(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 - 1, &cch)) || + (module->description && + FAILED(StringCchLength(module->description, KMM_MAXCCH_DESC - 1, &cch))) || + FAILED(StringCchLength(module->path, MAX_PATH, &cch)) || + (module->n_plugins > 0 && module->plugin_reg_info == NULL)) + { + return KHM_ERROR_INVALID_PARM; + } + +#define CKRV if(KHM_FAILED(rv)) goto _exit + + rv = kmm_get_module_config(module->name, config_flags | KHM_FLAG_CREATE, &csp_module); + CKRV; + + if(module->description) { + rv = khc_write_string(csp_module, L"Description", module->description); + CKRV; + } + rv = khc_write_string(csp_module, L"ImagePath", module->path); + CKRV; + + rv = khc_write_int32(csp_module, L"Flags", 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) +{ + /*TODO: implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} + +KHMEXP khm_int32 KHMAPI +kmm_unregister_module(wchar_t * module, khm_int32 config_flags) +{ + /*TODO: implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} diff --git a/src/windows/identity/kmm/kmm_registrar.c b/src/windows/identity/kmm/kmm_registrar.c new file mode 100644 index 0000000000..3c690f36b6 --- /dev/null +++ b/src/windows/identity/kmm/kmm_registrar.c @@ -0,0 +1,836 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +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; + 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(void) { + InterlockedIncrement(&pending_plugins); +} + +void +kmmint_remove_from_plugin_queue(void) { + InterlockedDecrement(&pending_plugins); + + 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 kmm_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: + kmm_init_module((kmm_module_i *) vparam); + kmm_release_module(kmm_handle_from_module((kmm_module_i *) vparam)); + break; + + case KMM_REG_EXIT_MODULE: + kmm_exit_module((kmm_module_i *) vparam); + kmm_release_module(kmm_handle_from_module((kmm_module_i *) vparam)); + break; + + case KMM_REG_INIT_PLUGIN: + kmm_init_plugin((kmm_plugin_i *) vparam); + kmm_release_plugin(kmm_handle_from_plugin((kmm_plugin_i *) vparam)); + break; + + case KMM_REG_EXIT_PLUGIN: + kmm_exit_plugin((kmm_plugin_i *) vparam); + 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 ( kmm_reg_cb() ) */ +DWORD WINAPI kmm_registrar( + LPVOID lpParameter +) +{ + tid_registrar = GetCurrentThreadId(); + + kmq_subscribe(KMSG_KMM, kmm_reg_cb); + kmq_subscribe(KMSG_SYSTEM, kmm_reg_cb); + + SetEvent(evt_startup); + + while(KHM_SUCCEEDED(kmq_dispatch(INFINITE))); + + 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 kmm_plugin_broker(LPVOID lpParameter) +{ + DWORD rv = 0; + kmm_plugin_i * p = (kmm_plugin_i *) lpParameter; + + TlsSetValue(tls_kmm, (LPVOID) p); + + kmm_hold_plugin(kmm_handle_from_plugin(p)); + + p->tid_thread = GetCurrentThreadId(); + + rv = (p->p.msg_proc(KMSG_SYSTEM, KMSG_SYSTEM_INIT, 0, (void *) &(p->p))); + + /* if it fails to initialize, we exit the plugin */ + if(KHM_FAILED(rv)) { + kmmint_remove_from_plugin_queue(); + rv = 1; + 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); + } + + if(p->p.flags & KHM_PIFLAG_IDENTITY_PROVIDER) { + khm_handle h = NULL; + + kmq_create_subscription(p->p.msg_proc, &h); + kcdb_identity_set_provider(h); + /* kcdb deletes the subscription when it's done with it */ + } + + if(p->p.type == KHM_PITYPE_CONFIG) { + /*TODO: subscribe to configuration provider messages here */ + } + + p->state = KMM_PLUGIN_STATE_RUNNING; + + /* 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) { + 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(); + + /* 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); + } + + if(p->p.flags & KHM_PIFLAG_IDENTITY_PROVIDER) { + kcdb_identity_set_provider(NULL); + } + + 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: + 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 kmm_init_plugin() is called on a plugin, then kmm_exit_plugin() + \b must be called for the plugin. + + \note Should only be called from the context of the registrar thread */ +void kmm_init_plugin(kmm_plugin_i * p) { + DWORD dummy; + khm_handle csp_plugin = NULL; + khm_handle csp_plugins = NULL; + khm_int32 t; + + /* the following will be undone in kmm_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. */ + p->module->plugin_count--; + } + + p->state = KMM_PLUGIN_STATE_PREINIT; + 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)) || + KHM_FAILED(khc_read_int32(csp_plugin, L"Flags", &t))) + { + if(KHM_FAILED(kmm_register_plugin(&(p->p), 0))) { + _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED); + + 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_FAILED(khc_read_int32(csp_plugin, L"Flags", &t))) { + _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED); + + p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED; + goto _exit; + } + } + + if(t & KMM_PLUGIN_FLAG_DISABLED) { + _report_mr0(KHERR_ERROR, MSG_IP_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 = malloc(sz); + if(KHM_FAILED(khc_read_multi_string(csp_plugin, L"Dependencies", deps, &sz))) { + if(deps) + free(deps); + break; + } + + for(d = deps; d && *d; d = multi_string_next(d)) { + kmm_plugin_i * pd; + int i; + + pd = kmm_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; in_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 kmm_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; + } + + free(deps); + + } while(FALSE); + LeaveCriticalSection(&cs_kmm); + + EnterCriticalSection(&cs_kmm); + p->module->plugin_count++; + kmm_delist_plugin(p); + kmm_list_plugin(p); + 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->ht_thread = CreateThread( + NULL, + 0, + kmm_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(); + + kmm_hold_plugin(kmm_handle_from_plugin(p)); + + kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_PLUGIN, (void *) p); +} + +/*! \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 kmm_exit_plugin(kmm_plugin_i * p) { + int np; + + 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 kmm_init_plugin() */ + if(p->state == KMM_PLUGIN_STATE_EXITED || + p->state == KMM_PLUGIN_STATE_HOLD) + { + np = --(p->module->plugin_count); + } else { + /* the plugin was never active. We can't base a module unload + decision on np */ + np = TRUE; + } + 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 kmm_init_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 kmm_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_WARNING, 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"Flags", &i))) { + if(i & KMM_MODULE_FLAG_DISABLED) { + _report_mr0(KHERR_ERROR, MSG_IM_DISABLED); + + m->state = KMM_MODULE_STATE_FAIL_DISABLED; + goto _exit; + } + } + + if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"FailureCount", &i))) { + khm_int64 tm; + khm_int64 ct; + + /* reset the failure count if the failure count reset time + period has elapsed */ + tm = 0; + khc_read_int64(csp_mod, L"FailureTime", &tm); + GetSystemTimeAsFileTime((LPFILETIME) &ct); + ct -= tm; + + if(tm > 0 && + FtIntervalToSeconds((LPFILETIME) &ct) > fail_reset_time) { + + i = 0; + khc_write_int32(csp_mod, L"FailureCount", 0); + khc_write_int64(csp_mod, L"FailureTime", 0); + + } + + if(i > max_fail_count) { + /* failed too many times */ + _report_mr0(KHERR_ERROR, 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) + free(m->path); + m->path = malloc(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; + } + + if (khc_read_string(csp_mod, L"Vendor", NULL, &sz) == KHM_ERROR_TOO_LONG) { + if (m->vendor) + free(m->vendor); + m->vendor = malloc(sz); + khc_read_string(csp_mod, L"Vendor", m->vendor, &sz); + } + + /* check again */ + if(m->state != KMM_MODULE_STATE_PREINIT) { + _report_mr0(KHERR_ERROR, MSG_IM_NOT_PREINIT); + + goto _exit; + } + + hm = LoadLibrary(m->path); + if(!hm) { + m->h_module = NULL; + m->state = KMM_MODULE_STATE_FAIL_NOT_FOUND; + record_failure = TRUE; + + _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 */ + release_module = FALSE; + exit_module = TRUE; + record_failure = 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; + kmm_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) { + _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_RUNNING; + + exit_module = FALSE; + record_failure = FALSE; + + ResetEvent(evt_exit); + +_exit: + if(csp_mod) { + if(record_failure) { + khm_int64 ct; + + 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((LPFILETIME) &ct); + khc_write_int64(csp_mod, L"FailureTime", ct); + } + } + 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)); + + if(release_module) + kmm_release_module(kmm_handle_from_module(m)); + + 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) + kmm_exit_module(m); + + _end_task(); +} + + +/*! \internal + \brief Uninitializes a module + + \note Should only be called from the context of the registrar + thread */ +void kmm_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 + kmm_exit_module(). + + When the last plugin is exited, the plugin management code + automatically signalls the registrar to remove the module. + kmm_exit_module() gets called again. This is the second + 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; + kmm_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) { + 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); + } + + 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; + } + } + + 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); + } + } + + LeaveCriticalSection(&cs_kmm); + + if(m->state > 0) + m->state = KMM_MODULE_STATE_EXITED; + + if(m->h_module) { + FreeLibrary(m->h_module); + } + + if(m->h_resource && (m->h_resource != m->h_module)) { + FreeLibrary(m->h_resource); + } + + m->h_module = NULL; + m->h_resource = NULL; + m->flags = 0; + + /* release the hold obtained in kmm_init_module() */ + kmm_release_module(kmm_handle_from_module(m)); +} diff --git a/src/windows/identity/kmm/kmmconfig.csv b/src/windows/identity/kmm/kmmconfig.csv new file mode 100644 index 0000000000..93444bdf4b --- /dev/null +++ b/src/windows/identity/kmm/kmmconfig.csv @@ -0,0 +1,52 @@ +Name,Type,Value,Description +PluginManager,KC_SPACE,0,Plugin Manager Configuration + Plugins,KC_SPACE,0,Plugin Specific configuration + PluginMaxFailureCount,KC_INT32,3,Maximum number of failure counts before plugin is disabled + PluginFailureCountResetTime,KC_INT64,36000,Time after first failure at which the failure count is reset + LoadList,KC_STRING,AfsCred,List of plugins that are active + _Schema,KC_SPACE,0,Plugin schema + Module,KC_STRING,,The name of the module that registered this plugin + Description,KC_STRING,,Description of the plugin + Dependencies,KC_STRING,,Multi string of plugin names of plugins that this plugin depends on + Type,KC_INT32,0,The type of the plugin + Flags,KC_INT32,0,Flags. Currently unused + FailureCount,KC_INT32,0,Number of failed loads + FailureTime,KC_INT64,0,FILETIME of first failure + FailureReason,KC_INT32,0,Reason for first failure. One of the plugin status values. + Parameters,KC_SPACE,0,Plugin parameters. The schema beyond this is plugin dependent. + Parameters,KC_ENDSPACE,0, + _Schema,KC_ENDSPACE,0, + Plugins,KC_ENDSPACE,0, + Modules,KC_SPACE,0,Module Specific configuration + LoadList,KC_STRING,"OpenAFS,MITKrb5,MITKrb4",List of modules to load at startup + ModuleMaxFailureCount,KC_INT32,3,Maximum number of failure counts before module is disabled + ModuleFailureCountResetTime,KC_INT64,72000,Time after first failure at which the failure count is reset + _Schema,KC_SPACE,0,Module schema + ImagePath,KC_STRING,,Path to the DLL + Description,KC_STRING,,Description of the module + Vendor,KC_STRING,,Vendor or copyright string + Flags,KC_INT32,0,Flags. Currently unused. + FailureCount,KC_INT32,0,Number of failed loads + FailureTime,KC_INT64,0,FILETIME of first failure + FailureReason,KC_INT32,0,Reason for first failure. One of the module status values. + FileVersion,KC_INT64,0,khm_version of file + ProductVersion,KC_INT64,0,khm_version of product + PluginList,KC_STRING,,List of plugins implemented in the module + _Schema,KC_ENDSPACE,0, + OpenAFS,KC_SPACE,0,OpenAFS Module + ImagePath,KC_STRING,afscred.dll, + PluginList,KC_STRING,AfsCred, + Vendor,KC_STRING,OpenAFS.org, + OpenAFS,KC_ENDSPACE,0, + MITKrb5,KC_SPACE,0,MIT Kerberos V + ImagePath,KC_STRING,krb5cred.dll, + PluginList,KC_STRING,Krb5Cred, + Vendor,KC_STRING,Massachusetts Institute of Technology, + MITKrb5,KC_ENDSPACE,0, + MITKrb4,KC_SPACE,0,MIT Kerberos IV + ImagePath,KC_STRING,krb4cred.dll, + PluginList,KC_STRING,Krb4Cred, + Vendor,KC_STRING,Massachusetts Institute of Technology, + MITKrb4,KC_ENDSPACE,0, + Modules,KC_ENDSPACE,0, +PluginManager,KC_ENDSPACE,0, diff --git a/src/windows/identity/kmm/kmminternal.h b/src/windows/identity/kmm/kmminternal.h new file mode 100644 index 0000000000..662eff228f --- /dev/null +++ b/src/windows/identity/kmm/kmminternal.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KMMINTERNAL_H +#define __KHIMAIRA_KMMINTERNAL_H + +#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 +#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 * vendor; + + 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) + +/* the resources have been loaded */ +#define KMM_MODULE_FLAG_RES_LOADED 8 + +/* the signature has been verified */ +#define KMM_MODULE_FLAG_SIG 16 + +/* LoadLibrary succeeded for module */ +#define KMM_MODULE_FLAG_LOADED 1 + +/* init_module entry called */ +#define KMM_MODULE_FLAG_INITP 2 + +/* the module is disabled by the user + (option specifed in configuration) */ +#define KMM_MODULE_FLAG_DISABLED 1024 + +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 1 + +/* the plugin is disabled by the user + (option specified in configuration) */ +#define KMM_PLUGIN_FLAG_DISABLED 1024 + +/* the plugin is in the kmm_listed_plugins list */ +#define KMM_PLUGIN_FLAG_IN_LIST 2 + +/* the plugin is in the module's plugin list */ +#define KMM_PLUGIN_FLAG_IN_MODLIST 4 + +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 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 +kmm_reg_cb(khm_int32 msg_type, + khm_int32 msg_sub_type, + khm_ui_4 uparam, + void *vparam); + +DWORD WINAPI kmm_registrar(LPVOID lpParameter); + +DWORD WINAPI kmm_plugin_broker(LPVOID lpParameter); + +void kmm_init_plugin(kmm_plugin_i * p); +void kmm_exit_plugin(kmm_plugin_i * p); +void kmm_init_module(kmm_module_i * m); +void kmm_exit_module(kmm_module_i * m); + +/* Modules */ +kmm_module_i * kmm_get_module_i(wchar_t * name); +kmm_module_i * kmm_find_module_i(wchar_t * name); +void kmm_free_module(kmm_module_i * m); + +/* Plugins */ +kmm_plugin_i * kmm_get_plugin_i(wchar_t * name); +kmm_plugin_i * kmm_find_plugin_i(wchar_t * name); +void kmm_free_plugin(kmm_plugin_i * pi); +void kmm_list_plugin(kmm_plugin_i * p); +void kmm_delist_plugin(kmm_plugin_i * p); + +khm_boolean kmm_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 new file mode 100644 index 0000000000..8ec4bc0a3c --- /dev/null +++ b/src/windows/identity/kmm/kmmmain.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +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, + kmm_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 */ + 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 new file mode 100644 index 0000000000..f7489bf4c0 --- /dev/null +++ b/src/windows/identity/kmm/kplugin.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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@8" +#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@8" +#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/kmm/lang/kmm_msgs.mc b/src/windows/identity/kmm/lang/kmm_msgs.mc new file mode 100644 index 0000000000..5e88121d14 --- /dev/null +++ b/src/windows/identity/kmm/lang/kmm_msgs.mc @@ -0,0 +1,146 @@ +; // ** kmm_msgs.mc + +; /* Since .mc files can contain strings from any language, we define +; all our messages in one file in the /lang/ directory instead of +; language specific subdirectories. */ + +; /* The type is set to (wchar_t *) because that's what we will be +; feeding kherr_report() function. */ + +MessageIdTypedef=LPWSTR + +; /* Severity values as defined in the message definition file are +; currently ignored. */ + +SeverityNames=( + Success=0x0 +) + +LanguageNames=( + English=0x409:MSG_ENU +) + +OutputBase=16 + +; /* Actual messages start here */ + +MessageId=1 +Severity=Success +SymbolicName=MSG_INITIAL +Language=English +Initial placeholder message +. + +MessageId= +SymbolicName=MSG_LOAD_DEFAULT +Language=English +Load default modules +. + +MessageId= +SymbolicName=MSG_INIT_MODULE +Language=English +Initializing module [%1] +. + +MessageId= +SymbolicName=MSG_IM_GET_CONFIG +Language=English +Can't get configuration for modules +. + +MessageId= +SymbolicName=MSG_IM_NOT_PREINIT +Language=English +Module is not in PREINIT state. Current state=[%1!d!] +. + +MessageId= +SymbolicName=MSG_IM_NOT_REGISTERED +Language=English +Module is not registered +. + +MessageId= +SymbolicName=MSG_IM_DISABLED +Language=English +Module is disabled +. + +MessageId= +SymbolicName=MSG_IM_MAX_FAIL +Language=English +Module has failed too many times +. + +Messageid= +SymbolicName=MSG_IM_NOT_FOUND +Language=English +Module binary was not found. Checked path [%1] +. + +MessageId= +SymbolicName=MSG_IM_NO_ENTRY +Language=English +Entry point not found. Checked entry point [%1] +. + +MessageId= +SymbolicName=MSG_IM_INIT_FAIL +Language=English +Module initialization entry point returned failure code [%1!d!] +. + +MessageId= +SymbolicName=MSG_IM_NO_PLUGINS +Language=English +No plugins were registerd by the module +. + +MessageId= +SymbolicName=MSG_IM_MOD_STATE +Language=English +Module [%1] is in state [%2!d!] +. + +MessageId= +SymbolicName=MSG_IP_TASK_DESC +Language=English +Initializing plugin [%1] +. + +MessageId= +SymbolicName=MSG_IP_GET_CONFIG +Language=English +Can't get configuration for plugins +. + +MessageId= +SymbolicName=MSG_IP_NOT_REGISTERED +Language=English +The plugin is not registered +. + +MessageId= +SymbolicName=MSG_IP_DISABLED +Language=English +The plugin is disabled +. + +MessageId= +SymbolicName=MSG_IP_HOLD +Language=English +Placing plugin [%1] on hold +. + +MessageId= +SymbolicName=MSG_IP_STATE +Language=English +Leaving plugin [%1] in state [%2!d!] +. + +MessageId= +SymbolicName=MSG_IP_EXITING +Language=English +The plugin [%1] is in error state [%2!d!]. Exiting plugin. +. diff --git a/src/windows/identity/kmq/Makefile b/src/windows/identity/kmq/Makefile new file mode 100644 index 0000000000..1f11e0fe42 --- /dev/null +++ b/src/windows/identity/kmq/Makefile @@ -0,0 +1,48 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=kmq +!include <../config/Makefile.w32> + +INCFILES= \ + $(INCDIR)\kmq.h + +OBJFILES= \ + $(OBJ)\kmqmain.obj \ + $(OBJ)\init.obj \ + $(OBJ)\msgtype.obj \ + $(OBJ)\consumer.obj \ + $(OBJ)\publisher.obj \ + $(OBJ)\kmqconfig.obj + +SDKLIBFILES=\ + strsafe.lib + +$(OBJ)\kmqconfig.c: kmqconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +all: mkdirs $(INCFILES) $(OBJFILES) + +clean:: + $(RM) $(INCFILES) diff --git a/src/windows/identity/kmq/consumer.c b/src/windows/identity/kmq/consumer.c new file mode 100644 index 0000000000..32072cf637 --- /dev/null +++ b/src/windows/identity/kmq/consumer.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +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; + +/*! \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 = malloc(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); + 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(&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++; + 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(&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) { + m->refcount++; + + 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. */ + SendMessage(s->recipient.hwnd, KMQ_WM_DISPATCH, m->type, (LPARAM) m); + m->nSent++; + } else { + m->nSent++; + 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); +#else + return; +#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 = malloc(sizeof(kmq_msg_subscription)); + 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 = malloc(sizeof(kmq_msg_subscription)); + 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; +} + +/*! \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 = malloc(sizeof(kmq_msg_subscription)); + 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; + + s->type = 0; + + EnterCriticalSection(&cs_kmq_global); + LDELETE(&kmq_adhoc_subs, s); + LeaveCriticalSection(&cs_kmq_global); + + free(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) + free(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) + free(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; +} + +/*! \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(); + + 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); + + /* 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 new file mode 100644 index 0000000000..cb50c54761 --- /dev/null +++ b/src/windows/identity/kmq/init.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include + +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) { + khc_read_int32(hconfig, KMQ_CONF_QUEUE_DEAD_TIMEOUT_NAME, &kmq_queue_dead_timeout); + khc_read_int32(hconfig, KMQ_CONF_CALL_DEAD_TIMEOUT_NAME, &kmq_call_dead_timeout); + 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; + + q = (kmq_queue *) TlsGetValue(kmq_tls_queue); + if(!q) { + EnterCriticalSection(&cs_kmq_global); + + q = malloc(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; + + 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) { + EnterCriticalSection(&cs_kmq_global); + + LDELETE(&queues, q); + + DeleteCriticalSection(&q->cs); + CloseHandle(q->wait_o); + + /* TODO: free up the queued messages */ + + TlsSetValue(kmq_tls_queue, (LPVOID) 0); + + LeaveCriticalSection(&cs_kmq_global); + } +} + +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; + + 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; +} diff --git a/src/windows/identity/kmq/kmq.h b/src/windows/identity/kmq/kmq.h new file mode 100644 index 0000000000..3d596d7954 --- /dev/null +++ b/src/windows/identity/kmq/kmq.h @@ -0,0 +1,743 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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_int32 refcount; + + LDCL(struct tag_kmq_message); +} kmq_message; + +/*! \brief A handle to a call + */ +typedef kmq_message *kmq_call; + +/*! \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 */ + + /*Q*/ + QDCL(kmq_message_ref); /*!< Queue of message references */ + + /*Lnode*/ + LDCL(struct tag_kmq_queue); +} kmq_queue; + +/*! \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 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; + +/*! \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 + +/* 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 *); + +/*! \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)) + +KHMEXP khm_int32 KHMAPI kmq_init(void); + +KHMEXP khm_int32 KHMAPI kmq_exit(void); + +/*! \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_PARM 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 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_PARM One of the parameters were invalid. +*/ +KHMEXP khm_int32 KHMAPI kmq_wait(kmq_call call, kmq_timer timeout); + +/*! \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/kmqconfig.csv b/src/windows/identity/kmq/kmqconfig.csv new file mode 100644 index 0000000000..c6d5ca451c --- /dev/null +++ b/src/windows/identity/kmq/kmqconfig.csv @@ -0,0 +1,5 @@ +Name,Type,Value,Description +KMQ,KC_SPACE,0,Options for the credentials window + QueueDeadTimeout,KC_INT32,12000, + CallDeadTimeout,KC_INT32,8000, +KMQ,KC_ENDSPACE,0, diff --git a/src/windows/identity/kmq/kmqinternal.h b/src/windows/identity/kmq/kmqinternal.h new file mode 100644 index 0000000000..c82fb925d7 --- /dev/null +++ b/src/windows/identity/kmq/kmqinternal.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KMQINTERNAL_H +#define __KHIMAIRA_KMQINTERNAL_H + +#include +#include +#include +#include +#include +#include +#include + +#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); + +/* 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 new file mode 100644 index 0000000000..d93403a57b --- /dev/null +++ b/src/windows/identity/kmq/kmqmain.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +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 new file mode 100644 index 0000000000..eb44eecf3a --- /dev/null +++ b/src/windows/identity/kmq/msgtype.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +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) { + /*TODO: free the message type*/ + /* must set handler to NULL before freeing type */ + /* must set msg_type[t] = NULL before starting to free type */ +} + +/*! \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 = malloc(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_PARM; + 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; + } else { + if(msg_types[i]->name != NULL && + !wcscmp(msg_types[i]->name, name)) + registered = TRUE; + } + } + + 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 = malloc(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_PARM; + + 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; + + 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_PARM; + + 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 new file mode 100644 index 0000000000..5391844ac1 --- /dev/null +++ b/src/windows/identity/kmq/publisher.c @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +CRITICAL_SECTION cs_kmq_msg; +kmq_message * msg_free = NULL; +kmq_message * msg_active = NULL; + +/*! \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 = malloc(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); +} + + +/*! \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; +} + +/* TODO:Implement these */ +KHMEXP khm_int32 KHMAPI kmq_get_next_response(kmq_call call, void ** resp) { + return 0; +} + +KHMEXP khm_boolean KHMAPI kmq_has_completed(kmq_call call) { + return (call->nCompleted + call->nFailed == call->nSent); +} + +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_PARM; +} + +/*! \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/Makefile b/src/windows/identity/nidmgrdll/Makefile new file mode 100644 index 0000000000..5d48c2d12d --- /dev/null +++ b/src/windows/identity/nidmgrdll/Makefile @@ -0,0 +1,106 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=nidmgrdll +!include <../config/Makefile.w32> + +DLLFILE=$(BINDIR)\nidmgr32.dll + +LIBFILE=$(LIBDIR)\nidmgr32.lib + +UTILDIR=$(OBJDIR)\util + +KHERRDIR=$(OBJDIR)\kherr + +KCONFIGDIR=$(OBJDIR)\kconfig + +KMQDIR=$(OBJDIR)\kmq + +KCDBDIR=$(OBJDIR)\kcreddb + +KMMDIR=$(OBJDIR)\kmm + +UIDIR=$(OBJDIR)\uilib + +OBJFILES= \ + $(OBJ)\dllmain.obj \ + $(UTILDIR)\hashtable.obj \ + $(UTILDIR)\sync.obj \ + $(UTILDIR)\mstring.obj \ + $(KHERRDIR)\kherrmain.obj \ + $(KHERRDIR)\kherr.obj \ + $(KCONFIGDIR)\kconfigmain.obj \ + $(KCONFIGDIR)\api.obj \ + $(KMQDIR)\kmqmain.obj \ + $(KMQDIR)\init.obj \ + $(KMQDIR)\msgtype.obj \ + $(KMQDIR)\consumer.obj \ + $(KMQDIR)\publisher.obj \ + $(KMQDIR)\kmqconfig.obj \ + $(KCDBDIR)\buf.obj \ + $(KCDBDIR)\attrib.obj \ + $(KCDBDIR)\credential.obj \ + $(KCDBDIR)\credset.obj \ + $(KCDBDIR)\credtype.obj \ + $(KCDBDIR)\identity.obj \ + $(KCDBDIR)\init.obj \ + $(KCDBDIR)\kcreddbmain.obj \ + $(KCDBDIR)\type.obj \ + $(KCDBDIR)\kcdbconfig.obj \ + $(KMMDIR)\kmmmain.obj \ + $(KMMDIR)\kmm.obj \ + $(KMMDIR)\kmm_plugin.obj \ + $(KMMDIR)\kmm_module.obj \ + $(KMMDIR)\kmm_reg.obj \ + $(KMMDIR)\kmm_registrar.obj \ + $(KMMDIR)\kmmconfig.obj \ + $(UIDIR)\rescache.obj \ + $(UIDIR)\action.obj \ + $(UIDIR)\creddlg.obj \ + $(UIDIR)\alert.obj \ + $(UIDIR)\propsheet.obj \ + $(UIDIR)\propwnd.obj \ + $(UIDIR)\uilibmain.obj \ + $(UIDIR)\actiondef.obj \ + $(UIDIR)\acceldef.obj \ + $(UIDIR)\configui.obj \ + $(UIDIR)\trackerwnd.obj + +RESFILES= \ + $(OBJ)\nidmgrdll.res \ + $(KCDBDIR)\kcredres.res \ + $(KMMDIR)\kmm_msgs.res \ + +SDKLIBFILES= \ + advapi32.lib \ + strsafe.lib \ + comctl32.lib + +$(DLLFILE): $(OBJFILES) $(RESFILES) + $(DLLGUILINK) $(LIBFILES) $(SDKLIBFILES) + +all: mkdirs $(DLLFILE) + +clean:: + $(RM) $(DLLFILE) diff --git a/src/windows/identity/nidmgrdll/dllmain.c b/src/windows/identity/nidmgrdll/dllmain.c new file mode 100644 index 0000000000..f54d4ef72c --- /dev/null +++ b/src/windows/identity/nidmgrdll/dllmain.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#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/nidmgrdll/nidmgrdll.rc b/src/windows/identity/nidmgrdll/nidmgrdll.rc new file mode 100644 index 0000000000..10870e8c39 --- /dev/null +++ b/src/windows/identity/nidmgrdll/nidmgrdll.rc @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif + +1 VERSIONINFO + FILEVERSION KH_VERSION_LIST + PRODUCTVERSION KH_VERSION_LIST + FILEFLAGSMASK 0x17L + FILEFLAGS KH_VER_FILEFLAGS + FILEOS KH_VER_FILEOS + FILETYPE KH_VER_FILETYPEDLL + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", KH_VERSTR_COMPANY_1033 + VALUE "FileDescription", "NetIDMgr API" + VALUE "FileVersion", KH_VERSION_STRING + VALUE "InternalName", "nidmgr32" + VALUE "LegalCopyright", KH_VERSTR_COPYRIGHT_1033 + VALUE "OriginalFilename", "nidmgr32.dll" + VALUE "ProductName", KH_VERSTR_PRODUCT_1033 + VALUE "ProductVersion", KH_VERSTR_VERSION_1033 +#ifdef KH_VERSTR_COMMENT_1033 + VALUE "Comments", KH_VERSTR_COMMENT_1033 +#endif +#ifdef KH_VERSTR_PRIVATE_1033 + VALUE "PrivateBuild", KH_VERSTR_PRIVATE_1033 +#endif +#ifdef KH_VERSTR_SPECIAL_1033 + VALUE "SpecialBuild", KH_VERSTR_SPECIAL_1033 +#endif + END + END + +/* Language independent */ + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END + +END diff --git a/src/windows/identity/plugins/common/Makefile b/src/windows/identity/plugins/common/Makefile new file mode 100644 index 0000000000..cbadbc6448 --- /dev/null +++ b/src/windows/identity/plugins/common/Makefile @@ -0,0 +1,42 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=plugins\common +!include <../../config/Makefile.w32> + +INCFILES= \ + $(INCDIR)\krb5common.h \ + $(INCDIR)\dynimport.h + +OBJFILES= \ + $(LIBDIR)\krb5common.obj \ + $(LIBDIR)\dynimport.obj + +all: mkdirs $(INCFILES) $(OBJFILES) + +clean:: + $(RM) $(INCFILES) + +{}.c{$(LIBDIR)}.obj: + $(C2OBJ) diff --git a/src/windows/identity/plugins/common/dynimport.c b/src/windows/identity/plugins/common/dynimport.c new file mode 100644 index 0000000000..cd33813f78 --- /dev/null +++ b/src/windows/identity/plugins/common/dynimport.c @@ -0,0 +1,420 @@ +/* +* Copyright (c) 2004 Massachusetts Institute of Technology +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* $Id$ */ + +#include +#include +#include +#include + +HINSTANCE hKrb4 = 0; +HINSTANCE hKrb5 = 0; +HINSTANCE hKrb524 = 0; +HINSTANCE hSecur32 = 0; +HINSTANCE hComErr = 0; +HINSTANCE hService = 0; +HINSTANCE hProfile = 0; +HINSTANCE hPsapi = 0; +HINSTANCE hToolHelp32 = 0; +HINSTANCE hCCAPI = 0; + +DWORD AfsAvailable = 0; + +// CCAPI +DECL_FUNC_PTR(cc_initialize); +DECL_FUNC_PTR(cc_shutdown); +DECL_FUNC_PTR(cc_get_NC_info); +DECL_FUNC_PTR(cc_free_NC_info); + +// krb4 functions +DECL_FUNC_PTR(get_krb_err_txt_entry); +DECL_FUNC_PTR(k_isinst); +DECL_FUNC_PTR(k_isname); +DECL_FUNC_PTR(k_isrealm); +DECL_FUNC_PTR(kadm_change_your_password); +DECL_FUNC_PTR(kname_parse); +DECL_FUNC_PTR(krb_get_cred); +DECL_FUNC_PTR(krb_get_krbhst); +DECL_FUNC_PTR(krb_get_lrealm); +DECL_FUNC_PTR(krb_get_pw_in_tkt); +DECL_FUNC_PTR(krb_get_tf_realm); +DECL_FUNC_PTR(krb_mk_req); +DECL_FUNC_PTR(krb_realmofhost); +DECL_FUNC_PTR(tf_init); +DECL_FUNC_PTR(tf_close); +DECL_FUNC_PTR(tf_get_cred); +DECL_FUNC_PTR(tf_get_pname); +DECL_FUNC_PTR(tf_get_pinst); +DECL_FUNC_PTR(LocalHostAddr); +DECL_FUNC_PTR(tkt_string); +DECL_FUNC_PTR(krb_set_tkt_string); +DECL_FUNC_PTR(initialize_krb_error_func); +DECL_FUNC_PTR(initialize_kadm_error_table); +DECL_FUNC_PTR(dest_tkt); +DECL_FUNC_PTR(krb_in_tkt); +DECL_FUNC_PTR(krb_save_credentials); +DECL_FUNC_PTR(krb_get_krbconf2); +DECL_FUNC_PTR(krb_get_krbrealm2); +DECL_FUNC_PTR(krb_life_to_time); + +// krb5 functions +DECL_FUNC_PTR(krb5_change_password); +DECL_FUNC_PTR(krb5_get_init_creds_opt_init); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list); +DECL_FUNC_PTR(krb5_get_init_creds_password); +DECL_FUNC_PTR(krb5_get_prompt_types); +DECL_FUNC_PTR(krb5_build_principal_ext); +DECL_FUNC_PTR(krb5_cc_get_name); +DECL_FUNC_PTR(krb5_cc_resolve); +DECL_FUNC_PTR(krb5_cc_default); +DECL_FUNC_PTR(krb5_cc_default_name); +DECL_FUNC_PTR(krb5_cc_set_default_name); +DECL_FUNC_PTR(krb5_cc_initialize); +DECL_FUNC_PTR(krb5_cc_destroy); +DECL_FUNC_PTR(krb5_cc_close); +DECL_FUNC_PTR(krb5_cc_store_cred); +DECL_FUNC_PTR(krb5_cc_copy_creds); +DECL_FUNC_PTR(krb5_cc_retrieve_cred); +DECL_FUNC_PTR(krb5_cc_get_principal); +DECL_FUNC_PTR(krb5_cc_start_seq_get); +DECL_FUNC_PTR(krb5_cc_next_cred); +DECL_FUNC_PTR(krb5_cc_end_seq_get); +DECL_FUNC_PTR(krb5_cc_remove_cred); +DECL_FUNC_PTR(krb5_cc_set_flags); +// DECL_FUNC_PTR(krb5_cc_get_type); +DECL_FUNC_PTR(krb5_free_context); +DECL_FUNC_PTR(krb5_free_cred_contents); +DECL_FUNC_PTR(krb5_free_principal); +DECL_FUNC_PTR(krb5_get_in_tkt_with_password); +DECL_FUNC_PTR(krb5_init_context); +DECL_FUNC_PTR(krb5_parse_name); +DECL_FUNC_PTR(krb5_timeofday); +DECL_FUNC_PTR(krb5_timestamp_to_sfstring); +DECL_FUNC_PTR(krb5_unparse_name); +DECL_FUNC_PTR(krb5_get_credentials); +DECL_FUNC_PTR(krb5_mk_req); +DECL_FUNC_PTR(krb5_sname_to_principal); +DECL_FUNC_PTR(krb5_get_credentials_renew); +DECL_FUNC_PTR(krb5_free_data); +DECL_FUNC_PTR(krb5_free_data_contents); +// DECL_FUNC_PTR(krb5_get_realm_domain); +DECL_FUNC_PTR(krb5_free_unparsed_name); +DECL_FUNC_PTR(krb5_os_localaddr); +DECL_FUNC_PTR(krb5_copy_keyblock_contents); +DECL_FUNC_PTR(krb5_copy_data); +DECL_FUNC_PTR(krb5_free_creds); +DECL_FUNC_PTR(krb5_build_principal); +DECL_FUNC_PTR(krb5_get_renewed_creds); +DECL_FUNC_PTR(krb5_get_default_config_files); +DECL_FUNC_PTR(krb5_free_config_files); +DECL_FUNC_PTR(krb5_get_default_realm); +DECL_FUNC_PTR(krb5_free_ticket); +DECL_FUNC_PTR(krb5_decode_ticket); +DECL_FUNC_PTR(krb5_get_host_realm); +DECL_FUNC_PTR(krb5_free_host_realm); +DECL_FUNC_PTR(krb5_c_random_make_octets); +DECL_FUNC_PTR(krb5_free_addresses); +DECL_FUNC_PTR(krb5_free_default_realm); + +// Krb524 functions +DECL_FUNC_PTR(krb524_init_ets); +DECL_FUNC_PTR(krb524_convert_creds_kdc); + +// ComErr functions +DECL_FUNC_PTR(com_err); +DECL_FUNC_PTR(error_message); + +// Profile functions +DECL_FUNC_PTR(profile_init); +DECL_FUNC_PTR(profile_release); +DECL_FUNC_PTR(profile_get_subsection_names); +DECL_FUNC_PTR(profile_free_list); +DECL_FUNC_PTR(profile_get_string); +DECL_FUNC_PTR(profile_release_string); + +// Service functions +DECL_FUNC_PTR(OpenSCManagerA); +DECL_FUNC_PTR(OpenServiceA); +DECL_FUNC_PTR(QueryServiceStatus); +DECL_FUNC_PTR(CloseServiceHandle); +DECL_FUNC_PTR(LsaNtStatusToWinError); + +// LSA Functions +DECL_FUNC_PTR(LsaConnectUntrusted); +DECL_FUNC_PTR(LsaLookupAuthenticationPackage); +DECL_FUNC_PTR(LsaCallAuthenticationPackage); +DECL_FUNC_PTR(LsaFreeReturnBuffer); +DECL_FUNC_PTR(LsaGetLogonSessionData); + +// CCAPI +FUNC_INFO ccapi_fi[] = { + MAKE_FUNC_INFO(cc_initialize), + MAKE_FUNC_INFO(cc_shutdown), + MAKE_FUNC_INFO(cc_get_NC_info), + MAKE_FUNC_INFO(cc_free_NC_info), + END_FUNC_INFO +}; + +FUNC_INFO k4_fi[] = { + MAKE_FUNC_INFO(get_krb_err_txt_entry), + MAKE_FUNC_INFO(k_isinst), + MAKE_FUNC_INFO(k_isname), + MAKE_FUNC_INFO(k_isrealm), + MAKE_FUNC_INFO(kadm_change_your_password), + MAKE_FUNC_INFO(kname_parse), + MAKE_FUNC_INFO(krb_get_cred), + MAKE_FUNC_INFO(krb_get_krbhst), + MAKE_FUNC_INFO(krb_get_lrealm), + MAKE_FUNC_INFO(krb_get_pw_in_tkt), + MAKE_FUNC_INFO(krb_get_tf_realm), + MAKE_FUNC_INFO(krb_mk_req), + MAKE_FUNC_INFO(krb_realmofhost), + MAKE_FUNC_INFO(tf_init), + MAKE_FUNC_INFO(tf_close), + MAKE_FUNC_INFO(tf_get_cred), + MAKE_FUNC_INFO(tf_get_pname), + MAKE_FUNC_INFO(tf_get_pinst), + MAKE_FUNC_INFO(LocalHostAddr), + MAKE_FUNC_INFO(tkt_string), + MAKE_FUNC_INFO(krb_set_tkt_string), + MAKE_FUNC_INFO(initialize_krb_error_func), + MAKE_FUNC_INFO(initialize_kadm_error_table), + MAKE_FUNC_INFO(dest_tkt), + /* MAKE_FUNC_INFO(lsh_LoadKrb4LeashErrorTables), */// XXX + MAKE_FUNC_INFO(krb_in_tkt), + MAKE_FUNC_INFO(krb_save_credentials), + MAKE_FUNC_INFO(krb_get_krbconf2), + MAKE_FUNC_INFO(krb_get_krbrealm2), + MAKE_FUNC_INFO(krb_life_to_time), + END_FUNC_INFO +}; + +FUNC_INFO k5_fi[] = { + MAKE_FUNC_INFO(krb5_change_password), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_init), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list), + MAKE_FUNC_INFO(krb5_get_init_creds_password), + MAKE_FUNC_INFO(krb5_get_prompt_types), + MAKE_FUNC_INFO(krb5_build_principal_ext), + MAKE_FUNC_INFO(krb5_cc_get_name), + MAKE_FUNC_INFO(krb5_cc_resolve), + MAKE_FUNC_INFO(krb5_cc_default), + MAKE_FUNC_INFO(krb5_cc_default_name), + MAKE_FUNC_INFO(krb5_cc_set_default_name), + MAKE_FUNC_INFO(krb5_cc_initialize), + MAKE_FUNC_INFO(krb5_cc_destroy), + MAKE_FUNC_INFO(krb5_cc_close), + MAKE_FUNC_INFO(krb5_cc_copy_creds), + MAKE_FUNC_INFO(krb5_cc_store_cred), + MAKE_FUNC_INFO(krb5_cc_retrieve_cred), + MAKE_FUNC_INFO(krb5_cc_get_principal), + MAKE_FUNC_INFO(krb5_cc_start_seq_get), + MAKE_FUNC_INFO(krb5_cc_next_cred), + MAKE_FUNC_INFO(krb5_cc_end_seq_get), + MAKE_FUNC_INFO(krb5_cc_remove_cred), + MAKE_FUNC_INFO(krb5_cc_set_flags), + // MAKE_FUNC_INFO(krb5_cc_get_type), + MAKE_FUNC_INFO(krb5_free_context), + MAKE_FUNC_INFO(krb5_free_cred_contents), + MAKE_FUNC_INFO(krb5_free_principal), + MAKE_FUNC_INFO(krb5_get_in_tkt_with_password), + MAKE_FUNC_INFO(krb5_init_context), + MAKE_FUNC_INFO(krb5_parse_name), + MAKE_FUNC_INFO(krb5_timeofday), + MAKE_FUNC_INFO(krb5_timestamp_to_sfstring), + MAKE_FUNC_INFO(krb5_unparse_name), + MAKE_FUNC_INFO(krb5_get_credentials), + MAKE_FUNC_INFO(krb5_mk_req), + MAKE_FUNC_INFO(krb5_sname_to_principal), + MAKE_FUNC_INFO(krb5_get_credentials_renew), + MAKE_FUNC_INFO(krb5_free_data), + MAKE_FUNC_INFO(krb5_free_data_contents), + // MAKE_FUNC_INFO(krb5_get_realm_domain), + MAKE_FUNC_INFO(krb5_free_unparsed_name), + MAKE_FUNC_INFO(krb5_os_localaddr), + MAKE_FUNC_INFO(krb5_copy_keyblock_contents), + MAKE_FUNC_INFO(krb5_copy_data), + MAKE_FUNC_INFO(krb5_free_creds), + MAKE_FUNC_INFO(krb5_build_principal), + MAKE_FUNC_INFO(krb5_get_renewed_creds), + MAKE_FUNC_INFO(krb5_free_addresses), + MAKE_FUNC_INFO(krb5_get_default_config_files), + MAKE_FUNC_INFO(krb5_free_config_files), + MAKE_FUNC_INFO(krb5_get_default_realm), + MAKE_FUNC_INFO(krb5_free_ticket), + MAKE_FUNC_INFO(krb5_decode_ticket), + MAKE_FUNC_INFO(krb5_get_host_realm), + MAKE_FUNC_INFO(krb5_free_host_realm), + MAKE_FUNC_INFO(krb5_c_random_make_octets), + MAKE_FUNC_INFO(krb5_free_default_realm), + END_FUNC_INFO +}; + +FUNC_INFO k524_fi[] = { + MAKE_FUNC_INFO(krb524_init_ets), + MAKE_FUNC_INFO(krb524_convert_creds_kdc), + END_FUNC_INFO +}; + +FUNC_INFO profile_fi[] = { + MAKE_FUNC_INFO(profile_init), + MAKE_FUNC_INFO(profile_release), + MAKE_FUNC_INFO(profile_get_subsection_names), + MAKE_FUNC_INFO(profile_free_list), + MAKE_FUNC_INFO(profile_get_string), + MAKE_FUNC_INFO(profile_release_string), + END_FUNC_INFO +}; + +FUNC_INFO ce_fi[] = { + MAKE_FUNC_INFO(com_err), + MAKE_FUNC_INFO(error_message), + END_FUNC_INFO +}; + +FUNC_INFO service_fi[] = { + MAKE_FUNC_INFO(OpenSCManagerA), + MAKE_FUNC_INFO(OpenServiceA), + MAKE_FUNC_INFO(QueryServiceStatus), + MAKE_FUNC_INFO(CloseServiceHandle), + MAKE_FUNC_INFO(LsaNtStatusToWinError), + END_FUNC_INFO +}; + +FUNC_INFO lsa_fi[] = { + MAKE_FUNC_INFO(LsaConnectUntrusted), + MAKE_FUNC_INFO(LsaLookupAuthenticationPackage), + MAKE_FUNC_INFO(LsaCallAuthenticationPackage), + MAKE_FUNC_INFO(LsaFreeReturnBuffer), + MAKE_FUNC_INFO(LsaGetLogonSessionData), + END_FUNC_INFO +}; + +// psapi functions +DECL_FUNC_PTR(GetModuleFileNameExA); +DECL_FUNC_PTR(EnumProcessModules); + +FUNC_INFO psapi_fi[] = { + MAKE_FUNC_INFO(GetModuleFileNameExA), + MAKE_FUNC_INFO(EnumProcessModules), + END_FUNC_INFO +}; + +// toolhelp functions +DECL_FUNC_PTR(CreateToolhelp32Snapshot); +DECL_FUNC_PTR(Module32First); +DECL_FUNC_PTR(Module32Next); + +FUNC_INFO toolhelp_fi[] = { + MAKE_FUNC_INFO(CreateToolhelp32Snapshot), + MAKE_FUNC_INFO(Module32First), + MAKE_FUNC_INFO(Module32Next), + END_FUNC_INFO +}; + +khm_int32 init_imports(void) { + OSVERSIONINFO osvi; + + LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0); + LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0); + LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0); + LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0); + LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1); + LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1); + LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0); + LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0); + + memset(&osvi, 0, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + + // XXX: We should really use feature testing, first + // checking for CreateToolhelp32Snapshot. If that's + // not around, we try the psapi stuff. + // + // Only load LSA functions if on NT/2000/XP + if(osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) + { + // Windows 9x + LoadFuncs(TOOLHELPDLL, toolhelp_fi, &hToolHelp32, 0, 1, 0, 0); + hPsapi = 0; + } + else if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + // Windows NT + LoadFuncs(PSAPIDLL, psapi_fi, &hPsapi, 0, 1, 0, 0); + hToolHelp32 = 0; + } + + AfsAvailable = TRUE; //afscompat_init(); + + return KHM_ERROR_SUCCESS; +} + +khm_int32 exit_imports(void) { + //afscompat_close(); + + if (hKrb4) + FreeLibrary(hKrb4); + if (hKrb5) + FreeLibrary(hKrb5); + if (hProfile) + FreeLibrary(hProfile); + if (hComErr) + FreeLibrary(hComErr); + if (hService) + FreeLibrary(hService); + if (hSecur32) + FreeLibrary(hSecur32); + if (hKrb524) + FreeLibrary(hKrb524); + if (hPsapi) + FreeLibrary(hPsapi); + if (hToolHelp32) + FreeLibrary(hToolHelp32); + + return KHM_ERROR_SUCCESS; +} + +int (*Lcom_err)(LPSTR,long,LPSTR,...); +LPSTR (*Lerror_message)(long); +LPSTR (*Lerror_table_name)(long); + +void Leash_load_com_err_callback(FARPROC ce, + FARPROC em, + FARPROC etn) +{ + (FARPROC)Lcom_err=ce; + (FARPROC)Lerror_message=em; + (FARPROC)Lerror_table_name=etn; +} diff --git a/src/windows/identity/plugins/common/dynimport.h b/src/windows/identity/plugins/common/dynimport.h new file mode 100644 index 0000000000..b3ba225a66 --- /dev/null +++ b/src/windows/identity/plugins/common/dynimport.h @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_DYNIMPORT_H +#define __KHIMAIRA_DYNIMPORT_H + +/* Dynamic imports */ +#include +#include +#include + +extern HINSTANCE hKrb4; +extern HINSTANCE hKrb5; +extern HINSTANCE hProfile; + +/////////////////////////////////////////////////////////////////////////////// + +#define CCAPI_DLL "krbcc32.dll" +#define KRBCC32_DLL "krbcc32.dll" +#define SERVICE_DLL "advapi32.dll" +#define SECUR32_DLL "secur32.dll" +#define PROFILE_DLL "xpprof32.dll" + +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +//// CCAPI +/* In order to avoid including the private CCAPI headers */ +typedef int cc_int32; + +#define CC_API_VER_1 1 +#define CC_API_VER_2 2 + +#define CCACHE_API cc_int32 + +/* +** The Official Error Codes +*/ +#define CC_NOERROR 0 +#define CC_BADNAME 1 +#define CC_NOTFOUND 2 +#define CC_END 3 +#define CC_IO 4 +#define CC_WRITE 5 +#define CC_NOMEM 6 +#define CC_FORMAT 7 +#define CC_LOCKED 8 +#define CC_BAD_API_VERSION 9 +#define CC_NO_EXIST 10 +#define CC_NOT_SUPP 11 +#define CC_BAD_PARM 12 +#define CC_ERR_CACHE_ATTACH 13 +#define CC_ERR_CACHE_RELEASE 14 +#define CC_ERR_CACHE_FULL 15 +#define CC_ERR_CRED_VERSION 16 + +enum { + CC_CRED_VUNKNOWN = 0, // For validation + CC_CRED_V4 = 1, + CC_CRED_V5 = 2, + CC_CRED_VMAX = 3 // For validation +}; + +typedef struct opaque_dll_control_block_type* apiCB; +typedef struct _infoNC { + char* name; + char* principal; + cc_int32 vers; +} infoNC; + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_initialize, + ( + apiCB** cc_ctx, // < DLL's primary control structure. + // returned here, passed everywhere else + cc_int32 api_version, // > ver supported by caller (use CC_API_VER_1) + cc_int32* api_supported, // < if ~NULL, max ver supported by DLL + const char** vendor // < if ~NULL, vendor name in read only C string + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_shutdown, + ( + apiCB** cc_ctx // <> DLL's primary control structure. NULL after + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_get_NC_info, + ( + apiCB* cc_ctx, // > DLL's primary control structure + struct _infoNC*** ppNCi // < (NULL before call) null terminated, + // list of a structs (free via cc_free_infoNC()) + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_free_NC_info, + ( + apiCB* cc_ctx, + struct _infoNC*** ppNCi // < free list of structs returned by + // cc_get_cache_names(). set to NULL on return + ) +); +//// \CCAPI + +extern DWORD AfsAvailable; + +// service definitions +typedef SC_HANDLE (WINAPI *FP_OpenSCManagerA)(char *, char *, DWORD); +typedef SC_HANDLE (WINAPI *FP_OpenServiceA)(SC_HANDLE, char *, DWORD); +typedef BOOL (WINAPI *FP_QueryServiceStatus)(SC_HANDLE, LPSERVICE_STATUS); +typedef BOOL (WINAPI *FP_CloseServiceHandle)(SC_HANDLE); + +////////////////////////////////////////////////////////////////////////////// + +// CCAPI +extern DECL_FUNC_PTR(cc_initialize); +extern DECL_FUNC_PTR(cc_shutdown); +extern DECL_FUNC_PTR(cc_get_NC_info); +extern DECL_FUNC_PTR(cc_free_NC_info); + +// krb4 functions +extern DECL_FUNC_PTR(get_krb_err_txt_entry); +extern DECL_FUNC_PTR(k_isinst); +extern DECL_FUNC_PTR(k_isname); +extern DECL_FUNC_PTR(k_isrealm); +extern DECL_FUNC_PTR(kadm_change_your_password); +extern DECL_FUNC_PTR(kname_parse); +extern DECL_FUNC_PTR(krb_get_cred); +extern DECL_FUNC_PTR(krb_get_krbhst); +extern DECL_FUNC_PTR(krb_get_lrealm); +extern DECL_FUNC_PTR(krb_get_pw_in_tkt); +extern DECL_FUNC_PTR(krb_get_tf_realm); +extern DECL_FUNC_PTR(krb_mk_req); +extern DECL_FUNC_PTR(krb_realmofhost); +extern DECL_FUNC_PTR(tf_init); +extern DECL_FUNC_PTR(tf_close); +extern DECL_FUNC_PTR(tf_get_cred); +extern DECL_FUNC_PTR(tf_get_pname); +extern DECL_FUNC_PTR(tf_get_pinst); +extern DECL_FUNC_PTR(LocalHostAddr); +extern DECL_FUNC_PTR(tkt_string); +extern DECL_FUNC_PTR(krb_set_tkt_string); +extern DECL_FUNC_PTR(initialize_krb_error_func); +extern DECL_FUNC_PTR(initialize_kadm_error_table); +extern DECL_FUNC_PTR(dest_tkt); +extern DECL_FUNC_PTR(lsh_LoadKrb4LeashErrorTables); // XXX +extern DECL_FUNC_PTR(krb_in_tkt); +extern DECL_FUNC_PTR(krb_save_credentials); +extern DECL_FUNC_PTR(krb_get_krbconf2); +extern DECL_FUNC_PTR(krb_get_krbrealm2); +extern DECL_FUNC_PTR(krb_life_to_time); + +// krb5 functions +extern DECL_FUNC_PTR(krb5_change_password); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_init); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list); +extern DECL_FUNC_PTR(krb5_get_init_creds_password); +extern DECL_FUNC_PTR(krb5_get_prompt_types); +extern DECL_FUNC_PTR(krb5_build_principal_ext); +extern DECL_FUNC_PTR(krb5_cc_get_name); +extern DECL_FUNC_PTR(krb5_cc_resolve); +extern DECL_FUNC_PTR(krb5_cc_default); +extern DECL_FUNC_PTR(krb5_cc_default_name); +extern DECL_FUNC_PTR(krb5_cc_set_default_name); +extern DECL_FUNC_PTR(krb5_cc_initialize); +extern DECL_FUNC_PTR(krb5_cc_destroy); +extern DECL_FUNC_PTR(krb5_cc_close); +extern DECL_FUNC_PTR(krb5_cc_copy_creds); +extern DECL_FUNC_PTR(krb5_cc_store_cred); +extern DECL_FUNC_PTR(krb5_cc_retrieve_cred); +extern DECL_FUNC_PTR(krb5_cc_get_principal); +extern DECL_FUNC_PTR(krb5_cc_start_seq_get); +extern DECL_FUNC_PTR(krb5_cc_next_cred); +extern DECL_FUNC_PTR(krb5_cc_end_seq_get); +extern DECL_FUNC_PTR(krb5_cc_remove_cred); +extern DECL_FUNC_PTR(krb5_cc_set_flags); +// extern DECL_FUNC_PTR(krb5_cc_get_type); +extern DECL_FUNC_PTR(krb5_free_context); +extern DECL_FUNC_PTR(krb5_free_cred_contents); +extern DECL_FUNC_PTR(krb5_free_principal); +extern DECL_FUNC_PTR(krb5_get_in_tkt_with_password); +extern DECL_FUNC_PTR(krb5_init_context); +extern DECL_FUNC_PTR(krb5_parse_name); +extern DECL_FUNC_PTR(krb5_timeofday); +extern DECL_FUNC_PTR(krb5_timestamp_to_sfstring); +extern DECL_FUNC_PTR(krb5_unparse_name); +extern DECL_FUNC_PTR(krb5_get_credentials); +extern DECL_FUNC_PTR(krb5_mk_req); +extern DECL_FUNC_PTR(krb5_sname_to_principal); +extern DECL_FUNC_PTR(krb5_get_credentials_renew); +extern DECL_FUNC_PTR(krb5_free_data); +extern DECL_FUNC_PTR(krb5_free_data_contents); +// extern DECL_FUNC_PTR(krb5_get_realm_domain); +extern DECL_FUNC_PTR(krb5_free_unparsed_name); +extern DECL_FUNC_PTR(krb5_os_localaddr); +extern DECL_FUNC_PTR(krb5_copy_keyblock_contents); +extern DECL_FUNC_PTR(krb5_copy_data); +extern DECL_FUNC_PTR(krb5_free_creds); +extern DECL_FUNC_PTR(krb5_build_principal); +extern DECL_FUNC_PTR(krb5_get_renewed_creds); +extern DECL_FUNC_PTR(krb5_free_addresses); +extern DECL_FUNC_PTR(krb5_get_default_config_files); +extern DECL_FUNC_PTR(krb5_free_config_files); +extern DECL_FUNC_PTR(krb5_get_default_realm); +extern DECL_FUNC_PTR(krb5_free_ticket); +extern DECL_FUNC_PTR(krb5_decode_ticket); +extern DECL_FUNC_PTR(krb5_get_host_realm); +extern DECL_FUNC_PTR(krb5_free_host_realm); +extern DECL_FUNC_PTR(krb5_c_random_make_octets); +extern DECL_FUNC_PTR(krb5_free_default_realm); + +// Krb524 functions +extern DECL_FUNC_PTR(krb524_init_ets); +extern DECL_FUNC_PTR(krb524_convert_creds_kdc); + +// ComErr functions +extern DECL_FUNC_PTR(com_err); +extern DECL_FUNC_PTR(error_message); + +// Profile functions +extern DECL_FUNC_PTR(profile_init); +extern DECL_FUNC_PTR(profile_release); +extern DECL_FUNC_PTR(profile_get_subsection_names); +extern DECL_FUNC_PTR(profile_free_list); +extern DECL_FUNC_PTR(profile_get_string); +extern DECL_FUNC_PTR(profile_release_string); + +// Service functions +extern DECL_FUNC_PTR(OpenSCManagerA); +extern DECL_FUNC_PTR(OpenServiceA); +extern DECL_FUNC_PTR(QueryServiceStatus); +extern DECL_FUNC_PTR(CloseServiceHandle); +extern DECL_FUNC_PTR(LsaNtStatusToWinError); + +// LSA Functions +extern DECL_FUNC_PTR(LsaConnectUntrusted); +extern DECL_FUNC_PTR(LsaLookupAuthenticationPackage); +extern DECL_FUNC_PTR(LsaCallAuthenticationPackage); +extern DECL_FUNC_PTR(LsaFreeReturnBuffer); +extern DECL_FUNC_PTR(LsaGetLogonSessionData); + +// toolhelp functions +TYPEDEF_FUNC( + HANDLE, + WINAPI, + CreateToolhelp32Snapshot, + (DWORD, DWORD) + ); +TYPEDEF_FUNC( + BOOL, + WINAPI, + Module32First, + (HANDLE, LPMODULEENTRY32) + ); +TYPEDEF_FUNC( + BOOL, + WINAPI, + Module32Next, + (HANDLE, LPMODULEENTRY32) + ); + +// psapi functions +TYPEDEF_FUNC( + DWORD, + WINAPI, + GetModuleFileNameExA, + (HANDLE, HMODULE, LPSTR, DWORD) + ); + +TYPEDEF_FUNC( + BOOL, + WINAPI, + EnumProcessModules, + (HANDLE, HMODULE*, DWORD, LPDWORD) + ); + +#define pGetModuleFileNameEx pGetModuleFileNameExA +#define TOOLHELPDLL "kernel32.dll" +#define PSAPIDLL "psapi.dll" + +// psapi functions +extern DECL_FUNC_PTR(GetModuleFileNameExA); +extern DECL_FUNC_PTR(EnumProcessModules); + +// toolhelp functions +extern DECL_FUNC_PTR(CreateToolhelp32Snapshot); +extern DECL_FUNC_PTR(Module32First); +extern DECL_FUNC_PTR(Module32Next); + +khm_int32 init_imports(void); +khm_int32 exit_imports(void); + +#endif diff --git a/src/windows/identity/plugins/common/krb5common.c b/src/windows/identity/plugins/common/krb5common.c new file mode 100644 index 0000000000..5501a12068 --- /dev/null +++ b/src/windows/identity/plugins/common/krb5common.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include + +/**************************************/ +/* khm_krb5_error(): */ +/**************************************/ +int +khm_krb5_error(krb5_error_code rc, LPCSTR FailedFunctionName, + int FreeContextFlag, krb5_context * ctx, + krb5_ccache * cache) +{ +#ifdef NO_KRB5 + return 0; +#else + +#ifdef SHOW_MESSAGE_IN_AN_ANNOYING_WAY + char message[256]; + const char *errText; + int krb5Error = ((int)(rc & 255)); + + errText = perror_message(rc); + _snprintf(message, sizeof(message), + "%s\n(Kerberos error %ld)\n\n%s failed", + errText, + krb5Error, + FailedFunctionName); + + MessageBoxA(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR | + MB_TASKMODAL | + MB_SETFOREGROUND); +#endif + + if (FreeContextFlag == 1) + { + if (*ctx != NULL) + { + if (*cache != NULL) { + pkrb5_cc_close(*ctx, *cache); + *cache = NULL; + } + + pkrb5_free_context(*ctx); + *ctx = NULL; + } + } + + return rc; + +#endif //!NO_KRB5 +} + +int +khm_krb5_initialize(khm_handle ident, + krb5_context *ctx, + krb5_ccache *cache) +{ +#ifdef NO_KRB5 + return(0); +#else + + LPCSTR functionName; + int freeContextFlag; + krb5_error_code rc; + krb5_flags flags = 0; + + if (pkrb5_init_context == NULL) + return 1; + + if (*ctx == 0 && (rc = (*pkrb5_init_context)(ctx))) + { + functionName = "krb5_init_context()"; + freeContextFlag = 0; + goto on_error; + } + + if(*cache == 0) { + wchar_t wccname[256]; + khm_size cbwccname; + + if(ident != NULL) { + cbwccname = sizeof(wccname); + do { + char ccname[256]; + + if(KHM_FAILED(kcdb_identity_get_attrib(ident, L"Krb5CCName", NULL, wccname, &cbwccname))) + break; + + if(UnicodeStrToAnsi(ccname, sizeof(ccname), wccname) == 0) + break; + + if((*pkrb5_cc_resolve)(*ctx, ccname, cache)) { + functionName = "krb5_cc_resolve()"; + freeContextFlag = 1; + goto on_error; + } + } while(FALSE); + } + + if (*cache == 0 && (rc = (*pkrb5_cc_default)(*ctx, cache))) + { + functionName = "krb5_cc_default()"; + freeContextFlag = 1; + goto on_error; + } + } + +#ifdef KRB5_TC_NOTICKET + flags = KRB5_TC_NOTICKET; +#endif + + if ((rc = (*pkrb5_cc_set_flags)(*ctx, *cache, flags))) + { + if (rc != KRB5_FCC_NOFILE && rc != KRB5_CC_NOTFOUND) + khm_krb5_error(rc, "krb5_cc_set_flags()", 0, ctx, + cache); + else if ((rc == KRB5_FCC_NOFILE || rc == KRB5_CC_NOTFOUND) && *ctx != NULL) + { + if (*cache != NULL) + (*pkrb5_cc_close)(*ctx, *cache); + } + return rc; + } + return 0; + +on_error: + return khm_krb5_error(rc, functionName, freeContextFlag, ctx, cache); +#endif //!NO_KRB5 +} diff --git a/src/windows/identity/plugins/common/krb5common.h b/src/windows/identity/plugins/common/krb5common.h new file mode 100644 index 0000000000..7d998215a5 --- /dev/null +++ b/src/windows/identity/plugins/common/krb5common.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* Adapted from multiple Leash header files */ + +#ifndef __KHIMAIRA_KRB5COMMON_H +#define __KHIMAIRA_KRB5COMMON_H + +#include + +#ifndef NO_KRB5 +int khm_krb5_error(krb5_error_code rc, LPCSTR FailedFunctionName, + int FreeContextFlag, krb5_context *ctx, + krb5_ccache *cache); + + +int khm_krb5_initialize(khm_handle ident, krb5_context *, krb5_ccache *); +#endif /* NO_KRB5 */ + +#endif \ No newline at end of file diff --git a/src/windows/identity/plugins/krb4/Makefile b/src/windows/identity/plugins/krb4/Makefile new file mode 100644 index 0000000000..d6b749192d --- /dev/null +++ b/src/windows/identity/plugins/krb4/Makefile @@ -0,0 +1,78 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=plugins\krb4 +!include <../../config/Makefile.w32> + +DLLFILE=$(BINDIR)\krb4cred.dll + +LIBFILE=$(LIBDIR)\krb4cred.lib + +OBJFILES= \ + $(LIBDIR)\dynimport.obj \ + $(LIBDIR)\krb5common.obj \ + $(OBJ)\main.obj \ + $(OBJ)\krb4plugin.obj \ + $(OBJ)\krb4funcs.obj \ + $(OBJ)\errorfuncs.obj \ + $(OBJ)\krb4config.obj \ + $(OBJ)\krb4configdlg.obj + +LIBFILES= \ + $(LIBDIR)\nidmgr32.lib \ + $(KFWLIBDIR)\loadfuncs.lib + +SDKLIBFILES= + +$(OBJ)\krb4config.c: krbconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +$(DLLFILE): $(OBJFILES) + $(DLLGUILINK) $(LIBFILES) $(SDKLIBFILES) + +all: mkdirs $(DLLFILE) lang + +lang:: + +# Repeat this block as necessary redefining LANG for additional +# languages. + +# Begin language block +LANG=en_us + +LANGDLL=$(BINDIR)\krb4cred_$(LANG).dll + +lang:: $(LANGDLL) + +$(LANGDLL): $(OBJ)\langres_$(LANG).res + $(DLLRESLINK) + +$(OBJ)\langres_$(LANG).res: lang\$(LANG)\langres.rc + $(RC2RES) +# End language block + +clean:: +!if defined(INCFILES) + $(RM) $(INCFILES) +!endif diff --git a/src/windows/identity/plugins/krb4/datarep.h b/src/windows/identity/plugins/krb4/datarep.h new file mode 100644 index 0000000000..9c7048e05e --- /dev/null +++ b/src/windows/identity/plugins/krb4/datarep.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KRB_DATAREP_H +#define __KHIMAIRA_KRB_DATAREP_H + + +khm_int32 KHMAPI enctype_toString(const void * data, khm_int32 cbdata, wchar_t *destbuf, khm_int32 *pcbdestbuf, khm_int32 flags); +khm_int32 KHMAPI addr_list_toString(const void *, khm_int32, wchar_t *, khm_int32 *, khm_int32); +khm_int32 KHMAPI krb5flags_toString(const void *, khm_int32, wchar_t *, khm_int32 *, khm_int32); +khm_int32 KHMAPI renew_for_cb(khm_handle cred, khm_int32 id, void * buffer, khm_int32 * pcbsize); + + +#endif \ No newline at end of file diff --git a/src/windows/identity/plugins/krb4/errorfuncs.c b/src/windows/identity/plugins/krb4/errorfuncs.c new file mode 100644 index 0000000000..9feaad2a70 --- /dev/null +++ b/src/windows/identity/plugins/krb4/errorfuncs.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +extern void (__cdecl *pinitialize_krb_error_func)(); +extern void (__cdecl *pinitialize_kadm_error_table)(); + + +khm_int32 init_error_funcs() +{ + +#if 0 + /*TODO: Do something about this */ + if (plsh_LoadKrb4LeashErrorTables) + plsh_LoadKrb4LeashErrorTables(hLeashInst, 0); +#endif + return KHM_ERROR_SUCCESS; +} + +khm_int32 exit_error_funcs() +{ + return KHM_ERROR_SUCCESS; +} + +// Global Variables. +static long lsh_errno; +static char *err_context; /* error context */ +extern int (*Lcom_err)(LPSTR,long,LPSTR,...); +extern LPSTR (*Lerror_message)(long); +extern LPSTR (*Lerror_table_name)(long); + +#ifdef WIN16 +#define UNDERSCORE "_" +#else +#define UNDERSCORE +#endif + +HWND GetRootParent (HWND Child) +{ + HWND Last; + while (Child) + { + Last = Child; + Child = GetParent (Child); + } + return Last; +} + + +LPSTR err_describe(LPSTR buf, long code) +{ + LPSTR cp, com_err_msg; + int offset; + long table_num; + char *etype; + + offset = (int) (code & 255); + table_num = code - offset; + com_err_msg = Lerror_message(code); + + switch(table_num) + { + case krb_err_base: + case kadm_err_base: + break; + default: + strcpy(buf, com_err_msg); + return buf; + } + + cp = buf; + if (table_num == krb_err_base) + switch(offset) + { + case KDC_NAME_EXP: /* 001 Principal expired */ + case KDC_SERVICE_EXP: /* 002 Service expired */ + case KDC_AUTH_EXP: /* 003 Auth expired */ + case KDC_PKT_VER: /* 004 Protocol version unknown */ + case KDC_P_MKEY_VER: /* 005 Wrong master key version */ + case KDC_S_MKEY_VER: /* 006 Wrong master key version */ + case KDC_BYTE_ORDER: /* 007 Byte order unknown */ + case KDC_PR_N_UNIQUE: /* 009 Principal not unique */ + case KDC_NULL_KEY: /* 010 Principal has null key */ + case KDC_GEN_ERR: /* 011 Generic error from KDC */ + case INTK_W_NOTALL : /* 061 Not ALL tickets returned */ + case INTK_PROT : /* 063 Protocol Error */ + case INTK_ERR : /* 070 Other error */ + com_err_msg = "Something weird happened... try again, and if Leash" + " continues to fail, contact Network Services as listed in the " + "About box."; + break; + case KDC_PR_UNKNOWN: /* 008 Principal unknown */ + com_err_msg = "You have entered an unknown username/instance/realm" + " combination."; + break; + case GC_TKFIL : /* 021 Can't read ticket file */ + case GC_NOTKT : /* 022 Can't find ticket or TGT */ + com_err_msg = "Something is wrong with the memory where your " + "tickets are stored. Try exiting Windows and restarting your " + "computer."; + break; + case MK_AP_TGTEXP : /* 026 TGT Expired */ + /* no extra error msg */ + break; + case RD_AP_TIME : /* 037 delta_t too big */ + com_err_msg = "Your computer's clock is out of sync with the " + "Kerberos server. Please see the help file about correcting " + "your clock."; + break; + + case RD_AP_UNDEC : /* 031 Can't decode authenticator */ + case RD_AP_EXP : /* 032 Ticket expired */ + case RD_AP_NYV : /* 033 Ticket not yet valid */ + case RD_AP_REPEAT : /* 034 Repeated request */ + case RD_AP_NOT_US : /* 035 The ticket isn't for us */ + case RD_AP_INCON : /* 036 Request is inconsistent */ + case RD_AP_BADD : /* 038 Incorrect net address */ + case RD_AP_VERSION : /* 039 protocol version mismatch */ + case RD_AP_MSG_TYPE : /* 040 invalid msg type */ + case RD_AP_MODIFIED : /* 041 message stream modified */ + case RD_AP_ORDER : /* 042 message out of order */ + case RD_AP_UNAUTHOR : /* 043 unauthorized request */ + /* no extra error msg */ + break; + case GT_PW_NULL: /* 51 Current PW is null */ + case GT_PW_BADPW: /* 52 Incorrect current password */ + case GT_PW_PROT: /* 53 Protocol Error */ + case GT_PW_KDCERR: /* 54 Error returned by KDC */ + case GT_PW_NULLTKT: /* 55 Null tkt returned by KDC */ + /* no error msg yet */ + break; + + /* Values returned by send_to_kdc */ + case SKDC_RETRY : /* 56 Retry count exceeded */ + case SKDC_CANT : /* 57 Can't send request */ + com_err_msg = "Cannot contact the kerberos server for the selected realm."; + break; + /* no error message on purpose: */ + case INTK_BADPW : /* 062 Incorrect password */ + break; + default: + /* no extra error msg */ + break; + } + else + switch(code) + { + case KADM_INSECURE_PW: + /* if( kadm_info != NULL ){ + * wsprintf(buf, "%s\n%s", com_err_msg, kadm_info); + * } else { + * wsprintf(buf, "%s\nPlease see the help file for information " + * "about secure passwords.", com_err_msg); + * } + * com_err_msg = buf; + */ + + /* The above code would be preferred since it allows site specific + * information to be delivered from the Kerberos server. However the + * message box is too small for VGA screens. + * It does work well if we only have to support 1024x768 + */ + + com_err_msg = "You have entered an insecure or weak password."; + + default: + /* no extra error msg */ + break; + } + if(com_err_msg != buf) + strcpy(buf, com_err_msg); + cp = buf + strlen(buf); + *cp++ = '\n'; + switch(table_num) { + case krb_err_base: + etype = "Kerberos"; + break; + case kadm_err_base: + etype = "Kerberos supplemental"; + break; + default: + etype = Lerror_table_name(table_num); + break; + } + wsprintfA((LPSTR) cp, (LPSTR) "(%s error %d" +#ifdef DEBUG_COM_ERR + " (absolute error %ld)" +#endif + ")", etype, offset + //")\nPress F1 for help on this error.", etype, offset +#ifdef DEBUG_COM_ERR + , code +#endif + ); + + return (LPSTR)buf; +} + +int lsh_com_err_proc (LPSTR whoami, long code, + LPSTR fmt, va_list args) +{ + int retval; + HWND hOldFocus; + char buf[1024], *cp; /* changed to 512 by jms 8/23/93 */ + WORD mbformat = MB_OK | MB_ICONEXCLAMATION; + + cp = buf; + memset(buf, '\0', sizeof(buf)); + cp[0] = '\0'; + + if (code) + { + err_describe(buf, code); + while (*cp) + cp++; + } + + if (fmt) + { + if (fmt[0] == '%' && fmt[1] == 'b') + { + fmt += 2; + mbformat = va_arg(args, WORD); + /* if the first arg is a %b, we use it for the message + box MB_??? flags. */ + } + if (code) + { + *cp++ = '\n'; + *cp++ = '\n'; + } + wvsprintfA((LPSTR)cp, fmt, args); + } + hOldFocus = GetFocus(); + retval = MessageBoxA(/*GetRootParent(hOldFocus)*/NULL, buf, whoami, + mbformat | MB_ICONHAND | MB_TASKMODAL); + SetFocus(hOldFocus); + return retval; +} diff --git a/src/windows/identity/plugins/krb4/errorfuncs.h b/src/windows/identity/plugins/krb4/errorfuncs.h new file mode 100644 index 0000000000..be8f4e7c57 --- /dev/null +++ b/src/windows/identity/plugins/krb4/errorfuncs.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_ERR_H +#define __KHIMAIRA_ERR_H + +/* All error handling and reporting related functions for the krb4/5 + and AFS plugins */ + +#include +#include +/* + * This is a hack needed because the real com_err.h does + * not define err_func. We need it in the case where + * we pull in the real com_err instead of the krb4 + * impostor. + */ +#ifndef _DCNS_MIT_COM_ERR_H +typedef LPSTR (*err_func)(int, long); +#endif + +#include +extern void Leash_initialize_krb_error_func(err_func func,struct et_list **); +#undef init_krb_err_func +#define init_krb_err_func(erf) Leash_initialize_krb_error_func(erf,&_et_list) + +#include + +extern void Leash_initialize_kadm_error_table(struct et_list **); +#undef init_kadm_err_tbl +#define init_kadm_err_tbl() Leash_initialize_kadm_error_table(&_et_list) +#define kadm_err_base ERROR_TABLE_BASE_kadm + +#define krb_err_func Leash_krb_err_func + +#include +int lsh_com_err_proc (LPSTR whoami, long code, + LPSTR fmt, va_list args); +void FAR Leash_load_com_err_callback(FARPROC,FARPROC,FARPROC); + +#ifndef KRBERR +#define KRBERR(code) (code + krb_err_base) +#endif + +int lsh_com_err_proc (LPSTR whoami, long code, LPSTR fmt, va_list args); +int DoNiftyErrorReport(long errnum, LPSTR what); + +LPSTR err_describe(LPSTR buf, long code); + + +/* */ +khm_int32 init_error_funcs(); + +khm_int32 exit_error_funcs(); + + +#endif diff --git a/src/windows/identity/plugins/krb4/krb4configdlg.c b/src/windows/identity/plugins/krb4/krb4configdlg.c new file mode 100644 index 0000000000..9ad3406980 --- /dev/null +++ b/src/windows/identity/plugins/krb4/krb4configdlg.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include + +INT_PTR CALLBACK +krb4_confg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + { + wchar_t wbuf[MAX_PATH]; + CHAR krb_path[MAX_PATH]; + CHAR krbrealm_path[MAX_PATH]; + CHAR ticketName[MAX_PATH]; + char * pticketName; + unsigned int krb_path_sz = sizeof(krb_path); + unsigned int krbrealm_path_sz = sizeof(krbrealm_path); + + // Set KRB.CON + memset(krb_path, '\0', sizeof(krb_path)); + if (!pkrb_get_krbconf2(krb_path, &krb_path_sz)) { + // Error has happened + } else { // normal find + AnsiStrToUnicode(wbuf, sizeof(wbuf), krb_path); + SetDlgItemText(hwnd, IDC_CFG_CFGPATH, wbuf); + } + + // Set KRBREALM.CON + memset(krbrealm_path, '\0', sizeof(krbrealm_path)); + if (!pkrb_get_krbrealm2(krbrealm_path, &krbrealm_path_sz)) { + // Error has happened + } else { + AnsiStrToUnicode(wbuf, sizeof(wbuf), krbrealm_path); + SetDlgItemText(hwnd, IDC_CFG_RLMPATH, wbuf); + } + + // Set TICKET.KRB file Editbox + *ticketName = 0; + pkrb_set_tkt_string(0); + + pticketName = ptkt_string(); + if (pticketName) + StringCbCopyA(ticketName, sizeof(ticketName), pticketName); + + if (!*ticketName) { + // error + } else { + AnsiStrToUnicode(wbuf, sizeof(wbuf), ticketName); + SetDlgItemText(hwnd, IDC_CFG_CACHE, wbuf); + } + } + break; + + case WM_DESTROY: + break; + } + return FALSE; +} diff --git a/src/windows/identity/plugins/krb4/krb4funcs.c b/src/windows/identity/plugins/krb4/krb4funcs.c new file mode 100644 index 0000000000..8fda720b3a --- /dev/null +++ b/src/windows/identity/plugins/krb4/krb4funcs.c @@ -0,0 +1,505 @@ +/* +* Copyright (c) 2004 Massachusetts Institute of Technology +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* $Id$ */ + +/* Originally this was krb5routines.c in Leash sources. Subsequently +modified and adapted for NetIDMgr */ + +#include +#include + +#define SECURITY_WIN32 +#include +#include + +#include +#include +#include +#include + + + +int com_addr(void) +{ + long ipAddr; + char loc_addr[ADDR_SZ]; + CREDENTIALS cred; + char service[40]; + char instance[40]; + // char addr[40]; + char realm[40]; + struct in_addr LocAddr; + int k_errno; + + if (pkrb_get_cred == NULL) + return(KSUCCESS); + + k_errno = (*pkrb_get_cred)(service,instance,realm,&cred); + if (k_errno) + return KRBERR(k_errno); + + while(1) { + ipAddr = (*pLocalHostAddr)(); + LocAddr.s_addr = ipAddr; + StringCbCopyA(loc_addr, sizeof(loc_addr), inet_ntoa(LocAddr)); + if ( strcmp(cred.address,loc_addr) != 0) { + /* TODO: do something about this */ + //Leash_kdestroy (); + break; + } + break; + } // while() + return 0; +} + + +long +khm_krb4_list_tickets(void) +{ + char pname[ANAME_SZ]; + char pinst[INST_SZ]; + char prealm[REALM_SZ]; + wchar_t wbuf[256]; + int k_errno; + CREDENTIALS c; + int newtickets = 0; + int open = 0; + khm_handle ident = NULL; + khm_handle cred = NULL; + time_t tt; + FILETIME ft; + + // Since krb_get_tf_realm will return a ticket_file error, + // we will call tf_init and tf_close first to filter out + // things like no ticket file. Otherwise, the error that + // the user would see would be + // klist: can't find realm of ticket file: No ticket file (tf_util) + // instead of klist: No ticket file (tf_util) + if (ptf_init == NULL) + return(KSUCCESS); + + com_addr(); + + // Open ticket file + if ((k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL))) + { + goto cleanup; + } + // Close ticket file + (void) (*ptf_close)(); + + // We must find the realm of the ticket file here before calling + // tf_init because since the realm of the ticket file is not + // really stored in the principal section of the file, the + // routine we use must itself call tf_init and tf_close. + + if ((k_errno = (*pkrb_get_tf_realm)((*ptkt_string)(), prealm)) != KSUCCESS) + { + goto cleanup; + } + + // Open ticket file + if (k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL)) + { + goto cleanup; + } + + open = 1; + + // Get principal name and instance + if ((k_errno = (*ptf_get_pname)(pname)) || (k_errno = (*ptf_get_pinst)(pinst))) + { + goto cleanup; + } + + // You may think that this is the obvious place to get the + // realm of the ticket file, but it can't be done here as the + // routine to do this must open the ticket file. This is why + // it was done before tf_init. + StringCbPrintf(wbuf, sizeof(wbuf), L"%S%S%S%S%S", (LPSTR)pname, + (LPSTR)(pinst[0] ? "." : ""), (LPSTR)pinst, + (LPSTR)(prealm[0] ? "@" : ""), (LPSTR)prealm); + + if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, &ident))) + { + goto cleanup; + } + + kcdb_credset_flush(krb4_credset); + + // Get KRB4 tickets + while ((k_errno = (*ptf_get_cred)(&c)) == KSUCCESS) + { + StringCbPrintf(wbuf, sizeof(wbuf), L"%S%S%S%S%S", + c.service, + (c.instance[0] ? "." : ""), + c.instance, + (c.realm[0] ? "@" : ""), + c.realm); + + if(KHM_FAILED(kcdb_cred_create(wbuf, ident, credtype_id_krb4, &cred))) + continue; + + tt = c.issue_date + c.lifetime * 5L * 60L; + TimetToFileTime(tt, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &ft, sizeof(ft)); + + tt = c.issue_date; + TimetToFileTime(tt, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft)); + + tt = c.lifetime * 5L * 60L; + TimetToFileTimeInterval(tt, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_LIFETIME, &ft, sizeof(ft)); + + kcdb_credset_add_cred(krb4_credset, cred, -1); + + } // while + + kcdb_credset_collect(NULL, krb4_credset, ident, credtype_id_krb4, NULL); + +cleanup: + if (ptf_close == NULL) + return(KSUCCESS); + + if (open) + (*ptf_close)(); //close ticket file + + if (k_errno == EOF) + k_errno = 0; + + // XXX the if statement directly below was inserted to eliminate + // an error NO_TKT_FIL on Leash startup. The error occurs from an + // error number thrown from krb_get_tf_realm. We believe this + // change does not eliminate other errors, but it may. + + if (k_errno == NO_TKT_FIL) + k_errno = 0; + + if(ident) + kcdb_identity_release(ident); + +#if 0 + /*TODO: Handle errors here */ + if (k_errno) + { + CHAR message[256]; + CHAR errBuf[256]; + LPCSTR errText; + + if (!Lerror_message) + return -1; + + errText = err_describe(errBuf, KRBERR(k_errno)); + + sprintf(message, "%s\n\n%s failed", errText, functionName); + MessageBox(NULL, message, "Kerberos Four", + MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND); + } +#endif + return k_errno; +} + +#define KRB_FILE "KRB.CON" +#define KRBREALM_FILE "KRBREALM.CON" +#define KRB5_FILE "KRB5.INI" + +BOOL +khm_get_profile_file(LPSTR confname, UINT szConfname) +{ + char **configFile = NULL; + if (pkrb5_get_default_config_files(&configFile)) + { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + return FALSE; + } + + *confname = 0; + + if (configFile) + { + strncpy(confname, *configFile, szConfname); + pkrb5_free_config_files(configFile); + } + + if (!*confname) + { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + } + + return FALSE; +} + +BOOL +khm_get_krb4_con_file(LPSTR confname, UINT szConfname) +{ + if (hKrb5 && !hKrb4) + { // hold krb.con where krb5.ini is located + CHAR krbConFile[MAX_PATH]=""; + LPSTR pFind; + + //strcpy(krbConFile, CLeashApp::m_krbv5_profile->first_file->filename); + if (khm_get_profile_file(krbConFile, sizeof(krbConFile))) + { + GetWindowsDirectoryA(krbConFile,sizeof(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, KRB5_FILE,sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + } + + pFind = strrchr(krbConFile, '\\'); + if (pFind) + { + *pFind = 0; + strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, KRB_FILE,sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + } + else + krbConFile[0] = 0; + + strncpy(confname, krbConFile, szConfname); + confname[szConfname-1] = '\0'; + } + else if (hKrb4) + { + unsigned int size = szConfname; + memset(confname, '\0', szConfname); + if (!pkrb_get_krbconf2(confname, &size)) + { // Error has happened + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",szConfname-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname,KRB_FILE,szConfname-strlen(confname)); + confname[szConfname-1] = '\0'; + } + } + return FALSE; +} + +int +readstring(FILE * file, char * buf, int len) +{ + int c,i; + memset(buf, '\0', sizeof(buf)); + for (i=0, c=fgetc(file); c != EOF ; c=fgetc(file), i++) + { + if (i < sizeof(buf)) { + if (c == '\n') { + buf[i] = '\0'; + return i; + } else { + buf[i] = c; + } + } else { + if (c == '\n') { + buf[len-1] = '\0'; + return(i); + } + } + } + if (c == EOF) { + if (i > 0 && i < len) { + buf[i] = '\0'; + return(i); + } else { + buf[len-1] = '\0'; + return(-1); + } + } + return(-1); +} + +/*! \internal + \brief Return a list of configured realms + + The string that is returned is a set of null terminated unicode strings, + each of which denotes one realm. The set is terminated by a zero length + null terminated string. + + The caller should free the returned string using free() + + \return The string with the list of realms or NULL if the operation fails. +*/ +wchar_t * khm_krb5_get_realm_list(void) +{ + wchar_t * rlist = NULL; + + if (pprofile_get_subsection_names && pprofile_free_list) { + const char* rootSection[] = {"realms", NULL}; + const char** rootsec = rootSection; + char **sections = NULL, **cpp = NULL, *value = NULL; + + char krb5_conf[MAX_PATH+1]; + + if (!khm_get_profile_file(krb5_conf,sizeof(krb5_conf))) { + profile_t profile; + long retval; + const char *filenames[2]; + wchar_t * d; + size_t cbsize; + size_t t; + + filenames[0] = krb5_conf; + filenames[1] = NULL; + retval = pprofile_init(filenames, &profile); + if (!retval) { + retval = pprofile_get_subsection_names(profile, rootsec, §ions); + + if (!retval) + { + /* first figure out how much space to allocate */ + cbsize = 0; + for (cpp = sections; *cpp; cpp++) + { + cbsize += sizeof(wchar_t) * (strlen(*cpp) + 1); + } + cbsize += sizeof(wchar_t); /* double null terminated */ + + rlist = malloc(cbsize); + d = rlist; + for (cpp = sections; *cpp; cpp++) + { + AnsiStrToUnicode(d, cbsize, *cpp); + t = wcslen(d) + 1; + d += t; + cbsize -= sizeof(wchar_t) * t; + } + *d = L'\0'; + } + + pprofile_free_list(sections); + +#if 0 + retval = pprofile_get_string(profile, "libdefaults","noaddresses", 0, "true", &value); + if ( value ) { + disable_noaddresses = config_boolean_to_int(value); + pprofile_release_string(value); + } +#endif + pprofile_release(profile); + } + } + } else { + FILE * file; + char krb_conf[MAX_PATH+1]; + char * p; + size_t cbsize, t; + wchar_t * d; + + if (!khm_get_krb4_con_file(krb_conf,sizeof(krb_conf)) && + (file = fopen(krb_conf, "rt"))) + { + char lineBuf[256]; + + /*TODO: compute the actual required buffer size instead of hardcoding */ + cbsize = 16384; // arbitrary + rlist = malloc(cbsize); + d = rlist; + + // Skip the default realm + readstring(file,lineBuf,sizeof(lineBuf)); + + // Read the defined realms + while (TRUE) + { + if (readstring(file,lineBuf,sizeof(lineBuf)) < 0) + break; + + if (*(lineBuf + strlen(lineBuf) - 1) == '\r') + *(lineBuf + strlen(lineBuf) - 1) = 0; + + for (p=lineBuf; *p ; p++) + { + if (isspace(*p)) { + *p = 0; + break; + } + } + + if ( strncmp(".KERBEROS.OPTION.",lineBuf,17) ) { + t = strlen(lineBuf) + 1; + if(cbsize > (1 + t*sizeof(wchar_t))) { + AnsiStrToUnicode(d, cbsize, lineBuf); + d += t; + cbsize -= t * sizeof(wchar_t); + } else + break; + } + } + + *d = L'\0'; + + fclose(file); + } + } + + return rlist; +} + +/*! \internal + \brief Get the default realm + + A string will be returned that specifies the default realm. The caller + should free the string using free(). + + Returns NULL if the operation fails. +*/ +wchar_t * khm_krb5_get_default_realm(void) +{ + wchar_t * realm; + size_t cch; + krb5_context ctx=0; + char * def = 0; + + pkrb5_init_context(&ctx); + pkrb5_get_default_realm(ctx,&def); + + if (def) { + cch = strlen(def) + 1; + realm = malloc(sizeof(wchar_t) * cch); + AnsiStrToUnicode(realm, sizeof(wchar_t) * cch, def); + pkrb5_free_default_realm(ctx, def); + } else + realm = NULL; + + pkrb5_free_context(ctx); + + return realm; +} diff --git a/src/windows/identity/plugins/krb4/krb4funcs.h b/src/windows/identity/plugins/krb4/krb4funcs.h new file mode 100644 index 0000000000..ea97358b9f --- /dev/null +++ b/src/windows/identity/plugins/krb4/krb4funcs.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* Adapted from multiple Leash header files */ + +#ifndef __KHIMAIRA_KRB5FUNCS_H +#define __KHIMAIRA_KRB5FUNCS_H + +#include +#include + +#include +#define SECURITY_WIN32 +#include +#include + +#include + +#define LEASH_DEBUG_CLASS_GENERIC 0 +#define LEASH_DEBUG_CLASS_KRB4 1 +#define LEASH_DEBUG_CLASS_KRB4_APP 2 + +#define LEASH_PRIORITY_LOW 0 +#define LEASH_PRIORITY_HIGH 1 + +#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ + +// Function Prototypes. +BOOL khm_krb5_ms2mit(BOOL); + +int +khm_krb5_kinit(krb5_context alt_ctx, + char * principal_name, + char * password, + krb5_deltat lifetime, + DWORD forwardable, + DWORD proxiable, + krb5_deltat renew_life, + DWORD addressless, + DWORD publicIP, + krb5_prompter_fct prompter, + void * p_data + ); + +long +Leash_int_kinit_ex( + krb5_context ctx, + HWND hParent, + char * principal, + char * password, + int lifetime, + int forwardable, + int proxiable, + int renew_life, + int addressless, + unsigned long publicIP, + int displayErrors + ); + +long +Leash_int_checkpwd( + char * principal, + char * password, + int displayErrors + ); + +long +Leash_int_changepwd( + char * principal, + char * password, + char * newpassword, + char** result_string, + int displayErrors + ); + +int +Leash_krb5_kdestroy( + void + ); + +int +Leash_krb5_kinit( + krb5_context, + HWND hParent, + char * principal_name, + char * password, + krb5_deltat lifetime, + DWORD forwardable, + DWORD proxiable, + krb5_deltat renew_life, + DWORD addressless, + DWORD publicIP + ); + +long +khm_convert524( + krb5_context ctx + ); + +int +Leash_afs_unlog( + void + ); + +int +Leash_afs_klog( + char *, + char *, + char *, + int + ); + +int +LeashKRB5_renew(void); + +LONG +write_registry_setting( + char* setting, + DWORD type, + void* buffer, + size_t size + ); + +LONG +read_registry_setting_user( + char* setting, + void* buffer, + size_t size + ); + +LONG +read_registry_setting( + char* setting, + void* buffer, + size_t size + ); + +BOOL +get_STRING_from_registry( + HKEY hBaseKey, + char * key, + char * value, + char * outbuf, + DWORD outlen + ); + +BOOL +get_DWORD_from_registry( + HKEY hBaseKey, + char * key, + char * value, + DWORD * result + ); + +int +config_boolean_to_int( + const char *s + ); + + +wchar_t * khm_krb5_get_default_realm(void); +wchar_t * khm_krb5_get_realm_list(void); +long khm_krb5_list_tickets(krb5_context *krbv5Context); +long khm_krb4_list_tickets(void); + + +#endif diff --git a/src/windows/identity/plugins/krb4/krb4plugin.c b/src/windows/identity/plugins/krb4/krb4plugin.c new file mode 100644 index 0000000000..106febac00 --- /dev/null +++ b/src/windows/identity/plugins/krb4/krb4plugin.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include +#include + +khm_int32 credtype_id_krb4 = KCDB_CREDTYPE_INVALID; +khm_boolean krb4_initialized = FALSE; +khm_handle krb4_credset = NULL; + +/* Kerberos IV stuff */ +khm_int32 KHMAPI +krb4_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_SYSTEM_INIT: + { + kcdb_credtype ct; + wchar_t buf[KCDB_MAXCCH_SHORT_DESC]; + size_t cbsize; + khui_config_node_reg reg; + wchar_t wshort_desc[KHUI_MAXCCH_SHORT_DESC]; + wchar_t wlong_desc[KHUI_MAXCCH_LONG_DESC]; + + /* perform critical registrations and initialization + stuff */ + ZeroMemory(&ct, sizeof(ct)); + ct.id = KCDB_CREDTYPE_AUTO; + ct.name = KRB4_CREDTYPE_NAME; + + if(LoadString(hResModule, IDS_KRB4_SHORT_DESC, + buf, ARRAYLENGTH(buf))) + { + StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); + cbsize += sizeof(wchar_t); + ct.short_desc = malloc(cbsize); + StringCbCopy(ct.short_desc, cbsize, buf); + } + + /* even though ideally we should be setting limits + based KCDB_MAXCB_LONG_DESC, our long description + actually fits nicely in KCDB_MAXCB_SHORT_DESC */ + if(LoadString(hResModule, IDS_KRB4_LONG_DESC, + buf, ARRAYLENGTH(buf))) + { + StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); + cbsize += sizeof(wchar_t); + ct.long_desc = malloc(cbsize); + StringCbCopy(ct.long_desc, cbsize, buf); + } + + ct.icon = NULL; /* TODO: set a proper icon */ + kmq_create_subscription(krb4_cb, &ct.sub); + + rv = kcdb_credtype_register(&ct, &credtype_id_krb4); + + if(KHM_SUCCEEDED(rv)) + rv = kcdb_credset_create(&krb4_credset); + + if(ct.short_desc) + free(ct.short_desc); + + if(ct.long_desc) + free(ct.long_desc); + + ZeroMemory(®, sizeof(reg)); + + reg.name = KRB4_CONFIG_NODE_NAME; + reg.short_desc = wshort_desc; + reg.long_desc = wlong_desc; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_KRB4); + reg.dlg_proc = krb4_confg_proc; + reg.flags = 0; + + LoadString(hResModule, IDS_CFG_KRB4_LONG, + wlong_desc, ARRAYLENGTH(wlong_desc)); + LoadString(hResModule, IDS_CFG_KRB4_SHORT, + wshort_desc, ARRAYLENGTH(wshort_desc)); + + khui_cfg_register(NULL, ®); + + if(KHM_SUCCEEDED(rv)) { + krb4_initialized = TRUE; + + khm_krb4_list_tickets(); + } + } + break; + + case KMSG_SYSTEM_EXIT: + if(credtype_id_krb4 >= 0) + { + /* basically just unregister the credential type */ + kcdb_credtype_unregister(credtype_id_krb4); + + kcdb_credset_delete(krb4_credset); + } + break; + } + + return rv; +} + +khm_int32 KHMAPI +krb4_msg_cred(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_CRED_REFRESH: + { + khm_krb4_list_tickets(); + } + break; + } + + return rv; +} + +khm_int32 KHMAPI +krb4_cb(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + switch(msg_type) { + case KMSG_SYSTEM: + return krb4_msg_system(msg_type, msg_subtype, uparam, vparam); + case KMSG_CRED: + return krb4_msg_cred(msg_type, msg_subtype, uparam, vparam); + } + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/plugins/krb4/krbconfig.csv b/src/windows/identity/plugins/krb4/krbconfig.csv new file mode 100644 index 0000000000..bed0d1ccb9 --- /dev/null +++ b/src/windows/identity/plugins/krb4/krbconfig.csv @@ -0,0 +1,23 @@ +Name,Type,Value,Description +Krb4Cred,KC_SPACE,0,"Kerberos IV Credentials Provider" + Module,KC_STRING,"MITKrb4", + Description,KC_STRING,"Kerberos IV Credentials Provider", + Dependencies,KC_STRING,Krb5Cred, + Type,KC_INT32,1, + Flags,KC_INT32,0, + Parameters,KC_SPACE,0,Parameters for KrbCred + CreateMissingConfig,KC_INT32,0,Create missing configuration files + MsLsaImport,KC_INT32,2,Automatically import MSLSA credentials + AutoRenewTickets,KC_INT32,1,Automatically renew expiring tickets + DefaultLifetime,KC_INT32,36000,Default ticket lifetime + MaxLifetime,KC_INT32,86400,Maximum lifetime + MinLifetime,KC_INT32,60,Minimum lifetime + Forwardable,KC_INT32,1,Obtain forwardable tickets (boolean) + Proxiable,KC_INT32,0,Obtain proxiable tickets (boolean) + Addressless,KC_INT32,1,Obtain addressless tickets (boolean) + Renewable,KC_INT32,1,Obtain renewable tickets (boolean) + DefaultRenewLifetime,KC_INT32,604800,Default renewable lifetime + MaxRenewLifetime,KC_INT32,2592000,Maximum renewable lifetime + MinRenewLifetime,KC_INT32,60,Maximum renewable lifetime + Parameters,KC_ENDSPACE,0, +Krb4Cred,KC_ENDSPACE,0, diff --git a/src/windows/identity/plugins/krb4/krbcred.h b/src/windows/identity/plugins/krb4/krbcred.h new file mode 100644 index 0000000000..e56d114ee9 --- /dev/null +++ b/src/windows/identity/plugins/krb4/krbcred.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KRBAFSCRED_H +#define __KHIMAIRA_KRBAFSCRED_H + +#include + +#include +#include +#include +#include + + +#include +#include +#include +#include + +#include +#include + +#define TYPENAME_ENCTYPE L"EncType" +#define TYPENAME_ADDR_LIST L"AddrList" +#define TYPENAME_KRB5_FLAGS L"Krb5Flags" + +#define ATTRNAME_KEY_ENCTYPE L"KeyEncType" +#define ATTRNAME_TKT_ENCTYPE L"TktEncType" +#define ATTRNAME_ADDR_LIST L"AddrList" +#define ATTRNAME_KRB5_FLAGS L"Krb5Flags" +#define ATTRNAME_RENEW_TILL L"RenewTill" +#define ATTRNAME_RENEW_FOR L"RenewFor" + +void init_krb(); +void exit_krb(); +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module); +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module); + +/* globals */ +extern kmm_module h_khModule; +extern HMODULE hResModule; +extern HINSTANCE hInstance; + +extern khm_int32 type_id_enctype; +extern khm_int32 type_id_addr_list; +extern khm_int32 type_id_krb5_flags; + +extern khm_int32 attr_id_key_enctype; +extern khm_int32 attr_id_tkt_enctype; +extern khm_int32 attr_id_addr_list; +extern khm_int32 attr_id_krb5_flags; +extern khm_int32 attr_id_renew_till; +extern khm_int32 attr_id_renew_for; + +/* Configuration spaces */ +#define CSNAME_KRB4CRED L"Krb4Cred" +#define CSNAME_PARAMS L"Parameters" + +/* plugin constants */ +#define KRB4_PLUGIN_NAME L"Krb4Cred" + +#define KRB4_PLUGIN_DEPS L"Krb5Cred\0" + +#define KRB4_CREDTYPE_NAME L"Krb4Cred" + +#define KRB4_CONFIG_NODE_NAME L"Krb4Config" + +extern khm_handle csp_plugins; +extern khm_handle csp_krbcred; +extern khm_handle csp_params; + +extern kconf_schema schema_krbconfig[]; + +/* other globals */ +extern khm_int32 credtype_id_krb4; + +extern khm_boolean krb4_initialized; + +extern khm_handle krb4_credset; + +/* plugin callbacks */ +khm_int32 KHMAPI +krb4_cb(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam); + +INT_PTR CALLBACK +krb4_confg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); +#endif diff --git a/src/windows/identity/plugins/krb4/lang/en_us/langres.rc b/src/windows/identity/plugins/krb4/lang/en_us/langres.rc new file mode 100644 index 0000000000..a5d62a26a4 --- /dev/null +++ b/src/windows/identity/plugins/krb4/lang/en_us/langres.rc @@ -0,0 +1,141 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\..\langres.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\..\\langres.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_NC_KRB4 DIALOGEX 0, 0, 300, 166 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "kRB4",IDC_STATIC,38,43,71,24 +END + +IDD_CFG_KRB4 DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Ticket cache location",IDC_CFG_LBL_CACHE,7,10,67,8 + EDITTEXT IDC_CFG_CACHE,83,7,165,14,ES_AUTOHSCROLL + LTEXT "Config file path",IDC_CFG_LBL_CFGFILE,7,30,50,8 + EDITTEXT IDC_CFG_CFGPATH,83,27,113,14,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_CFG_CFGBROW,200,27,48,14 + LTEXT "Realm file path",IDC_CFG_LBL_RLMPATH,7,50,48,8 + EDITTEXT IDC_CFG_RLMPATH,83,47,113,14,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_CFG_RLMBROW,200,47,48,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_NC_KRB4, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 159 + END + + IDD_CFG_KRB4, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 83 + VERTGUIDE, 196 + VERTGUIDE, 200 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_PLUGIN_DESC "Kerberos 4 Credentials Provider" +END + +STRINGTABLE +BEGIN + IDS_KRB4_SHORT_DESC "Kerberos 4 tickets" + IDS_KRB4_LONG_DESC "Kerberos 4 tickets" + IDS_CFG_KRB4_LONG "Kerberos 4 Configuration" + IDS_CFG_KRB4_SHORT "Kerberos 4" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/windows/identity/plugins/krb4/langres.h b/src/windows/identity/plugins/krb4/langres.h new file mode 100644 index 0000000000..2096adec3b --- /dev/null +++ b/src/windows/identity/plugins/krb4/langres.h @@ -0,0 +1,78 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by D:\work\khimaira\src\plugins\krb4\lang\en_us\langres.rc +// +#define IDS_UNK_ADDR_FMT 101 +#define IDS_KRB5_CREDTEXT_0 102 +#define IDD_NC_KRB4 103 +#define IDS_PLUGIN_DESC 103 +#define IDS_KEY_ENCTYPE_SHORT_DESC 104 +#define IDD_CFG_KRB4 104 +#define IDS_TKT_ENCTYPE_SHORT_DESC 105 +#define IDS_KEY_ENCTYPE_LONG_DESC 106 +#define IDS_TKT_ENCTYPE_LONG_DESC 107 +#define IDS_ADDR_LIST_SHORT_DESC 108 +#define IDS_ADDR_LIST_LONG_DESC 109 +#define IDS_ETYPE_NULL 110 +#define IDS_ETYPE_DES_CBC_CRC 111 +#define IDS_ETYPE_DES_CBC_MD4 112 +#define IDS_ETYPE_DES_CBC_MD5 113 +#define IDS_ETYPE_DES_CBC_RAW 114 +#define IDS_ETYPE_DES3_CBC_SHA 115 +#define IDS_ETYPE_DES3_CBC_RAW 116 +#define IDS_ETYPE_DES_HMAC_SHA1 117 +#define IDS_ETYPE_DES3_CBC_SHA1 118 +#define IDS_ETYPE_AES128_CTS_HMAC_SHA1_96 119 +#define IDS_ETYPE_AES256_CTS_HMAC_SHA1_96 120 +#define IDS_ETYPE_ARCFOUR_HMAC 121 +#define IDS_ETYPE_ARCFOUR_HMAC_EXP 122 +#define IDS_ETYPE_UNKNOWN 123 +#define IDS_ETYPE_LOCAL_DES3_HMAC_SHA1 124 +#define IDS_ETYPE_LOCAL_RC4_MD4 125 +#define IDS_KRB5_SHORT_DESC 126 +#define IDS_KRB5_LONG_DESC 127 +#define IDS_KRB4_SHORT_DESC 128 +#define IDS_KRB4_LONG_DESC 129 +#define IDS_KRB5_FLAGS_SHORT_DESC 130 +#define IDS_RENEW_TILL_SHORT_DESC 131 +#define IDS_RENEW_TILL_LONG_DESC 132 +#define IDS_RENEW_FOR_SHORT_DESC 133 +#define IDS_RENEW_FOR_LONG_DESC 134 +#define IDS_CFG_KRB4_LONG 135 +#define IDS_CFG_KRB4_SHORT 136 +#define IDC_NCK5_RENEWABLE 1002 +#define IDC_NCK5_FORWARDABLE 1004 +#define IDC_NCK5_REALM 1005 +#define IDC_NCK5_ADD_REALMS 1006 +#define IDC_NCK5_LIFETIME_EDIT 1008 +#define IDC_NCK5_RENEW_EDIT 1009 +#define IDC_PPK5_CRENEW 1014 +#define IDC_PPK5_CFORWARD 1015 +#define IDC_PPK5_CPROXY 1016 +#define IDC_PPK5_NAME 1017 +#define IDC_PPK5_ISSUE 1018 +#define IDC_PPK5_VALID 1019 +#define IDC_PPK5_RENEW 1020 +#define IDC_CHECK2 1022 +#define IDC_CHECK4 1024 +#define IDC_PPK5_LIFETIME 1024 +#define IDC_CHECK5 1025 +#define IDC_CFG_LBL_CACHE 1025 +#define IDC_CFG_LBL_CFGFILE 1026 +#define IDC_CFG_LBL_RLMPATH 1027 +#define IDC_CFG_CACHE 1028 +#define IDC_CFG_CFGPATH 1029 +#define IDC_CFG_RLMPATH 1030 +#define IDC_CFG_CFGBROW 1031 +#define IDC_CFG_RLMBROW 1032 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1033 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/windows/identity/plugins/krb4/main.c b/src/windows/identity/plugins/krb4/main.c new file mode 100644 index 0000000000..60ceb7f83c --- /dev/null +++ b/src/windows/identity/plugins/krb4/main.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +kmm_module h_khModule; /* KMM's handle to this module */ +HINSTANCE hInstance; +HMODULE hResModule; /* HMODULE to the resource library */ + +khm_int32 type_id_enctype = -1; +khm_int32 type_id_addr_list = -1; +khm_int32 type_id_krb5_flags = -1; + +khm_int32 attr_id_key_enctype = -1; +khm_int32 attr_id_tkt_enctype = -1; +khm_int32 attr_id_addr_list = -1; +khm_int32 attr_id_krb5_flags = -1; +khm_int32 attr_id_renew_till = -1; +khm_int32 attr_id_renew_for = -1; + +khm_handle csp_plugins = NULL; +khm_handle csp_krbcred = NULL; +khm_handle csp_params = NULL; + +kmm_module_locale locales[] = { + LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), L"krb4cred_en_us.dll", KMM_MLOC_FLAG_DEFAULT) +}; + +int n_locales = ARRAYLENGTH(locales); + +/* These two probably should not do anything */ +void init_krb() { +} + +void exit_krb() { +} + +/* called by the NetIDMgr module manager */ +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { + khm_int32 rv = KHM_ERROR_SUCCESS; + kmm_plugin_reg pi; + wchar_t buf[256]; + + h_khModule = h_module; + + rv = kmm_set_locale_info(h_module, locales, n_locales); + if(KHM_SUCCEEDED(rv)) { + hResModule = kmm_get_resource_hmodule(h_module); + } else + goto _exit; + + ZeroMemory(&pi, sizeof(pi)); + pi.name = KRB4_PLUGIN_NAME; + pi.type = KHM_PITYPE_CRED; + pi.icon = NULL; /*TODO: Assign icon */ + pi.flags = 0; + pi.msg_proc = krb4_cb; + pi.dependencies = KRB4_PLUGIN_DEPS; + pi.description = buf; + LoadString(hResModule, IDS_PLUGIN_DESC, + buf, ARRAYLENGTH(buf)); + kmm_provide_plugin(h_module, &pi); + + if(KHM_FAILED(rv = init_imports())) + goto _exit; + + if(KHM_FAILED(rv = init_error_funcs())) + goto _exit; + + /* Lookup common data types */ + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ENCTYPE, &type_id_enctype))) { + goto _exit; + } + + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ADDR_LIST, &type_id_addr_list))) { + goto _exit; + } + + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_KRB5_FLAGS, &type_id_krb5_flags))) { + goto _exit; + } + + /* Lookup common attributes */ + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KEY_ENCTYPE, &attr_id_key_enctype))) { + goto _exit; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_TKT_ENCTYPE, &attr_id_tkt_enctype))) { + goto _exit; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_ADDR_LIST, &attr_id_addr_list))) { + goto _exit; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_FLAGS, &attr_id_krb5_flags))) { + goto _exit; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_RENEW_TILL, &attr_id_renew_till))) { + goto _exit; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_RENEW_FOR, &attr_id_renew_for))) { + goto _exit; + } + + rv = kmm_get_plugins_config(0, &csp_plugins); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_load_schema(csp_plugins, schema_krbconfig); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_open_space(csp_plugins, CSNAME_KRB4CRED, 0, &csp_krbcred); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_open_space(csp_krbcred, CSNAME_PARAMS, 0, &csp_params); + if(KHM_FAILED(rv)) goto _exit; + +_exit: + return rv; +} + +/* called by the NetIDMgr module manager */ +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module) { + exit_imports(); + exit_error_funcs(); + + if(csp_params) { + khc_close_space(csp_params); + csp_params = NULL; + } + if(csp_krbcred) { + khc_close_space(csp_krbcred); + csp_krbcred = NULL; + } + if(csp_plugins) { + khc_unload_schema(csp_plugins, schema_krbconfig); + khc_close_space(csp_plugins); + csp_plugins = NULL; + } + + return KHM_ERROR_SUCCESS; /* the return code is ignored */ +} + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved +) +{ + switch(fdwReason) { + case DLL_PROCESS_ATTACH: + hInstance = hinstDLL; + init_krb(); + break; + case DLL_PROCESS_DETACH: + exit_krb(); + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + } + + return TRUE; +} diff --git a/src/windows/identity/plugins/krb5/Makefile b/src/windows/identity/plugins/krb5/Makefile new file mode 100644 index 0000000000..9bf9ef020e --- /dev/null +++ b/src/windows/identity/plugins/krb5/Makefile @@ -0,0 +1,91 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=plugins\krb5 +!include <../../config/Makefile.w32> + +DLLFILE=$(BINDIR)\krb5cred.dll + +LIBFILE=$(LIBDIR)\krb5cred.lib + +OBJFILES= \ + $(LIBDIR)\dynimport.obj \ + $(LIBDIR)\krb5common.obj \ + $(OBJ)\main.obj \ + $(OBJ)\datarep.obj \ + $(OBJ)\errorfuncs.obj \ + $(OBJ)\krb5plugin.obj \ + $(OBJ)\krb5props.obj \ + $(OBJ)\krb5newcreds.obj \ + $(OBJ)\krb5funcs.obj \ + $(OBJ)\krb5config.obj \ + $(OBJ)\krb5identpro.obj \ + $(OBJ)\krb5configdlg.obj + +LIBFILES= \ + $(LIBDIR)\nidmgr32.lib \ + $(KFWLIBDIR)\loadfuncs.lib + +SDKLIBFILES= \ + netapi32.lib + +MSGRESFILE=$(OBJ)\krb5_msgs.res + +$(OBJ)\krb5config.c: krbconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +$(DLLFILE): $(MSGRESFILE) $(OBJFILES) + $(DLLGUILINK) $(LIBFILES) $(SDKLIBFILES) + +$(MSGRESFILE): $(OBJ)\krb5_msgs.rc + +$(OBJ)\krb5_msgs.rc: lang\krb5_msgs.mc + $(MC2RC) + +all: mkdirs $(DLLFILE) lang + +lang:: + +# Repeat this block as necessary redefining LANG for additional +# languages. + +# Begin language block +LANG=en_us + +LANGDLL=$(BINDIR)\krb5cred_$(LANG).dll + +lang:: $(LANGDLL) + +$(LANGDLL): $(OBJ)\langres_$(LANG).res + $(DLLRESLINK) + +$(OBJ)\langres_$(LANG).res: lang\$(LANG)\langres.rc + $(RC2RES) + +# End language block + +clean:: +!if defined(INCFILES) + $(RM) $(INCFILES) +!endif diff --git a/src/windows/identity/plugins/krb5/datarep.c b/src/windows/identity/plugins/krb5/datarep.c new file mode 100644 index 0000000000..f8cc4cc484 --- /dev/null +++ b/src/windows/identity/plugins/krb5/datarep.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* Data representation and related functions */ + +#include +#include +#include +#include + +khm_int32 KHMAPI enctype_toString(const void * data, khm_size cbdata, wchar_t *destbuf, khm_size *pcbdestbuf, khm_int32 flags) +{ + int resid = 0; + int etype; + wchar_t buf[256]; + size_t cblength; + + if(cbdata != sizeof(khm_int32)) + return KHM_ERROR_INVALID_PARM; + + etype = *((khm_int32 *) data); + + switch(etype) { + case ENCTYPE_NULL: + resid = IDS_ETYPE_NULL; + break; + + case ENCTYPE_DES_CBC_CRC: + resid = IDS_ETYPE_DES_CBC_CRC; + break; + + case ENCTYPE_DES_CBC_MD4: + resid = IDS_ETYPE_DES_CBC_MD4; + break; + + case ENCTYPE_DES_CBC_MD5: + resid = IDS_ETYPE_DES_CBC_MD5; + break; + + case ENCTYPE_DES_CBC_RAW: + resid = IDS_ETYPE_DES_CBC_RAW; + break; + + case ENCTYPE_DES3_CBC_SHA: + resid = IDS_ETYPE_DES3_CBC_SHA; + break; + + case ENCTYPE_DES3_CBC_RAW: + resid = IDS_ETYPE_DES3_CBC_RAW; + break; + + case ENCTYPE_DES_HMAC_SHA1: + resid = IDS_ETYPE_DES_HMAC_SHA1; + break; + + case ENCTYPE_DES3_CBC_SHA1: + resid = IDS_ETYPE_DES3_CBC_SHA1; + break; + + case ENCTYPE_AES128_CTS_HMAC_SHA1_96: + resid = IDS_ETYPE_AES128_CTS_HMAC_SHA1_96; + break; + + case ENCTYPE_AES256_CTS_HMAC_SHA1_96: + resid = IDS_ETYPE_AES256_CTS_HMAC_SHA1_96; + break; + + case ENCTYPE_ARCFOUR_HMAC: + resid = IDS_ETYPE_ARCFOUR_HMAC; + break; + + case ENCTYPE_ARCFOUR_HMAC_EXP: + resid = IDS_ETYPE_ARCFOUR_HMAC_EXP; + break; + + case ENCTYPE_UNKNOWN: + resid = IDS_ETYPE_UNKNOWN; + break; + +#if 0 + case ENCTYPE_LOCAL_DES3_HMAC_SHA1: + resid = IDS_ETYPE_LOCAL_DES3_HMAC_SHA1; + break; + + case ENCTYPE_LOCAL_RC4_MD4: + resid = IDS_ETYPE_LOCAL_RC4_MD4; + break; +#endif + } + + if(resid != 0) { + LoadString(hResModule, (UINT) resid, buf, ARRAYLENGTH(buf)); + } else { + StringCbPrintf(buf, sizeof(buf), L"#%d", etype); + } + + StringCbLength(buf, ARRAYLENGTH(buf), &cblength); + cblength += sizeof(wchar_t); + + if(!destbuf || *pcbdestbuf < cblength) { + *pcbdestbuf = cblength; + return KHM_ERROR_TOO_LONG; + } else { + StringCbCopy(destbuf, *pcbdestbuf, buf); + *pcbdestbuf = cblength; + return KHM_ERROR_SUCCESS; + } +} + +khm_int32 KHMAPI addr_list_toString(const void *d, khm_size cb_d, wchar_t *buf, khm_size *pcb_buf, khm_int32 flags) +{ + /*TODO: implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} + +khm_int32 KHMAPI krb5flags_toString(const void *d, + khm_size cb_d, + wchar_t *buf, + khm_size *pcb_buf, + khm_int32 f) +{ + wchar_t sbuf[32]; + int i = 0; + khm_size cb; + khm_int32 flags; + + flags = *((khm_int32 *) d); + + if (flags & TKT_FLG_FORWARDABLE) + sbuf[i++] = L'F'; + + if (flags & TKT_FLG_FORWARDED) + sbuf[i++] = L'f'; + + if (flags & TKT_FLG_PROXIABLE) + sbuf[i++] = L'P'; + + if (flags & TKT_FLG_PROXY) + sbuf[i++] = L'p'; + + if (flags & TKT_FLG_MAY_POSTDATE) + sbuf[i++] = L'D'; + + if (flags & TKT_FLG_POSTDATED) + sbuf[i++] = L'd'; + + if (flags & TKT_FLG_INVALID) + sbuf[i++] = L'i'; + + if (flags & TKT_FLG_RENEWABLE) + sbuf[i++] = L'R'; + + if (flags & TKT_FLG_INITIAL) + sbuf[i++] = L'I'; + + if (flags & TKT_FLG_HW_AUTH) + sbuf[i++] = L'H'; + + if (flags & TKT_FLG_PRE_AUTH) + sbuf[i++] = L'A'; + + sbuf[i++] = L'\0'; + + cb = i * sizeof(wchar_t); + + if (!buf || *pcb_buf < cb) { + *pcb_buf = cb; + return KHM_ERROR_TOO_LONG; + } else { + StringCbCopy(buf, *pcb_buf, sbuf); + *pcb_buf = cb; + return KHM_ERROR_SUCCESS; + } +} + +khm_int32 serialize_krb5_addresses(krb5_address ** a, void ** buf, size_t * pcbbuf) +{ + /*TODO: implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} + +#if 0 + +wchar_t * +one_addr(krb5_address *a) +{ + static wchar_t retstr[256]; + struct hostent *h; + int no_resolve = 1; + + retstr[0] = L'\0'; + + if ((a->addrtype == ADDRTYPE_INET && a->length == 4) +#ifdef AF_INET6 + || (a->addrtype == ADDRTYPE_INET6 && a->length == 16) +#endif + ) + { + int af = AF_INET; +#ifdef AF_INET6 + if (a->addrtype == ADDRTYPE_INET6) + af = AF_INET6; +#endif + if (!no_resolve) { +#ifdef HAVE_GETIPNODEBYADDR + int err; + h = getipnodebyaddr(a->contents, a->length, af, &err); + if (h) { + StringCbPrintf(retstr, sizeof(retstr), L"%S", h->h_name); + freehostent(h); + } +#else + h = gethostbyaddr(a->contents, a->length, af); + if (h) { + StringCbPrintf(retstr, sizeof(retstr), L"%S", h->h_name); + } +#endif + if (h) + return(retstr); + } + if (no_resolve || !h) { +#ifdef HAVE_INET_NTOP + char buf[46]; + const char *name = inet_ntop(a->addrtype, a->contents, buf, sizeof(buf)); + if (name) { + StringCbPrintf(retstr, sizeof(retstr), L"%S", name); + return; + } +#else + if (a->addrtype == ADDRTYPE_INET) { + StringCbPrintf(retstr, sizeof(retstr), + L"%d.%d.%d.%d", a->contents[0], a->contents[1], + a->contents[2], a->contents[3]); + return(retstr); + } +#endif + } + } + { + wchar_t tmpfmt[128]; + LoadString(hResModule, IDS_UNK_ADDR_FMT, tmpfmt, sizeof(tmpfmt)/sizeof(wchar_t)); + StringCbPrintf(retstr, sizeof(retstr), tmpfmt, a->addrtype); + } + return(retstr); +} +#endif diff --git a/src/windows/identity/plugins/krb5/datarep.h b/src/windows/identity/plugins/krb5/datarep.h new file mode 100644 index 0000000000..e5388f01db --- /dev/null +++ b/src/windows/identity/plugins/krb5/datarep.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KRB_DATAREP_H +#define __KHIMAIRA_KRB_DATAREP_H + + +khm_int32 KHMAPI enctype_toString(const void * data, khm_size cbdata, wchar_t *destbuf, khm_size *pcbdestbuf, khm_int32 flags); +khm_int32 KHMAPI addr_list_toString(const void *, khm_size, wchar_t *, khm_size *, khm_int32); +khm_int32 KHMAPI krb5flags_toString(const void *, khm_size, wchar_t *, khm_size *, khm_int32); +khm_int32 KHMAPI renew_for_cb(khm_handle cred, khm_int32 id, void * buffer, khm_size * pcbsize); + + +#endif \ No newline at end of file diff --git a/src/windows/identity/plugins/krb5/errorfuncs.c b/src/windows/identity/plugins/krb5/errorfuncs.c new file mode 100644 index 0000000000..ab64889cb7 --- /dev/null +++ b/src/windows/identity/plugins/krb5/errorfuncs.c @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +extern void (__cdecl *pinitialize_krb_error_func)(); +extern void (__cdecl *pinitialize_kadm_error_table)(); + + +khm_int32 init_error_funcs() +{ + return KHM_ERROR_SUCCESS; +} + +khm_int32 exit_error_funcs() +{ + return KHM_ERROR_SUCCESS; +} + +#ifdef DEPRECATED_REMOVABLE +HWND GetRootParent (HWND Child) +{ + HWND Last; + while (Child) + { + Last = Child; + Child = GetParent (Child); + } + return Last; +} +#endif + +void khm_err_describe(long code, wchar_t * buf, khm_size cbbuf, + DWORD * suggestion, + kherr_suggestion * suggest_code) +{ + const char * com_err_msg; + int offset; + long table_num; + DWORD msg_id = 0; + DWORD sugg_id = 0; + kherr_suggestion sugg_code = KHERR_SUGGEST_NONE; + + if (suggestion == NULL || buf == NULL || cbbuf == 0 || suggest_code == 0) + return; + + *buf = L'\0'; + + offset = (int) (code & 255); + table_num = code - offset; + com_err_msg = perror_message(code); + + *suggestion = 0; + *suggest_code = KHERR_SUGGEST_NONE; + + switch(table_num) + { + case krb_err_base: + case kadm_err_base: + break; + default: + *suggest_code = KHERR_SUGGEST_RETRY; + AnsiStrToUnicode(buf, cbbuf, com_err_msg); + return; + } + + if (table_num == krb_err_base) + switch(offset) + { + case KDC_NAME_EXP: /* 001 Principal expired */ + case KDC_SERVICE_EXP: /* 002 Service expired */ + case KDC_AUTH_EXP: /* 003 Auth expired */ + case KDC_PKT_VER: /* 004 Protocol version unknown */ + case KDC_P_MKEY_VER: /* 005 Wrong master key version */ + case KDC_S_MKEY_VER: /* 006 Wrong master key version */ + case KDC_BYTE_ORDER: /* 007 Byte order unknown */ + case KDC_PR_N_UNIQUE: /* 009 Principal not unique */ + case KDC_NULL_KEY: /* 010 Principal has null key */ + case KDC_GEN_ERR: /* 011 Generic error from KDC */ + case INTK_W_NOTALL : /* 061 Not ALL tickets returned */ + case INTK_PROT : /* 063 Protocol Error */ + case INTK_ERR : /* 070 Other error */ + msg_id = MSG_ERR_UNKNOWN; + sugg_code = KHERR_SUGGEST_RETRY; + break; + + case KDC_PR_UNKNOWN: /* 008 Principal unknown */ + msg_id = MSG_ERR_PR_UNKNOWN; + sugg_code = KHERR_SUGGEST_RETRY; + break; + case GC_TKFIL : /* 021 Can't read ticket file */ + case GC_NOTKT : /* 022 Can't find ticket or TGT */ + msg_id = MSG_ERR_TKFIL; + sugg_id = MSG_ERR_S_TKFIL; + sugg_code = KHERR_SUGGEST_RETRY; + break; + case MK_AP_TGTEXP : /* 026 TGT Expired */ + /* no extra error msg */ + break; + + case RD_AP_TIME : /* 037 delta_t too big */ + msg_id = MSG_ERR_CLOCKSKEW; + sugg_id = MSG_ERR_S_CLOCKSKEW; + sugg_code = KHERR_SUGGEST_RETRY; + break; + + case RD_AP_UNDEC : /* 031 Can't decode + authenticator */ + case RD_AP_EXP : /* 032 Ticket expired */ + case RD_AP_NYV : /* 033 Ticket not yet valid */ + case RD_AP_REPEAT : /* 034 Repeated request */ + case RD_AP_NOT_US : /* 035 The ticket isn't for us */ + case RD_AP_INCON : /* 036 Request is inconsistent */ + case RD_AP_BADD : /* 038 Incorrect net address */ + case RD_AP_VERSION : /* 039 protocol version mismatch */ + case RD_AP_MSG_TYPE : /* 040 invalid msg type */ + case RD_AP_MODIFIED : /* 041 message stream modified */ + case RD_AP_ORDER : /* 042 message out of order */ + case RD_AP_UNAUTHOR : /* 043 unauthorized request */ + /* no extra error msg */ + sugg_code = KHERR_SUGGEST_RETRY; + break; + + case GT_PW_NULL: /* 51 Current PW is null */ + case GT_PW_BADPW: /* 52 Incorrect current password */ + case GT_PW_PROT: /* 53 Protocol Error */ + case GT_PW_KDCERR: /* 54 Error returned by KDC */ + case GT_PW_NULLTKT: /* 55 Null tkt returned by KDC */ + /* no error msg yet */ + sugg_code = KHERR_SUGGEST_RETRY; + break; + + /* Values returned by send_to_kdc */ + case SKDC_RETRY : /* 56 Retry count exceeded */ + case SKDC_CANT : /* 57 Can't send request */ + msg_id = MSG_ERR_KDC_CONTACT; + break; + /* no error message on purpose: */ + case INTK_BADPW : /* 062 Incorrect password */ + sugg_code = KHERR_SUGGEST_RETRY; + break; + default: + /* no extra error msg */ + break; + } + else + switch(code) + { + case KADM_INSECURE_PW: + /* if( kadm_info != NULL ){ + * wsprintf(buf, "%s\n%s", com_err_msg, kadm_info); + * } else { + * wsprintf(buf, "%s\nPlease see the help file for information " + * "about secure passwords.", com_err_msg); + * } + * com_err_msg = buf; + */ + + /* The above code would be preferred since it allows site + * specific information to be delivered from the Kerberos + * server. However the message box is too small for VGA + * screens. It does work well if we only have to support + * 1024x768 + */ + + msg_id = MSG_ERR_INSECURE_PW; + sugg_code = KHERR_SUGGEST_RETRY; + break; + + default: + /* no extra error msg */ + break; + } + + if (msg_id != 0) { + FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | + FORMAT_MESSAGE_IGNORE_INSERTS, + KHERR_HMODULE, + msg_id, + 0, + buf, + (int) (cbbuf / sizeof(buf[0])), + NULL); + } + + if (sugg_id != 0) { + *suggestion = sugg_id; + } + + if (sugg_code != KHERR_SUGGEST_NONE) + *suggest_code = sugg_code; +} + +#ifdef DEPRECATED_REMOVABLE +int lsh_com_err_proc (LPSTR whoami, long code, + LPSTR fmt, va_list args) +{ + int retval; + HWND hOldFocus; + char buf[1024], *cp; + WORD mbformat = MB_OK | MB_ICONEXCLAMATION; + + cp = buf; + memset(buf, '\0', sizeof(buf)); + cp[0] = '\0'; + + if (code) + { + err_describe(buf, code); + while (*cp) + cp++; + } + + if (fmt) + { + if (fmt[0] == '%' && fmt[1] == 'b') + { + fmt += 2; + mbformat = va_arg(args, WORD); + /* if the first arg is a %b, we use it for the message + box MB_??? flags. */ + } + if (code) + { + *cp++ = '\n'; + *cp++ = '\n'; + } + wvsprintfA((LPSTR)cp, fmt, args); + } + hOldFocus = GetFocus(); + retval = MessageBoxA(/*GetRootParent(hOldFocus)*/NULL, buf, whoami, + mbformat | MB_ICONHAND | MB_TASKMODAL); + SetFocus(hOldFocus); + return retval; +} +#endif diff --git a/src/windows/identity/plugins/krb5/errorfuncs.h b/src/windows/identity/plugins/krb5/errorfuncs.h new file mode 100644 index 0000000000..46d68f9fc0 --- /dev/null +++ b/src/windows/identity/plugins/krb5/errorfuncs.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_ERR_H +#define __KHIMAIRA_ERR_H + +/* All error handling and reporting related functions for the krb4/5 + and AFS plugins */ + +#include +#include +/* + * This is a hack needed because the real com_err.h does + * not define err_func. We need it in the case where + * we pull in the real com_err instead of the krb4 + * impostor. + */ +#ifndef _DCNS_MIT_COM_ERR_H +typedef LPSTR (*err_func)(int, long); +#endif + +#include +#include + +#define kadm_err_base ERROR_TABLE_BASE_kadm + +#include + +#ifndef KRBERR +#define KRBERR(code) (code + krb_err_base) +#endif + +/*! \internal + \brief Describe an error + + \param[in] code Error code returned by Kerberos + \param[out] buf Receives the error string + \param[in] cbbuf Size of buffer pointed to by \a buf + \param[out] suggestion Message ID of suggestion + \param[out] suggest_code Suggestion ID +*/ +void khm_err_describe(long code, wchar_t * buf, khm_size cbbuf, + DWORD * suggestion, + kherr_suggestion * suggest_code); + +/* */ +khm_int32 init_error_funcs(); + +khm_int32 exit_error_funcs(); + + +#endif diff --git a/src/windows/identity/plugins/krb5/krb5configdlg.c b/src/windows/identity/plugins/krb5/krb5configdlg.c new file mode 100644 index 0000000000..c3b00e1612 --- /dev/null +++ b/src/windows/identity/plugins/krb5/krb5configdlg.c @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include + +INT_PTR CALLBACK +k5_config_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + { + HWND hw; + wchar_t * realms; + wchar_t * defrealm; + wchar_t * t; + char conffile[MAX_PATH]; + wchar_t wconffile[MAX_PATH]; + wchar_t importopts[256]; + WKSTA_INFO_100 * winfo100; + + hw = GetDlgItem(hwnd, IDC_CFG_DEFREALM); +#ifdef DEBUG + assert(hw); +#endif + realms = khm_krb5_get_realm_list(); + defrealm = khm_krb5_get_default_realm(); +#ifdef DEBUG + assert(realms); + assert(defrealm); +#endif + + SendMessage(hw, CB_RESETCONTENT, 0, 0); + + for(t = realms; t && *t; t = multi_string_next(t)) { + SendMessage(hw, CB_ADDSTRING, 0, (LPARAM) t); + } + + SendMessage(hw, CB_SELECTSTRING, -1, (LPARAM) defrealm); + + free(defrealm); + free(realms); + + khm_get_profile_file(conffile, sizeof(conffile)); + + AnsiStrToUnicode(wconffile, sizeof(wconffile), conffile); + + SetDlgItemText(hwnd, IDC_CFG_CFGFILE, wconffile); + + /* hostname/domain */ + if (NetWkstaGetInfo(NULL, 100, (LPBYTE *) &winfo100) == NERR_Success) { + SetDlgItemText(hwnd, IDC_CFG_HOSTNAME, winfo100->wki100_computername); + SetDlgItemText(hwnd, IDC_CFG_DOMAIN, winfo100->wki100_langroup); + NetApiBufferFree(winfo100); + } + + /* and the import ticket options */ + LoadString(hResModule, IDS_K5CFG_IMPORT_OPTIONS, + importopts, ARRAYLENGTH(importopts)); + + hw = GetDlgItem(hwnd, IDC_CFG_IMPORT); +#ifdef DEBUG + assert(hw); +#endif + SendMessage(hw, CB_RESETCONTENT, 0, 0); + + for (t=importopts; + t && *t && *t != L' ' && + t < importopts + ARRAYLENGTH(importopts); + t = multi_string_next(t)) { + + SendMessage(hw, CB_ADDSTRING, 0, (LPARAM) t); + } + + SendMessage(hw, CB_SETCURSEL, 0, 0); + + } + break; + + case WM_DESTROY: + break; + } + return FALSE; +} + +INT_PTR CALLBACK +k5_realms_dlgproc(HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + break; + + case WM_DESTROY: + break; + } + return FALSE; +} + +typedef struct tag_k5_ids_dlg_data { + khui_tracker tc_life; + khui_tracker tc_renew; + khui_tracker tc_life_min; + khui_tracker tc_life_max; + khui_tracker tc_renew_min; + khui_tracker tc_renew_max; + + time_t life; + time_t renew_life; + time_t life_min; + time_t life_max; + time_t renew_min; + time_t renew_max; +} k5_ids_dlg_data; + +static void +k5_ids_read_params(k5_ids_dlg_data * d) { + khm_int32 t; + khm_int32 rv; + +#ifdef DEBUG + assert(csp_params); +#endif + + rv = khc_read_int32(csp_params, L"DefaultLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->life = t; + + rv = khc_read_int32(csp_params, L"DefaultRenewLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->renew_life = t; + + rv = khc_read_int32(csp_params, L"MaxLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->life_max = t; + + rv = khc_read_int32(csp_params, L"MinLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->life_min = t; + + rv = khc_read_int32(csp_params, L"MaxRenewLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->renew_max = t; + + rv = khc_read_int32(csp_params, L"MinRenewLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->renew_min = t; + + khui_tracker_initialize(&d->tc_life); + d->tc_life.current = d->life; + d->tc_life.min = 0; + d->tc_life.max = 3600 * 24 * 7; + + khui_tracker_initialize(&d->tc_renew); + d->tc_renew.current = d->renew_life; + d->tc_renew.min = 0; + d->tc_renew.max = 3600 * 24 * 30; + + khui_tracker_initialize(&d->tc_life_min); + d->tc_life_min.current = d->life_min; + d->tc_life_min.min = d->tc_life.min; + d->tc_life_min.max = d->tc_life.max; + + khui_tracker_initialize(&d->tc_life_max); + d->tc_life_max.current = d->life_max; + d->tc_life_max.min = d->tc_life.min; + d->tc_life_max.max = d->tc_life.max; + + khui_tracker_initialize(&d->tc_renew_min); + d->tc_renew_min.current = d->renew_min; + d->tc_renew_min.min = d->tc_renew.min; + d->tc_renew_min.max = d->tc_renew.max; + + khui_tracker_initialize(&d->tc_renew_max); + d->tc_renew_max.current = d->renew_max; + d->tc_renew_max.min = d->tc_renew.min; + d->tc_renew_max.max = d->tc_renew.max; +} + +INT_PTR CALLBACK +k5_ids_tab_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + k5_ids_dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + d = malloc(sizeof(*d)); +#ifdef DEBUG + assert(d); +#endif + ZeroMemory(d, sizeof(*d)); +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + k5_ids_read_params(d); + + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFLIFE), + &d->tc_life); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFRLIFE), + &d->tc_renew); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_LRNG_MIN), + &d->tc_life_min); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_LRNG_MAX), + &d->tc_life_max); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_RLRNG_MIN), + &d->tc_renew_min); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_RLRNG_MAX), + &d->tc_renew_max); + khui_tracker_refresh(&d->tc_life); + khui_tracker_refresh(&d->tc_life_min); + khui_tracker_refresh(&d->tc_life_max); + khui_tracker_refresh(&d->tc_renew); + khui_tracker_refresh(&d->tc_renew_min); + khui_tracker_refresh(&d->tc_renew_max); + break; + + case WM_DESTROY: + d = (k5_ids_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + khui_tracker_kill_controls(&d->tc_life); + khui_tracker_kill_controls(&d->tc_renew); + khui_tracker_kill_controls(&d->tc_life_min); + khui_tracker_kill_controls(&d->tc_life_max); + khui_tracker_kill_controls(&d->tc_renew_min); + khui_tracker_kill_controls(&d->tc_renew_max); + break; + } + return FALSE; +} + +INT_PTR CALLBACK +k5_id_tab_dlgproc(HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + break; + + case WM_DESTROY: + break; + } + return FALSE; +} + + +void +k5_register_config_panels(void) { + khui_config_node node; + khui_config_node_reg reg; + wchar_t wshort[KHUI_MAXCCH_SHORT_DESC]; + wchar_t wlong[KHUI_MAXCCH_LONG_DESC]; + + ZeroMemory(®, sizeof(reg)); + + LoadString(hResModule, IDS_K5CFG_SHORT_DESC, + wshort, ARRAYLENGTH(wshort)); + LoadString(hResModule, IDS_K5CFG_LONG_DESC, + wlong, ARRAYLENGTH(wlong)); + + reg.name = L"Kerberos5"; + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CONFIG); + reg.dlg_proc = k5_config_dlgproc; + reg.flags = 0; + + khui_cfg_register(NULL, ®); + + if (KHM_FAILED(khui_cfg_open(NULL, L"Kerberos5", &node))) { + node = NULL; +#ifdef DEBUG + assert(FALSE); +#endif + } + + ZeroMemory(®, sizeof(reg)); + + LoadString(hResModule, IDS_K5RLM_SHORT_DESC, + wshort, ARRAYLENGTH(wshort)); + LoadString(hResModule, IDS_K5RLM_LONG_DESC, + wlong, ARRAYLENGTH(wlong)); + + reg.name = L"KerberosRealms"; + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_REALMS); + reg.dlg_proc = k5_realms_dlgproc; + reg.flags = 0; + + khui_cfg_register(node, ®); + + khui_cfg_release(node); + + if (KHM_FAILED(khui_cfg_open(NULL, L"KhmIdentities", &node))) { + node = NULL; +#ifdef DEBUG + assert(FALSE); +#endif + } + + ZeroMemory(®, sizeof(reg)); + + LoadString(hResModule, IDS_K5CFG_IDS_SHORT_DESC, + wshort, ARRAYLENGTH(wshort)); + LoadString(hResModule, IDS_K5CFG_IDS_LONG_DESC, + wlong, ARRAYLENGTH(wlong)); + + reg.name = L"KerberosIdentities"; + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDS_TAB); + reg.dlg_proc = k5_ids_tab_dlgproc; + reg.flags = KHUI_CNFLAG_SUBPANEL; + + khui_cfg_register(node, ®); + + ZeroMemory(®, sizeof(reg)); + + LoadString(hResModule, IDS_K5CFG_ID_SHORT_DESC, + wshort, ARRAYLENGTH(wshort)); + LoadString(hResModule, IDS_K5CFG_ID_LONG_DESC, + wlong, ARRAYLENGTH(wlong)); + + reg.name = L"KerberosIdentitiesPlural"; + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_ID_TAB); + reg.dlg_proc = k5_id_tab_dlgproc; + reg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_PLURAL; + + khui_cfg_register(node, ®); + + khui_cfg_release(node); +} + +void +k5_unregister_config_panels(void) { + khui_config_node node_main; + khui_config_node node_realms; + khui_config_node node_ids; + khui_config_node node_tab; + + if (KHM_FAILED(khui_cfg_open(NULL, L"Kerberos5", &node_main))) { + node_main = NULL; +#ifdef DEBUG + assert(FALSE); +#endif + } + + if (KHM_SUCCEEDED(khui_cfg_open(node_main, L"KerberosRealms", + &node_realms))) { + khui_cfg_remove(node_realms); + khui_cfg_release(node_realms); + } +#ifdef DEBUG + else + assert(FALSE); +#endif + + if (node_main) { + khui_cfg_remove(node_main); + khui_cfg_release(node_main); + } + + if (KHM_FAILED(khui_cfg_open(NULL, L"KhmIdentities", &node_ids))) { + node_ids = NULL; +#ifdef DEBUG + assert(FALSE); +#endif + } + + if (KHM_SUCCEEDED(khui_cfg_open(node_ids, L"KerberosIdentities", &node_tab))) { + khui_cfg_remove(node_tab); + khui_cfg_release(node_tab); + } + if (KHM_SUCCEEDED(khui_cfg_open(node_ids, L"KerberosIdentitiesPlural", &node_tab))) { + khui_cfg_remove(node_tab); + khui_cfg_release(node_tab); + } + + if (node_ids) + khui_cfg_release(node_ids); +} diff --git a/src/windows/identity/plugins/krb5/krb5funcs.c b/src/windows/identity/plugins/krb5/krb5funcs.c new file mode 100644 index 0000000000..d3c97fff2f --- /dev/null +++ b/src/windows/identity/plugins/krb5/krb5funcs.c @@ -0,0 +1,1889 @@ +/* +* Copyright (c) 2004 Massachusetts Institute of Technology +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* $Id$ */ + +/* Originally this was krb5routines.c in Leash sources. Subsequently +modified and adapted for NetIDMgr */ + +#include +#include + +#define SECURITY_WIN32 +#include +#include + +#include +#include +#include +#include + +long +khm_convert524(krb5_context alt_ctx) +{ + krb5_context ctx = 0; + krb5_error_code code = 0; + int icode = 0; + krb5_principal me = 0; + krb5_principal server = 0; + krb5_creds *v5creds = 0; + krb5_creds increds; + krb5_ccache cc = 0; + CREDENTIALS * v4creds = NULL; + static int init_ets = 1; + + if (!pkrb5_init_context || + !pkrb_in_tkt || + !pkrb524_init_ets || + !pkrb524_convert_creds_kdc) + return 0; + + v4creds = (CREDENTIALS *) malloc(sizeof(CREDENTIALS)); + memset((char *) v4creds, 0, sizeof(CREDENTIALS)); + + memset((char *) &increds, 0, sizeof(increds)); + /* + From this point on, we can goto cleanup because increds is + initialized. + */ + + if (alt_ctx) + { + ctx = alt_ctx; + } + else + { + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + } + + code = pkrb5_cc_default(ctx, &cc); + if (code) goto cleanup; + + if ( init_ets ) { + pkrb524_init_ets(ctx); + init_ets = 0; + } + + if (code = pkrb5_cc_get_principal(ctx, cc, &me)) + goto cleanup; + + if ((code = pkrb5_build_principal(ctx, + &server, + krb5_princ_realm(ctx, me)->length, + krb5_princ_realm(ctx, me)->data, + "krbtgt", + krb5_princ_realm(ctx, me)->data, + NULL))) + { + goto cleanup; + } + + increds.client = me; + increds.server = server; + increds.times.endtime = 0; + increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; + if ((code = pkrb5_get_credentials(ctx, 0, + cc, + &increds, + &v5creds))) + { + goto cleanup; + } + + if ((icode = pkrb524_convert_creds_kdc(ctx, + v5creds, + v4creds))) + { + goto cleanup; + } + + /* initialize ticket cache */ + if ((icode = pkrb_in_tkt(v4creds->pname, v4creds->pinst, v4creds->realm) + != KSUCCESS)) + { + goto cleanup; + } + /* stash ticket, session key, etc. for future use */ + if ((icode = pkrb_save_credentials(v4creds->service, + v4creds->instance, + v4creds->realm, + v4creds->session, + v4creds->lifetime, + v4creds->kvno, + &(v4creds->ticket_st), + v4creds->issue_date))) + { + goto cleanup; + } + +cleanup: + memset(v4creds, 0, sizeof(v4creds)); + free(v4creds); + + if (v5creds) { + pkrb5_free_creds(ctx, v5creds); + } + if (increds.client == me) + me = 0; + if (increds.server == server) + server = 0; + pkrb5_free_cred_contents(ctx, &increds); + if (server) { + pkrb5_free_principal(ctx, server); + } + if (me) { + pkrb5_free_principal(ctx, me); + } + pkrb5_cc_close(ctx, cc); + + if (ctx && (ctx != alt_ctx)) { + pkrb5_free_context(ctx); + } + return !(code || icode); +} + +#ifdef DEPRECATED_REMOVABLE +int com_addr(void) +{ + long ipAddr; + char loc_addr[ADDR_SZ]; + CREDENTIALS cred; + char service[40]; + char instance[40]; + // char addr[40]; + char realm[40]; + struct in_addr LocAddr; + int k_errno; + + if (pkrb_get_cred == NULL) + return(KSUCCESS); + + k_errno = (*pkrb_get_cred)(service,instance,realm,&cred); + if (k_errno) + return KRBERR(k_errno); + + while(1) { + ipAddr = (*pLocalHostAddr)(); + LocAddr.s_addr = ipAddr; + StringCbCopyA(loc_addr, sizeof(loc_addr), inet_ntoa(LocAddr)); + if ( strcmp(cred.address, loc_addr) != 0) { + /* TODO: do something about this */ + //Leash_kdestroy (); + break; + } + break; + } // while() + return 0; +} +#endif + +#ifndef ENCTYPE_LOCAL_RC4_MD4 +#define ENCTYPE_LOCAL_RC4_MD4 0xFFFFFF80 +#endif + +static long get_tickets_from_cache(krb5_context ctx, + krb5_ccache cache) +{ + krb5_error_code code; + krb5_principal KRBv5Principal; + krb5_flags flags = 0; + krb5_cc_cursor KRBv5Cursor; + krb5_creds KRBv5Credentials; + krb5_ticket *tkt=NULL; + char *ClientName; + char *PrincipalName; + wchar_t wbuf[256]; /* temporary conversion buffer */ + wchar_t *wcc_name = NULL; /* credential cache name */ + char *sServerName; + khm_handle ident = NULL; + khm_handle cred = NULL; + time_t tt; + khm_int64 ft, eft; + khm_int32 ti; + + +#ifdef KRB5_TC_NOTICKET + flags = KRB5_TC_NOTICKET; +#else + flags = 0; +#endif + + { + char * cc_name; + size_t namelen; + + cc_name = (*pkrb5_cc_get_name)(ctx, cache); + if(cc_name) { + namelen = strlen(cc_name); + namelen = (namelen + 1 + 4) * sizeof(wchar_t); + /* the +4 is for the possible addtion of API: during the + cannonicalization process */ + wcc_name = malloc(namelen); + AnsiStrToUnicode(wcc_name, namelen, cc_name); + khm_krb5_canon_cc_name(wcc_name, namelen); + } + } + + if ((code = (*pkrb5_cc_set_flags)(ctx, cache, flags))) + { + if (code != KRB5_FCC_NOFILE && code != KRB5_CC_NOTFOUND) + khm_krb5_error(code, "krb5_cc_set_flags()", 0, &ctx, &cache); + + goto _exit; + } + + if ((code = (*pkrb5_cc_get_principal)(ctx, cache, &KRBv5Principal))) + { + if (code != KRB5_FCC_NOFILE && code != KRB5_CC_NOTFOUND) + khm_krb5_error(code, "krb5_cc_get_principal()", 0, &ctx, &cache); + + goto _exit; + } + + PrincipalName = NULL; + ClientName = NULL; + sServerName = NULL; + if ((code = (*pkrb5_unparse_name)(ctx, KRBv5Principal, + (char **)&PrincipalName))) + { + if (PrincipalName != NULL) + (*pkrb5_free_unparsed_name)(ctx, PrincipalName); + + (*pkrb5_free_principal)(ctx, KRBv5Principal); + + goto _exit; + } + + if (!strcspn(PrincipalName, "@" )) + { + if (PrincipalName != NULL) + (*pkrb5_free_unparsed_name)(ctx, PrincipalName); + + (*pkrb5_free_principal)(ctx, KRBv5Principal); + + goto _exit; + } + + AnsiStrToUnicode(wbuf, sizeof(wbuf), PrincipalName); + if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, + &ident))) { + /* something bad happened */ + code = 1; + goto _exit; + } + + (*pkrb5_free_principal)(ctx, KRBv5Principal); + + if ((code = (*pkrb5_cc_start_seq_get)(ctx, cache, &KRBv5Cursor))) + { + goto _exit; + } + + memset(&KRBv5Credentials, '\0', sizeof(KRBv5Credentials)); + + ClientName = NULL; + sServerName = NULL; + cred = NULL; + + while (!(code = pkrb5_cc_next_cred(ctx, cache, &KRBv5Cursor, + &KRBv5Credentials))) + { + khm_handle tident = NULL; + + if(ClientName != NULL) + (*pkrb5_free_unparsed_name)(ctx, ClientName); + if(sServerName != NULL) + (*pkrb5_free_unparsed_name)(ctx, sServerName); + if(cred) + kcdb_cred_release(cred); + + ClientName = NULL; + sServerName = NULL; + cred = NULL; + + if ((*pkrb5_unparse_name)(ctx, KRBv5Credentials.client, &ClientName)) + { + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + khm_krb5_error(code, "krb5_free_cred_contents()", 0, &ctx, &cache); + continue; + } + + if ((*pkrb5_unparse_name)(ctx, KRBv5Credentials.server, &sServerName)) + { + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + khm_krb5_error(code, "krb5_free_cred_contents()", 0, &ctx, &cache); + continue; + } + + /* if the ClientName differs from PrincipalName for some + reason, we need to create a new identity */ + if(strcmp(ClientName, PrincipalName)) { + AnsiStrToUnicode(wbuf, sizeof(wbuf), ClientName); + if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, + &tident))) { + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + continue; + } + } else { + tident = ident; + } + + AnsiStrToUnicode(wbuf, sizeof(wbuf), sServerName); + if(KHM_FAILED(kcdb_cred_create(wbuf, tident, credtype_id_krb5, + &cred))) { + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + continue; + } + + if (!KRBv5Credentials.times.starttime) + KRBv5Credentials.times.starttime = KRBv5Credentials.times.authtime; + + tt = KRBv5Credentials.times.starttime; + TimetToFileTime(tt, (LPFILETIME) &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft)); + + tt = KRBv5Credentials.times.endtime; + TimetToFileTime(tt, (LPFILETIME) &eft); + kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &eft, sizeof(eft)); + + eft -= ft; + kcdb_cred_set_attr(cred, KCDB_ATTR_LIFETIME, &eft, sizeof(eft)); + + if (KRBv5Credentials.times.renew_till >= 0) { + tt = KRBv5Credentials.times.renew_till; + TimetToFileTime(tt, (LPFILETIME) &eft); + kcdb_cred_set_attr(cred, KCDB_ATTR_RENEW_EXPIRE, &eft, + sizeof(eft)); + + eft -= ft; + kcdb_cred_set_attr(cred, KCDB_ATTR_RENEW_LIFETIME, &eft, + sizeof(eft)); + } + + ti = KRBv5Credentials.ticket_flags; + kcdb_cred_set_attr(cred, attr_id_krb5_flags, &ti, sizeof(ti)); + + /* special flags understood by NetIDMgr */ + { + khm_int32 oflags, nflags; + + kcdb_cred_get_flags(cred, &oflags); + nflags = oflags; + + if (ti & TKT_FLG_RENEWABLE) + nflags |= KCDB_CRED_FLAG_RENEWABLE; + if (ti & TKT_FLG_INITIAL) + nflags |= KCDB_CRED_FLAG_INITIAL; + + if (oflags != nflags) + kcdb_cred_set_flags(cred, nflags, KCDB_CRED_FLAGMASK_ALL); + } + + if ( !pkrb5_decode_ticket(&KRBv5Credentials.ticket, &tkt)) { + ti = tkt->enc_part.enctype; + kcdb_cred_set_attr(cred, attr_id_tkt_enctype, &ti, sizeof(ti)); + pkrb5_free_ticket(ctx, tkt); + tkt = NULL; + } + + ti = KRBv5Credentials.keyblock.enctype; + kcdb_cred_set_attr(cred, attr_id_key_enctype, &ti, sizeof(ti)); + + kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION, wcc_name, KCDB_CBSIZE_AUTO); + + /*TODO: going here */ +#if 0 + if ( KRBv5Credentials.addresses && KRBv5Credentials.addresses[0] ) { + int n = 0; + while ( KRBv5Credentials.addresses[n] ) + n++; + list->addrList = calloc(1, n * sizeof(char *)); + if (!list->addrList) { + MessageBox(NULL, "Memory Error", "Error", MB_OK); + return ENOMEM; + } + list->addrCount = n; + for ( n=0; naddrCount; n++ ) { + wsprintf(Buffer, "Address: %s", one_addr(KRBv5Credentials.addresses[n])); + list->addrList[n] = (char*) calloc(1, strlen(Buffer)+1); + if (!list->addrList[n]) + { + MessageBox(NULL, "Memory Error", "Error", MB_OK); + return ENOMEM; + } + strcpy(list->addrList[n], Buffer); + } + } +#endif + + if(KRBv5Credentials.ticket_flags & TKT_FLG_INITIAL) { + __int64 t_expire_old; + __int64 t_expire_new; + khm_size cb; + + /* an initial ticket! If we find one, we generally set + the lifetime, and primary ccache based on this, but + only if this initial cred has a greater lifetime than + the current primary credential. */ + + tt = KRBv5Credentials.times.endtime; + TimetToFileTime(tt, (LPFILETIME) &t_expire_new); + + cb = sizeof(t_expire_old); + if(KHM_FAILED(kcdb_identity_get_attr(tident, + KCDB_ATTR_EXPIRE, + NULL, &t_expire_old, + &cb)) + || t_expire_new > t_expire_old) + { + kcdb_identity_set_attr(tident, attr_id_krb5_ccname, + wcc_name, KCDB_CBSIZE_AUTO); + kcdb_identity_set_attr(tident, KCDB_ATTR_EXPIRE, + &t_expire_new, + sizeof(t_expire_new)); + + if (KRBv5Credentials.times.renew_till >= 0) { + tt = KRBv5Credentials.times.renew_till; + TimetToFileTime(tt, (LPFILETIME) &ft); + kcdb_identity_set_attr(tident, + KCDB_ATTR_RENEW_EXPIRE, + &ft, sizeof(ft)); + } else { + kcdb_identity_set_attr(tident, + KCDB_ATTR_RENEW_EXPIRE, + NULL, 0); + } + + ti = KRBv5Credentials.ticket_flags; + kcdb_identity_set_attr(tident, attr_id_krb5_flags, + &ti, sizeof(ti)); + } + } + + kcdb_credset_add_cred(krb5_credset, cred, -1); + + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + + if(tident != ident) + kcdb_identity_release(tident); + } + + if (PrincipalName != NULL) + (*pkrb5_free_unparsed_name)(ctx, PrincipalName); + + if (ClientName != NULL) + (*pkrb5_free_unparsed_name)(ctx, ClientName); + + if (sServerName != NULL) + (*pkrb5_free_unparsed_name)(ctx, sServerName); + + if (cred) + kcdb_cred_release(cred); + + if ((code == KRB5_CC_END) || (code == KRB5_CC_NOTFOUND)) + { + if ((code = pkrb5_cc_end_seq_get(ctx, cache, &KRBv5Cursor))) + { + goto _exit; + } + + flags = KRB5_TC_OPENCLOSE; +#ifdef KRB5_TC_NOTICKET + flags |= KRB5_TC_NOTICKET; +#endif + if ((code = pkrb5_cc_set_flags(ctx, cache, flags))) + { + goto _exit; + } + } + else + { + goto _exit; + } + +_exit: + if(wcc_name) + free(wcc_name); + + return code; +} + +long +khm_krb5_list_tickets(krb5_context *krbv5Context) +{ + krb5_context ctx; + krb5_ccache cache; + krb5_error_code code; + apiCB * cc_ctx = 0; + struct _infoNC ** pNCi = NULL; + int i; + + ctx = NULL; + cache = NULL; + + kcdb_credset_flush(krb5_credset); + + code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL); + if (code) + goto _exit; + + code = pcc_get_NC_info(cc_ctx, &pNCi); + if (code) + goto _exit; + + if((*krbv5Context == 0) && (code = (*pkrb5_init_context)(krbv5Context))) { + goto _exit; + } + + ctx = (*krbv5Context); + + for(i=0; pNCi[i]; i++) { + if (pNCi[i]->vers != CC_CRED_V5) + continue; + + code = (*pkrb5_cc_resolve)(ctx, pNCi[i]->name, &cache); + + if (code) + continue; + + code = get_tickets_from_cache(ctx, cache); + + if(ctx != NULL && cache != NULL) + (*pkrb5_cc_close)(ctx, cache); + + cache = 0; + } + +_exit: + if (pNCi) + (*pcc_free_NC_info)(cc_ctx, &pNCi); + if (cc_ctx) + (*pcc_shutdown)(&cc_ctx); + + kcdb_credset_collect(NULL, krb5_credset, NULL, credtype_id_krb5, NULL); + + return(code); + +} + +int +khm_krb5_renew(khm_handle identity) +{ + krb5_error_code code = 0; + krb5_context ctx = 0; + krb5_ccache cc = 0; + krb5_principal me = 0; + krb5_principal server = 0; + krb5_creds my_creds; + krb5_data *realm = 0; + + if ( !pkrb5_init_context ) + goto cleanup; + + memset(&my_creds, 0, sizeof(krb5_creds)); + + code = khm_krb5_initialize(identity, &ctx, &cc); + if (code) + goto cleanup; + + code = pkrb5_cc_get_principal(ctx, cc, &me); + if (code) + goto cleanup; + + realm = krb5_princ_realm(ctx, me); + + code = pkrb5_build_principal_ext(ctx, &server, + realm->length,realm->data, + KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, + realm->length,realm->data, + 0); + + if (code) + goto cleanup; + + my_creds.client = me; + my_creds.server = server; + +#ifdef KRB5_TC_NOTICKET + pkrb5_cc_set_flags(ctx, cc, 0); +#endif + code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL); +#ifdef KRB5_TC_NOTICKET + pkrb5_cc_set_flags(ctx, cc, KRB5_TC_NOTICKET); +#endif + if (code) { + if ( code != KRB5KDC_ERR_ETYPE_NOSUPP || + code != KRB5_KDC_UNREACH) + khm_krb5_error(code, "krb5_get_renewed_creds()", 0, &ctx, &cc); + goto cleanup; + } + + code = pkrb5_cc_initialize(ctx, cc, me); + if (code) goto cleanup; + + code = pkrb5_cc_store_cred(ctx, cc, &my_creds); + if (code) goto cleanup; + +cleanup: + if (my_creds.client == me) + my_creds.client = 0; + if (my_creds.server == server) + my_creds.server = 0; + + pkrb5_free_cred_contents(ctx, &my_creds); + + if (me) + pkrb5_free_principal(ctx, me); + if (server) + pkrb5_free_principal(ctx, server); + if (cc) + pkrb5_cc_close(ctx, cc); + if (ctx) + pkrb5_free_context(ctx); + return(code); +} + +int +khm_krb5_kinit(krb5_context alt_ctx, + char * principal_name, + char * password, + char * ccache, + krb5_deltat lifetime, + DWORD forwardable, + DWORD proxiable, + krb5_deltat renew_life, + DWORD addressless, + DWORD publicIP, + krb5_prompter_fct prompter, + void * p_data) +{ + krb5_error_code code = 0; + krb5_context ctx = 0; + krb5_ccache cc = 0; + krb5_principal me = 0; + char* name = 0; + krb5_creds my_creds; + krb5_get_init_creds_opt options; + krb5_address ** addrs = NULL; + int i = 0, addr_count = 0; + + if (!pkrb5_init_context) + return 0; + + pkrb5_get_init_creds_opt_init(&options); + memset(&my_creds, 0, sizeof(my_creds)); + + if (alt_ctx) + { + ctx = alt_ctx; + } + else + { + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + } + +// code = pkrb5_cc_default(ctx, &cc); + if (ccache) + code = pkrb5_cc_resolve(ctx, ccache, &cc); + else + code = pkrb5_cc_resolve(ctx, principal_name, &cc); + if (code) goto cleanup; + + code = pkrb5_parse_name(ctx, principal_name, &me); + if (code) goto cleanup; + + code = pkrb5_unparse_name(ctx, me, &name); + if (code) goto cleanup; + + if (lifetime == 0) { + khc_read_int32(csp_params, L"DefaultLifetime", &lifetime); + } + + if (lifetime) + pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime); + pkrb5_get_init_creds_opt_set_forwardable(&options, + forwardable ? 1 : 0); + pkrb5_get_init_creds_opt_set_proxiable(&options, + proxiable ? 1 : 0); + pkrb5_get_init_creds_opt_set_renew_life(&options, + renew_life); + if (addressless) + pkrb5_get_init_creds_opt_set_address_list(&options,NULL); + else { + if (publicIP) + { + // we are going to add the public IP address specified by the user + // to the list provided by the operating system + krb5_address ** local_addrs=NULL; + DWORD netIPAddr; + + pkrb5_os_localaddr(ctx, &local_addrs); + while ( local_addrs[i++] ); + addr_count = i + 1; + + addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *)); + if ( !addrs ) { + pkrb5_free_addresses(ctx, local_addrs); + assert(0); + } + memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1)); + i = 0; + while ( local_addrs[i] ) { + addrs[i] = (krb5_address *)malloc(sizeof(krb5_address)); + if (addrs[i] == NULL) { + pkrb5_free_addresses(ctx, local_addrs); + assert(0); + } + + addrs[i]->magic = local_addrs[i]->magic; + addrs[i]->addrtype = local_addrs[i]->addrtype; + addrs[i]->length = local_addrs[i]->length; + addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length); + if (!addrs[i]->contents) { + pkrb5_free_addresses(ctx, local_addrs); + assert(0); + } + + memcpy(addrs[i]->contents,local_addrs[i]->contents, + local_addrs[i]->length); /* safe */ + i++; + } + pkrb5_free_addresses(ctx, local_addrs); + + addrs[i] = (krb5_address *)malloc(sizeof(krb5_address)); + if (addrs[i] == NULL) + assert(0); + + addrs[i]->magic = KV5M_ADDRESS; + addrs[i]->addrtype = AF_INET; + addrs[i]->length = 4; + addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length); + if (!addrs[i]->contents) + assert(0); + + netIPAddr = htonl(publicIP); + memcpy(addrs[i]->contents,&netIPAddr,4); + + pkrb5_get_init_creds_opt_set_address_list(&options,addrs); + + } + } + + code = pkrb5_get_init_creds_password(ctx, + &my_creds, + me, + password, // password + prompter, // prompter + p_data, // prompter data + 0, // start time + 0, // service name + &options); + if (code) goto cleanup; + + code = pkrb5_cc_initialize(ctx, cc, me); + if (code) goto cleanup; + + code = pkrb5_cc_store_cred(ctx, cc, &my_creds); + if (code) goto cleanup; + +cleanup: + if ( addrs ) { + for ( i=0;icontents ) + free(addrs[i]->contents); + free(addrs[i]); + } + } + } + if (my_creds.client == me) + my_creds.client = 0; + pkrb5_free_cred_contents(ctx, &my_creds); + if (name) + pkrb5_free_unparsed_name(ctx, name); + if (me) + pkrb5_free_principal(ctx, me); + if (cc) + pkrb5_cc_close(ctx, cc); + if (ctx && (ctx != alt_ctx)) + pkrb5_free_context(ctx); + return(code); +} + +long +khm_krb5_copy_ccache_by_name(krb5_context in_ctx, + wchar_t * wscc_dest, + wchar_t * wscc_src) { + krb5_context ctx = NULL; + krb5_error_code code = 0; + khm_boolean free_ctx; + krb5_ccache cc_src = NULL; + krb5_ccache cc_dest = NULL; + krb5_principal princ_src = NULL; + char scc_dest[KRB5_MAXCCH_CCNAME]; + char scc_src[KRB5_MAXCCH_CCNAME]; + int t; + + t = UnicodeStrToAnsi(scc_dest, sizeof(scc_dest), wscc_dest); + if (t == 0) + return KHM_ERROR_TOO_LONG; + t = UnicodeStrToAnsi(scc_src, sizeof(scc_src), wscc_src); + if (t == 0) + return KHM_ERROR_TOO_LONG; + + if (in_ctx) { + ctx = in_ctx; + free_ctx = FALSE; + } else { + code = pkrb5_init_context(&ctx); + if (code) { + if (ctx) + pkrb5_free_context(ctx); + return code; + } + free_ctx = TRUE; + } + + code = pkrb5_cc_resolve(ctx, scc_dest, &cc_dest); + if (code) + goto _cleanup; + + code = pkrb5_cc_resolve(ctx, scc_src, &cc_src); + if (code) + goto _cleanup; + + code = pkrb5_cc_get_principal(ctx, cc_src, &princ_src); + if (code) + goto _cleanup; + + code = pkrb5_cc_initialize(ctx, cc_dest, princ_src); + if (code) + goto _cleanup; + + code = pkrb5_cc_copy_creds(ctx, cc_src, cc_dest); + + _cleanup: + if (princ_src) + pkrb5_free_principal(ctx, princ_src); + + if (cc_dest) + pkrb5_cc_close(ctx, cc_dest); + + if (cc_src) + pkrb5_cc_close(ctx, cc_src); + + if (free_ctx && ctx) + pkrb5_free_context(ctx); + + return code; +} + +long +khm_krb5_canon_cc_name(wchar_t * wcc_name, + size_t cb_cc_name) { + size_t cb_len; + wchar_t * colon; + + if (FAILED(StringCbLength(wcc_name, + cb_cc_name, + &cb_len))) { +#ifdef DEBUG + assert(FALSE); +#else + return KHM_ERROR_TOO_LONG; +#endif + } + + cb_len += sizeof(wchar_t); + + colon = wcschr(wcc_name, L':'); + + if (colon) + return 0; + + if (cb_len + 4 * sizeof(wchar_t) > cb_cc_name) + return KHM_ERROR_TOO_LONG; + + memmove(&wcc_name[4], &wcc_name[0], cb_len); + memmove(&wcc_name[0], L"API:", sizeof(wchar_t) * 4); + + return 0; +} + +int +khm_krb5_cc_name_cmp(const wchar_t * cc_name_1, + const wchar_t * cc_name_2) { + if (!wcsncmp(cc_name_1, L"API:", 4)) + cc_name_1 += 4; + + if (!wcsncmp(cc_name_2, L"API:", 4)) + cc_name_2 += 4; + + return wcscmp(cc_name_1, cc_name_2); +} + +static khm_int32 KHMAPI +khmint_location_comp_func(khm_handle cred1, + khm_handle cred2, + void * rock) { + return kcdb_creds_comp_attr(cred1, cred2, KCDB_ATTR_LOCATION); +} + +struct khmint_location_check { + khm_handle credset; + khm_handle cred; + wchar_t * ccname; + khm_boolean success; +}; + +static khm_int32 KHMAPI +khmint_find_matching_cred_func(khm_handle cred, + void * rock) { + struct khmint_location_check * lc; + + lc = (struct khmint_location_check *) rock; + + if (!kcdb_creds_is_equal(cred, lc->cred)) + return KHM_ERROR_SUCCESS; + if (kcdb_creds_comp_attr(cred, lc->cred, KCDB_ATTR_LOCATION)) + return KHM_ERROR_SUCCESS; + + /* found it */ + lc->success = TRUE; + + /* break the search */ + return !KHM_ERROR_SUCCESS; +} + +static khm_int32 KHMAPI +khmint_location_check_func(khm_handle cred, + void * rock) { + khm_int32 t; + khm_size cb; + wchar_t ccname[KRB5_MAXCCH_CCNAME]; + struct khmint_location_check * lc; + + lc = (struct khmint_location_check *) rock; + + if (KHM_FAILED(kcdb_cred_get_type(cred, &t))) + return KHM_ERROR_SUCCESS; + + if (t != credtype_id_krb5) + return KHM_ERROR_SUCCESS; + + cb = sizeof(ccname); + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + ccname, + &cb))) + return KHM_ERROR_SUCCESS; + + if(wcscmp(ccname, lc->ccname)) + return KHM_ERROR_SUCCESS; + + lc->cred = cred; + + lc->success = FALSE; + + kcdb_credset_apply(lc->credset, + khmint_find_matching_cred_func, + (void *) lc); + + if (!lc->success) + return KHM_ERROR_NOT_FOUND; + else + return KHM_ERROR_SUCCESS; +} + +static khm_int32 KHMAPI +khmint_delete_location_func(khm_handle cred, + void * rock) { + wchar_t cc_cred[KRB5_MAXCCH_CCNAME]; + struct khmint_location_check * lc; + khm_size cb; + + lc = (struct khmint_location_check *) rock; + + cb = sizeof(cc_cred); + + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + cc_cred, + &cb))) + return KHM_ERROR_SUCCESS; + + if (wcscmp(cc_cred, lc->ccname)) + return KHM_ERROR_SUCCESS; + + kcdb_credset_del_cred_ref(lc->credset, + cred); + + return KHM_ERROR_SUCCESS; +} + +int +khm_krb5_destroy_by_credset(khm_handle p_cs) +{ + khm_handle d_cs = NULL; + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_size s, cb; + krb5_context ctx; + krb5_error_code code = 0; + int i; + wchar_t ccname[KRB5_MAXCCH_CCNAME]; + struct khmint_location_check lc; + + rv = kcdb_credset_create(&d_cs); + + assert(KHM_SUCCEEDED(rv) && d_cs != NULL); + + kcdb_credset_extract(d_cs, p_cs, NULL, credtype_id_krb5); + + kcdb_credset_get_size(d_cs, &s); + + if (s == 0) { + /* nothing to do */ + kcdb_credset_delete(d_cs); + return 0; + } + + code = pkrb5_init_context(&ctx); + if (code != 0) { + rv = code; + goto _cleanup; + } + + /* we should synchronize the credential lists before we attempt to + make any assumptions on the state of the root credset */ + khm_krb5_list_tickets(&ctx); + + /* so, we need to make a decision about whether to destroy entire + ccaches or just individual credentials. Therefore we first + sort them by ccache. */ + kcdb_credset_sort(d_cs, + khmint_location_comp_func, + NULL); + + /* now, for each ccache we encounter, we check if we have all the + credentials from that ccache in the to-be-deleted list. */ + for (i=0; i < (int) s; i++) { + khm_handle cred; + + if (KHM_FAILED(kcdb_credset_get_cred(d_cs, + i, + &cred))) + continue; + + cb = sizeof(ccname); + rv = kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + ccname, + &cb); + +#ifdef DEBUG + assert(KHM_SUCCEEDED(rv)); +#endif + kcdb_cred_release(cred); + + lc.credset = d_cs; + lc.cred = NULL; + lc.ccname = ccname; + lc.success = FALSE; + + kcdb_credset_apply(NULL, + khmint_location_check_func, + (void *) &lc); + + if (lc.success) { + /* ok the destroy the ccache */ + char a_ccname[KRB5_MAXCCH_CCNAME]; + krb5_ccache cc = NULL; + + UnicodeStrToAnsi(a_ccname, + sizeof(a_ccname), + ccname); + + code = pkrb5_cc_resolve(ctx, + a_ccname, + &cc); + if (code) + goto _delete_this_set; + + code = pkrb5_cc_destroy(ctx, cc); + + if (code) { + /*TODO: report error */ + } + + _delete_this_set: + + lc.credset = d_cs; + lc.ccname = ccname; + + /* note that although we are deleting credentials off the + credential set, the size of the credential set does not + decrease since we are doing it from inside + kcdb_credset_apply(). The deleted creds will simply be + marked as deleted until kcdb_credset_purge() is + called. */ + + kcdb_credset_apply(d_cs, + khmint_delete_location_func, + (void *) &lc); + } + } + + kcdb_credset_purge(d_cs); + + /* the remainder need to be deleted one by one */ + + kcdb_credset_get_size(d_cs, &s); + + for (i=0; i < (int) s; ) { + khm_handle cred; + char a_ccname[KRB5_MAXCCH_CCNAME]; + char a_srvname[KCDB_CRED_MAXCCH_NAME]; + wchar_t srvname[KCDB_CRED_MAXCCH_NAME]; + krb5_ccache cc; + krb5_creds in_cred, out_cred; + krb5_principal princ; + khm_int32 etype; + + if (KHM_FAILED(kcdb_credset_get_cred(d_cs, + i, + &cred))) { + i++; + continue; + } + + cb = sizeof(ccname); + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + ccname, + &cb))) + goto _done_with_this_cred; + + UnicodeStrToAnsi(a_ccname, + sizeof(a_ccname), + ccname); + + code = pkrb5_cc_resolve(ctx, + a_ccname, + &cc); + + if (code) + goto _skip_similar; + + code = pkrb5_cc_get_principal(ctx, cc, &princ); + + if (code) { + pkrb5_cc_close(ctx, cc); + goto _skip_similar; + } + + _del_this_cred: + + cb = sizeof(etype); + + if (KHM_FAILED(kcdb_cred_get_attr(cred, + attr_id_key_enctype, + NULL, + &etype, + &cb))) + goto _do_next_cred; + + cb = sizeof(srvname); + if (KHM_FAILED(kcdb_cred_get_name(cred, + srvname, + &cb))) + goto _do_next_cred; + + UnicodeStrToAnsi(a_srvname, sizeof(a_srvname), srvname); + + ZeroMemory(&in_cred, sizeof(in_cred)); + + code = pkrb5_parse_name(ctx, a_srvname, &in_cred.server); + if (code) + goto _do_next_cred; + in_cred.client = princ; + in_cred.keyblock.enctype = etype; + + code = pkrb5_cc_retrieve_cred(ctx, + cc, + KRB5_TC_MATCH_SRV_NAMEONLY | + KRB5_TC_SUPPORTED_KTYPES, + &in_cred, + &out_cred); + if (code) + goto _do_next_cred_0; + + code = pkrb5_cc_remove_cred(ctx, cc, + KRB5_TC_MATCH_SRV_NAMEONLY | + KRB5_TC_SUPPORTED_KTYPES | + KRB5_TC_MATCH_AUTHDATA, + &out_cred); + + pkrb5_free_cred_contents(ctx, &out_cred); + _do_next_cred_0: + pkrb5_free_principal(ctx, in_cred.server); + _do_next_cred: + + /* check if the next cred is also of the same ccache */ + kcdb_cred_release(cred); + + for (i++; i < (int) s; i++) { + if (KHM_FAILED(kcdb_credset_get_cred(d_cs, + i, + &cred))) + continue; + } + + if (i < (int) s) { + wchar_t newcc[KRB5_MAXCCH_CCNAME]; + + cb = sizeof(newcc); + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + newcc, + &cb)) || + wcscmp(newcc, ccname)) { + i--; /* we have to look at this again */ + goto _done_with_this_set; + } + goto _del_this_cred; + } + + + _done_with_this_set: + pkrb5_free_principal(ctx, princ); + + pkrb5_cc_close(ctx, cc); + + _done_with_this_cred: + kcdb_cred_release(cred); + i++; + continue; + + _skip_similar: + kcdb_cred_release(cred); + + for (++i; i < (int) s; i++) { + wchar_t newcc[KRB5_MAXCCH_CCNAME]; + + if (KHM_FAILED(kcdb_credset_get_cred(d_cs, + i, + &cred))) + continue; + + cb = sizeof(newcc); + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + &newcc, + &cb))) { + kcdb_cred_release(cred); + continue; + } + + if (wcscmp(newcc, ccname)) { + kcdb_cred_release(cred); + break; + } + } + } + + _cleanup: + + if (d_cs) + kcdb_credset_delete(&d_cs); + + return rv; +} + +int +khm_krb5_destroy_identity(khm_handle identity) +{ + krb5_context ctx; + krb5_ccache cache; + krb5_error_code rc; + + ctx = NULL; + cache = NULL; + + if (rc = khm_krb5_initialize(identity, &ctx, &cache)) + return(rc); + + rc = pkrb5_cc_destroy(ctx, cache); + + if (ctx != NULL) + pkrb5_free_context(ctx); + + return(rc); +} + +static BOOL +GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData) +{ + NTSTATUS Status = 0; + HANDLE TokenHandle; + TOKEN_STATISTICS Stats; + DWORD ReqLen; + BOOL Success; + + if (!ppSessionData) + return FALSE; + *ppSessionData = NULL; + + Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle ); + if ( !Success ) + return FALSE; + + Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen ); + CloseHandle( TokenHandle ); + if ( !Success ) + return FALSE; + + Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData ); + if ( FAILED(Status) || !ppSessionData ) + return FALSE; + + return TRUE; +} + +// IsKerberosLogon() does not validate whether or not there are valid +// tickets in the cache. It validates whether or not it is reasonable +// to assume that if we attempted to retrieve valid tickets we could +// do so. Microsoft does not automatically renew expired tickets. +// Therefore, the cache could contain expired or invalid tickets. +// Microsoft also caches the user's password and will use it to +// retrieve new TGTs if the cache is empty and tickets are requested. + +static BOOL +IsKerberosLogon(VOID) +{ + PSECURITY_LOGON_SESSION_DATA pSessionData = NULL; + BOOL Success = FALSE; + + if ( GetSecurityLogonSessionData(&pSessionData) ) { + if ( pSessionData->AuthenticationPackage.Buffer ) { + WCHAR buffer[256]; + WCHAR *usBuffer; + int usLength; + + Success = FALSE; + usBuffer = (pSessionData->AuthenticationPackage).Buffer; + usLength = (pSessionData->AuthenticationPackage).Length; + if (usLength < 256) + { + lstrcpynW (buffer, usBuffer, usLength); + StringCbCatW (buffer, sizeof(buffer), L""); + if ( !lstrcmpW(L"Kerberos",buffer) ) + Success = TRUE; + } + } + pLsaFreeReturnBuffer(pSessionData); + } + return Success; +} + + +BOOL +khm_krb5_ms2mit(BOOL save_creds) +{ +#ifdef NO_KRB5 + return(FALSE); +#else /* NO_KRB5 */ + krb5_context kcontext = 0; + krb5_error_code code; + krb5_ccache ccache=0; + krb5_ccache mslsa_ccache=0; + krb5_creds creds; + krb5_cc_cursor cursor=0; + krb5_principal princ = 0; + char *cache_name = NULL; + char *princ_name = NULL; + BOOL rc = FALSE; + + if ( !pkrb5_init_context ) + goto cleanup; + + if (code = pkrb5_init_context(&kcontext)) + goto cleanup; + + if (code = pkrb5_cc_resolve(kcontext, "MSLSA:", &mslsa_ccache)) + goto cleanup; + + if ( save_creds ) { + if (code = pkrb5_cc_get_principal(kcontext, mslsa_ccache, &princ)) + goto cleanup; + + if (code = pkrb5_unparse_name(kcontext, princ, &princ_name)) + goto cleanup; + + /* TODO: actually look up the preferred ccache name */ + if ((code = pkrb5_cc_resolve(kcontext, princ_name, &ccache)) || + (code = pkrb5_cc_default(kcontext, &ccache))) + goto cleanup; + + if (code = pkrb5_cc_initialize(kcontext, ccache, princ)) + goto cleanup; + + if (code = pkrb5_cc_copy_creds(kcontext, mslsa_ccache, ccache)) + goto cleanup; + + rc = TRUE; + } else { + /* Enumerate tickets from cache looking for an initial ticket */ + if ((code = pkrb5_cc_start_seq_get(kcontext, mslsa_ccache, &cursor))) + goto cleanup; + + while (!(code = pkrb5_cc_next_cred(kcontext, mslsa_ccache, &cursor, &creds))) + { + if ( creds.ticket_flags & TKT_FLG_INITIAL ) { + rc = TRUE; + pkrb5_free_cred_contents(kcontext, &creds); + break; + } + pkrb5_free_cred_contents(kcontext, &creds); + } + pkrb5_cc_end_seq_get(kcontext, mslsa_ccache, &cursor); + } + +cleanup: + if (princ_name) + pkrb5_free_unparsed_name(kcontext, princ_name); + if (princ) + pkrb5_free_principal(kcontext, princ); + if (ccache) + pkrb5_cc_close(kcontext, ccache); + if (mslsa_ccache) + pkrb5_cc_close(kcontext, mslsa_ccache); + if (kcontext) + pkrb5_free_context(kcontext); + return(rc); +#endif /* NO_KRB5 */ +} + +#define KRB_FILE "KRB.CON" +#define KRBREALM_FILE "KRBREALM.CON" +#define KRB5_FILE "KRB5.INI" + +BOOL +khm_get_profile_file(LPSTR confname, UINT szConfname) +{ + char **configFile = NULL; + if (pkrb5_get_default_config_files(&configFile)) + { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + return FALSE; + } + + *confname = 0; + + if (configFile) + { + strncpy(confname, *configFile, szConfname); + pkrb5_free_config_files(configFile); + } + + if (!*confname) + { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + } + + return FALSE; +} + +BOOL +khm_get_krb4_con_file(LPSTR confname, UINT szConfname) +{ + if (hKrb5 && !hKrb4) { // hold krb.con where krb5.ini is located + CHAR krbConFile[MAX_PATH]=""; + LPSTR pFind; + + //strcpy(krbConFile, CLeashApp::m_krbv5_profile->first_file->filename); + if (khm_get_profile_file(krbConFile, sizeof(krbConFile))) { + GetWindowsDirectoryA(krbConFile,sizeof(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, KRB5_FILE,sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + } + + pFind = strrchr(krbConFile, '\\'); + if (pFind) { + *pFind = 0; + strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, KRB_FILE,sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + } + else + krbConFile[0] = 0; + + strncpy(confname, krbConFile, szConfname); + confname[szConfname-1] = '\0'; + } + else if (hKrb4) { + unsigned int size = szConfname; + memset(confname, '\0', szConfname); + if (!pkrb_get_krbconf2(confname, &size)) + { // Error has happened + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",szConfname-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname,KRB_FILE,szConfname-strlen(confname)); + confname[szConfname-1] = '\0'; + } + } + return FALSE; +} + +int +readstring(FILE * file, char * buf, int len) +{ + int c,i; + memset(buf, '\0', sizeof(buf)); + for (i=0, c=fgetc(file); c != EOF ; c=fgetc(file), i++) { + if (i < sizeof(buf)) { + if (c == '\n') { + buf[i] = '\0'; + return i; + } else { + buf[i] = c; + } + } else { + if (c == '\n') { + buf[len-1] = '\0'; + return(i); + } + } + } + if (c == EOF) { + if (i > 0 && i < len) { + buf[i] = '\0'; + return(i); + } else { + buf[len-1] = '\0'; + return(-1); + } + } + return(-1); +} + +/*! \internal + \brief Return a list of configured realms + + The string that is returned is a set of null terminated unicode + strings, each of which denotes one realm. The set is terminated + by a zero length null terminated string. + + The caller should free the returned string using free() + + \return The string with the list of realms or NULL if the + operation fails. +*/ +wchar_t * khm_krb5_get_realm_list(void) +{ + wchar_t * rlist = NULL; + + if (pprofile_get_subsection_names && pprofile_free_list) { + const char* rootSection[] = {"realms", NULL}; + const char** rootsec = rootSection; + char **sections = NULL, **cpp = NULL, *value = NULL; + + char krb5_conf[MAX_PATH+1]; + + if (!khm_get_profile_file(krb5_conf,sizeof(krb5_conf))) { + profile_t profile; + long retval; + const char *filenames[2]; + wchar_t * d; + size_t cbsize; + size_t t; + + filenames[0] = krb5_conf; + filenames[1] = NULL; + retval = pprofile_init(filenames, &profile); + if (!retval) { + retval = pprofile_get_subsection_names(profile, rootsec, + §ions); + + if (!retval) + { + /* first figure out how much space to allocate */ + cbsize = 0; + for (cpp = sections; *cpp; cpp++) + { + cbsize += sizeof(wchar_t) * (strlen(*cpp) + 1); + } + cbsize += sizeof(wchar_t); /* double null terminated */ + + rlist = malloc(cbsize); + d = rlist; + for (cpp = sections; *cpp; cpp++) + { + AnsiStrToUnicode(d, cbsize, *cpp); + t = wcslen(d) + 1; + d += t; + cbsize -= sizeof(wchar_t) * t; + } + *d = L'\0'; + } + + pprofile_free_list(sections); + +#if 0 + retval = pprofile_get_string(profile, "libdefaults","noaddresses", 0, "true", &value); + if ( value ) { + disable_noaddresses = config_boolean_to_int(value); + pprofile_release_string(value); + } +#endif + pprofile_release(profile); + } + } + } else { + FILE * file; + char krb_conf[MAX_PATH+1]; + char * p; + size_t cbsize, t; + wchar_t * d; + + if (!khm_get_krb4_con_file(krb_conf,sizeof(krb_conf)) && + (file = fopen(krb_conf, "rt"))) + { + char lineBuf[256]; + + /*TODO: compute the actual required buffer size instead of hardcoding */ + cbsize = 16384; // arbitrary + rlist = malloc(cbsize); + d = rlist; + + // Skip the default realm + readstring(file,lineBuf,sizeof(lineBuf)); + + // Read the defined realms + while (TRUE) + { + if (readstring(file,lineBuf,sizeof(lineBuf)) < 0) + break; + + if (*(lineBuf + strlen(lineBuf) - 1) == '\r') + *(lineBuf + strlen(lineBuf) - 1) = 0; + + for (p=lineBuf; *p ; p++) + { + if (isspace(*p)) { + *p = 0; + break; + } + } + + if ( strncmp(".KERBEROS.OPTION.",lineBuf,17) ) { + t = strlen(lineBuf) + 1; + if(cbsize > (1 + t*sizeof(wchar_t))) { + AnsiStrToUnicode(d, cbsize, lineBuf); + d += t; + cbsize -= t * sizeof(wchar_t); + } else + break; + } + } + + *d = L'\0'; + + fclose(file); + } + } + + return rlist; +} + +/*! \internal + \brief Get the default realm + + A string will be returned that specifies the default realm. The + caller should free the string using free(). + + Returns NULL if the operation fails. +*/ +wchar_t * khm_krb5_get_default_realm(void) +{ + wchar_t * realm; + size_t cch; + krb5_context ctx=0; + char * def = 0; + + pkrb5_init_context(&ctx); + pkrb5_get_default_realm(ctx,&def); + + if (def) { + cch = strlen(def) + 1; + realm = malloc(sizeof(wchar_t) * cch); + AnsiStrToUnicode(realm, sizeof(wchar_t) * cch, def); + pkrb5_free_default_realm(ctx, def); + } else + realm = NULL; + + pkrb5_free_context(ctx); + + return realm; +} + +wchar_t * khm_get_realm_from_princ(wchar_t * princ) { + wchar_t * t; + + if(!princ) + return NULL; + + for (t = princ; *t; t++) { + if(*t == L'\\') { /* escape */ + t++; + if(! *t) /* malformed */ + break; + } else if (*t == L'@') + break; + } + + if (*t == '@' && *(t+1) != L'\0') + return (t+1); + else + return NULL; +} + +long +khm_krb5_changepwd(char * principal, + char * password, + char * newpassword, + char** error_str) +{ + krb5_error_code rc = 0; + int result_code; + krb5_data result_code_string, result_string; + krb5_context context = 0; + krb5_principal princ = 0; + krb5_get_init_creds_opt opts; + krb5_creds creds; + + result_string.data = 0; + result_code_string.data = 0; + + if ( !pkrb5_init_context ) + goto cleanup; + + if (rc = pkrb5_init_context(&context)) { + goto cleanup; + } + + if (rc = pkrb5_parse_name(context, principal, &princ)) { + goto cleanup; + } + + pkrb5_get_init_creds_opt_init(&opts); + pkrb5_get_init_creds_opt_set_tkt_life(&opts, 5*60); + pkrb5_get_init_creds_opt_set_renew_life(&opts, 0); + pkrb5_get_init_creds_opt_set_forwardable(&opts, 0); + pkrb5_get_init_creds_opt_set_proxiable(&opts, 0); + pkrb5_get_init_creds_opt_set_address_list(&opts,NULL); + + if (rc = pkrb5_get_init_creds_password(context, &creds, princ, + password, 0, 0, 0, + "kadmin/changepw", &opts)) { + if (rc == KRB5KRB_AP_ERR_BAD_INTEGRITY) { +#if 0 + com_err(argv[0], 0, + "Password incorrect while getting initial ticket"); +#endif + } + else { +#if 0 + com_err(argv[0], ret, "getting initial ticket"); +#endif + } + goto cleanup; + } + + if (rc = pkrb5_change_password(context, &creds, newpassword, + &result_code, &result_code_string, + &result_string)) { +#if 0 + com_err(argv[0], ret, "changing password"); +#endif + goto cleanup; + } + + if (result_code) { + int len = result_code_string.length + + (result_string.length ? (sizeof(": ") - 1) : 0) + + result_string.length; + if (len && error_str) { + *error_str = malloc(len + 1); + if (*error_str) + StringCchPrintfA(*error_str, len+1, + "%.*s%s%.*s", + result_code_string.length, + result_code_string.data, + result_string.length?": ":"", + result_string.length, + result_string.data); + } + rc = result_code; + goto cleanup; + } + + cleanup: + if (result_string.data) + pkrb5_free_data_contents(context, &result_string); + + if (result_code_string.data) + pkrb5_free_data_contents(context, &result_code_string); + + if (princ) + pkrb5_free_principal(context, princ); + + if (context) + pkrb5_free_context(context); + + return rc; +} diff --git a/src/windows/identity/plugins/krb5/krb5funcs.h b/src/windows/identity/plugins/krb5/krb5funcs.h new file mode 100644 index 0000000000..79ca95646a --- /dev/null +++ b/src/windows/identity/plugins/krb5/krb5funcs.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* Adapted from multiple Leash header files */ + +#ifndef __KHIMAIRA_KRB5FUNCS_H +#define __KHIMAIRA_KRB5FUNCS_H + +#include +#include + +#include +#define SECURITY_WIN32 +#include +#include + +#include + +#define LEASH_DEBUG_CLASS_GENERIC 0 +#define LEASH_DEBUG_CLASS_KRB4 1 +#define LEASH_DEBUG_CLASS_KRB4_APP 2 + +#define LEASH_PRIORITY_LOW 0 +#define LEASH_PRIORITY_HIGH 1 + +#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ + +#define KRB5_MAXCCH_CCNAME 1024 + +// Function Prototypes. + +BOOL +khm_krb5_ms2mit(BOOL); + +int +khm_krb5_kinit(krb5_context alt_ctx, + char * principal_name, + char * password, + char * ccache, + krb5_deltat lifetime, + DWORD forwardable, + DWORD proxiable, + krb5_deltat renew_life, + DWORD addressless, + DWORD publicIP, + krb5_prompter_fct prompter, + void * p_data); + +long +khm_krb5_changepwd(char * principal, + char * password, + char * newpassword, + char** error_str); + +int +khm_krb5_destroy_by_credset(khm_handle p_cs); + +int +khm_krb5_destroy_identity(khm_handle identity); + +long +khm_convert524(krb5_context ctx); + +int +khm_krb5_renew(khm_handle identity); + +wchar_t * +khm_krb5_get_default_realm(void); + +wchar_t * +khm_krb5_get_realm_list(void); + +long +khm_krb5_list_tickets(krb5_context *krbv5Context); + +long +khm_krb4_list_tickets(void); + +wchar_t * +khm_get_realm_from_princ(wchar_t * princ); + +long +khm_krb5_copy_ccache_by_name(krb5_context in_ctx, + wchar_t * wscc_dest, + wchar_t * wscc_src); + +long +khm_krb5_canon_cc_name(wchar_t * wcc_name, + size_t cb_cc_name); + +int +khm_krb5_cc_name_cmp(const wchar_t * cc_name_1, + const wchar_t * cc_name_2); + +BOOL +khm_get_profile_file(LPSTR confname, UINT szConfname); + +#endif diff --git a/src/windows/identity/plugins/krb5/krb5identpro.c b/src/windows/identity/plugins/krb5/krb5identpro.c new file mode 100644 index 0000000000..c568e49d03 --- /dev/null +++ b/src/windows/identity/plugins/krb5/krb5identpro.c @@ -0,0 +1,1108 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include +#include + +#define K5_NCID_UN_LABEL (KHUI_CW_ID_MIN + 0) +#define K5_NCID_UN (KHUI_CW_ID_MIN + 1) +#define K5_NCID_REALM_LABEL (KHUI_CW_ID_MIN + 2) +#define K5_NCID_REALM (KHUI_CW_ID_MIN + 3) + +#define NC_UNCHANGE_TIMEOUT 3000 +#define NC_UNCHANGE_TIMER 2 +#define NC_REALMCHANGE_TIMEOUT NC_UNCHANGE_TIMEOUT +#define NC_REALMCHANGE_TIMER 3 + +typedef struct tag_k5_new_cred_data { + HWND hw_username_label; + HWND hw_username; + HWND hw_realm_label; + HWND hw_realm; +} k5_new_cred_data; + +int +k5_get_realm_from_nc(khui_new_creds * nc, + wchar_t * buf, + khm_size cch_buf) { + k5_new_cred_data * d; + + d = (k5_new_cred_data *) nc->ident_aux; + return GetWindowText(d->hw_realm, buf, (int) cch_buf); +} + +/* set the primary identity of a new credentials dialog depending on + the selection of the username and realm + + Runs in the UI thread +*/ +static void +set_identity_from_ui(khui_new_creds * nc, + k5_new_cred_data * d) { + wchar_t un[KCDB_IDENT_MAXCCH_NAME]; + wchar_t * realm; + khm_size cch; + khm_size cch_left; + khm_handle ident; + LRESULT idx = CB_ERR; + + cch = GetWindowTextLength(d->hw_username); + + /* we already set the max length of the edit control to be this. + shouldn't exceed it unless the edit control is confused. */ + assert(cch < KCDB_IDENT_MAXCCH_NAME - 1); + + GetWindowText(d->hw_username, un, ARRAYLENGTH(un)); + + realm = khm_get_realm_from_princ(un); + if (realm) /* realm was specified */ + goto _set_ident; + + /* the cch we got from GetWindowTextLength can not be trusted to + be exact. For caveats see MSDN for GetWindowTextLength. */ + StringCchLength(un, KCDB_IDENT_MAXCCH_NAME, &cch); + + realm = un + cch; /* now points at terminating NULL */ + cch_left = KCDB_IDENT_MAXCCH_NAME - cch; + + *realm++ = L'@'; + cch_left--; + + cch = GetWindowTextLength(d->hw_realm); + if (cch == 0 || cch >= cch_left) + goto _set_null_ident; + + GetWindowText(d->hw_realm, realm, (int) cch_left); + + _set_ident: + if (KHM_FAILED(kcdb_identity_create(un, + KCDB_IDENT_FLAG_CREATE, + &ident))) + goto _set_null_ident; + + khui_cw_set_primary_id(nc, ident); + + kcdb_identity_release(ident); + return; + + _set_null_ident: + khui_cw_set_primary_id(nc, NULL); + return; +} + +static BOOL +update_crossfeed(khui_new_creds * nc, + k5_new_cred_data * d, + int ctrl_id_src) { + wchar_t un[KCDB_IDENT_MAXCCH_NAME]; + wchar_t * un_realm; + wchar_t realm[KCDB_IDENT_MAXCCH_NAME]; + khm_size cch; + khm_size cch_left; + + cch = (khm_size) GetWindowTextLength(d->hw_username); +#ifdef DEBUG + assert(cch < KCDB_IDENT_MAXCCH_NAME); +#endif + if (cch == 0) + return FALSE; + + GetWindowText(d->hw_username, + un, + ARRAYLENGTH(un)); + + un_realm = khm_get_realm_from_princ(un); + + if (un_realm == NULL) + return FALSE; + + if (ctrl_id_src == K5_NCID_UN) { + SendMessage(d->hw_realm, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) un_realm); + + SetWindowText(d->hw_realm, + un_realm); + + return TRUE; + } + /* else... */ + + cch_left = KCDB_IDENT_MAXCCH_NAME - (un_realm - un); + + cch = (khm_size) GetWindowTextLength(d->hw_realm); + +#ifdef DEBUG + assert(cch < KCDB_IDENT_MAXCCH_NAME); +#endif + if (cch == 0) + return FALSE; + + GetWindowText(d->hw_realm, realm, + ARRAYLENGTH(realm)); + + StringCchCopy(un_realm, cch_left, realm); + + SendMessage(d->hw_username, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) un); + + SetWindowText(d->hw_username, un); + + return TRUE; +} + +/* Handle window messages for the identity specifiers + + runs in UI thread */ +static LRESULT +handle_wnd_msg(khui_new_creds * nc, + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + k5_new_cred_data * d; + + d = (k5_new_cred_data *) nc->ident_aux; + + switch(uMsg) { + case WM_COMMAND: + switch(wParam) { + case MAKEWPARAM(K5_NCID_UN, CBN_EDITCHANGE): + /* the username has changed. Instead of handling this + for every keystroke, set a timer that elapses some + time afterwards and then handle the event. */ + SetTimer(hwnd, NC_UNCHANGE_TIMER, + NC_UNCHANGE_TIMEOUT, NULL); + return TRUE; + + case MAKEWPARAM(K5_NCID_UN, CBN_KILLFOCUS): + case MAKEWPARAM(K5_NCID_UN, CBN_CLOSEUP): + KillTimer(hwnd, NC_UNCHANGE_TIMER); + + update_crossfeed(nc,d,K5_NCID_UN); + set_identity_from_ui(nc,d); + return TRUE; + + case MAKEWPARAM(K5_NCID_REALM,CBN_EDITCHANGE): + SetTimer(hwnd, NC_REALMCHANGE_TIMER, + NC_REALMCHANGE_TIMEOUT, NULL); + return TRUE; + + case MAKEWPARAM(K5_NCID_REALM,CBN_KILLFOCUS): + case MAKEWPARAM(K5_NCID_REALM,CBN_CLOSEUP): + KillTimer(hwnd, NC_REALMCHANGE_TIMER); + + update_crossfeed(nc,d,K5_NCID_REALM); + set_identity_from_ui(nc, d); + return TRUE; + } + break; + + case WM_TIMER: + if(wParam == NC_UNCHANGE_TIMER) { + KillTimer(hwnd, NC_UNCHANGE_TIMER); + + update_crossfeed(nc, d, K5_NCID_UN); + set_identity_from_ui(nc,d); + return TRUE; + } else if (wParam == NC_REALMCHANGE_TIMER) { + KillTimer(hwnd, NC_REALMCHANGE_TIMER); + + update_crossfeed(nc, d, K5_NCID_REALM); + set_identity_from_ui(nc, d); + return TRUE; + } + break; + } + return FALSE; +} + +/* UI Callback + + runs in UI thread */ +static LRESULT KHMAPI +ui_cb(khui_new_creds * nc, + UINT cmd, + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + k5_new_cred_data * d; + + d = (k5_new_cred_data *) nc->ident_aux; + + switch(cmd) { + case WMNC_IDENT_INIT: + { + wchar_t defident[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wbuf[1024]; + wchar_t * ms = NULL; + wchar_t * t; + wchar_t * defrealm = NULL; + LRESULT lr; + khm_size cb_ms; + khm_size cb; + HWND hw_parent; + khm_int32 rv; + khm_handle hident; + + hw_parent = (HWND) lParam; + defident[0] = L'\0'; + +#ifdef DEBUG + assert(d == NULL); + assert(hw_parent != NULL); +#endif + + d = malloc(sizeof(*d)); + assert(d); + ZeroMemory(d, sizeof(*d)); + + khui_cw_lock_nc(nc); + nc->ident_aux = (LPARAM) d; + khui_cw_unlock_nc(nc); + + LoadString(hResModule, IDS_NC_USERNAME, + wbuf, ARRAYLENGTH(wbuf)); + + d->hw_username_label = CreateWindow + (L"STATIC", + wbuf, + SS_SIMPLE | WS_CHILD | WS_VISIBLE, + 0, 0, 100, 100, /* bogus values */ + hw_parent, + (HMENU) K5_NCID_UN_LABEL, + hInstance, + NULL); + assert(d->hw_username_label != NULL); + + d->hw_username = CreateWindow + (L"COMBOBOX", + L"", + CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | + WS_CHILD | WS_VISIBLE | WS_TABSTOP, + 0, 0, 100, 100, /* bogus values */ + hw_parent, + (HMENU) K5_NCID_UN, + hInstance, + NULL); + assert(d->hw_username != NULL); + + SendMessage(d->hw_username, + CB_LIMITTEXT, + (WPARAM)(KCDB_IDENT_MAXCCH_NAME - 1), + 0); + + SendMessage(d->hw_username, + CB_SETEXTENDEDUI, + (WPARAM) TRUE, + 0); + + khui_cw_add_control_row(nc, + d->hw_username_label, + d->hw_username, + KHUI_CTRLSIZE_SMALL); + + LoadString(hResModule, IDS_NC_REALM, + wbuf, ARRAYLENGTH(wbuf)); + + d->hw_realm_label = CreateWindow + (L"STATIC", + wbuf, + SS_SIMPLE | WS_CHILD | WS_VISIBLE, + 0, 0, 100, 100, /* bogus */ + hw_parent, + (HMENU) K5_NCID_REALM_LABEL, + hInstance, + NULL); + assert(d->hw_realm_label != NULL); + + d->hw_realm = CreateWindow + (L"COMBOBOX", + L"", + CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | + WS_CHILD | WS_VISIBLE | WS_TABSTOP, + 0, 0, 100, 100, /* bogus */ + hw_parent, + (HMENU) K5_NCID_REALM, + hInstance, + NULL); + assert(d->hw_realm != NULL); + + SendMessage(d->hw_realm, + CB_LIMITTEXT, + (WPARAM) (KCDB_IDENT_MAXCCH_NAME - 1), + 0); + + SendMessage(d->hw_realm, + CB_SETEXTENDEDUI, + (WPARAM) TRUE, + 0); + + khui_cw_add_control_row(nc, + d->hw_realm_label, + d->hw_realm, + KHUI_CTRLSIZE_SMALL); + + /* add the LRU realms and principals to the dropdown + lists */ + rv = khc_read_multi_string(csp_params, + L"LRUPrincipals", + NULL, + &cb_ms); + + if (rv != KHM_ERROR_TOO_LONG) + goto _add_lru_realms; + + ms = malloc(cb_ms); + assert(ms != NULL); + + cb = cb_ms; + rv = khc_read_multi_string(csp_params, + L"LRUPrincipals", + ms, + &cb); + + assert(KHM_SUCCEEDED(rv)); + + /* the first of these is considered the default identity + if no other default is known */ + StringCbCopy(defident, sizeof(defident), ms); + + t = ms; + while(t && *t) { + SendMessage(d->hw_username, + CB_ADDSTRING, + 0, + (LPARAM) t); + + t = multi_string_next(t); + } + + _add_lru_realms: + /* add the default realm first */ + defrealm = khm_krb5_get_default_realm(); + if (defrealm) { + SendMessage(d->hw_realm, + CB_ADDSTRING, + 0, + (LPARAM) defrealm); + } + + rv = khc_read_multi_string(csp_params, + L"LRURealms", + NULL, + &cb); + + if (rv != KHM_ERROR_TOO_LONG) + goto _done_adding_lru; + + if (ms != NULL) { + if (cb_ms < cb) { + free(ms); + ms = malloc(cb); + assert(ms); + cb_ms = cb; + } + } else { + ms = malloc(cb); + cb_ms = cb; + } + + rv = khc_read_multi_string(csp_params, + L"LRURealms", + ms, + &cb); + + assert(KHM_SUCCEEDED(rv)); + + for (t = ms; t && *t; t = multi_string_next(t)) { + lr = SendMessage(d->hw_realm, + CB_FINDSTRINGEXACT, + (WPARAM) -1, + (LPARAM) t); + if (lr != CB_ERR) + continue; + + SendMessage(d->hw_realm, + CB_ADDSTRING, + 0, + (LPARAM) t); + } + + _done_adding_lru: + /* set the current selection of the realms list */ + if (defrealm) { + SendMessage(d->hw_realm, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) defrealm); + } else { + SendMessage(d->hw_realm, + CB_SETCURSEL, + (WPARAM) 0, + (LPARAM) 0); + } + + if (defrealm) + free(defrealm); + + if (ms) + free(ms); + + /* now see about that default identity */ + if (nc->ctx.identity) { + cb = sizeof(defident); + kcdb_identity_get_name(nc->ctx.identity, + defident, + &cb); + } + + if (defident[0] == L'\0' && + KHM_SUCCEEDED(kcdb_identity_get_default(&hident))) { + cb = sizeof(defident); + kcdb_identity_get_name(hident, defident, &cb); + kcdb_identity_release(hident); + } + + if (defident[0] == L'\0') { + DWORD dw; + + dw = ARRAYLENGTH(defident); + GetUserName(defident, &dw); + } + + t = khm_get_realm_from_princ(defident); + if (t) { + /* there is a realm */ + assert(t != defident); + *--t = L'\0'; + t++; + + SendMessage(d->hw_realm, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) t); + + SendMessage(d->hw_realm, + WM_SETTEXT, + 0, + (LPARAM) t); + } + + if (defident[0] != L'\0') { + /* there is a username */ + SendMessage(d->hw_username, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) defident); + + SendMessage(d->hw_username, + WM_SETTEXT, + 0, + (LPARAM) defident); + } + + set_identity_from_ui(nc, d); + } + return TRUE; + + case WMNC_IDENT_WMSG: + return handle_wnd_msg(nc, hwnd, uMsg, wParam, lParam); + + case WMNC_IDENT_EXIT: + { +#ifdef DEBUG + assert(d != NULL); +#endif + khui_cw_lock_nc(nc); + nc->ident_aux = 0; + khui_cw_unlock_nc(nc); + + /* since we created all the windows as child windows of + the new creds window, they will be destroyed when that + window is destroyed. */ + free(d); + } + return TRUE; + } + return FALSE; +} + +static khm_int32 +k5_ident_valiate_name(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + krb5_principal princ = NULL; + char princ_name[KCDB_IDENT_MAXCCH_NAME]; + kcdb_ident_name_xfer * nx; + krb5_error_code code; + + nx = (kcdb_ident_name_xfer *) vparam; + + if(UnicodeStrToAnsi(princ_name, sizeof(princ_name), + nx->name_src) == 0) { + nx->result = KHM_ERROR_INVALID_NAME; + return KHM_ERROR_SUCCESS; + } + + assert(k5_identpro_ctx != NULL); + + code = pkrb5_parse_name(k5_identpro_ctx, + princ_name, + &princ); + + if (code) { + nx->result = KHM_ERROR_INVALID_NAME; + return KHM_ERROR_SUCCESS; + } + + if (princ != NULL) + pkrb5_free_principal(k5_identpro_ctx, + princ); + + nx->result = KHM_ERROR_SUCCESS; + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +k5_ident_set_default(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + + /* Logic for setting the default identity: + + When setting identity I as the default; + + - If KRB5CCNAME is set + - If I["Krb5CCName"] == %KRB5CCNAME% + - do nothing + - Else + - Copy the contents of I["Krb5CCName"] to %KRB5CCNAME + - Set I["Krb5CCName"] to %KRB5CCNAME + - Else + - Set HKCU\Software\MIT\kerberos5,ccname to + "API:".I["Krb5CCName"] + */ + + if (uparam) { + /* an identity is being made default */ + khm_handle def_ident = (khm_handle) vparam; + wchar_t env_ccname[KRB5_MAXCCH_CCNAME]; + wchar_t id_ccname[KRB5_MAXCCH_CCNAME]; + khm_size cb; + DWORD dw; + LONG l; + +#ifdef DEBUG + assert(def_ident != NULL); +#endif + + cb = sizeof(id_ccname); + if (KHM_FAILED(kcdb_identity_get_attr(def_ident, + attr_id_krb5_ccname, + NULL, + id_ccname, + &cb))) + return KHM_ERROR_UNKNOWN; + + khm_krb5_canon_cc_name(id_ccname, sizeof(id_ccname)); + + StringCbLength(id_ccname, sizeof(id_ccname), &cb); + cb += sizeof(wchar_t); + + dw = GetEnvironmentVariable(L"KRB5CCNAME", + env_ccname, + ARRAYLENGTH(env_ccname)); + + if (dw == 0 && + GetLastError() == ERROR_ENVVAR_NOT_FOUND) { + /* KRB5CCNAME not set */ + HKEY hk_ccname; + DWORD dwType; + DWORD dwSize; + wchar_t reg_ccname[KRB5_MAXCCH_CCNAME]; + + l = RegOpenKeyEx(HKEY_CURRENT_USER, + L"Software\\MIT\\kerberos5", + 0, + KEY_READ | KEY_WRITE, + &hk_ccname); + + if (l != ERROR_SUCCESS) + l = RegCreateKeyEx(HKEY_CURRENT_USER, + L"Software\\MIT\\kerberos5", + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, + &hk_ccname, + &dw); + + if (l != ERROR_SUCCESS) + return KHM_ERROR_UNKNOWN; + + dwSize = sizeof(reg_ccname); + + l = RegQueryValueEx(hk_ccname, + L"ccname", + NULL, + &dwType, + (LPBYTE) reg_ccname, + &dwSize); + + if (l != ERROR_SUCCESS || + dwType != REG_SZ || + khm_krb5_cc_name_cmp(reg_ccname, id_ccname)) { + + /* we have to write the new value in */ + + l = RegSetValueEx(hk_ccname, + L"ccname", + 0, + REG_SZ, + (BYTE *) id_ccname, + (DWORD) cb); + } + + RegCloseKey(hk_ccname); + + if (l == ERROR_SUCCESS) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_UNKNOWN; + + } else if (dw > ARRAYLENGTH(env_ccname)) { + /* buffer was not enough */ +#ifdef DEBUG + assert(FALSE); +#else + return KHM_ERROR_UNKNOWN; +#endif + } else { + /* KRB5CCNAME is set */ + long code; + krb5_context ctx; + + /* if the %KRB5CCNAME is the same as the identity + ccache, then it is already the default. */ + if (!khm_krb5_cc_name_cmp(id_ccname, env_ccname)) + return KHM_ERROR_SUCCESS; + + /* if not, we have to copy the contents of id_ccname + to env_ccname */ + code = pkrb5_init_context(&ctx); + if (code) + return KHM_ERROR_UNKNOWN; + + code = khm_krb5_copy_ccache_by_name(ctx, + env_ccname, + id_ccname); + + if (code == 0) + khm_krb5_list_tickets(&ctx); + + if (ctx) + pkrb5_free_context(ctx); + + return (code == 0)?KHM_ERROR_SUCCESS:KHM_ERROR_UNKNOWN; + } + } else { + /* the default identity is being forgotten */ + + /* we don't really do anything about this case */ + } + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +k5_ident_get_ui_cb(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + khui_ident_new_creds_cb * cb; + + cb = (khui_ident_new_creds_cb *) vparam; + + *cb = ui_cb; + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +k5_ident_notify_create(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + + /* a new identity has been created. What we want to do at + this point is to check if the identity belongs to krb5 + and to see if it is the default. */ + + krb5_ccache cc = NULL; + krb5_error_code code; + krb5_principal princ = NULL; + char * princ_nameA = NULL; + wchar_t princ_nameW[KCDB_IDENT_MAXCCH_NAME]; + wchar_t id_nameW[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khm_handle ident; + + ident = (khm_handle) vparam; + + assert(k5_identpro_ctx != NULL); + + code = pkrb5_cc_default(k5_identpro_ctx, &cc); + if (code) + goto _nc_cleanup; + + code = pkrb5_cc_get_principal(k5_identpro_ctx, + cc, + &princ); + if (code) + goto _nc_cleanup; + + code = pkrb5_unparse_name(k5_identpro_ctx, + princ, + &princ_nameA); + if (code) + goto _nc_cleanup; + + AnsiStrToUnicode(princ_nameW, + sizeof(princ_nameW), + princ_nameA); + + cb = sizeof(id_nameW); + + if (KHM_FAILED(kcdb_identity_get_name(ident, + id_nameW, + &cb))) + goto _nc_cleanup; + + if (!wcscmp(id_nameW, princ_nameW)) { + kcdb_identity_set_default_int(ident); + } + + _nc_cleanup: + if (princ_nameA) + pkrb5_free_unparsed_name(k5_identpro_ctx, + princ_nameA); + if (princ) + pkrb5_free_principal(k5_identpro_ctx, + princ); + if (cc) + pkrb5_cc_close(k5_identpro_ctx, cc); + + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 KHMAPI +k5_ident_update_apply_proc(khm_handle cred, + void * rock) { + wchar_t ccname[KRB5_MAXCCH_CCNAME]; + khm_handle tident = (khm_handle) rock; + khm_handle ident = NULL; + khm_int32 t; + khm_int32 flags; + __int64 t_expire; + __int64 t_rexpire; + khm_size cb; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if (KHM_FAILED(kcdb_cred_get_type(cred, &t)) || + t != credtype_id_krb5 || + KHM_FAILED(kcdb_cred_get_identity(cred, &ident))) + return KHM_ERROR_SUCCESS; + + if (ident != tident) + goto _cleanup; + + if (KHM_FAILED(kcdb_cred_get_flags(cred, &flags))) + flags = 0; + + cb = sizeof(t_expire); + if (KHM_SUCCEEDED(kcdb_cred_get_attr(cred, + KCDB_ATTR_EXPIRE, + NULL, + &t_expire, + &cb))) { + __int64 t_cexpire; + + cb = sizeof(t_cexpire); + if ((flags & KCDB_CRED_FLAG_INITIAL) || + KHM_FAILED(kcdb_identity_get_attr(tident, + KCDB_ATTR_EXPIRE, + NULL, + &t_cexpire, + &cb)) || + t_cexpire > t_expire) + kcdb_identity_set_attr(tident, KCDB_ATTR_EXPIRE, + &t_expire, sizeof(t_expire)); + } else if (flags & KCDB_CRED_FLAG_INITIAL) { + kcdb_identity_set_attr(tident, KCDB_ATTR_EXPIRE, NULL, 0); + } + + cb = sizeof(ccname); + if (KHM_SUCCEEDED(kcdb_cred_get_attr(cred, KCDB_ATTR_LOCATION, + NULL, + ccname, + &cb))) { + kcdb_identity_set_attr(tident, attr_id_krb5_ccname, + ccname, cb); + } else { + kcdb_identity_set_attr(tident, attr_id_krb5_ccname, + NULL, 0); + } + + if (!(flags & KCDB_CRED_FLAG_INITIAL)) + goto _cleanup; + + cb = sizeof(t); + if (KHM_SUCCEEDED(kcdb_cred_get_attr(cred, + attr_id_krb5_flags, + NULL, + &t, + &cb))) { + kcdb_identity_set_attr(tident, attr_id_krb5_flags, + &t, sizeof(t)); + + cb = sizeof(t_rexpire); + if (!(t & TKT_FLG_RENEWABLE) || + KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_RENEW_EXPIRE, + NULL, + &t_rexpire, + &cb))) { + kcdb_identity_set_attr(tident, KCDB_ATTR_RENEW_EXPIRE, + NULL, 0); + } else { + kcdb_identity_set_attr(tident, KCDB_ATTR_RENEW_EXPIRE, + &t_rexpire, sizeof(t_rexpire)); + } + } else { + kcdb_identity_set_attr(tident, attr_id_krb5_flags, + NULL, 0); + kcdb_identity_set_attr(tident, KCDB_ATTR_RENEW_EXPIRE, + NULL, 0); + } + + rv = KHM_ERROR_EXIT; + + _cleanup: + if (ident) + kcdb_identity_release(ident); + + return rv; +} + +static khm_int32 +k5_ident_update(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + + khm_handle ident; + + ident = (khm_handle) vparam; + if (ident == NULL) + return KHM_ERROR_SUCCESS; + + kcdb_credset_apply(NULL, + k5_ident_update_apply_proc, + (void *) ident); + + return KHM_ERROR_SUCCESS; +} + + +static khm_int32 +k5_ident_init(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + /* just like notify_create, except now we set the default identity + based on what we find in the configuration */ + krb5_ccache cc = NULL; + krb5_error_code code; + krb5_principal princ = NULL; + char * princ_nameA = NULL; + wchar_t princ_nameW[KCDB_IDENT_MAXCCH_NAME]; + khm_handle ident = NULL; + + assert(k5_identpro_ctx != NULL); + + code = pkrb5_cc_default(k5_identpro_ctx, &cc); + if (code) + goto _nc_cleanup; + + code = pkrb5_cc_get_principal(k5_identpro_ctx, + cc, + &princ); + if (code) + goto _nc_cleanup; + + code = pkrb5_unparse_name(k5_identpro_ctx, + princ, + &princ_nameA); + if (code) + goto _nc_cleanup; + + AnsiStrToUnicode(princ_nameW, + sizeof(princ_nameW), + princ_nameA); + + if (KHM_FAILED(kcdb_identity_create(princ_nameW, + 0, + &ident))) + goto _nc_cleanup; + + kcdb_identity_set_default_int(ident); + + _nc_cleanup: + if (princ_nameA) + pkrb5_free_unparsed_name(k5_identpro_ctx, + princ_nameA); + if (princ) + pkrb5_free_principal(k5_identpro_ctx, + princ); + if (cc) + pkrb5_cc_close(k5_identpro_ctx, cc); + + if (ident) + kcdb_identity_release(ident); + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +k5_ident_exit(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + /* don't really do anything */ + return KHM_ERROR_SUCCESS; +} + +#if 0 +/* copy and paste template for ident provider messages */ +static khm_int32 +k5_ident_(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { +} +#endif + +khm_int32 KHMAPI +k5_msg_ident(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) +{ + switch(msg_subtype) { + case KMSG_IDENT_INIT: + return k5_ident_init(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_EXIT: + return k5_ident_exit(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_VALIDATE_NAME: + return k5_ident_valiate_name(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_VALIDATE_IDENTITY: + /* TODO: handle KMSG_IDENT_VALIDATE_IDENTITY */ + break; + + case KMSG_IDENT_CANON_NAME: + /* TODO: handle KMSG_IDENT_CANON_NAME */ + break; + + case KMSG_IDENT_COMPARE_NAME: + /* TODO: handle KMSG_IDENT_COMPARE_NAME */ + break; + + case KMSG_IDENT_SET_DEFAULT: + return k5_ident_set_default(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_SET_SEARCHABLE: + /* TODO: handle KMSG_IDENT_SET_SEARCHABLE */ + break; + + case KMSG_IDENT_GET_INFO: + /* TODO: handle KMSG_IDENT_GET_INFO */ + break; + + case KMSG_IDENT_UPDATE: + return k5_ident_update(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_ENUM_KNOWN: + /* TODO: handle KMSG_IDENT_ENUM_KNOWN */ + break; + + case KMSG_IDENT_GET_UI_CALLBACK: + return k5_ident_get_ui_cb(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_NOTIFY_CREATE: + return k5_ident_notify_create(msg_type, + msg_subtype, + uparam, + vparam); + } + + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/plugins/krb5/krb5newcreds.c b/src/windows/identity/plugins/krb5/krb5newcreds.c new file mode 100644 index 0000000000..968e0e2903 --- /dev/null +++ b/src/windows/identity/plugins/krb5/krb5newcreds.c @@ -0,0 +1,2167 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include + +#include + +extern LPVOID k5_main_fiber; +extern LPVOID k5_kinit_fiber; + +typedef struct k5_dlg_data_t { + khui_new_creds * nc; + + khui_tracker tc_lifetime; + khui_tracker tc_renew; + + BOOL dirty; + + DWORD renewable; + DWORD forwardable; + DWORD proxiable; + DWORD addressless; + DWORD publicIP; + + wchar_t * cred_message; /* overrides the credential text, if + non-NULL */ +} k5_dlg_data; + + +INT_PTR +k5_handle_wm_initdialog(HWND hwnd, + WPARAM wParam, + LPARAM lParam) +{ + HWND hw; + k5_dlg_data * d; + khui_new_creds_by_type * nct; + + d = malloc(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + /* lParam is a pointer to a khui_new_creds structure */ + d->nc = (khui_new_creds *) lParam; + khui_cw_find_type(d->nc, credtype_id_krb5, &nct); + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM) d); +#pragma warning(pop) + + nct->aux = (LPARAM) d; + + if (d->nc->subtype == KMSG_CRED_NEW_CREDS) { + khui_tracker_initialize(&d->tc_lifetime); + khui_tracker_initialize(&d->tc_renew); + + hw = GetDlgItem(hwnd, IDC_NCK5_LIFETIME_EDIT); + khui_tracker_install(hw, &d->tc_lifetime); + + hw = GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT); + khui_tracker_install(hw, &d->tc_renew); + } + return TRUE; +} + +INT_PTR +k5_handle_wm_destroy(HWND hwnd, + WPARAM wParam, + LPARAM lParam) +{ + k5_dlg_data * d; + khui_new_creds_by_type * nct = NULL; + + d = (k5_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); +#ifdef DEBUG + assert(d); +#endif + + khui_cw_find_type(d->nc, credtype_id_krb5, &nct); + +#ifdef DEBUG + assert(nct); +#endif + + nct->aux = 0; + + if (d->nc->subtype == KMSG_CRED_NEW_CREDS) { + khui_tracker_kill_controls(&d->tc_renew); + khui_tracker_kill_controls(&d->tc_lifetime); + } + + free(d); + + return TRUE; +} + +INT_PTR +k5_handle_wmnc_notify(HWND hwnd, + WPARAM wParam, + LPARAM lParam) +{ + switch(HIWORD(wParam)) { + case WMNC_DIALOG_MOVE: + { + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (d->nc->subtype == KMSG_CRED_NEW_CREDS) { + khui_tracker_reposition(&d->tc_lifetime); + khui_tracker_reposition(&d->tc_renew); + } + + return TRUE; + } + break; + + case WMNC_DIALOG_SETUP: + { + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (d->nc->subtype == KMSG_CRED_PASSWORD) + return TRUE; + + /* need to update the controls with d->* */ + if(d->renewable) { + SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, + BM_SETCHECK, BST_CHECKED, + 0); + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), + TRUE); + } else { + SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, + BM_SETCHECK, BST_UNCHECKED, 0); + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), + FALSE); + } + + khui_tracker_refresh(&d->tc_lifetime); + khui_tracker_refresh(&d->tc_renew); + + if(d->forwardable) { + SendDlgItemMessage(hwnd, IDC_NCK5_FORWARDABLE, + BM_SETCHECK, BST_CHECKED, 0); + } else { + SendDlgItemMessage(hwnd, IDC_NCK5_FORWARDABLE, + BM_SETCHECK, BST_UNCHECKED, 0); + } + } + break; + + case WMNC_UPDATE_CREDTEXT: + { + k5_dlg_data * d; + khui_new_creds * nc; + khui_new_creds_by_type * nct; + wchar_t sbuf[1024]; + wchar_t fbuf[256]; + wchar_t tbuf[256]; + size_t cbsize; + khm_int32 flags; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + nc = d->nc; + khui_cw_find_type(nc, credtype_id_krb5, &nct); + + if(nct == NULL) + break; + + if(nct->credtext) + free(nct->credtext); + nct->credtext = NULL; + + tbuf[0] = L'\0'; + + if (nc->n_identities > 0 && + KHM_SUCCEEDED(kcdb_identity_get_flags(nc->identities[0], + &flags)) && + (flags & KCDB_IDENT_FLAG_VALID) && + nc->subtype == KMSG_CRED_NEW_CREDS) { + + if (is_k5_identpro) + k5_get_realm_from_nc(nc, tbuf, ARRAYLENGTH(tbuf)); + else + GetDlgItemText(hwnd, IDC_NCK5_REALM, tbuf, + ARRAYLENGTH(tbuf)); + + /*TODO: if additional realms were specified, then those + must be listed as well */ + LoadString(hResModule, IDS_KRB5_CREDTEXT_0, + fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(sbuf, sizeof(sbuf), fbuf, + tbuf); + + StringCbLength(sbuf, sizeof(sbuf), &cbsize); + cbsize += sizeof(wchar_t); + + nct->credtext = malloc(cbsize); + + StringCbCopy(nct->credtext, cbsize, sbuf); + } else if (nc->n_identities > 0 && + nc->subtype == KMSG_CRED_PASSWORD) { + cbsize = sizeof(tbuf); + kcdb_identity_get_name(nc->identities[0], tbuf, &cbsize); + + LoadString(hResModule, IDS_KRB5_CREDTEXT_P0, + fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(sbuf, sizeof(sbuf), fbuf, tbuf); + + StringCbLength(sbuf, sizeof(sbuf), &cbsize); + cbsize += sizeof(wchar_t); + + nct->credtext = malloc(cbsize); + + StringCbCopy(nct->credtext, cbsize, sbuf); + } else { + if (d->cred_message) { + StringCbLength(d->cred_message, KHUI_MAXCB_BANNER, + &cbsize); + cbsize += sizeof(wchar_t); + + nct->credtext = malloc(cbsize); + + StringCbCopy(nct->credtext, cbsize, d->cred_message); + } + } + } + break; + + case WMNC_IDENTITY_CHANGE: + { + /* There has been a change of identity */ + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + kmq_post_sub_msg(k5_sub, KMSG_CRED, + KMSG_CRED_DIALOG_NEW_IDENTITY, + 0, (void *) d->nc); + } + break; + + case WMNC_DIALOG_PREPROCESS: + { + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if(d->dirty) { + kmq_post_sub_msg(k5_sub, KMSG_CRED, + KMSG_CRED_DIALOG_NEW_OPTIONS, + 0, (void *) d->nc); + + /* the above notification effectively takes + all our changes into account. The data we + have is no longer dirty */ + d->dirty = FALSE; + } + } + break; + } + + return 0; +} + +INT_PTR +k5_handle_wm_command(HWND hwnd, + WPARAM wParam, + LPARAM lParam) +{ + int cid; + int notif; + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + cid = LOWORD(wParam); + notif = HIWORD(wParam); + + if(notif == BN_CLICKED && cid == IDC_NCK5_RENEWABLE) { + int c; + c = (int) SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, + BM_GETCHECK, 0, 0); + if(c==BST_CHECKED) { + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), TRUE); + d->renewable = TRUE; + } else { + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), FALSE); + d->renewable = FALSE; + } + d->dirty = TRUE; + } else if(notif == BN_CLICKED && cid == IDC_NCK5_FORWARDABLE) { + int c; + c = (int) SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, + BM_GETCHECK, 0, 0); + if(c==BST_CHECKED) { + d->forwardable = TRUE; + } else { + d->forwardable = FALSE; + } + d->dirty = TRUE; + } else if((notif == CBN_SELCHANGE || + notif == CBN_KILLFOCUS) && + cid == IDC_NCK5_REALM && + !is_k5_identpro) { + /* find out what the realm of the current identity + is, and if they are the same, then we don't do + anything */ + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t realm[KCDB_IDENT_MAXCCH_NAME]; + wchar_t *r; + khm_size cbsize; + khm_handle ident; + int idx; + + if(d->nc->n_identities > 0) { + if(notif == CBN_SELCHANGE) { + idx = (int) SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_GETCURSEL, 0, 0); + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_GETLBTEXT, idx, (LPARAM) realm); + } else { + GetDlgItemText(hwnd, IDC_NCK5_REALM, + realm, ARRAYLENGTH(realm)); + } + cbsize = sizeof(idname); + if(KHM_SUCCEEDED(kcdb_identity_get_name(d->nc->identities[0], + idname, &cbsize))) { + r = wcschr(idname, L'@'); + if(r && !wcscmp(realm, r+1)) + return 0; /* nothing to do */ + + if(!r) { + r = idname + wcslen(idname); + *r++ = L'@'; + *r++ = 0; + } + + /* if we get here, we have a new user */ + StringCchCopy(r+1, + ARRAYLENGTH(idname) - ((r+1) - idname), + realm); + if(KHM_SUCCEEDED(kcdb_identity_create(idname, + KCDB_IDENT_FLAG_CREATE, + &ident))) { + khui_cw_set_primary_id(d->nc, ident); + kcdb_identity_release(ident); + } + return 0; + } + } + + /* if we get here, we have a new realm, but there is no + identity */ + PostMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0); + } + + return 0; +} + + +/* Dialog procedure for the Krb5 credentials type panel. + + NOTE: Runs in the context of the UI thread +*/ +INT_PTR CALLBACK +k5_nc_dlg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) { + case WM_INITDIALOG: + return k5_handle_wm_initdialog(hwnd, wParam, lParam); + + case WM_COMMAND: + return k5_handle_wm_command(hwnd, wParam, lParam); + + case KHUI_WM_NC_NOTIFY: + return k5_handle_wmnc_notify(hwnd, wParam, lParam); + + case WM_DESTROY: + return k5_handle_wm_destroy(hwnd, wParam, lParam); + } + return FALSE; +} + +/* forward dcl */ +krb5_error_code KRB5_CALLCONV +k5_kinit_prompter(krb5_context context, + void *data, + const char *name, + const char *banner, + int num_prompts, + krb5_prompt prompts[]); + + + +fiber_job g_fjob; /* global fiber job object */ + +static BOOL +k5_cached_kinit_prompter(void); + +static BOOL +k5_cp_check_continue(void); + +/* + Runs in the context of the krb5 plugin's slave fiber +*/ +VOID CALLBACK +k5_kinit_fiber_proc(PVOID lpParameter) +{ + while(TRUE) + { + if(g_fjob.command == FIBER_CMD_KINIT) { + g_fjob.state = FIBER_STATE_KINIT; + + g_fjob.prompt_set = 0; + + if (k5_cached_kinit_prompter()) { + SwitchToFiber(k5_main_fiber); + + if (g_fjob.command != FIBER_CMD_CONTINUE) + goto _switch_to_main; + + if (!k5_cp_check_continue()) { + goto _switch_to_main; + } + } + + g_fjob.code = khm_krb5_kinit( + 0, + g_fjob.principal, + g_fjob.password, + g_fjob.ccache, + g_fjob.lifetime, + g_fjob.forwardable, + g_fjob.proxiable, + (g_fjob.renewable ? g_fjob.renew_life : 0), + g_fjob.addressless, + g_fjob.publicIP, + k5_kinit_prompter, + &g_fjob); + } + + _switch_to_main: + g_fjob.state = FIBER_STATE_NONE; + + SwitchToFiber(k5_main_fiber); + } +} + +/* return TRUE if we should go ahead with creds acquisition */ +static BOOL +k5_cp_check_continue(void) { + khm_size i; + khm_size n_p; + khui_new_creds_prompt * p; + size_t cch; + +#ifdef DEBUG + assert(g_fjob.nc); +#endif + + if (KHM_FAILED(khui_cw_get_prompt_count(g_fjob.nc, &n_p))) { +#ifdef DEBUG + assert(FALSE); +#endif + return TRUE; + } + + khui_cw_sync_prompt_values(g_fjob.nc); + + g_fjob.null_password = FALSE; + + /* we are just checking whether there was a password field that + was left empty, in which case we can't continue with the + credentials acquisition. */ + for (i=0; i < n_p; i++) { + if(KHM_FAILED(khui_cw_get_prompt(g_fjob.nc, + (int) i, + &p))) + continue; + if(p->type == KHUI_NCPROMPT_TYPE_PASSWORD) { + if (p->value == NULL || + FAILED(StringCchLength(p->value, KHUI_MAXCCH_PROMPT, + &cch)) || + cch == 0) { + g_fjob.null_password = TRUE; + return FALSE; + } else + break; + } + } + + return TRUE; +} + +/* returns true if we find cached prompts */ +static BOOL +k5_cached_kinit_prompter(void) { + BOOL rv = FALSE; + khm_handle ident; + khm_handle csp_idconfig = NULL; + khm_handle csp_k5config = NULL; + khm_handle csp_prcache = NULL; + khm_size cb; + khm_size n_cur_prompts; + khm_int32 n_prompts; + khm_int32 i; + +#ifdef DEBUG + assert(g_fjob.nc); +#endif + + ident = g_fjob.identity; + if (!ident) + return FALSE; + + /* don't need to hold ident, since it is already held in g_fjob + and it doesn't change until we return */ + + if (KHM_FAILED(kcdb_identity_get_config(ident, 0, &csp_idconfig)) || + + KHM_FAILED(khc_open_space(csp_idconfig, CSNAME_KRB5CRED, + 0, &csp_k5config)) || + + KHM_FAILED(khc_open_space(csp_k5config, CSNAME_PROMPTCACHE, + 0, &csp_prcache)) || + + KHM_FAILED(khc_read_int32(csp_prcache, L"PromptCount", + &n_prompts)) || + n_prompts == 0) + + goto _cleanup; + + /* check if there are any prompts currently showing. If there are + we check if they are the same as the ones we are going to show. + In which case we just reuse the exisitng prompts */ + if (KHM_FAILED(khui_cw_get_prompt_count(g_fjob.nc, + &n_cur_prompts)) || + n_prompts != (khm_int32) n_cur_prompts) + goto _show_new_prompts; + + for(i = 0; i < n_prompts; i++) { + wchar_t wsname[8]; + wchar_t wprompt[KHUI_MAXCCH_PROMPT]; + khm_handle csp_p = NULL; + khm_int32 p_type; + khm_int32 p_flags; + khui_new_creds_prompt * p; + + if (KHM_FAILED(khui_cw_get_prompt(g_fjob.nc, i, &p))) + break; + + StringCbPrintf(wsname, sizeof(wsname), L"%d", i); + + if (KHM_FAILED(khc_open_space(csp_prcache, wsname, 0, &csp_p))) + break; + + cb = sizeof(wprompt); + if (KHM_FAILED(khc_read_string(csp_p, L"Prompt", + wprompt, &cb))) { + khc_close_space(csp_p); + break; + } + + if (KHM_FAILED(khc_read_int32(csp_p, L"Type", &p_type))) + p_type = 0; + + if (KHM_FAILED(khc_read_int32(csp_p, L"Flags", &p_flags))) + p_flags = 0; + + if ( /* if we received a prompt string, + then it should be the same as the + one that is displayed */ + (wprompt[0] && + (p->prompt == NULL || + wcscmp(wprompt, p->prompt))) || + + /* if we didn't receive one, then + there shouldn't be one displayed. + This case really shouldn't happen + in reality, but we check anyway. */ + (!wprompt[0] && + p->prompt != NULL) || + + /* the type should match */ + (p_type != p->type) || + + /* if this prompt should be hidden, + then it must also be so */ + (p_flags != p->flags) + ) { + + khc_close_space(csp_p); + break; + + } + + + khc_close_space(csp_p); + } + + if (i == n_prompts) { + rv = TRUE; + goto _cleanup; + } + + _show_new_prompts: + + khui_cw_clear_prompts(g_fjob.nc); + + { + wchar_t wbanner[KHUI_MAXCCH_BANNER]; + wchar_t wpname[KHUI_MAXCCH_PNAME]; + + cb = sizeof(wbanner); + if (KHM_FAILED(khc_read_string(csp_prcache, L"Banner", + wbanner, &cb))) + wbanner[0] = 0; + + cb = sizeof(wpname); + if (KHM_FAILED(khc_read_string(csp_prcache, L"Name", + wpname, &cb))) + wpname[0] = 0; + + khui_cw_begin_custom_prompts(g_fjob.nc, + n_prompts, + (wbanner[0]? wbanner: NULL), + (wpname[0]? wpname: NULL)); + } + + for(i = 0; i < n_prompts; i++) { + wchar_t wsname[8]; + wchar_t wprompt[KHUI_MAXCCH_PROMPT]; + khm_handle csp_p = NULL; + khm_int32 p_type; + khm_int32 p_flags; + + StringCbPrintf(wsname, sizeof(wsname), L"%d", i); + + if (KHM_FAILED(khc_open_space(csp_prcache, wsname, 0, &csp_p))) + break; + + cb = sizeof(wprompt); + if (KHM_FAILED(khc_read_string(csp_p, L"Prompt", + wprompt, &cb))) { + khc_close_space(csp_p); + break; + } + + if (KHM_FAILED(khc_read_int32(csp_p, L"Type", &p_type))) + p_type = 0; + + if (KHM_FAILED(khc_read_int32(csp_p, L"Flags", &p_flags))) + p_flags = 0; + + khui_cw_add_prompt(g_fjob.nc, p_type, wprompt, NULL, p_flags); + + khc_close_space(csp_p); + } + + if (i < n_prompts) { + khui_cw_clear_prompts(g_fjob.nc); + } else { + rv = TRUE; + } + + _cleanup: + + if (csp_prcache) + khc_close_space(csp_prcache); + + if (csp_k5config) + khc_close_space(csp_k5config); + + if (csp_idconfig) + khc_close_space(csp_idconfig); + + return rv; +} + +/* Runs in the context of the Krb5 plugin's slave fiber */ +krb5_error_code KRB5_CALLCONV +k5_kinit_prompter(krb5_context context, + void *data, + const char *name, + const char *banner, + int num_prompts, + krb5_prompt prompts[]) +{ + int i; + khui_new_creds * nc; + krb5_prompt_type * ptypes; + khm_size ncp; + krb5_error_code code = 0; + BOOL new_prompts = TRUE; + + khm_handle csp_prcache = NULL; + + nc = g_fjob.nc; + + if(pkrb5_get_prompt_types) + ptypes = pkrb5_get_prompt_types(context); + else + ptypes = NULL; + + /* check if we are already showing the right prompts */ + khui_cw_get_prompt_count(nc, &ncp); + + if (num_prompts != (int) ncp) + goto _show_new_prompts; + + for (i=0; i < num_prompts; i++) { + wchar_t wprompt[KHUI_MAXCCH_PROMPT]; + khui_new_creds_prompt * p; + + if(prompts[i].prompt) { + AnsiStrToUnicode(wprompt, sizeof(wprompt), + prompts[i].prompt); + } else { + wprompt[0] = 0; + } + + if (KHM_FAILED(khui_cw_get_prompt(nc, i, &p))) + break; + + if ( /* if we received a prompt string, + then it should be the same as the + one that is displayed */ + (wprompt[0] && + (p->prompt == NULL || + wcscmp(wprompt, p->prompt))) || + /* if we didn't receive one, then + there shouldn't be one displayed. + This case really shouldn't happen + in reality, but we check anyway. */ + (!wprompt[0] && + p->prompt != NULL) || + /* the type should match */ + (ptypes && + ptypes[i] != p->type) || + (!ptypes && + p->type != 0) || + /* if this prompt should be hidden, + then it must also be so */ + (prompts[i].hidden && + !(p->flags & KHUI_NCPROMPT_FLAG_HIDDEN)) || + (!prompts[i].hidden && + (p->flags & KHUI_NCPROMPT_FLAG_HIDDEN)) + ) + break; + } + + if (i < num_prompts) + goto _show_new_prompts; + + new_prompts = FALSE; + + /* ok. looks like we are already showing the same set of prompts + that we were supposed to show. Sync up the values and go + ahead. */ + khui_cw_sync_prompt_values(nc); + goto _process_prompts; + + _show_new_prompts: + /* special case. if there are no actual input controls involved, + then we have to show an alerter window and pass through */ + if (num_prompts == 0) { + wchar_t wbanner[KHUI_MAXCCH_BANNER]; + wchar_t wname[KHUI_MAXCCH_PNAME]; + wchar_t wident[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wmsg[KHUI_MAXCCH_MESSAGE]; + wchar_t wfmt[KHUI_MAXCCH_BANNER]; + khm_size cb; + + if (!banner) { + code = 0; + g_fjob.null_password = FALSE; + goto _exit; + } else { + AnsiStrToUnicode(wbanner, sizeof(wbanner), banner); + } + + if (name) { + AnsiStrToUnicode(wname, sizeof(wname), name); + } else { + LoadString(hResModule, + IDS_KRB5_WARNING, + wname, + ARRAYLENGTH(wname)); + } + + cb = sizeof(wident); + if (KHM_FAILED(kcdb_identity_get_name(g_fjob.identity, wident, &cb))) + wident[0] = L'\0'; + + LoadString(hResModule, + IDS_KRB5_WARN_FMT, + wfmt, + ARRAYLENGTH(wfmt)); + + StringCbPrintf(wmsg, sizeof(wmsg), wfmt, wident, wbanner); + + khui_alert_show_simple(wname, wmsg, KHERR_WARNING); + + code = 0; + g_fjob.null_password = FALSE; + goto _exit; + } + + /* in addition to showing new prompts, we also cache the set of + prompts. */ + if(g_fjob.prompt_set == 0) { + khm_handle csp_idconfig = NULL; + khm_handle csp_idk5 = NULL; + + kcdb_identity_get_config(g_fjob.identity, + KHM_FLAG_CREATE, + &csp_idconfig); + + if (csp_idconfig != NULL) + khc_open_space(csp_idconfig, + CSNAME_KRB5CRED, + KHM_FLAG_CREATE, + &csp_idk5); + + if (csp_idk5 != NULL) + khc_open_space(csp_idk5, + CSNAME_PROMPTCACHE, + KHM_FLAG_CREATE, + &csp_prcache); + + khc_close_space(csp_idconfig); + khc_close_space(csp_idk5); + } + + { + wchar_t wbanner[KHUI_MAXCCH_BANNER]; + wchar_t wname[KHUI_MAXCCH_PNAME]; + + if(banner) + AnsiStrToUnicode(wbanner, sizeof(wbanner), banner); + if(name) + AnsiStrToUnicode(wname, sizeof(wname), name); + + khui_cw_clear_prompts(nc); + + khui_cw_begin_custom_prompts( + nc, + num_prompts, + (banner)?wbanner:NULL, + (name)?wname:NULL); + + if (banner && csp_prcache) + khc_write_string(csp_prcache, + L"Banner", + wbanner); + else if (csp_prcache) + khc_write_string(csp_prcache, + L"Banner", + L""); + + if (name && csp_prcache) + khc_write_string(csp_prcache, + L"Name", + wname); + else if (csp_prcache) + khc_write_string(csp_prcache, + L"Name", + L""); + + if (csp_prcache) + khc_write_int32(csp_prcache, + L"PromptCount", + (khm_int32) num_prompts); + } + + for(i=0; i < num_prompts; i++) { + wchar_t wprompt[KHUI_MAXCCH_PROMPT]; + + if(prompts[i].prompt) { + AnsiStrToUnicode(wprompt, sizeof(wprompt), + prompts[i].prompt); + } else { + wprompt[0] = 0; + } + + khui_cw_add_prompt( + nc, + (ptypes?ptypes[i]:0), + wprompt, + NULL, + (prompts[i].hidden?KHUI_NCPROMPT_FLAG_HIDDEN:0)); + + if (csp_prcache) { + khm_handle csp_p = NULL; + wchar_t wnum[8]; /* should be enough for 10 + million prompts */ + + wnum[0] = 0; + StringCbPrintf(wnum, sizeof(wnum), L"%d", i); + + khc_open_space(csp_prcache, wnum, + KHM_FLAG_CREATE, &csp_p); + + if (csp_p) { + khc_write_string(csp_p, L"Prompt", wprompt); + khc_write_int32(csp_p, L"Type", (ptypes?ptypes[i]:0)); + khc_write_int32(csp_p, L"Flags", + (prompts[i].hidden? + KHUI_NCPROMPT_FLAG_HIDDEN:0)); + + khc_close_space(csp_p); + } + } + } + + if (csp_prcache) { + khc_close_space(csp_prcache); + csp_prcache = NULL; + } + + _process_prompts: + /* switch back to main thread if we showed new prompts */ + if (new_prompts) + SwitchToFiber(k5_main_fiber); + + /* we get here after the user selects an action that either + cancles the credentials acquisition operation or triggers the + actual acquisition of credentials. */ + if(g_fjob.command != FIBER_CMD_CONTINUE && + g_fjob.command != FIBER_CMD_KINIT) { + code = -2; + goto _exit; + } + + g_fjob.null_password = FALSE; + + /* otherwise, we need to get the data back from the UI and + return 0 */ + for(i=0; idata, d->length, wbuf); + if(SUCCEEDED(StringCchLengthA(d->data, d->length, &cch))) + d->length = (unsigned int) cch; + else + d->length = 0; + } else { +#ifdef DEBUG + assert(FALSE); +#endif + d->length = 0; + } + + if (ptypes && + ptypes[i] == KRB5_PROMPT_TYPE_PASSWORD && + d->length == 0) + + g_fjob.null_password = TRUE; + } + + _exit: + + g_fjob.prompt_set++; + + /* entering a NULL password is equivalent to cancelling out */ + if (g_fjob.null_password) + return -2; + else + return code; +} + + +void +k5_read_dlg_params(khm_handle conf, + k5_dlg_data * d) +{ + khm_int32 i; + + khc_read_int32(conf, L"Renewable", &d->renewable); + khc_read_int32(conf, L"Forwardable", &d->forwardable); + khc_read_int32(conf, L"Proxiable", &d->proxiable); + khc_read_int32(conf, L"Addressless", &d->addressless); + + khc_read_int32(conf, L"DefaultLifetime", &i); + d->tc_lifetime.current = i; + khc_read_int32(conf, L"MaxLifetime", &i); + d->tc_lifetime.max = i; + khc_read_int32(conf, L"MinLifetime", &i); + d->tc_lifetime.min = i; + + khc_read_int32(conf, L"DefaultRenewLifetime", &i); + d->tc_renew.current = i; + khc_read_int32(conf, L"MaxRenewLifetime", &i); + d->tc_renew.max = i; + khc_read_int32(conf, L"MinRenewLifetime", &i); + d->tc_renew.min = i; + + /* however, if this has externally supplied defaults, we have to + use them too. */ + if (d->nc && d->nc->ctx.vparam && + d->nc->ctx.cb_vparam == sizeof(NETID_DLGINFO)) { + LPNETID_DLGINFO pdlginfo; + + pdlginfo = (LPNETID_DLGINFO) d->nc->ctx.vparam; + if (pdlginfo->size == NETID_DLGINFO_V1_SZ && + pdlginfo->in.use_defaults == 0) { + d->forwardable = pdlginfo->in.forwardable; + d->addressless = pdlginfo->in.noaddresses; + d->tc_lifetime.current = pdlginfo->in.lifetime; + d->tc_renew.current = pdlginfo->in.renew_till; + + if (pdlginfo->in.renew_till == 0) + d->renewable = FALSE; + else + d->renewable = TRUE; + + d->proxiable = pdlginfo->in.proxiable; + d->publicIP = pdlginfo->in.publicip; + } + } + + /* once we read the new data, in, it is no longer considered + dirty */ + d->dirty = FALSE; +} + +void +k5_write_dlg_params(khm_handle conf, + k5_dlg_data * d) +{ + khc_write_int32(conf, L"Renewable", d->renewable); + khc_write_int32(conf, L"Forwardable", d->forwardable); + khc_write_int32(conf, L"Proxiable", d->proxiable); + khc_write_int32(conf, L"Addressless", d->addressless); + + khc_write_int32(conf, L"DefaultLifetime", + (khm_int32) d->tc_lifetime.current); + khc_write_int32(conf, L"MaxLifetime", + (khm_int32) d->tc_lifetime.max); + khc_write_int32(conf, L"MinLifetime", + (khm_int32) d->tc_lifetime.min); + + khc_write_int32(conf, L"DefaultRenewLifetime", + (khm_int32) d->tc_renew.current); + khc_write_int32(conf, L"MaxRenewLifetime", + (khm_int32) d->tc_renew.max); + khc_write_int32(conf, L"MinRenewLifetime", + (khm_int32) d->tc_renew.min); + + /* as in k5_read_dlg_params, once we write the data in, the local + data is no longer dirty */ + d->dirty = FALSE; +} + +void +k5_prep_kinit_job(khui_new_creds * nc) +{ + khui_new_creds_by_type * nct; + k5_dlg_data * d; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cbbuf; + size_t size; + khm_handle ident; + LPNETID_DLGINFO pdlginfo; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + if (!nct) + return; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + + khui_cw_lock_nc(nc); + ident = nc->identities[0]; + kcdb_identity_hold(ident); + khui_cw_unlock_nc(nc); + + cbbuf = sizeof(idname); + kcdb_identity_get_name(ident, idname, &cbbuf); + StringCchLength(idname, ARRAYLENGTH(idname), &size); + size++; + + ZeroMemory(&g_fjob, sizeof(g_fjob)); + g_fjob.command = FIBER_CMD_KINIT; + g_fjob.nc = nc; + g_fjob.nct = nct; + g_fjob.dialog = nct->hwnd_panel; + g_fjob.principal = malloc(size); + UnicodeStrToAnsi(g_fjob.principal, size, idname); + g_fjob.password = NULL; + g_fjob.lifetime = (krb5_deltat) d->tc_lifetime.current; + g_fjob.forwardable = d->forwardable; + g_fjob.proxiable = d->proxiable; + g_fjob.renewable = d->renewable; + g_fjob.renew_life = (krb5_deltat) d->tc_renew.current; + g_fjob.addressless = d->addressless; + g_fjob.publicIP = 0; + g_fjob.code = 0; + g_fjob.identity = ident; + g_fjob.prompt_set = 0; + + /* if we have external parameters, we should use them as well */ + if (nc->ctx.cb_vparam == sizeof(NETID_DLGINFO) && + (pdlginfo = nc->ctx.vparam) && + pdlginfo->size == NETID_DLGINFO_V1_SZ) { + wchar_t * t; + + if (pdlginfo->in.ccache[0] && + SUCCEEDED(StringCchLength(pdlginfo->in.ccache, + NETID_CCACHE_NAME_SZ, + &size))) { + g_fjob.ccache = malloc(sizeof(char) * (size + 1)); +#ifdef DEBUG + assert(g_fjob.ccache); +#endif + UnicodeStrToAnsi(g_fjob.ccache, size + 1, + pdlginfo->in.ccache); + + /* this is the same as the output cache */ + + StringCbCopy(pdlginfo->out.ccache, sizeof(pdlginfo->out.ccache), + pdlginfo->in.ccache); + } else { + g_fjob.ccache = NULL; + + StringCbCopy(pdlginfo->out.ccache, sizeof(pdlginfo->out.ccache), + idname); + + khm_krb5_canon_cc_name(pdlginfo->out.ccache, + sizeof(pdlginfo->out.ccache)); + } + + t = khm_get_realm_from_princ(idname); + + if (t) { + StringCbCopy(pdlginfo->out.realm, + sizeof(pdlginfo->out.realm), + t); + + if ((t - idname) > 1) { + StringCchCopyN(pdlginfo->out.username, + ARRAYLENGTH(pdlginfo->out.username), + idname, + (t - idname) - 1); + } else { + StringCbCopy(pdlginfo->out.username, + sizeof(pdlginfo->out.username), + L""); + } + } else { + StringCbCopy(pdlginfo->out.username, + sizeof(pdlginfo->out.username), + idname); + StringCbCopy(pdlginfo->out.realm, + sizeof(pdlginfo->out.realm), + L""); + } + } + + /* leave identity held, since we added a reference above */ +} + +void +k5_free_kinit_job(void) +{ + if (g_fjob.principal) + free(g_fjob.principal); + + if (g_fjob.password) + free(g_fjob.password); + + if (g_fjob.identity) + kcdb_identity_release(g_fjob.identity); + + if (g_fjob.ccache) + free(g_fjob.ccache); + + ZeroMemory(&g_fjob, sizeof(g_fjob)); +} + +static khm_int32 KHMAPI +k5_find_tgt_filter(khm_handle cred, + khm_int32 flags, + void * rock) { + khm_handle ident = (khm_handle) rock; + khm_handle cident = NULL; + khm_int32 f; + khm_int32 rv; + + if (KHM_SUCCEEDED(kcdb_cred_get_identity(cred, + &cident)) && + cident == ident && + KHM_SUCCEEDED(kcdb_cred_get_flags(cred, &f)) && + (f & KCDB_CRED_FLAG_INITIAL)) + rv = 1; + else + rv = 0; + + if (cident) + kcdb_identity_release(cident); + + return rv; +} + +/* Handler for CRED type messages + + Runs in the context of the Krb5 plugin +*/ +khm_int32 KHMAPI +k5_msg_cred_dialog(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + + case KMSG_CRED_PASSWORD: + case KMSG_CRED_NEW_CREDS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + wchar_t wbuf[256]; + size_t cbsize; + + nc = (khui_new_creds *) vparam; + + nct = malloc(sizeof(*nct)); + ZeroMemory(nct, sizeof(*nct)); + + nct->type = credtype_id_krb5; + nct->ordinal = 1; + + LoadString(hResModule, IDS_KRB5_SHORT_DESC, + wbuf, ARRAYLENGTH(wbuf)); + StringCbLength(wbuf, sizeof(wbuf), &cbsize); + cbsize += sizeof(wchar_t); + + nct->name = malloc(cbsize); + StringCbCopy(nct->name, cbsize, wbuf); + + nct->h_module = hResModule; + nct->dlg_proc = k5_nc_dlg_proc; + if (nc->subtype == KMSG_CRED_PASSWORD) + nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB5_PASSWORD); + else + nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB5); + + khui_cw_add_type(nc, nct); + } + break; + + case KMSG_CRED_RENEW_CREDS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + + nc = (khui_new_creds *) vparam; + + nct = malloc(sizeof(*nct)); + ZeroMemory(nct, sizeof(*nct)); + + nct->type = credtype_id_krb5; + + khui_cw_add_type(nc, nct); + } + break; + + case KMSG_CRED_DIALOG_PRESTART: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + k5_dlg_data * d; + HWND hwnd; + wchar_t * realms; + wchar_t * t; + wchar_t * defrealm; + + nc = (khui_new_creds *) vparam; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + + if(!nct) + break; + + hwnd = nct->hwnd_panel; + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + + if (!is_k5_identpro) { + + /* enumerate all realms and place in realms combo box */ + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_RESETCONTENT, + 0, 0); + + realms = khm_krb5_get_realm_list(); + if(realms) { + t = realms; + while(t && *t) { + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_ADDSTRING, + 0, (LPARAM) t); + t = multi_string_next(t); + } + free(realms); + } + + /* and set the default realm */ + defrealm = khm_krb5_get_default_realm(); + if(defrealm) { + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) defrealm); + + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + WM_SETTEXT, + 0, (LPARAM) defrealm); + free(defrealm); + } + } else { /* if krb5 is the identity provider */ + HWND hw_realms; + + /* in this case, the realm selection is done by the + identity provider prompts. */ + + hw_realms = GetDlgItem(hwnd, IDC_NCK5_REALM); +#ifdef DEBUG + assert(hw_realms); +#endif + EnableWindow(hw_realms, FALSE); + } + + if (nc->subtype == KMSG_CRED_NEW_CREDS) { + k5_read_dlg_params(csp_params, d); + } + + PostMessage(hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0); + } + break; + + case KMSG_CRED_DIALOG_NEW_IDENTITY: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + k5_dlg_data * d; + + nc = (khui_new_creds *) vparam; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + if (!nct) + break; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + + /* we only load the identity specific defaults if the user + hasn't changed the options */ + khui_cw_lock_nc(nc); + + if(!d->dirty && nc->n_identities > 0 && + nc->subtype == KMSG_CRED_NEW_CREDS) { + + khm_handle h_id = NULL; + khm_handle h_idk5 = NULL; + + do { + if(KHM_FAILED + (kcdb_identity_get_config(nc->identities[0], + 0, + &h_id))) + break; + + if(KHM_FAILED + (khc_open_space(h_id, CSNAME_KRB5CRED, + 0, &h_idk5))) + break; + + if(KHM_FAILED(khc_shadow_space(h_idk5, csp_params))) + break; + + k5_read_dlg_params(h_idk5, d); + + PostMessage(nct->hwnd_panel, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0); + } while(FALSE); + + if(h_id) + khc_close_space(h_id); + if(h_idk5) + khc_close_space(h_idk5); + } + + khui_cw_unlock_nc(nc); + } + + /* fallthrough */ + case KMSG_CRED_DIALOG_NEW_OPTIONS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + k5_dlg_data * d; + + nc = (khui_new_creds *) vparam; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + if (!nct) + break; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + + if (nc->subtype == KMSG_CRED_PASSWORD) { + khm_size n_prompts = 0; + + khui_cw_get_prompt_count(nc, &n_prompts); + + if (nc->n_identities == 0) { + if (n_prompts) + khui_cw_clear_prompts(nc); + } else if (n_prompts != 3) { + wchar_t wbuf[KHUI_MAXCCH_BANNER]; + + khui_cw_clear_prompts(nc); + + LoadString(hResModule, IDS_NC_PWD_BANNER, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_begin_custom_prompts(nc, 3, NULL, wbuf); + + LoadString(hResModule, IDS_NC_PWD_PWD, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_PASSWORD, + wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); + + LoadString(hResModule, IDS_NC_PWD_NPWD, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_NEW_PASSWORD, + wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); + + LoadString(hResModule, IDS_NC_PWD_NPWD_AGAIN, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_NEW_PASSWORD_AGAIN, + wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); + } + + return KHM_ERROR_SUCCESS; + } + /* else; nc->subtype == KMSG_CRED_NEW_CREDS */ + + assert(nc->subtype == KMSG_CRED_NEW_CREDS); + + /* if the fiber is already in a kinit, cancel it */ + if(g_fjob.state == FIBER_STATE_KINIT) { + g_fjob.command = FIBER_CMD_CANCEL; + SwitchToFiber(k5_kinit_fiber); + /* we get here when the cancel operation completes */ + k5_free_kinit_job(); + } + + khui_cw_lock_nc(nc); + + if(nc->n_identities > 0) { + khm_handle ident = nc->identities[0]; + + kcdb_identity_hold(ident); + + k5_prep_kinit_job(nc); + khui_cw_unlock_nc(nc); + + SwitchToFiber(k5_kinit_fiber); + /* we get here when the fiber switches back */ + if(g_fjob.state == FIBER_STATE_NONE) { + wchar_t msg[KHUI_MAXCCH_BANNER]; + khm_size cb; + + /* we can't possibly have succeeded without a + password */ + if(g_fjob.code) { + if (is_k5_identpro) + kcdb_identity_set_flags(ident, + KCDB_IDENT_FLAG_INVALID); + + khui_cw_clear_prompts(nc); + } + + if (d->cred_message) { + free(d->cred_message); + d->cred_message = NULL; + } + + msg[0] = L'\0'; + + switch(g_fjob.code) { + case KRB5KDC_ERR_NAME_EXP: + /* principal expired */ + LoadString(hResModule, IDS_K5ERR_NAME_EXPIRED, + msg, ARRAYLENGTH(msg)); + break; + + case KRB5KDC_ERR_KEY_EXP: + /* password needs changing */ + LoadString(hResModule, IDS_K5ERR_KEY_EXPIRED, + msg, ARRAYLENGTH(msg)); + break; + + default: + { + DWORD dw_dummy; + kherr_suggestion sug_dummy; + wchar_t fmt[KHUI_MAXCCH_BANNER]; + wchar_t desc[KHUI_MAXCCH_BANNER]; + + LoadString(hResModule, IDS_K5ERR_FMT, + fmt, ARRAYLENGTH(fmt)); + + khm_err_describe(g_fjob.code, + desc, + sizeof(desc), + &dw_dummy, + &sug_dummy); + + StringCbPrintf(msg, sizeof(msg), fmt, desc); + } + } + + if (msg[0]) { + StringCbLength(msg, sizeof(msg), &cb); + cb += sizeof(wchar_t); + + d->cred_message = malloc(cb); + StringCbCopy(d->cred_message, cb, msg); + } + + k5_free_kinit_job(); + + } else if(g_fjob.state == FIBER_STATE_KINIT) { + /* this is what we want. Leave the fiber there. */ + + if(is_k5_identpro) + kcdb_identity_set_flags(ident, + KCDB_IDENT_FLAG_VALID); + } else { + /* huh?? */ +#ifdef DEBUG + assert(FALSE); +#endif + } + + /* since the attributes of the identity have changed, + we should update the cred text as well */ + kcdb_identity_release(ident); + khui_cw_lock_nc(nc); + PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0); + } else { + khui_cw_unlock_nc(nc); + khui_cw_clear_prompts(nc); + khui_cw_lock_nc(nc); + } + + khui_cw_unlock_nc(nc); + } + break; + + case KMSG_CRED_PROCESS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + k5_dlg_data * d; + + khm_int32 r; + + nc = (khui_new_creds *) vparam; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + + if(!nct) + break; + + /* reset the null_password flag, just in case */ + g_fjob.null_password = FALSE; + + if (nc->subtype == KMSG_CRED_NEW_CREDS) { + d = (k5_dlg_data *) nct->aux; + + _begin_task(0); + _report_mr0(KHERR_NONE, MSG_CTX_INITAL_CREDS); + _describe(); + + if (g_fjob.state == FIBER_STATE_KINIT) { + if(nc->result == KHUI_NC_RESULT_CANCEL) { + g_fjob.command = FIBER_CMD_CANCEL; + SwitchToFiber(k5_kinit_fiber); + + /* if we cancelled out, then we shouldn't care + about the return code. */ +#ifdef DEBUG + assert(g_fjob.state == FIBER_STATE_NONE); +#endif + g_fjob.code = 0; + } else if (nc->result == KHUI_NC_RESULT_GET_CREDS) { + khui_cw_sync_prompt_values(nc); + g_fjob.command = FIBER_CMD_CONTINUE; + SwitchToFiber(k5_kinit_fiber); + + /* We get back here once the fiber finishes + processing */ + } +#ifdef DEBUG + else { + assert(FALSE); + } +#endif + } else { + /* we weren't in a KINIT state */ + if (nc->result == KHUI_NC_RESULT_CANCEL) { + /* nothing to report */ + g_fjob.code = 0; + } else if (nc->result == KHUI_NC_RESULT_GET_CREDS) { + /* g_fjob.code should have the result of the + last kinit attempt. We should leave it + as-is */ + } +#ifdef DEBUG + else { + /* unknown result */ + assert(FALSE); + } +#endif + } + + /* special case: if there was no password entered, and + if there is a valid TGT we allow the credential + acquisition to go through */ + if (g_fjob.state == FIBER_STATE_NONE && + g_fjob.code && + g_fjob.null_password && + + (nc->n_identities == 0 || + nc->identities[0] == NULL || + KHM_SUCCEEDED(kcdb_credset_find_filtered + (NULL, + -1, + k5_find_tgt_filter, + nc->identities[0], + NULL, + NULL)))) + g_fjob.code = 0; + + + if(g_fjob.code != 0) { + wchar_t tbuf[1024]; + DWORD suggestion; + kherr_suggestion suggest_code; + + khm_err_describe(g_fjob.code, tbuf, sizeof(tbuf), + &suggestion, &suggest_code); + + _report_cs0(KHERR_ERROR, tbuf); + if (suggestion != 0) + _suggest_mr(suggestion, suggest_code); + + _resolve(); + + r = KHUI_NC_RESPONSE_FAILED; + + if (suggest_code == KHERR_SUGGEST_RETRY) { + r |= KHUI_NC_RESPONSE_NOEXIT | + KHUI_NC_RESPONSE_PENDING; + } + +#ifdef DEBUG + assert(g_fjob.state == FIBER_STATE_NONE); +#endif + + } else if (nc->result == KHUI_NC_RESULT_GET_CREDS && + g_fjob.state == FIBER_STATE_NONE) { + khm_handle sp = NULL; + khm_handle ep = NULL; + krb5_context ctx = NULL; + wchar_t * wbuf; + wchar_t * idname; + wchar_t * atsign; + khm_size cb; + khm_size cb_ms; + khm_int32 rv; + + r = KHUI_NC_RESPONSE_SUCCESS | + KHUI_NC_RESPONSE_EXIT; + + /* if we successfully obtained credentials, we + should save the current settings in the + identity config space */ + + assert(nc->n_identities > 0); + assert(nc->identities[0]); + + if(KHM_SUCCEEDED + (kcdb_identity_get_config(nc->identities[0], + KHM_FLAG_CREATE, + &sp)) && + KHM_SUCCEEDED + (khc_open_space(sp, CSNAME_KRB5CRED, + KHM_FLAG_CREATE, &ep))) { + k5_write_dlg_params(ep, d); + } + + if(ep != NULL) + khc_close_space(ep); + if(sp != NULL) + khc_close_space(sp); + + /* We should also quickly refresh the credentials + so that the identity flags and ccache + properties reflect the current state of + affairs. This has to be done here so that + other credentials providers which depend on + Krb5 can properly find the initial creds to + obtain their respective creds. */ + + khm_krb5_list_tickets(&ctx); + + /* also add the principal and the realm in to the + LRU lists */ + rv = kcdb_identity_get_name(nc->identities[0], + NULL, + &cb); + assert(rv == KHM_ERROR_TOO_LONG); + + idname = malloc(cb); + assert(idname); + + rv = kcdb_identity_get_name(nc->identities[0], + idname, + &cb); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_read_multi_string(csp_params, + L"LRUPrincipals", + NULL, + &cb_ms); + if (rv != KHM_ERROR_TOO_LONG) + cb_ms = cb + sizeof(wchar_t); + else + cb_ms += cb + sizeof(wchar_t); + + wbuf = malloc(cb_ms); + assert(wbuf); + + cb = cb_ms; + + if (rv == KHM_ERROR_TOO_LONG) { + rv = khc_read_multi_string(csp_params, + L"LRUPrincipals", + wbuf, + &cb); + assert(KHM_SUCCEEDED(rv)); + + if (multi_string_find(wbuf, + idname, + KHM_CASE_SENSITIVE) + != NULL) + /* it's already there */ + goto _add_realm_to_LRU; + } else { + multi_string_init(wbuf, cb_ms); + } + + cb = cb_ms; + rv = multi_string_prepend(wbuf, &cb, idname); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_write_multi_string(csp_params, + L"LRUPrincipals", + wbuf); + + _add_realm_to_LRU: + + atsign = wcschr(idname, L'@'); + assert(atsign != NULL); + + atsign++; + assert(*atsign != L'\0'); + + cb = cb_ms; + rv = khc_read_multi_string(csp_params, + L"LRURealms", + wbuf, + &cb); + + if (rv == KHM_ERROR_TOO_LONG) { + free(wbuf); + wbuf = malloc(cb); + assert(wbuf); + + cb_ms = cb; + + rv = khc_read_multi_string(csp_params, + L"LRURealms", + wbuf, + &cb); + + assert(KHM_SUCCEEDED(rv)); + } else if (rv == KHM_ERROR_SUCCESS) { + if (multi_string_find(wbuf, + atsign, + KHM_CASE_SENSITIVE) + != NULL) + goto _done_with_LRU; + } else { + multi_string_init(wbuf, cb_ms); + } + + cb = cb_ms; + rv = multi_string_prepend(wbuf, + &cb, + atsign); + + if (rv == KHM_ERROR_TOO_LONG) { + wbuf = realloc(wbuf, cb); + + rv = multi_string_prepend(wbuf, + &cb, + atsign); + + assert(KHM_SUCCEEDED(rv)); + } + + rv = khc_write_multi_string(csp_params, + L"LRURealms", + wbuf); + assert(KHM_SUCCEEDED(rv)); + + _done_with_LRU: + + if (ctx != NULL) + pkrb5_free_context(ctx); + + if (idname) + free(idname); + + if (wbuf) + free(wbuf); + } else if (g_fjob.state == FIBER_STATE_NONE) { + /* the user cancelled the operation */ + r = KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_SUCCESS; + } + + if(g_fjob.state == FIBER_STATE_NONE) { + khui_cw_set_response(nc, credtype_id_krb5, r); + + if (r & KHUI_NC_RESPONSE_NOEXIT) { + /* if we are retrying the call, we should + restart the kinit fiber */ +#ifdef DEBUG + assert(r & KHUI_NC_RESPONSE_PENDING); +#endif + + k5_prep_kinit_job(nc); + SwitchToFiber(k5_kinit_fiber); + } else { + /* free up the fiber data fields. */ + k5_free_kinit_job(); + } + } else { + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_NOEXIT | + KHUI_NC_RESPONSE_PENDING | r); + } + + _end_task(); + } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { + + _begin_task(0); + _report_mr0(KHERR_NONE, MSG_CTX_RENEW_CREDS); + _describe(); + + if (nc->ctx.scope == KHUI_SCOPE_IDENT || + (nc->ctx.scope == KHUI_SCOPE_CREDTYPE && + nc->ctx.cred_type == credtype_id_krb5)) { + int code; + + if (nc->ctx.identity != 0) + code = khm_krb5_renew(nc->ctx.identity); + else + code = 1; /* it just has to be non-zero */ + + if (code == 0) { + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_SUCCESS); + } else if (nc->ctx.identity == 0) { + + _report_mr0(KHERR_ERROR, MSG_ERR_NO_IDENTITY); + + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_FAILED); + } else { + wchar_t tbuf[1024]; + DWORD suggestion; + kherr_suggestion sug_id; + + khm_err_describe(code, tbuf, sizeof(tbuf), + &suggestion, &sug_id); + + _report_cs0(KHERR_ERROR, tbuf); + if (suggestion) + _suggest_mr(suggestion, sug_id); + + _resolve(); + + khui_cw_set_response(nc, credtype_id_krb5, + ((sug_id == KHERR_SUGGEST_RETRY)?KHUI_NC_RESPONSE_NOEXIT:KHUI_NC_RESPONSE_EXIT) | + KHUI_NC_RESPONSE_FAILED); + } + } else { + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_SUCCESS); + } + + _end_task(); + } else if (nc->subtype == KMSG_CRED_PASSWORD && + nc->result == KHUI_NC_RESULT_GET_CREDS) { + + _begin_task(0); + _report_mr0(KHERR_NONE, MSG_CTX_PASSWD); + _describe(); + + khui_cw_lock_nc(nc); + + if (nc->n_identities == 0 || + nc->identities[0] == NULL) { + _report_mr0(KHERR_ERROR, MSG_PWD_NO_IDENTITY); + _suggest_mr(MSG_PWD_S_NO_IDENTITY, KHERR_SUGGEST_RETRY); + + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_FAILED | + KHUI_NC_RESPONSE_NOEXIT); + } else { + wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; + char idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wpwd[KHUI_MAXCCH_PASSWORD]; + char pwd[KHUI_MAXCCH_PASSWORD]; + wchar_t wnpwd[KHUI_MAXCCH_PASSWORD]; + char npwd[KHUI_MAXCCH_PASSWORD]; + wchar_t wnpwd2[KHUI_MAXCCH_PASSWORD]; + wchar_t * wresult; + char * result; + khm_size n_prompts = 0; + khm_size cb; + khm_int32 rv = KHM_ERROR_SUCCESS; + long code = 0; + khm_handle ident; + + khui_cw_get_prompt_count(nc, &n_prompts); + assert(n_prompts == 3); + + ident = nc->identities[0]; + cb = sizeof(widname); + rv = kcdb_identity_get_name(ident, widname, &cb); + if (KHM_FAILED(rv)) { +#ifdef DEBUG + assert(FALSE); +#endif + _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); + goto _pwd_exit; + } + + cb = sizeof(wpwd); + rv = khui_cw_get_prompt_value(nc, 0, wpwd, &cb); + if (KHM_FAILED(rv)) { +#ifdef DEBUG + assert(FALSE); +#endif + _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); + goto _pwd_exit; + } + + cb = sizeof(wnpwd); + rv = khui_cw_get_prompt_value(nc, 1, wnpwd, &cb); + if (KHM_FAILED(rv)) { +#ifdef DEBUG + assert(FALSE); +#endif + _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); + goto _pwd_exit; + } + + cb = sizeof(wnpwd2); + rv = khui_cw_get_prompt_value(nc, 2, wnpwd2, &cb); + if (KHM_FAILED(rv)) { +#ifdef DEBUG + assert(FALSE); +#endif + _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); + goto _pwd_exit; + } + + if (wcscmp(wnpwd, wnpwd2)) { + rv = KHM_ERROR_INVALID_PARM; + _report_mr0(KHERR_ERROR, MSG_PWD_NOT_SAME); + _suggest_mr(MSG_PWD_S_NOT_SAME, KHERR_SUGGEST_INTERACT); + goto _pwd_exit; + } + + if (!wcscmp(wpwd, wnpwd)) { + rv = KHM_ERROR_INVALID_PARM; + _report_mr0(KHERR_ERROR, MSG_PWD_SAME); + _suggest_mr(MSG_PWD_S_SAME, KHERR_SUGGEST_INTERACT); + goto _pwd_exit; + } + + UnicodeStrToAnsi(idname, sizeof(idname), widname); + UnicodeStrToAnsi(pwd, sizeof(pwd), wpwd); + UnicodeStrToAnsi(npwd, sizeof(npwd), wnpwd); + + result = NULL; + + code = khm_krb5_changepwd(idname, + pwd, + npwd, + &result); + + if (code) + rv = KHM_ERROR_UNKNOWN; + + /* result is only set when code != 0 */ + if (code && result) { + size_t len; + + StringCchLengthA(result, KHERR_MAXCCH_STRING, + &len); + wresult = malloc((len + 1) * sizeof(wchar_t)); +#ifdef DEBUG + assert(wresult); +#endif + AnsiStrToUnicode(wresult, (len + 1) * sizeof(wchar_t), + result); + + _report_cs1(KHERR_ERROR, L"%1!s!", _cstr(wresult)); + _resolve(); + + free(result); + free(wresult); + + /* leave wresult. It will get freed when the + reported event is freed. */ + + /* we don't need to report anything more */ + code = 0; + } + + _pwd_exit: + if (KHM_FAILED(rv)) { + if (code) { + wchar_t tbuf[1024]; + DWORD suggestion; + kherr_suggestion sug_id; + + khm_err_describe(code, tbuf, sizeof(tbuf), + &suggestion, &sug_id); + _report_cs0(KHERR_ERROR, tbuf); + + if (suggestion) + _suggest_mr(suggestion, sug_id); + + _resolve(); + } + + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_NOEXIT| + KHUI_NC_RESPONSE_FAILED); + } else { + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_SUCCESS | + KHUI_NC_RESPONSE_EXIT); + } + } + + khui_cw_unlock_nc(nc); + + _end_task(); + } /* KMSG_CRED_PASSWORD */ + } + break; + + case KMSG_CRED_END: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + + nc = (khui_new_creds *) vparam; + khui_cw_find_type(nc, credtype_id_krb5, &nct); + + if(!nct) + break; + + khui_cw_del_type(nc, credtype_id_krb5); + + if(nct->name) + free(nct->name); + + free(nct); + } + break; + + case KMSG_CRED_IMPORT: + { + khm_krb5_ms2mit(TRUE); + } + break; + } + + return rv; +} diff --git a/src/windows/identity/plugins/krb5/krb5plugin.c b/src/windows/identity/plugins/krb5/krb5plugin.c new file mode 100644 index 0000000000..4b53ed3e8f --- /dev/null +++ b/src/windows/identity/plugins/krb5/krb5plugin.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include + +khm_int32 credtype_id_krb5 = KCDB_CREDTYPE_INVALID; +khm_boolean krb5_initialized = FALSE; +khm_handle krb5_credset = NULL; + +khm_handle k5_sub = NULL; + +LPVOID k5_main_fiber = NULL; +LPVOID k5_kinit_fiber = NULL; + +VOID CALLBACK k5_kinit_fiber_proc(PVOID lpParameter); + +krb5_context k5_identpro_ctx = NULL; + +/* The system message handler. + + Runs in the context of the plugin thread */ +khm_int32 KHMAPI k5_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_SYSTEM_INIT: + { + kcdb_credtype ct; + wchar_t buf[KCDB_MAXCCH_SHORT_DESC]; + size_t cbsize; + + /* perform critical registrations and initialization + stuff */ + ZeroMemory(&ct, sizeof(ct)); + ct.id = KCDB_CREDTYPE_AUTO; + ct.name = KRB5_CREDTYPE_NAME; + + if(LoadString(hResModule, IDS_KRB5_SHORT_DESC, buf, ARRAYLENGTH(buf))) + { + StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); + cbsize += sizeof(wchar_t); + ct.short_desc = malloc(cbsize); + StringCbCopy(ct.short_desc, cbsize, buf); + } + + /* even though ideally we should be setting limits + based KCDB_MAXCB_LONG_DESC, our long description + actually fits nicely in KCDB_MAXCB_SHORT_DESC */ + if(LoadString(hResModule, IDS_KRB5_LONG_DESC, buf, ARRAYLENGTH(buf))) + { + StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); + cbsize += sizeof(wchar_t); + ct.long_desc = malloc(cbsize); + StringCbCopy(ct.long_desc, cbsize, buf); + } + + ct.icon = NULL; /* TODO: set a proper icon */ + + kmq_create_subscription(k5_msg_callback, &ct.sub); + + rv = kcdb_credtype_register(&ct, &credtype_id_krb5); + + if(KHM_SUCCEEDED(rv)) + rv = kcdb_credset_create(&krb5_credset); + + if(ct.short_desc) + free(ct.short_desc); + + if(ct.long_desc) + free(ct.long_desc); + + if (is_k5_identpro) + kcdb_identity_set_type(credtype_id_krb5); + + if(KHM_SUCCEEDED(rv)) { + krb5_context ctx = NULL; + + krb5_initialized = TRUE; + + khm_krb5_list_tickets(&ctx); + + if(ctx != NULL) + pkrb5_free_context(ctx); + + /* now convert this thread to a fiber and create a + separate fiber to do kinit stuff */ + k5_main_fiber = ConvertThreadToFiber(NULL); + k5_kinit_fiber = CreateFiber(0,k5_kinit_fiber_proc,NULL); + + ZeroMemory(&g_fjob, sizeof(g_fjob)); + + kmq_create_subscription(k5_msg_callback, &k5_sub); + + pkrb5_init_context(&k5_identpro_ctx); + + k5_register_config_panels(); + } + } + break; + + case KMSG_SYSTEM_EXIT: + + k5_unregister_config_panels(); + + if(credtype_id_krb5 >= 0) + { + /* basically just unregister the credential type */ + kcdb_credtype_unregister(credtype_id_krb5); + + /* kcdb knows how to deal with bad handles */ + kcdb_credset_delete(krb5_credset); + krb5_credset = NULL; + } + + if(k5_main_fiber != NULL) { + ConvertFiberToThread(); + k5_main_fiber = NULL; + } + + if(k5_sub != NULL) { + kmq_delete_subscription(k5_sub); + k5_sub = NULL; + } + + if (k5_identpro_ctx) { + pkrb5_free_context(k5_identpro_ctx); + k5_identpro_ctx = NULL; + } + + break; + } + + return rv; +} + + +/* Handler for CRED type messages + + Runs in the context of the Krb5 plugin +*/ +khm_int32 KHMAPI k5_msg_cred(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_CRED_REFRESH: + { + krb5_context ctx = NULL; + + khm_krb5_list_tickets(&ctx); + + if(ctx != NULL) + pkrb5_free_context(ctx); + } + break; + + case KMSG_CRED_DESTROY_CREDS: + { + khui_action_context * ctx; + + ctx = (khui_action_context *) vparam; + + if (ctx->credset) + khm_krb5_destroy_by_credset(ctx->credset); + } + break; + + case KMSG_CRED_PP_BEGIN: + k5_pp_begin((khui_property_sheet *) vparam); + break; + + case KMSG_CRED_PP_END: + k5_pp_end((khui_property_sheet *) vparam); + break; + + default: + if(IS_CRED_ACQ_MSG(msg_subtype)) + return k5_msg_cred_dialog(msg_type, msg_subtype, + uparam, vparam); + } + + return rv; +} + +/* The main message handler. We don't do much here, except delegate + to other message handlers + + Runs in the context of the Krb5 plugin +*/ +khm_int32 KHMAPI k5_msg_callback(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam) +{ + switch(msg_type) { + case KMSG_SYSTEM: + return k5_msg_system(msg_type, msg_subtype, uparam, vparam); + case KMSG_CRED: + return k5_msg_cred(msg_type, msg_subtype, uparam, vparam); + case KMSG_IDENT: + return k5_msg_ident(msg_type, msg_subtype, uparam, vparam); + } + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/plugins/krb5/krb5props.c b/src/windows/identity/plugins/krb5/krb5props.c new file mode 100644 index 0000000000..9134de2925 --- /dev/null +++ b/src/windows/identity/plugins/krb5/krb5props.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include + +/* Property page + + Runs in the context of the UI thread. + */ +INT_PTR CALLBACK krb5_pp_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ) +{ + switch(uMsg) { + case WM_INITDIALOG: + { + khui_property_sheet * s; + PROPSHEETPAGE * p; + wchar_t buf[512]; + khm_size cbsize; + + p = (PROPSHEETPAGE *) lParam; + s = (khui_property_sheet *) p->lParam; + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) s); +#pragma warning(pop) + + if(s->cred) { + cbsize = sizeof(buf); + kcdb_cred_get_name(s->cred, buf, &cbsize); + SetDlgItemText(hwnd, IDC_PPK5_NAME, buf); + + cbsize = sizeof(buf); + kcdb_cred_get_attr_string(s->cred, KCDB_ATTR_ISSUE, buf, &cbsize, 0); + SetDlgItemText(hwnd, IDC_PPK5_ISSUE, buf); + + cbsize = sizeof(buf); + kcdb_cred_get_attr_string(s->cred, KCDB_ATTR_EXPIRE, buf, &cbsize, 0); + SetDlgItemText(hwnd, IDC_PPK5_VALID, buf); + + cbsize = sizeof(buf); + kcdb_cred_get_attr_string(s->cred, KCDB_ATTR_RENEW_EXPIRE, buf, &cbsize, 0); + SetDlgItemText(hwnd, IDC_PPK5_RENEW, buf); + + /*TODO: select other properties */ + } else { + /*TODO: select properties */ + } + } + return FALSE; + } + + return FALSE; +} + +void k5_pp_begin(khui_property_sheet * s) +{ + PROPSHEETPAGE *p; + + if(s->credtype == credtype_id_krb5) { + p = malloc(sizeof(*p)); + ZeroMemory(p, sizeof(*p)); + + p->dwSize = sizeof(*p); + p->dwFlags = 0; + p->hInstance = hResModule; + p->pszTemplate = (s->cred)? MAKEINTRESOURCE(IDD_PP_KRB5C): MAKEINTRESOURCE(IDD_PP_KRB5); + p->pfnDlgProc = krb5_pp_proc; + p->lParam = (LPARAM) s; + khui_ps_add_page(s, credtype_id_krb5, 0, p, NULL); + } +} + +void k5_pp_end(khui_property_sheet * s) +{ + khui_property_page * p = NULL; + + khui_ps_find_page(s, credtype_id_krb5, &p); + if(p) { + if(p->p_page) + free(p->p_page); + p->p_page = NULL; + } +} + diff --git a/src/windows/identity/plugins/krb5/krb5util.c b/src/windows/identity/plugins/krb5/krb5util.c new file mode 100644 index 0000000000..b892531afc --- /dev/null +++ b/src/windows/identity/plugins/krb5/krb5util.c @@ -0,0 +1,1362 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include "leashdll.h" +#include +#include +#include + +#include +#include "leasherr.h" +#include "leash-int.h" +#include "leashids.h" + +#include + +#include +#include "reminder.h" + +static char FAR *err_context; + +char KRB_HelpFile[_MAX_PATH] = HELPFILE; + +#define LEN 64 /* Maximum Hostname Length */ + +#define LIFE DEFAULT_TKT_LIFE /* lifetime of ticket in 5-minute units */ + +char * +short_date(dp) + long *dp; +{ + register char *cp; + cp = ctime(dp) + 4; // skip day of week + // cp[15] = '\0'; + cp[12] = '\0'; // Don't display seconds + return (cp); +} + + +static +char* +clean_string( + char* s + ) +{ + char* p = s; + char* b = s; + + if (!s) return s; + + for (p = s; *p; p++) { + switch (*p) { + case '\007': + /* Add more cases here */ + break; + default: + *b = *p; + b++; + } + } + *b = *p; + return s; +} + +static +int +leash_error_message( + const char *error, + int rcL, + int rc4, + int rc5, + int rcA, + char* result_string, + int displayMB + ) +{ + char message[2048]; + char *p = message; + int size = sizeof(message); + int n; + + // XXX: ignore AFS for now. + + if (!rc5 && !rc4 && !rcL) + return 0; + + n = _snprintf(p, size, "%s\n\n", error); + p += n; + size -= n; + + if (rc5 && !result_string) + { + n = _snprintf(p, size, + "Kerberos 5: %s (error %ld)\n", + perror_message(rc5), + rc5 & 255 // XXX: & 255??!!! + ); + p += n; + size -= n; + } + if (rc4 && !result_string) + { + char buffer[1024]; + n = _snprintf(p, size, + "Kerberos 4: %s\n", + err_describe(buffer, rc4) + ); + p += n; + size -= n; + } + if (rcL) + { + char buffer[1024]; + n = _snprintf(p, size, + "\n%s\n", + err_describe(buffer, rcL) + ); + p += n; + size -= n; + } + if (result_string) + { + n = _snprintf(p, size, + "%s\n", + result_string); + p += n; + size -= n; + } + if ( displayMB ) + MessageBox(NULL, message, "Leash", MB_OK | MB_ICONERROR | MB_TASKMODAL | + MB_SETFOREGROUND); + + if (rc5) return rc5; + if (rc4) return rc4; + if (rcL) return rcL; + return 0; +} + + +static +char * +make_postfix( + const char * base, + const char * postfix, + char ** rcopy + ) +{ + int base_size; + int ret_size; + char * copy = 0; + char * ret = 0; + + base_size = strlen(base) + 1; + ret_size = base_size + strlen(postfix) + 1; + copy = malloc(base_size); + ret = malloc(ret_size); + + if (!copy || !ret) + goto cleanup; + + strncpy(copy, base, base_size); + copy[base_size - 1] = 0; + + strncpy(ret, base, base_size); + strncpy(ret + (base_size - 1), postfix, ret_size - (base_size - 1)); + ret[ret_size - 1] = 0; + + cleanup: + if (!copy || !ret) { + if (copy) + free(copy); + if (ret) + free(ret); + copy = ret = 0; + } + // INVARIANT: (ret ==> copy) && (copy ==> ret) + *rcopy = copy; + return ret; +} + +static +long +make_temp_cache_v4( + const char * postfix + ) +{ + static char * old_cache = 0; + + if (!pkrb_set_tkt_string || !ptkt_string || !pdest_tkt) + return 0; // XXX - is this appropriate? + + if (old_cache) { + pdest_tkt(); + pkrb_set_tkt_string(old_cache); + free(old_cache); + old_cache = 0; + } + + if (postfix) + { + char * tmp_cache = make_postfix(ptkt_string(), postfix, &old_cache); + + if (!tmp_cache) + return KFAILURE; + + pkrb_set_tkt_string(tmp_cache); + free(tmp_cache); + } + return 0; +} + +static +long +make_temp_cache_v5( + const char * postfix, + krb5_context * pctx + ) +{ + static krb5_context ctx = 0; + static char * old_cache = 0; + + // INVARIANT: old_cache ==> ctx && ctx ==> old_cache + + if (pctx) + *pctx = 0; + + if (!pkrb5_init_context || !pkrb5_free_context || !pkrb5_cc_resolve || + !pkrb5_cc_default_name || !pkrb5_cc_set_default_name) + return 0; + + if (old_cache) { + krb5_ccache cc = 0; + if (!pkrb5_cc_resolve(ctx, pkrb5_cc_default_name(ctx), &cc)) + pkrb5_cc_destroy(ctx, cc); + pkrb5_cc_set_default_name(ctx, old_cache); + free(old_cache); + old_cache = 0; + } + if (ctx) { + pkrb5_free_context(ctx); + ctx = 0; + } + + if (postfix) + { + char * tmp_cache = 0; + krb5_error_code rc = 0; + + rc = pkrb5_init_context(&ctx); + if (rc) goto cleanup; + + tmp_cache = make_postfix(pkrb5_cc_default_name(ctx), postfix, + &old_cache); + + if (!tmp_cache) { + rc = ENOMEM; + goto cleanup; + } + + rc = pkrb5_cc_set_default_name(ctx, tmp_cache); + + cleanup: + if (rc && ctx) { + pkrb5_free_context(ctx); + ctx = 0; + } + if (tmp_cache) + free(tmp_cache); + if (pctx) + *pctx = ctx; + return rc; + } + return 0; +} + +long +Leash_checkpwd( + char *principal, + char *password + ) +{ + return Leash_int_checkpwd(principal, password, 0); +} + +long +Leash_int_checkpwd( + char * principal, + char * password, + int displayErrors + ) +{ + long rc = 0; + krb5_context ctx = 0; // statically allocated in make_temp_cache_v5 + // XXX - we ignore errors in make_temp_cache_v? This is BAD!!! + make_temp_cache_v4("_checkpwd"); + make_temp_cache_v5("_checkpwd", &ctx); + rc = Leash_int_kinit_ex( ctx, 0, + principal, password, 0, 0, 0, 0, + Leash_get_default_noaddresses(), + Leash_get_default_publicip(), + displayErrors + ); + make_temp_cache_v4(0); + make_temp_cache_v5(0, &ctx); + return rc; +} + +static +long +Leash_changepwd_v5(char * principal, + char * password, + char * newpassword, + char** error_str) +{ + krb5_error_code rc = 0; + int result_code; + krb5_data result_code_string, result_string; + krb5_context context = 0; + krb5_principal princ = 0; + krb5_get_init_creds_opt opts; + krb5_creds creds; + DWORD addressless = 0; + + result_string.data = 0; + result_code_string.data = 0; + + if ( !pkrb5_init_context ) + goto cleanup; + + if (rc = pkrb5_init_context(&context)) { +#if 0 + com_err(argv[0], ret, "initializing kerberos library"); +#endif + goto cleanup; + } + + if (rc = pkrb5_parse_name(context, principal, &princ)) { +#if 0 + com_err(argv[0], ret, "parsing client name"); +#endif + goto cleanup; + } + + pkrb5_get_init_creds_opt_init(&opts); + pkrb5_get_init_creds_opt_set_tkt_life(&opts, 5*60); + pkrb5_get_init_creds_opt_set_renew_life(&opts, 0); + pkrb5_get_init_creds_opt_set_forwardable(&opts, 0); + pkrb5_get_init_creds_opt_set_proxiable(&opts, 0); + + addressless = Leash_get_default_noaddresses(); + if (addressless) + pkrb5_get_init_creds_opt_set_address_list(&opts,NULL); + + + if (rc = pkrb5_get_init_creds_password(context, &creds, princ, password, + 0, 0, 0, "kadmin/changepw", &opts)) { + if (rc == KRB5KRB_AP_ERR_BAD_INTEGRITY) { +#if 0 + com_err(argv[0], 0, + "Password incorrect while getting initial ticket"); +#endif + } + else { +#if 0 + com_err(argv[0], ret, "getting initial ticket"); +#endif + } + goto cleanup; + } + + if (rc = pkrb5_change_password(context, &creds, newpassword, + &result_code, &result_code_string, + &result_string)) { +#if 0 + com_err(argv[0], ret, "changing password"); +#endif + goto cleanup; + } + + if (result_code) { + int len = result_code_string.length + + (result_string.length ? (sizeof(": ") - 1) : 0) + + result_string.length; + if (len && error_str) { + *error_str = malloc(len + 1); + if (*error_str) + _snprintf(*error_str, len + 1, + "%.*s%s%.*s", + result_code_string.length, result_code_string.data, + result_string.length?": ":"", + result_string.length, result_string.data); + } + rc = result_code; + goto cleanup; + } + + cleanup: + if (result_string.data) + pkrb5_free_data_contents(context, &result_string); + + if (result_code_string.data) + pkrb5_free_data_contents(context, &result_code_string); + + if (princ) + pkrb5_free_principal(context, princ); + + if (context) + pkrb5_free_context(context); + + return rc; +} + +static +long +Leash_changepwd_v4( + char * principal, + char * password, + char * newpassword, + char** error_str + ) +{ + long k_errno; + + if (!pkrb_set_tkt_string || !ptkt_string || !pkadm_change_your_password || + !pdest_tkt) + return KFAILURE; + + k_errno = make_temp_cache_v4("_chgpwd"); + if (k_errno) return k_errno; + k_errno = pkadm_change_your_password(principal, password, newpassword, + error_str); + make_temp_cache_v4(0); + return k_errno; +} + +/* + * Leash_changepwd + * + * Try to change the password using one of krb5 or krb4 -- whichever one + * works. We return ok on the first one that works. + */ +long +Leash_changepwd( + char * principal, + char * password, + char * newpassword, + char** result_string + ) +{ + return Leash_int_changepwd(principal, password, newpassword, result_string, 0); +} + +long +Leash_int_changepwd( + char * principal, + char * password, + char * newpassword, + char** result_string, + int displayErrors + ) +{ + char* v5_error_str = 0; + char* v4_error_str = 0; + char* error_str = 0; + int rc4 = 0; + int rc5 = 0; + int rc = 0; + if (hKrb5) + rc = rc5 = Leash_changepwd_v5(principal, password, newpassword, + &v5_error_str); + if (hKrb4 && + Leash_get_default_use_krb4() && + (!hKrb5 || rc5)) + rc = rc4 = Leash_changepwd_v4(principal, password, newpassword, + &v4_error_str); + if (!rc) + return 0; + if (v5_error_str || v4_error_str) { + int len = 0; + char v5_prefix[] = "Kerberos 5: "; + char sep[] = "\n"; + char v4_prefix[] = "Kerberos 4: "; + + clean_string(v5_error_str); + clean_string(v4_error_str); + + if (v5_error_str) + len += sizeof(sep) + sizeof(v5_prefix) + strlen(v5_error_str) + + sizeof(sep); + if (v4_error_str) + len += sizeof(sep) + sizeof(v4_prefix) + strlen(v4_error_str) + + sizeof(sep); + error_str = malloc(len + 1); + if (error_str) { + char* p = error_str; + int size = len + 1; + int n; + if (v5_error_str) { + n = _snprintf(p, size, "%s%s%s%s", + sep, v5_prefix, v5_error_str, sep); + p += n; + size -= n; + } + if (v4_error_str) { + n = _snprintf(p, size, "%s%s%s%s", + sep, v4_prefix, v4_error_str, sep); + p += n; + size -= n; + } + if (result_string) + *result_string = error_str; + } + } + return leash_error_message("Error while changing password.", + rc4, rc4, rc5, 0, error_str, + displayErrors + ); +} + +int (*Lcom_err)(LPSTR,long,LPSTR,...); +LPSTR (*Lerror_message)(long); +LPSTR (*Lerror_table_name)(long); + + +long +Leash_kinit( + char * principal, + char * password, + int lifetime + ) +{ + return Leash_int_kinit_ex( 0, 0, + principal, + password, + lifetime, + Leash_get_default_forwardable(), + Leash_get_default_proxiable(), + Leash_get_default_renew_till(), + Leash_get_default_noaddresses(), + Leash_get_default_publicip(), + 0 + ); +} + +long +Leash_kinit_ex( + char * principal, + char * password, + int lifetime, + int forwardable, + int proxiable, + int renew_life, + int addressless, + unsigned long publicip + ) +{ + return Leash_int_kinit_ex( 0, /* krb5 context */ + 0, /* parent window */ + principal, + password, + lifetime, + forwardable, + proxiable, + renew_life, + addressless, + publicip, + 0 + ); +} + +long +Leash_int_kinit_ex( + krb5_context ctx, + HWND hParent, + char * principal, + char * password, + int lifetime, + int forwardable, + int proxiable, + int renew_life, + int addressless, + unsigned long publicip, + int displayErrors + ) +{ + LPCSTR functionName; + char aname[ANAME_SZ]; + char inst[INST_SZ]; + char realm[REALM_SZ]; + char first_part[256]; + char second_part[256]; + char temp[1024]; + int count; + int i; + int rc4 = 0; + int rc5 = 0; + int rcA = 0; + int rcL = 0; + + if (lifetime < 5) + lifetime = 1; + else + lifetime /= 5; + + if (renew_life > 0 && renew_life < 5) + renew_life = 1; + else + renew_life /= 5; + + /* This should be changed if the maximum ticket lifetime */ + /* changes */ + + if (lifetime > 255) + lifetime = 255; + + err_context = "parsing principal"; + + memset(temp, '\0', sizeof(temp)); + memset(inst, '\0', sizeof(inst)); + memset(realm, '\0', sizeof(realm)); + memset(first_part, '\0', sizeof(first_part)); + memset(second_part, '\0', sizeof(second_part)); + + sscanf(principal, "%[/0-9a-zA-Z._-]@%[/0-9a-zA-Z._-]", first_part, second_part); + strcpy(temp, first_part); + strcpy(realm, second_part); + memset(first_part, '\0', sizeof(first_part)); + memset(second_part, '\0', sizeof(second_part)); + if (sscanf(temp, "%[@0-9a-zA-Z._-]/%[@0-9a-zA-Z._-]", first_part, second_part) == 2) + { + strcpy(aname, first_part); + strcpy(inst, second_part); + } + else + { + count = 0; + i = 0; + for (i = 0; temp[i]; i++) + { + if (temp[i] == '.') + ++count; + } + if (count > 1) + { + strcpy(aname, temp); + } + else + { + if (pkname_parse != NULL) + { + memset(first_part, '\0', sizeof(first_part)); + memset(second_part, '\0', sizeof(second_part)); + sscanf(temp, "%[@/0-9a-zA-Z_-].%[@/0-9a-zA-Z_-]", first_part, second_part); + strcpy(aname, first_part); + strcpy(inst, second_part); + } + else + { + strcpy(aname, temp); + } + } + } + + memset(temp, '\0', sizeof(temp)); + strcpy(temp, aname); + if (strlen(inst) != 0) + { + strcat(temp, "/"); + strcat(temp, inst); + } + if (strlen(realm) != 0) + { + strcat(temp, "@"); + strcat(temp, realm); + } + + rc5 = Leash_krb5_kinit(ctx, hParent, + temp, password, lifetime, + forwardable, + proxiable, + renew_life, + addressless, + publicip + ); + if ( Leash_get_default_use_krb4() ) { + if ( !rc5 ) { + if (!Leash_convert524(ctx)) + rc4 = KFAILURE; + } else { + if (pkname_parse == NULL) + { + goto cleanup; + } + + err_context = "getting realm"; + if (!*realm && (rc4 = (int)(*pkrb_get_lrealm)(realm, 1))) + { + functionName = "krb_get_lrealm()"; + rcL = LSH_FAILEDREALM; + goto cleanup; + } + + err_context = "checking principal"; + if ((!*aname) || (!(rc4 = (int)(*pk_isname)(aname)))) + { + functionName = "krb_get_lrealm()"; + rcL = LSH_INVPRINCIPAL; + goto cleanup; + } + + /* optional instance */ + if (!(rc4 = (int)(*pk_isinst)(inst))) + { + functionName = "k_isinst()"; + rcL = LSH_INVINSTANCE; + goto cleanup; + } + + if (!(rc4 = (int)(*pk_isrealm)(realm))) + { + functionName = "k_isrealm()"; + rcL = LSH_INVREALM; + goto cleanup; + } + + err_context = "fetching ticket"; + rc4 = (*pkrb_get_pw_in_tkt)(aname, inst, realm, "krbtgt", realm, + lifetime, password); + if (rc4) /* XXX: do we want: && (rc != NO_TKT_FIL) as well? */ + { + functionName = "krb_get_pw_in_tkt()"; + rcL = KRBERR(rc4); + goto cleanup; + } + } + } + +#ifndef NO_AFS + if ( !rc5 || (Leash_get_default_use_krb4() && !rc4) ) { + char c; + char *r; + char *t; + for ( r=realm, t=temp; c=*r; r++,t++ ) + *t = isupper(c) ? tolower(c) : c; + *t = '\0'; + + rcA = Leash_afs_klog("afs", temp, realm, lifetime); + if (rcA) + rcA = Leash_afs_klog("afs", "", realm, lifetime); + } +#endif /* NO_AFS */ + + cleanup: + return leash_error_message("Ticket initialization failed.", + rcL, (rc5 && rc4)?KRBERR(rc4):0, rc5, rcA, 0, + displayErrors); +} + +long FAR +Leash_renew(void) +{ + if ( hKrb5 && !LeashKRB5_renew() ) { + int lifetime; + lifetime = Leash_get_default_lifetime() / 5; + if (hKrb4 && Leash_get_default_use_krb4()) + Leash_convert524(0); +#ifndef NO_AFS + { + TicketList * list = NULL, * token; + afs_get_tokens(NULL,&list,NULL); + for ( token = list ; token ; token = token->next ) + Leash_afs_klog("afs", token->realm, "", lifetime); + not_an_API_LeashFreeTicketList(&list); + } +#endif /* NO_AFS */ + return 1; + } + return 0; +} + +static BOOL +GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData) +{ + NTSTATUS Status = 0; + HANDLE TokenHandle; + TOKEN_STATISTICS Stats; + DWORD ReqLen; + BOOL Success; + + if (!ppSessionData || !pLsaGetLogonSessionData) + return FALSE; + *ppSessionData = NULL; + + Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle ); + if ( !Success ) + return FALSE; + + Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen ); + CloseHandle( TokenHandle ); + if ( !Success ) + return FALSE; + + Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData ); + if ( FAILED(Status) || !ppSessionData ) + return FALSE; + + return TRUE; +} + +// IsKerberosLogon() does not validate whether or not there are valid tickets in the +// cache. It validates whether or not it is reasonable to assume that if we +// attempted to retrieve valid tickets we could do so. Microsoft does not +// automatically renew expired tickets. Therefore, the cache could contain +// expired or invalid tickets. Microsoft also caches the user's password +// and will use it to retrieve new TGTs if the cache is empty and tickets +// are requested. + +static BOOL +IsKerberosLogon(VOID) +{ + PSECURITY_LOGON_SESSION_DATA pSessionData = NULL; + BOOL Success = FALSE; + + if ( GetSecurityLogonSessionData(&pSessionData) ) { + if ( pSessionData->AuthenticationPackage.Buffer ) { + WCHAR buffer[256]; + WCHAR *usBuffer; + int usLength; + + Success = FALSE; + usBuffer = (pSessionData->AuthenticationPackage).Buffer; + usLength = (pSessionData->AuthenticationPackage).Length; + if (usLength < 256) + { + lstrcpyn (buffer, usBuffer, usLength); + lstrcat (buffer,L""); + if ( !lstrcmp(L"Kerberos",buffer) ) + Success = TRUE; + } + } + pLsaFreeReturnBuffer(pSessionData); + } + return Success; +} + + +// This looks really ugly because it is. The result of IsKerberosLogon() +// does not prove whether or not there are Kerberos tickets available to +// be imported. Only the call to khm_krb5_ms2mit() which actually attempts +// to import tickets can do that. However, calling khm_krb5_ms2mit() can +// result in a TGS_REQ being sent to the KDC and since Leash_importable() +// is called quite often we want to avoid this if at all possible. +// Unfortunately, we have be shown at least one case in which the primary +// authentication package was not Kerberos and yet there were Kerberos +// tickets available. Therefore, if IsKerberosLogon() is not TRUE we +// must call khm_krb5_ms2mit() but we still do not want to call it in a +// tight loop so we cache the response and assume it won't change. +long FAR +Leash_importable(void) +{ + if ( IsKerberosLogon() ) + return TRUE; + else { + static int response = -1; + if (response == -1) { + response = khm_krb5_ms2mit(0); + } + return response; + } +} + +long FAR +Leash_import(void) +{ + if ( khm_krb5_ms2mit(1) ) { + int lifetime; + lifetime = Leash_get_default_lifetime() / 5; + if (hKrb4 && Leash_get_default_use_krb4()) + Leash_convert524(0); +#ifndef NO_AFS + { + char c; + char *r; + char *t; + char cell[256]; + char realm[256]; + int i = 0; + int rcA = 0; + + krb5_context ctx = 0; + krb5_error_code code = 0; + krb5_ccache cc = 0; + krb5_principal me = 0; + + if ( !pkrb5_init_context ) + goto cleanup; + + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + + code = pkrb5_cc_default(ctx, &cc); + if (code) goto cleanup; + + if (code = pkrb5_cc_get_principal(ctx, cc, &me)) + goto cleanup; + + for ( r=realm, t=cell, i=0; ilength; r++,t++,i++ ) { + c = krb5_princ_realm(ctx, me)->data[i]; + *r = c; + *t = isupper(c) ? tolower(c) : c; + } + *r = *t = '\0'; + + rcA = Leash_afs_klog("afs", cell, realm, lifetime); + if (rcA) + rcA = Leash_afs_klog("afs", "", realm, lifetime); + + cleanup: + if (me) + pkrb5_free_principal(ctx, me); + if (cc) + pkrb5_cc_close(ctx, cc); + if (ctx) + pkrb5_free_context(ctx); + } +#endif /* NO_AFS */ + return 1; + } + return 0; +} + +long +Leash_kdestroy(void) +{ + int k_errno; + + Leash_afs_unlog(); + khm_krb5_destroy_identity(NULL); + + if (pdest_tkt != NULL) + { + k_errno = (*pdest_tkt)(); + if (k_errno && (k_errno != RET_TKFIL)) + return KRBERR(k_errno); + } + + return 0; +} + +int com_addr(void) +{ + long ipAddr; + char loc_addr[ADDR_SZ]; + CREDENTIALS cred; + char service[40]; + char instance[40]; +// char addr[40]; + char realm[40]; + struct in_addr LocAddr; + int k_errno; + + if (pkrb_get_cred == NULL) + return(KSUCCESS); + + k_errno = (*pkrb_get_cred)(service,instance,realm,&cred); + if (k_errno) + return KRBERR(k_errno); + + + while(1) { + ipAddr = (*pLocalHostAddr)(); + LocAddr.s_addr = ipAddr; + strcpy(loc_addr,inet_ntoa(LocAddr)); + if ( strcmp(cred.address,loc_addr) != 0) { + Leash_kdestroy (); + break; + } + break; + } // while() + return 0; +} + +long FAR +not_an_API_LeashFreeTicketList(TicketList** ticketList) +{ + TicketList* tempList = *ticketList, *killList; + + //if (tempList == NULL) + //return -1; + + while (tempList) + { + killList = tempList; + + tempList = (TicketList*)tempList->next; + free(killList->theTicket); + if (killList->tktEncType) + free(killList->tktEncType); + if (killList->keyEncType) + free(killList->keyEncType); + if (killList->addrCount) { + int n; + for ( n=0; naddrCount; n++) { + if (killList->addrList[n]) + free(killList->addrList[n]); + } + } + if (killList->addrList) + free(killList->addrList); + if (killList->name) + free(killList->name); + if (killList->inst) + free(killList->inst); + if (killList->realm) + free(killList->realm); + free(killList); + } + + *ticketList = NULL; + return 0; +} + + +long FAR Leash_klist(HWND hlist, TICKETINFO FAR *ticketinfo) +{ + // Don't think this function will be used anymore - ADL 5-15-99 + // Old fucntion to put tickets in a listbox control + // Use function "not_an_API_LeashKRB4GetTickets()" instead! + char pname[ANAME_SZ]; + char pinst[INST_SZ]; + char prealm[REALM_SZ]; + char buf[MAX_K_NAME_SZ+40]; + LPSTR cp; + long expdate; + int k_errno; + CREDENTIALS c; + int newtickets = 0; + int open = 0; + + /* + * Since krb_get_tf_realm will return a ticket_file error, + * we will call tf_init and tf_close first to filter out + * things like no ticket file. Otherwise, the error that + * the user would see would be + * klist: can't find realm of ticket file: No ticket file (tf_util) + * instead of + * klist: No ticket file (tf_util) + */ + if (ptf_init == NULL) + return(KSUCCESS); + + if (hlist) + { + SendMessage(hlist, WM_SETREDRAW, FALSE, 0L); + SendMessage(hlist, LB_RESETCONTENT, 0, 0L); + } + com_addr(); + newtickets = NO_TICKETS; + + err_context = (LPSTR)"tktf1"; + + /* Open ticket file */ + if (k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL)) + { + goto cleanup; + } + /* Close ticket file */ + (void) (*ptf_close)(); + /* + * We must find the realm of the ticket file here before calling + * tf_init because since the realm of the ticket file is not + * really stored in the principal section of the file, the + * routine we use must itself call tf_init and tf_close. + */ + err_context = "tf realm"; + if ((k_errno = (*pkrb_get_tf_realm)((*ptkt_string)(), prealm)) != KSUCCESS) + { + goto cleanup; + } + /* Open ticket file */ + err_context = "tf init"; + if (k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL)) + { + goto cleanup; + } + + open = 1; + err_context = "tf pname"; + /* Get principal name and instance */ + if ((k_errno = (*ptf_get_pname)(pname)) || (k_errno = (*ptf_get_pinst)(pinst))) + { + goto cleanup; + } + + /* + * You may think that this is the obvious place to get the + * realm of the ticket file, but it can't be done here as the + * routine to do this must open the ticket file. This is why + * it was done before tf_init. + */ + + wsprintf((LPSTR)ticketinfo->principal,"%s%s%s%s%s", (LPSTR)pname, + (LPSTR)(pinst[0] ? "." : ""), (LPSTR)pinst, + (LPSTR)(prealm[0] ? "@" : ""), (LPSTR)prealm); + newtickets = GOOD_TICKETS; + + err_context = "tf cred"; + while ((k_errno = (*ptf_get_cred)(&c)) == KSUCCESS) + { + expdate = c.issue_date + c.lifetime * 5L * 60L; + + if (!lstrcmp((LPSTR)c.service, (LPSTR)TICKET_GRANTING_TICKET) && !lstrcmp((LPSTR)c.instance, (LPSTR)prealm)) + { + ticketinfo->issue_date = c.issue_date; + ticketinfo->lifetime = c.lifetime * 5L * 60L; + ticketinfo->renew_till = 0; + } + + cp = (LPSTR)buf; + lstrcpy(cp, (LPSTR)short_date(&c.issue_date)); + cp += lstrlen(cp); + wsprintf(cp,"\t%s\t%s%s%s%s%s", + (LPSTR)short_date(&expdate), (LPSTR)c.service, + (LPSTR)(c.instance[0] ? "." : ""), + (LPSTR)c.instance, (LPSTR)(c.realm[0] ? "@" : ""), + (LPSTR) c.realm); + if (hlist) + SendMessage(hlist, LB_ADDSTRING, 0, (LONG)(LPSTR)buf); + } /* WHILE */ + +cleanup: + + if (open) + (*ptf_close)(); /* close ticket file */ + + if (hlist) + { + SendMessage(hlist, WM_SETREDRAW, TRUE, 0L); + InvalidateRect(hlist, NULL, TRUE); + UpdateWindow(hlist); + } + if (k_errno == EOF) + k_errno = 0; + + /* XXX the if statement directly below was inserted to eliminate + an error 20 on Leash startup. The error occurs from an error + number thrown from krb_get_tf_realm. We believe this change + does not eliminate other errors, but it may. */ + + if (k_errno == RET_NOTKT) + k_errno = 0; + + ticketinfo->btickets = newtickets; + if (k_errno != 0) + return KRBERR(k_errno); + return 0; +} + + + +static BOOL CALLBACK +EnumChildProc(HWND hwnd, LPARAM lParam) +{ + HWND * h = (HWND *)lParam; + *h = hwnd; + return FALSE; +} + + +static HWND +FindFirstChildWindow(HWND parent) +{ + HWND hFirstChild = 0; + EnumChildWindows(parent, EnumChildProc, (LPARAM) &hFirstChild); + return hFirstChild; +} + +void FAR +not_an_API_Leash_AcquireInitialTicketsIfNeeded(krb5_context context, krb5_principal desiredKrb5Principal) +{ + krb5_error_code err; + LSH_DLGINFO_EX dlginfo; + HGLOBAL hData; + HWND hLeash; + HWND hForeground; + char *desiredName = 0; + char *desiredRealm = 0; + char *p; + TicketList * list = NULL; + TICKETINFO ticketinfo; + krb5_context ctx; + char newenv[256]; + char * env = 0; + DWORD dwMsLsaImport = Leash_get_default_mslsa_import(); + + char loginenv[16]; + BOOL prompt; + + GetEnvironmentVariable("KERBEROSLOGIN_NEVER_PROMPT", loginenv, sizeof(loginenv)); + prompt = (GetLastError() == ERROR_ENVVAR_NOT_FOUND); + + if ( !prompt || !pkrb5_init_context ) + return; + + ctx = context; + env = getenv("KRB5CCNAME"); + if ( !env && context ) { + sprintf(newenv,"KRB5CCNAME=%s",pkrb5_cc_default_name(ctx)); + env = (char *)putenv(newenv); + } + + not_an_API_LeashKRB5GetTickets(&ticketinfo,&list,&ctx); + not_an_API_LeashFreeTicketList(&list); + + if ( ticketinfo.btickets != GOOD_TICKETS && + Leash_get_default_mslsa_import() && Leash_importable() ) { + // We have the option of importing tickets from the MSLSA + // but should we? Do the tickets in the MSLSA cache belong + // to the default realm used by Leash? If so, import. + int import = 0; + + if ( dwMsLsaImport == 1 ) { /* always import */ + import = 1; + } else if ( dwMsLsaImport == 2 ) { /* import when realms match */ + krb5_error_code code; + krb5_ccache mslsa_ccache=0; + krb5_principal princ = 0; + char ms_realm[128] = "", *def_realm = 0, *r; + int i; + + if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache)) + goto cleanup; + + if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ)) + goto cleanup; + + for ( r=ms_realm, i=0; ilength; r++, i++ ) { + *r = krb5_princ_realm(ctx, princ)->data[i]; + } + *r = '\0'; + + if (code = pkrb5_get_default_realm(ctx, &def_realm)) + goto cleanup; + + import = !strcmp(def_realm, ms_realm); + + cleanup: + if (def_realm) + pkrb5_free_default_realm(ctx, def_realm); + + if (princ) + pkrb5_free_principal(ctx, princ); + + if (mslsa_ccache) + pkrb5_cc_close(ctx, mslsa_ccache); + } + + if ( import ) { + Leash_import(); + + not_an_API_LeashKRB5GetTickets(&ticketinfo,&list,&ctx); + not_an_API_LeashFreeTicketList(&list); + } + } + + if ( ticketinfo.btickets != GOOD_TICKETS ) + { + /* do we want a specific client principal? */ + if (desiredKrb5Principal != NULL) { + err = pkrb5_unparse_name (ctx, desiredKrb5Principal, &desiredName); + if (!err) { + dlginfo.username = desiredName; + for (p = desiredName; *p && *p != '@'; p++); + if ( *p == '@' ) { + *p = '\0'; + desiredRealm = dlginfo.realm = ++p; + } + } + } + +#ifdef COMMENT + memset(&dlginfo, 0, sizeof(LSH_DLGINFO_EX)); + dlginfo.size = sizeof(LSH_DLGINFO_EX); + dlginfo.dlgtype = DLGTYPE_PASSWD; + dlginfo.title = "Obtain Kerberos Ticket Getting Tickets"; + dlginfo.use_defaults = 1; + + err = Leash_kinit_dlg_ex(NULL, &dlginfo); +#else + /* construct a marshalling of data + * <principal><realm> + * then send to Leash + */ + + hData = GlobalAlloc( GHND, 4096 ); + hForeground = GetForegroundWindow(); + hLeash = FindWindow("LEASH.0WNDCLASS", NULL); + SetForegroundWindow(hLeash); + hLeash = FindFirstChildWindow(hLeash); + if ( hData && hLeash ) { + char * strs = GlobalLock( hData ); + if ( strs ) { + strcpy(strs, "Obtain Kerberos Ticket Getting Tickets"); + strs += strlen(strs) + 1; + if ( desiredName ) { + strcpy(strs, desiredName); + strs += strlen(strs) + 1; + if (desiredRealm) { + strcpy(strs, desiredRealm); + strs += strlen(strs) + 1; + } + } else { + *strs = 0; + strs++; + *strs = 0; + strs++; + } + + GlobalUnlock( hData ); + SendMessage(hLeash, 32809, 0, (LPARAM) hData); + } + + GlobalFree( hData ); + } + SetForegroundWindow(hForeground); +#endif + if (desiredName != NULL) + pkrb5_free_unparsed_name(ctx, desiredName); + } + + if ( !env && context ) + putenv("KRB5CCNAME="); + + if ( !context ) + pkrb5_free_context(ctx); +} diff --git a/src/windows/identity/plugins/krb5/krbconfig.csv b/src/windows/identity/plugins/krb5/krbconfig.csv new file mode 100644 index 0000000000..c577eec3b9 --- /dev/null +++ b/src/windows/identity/plugins/krb5/krbconfig.csv @@ -0,0 +1,34 @@ +Name,Type,Value,Description +Krb5Cred,KC_SPACE,0,Kerberos V Credentials Provider + Module,KC_STRING,MITKrb5, + Description,KC_STRING,Kerberos V Credentials Provider, + Type,KC_INT32,1, + Flags,KC_INT32,0, + Parameters,KC_SPACE,0,Parameters for KrbCred + CreateMissingConfig,KC_INT32,0,Create missing configuration files + MsLsaImport,KC_INT32,2,Automatically import MSLSA credentials + AutoRenewTickets,KC_INT32,1,Automatically renew expiring tickets + DefaultLifetime,KC_INT32,36000,Default ticket lifetime + MaxLifetime,KC_INT32,86400,Maximum lifetime + MinLifetime,KC_INT32,60,Minimum lifetime + Forwardable,KC_INT32,1,Obtain forwardable tickets (boolean) + Proxiable,KC_INT32,0,Obtain proxiable tickets (boolean) + Addressless,KC_INT32,1,Obtain addressless tickets (boolean) + Renewable,KC_INT32,1,Obtain renewable tickets (boolean) + DefaultRenewLifetime,KC_INT32,604800,Default renewable lifetime + MaxRenewLifetime,KC_INT32,2592000,Maximum renewable lifetime + MinRenewLifetime,KC_INT32,60,Maximum renewable lifetime + LRURealms,KC_STRING,, + LRUPrincipals,KC_STRING,, + PromptCache,KC_SPACE,0,Cache of prompts (only per identity) + Name,KC_STRING,, + Banner,KC_STRING,, + PromptCount,KC_INT32,0, + (n),KC_SPACE,0,Parameters for each prompt + Prompt,KC_STRING,, + Type,KC_INT32,0, + Flags,KC_INT32,0, + (n),KC_ENDSPACE,0, + PromptCache,KC_ENDSPACE,0, + Parameters,KC_ENDSPACE,0, +Krb5Cred,KC_ENDSPACE,0, diff --git a/src/windows/identity/plugins/krb5/krbcred.h b/src/windows/identity/plugins/krb5/krbcred.h new file mode 100644 index 0000000000..08978f11fd --- /dev/null +++ b/src/windows/identity/plugins/krb5/krbcred.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KRBAFSCRED_H +#define __KHIMAIRA_KRBAFSCRED_H + +#include<windows.h> + +/* While we generally pull resources out of hResModule, the message + strings for all the languages are kept in the main DLL. */ +#define KHERR_HMODULE hInstance +#define KHERR_FACILITY k5_facility +#define KHERR_FACILITY_ID 64 + +#include<khdefs.h> +#include<kcreddb.h> +#include<kmm.h> +#include<kconfig.h> +#include<khuidefs.h> +#include<kherr.h> + +#include<krb5funcs.h> +#include<krb5common.h> +#include<errorfuncs.h> +#include<dynimport.h> + +#include<langres.h> +#include<datarep.h> +#include<krb5_msgs.h> + +#define TYPENAME_ENCTYPE L"EncType" +#define TYPENAME_ADDR_LIST L"AddrList" +#define TYPENAME_KRB5_FLAGS L"Krb5Flags" + +#define ATTRNAME_KEY_ENCTYPE L"KeyEncType" +#define ATTRNAME_TKT_ENCTYPE L"TktEncType" +#define ATTRNAME_ADDR_LIST L"AddrList" +#define ATTRNAME_KRB5_FLAGS L"Krb5Flags" +#define ATTRNAME_KRB5_CCNAME L"Krb5CCName" + +void init_krb(); +void exit_krb(); +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module); +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module); + +/* globals */ +extern kmm_module h_khModule; +extern HMODULE hResModule; +extern HINSTANCE hInstance; +extern const wchar_t * k5_facility; + +extern khm_int32 type_id_enctype; +extern khm_int32 type_id_addr_list; +extern khm_int32 type_id_krb5_flags; + +extern khm_int32 attr_id_key_enctype; +extern khm_int32 attr_id_tkt_enctype; +extern khm_int32 attr_id_addr_list; +extern khm_int32 attr_id_krb5_flags; +extern khm_int32 attr_id_krb5_ccname; + +/* Configuration spaces */ +#define CSNAME_KRB5CRED L"Krb5Cred" +#define CSNAME_PARAMS L"Parameters" +#define CSNAME_PROMPTCACHE L"PromptCache" + +/* plugin constants */ +#define KRB5_PLUGIN_NAME L"Krb5Cred" + +#define KRB5_CREDTYPE_NAME L"Krb5Cred" + +extern khm_handle csp_plugins; +extern khm_handle csp_krbcred; +extern khm_handle csp_params; + +extern kconf_schema schema_krbconfig[]; + +/* other globals */ +extern khm_int32 credtype_id_krb5; + +extern khm_boolean krb5_initialized; + +extern khm_handle krb5_credset; + +extern khm_handle k5_sub; + +extern krb5_context k5_identpro_ctx; + +extern BOOL is_k5_identpro; + +/* plugin callbacks */ +khm_int32 KHMAPI k5_msg_callback(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam); + +/* kinit fiber */ +typedef struct _fiber_job_t { + int command; + + khui_new_creds * nc; + khui_new_creds_by_type * nct; + HWND dialog; + + khm_handle identity; + char * principal; + char * password; + char * ccache; + krb5_deltat lifetime; + DWORD forwardable; + DWORD proxiable; + DWORD renewable; + krb5_deltat renew_life; + DWORD addressless; + DWORD publicIP; + + int code; + int state; + int prompt_set; + + BOOL null_password; +} fiber_job; + +extern fiber_job g_fjob; /* global fiber job object */ + +#define FIBER_CMD_KINIT 1 +#define FIBER_CMD_CANCEL 2 +#define FIBER_CMD_CONTINUE 3 + +#define FIBER_STATE_NONE 0 +#define FIBER_STATE_KINIT 1 + +void +k5_pp_begin(khui_property_sheet * s); + +void +k5_pp_end(khui_property_sheet * s); + +khm_int32 KHMAPI +k5_msg_cred_dialog(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam); + +khm_int32 KHMAPI +k5_msg_ident(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam); + +int +k5_get_realm_from_nc(khui_new_creds * nc, + wchar_t * buf, + khm_size cch_buf); + +void +k5_register_config_panels(void); + +void +k5_unregister_config_panels(void); + +#endif diff --git a/src/windows/identity/plugins/krb5/lang/en_us/langres.rc b/src/windows/identity/plugins/krb5/lang/en_us/langres.rc new file mode 100644 index 0000000000..087b93e47c --- /dev/null +++ b/src/windows/identity/plugins/krb5/lang/en_us/langres.rc @@ -0,0 +1,406 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\..\langres.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\..\\langres.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_NC_KRB5 DIALOGEX 0, 0, 300, 166 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | + WS_CLIPCHILDREN +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Realm",IDC_STATIC,7,25,52,13 + COMBOBOX IDC_NCK5_REALM,60,25,233,17,CBS_DROPDOWN | + CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Specify &additional realms ...",IDC_NCK5_ADD_REALMS,181, + 43,112,16,BS_NOTIFY | WS_DISABLED + LTEXT "&Lifetime",IDC_STATIC,7,67,61,12 + EDITTEXT IDC_NCK5_LIFETIME_EDIT,85,67,107,12,ES_AUTOHSCROLL + CONTROL "&Renewable for",IDC_NCK5_RENEWABLE,"Button", + BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,7,87,64,12 + EDITTEXT IDC_NCK5_RENEW_EDIT,85,87,108,12,ES_AUTOHSCROLL + CONTROL "Can be &forwarded to other machines", + IDC_NCK5_FORWARDABLE,"Button",BS_AUTOCHECKBOX | + BS_NOTIFY | WS_TABSTOP,7,107,132,12 + CONTROL "Kerberos 5 Ticket Options",IDC_STATIC,"Static", + SS_LEFTNOWORDWRAP | SS_SUNKEN | WS_GROUP,7,7,286,11 +END + +IDD_PP_KRB5C DIALOGEX 0, 0, 235, 156 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Kerberos 5" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "Name",IDC_STATIC,7,7,19,8 + LTEXT "Valid till",IDC_STATIC,7,39,24,8 + LTEXT "Renewable till",IDC_STATIC,7,55,45,12 + CONTROL "Renewable",IDC_PPK5_CRENEW,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,31,125,51,10 + CONTROL "Forwardable",IDC_PPK5_CFORWARD,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,91,125,56,10 + CONTROL "Proxiable",IDC_PPK5_CPROXY,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,156,125,45,10 + LTEXT "Issued on",IDC_STATIC,7,23,32,8 + GROUPBOX "Ticket flags",IDC_STATIC,7,108,221,41 + LTEXT "Static",IDC_PPK5_NAME,72,7,156,12,NOT WS_GROUP, + WS_EX_CLIENTEDGE + LTEXT "Static",IDC_PPK5_ISSUE,72,23,156,12,NOT WS_GROUP, + WS_EX_CLIENTEDGE + LTEXT "Static",IDC_PPK5_VALID,72,39,156,12,NOT WS_GROUP, + WS_EX_CLIENTEDGE + LTEXT "Static",IDC_PPK5_RENEW,72,55,156,12,NOT WS_GROUP, + WS_EX_CLIENTEDGE +END + +IDD_PP_KRB5 DIALOGEX 0, 0, 235, 156 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Kerberos 5" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "Default realm",IDC_STATIC,7,7,44,8 + LTEXT "Default lifetime",IDC_STATIC,7,22,49,8 + LTEXT "Minimum lifetime",IDC_STATIC,7,37,52,8 + LTEXT "Maximum lifetime",IDC_STATIC,7,52,55,8 + LTEXT "Renewable lifetime",IDC_STATIC,7,67,61,8 + LTEXT "Min. Renewable lifetime",IDC_STATIC,7,82,76,8 + LTEXT "Max. Renewable lifetime",IDC_STATIC,7,97,79,8 + GROUPBOX "Default ticket flags",IDC_STATIC,7,113,221,36 + CONTROL "Proxiable",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,129,45,10 + CONTROL "Renewable",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,23,129,51,10 + CONTROL "Forwardable",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,89,129,56,10 + LTEXT "ATHENA.MIT.EDU",IDC_STATIC,95,7,133,11,0, + WS_EX_CLIENTEDGE + LTEXT "10 hours",IDC_STATIC,95,22,133,11,0,WS_EX_CLIENTEDGE + LTEXT "1 minute",IDC_STATIC,95,37,133,11,0,WS_EX_CLIENTEDGE + LTEXT "7 days",IDC_STATIC,95,52,133,11,0,WS_EX_CLIENTEDGE + LTEXT "7 days",IDC_STATIC,95,67,133,11,0,WS_EX_CLIENTEDGE + LTEXT "1 minute",IDC_STATIC,95,82,133,11,0,WS_EX_CLIENTEDGE + LTEXT "21 days",IDC_STATIC,95,97,133,11,0,WS_EX_CLIENTEDGE +END + +IDD_CONFIG DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Default Realm",IDC_CFG_LBL_REALM,13,9,46,8 + COMBOBOX IDC_CFG_DEFREALM,76,7,166,30,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure Realms ...",IDC_CFG_CFGREALMS,76,25,84,14 + GROUPBOX "Keberos Configuration File",IDC_CFG_CFGFILEGRP,7,57,241, + 48 + LTEXT "Location",IDC_CFG_LBL_CFGFILE,13,71,28,8 + EDITTEXT IDC_CFG_CFGFILE,76,68,119,14,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_CFG_BROWSE,198,68,44,14 + CONTROL "Create file if missing",IDC_CFG_CREATECONFIG,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,76,89,80,10 + GROUPBOX "Windows® Options",IDC_CFG_WINGRP,7,110,241,65 + LTEXT "Hostname",IDC_CFG_LBL_HOSTNAME,13,123,33,8 + EDITTEXT IDC_CFG_HOSTNAME,76,120,166,14,ES_AUTOHSCROLL | + ES_READONLY + LTEXT "Domain",IDC_CFG_LBL_DOMAIN,13,141,24,8 + EDITTEXT IDC_CFG_DOMAIN,76,138,166,14,ES_AUTOHSCROLL | + ES_READONLY + LTEXT "Import tickets",IDC_LBL_IMPORT,13,158,45,8 + COMBOBOX IDC_CFG_IMPORT,76,156,166,30,CBS_DROPDOWNLIST | CBS_SORT | + WS_VSCROLL | WS_TABSTOP +END + +IDD_CFG_REALMS DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_CFG_REALMS,"SysListView32",LVS_ALIGNLEFT | + WS_BORDER | WS_TABSTOP,7,19,81,148 + GROUPBOX "Servers",IDC_CFG_SERVERSGRP,93,7,155,91 + GROUPBOX "Domain/Hostname mappings",IDC_CFG_DOMAINGRP,93,101,155, + 74 + CONTROL "",IDC_LIST3,"SysListView32",LVS_ALIGNLEFT | WS_BORDER | + WS_TABSTOP,99,19,143,72 + CONTROL "",IDC_LIST4,"SysListView32",LVS_ALIGNLEFT | WS_BORDER | + WS_TABSTOP,99,111,143,56 +END + +IDD_CFG_IDS_TAB DIALOGEX 0, 0, 235, 151 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Ticket lifetime",IDC_CFG_LBL_DEFLIFE,7,10,44,8 + EDITTEXT IDC_CFG_DEFLIFE,91,7,137,14,ES_AUTOHSCROLL + LTEXT "Ticket renewable lifetime",IDC_CFG_LBL_DEFRLIFE,7,29,80, + 8 + EDITTEXT IDC_CFG_DEFRLIFE,91,26,137,14,ES_AUTOHSCROLL + GROUPBOX "Ticket lifetime range",IDC_CFG_LIFEGRP,7,43,221,49 + LTEXT "Minimum",IDC_STATIC,13,56,28,8 + EDITTEXT IDC_CFG_LRNG_MIN,91,53,131,14,ES_AUTOHSCROLL + LTEXT "Maximum",IDC_STATIC,13,75,30,8 + EDITTEXT IDC_CFG_LRNG_MAX,91,72,131,14,ES_AUTOHSCROLL + GROUPBOX "Ticket renewable lifetime range",IDC_STATIC,7,95,221,49 + LTEXT "Minimum",IDC_STATIC,13,108,28,8 + EDITTEXT IDC_CFG_RLRNG_MIN,91,105,131,14,ES_AUTOHSCROLL + LTEXT "Maximum",IDC_STATIC,13,128,30,8 + EDITTEXT IDC_CFG_RLRNG_MAX,91,125,131,14,ES_AUTOHSCROLL +END + +IDD_CFG_ID_TAB DIALOGEX 0, 0, 235, 151 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Ticket lifetime",IDC_CFG_LBL_DEFLIFE,7,10,44,8 + EDITTEXT IDC_CFG_DEFLIFE,91,7,137,14,ES_AUTOHSCROLL + LTEXT "Ticket renewable lifetime",IDC_CFG_LBL_DEFRLIFE,7,29,80, + 8 + EDITTEXT IDC_CFG_DEFRLIFE,91,26,137,14,ES_AUTOHSCROLL + LTEXT "Credentials cache",IDC_STATIC,7,63,58,8 + EDITTEXT IDC_CFG_CCACHE,91,60,137,14,ES_AUTOHSCROLL +END + +IDD_NC_KRB5_PASSWORD DIALOGEX 0, 0, 300, 166 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Kerberos 5 Change Password Options",IDC_STATIC,"Static", + SS_LEFTNOWORDWRAP | SS_SUNKEN | WS_GROUP,7,7,286,11 + LTEXT "Realm",IDC_STATIC,7,25,52,13 + COMBOBOX IDC_NCK5_REALM,60,25,233,17,CBS_DROPDOWN | + CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Specify &additional realms ...",IDC_NCK5_ADD_REALMS,181, + 43,112,16,BS_NOTIFY | WS_DISABLED +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_NC_KRB5, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 159 + END + + IDD_PP_KRB5C, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 149 + END + + IDD_PP_KRB5, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 149 + END + + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 13 + VERTGUIDE, 76 + VERTGUIDE, 242 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END + + IDD_CFG_REALMS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 93 + VERTGUIDE, 99 + VERTGUIDE, 242 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + HORZGUIDE, 19 + HORZGUIDE, 167 + END + + IDD_CFG_IDS_TAB, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + VERTGUIDE, 13 + VERTGUIDE, 91 + VERTGUIDE, 222 + TOPMARGIN, 7 + BOTTOMMARGIN, 144 + END + + IDD_CFG_ID_TAB, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + VERTGUIDE, 91 + TOPMARGIN, 7 + BOTTOMMARGIN, 144 + END + + IDD_NC_KRB5_PASSWORD, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 159 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_UNK_ADDR_FMT "Unknown address type %d" + IDS_KRB5_CREDTEXT_0 "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: Creds for realm %s</p>" + IDS_KRB5_CCNAME_SHORT_DESC "Krb5 CCache" + IDS_KEY_ENCTYPE_SHORT_DESC "Key EncType" + IDS_TKT_ENCTYPE_SHORT_DESC "Ticket EncType" + IDS_KEY_ENCTYPE_LONG_DESC "Session Key Encryption Type" + IDS_TKT_ENCTYPE_LONG_DESC "Ticket Encryption Type" + IDS_ADDR_LIST_SHORT_DESC "Addresses" + IDS_ADDR_LIST_LONG_DESC "Address List" + IDS_ETYPE_NULL "NULL" + IDS_ETYPE_DES_CBC_CRC "DES-CBC-CRC" +END + +STRINGTABLE +BEGIN + IDS_ETYPE_DES_CBC_MD4 "DES-CBC-MD4" + IDS_ETYPE_DES_CBC_MD5 "DES-CBC-MD5" + IDS_ETYPE_DES_CBC_RAW "DES-CBC-RAW" + IDS_ETYPE_DES3_CBC_SHA "DES3-CBC-SHA" + IDS_ETYPE_DES3_CBC_RAW "DES3-CBC-RAW" + IDS_ETYPE_DES_HMAC_SHA1 "DES-HMAC-SHA1" + IDS_ETYPE_DES3_CBC_SHA1 "DES3-CBC-SHA1" + IDS_ETYPE_AES128_CTS_HMAC_SHA1_96 "AES128_CTS-HMAC-SHA1_96" + IDS_ETYPE_AES256_CTS_HMAC_SHA1_96 "AES256_CTS-HMAC-SHA1_96" + IDS_ETYPE_ARCFOUR_HMAC "RC4-HMAC-NT" + IDS_ETYPE_ARCFOUR_HMAC_EXP "RC4-HMAC-NT-EXP" + IDS_ETYPE_UNKNOWN "(Unknown)" + IDS_ETYPE_LOCAL_DES3_HMAC_SHA1 "LOCAL-DES3-HMAC-SHA1" + IDS_ETYPE_LOCAL_RC4_MD4 "LOCAL-RC4-MD4" + IDS_KRB5_SHORT_DESC "Kerberos 5" + IDS_KRB5_LONG_DESC "Kerberos 5 tickets" +END + +STRINGTABLE +BEGIN + IDS_KRB4_SHORT_DESC "Kerberos 4" + IDS_KRB4_LONG_DESC "Kerberos 4 tickets" + IDS_KRB5_FLAGS_SHORT_DESC "Flags" + IDS_RENEW_TILL_SHORT_DESC "Renew Till" + IDS_RENEW_TILL_LONG_DESC "Renewable Till" + IDS_RENEW_FOR_SHORT_DESC "Renew for" + IDS_RENEW_FOR_LONG_DESC "Renewable for" + IDS_KRB5_CCNAME_LONG_DESC "Krb5 Primary Credentials Cache" + IDS_NC_USERNAME "Username" + IDS_NC_REALM "Realm" + IDS_KRB5_WARNING "Kerberos 5 Warning" + IDS_K5ERR_NAME_EXPIRED "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: The selected principal name has expired.</p><p><tab> Please contact your system administrator.</p>" + IDS_K5ERR_KEY_EXPIRED "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: The password for the selected identity has expired.</p><p><tab> Click <a id=""Krb5Cred:Passwd"">here</a> to change the password</p>" + IDS_KRB5_WARN_FMT "Kerberos 5: %s\n\n%s" + IDS_K5ERR_FMT "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tag>: %s</p>" + IDS_K5CFG_SHORT_DESC "Kerberos 5" +END + +STRINGTABLE +BEGIN + IDS_K5CFG_LONG_DESC "Kerberos 5 Configuration" + IDS_K5RLM_SHORT_DESC "Realms" + IDS_K5RLM_LONG_DESC "Kerberos Realm Configuration" + IDS_K5CFG_IDS_SHORT_DESC "Kerberos 5" + IDS_K5CFG_IDS_LONG_DESC "Kerberos 5 options for all identities" + IDS_K5CFG_ID_SHORT_DESC "Kerberos 5" + IDS_K5CFG_ID_LONG_DESC "Kerberos 5 options for this identity" + IDS_PLUGIN_DESC "Kerberos 5 Credentials Provider" + IDS_NC_PWD_BANNER "Changing Kerberos 5 Password" + IDS_NC_PWD_PWD "Current Password" + IDS_NC_PWD_NPWD "New Password" + IDS_NC_PWD_NPWD_AGAIN "New Password again" + IDS_KRB5_CREDTEXT_P0 "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: Changing password for %s</p>" + IDS_K5CFG_IMPORT_OPTIONS + "Never\000Always\000Only when the principal name matches\000 \000" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/windows/identity/plugins/krb5/lang/krb5_msgs.mc b/src/windows/identity/plugins/krb5/lang/krb5_msgs.mc new file mode 100644 index 0000000000..22f973f939 --- /dev/null +++ b/src/windows/identity/plugins/krb5/lang/krb5_msgs.mc @@ -0,0 +1,151 @@ +; // ** krb5_msgs.mc + +; /* Since .mc files can contain strings from any language, we define +; all our messages in one file in the /lang/ directory instead of +; language specific subdirectories. */ + +; /* The type is set to (wchar_t *) because that's what we will be +; feeding kherr_report() function. */ + +; // MessageIdTypedef=LPWSTR + +; /* Severity values as defined in the message definition file are +; currently ignored. */ + +SeverityNames=( + Success=0x0 +) + +LanguageNames=( + English=0x409:MSG_ENU +) + +OutputBase=16 + +; /* Actual messages start here */ + +MessageId=1 +Severity=Success +SymbolicName=MSG_INITIAL +Language=English +Initial placeholder message +. + +MessageId= +SymbolicName=MSG_CTX_INITAL_CREDS +Language=English +Obtaining initial Krb5 credentials +. + +MessageId= +SymbolicName=MSG_CTX_RENEW_CREDS +Language=English +Renewing Krb5 credentials +. + +MessageId= +SymbolicName=MSG_ERR_UNKNOWN +Language=English +An unknown error has occurred. +. + +MessageId= +SymbolicName=MSG_ERR_PR_UNKNOWN +Language=English +You have entered an unknown username/instance/realm combination. +. + +MessageId= +SymbolicName=MSG_ERR_TKFIL +Language=English +The tickets could not be accessed from the memory location where they were stored. +. + +MessageId= +SymbolicName=MSG_ERR_S_TKFIL +Language=English +This may be due to a problem with the memory where your tickets are stored. Restarting your computer might be worth a try. +. + +MessageId= +SymbolicName=MSG_ERR_CLOCKSKEW +Language=English +Your computer's clock is out of sync with the Kerberos server. +. + +MessageId= +SymbolicName=MSG_ERR_S_CLOCKSKEW +Language=English +Synchronize your clock withe the Kerberos server. +. + +MessageId= +SymbolicName=MSG_ERR_KDC_CONTACT +Language=English +Cannot contact the Kerberos server for the requested realm. +. + +MessageId= +SymbolicName=MSG_ERR_INSECURE_PW +Language=English +You have entered an insecure or weak password. +. + +MessageId= +SymbolicName=MSG_ERR_NO_IDENTITY +Language=English +There were no identities for which to renew credentials. +. + +MessageId= +SymbolicName=MSG_CTX_PASSWD +Language=English +Changing Kerberos 5 Password +. + +MessageId= +SymbolicName=MSG_PWD_UNKNOWN +Language=English +Unknown error +. + +MessageId= +SymbolicName=MSG_PWD_NOT_SAME +Language=English +The new passwords are not the same. +. + +MessageId= +SymbolicName=MSG_PWD_S_NOT_SAME +Language=English +The new password is asked for twice to protect against a mistake when setting the new password. Both instances of the new password must be the same. Please correct this and try again. +. + +MessageId= +SymbolicName=MSG_PWD_SAME +Language=English +The new and the old passwords are the same. +. + +MessageId= +SymbolicName=MSG_PWD_S_SAME +Language=English +Please type a new password to continue. +. + +MessageId= +SymbolicName=MSG_PWD_NO_IDENTITY +Language=English +There are no identities selected. +. + +MessageId= +SymbolicName=MSG_PWD_S_NO_IDENTITY +Language=English +Please select an identity to change the password. +. + +MessageId= +SymbolicName=MSG_ +Language=English +. diff --git a/src/windows/identity/plugins/krb5/langres.h b/src/windows/identity/plugins/krb5/langres.h new file mode 100644 index 0000000000..87f74f547a --- /dev/null +++ b/src/windows/identity/plugins/krb5/langres.h @@ -0,0 +1,127 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by D:\work\khimaira\src\plugins\krb5\lang\en_us\langres.rc +// +#define IDS_UNK_ADDR_FMT 101 +#define IDD_NC_KRB5 102 +#define IDS_KRB5_CREDTEXT_0 102 +#define IDS_KRB5_CCNAME_SHORT_DESC 103 +#define IDS_KEY_ENCTYPE_SHORT_DESC 104 +#define IDD_CONFIG 104 +#define IDS_TKT_ENCTYPE_SHORT_DESC 105 +#define IDD_CFG_REALMS 105 +#define IDS_KEY_ENCTYPE_LONG_DESC 106 +#define IDD_CFG_IDS_TAB 106 +#define IDS_TKT_ENCTYPE_LONG_DESC 107 +#define IDD_PP_KRB5C 107 +#define IDS_ADDR_LIST_SHORT_DESC 108 +#define IDD_PP_KRB5 108 +#define IDS_ADDR_LIST_LONG_DESC 109 +#define IDD_CFG_ID_TAB 109 +#define IDS_ETYPE_NULL 110 +#define IDD_NC_KRB5_PASSWORD 110 +#define IDS_ETYPE_DES_CBC_CRC 111 +#define IDS_ETYPE_DES_CBC_MD4 112 +#define IDS_ETYPE_DES_CBC_MD5 113 +#define IDS_ETYPE_DES_CBC_RAW 114 +#define IDS_ETYPE_DES3_CBC_SHA 115 +#define IDS_ETYPE_DES3_CBC_RAW 116 +#define IDS_ETYPE_DES_HMAC_SHA1 117 +#define IDS_ETYPE_DES3_CBC_SHA1 118 +#define IDS_ETYPE_AES128_CTS_HMAC_SHA1_96 119 +#define IDS_ETYPE_AES256_CTS_HMAC_SHA1_96 120 +#define IDS_ETYPE_ARCFOUR_HMAC 121 +#define IDS_ETYPE_ARCFOUR_HMAC_EXP 122 +#define IDS_ETYPE_UNKNOWN 123 +#define IDS_ETYPE_LOCAL_DES3_HMAC_SHA1 124 +#define IDS_ETYPE_LOCAL_RC4_MD4 125 +#define IDS_KRB5_SHORT_DESC 126 +#define IDS_KRB5_LONG_DESC 127 +#define IDS_KRB4_SHORT_DESC 128 +#define IDS_KRB4_LONG_DESC 129 +#define IDS_KRB5_FLAGS_SHORT_DESC 130 +#define IDS_RENEW_TILL_SHORT_DESC 131 +#define IDS_RENEW_TILL_LONG_DESC 132 +#define IDS_RENEW_FOR_SHORT_DESC 133 +#define IDS_RENEW_FOR_LONG_DESC 134 +#define IDS_KRB5_CCNAME_LONG_DESC 135 +#define IDS_NC_USERNAME 136 +#define IDS_NC_REALM 137 +#define IDS_KRB5_WARNING 138 +#define IDS_K5ERR_NAME_EXPIRED 139 +#define IDS_K5ERR_KEY_EXPIRED 140 +#define IDS_KRB5_WARN_FMT 141 +#define IDS_K5ERR_FMT 142 +#define IDS_K5CFG_SHORT_DESC 143 +#define IDS_K5CFG_LONG_DESC 144 +#define IDS_K5RLM_SHORT_DESC 145 +#define IDS_K5RLM_LONG_DESC 146 +#define IDS_K5CFG_IDS_SHORT_DESC 147 +#define IDS_K5CFG_IDS_LONG_DESC 148 +#define IDS_K5CFG_ID_SHORT_DESC 149 +#define IDS_K5CFG_ID_LONG_DESC 150 +#define IDS_PLUGIN_DESC 151 +#define IDS_NC_PWD_BANNER 152 +#define IDS_NC_PWD_PWD 153 +#define IDS_NC_PWD_NPWD 154 +#define IDS_NC_PWD_NPWD_AGAIN 155 +#define IDS_KRB5_CREDTEXT_P0 156 +#define IDS_K5CFG_IMPORT_OPTIONS 157 +#define IDC_NCK5_RENEWABLE 1002 +#define IDC_NCK5_FORWARDABLE 1004 +#define IDC_NCK5_REALM 1005 +#define IDC_NCK5_ADD_REALMS 1006 +#define IDC_NCK5_LIFETIME_EDIT 1008 +#define IDC_NCK5_RENEW_EDIT 1009 +#define IDC_PPK5_CRENEW 1014 +#define IDC_PPK5_CFORWARD 1015 +#define IDC_PPK5_CPROXY 1016 +#define IDC_PPK5_NAME 1017 +#define IDC_PPK5_ISSUE 1018 +#define IDC_PPK5_VALID 1019 +#define IDC_PPK5_RENEW 1020 +#define IDC_CHECK2 1022 +#define IDC_CHECK4 1024 +#define IDC_PPK5_LIFETIME 1024 +#define IDC_CHECK5 1025 +#define IDC_CFG_LBL_REALM 1025 +#define IDC_CFG_DEFREALM 1026 +#define IDC_CFG_LBL_CFGFILE 1029 +#define IDC_CFG_CFGFILE 1030 +#define IDC_CFG_WINGRP 1031 +#define IDC_LBL_IMPORT 1032 +#define IDC_CFG_IMPORT 1033 +#define IDC_CFG_LBL_HOSTNAME 1034 +#define IDC_CFG_HOSTNAME 1035 +#define IDC_CFG_LBL_DOMAIN 1036 +#define IDC_CFG_DOMAIN 1037 +#define IDC_CFG_CREATECONFIG 1038 +#define IDC_CFG_BROWSE 1039 +#define IDC_CFG_CFGFILEGRP 1040 +#define IDC_CFG_CFGREALMS 1041 +#define IDC_CFG_REALMS 1044 +#define IDC_CFG_DOMAINGRP 1045 +#define IDC_CFG_SERVERSGRP 1046 +#define IDC_LIST3 1047 +#define IDC_LIST4 1048 +#define IDC_CFG_LBL_DEFLIFE 1049 +#define IDC_CFG_DEFLIFE 1050 +#define IDC_CFG_LBL_DEFRLIFE 1051 +#define IDC_CFG_DEFRLIFE 1052 +#define IDC_CFG_LIFEGRP 1053 +#define IDC_CFG_LRNG_MIN 1054 +#define IDC_CFG_LRNG_MAX 1055 +#define IDC_CFG_RLRNG_MIN 1056 +#define IDC_CFG_RLRNG_MAX 1057 +#define IDC_CFG_CCACHE 1058 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 111 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1059 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/windows/identity/plugins/krb5/main.c b/src/windows/identity/plugins/krb5/main.c new file mode 100644 index 0000000000..db996d951b --- /dev/null +++ b/src/windows/identity/plugins/krb5/main.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<krbcred.h> +#include<kherror.h> + +kmm_module h_khModule; /* KMM's handle to this module */ +HINSTANCE hInstance; +HMODULE hResModule; /* HMODULE to the resource library */ +const wchar_t * k5_facility = L"Krb5"; + +khm_int32 type_id_enctype = -1; +khm_int32 type_id_addr_list = -1; +khm_int32 type_id_krb5_flags = -1; + +BOOL type_regd_enctype = FALSE; +BOOL type_regd_addr_list = FALSE; +BOOL type_regd_krb5_flags = FALSE; + +khm_int32 attr_id_key_enctype = -1; +khm_int32 attr_id_tkt_enctype = -1; +khm_int32 attr_id_addr_list = -1; +khm_int32 attr_id_krb5_flags = -1; +khm_int32 attr_id_krb5_ccname = -1; + +BOOL attr_regd_key_enctype = FALSE; +BOOL attr_regd_tkt_enctype = FALSE; +BOOL attr_regd_addr_list = FALSE; +BOOL attr_regd_krb5_flags = FALSE; +BOOL attr_regd_krb5_ccname = FALSE; + +khm_handle csp_plugins = NULL; +khm_handle csp_krbcred = NULL; +khm_handle csp_params = NULL; + +BOOL is_k5_identpro = TRUE; + +kmm_module_locale locales[] = { + LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), L"krb5cred_en_us.dll", KMM_MLOC_FLAG_DEFAULT) +}; +int n_locales = ARRAYLENGTH(locales); + +/* These two should not do anything */ +void init_krb() { +} + +void exit_krb() { +} + +/* called by the NetIDMgr module manager */ +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { + khm_int32 rv = KHM_ERROR_SUCCESS; + kmm_plugin_reg pi; + wchar_t buf[256]; + + h_khModule = h_module; + + rv = kmm_set_locale_info(h_module, locales, n_locales); + if(KHM_SUCCEEDED(rv)) { + hResModule = kmm_get_resource_hmodule(h_module); + } else + goto _exit; + + /* register the plugin */ + ZeroMemory(&pi, sizeof(pi)); + pi.name = KRB5_PLUGIN_NAME; + pi.type = KHM_PITYPE_CRED; + pi.icon = NULL; /*TODO: Assign icon */ + pi.flags = KHM_PIFLAG_IDENTITY_PROVIDER; + pi.msg_proc = k5_msg_callback; + pi.description = buf; + LoadString(hResModule, IDS_PLUGIN_DESC, + buf, ARRAYLENGTH(buf)); + kmm_provide_plugin(h_module, &pi); + + if(KHM_FAILED(rv = init_imports())) + goto _exit; + + if(KHM_FAILED(rv = init_error_funcs())) + goto _exit; + + /* Register common data types */ + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ENCTYPE, &type_id_enctype))) { + kcdb_type type; + kcdb_type *t32; + + kcdb_type_get_info(KCDB_TYPE_INT32, &t32); + + type.id = KCDB_TYPE_INVALID; + type.name = TYPENAME_ENCTYPE; + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + type.cb_max = t32->cb_max; + type.cb_min = t32->cb_min; + type.isValid = t32->isValid; + type.comp = t32->comp; + type.dup = t32->dup; + type.toString = enctype_toString; + + rv = kcdb_type_register(&type, &type_id_enctype); + kcdb_type_release_info(t32); + + if(KHM_FAILED(rv)) + goto _exit; + type_regd_enctype = TRUE; + } + + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ADDR_LIST, &type_id_addr_list))) { + kcdb_type type; + kcdb_type *tdata; + + kcdb_type_get_info(KCDB_TYPE_DATA, &tdata); + + type.id = KCDB_TYPE_INVALID; + type.name = TYPENAME_ADDR_LIST; + type.flags = KCDB_TYPE_FLAG_CB_MIN; + type.cb_min = 0; + type.cb_max = 0; + type.isValid = tdata->isValid; + type.comp = tdata->comp; + type.dup = tdata->dup; + type.toString = addr_list_toString; + + rv = kcdb_type_register(&type, &type_id_addr_list); + kcdb_type_release_info(tdata); + + if(KHM_FAILED(rv)) + goto _exit; + type_regd_addr_list = TRUE; + } + + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_KRB5_FLAGS, &type_id_krb5_flags))) { + kcdb_type type; + kcdb_type *t32; + + kcdb_type_get_info(KCDB_TYPE_INT32, &t32); + + type.id = KCDB_TYPE_INVALID; + type.name = TYPENAME_KRB5_FLAGS; + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + type.cb_max = t32->cb_max; + type.cb_min = t32->cb_min; + type.isValid = t32->isValid; + type.comp = t32->comp; + type.dup = t32->dup; + type.toString = krb5flags_toString; + + rv = kcdb_type_register(&type, &type_id_krb5_flags); + kcdb_type_release_info(t32); + + if(KHM_FAILED(rv)) + goto _exit; + type_regd_krb5_flags = TRUE; + } + + /* Register common attributes */ + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KEY_ENCTYPE, &attr_id_key_enctype))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_KEY_ENCTYPE; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_enctype; + attrib.flags = 0; + LoadString(hResModule, IDS_KEY_ENCTYPE_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + LoadString(hResModule, IDS_KEY_ENCTYPE_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_key_enctype); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_key_enctype = TRUE; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_TKT_ENCTYPE, &attr_id_tkt_enctype))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_TKT_ENCTYPE; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_enctype; + attrib.flags = 0; + LoadString(hResModule, IDS_TKT_ENCTYPE_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + LoadString(hResModule, IDS_TKT_ENCTYPE_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_tkt_enctype); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_tkt_enctype = TRUE; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_ADDR_LIST, &attr_id_addr_list))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_ADDR_LIST; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_addr_list; + attrib.flags = 0; + LoadString(hResModule, IDS_ADDR_LIST_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + LoadString(hResModule, IDS_ADDR_LIST_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_addr_list); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_addr_list = TRUE; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_FLAGS, &attr_id_krb5_flags))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_KRB5_FLAGS; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_krb5_flags; + attrib.flags = 0; + LoadString(hResModule, IDS_KRB5_FLAGS_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + + rv = kcdb_attrib_register(&attrib, &attr_id_krb5_flags); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_krb5_flags = TRUE; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_CCNAME, &attr_id_krb5_ccname))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_KRB5_CCNAME; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = KCDB_TYPE_STRING; + attrib.flags = KCDB_ATTR_FLAG_PROPERTY; + LoadString(hResModule, IDS_KRB5_CCNAME_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + LoadString(hResModule, IDS_KRB5_CCNAME_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_krb5_ccname); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_krb5_ccname = TRUE; + } + + rv = kmm_get_plugins_config(0, &csp_plugins); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_load_schema(csp_plugins, schema_krbconfig); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_open_space(csp_plugins, CSNAME_KRB5CRED, 0, &csp_krbcred); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_open_space(csp_krbcred, CSNAME_PARAMS, 0, &csp_params); + if(KHM_FAILED(rv)) goto _exit; + +_exit: + return rv; +} + +/* called by the NetIDMgr module manager */ +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module) { + exit_imports(); + exit_error_funcs(); + + if(attr_regd_key_enctype) + kcdb_attrib_unregister(attr_id_key_enctype); + if(attr_regd_tkt_enctype) + kcdb_attrib_unregister(attr_id_tkt_enctype); + if(attr_regd_addr_list) + kcdb_attrib_unregister(attr_id_addr_list); + if(attr_regd_krb5_flags) + kcdb_attrib_unregister(attr_id_krb5_flags); + if(attr_regd_krb5_ccname) + kcdb_attrib_unregister(attr_id_krb5_ccname); + + if(type_regd_enctype) + kcdb_type_unregister(type_id_enctype); + if(type_regd_addr_list) + kcdb_type_unregister(type_id_addr_list); + if(type_regd_krb5_flags) + kcdb_type_unregister(type_id_krb5_flags); + + if(csp_params) { + khc_close_space(csp_params); + csp_params = NULL; + } + + if(csp_krbcred) { + khc_close_space(csp_krbcred); + csp_krbcred = NULL; + } + + if(csp_plugins) { + khc_unload_schema(csp_plugins, schema_krbconfig); + khc_close_space(csp_plugins); + csp_plugins = NULL; + } + + return KHM_ERROR_SUCCESS; /* the return code is ignored */ +} + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved +) +{ + switch(fdwReason) { + case DLL_PROCESS_ATTACH: + hInstance = hinstDLL; + init_krb(); + break; + case DLL_PROCESS_DETACH: + exit_krb(); + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + } + + return TRUE; +} diff --git a/src/windows/identity/ui/Makefile b/src/windows/identity/ui/Makefile new file mode 100644 index 0000000000..402fc5d885 --- /dev/null +++ b/src/windows/identity/ui/Makefile @@ -0,0 +1,81 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=ui +!include <../config/Makefile.w32> + +EXEFILE=$(BINDIR)\netidmgr.exe + +MANIFESTFILE=$(BINDIR)\netidmgr.exe.manifest + +OBJFILES= \ + $(OBJ)\main.obj \ + $(OBJ)\mainmenu.obj \ + $(OBJ)\toolbar.obj \ + $(OBJ)\statusbar.obj \ + $(OBJ)\notifier.obj \ + $(OBJ)\timer.obj \ + $(OBJ)\uiconfig.obj \ + $(OBJ)\mainwnd.obj \ + $(OBJ)\credwnd.obj \ + $(OBJ)\htwnd.obj \ + $(OBJ)\passwnd.obj \ + $(OBJ)\newcredwnd.obj \ + $(OBJ)\propertywnd.obj \ + $(OBJ)\credfuncs.obj \ + $(OBJ)\configwnd.obj \ + $(OBJ)\aboutwnd.obj \ + $(OBJ)\reqdaemon.obj \ + $(OBJ)\cfg_general_wnd.obj \ + $(OBJ)\cfg_identities_wnd.obj \ + $(OBJ)\cfg_notif_wnd.obj \ + $(OBJ)\cfg_plugins_wnd.obj + +RESFILE=$(OBJ)\khapp.res + +LIBFILES= \ + $(LIBDIR)\nidmgr32.lib + +SDKLIBFILES= \ + comctl32.lib \ + shell32.lib + +$(OBJ)\uiconfig.c: uiconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +$(RESFILE): lang\en_us\khapp.rc + $(RC2RES) + +!if "$(KH_BUILD)"=="RETAIL" +$(MANIFESTFILE): netidmgr.manifest.$(CPU).$(KH_CLVER) +!else +$(MANIFESTFILE): netidmgr.manifest.$(CPU).$(KH_CLVER).debug +!endif + $(CP) $** $@ + +$(EXEFILE): $(OBJFILES) $(RESFILE) $(LIBFILES) + $(EXEGUILINK) $(SDKLIBFILES) + +all: mkdirs $(EXEFILE) $(MANIFESTFILE) + diff --git a/src/windows/identity/ui/aboutwnd.c b/src/windows/identity/ui/aboutwnd.c new file mode 100644 index 0000000000..2dde601a49 --- /dev/null +++ b/src/windows/identity/ui/aboutwnd.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<khimaira_version.h> +#include<tlhelp32.h> + +#if DEBUG +#include<assert.h> +#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)); + SetDlgItemText(hwnd, IDC_COPYRIGHT, + TEXT(KH_VERSTR_COPYRIGHT_1033)); + 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)); + + ListView_SetView(hw, LV_VIEW_DETAILS); + + _done_with_modules: + CloseHandle(hsnap); + } + + khm_add_dialog(hwnd); + khm_enter_modal(hwnd); + } + return FALSE; + + case WM_DESTROY: + khm_leave_modal(); + khm_del_dialog(hwnd); + return TRUE; + + case WM_COMMAND: + if (wParam == MAKEWPARAM(IDOK, BN_CLICKED)) + 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 new file mode 100644 index 0000000000..a427b7dd0d --- /dev/null +++ b/src/windows/identity/ui/aboutwnd.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_ABOUTWND_H +#define __KHIMAIRA_ABOUTWND_H + +void +khm_create_about_window(void); + +#endif diff --git a/src/windows/identity/ui/appglobal.h b/src/windows/identity/ui/appglobal.h new file mode 100644 index 0000000000..41fca2d17e --- /dev/null +++ b/src/windows/identity/ui/appglobal.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_APPGLOBAL_H +#define __KHIMAIRA_APPGLOBAL_H + +/* global data */ +extern HINSTANCE khm_hInstance; +extern int khm_nCmdShow; +extern const wchar_t * khm_facility; +extern kconf_schema schema_uiconfig[]; + +typedef struct tag_khm_startup_options { + BOOL seen; + BOOL processing; + + BOOL init; + BOOL import; + BOOL renew; + BOOL destroy; + + BOOL autoinit; + BOOL exit; + BOOL error_exit; + + BOOL no_main_window; +} khm_startup_options; + +extern khm_startup_options khm_startup; + +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); + +#define MAX_RES_STRING 1024 + +#define ELIPSIS L"..." + +#endif diff --git a/src/windows/identity/ui/cfg_general_wnd.c b/src/windows/identity/ui/cfg_general_wnd.c new file mode 100644 index 0000000000..37c7ba7d11 --- /dev/null +++ b/src/windows/identity/ui/cfg_general_wnd.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +typedef struct tag_cfg_data { + BOOL auto_init; + BOOL auto_start; + BOOL auto_import; + BOOL keep_running; + BOOL auto_detect_net; +} 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_close_space(csp_cw); + + dd->work = *d; +} + +static void +write_params(dlg_data * dd) { + cfg_data * d, * s; + khm_handle csp_cw; + + 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); + + if (!!d->auto_start != !!s->auto_start) + khc_write_int32(csp_cw, L"AutoStart", d->auto_start); + + if (!!d->auto_import != !!s->auto_import) + khc_write_int32(csp_cw, L"AutoImport", d->auto_import); + + if (!!d->keep_running != !!s->keep_running) + khc_write_int32(csp_cw, L"KeepRunning", d->keep_running); + + if (!!d->auto_detect_net != !!s->auto_detect_net) + khc_write_int32(csp_cw, L"AutoDetectNet", d->auto_detect_net); + + khc_close_space(csp_cw); + + khui_cfg_set_flags(dd->node, + KHUI_CNFLAG_APPLIED, + 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) { + + 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 +refresh_view(HWND hwnd, dlg_data * d) { + 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)); +} + +static void +refresh_data(HWND hwnd, dlg_data * d) { + 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); +} + +INT_PTR CALLBACK +khm_cfg_general_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + d = malloc(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_COMMAND: + d = (dlg_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == BN_CLICKED) { + 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 new file mode 100644 index 0000000000..1cef2d7ce7 --- /dev/null +++ b/src/windows/identity/ui/cfg_identities_wnd.c @@ -0,0 +1,1256 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +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; + + count = TabCtrl_GetItemCount(hw_tab); + + for (idx = 0; idx < count; 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 + + PostMessage(hw, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(0, WMCFG_APPLY), 0); + } +} + +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; + 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); +} + +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_idents_data { + BOOL valid; + + ident_data * idents; + khm_size n_idents; + khm_size nc_idents; + + int refcount; + + HIMAGELIST hi_status; + int idx_id; + int idx_default; + int idx_modified; + int idx_applied; + int idx_deleted; + + HWND hwnd; +} idents_data; + +static idents_data cfg_idents = {FALSE, NULL, 0, 0, 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->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) { + khc_write_int32(csp_ident, L"Sticky", !!d->work.sticky); + if (d->work.sticky) { + kcdb_identity_set_flags(d->ident, KCDB_IDENT_FLAG_STICKY); + } else { + kcdb_identity_set_flags(d->ident, + KCDB_IDENT_FLAG_STICKY | + KCDB_IDENT_FLAG_INVERT); + } + } + + 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); +} + +static void +write_params_idents(void) { + int i; + + for (i=0; i < (int)cfg_idents.n_idents; i++) { + write_params_ident(&cfg_idents.idents[i]); + } + + 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; + + 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 + + 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) + free(widnames); + widnames = malloc(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 = malloc(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 = malloc(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); + + read_params_ident(&cfg_idents.idents[i]); + + i++; + /* leave identity held */ + } + + _cleanup: + + cfg_idents.valid = TRUE; + + if (widnames) + free(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) + free(cfg_idents.idents[i].idname); + } + + if (cfg_idents.idents) + free(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(); +} + +#define BS_TRUE 1 +#define BS_FALSE 2 + +static void +refresh_view_idents_sel(HWND hwnd) { + HWND hw; + int sel_count; + int i; + int idx; + ident_data * d; + LVITEM lvi; + + int monitor = 0; + int auto_renew = 0; + int sticky = 0; + + hw = GetDlgItem(hwnd, IDC_CFG_IDENTS); + + sel_count = ListView_GetSelectedCount(hw); + + idx = -1; + for (i=0; i < sel_count; i++) { + idx = ListView_GetNextItem(hw, idx, 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); + + d = (ident_data *) lvi.lParam; +#ifdef DEBUG + assert(d != NULL); +#endif + + if (d->work.monitor) + monitor |= BS_TRUE; + else + monitor |= BS_FALSE; + + if (d->work.auto_renew) + auto_renew |= BS_TRUE; + else + auto_renew |= BS_FALSE; + + if (d->work.sticky) + sticky |= BS_TRUE; + else + sticky |= BS_FALSE; + } + + CheckDlgButton(hwnd, IDC_CFG_MONITOR, + (monitor == BS_TRUE)? BST_CHECKED: + ((monitor == BS_FALSE)? BST_UNCHECKED: + BST_INDETERMINATE)); + + CheckDlgButton(hwnd, IDC_CFG_RENEW, + (auto_renew == BS_TRUE)? BST_CHECKED: + ((auto_renew == BS_FALSE)? BST_UNCHECKED: + BST_INDETERMINATE)); + + CheckDlgButton(hwnd, IDC_CFG_STICKY, + (sticky == BS_TRUE)? BST_CHECKED: + ((sticky == BS_FALSE)? BST_UNCHECKED: + BST_INDETERMINATE)); + + if (sel_count > 0) { + EnableWindow(GetDlgItem(hwnd, IDC_CFG_REMOVE), TRUE); + } else { + EnableWindow(GetDlgItem(hwnd, IDC_CFG_REMOVE), FALSE); + } +} + +#undef BS_TRUE +#undef BS_FALSE + +static void +refresh_data_idents(HWND hwnd) { + HWND hw; + int sel_count; + int i; + int idx; + ident_data * d; + LVITEM lvi; + + UINT monitor = IsDlgButtonChecked(hwnd, IDC_CFG_MONITOR); + UINT auto_renew = IsDlgButtonChecked(hwnd, IDC_CFG_RENEW); + UINT sticky = IsDlgButtonChecked(hwnd, IDC_CFG_STICKY); + + hw = GetDlgItem(hwnd, IDC_CFG_IDENTS); + + sel_count = ListView_GetSelectedCount(hw); + + idx = -1; + for (i=0; i < sel_count; i++) { + idx = ListView_GetNextItem(hw, idx, 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); + + d = (ident_data *) lvi.lParam; +#ifdef DEBUG + assert(d != NULL); +#endif + + if (monitor == BST_CHECKED) + d->work.monitor = TRUE; + else if (monitor == BST_UNCHECKED) + d->work.monitor = FALSE; + + if (auto_renew == BST_CHECKED) + d->work.auto_renew = TRUE; + else if (auto_renew == BST_UNCHECKED) + d->work.auto_renew = FALSE; + + if (sticky == BST_CHECKED) + d->work.sticky = TRUE; + else if (sticky == BST_UNCHECKED) + d->work.sticky = FALSE; + + if (d->hwnd) + PostMessage(d->hwnd, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(0, WMCFG_UPDATE_STATE), 0); + } +} + +static void +refresh_view_idents_state(HWND hwnd) { + HWND hw; + int i; + LVITEM lvi; + ident_data * d; + + BOOL modified = FALSE; + BOOL applied = FALSE; + + hw = GetDlgItem(hwnd, IDC_CFG_IDENTS); + + for (i = -1;;) { + + i = ListView_GetNextItem(hw, i, LVNI_ALL); + if (i == -1) + break; + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.iItem = i; + lvi.iSubItem = 0; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hw, &lvi); + + d = (ident_data *) lvi.lParam; +#ifdef DEBUG + assert(d != NULL); +#endif + + ZeroMemory(&lvi, sizeof(lvi)); + + lvi.mask = LVIF_STATE; + lvi.stateMask = LVIS_STATEIMAGEMASK; + lvi.iItem = i; + lvi.iSubItem = 0; + + if (d->removed) { + lvi.state = INDEXTOSTATEIMAGEMASK(cfg_idents.idx_deleted); + modified = TRUE; + } else if (d->saved.monitor != d->work.monitor || + d->saved.auto_renew != d->work.auto_renew || + d->saved.sticky != d->work.sticky) { + lvi.state = INDEXTOSTATEIMAGEMASK(cfg_idents.idx_modified); + modified = TRUE; + } else if (d->applied) { + lvi.state = INDEXTOSTATEIMAGEMASK(cfg_idents.idx_applied); + applied = TRUE; + } else { + lvi.state = INDEXTOSTATEIMAGEMASK(cfg_idents.idx_default); + } + + ListView_SetItem(hw, &lvi); + } + + { + khm_int32 flags = 0; + khui_config_node node = NULL; + + if (modified) + flags |= KHUI_CNFLAG_MODIFIED; + if (applied) + flags |= KHUI_CNFLAG_APPLIED; + + khui_cfg_open(NULL, L"KhmIdentities", &node); +#ifdef DEBUG + assert(node); +#endif + khui_cfg_set_flags(node, flags, + KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); + } +} + +static void +remove_idents(HWND hwnd) { + HWND hw; + int sel_count; + int i; + int idx; + ident_data * d; + LVITEM lvi; + + hw = GetDlgItem(hwnd, IDC_CFG_IDENTS); + + sel_count = ListView_GetSelectedCount(hw); + + idx = -1; + for (i=0; i < sel_count; i++) { + idx = ListView_GetNextItem(hw, idx, 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); + + d = (ident_data *) lvi.lParam; +#ifdef DEBUG + assert(d != NULL); +#endif + + d->removed = TRUE; + } +} + +INT_PTR CALLBACK +khm_cfg_ids_tab_proc(HWND hwnd, + UINT umsg, + WPARAM wParam, + LPARAM lParam) { + + switch(umsg) { + case WM_INITDIALOG: + { + HWND hw; + HICON hicon; + LVCOLUMN lvcol; + LVITEM lvi; + wchar_t coltext[256]; + RECT r; + int i; + + hold_idents_data(); + + cfg_idents.hwnd = hwnd; + + /* first add the column */ + hw = GetDlgItem(hwnd, IDC_CFG_IDENTS); + + ZeroMemory(&lvcol, sizeof(lvcol)); + lvcol.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT; + + lvcol.fmt = LVCFMT_IMAGE | LVCFMT_LEFT; + + GetWindowRect(hw, &r); + lvcol.cx = ((r.right - r.left) * 95) / 100; + + LoadString(khm_hInstance, IDS_CFG_IDS_IDENTITY, + coltext, ARRAYLENGTH(coltext)); + lvcol.pszText = coltext; + + ListView_InsertColumn(hw, 0, &lvcol); + + /* and the status icons */ + if (cfg_idents.hi_status) + goto _done_with_icons; + + cfg_idents.hi_status = ImageList_Create(SM_CXICON, SM_CYICON, + ILC_COLOR8 | ILC_MASK, + 4,4); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_ID), + IMAGE_ICON, SM_CXICON, SM_CYICON, 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, SM_CXICON, SM_CYICON, 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, SM_CXICON, SM_CYICON, 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, SM_CXICON, SM_CYICON, 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, SM_CXICON, SM_CYICON, LR_DEFAULTCOLOR); + + cfg_idents.idx_deleted = ImageList_AddIcon(cfg_idents.hi_status, + hicon) + 1; + + DestroyIcon(hicon); + + ListView_SetImageList(hw, cfg_idents.hi_status, LVSIL_SMALL); + ListView_SetImageList(hw, cfg_idents.hi_status, LVSIL_STATE); + + _done_with_icons: + + /* now add each identity */ + for(i=0; i < (int)cfg_idents.n_idents; i++) { + ZeroMemory(&lvi, sizeof(lvi)); + + lvi.mask = LVIF_PARAM | LVIF_TEXT | LVIF_STATE | LVIF_IMAGE; + lvi.iImage = cfg_idents.idx_id; + lvi.lParam = (LPARAM) &cfg_idents.idents[i]; + lvi.pszText = cfg_idents.idents[i].idname; + lvi.state = INDEXTOSTATEIMAGEMASK(cfg_idents.idx_default); + lvi.stateMask = LVIS_STATEIMAGEMASK; + + cfg_idents.idents[i].lv_idx = ListView_InsertItem(hw, &lvi); + } + + ListView_SetView(hw, LV_VIEW_DETAILS); + } + return FALSE; + + case WM_NOTIFY: + { + LPNMHDR lpnm = (LPNMHDR) lParam; + + if (lpnm->code == LVN_ITEMCHANGED) { + refresh_view_idents_sel(hwnd); + } + } + return TRUE; + + 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: + if (IsDlgButtonChecked(hwnd, ctrl) == BST_CHECKED) + CheckDlgButton(hwnd, ctrl, BST_UNCHECKED); + else + CheckDlgButton(hwnd, ctrl, BST_CHECKED); + refresh_data_idents(hwnd); + break; + + case IDC_CFG_REMOVE: + remove_idents(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); + refresh_view_idents_sel(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; +} + +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; + + 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]; + else + return NULL; +} + +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 +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); + } +} + +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; + } + } + 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; + + khui_cfg_get_dialog_data(hwnd, &idata, NULL); + + switch (HIWORD(wParam)) { + case WMCFG_APPLY: + d = find_ident_by_node(idata->ctx_node); + write_params_ident(d); + 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; +} + +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 new file mode 100644 index 0000000000..aafa12d723 --- /dev/null +++ b/src/windows/identity/ui/cfg_notif_wnd.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +typedef struct tag_notif_data { + khui_config_node node; + + BOOL monitor; + BOOL renew; + 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"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); +} + +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->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); + + } else { + khui_cfg_set_flags(d->node, + 0, + KHUI_CNFLAG_MODIFIED); + } +} + +static void +write_params(notif_data * d) { + khm_handle csp_cw; + khm_int32 rv; + + 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"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); +} + +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_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_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_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->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 = malloc(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); + + free(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 new file mode 100644 index 0000000000..16a344275c --- /dev/null +++ b/src/windows/identity/ui/cfg_plugins_wnd.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +#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_dlg_data; + +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]; + + + d = malloc(sizeof(*d)); +#ifdef DEBUG + assert(d); +#endif + ZeroMemory(d, sizeof(*d)); +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + 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] = malloc(sizeof(*(d->info[i]))); +#ifdef DEBUG + assert(d->info[i]); +#endif + + if (KHM_FAILED(kmm_get_plugin_info_i(p, &d->info[i]->plugin))) { + free(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 + ListView_SetView(hw, LV_VIEW_DETAILS); + + 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; i<d->n_info; i++) { + LVITEM lvi; + + ZeroMemory(&lvi, sizeof(lvi)); + + lvi.mask = LVIF_PARAM | LVIF_TEXT; + lvi.lParam = (LPARAM) d->info[i]; + lvi.pszText = d->info[i]->plugin.reg.name; + + ListView_InsertItem(hw, &lvi); + } + } + 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""); + EnableWindow(GetDlgItem(hwnd, IDC_CFG_ENABLE), FALSE); + EnableWindow(GetDlgItem(hwnd, IDC_CFG_DISABLE), FALSE); + SendDlgItemMessage(hwnd, IDC_CFG_DEPS, + LB_RESETCONTENT, 0, 0); + } else { + int idx; + plugin_data * info; + wchar_t buf[256]; + UINT resid; + wchar_t * t; + + 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; + + if (info->plugin.reg.description) + SetDlgItemText(hwnd, IDC_CFG_DESC, info->plugin.reg.description); + else + SetDlgItemText(hwnd, IDC_CFG_DESC, L""); + + switch(info->plugin.state) { + 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""); + } + } + } + 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; i<d->n_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); + free(d->info[i]); + } + + free(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 new file mode 100644 index 0000000000..22a41eeb5a --- /dev/null +++ b/src/windows/identity/ui/configwnd.c @@ -0,0 +1,839 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +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(SM_CXICON, SM_CYICON, + ILC_COLOR8 | ILC_MASK, + 4,4); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_DEFAULT), + IMAGE_ICON, SM_CXICON, SM_CYICON, 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, SM_CXICON, SM_CYICON, LR_DEFAULTCOLOR); + + d->idx_modified = ImageList_AddIcon(d->hi_status, hicon); + + DestroyIcon(hicon); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_APPLIED), + IMAGE_ICON, SM_CXICON, SM_CYICON, 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 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 { + khui_config_node_reg reg; + khm_int32 rv; + + hw_new = khui_cfg_get_hwnd(node); + + if (hw_new == NULL) { + 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); + } + } + + 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; + + hwnd = khui_cfg_get_hwnd(node); + + if (hwnd) + 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_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, IDC_CFG_SUMMARY), TRUE); + EnableWindow(GetDlgItem(hwnd, IDAPPLY), TRUE); + } else { + EnableWindow(GetDlgItem(hwnd, IDC_CFG_SUMMARY), FALSE); + 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); + + SetWindowLong(hwnd, DWL_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(); + + d = malloc(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); + + khui_cfg_set_configui_handle(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); + + khm_leave_modal(); + khm_del_dialog(hwnd); + + SetForegroundWindow(khm_hwnd_main); + + return FALSE; + + case WM_NOTIFY: + { + LPNMHDR lpnm; + LPNMTREEVIEW lptv; + + lpnm = (LPNMHDR) lParam; + + switch (lpnm->code) { + case TVN_SELCHANGED: + lptv = (LPNMTREEVIEW) lParam; + cfgui_activate_node(hwnd, + (khui_config_node) + lptv->itemNew.lParam); + 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): + DestroyWindow(hwnd); + break; + + case MAKEWPARAM(IDAPPLY, BN_CLICKED): + cfgui_apply_settings(NULL); + break; + + case MAKEWPARAM(IDOK, BN_CLICKED): + cfgui_apply_settings(NULL); + 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; + } + 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; + + 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) + free(idents); + idents = malloc(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); + } + } + + _cleanup: + if (cfg_ids) + khui_cfg_release(cfg_ids); + + if (idents) + free(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 = 0; + + 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"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_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_cfg_register(node, ®); + + reg.flags = 0; + 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 new file mode 100644 index 0000000000..64da771532 --- /dev/null +++ b/src/windows/identity/ui/configwnd.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_CONFIGWND_H +#define __KHIMAIRA_CONFIGWND_H + +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); +#endif diff --git a/src/windows/identity/ui/credfuncs.c b/src/windows/identity/ui/credfuncs.c new file mode 100644 index 0000000000..b92e5d4a83 --- /dev/null +++ b/src/windows/identity/ui/credfuncs.c @@ -0,0 +1,827 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +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 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; + else { + rv = TRUE; + in_dialog = TRUE; + ResetEvent(in_dialog_evt); + } + + LeaveCriticalSection(&cs_dialog); + return rv; +} + +void +khm_cred_end_dialog(khm_int32 result) { + dialog_sync_init(); + + EnterCriticalSection(&cs_dialog); + if (in_dialog) { + in_dialog = FALSE; + SetEvent(in_dialog_evt); + } + dialog_result = result; + 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) { + 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; + break; + } else if(dw == WAIT_TIMEOUT) { + rv = KHM_ERROR_TIMEOUT; + break; + } + } while(TRUE); + } + LeaveCriticalSection(&cs_dialog); + + return rv; +} + +/* completion handler for KMSG_CRED messages */ +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 not 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(!khm_cred_dispatch_process_level(nc)) { + + if(kherr_is_error()) { + khui_alert * alert; + kherr_event * evt; + kherr_context * ctx; + wchar_t ws_title[1024]; + + ctx = kherr_peek_context(); + evt = kherr_get_err_event(ctx); + kherr_evaluate_event(evt); + + khui_alert_create_empty(&alert); + + if (nc->subtype == KMSG_CRED_PASSWORD) + LoadString(khm_hInstance, IDS_NC_PWD_FAILED_TITLE, + ws_title, ARRAYLENGTH(ws_title)); + else + LoadString(khm_hInstance, IDS_NC_FAILED_TITLE, + ws_title, ARRAYLENGTH(ws_title)); + + 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); + + khui_alert_show(alert); + khui_alert_release(alert); + + kherr_release_context(ctx); + + kherr_clear_error(); + } + + 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; + + nc = (khui_new_creds *) m->vparam; + + if (nc->subtype == KMSG_CRED_NEW_CREDS || + nc->subtype == KMSG_CRED_PASSWORD) { + + if (nc->subtype == KMSG_CRED_NEW_CREDS) + khui_context_reset(); + + khm_cred_end_dialog(nc->result); + } + + khui_cw_destroy_cred_blob(nc); + + kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0); + + khm_cred_process_commandline(); + } + 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); + free(m->vparam); + + kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0); + + khm_cred_process_commandline(); + break; + + case KMSG_CRED_IMPORT: + khm_cred_process_commandline(); + 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(void) +{ + khui_action_context * pctx; + + pctx = malloc(sizeof(*pctx)); +#ifdef DEBUG + assert(pctx); +#endif + + khui_context_get(pctx); + + if(pctx->scope == KHUI_SCOPE_NONE) { + /* 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); + free(pctx); + } else { + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS); + _describe(); + + kmq_post_message(KMSG_CRED, + KMSG_CRED_DESTROY_CREDS, + 0, + (void *) pctx); + + _end_task(); + } +} + +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_GET_CREDS; + 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(); + + 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_GET_CREDS; + 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(); + + 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_GET_CREDS; + khui_context_get(&c->ctx); + + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS); + _describe(); + + 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; + + 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 = malloc(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 = malloc(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(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; + + 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 = malloc(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 = malloc(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_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; i<nc->n_types; i++) { + t = nc->types[i]; + + if((t->flags & KHUI_NCT_FLAG_PROCESSED) || + (t->flags & KHUI_NC_RESPONSE_COMPLETED)) + continue; + + for(j=0; j<t->n_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(j<t->n_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; i<nc->n_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_commandline(void) { + khm_handle defident = NULL; + + if (!khm_startup.processing) + return; + + if (khm_startup.init || + khm_startup.renew || + khm_startup.destroy) { + kcdb_identity_get_default(&defident); + } + + 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; + break; + } + + if (khm_startup.renew) { + if (defident) + khui_context_set(KHUI_SCOPE_IDENT, + defident, + KCDB_CREDTYPE_INVALID, + NULL, NULL, 0, + NULL); + else + khui_context_reset(); + + khm_cred_renew_creds(); + khm_startup.renew = FALSE; + break; + } + + if (khm_startup.destroy) { + if (defident) { + khui_context_set(KHUI_SCOPE_IDENT, + defident, + KCDB_CREDTYPE_INVALID, + NULL, NULL, 0, + NULL); + + khm_cred_destroy_creds(); + } + + khm_startup.destroy = FALSE; + break; + } + + if (khm_startup.autoinit) { + khm_size count; + + kcdb_credset_get_size(NULL, &count); + + if (count == 0) { + khm_cred_obtain_new_creds(NULL); + } + khm_startup.autoinit = FALSE; + break; + } + + if (khm_startup.exit) { + PostMessage(khm_hwnd_main, + WM_COMMAND, + MAKEWPARAM(KHUI_ACTION_EXIT, 0), 0); + khm_startup.exit = FALSE; + break; + } + + khm_startup.processing = FALSE; + } while(FALSE); + + if (defident) + kcdb_identity_release(defident); +} + +void +khm_cred_begin_commandline(void) { + if (khm_startup.seen) + return; + + khm_startup.seen = TRUE; + khm_startup.processing = TRUE; + + khm_cred_process_commandline(); +} diff --git a/src/windows/identity/ui/credfuncs.h b/src/windows/identity/ui/credfuncs.h new file mode 100644 index 0000000000..b25b6630eb --- /dev/null +++ b/src/windows/identity/ui/credfuncs.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_CREDFUNCS_H +#define __KHIMAIRA_CREDFUNCS_H + +void KHMAPI +kmsg_cred_completion(kmq_message *m); + +void +khm_cred_destroy_creds(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_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); + +void +khm_cred_begin_commandline(void); + +void +khm_cred_process_commandline(void); + +#endif diff --git a/src/windows/identity/ui/credwnd.c b/src/windows/identity/ui/credwnd.c new file mode 100644 index 0000000000..784a7f90b9 --- /dev/null +++ b/src/windows/identity/ui/credwnd.c @@ -0,0 +1,3223 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<prsht.h> +#include<assert.h> + +ATOM khui_credwnd_cls; +khm_int32 khui_cw_flag_id; + +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; +} + +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 * cstr = NULL; + wchar_t * iter = NULL; + int i; + HDC hdc; + + tbl->hwnd = hwnd; + + if(KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, &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, L"DefaultView", buf, &cbsize))) + goto _exit; + view = buf; + } + + if(KHM_FAILED(khc_open_space(hc_vs, view, KHM_PERM_READ, &hc_v))) + goto _exit; + + if(KHM_FAILED(khc_open_space(hc_v, L"Columns", KHM_PERM_READ, &hc_cs))) + goto _exit; + + cbsize = 0; + if(khc_read_multi_string(hc_v, L"ColumnList", NULL, &cbsize) != KHM_ERROR_TOO_LONG) + goto _exit; + + clist = malloc(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 = malloc(sizeof(khui_credwnd_col) * tbl->n_total_cols); + ZeroMemory(tbl->cols, sizeof(khui_credwnd_col) * tbl->n_total_cols); + + 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))) + goto _skip_col; + if(kcdb_attrib_describe(attr_id, NULL, &cbsize, KCDB_TS_SHORT) != KHM_ERROR_TOO_LONG || + cbsize == 0) + goto _skip_col; + tbl->cols[i].title = malloc(cbsize); + kcdb_attrib_describe(attr_id, tbl->cols[i].title, &cbsize, KCDB_TS_SHORT); + } 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, &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 = -1; + 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); + } + + /* 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); + + tbl->hf_header = CreateFont( + -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */ + 0,0, /* escapement */ + FW_THIN, + FALSE, + FALSE, + FALSE, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_SWISS, + L"MS Shell Dlg"); + + if(tbl->hf_header && tbl->hwnd_header) + SendMessage(tbl->hwnd_header, WM_SETFONT, (WPARAM) tbl->hf_header, 0); + + tbl->hf_bold_header = CreateFont( + -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */ + 0,0, /* escapement */ + FW_BOLD, + FALSE, + FALSE, + FALSE, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_SWISS, + L"MS Shell Dlg"); + + tbl->hf_normal = CreateFont( + -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */ + 0,0, /* escapement */ + FW_THIN, + FALSE, + FALSE, + FALSE, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_SWISS, + L"MS Shell Dlg"); + + tbl->hf_bold = CreateFont( + -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */ + 0,0, /* escapement */ + FW_BOLD, + FALSE, + FALSE, + FALSE, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_SWISS, + L"MS Shell Dlg"); + + ReleaseDC(hwnd, hdc); + + khui_bitmap_from_hbmp(&(tbl->kbm_logo_shade),LoadImage( + khm_hInstance, + MAKEINTRESOURCE(IDB_LOGO_SHADE), + IMAGE_BITMAP, + 0, + 0, + LR_DEFAULTCOLOR)); + + tbl->hb_normal = CreateSolidBrush(RGB(255,255,255)); + tbl->hb_grey = CreateSolidBrush(RGB(240,240,240)); + tbl->hb_sel = CreateSolidBrush(RGB(230,230,255)); + tbl->hb_hdr_bg = CreateSolidBrush(RGB(230,230,230)); + tbl->hb_hdr_bg_sel = CreateSolidBrush(RGB(0,0,255)); + tbl->hb_hdr_bg_crit = CreateSolidBrush(RGB(240,133,117)); + tbl->hb_hdr_bg_warn = CreateSolidBrush(RGB(251,199,77)); + tbl->hb_hdr_bg_exp = CreateSolidBrush(RGB(255,144,144)); + + tbl->cr_normal = RGB(0,0,0); + tbl->cr_sel = RGB(0,0,0); + tbl->cr_hdr_outline = RGB(0,0,0); + tbl->cr_hdr_normal = RGB(0,0,0); + tbl->cr_hdr_sel = RGB(255,255,255); + + tbl->ilist = khui_create_ilist(KHUI_SMICON_CX, KHUI_SMICON_CY-1, 16, 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); + +#undef ADD_BITMAP + } + + tbl->cursor_row = -1; + tbl->scr_left = 0; + tbl->scr_top = 0; + tbl->ext_height = 0; + tbl->ext_width = 0; + +_exit: + if(hc_cw) + khc_close_space(hc_cw); + if(hc_vs) + khc_close_space(hc_vs); + if(hc_v) + khc_close_space(hc_v); + if(hc_cs) + khc_close_space(hc_cs); + if(clist) + free(clist); +} + +void +cw_update_creds(khui_credwnd_tbl * tbl) +{ + kcdb_cred_comp_field * fields; + kcdb_cred_comp_order comp_order; + khm_size 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 = malloc(sizeof(kcdb_cred_comp_field) * tbl->n_cols); + ZeroMemory(fields, sizeof(kcdb_cred_comp_field) * tbl->n_cols); + + for(i=0, n=0; i<tbl->n_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<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); + } + } +} + +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) + free(o->header); + if ((o->flags & KHUI_CW_O_DATAALLOC) && + o->data) + free(o->data); + + LPOP(&(o->children), &c); + while(c) { + cw_del_outline(c); + LPOP(&(o->children), &c); + } + + free(o); +} + +khui_credwnd_outline * +cw_new_outline_node(wchar_t * heading) { + khui_credwnd_outline * o; + size_t cblen; + + o = malloc(sizeof(khui_credwnd_outline)); + ZeroMemory(o, sizeof(khui_credwnd_outline)); + + if(SUCCEEDED(StringCbLength(heading, KHUI_MAXCB_HEADING, &cblen))) { + cblen += sizeof(wchar_t); + o->header = malloc(cblen); + StringCbCopy(o->header, cblen, heading); + } + + return o; +} + +khm_int32 +cw_get_cred_exp_flags(khui_credwnd_tbl * tbl, khm_handle cred) +{ + khm_int32 flags; + long s; + FILETIME ft; + khm_size cbsize; + + cbsize = sizeof(ft); + if(KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_TIMELEFT, NULL, &ft, &cbsize))) + return 0; + + s = FtIntervalToMilliseconds(&ft) / 1000; + + 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); + +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; + khm_size nr; + long ms; + FILETIME ft; + khm_size cbsize; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + r = (khui_credwnd_row *) idEvent; + + nr = r - tbl->rows; + + if(nr < 0 || nr >= tbl->n_rows) + return; + + if(!(r->flags & KHUI_CW_ROW_CRED)) + return; /* we only know what to do with cred rows */ + + nflags = cw_get_cred_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 r,rr,ri; + + GetClientRect(tbl->hwnd, &r); + r.top += tbl->header_height; + rr.top = r.top + (long)nr * tbl->cell_height - tbl->scr_top; + rr.bottom = rr.top + tbl->cell_height; + rr.left = r.left; + rr.right = r.right; + + if(IntersectRect(&ri, &r, &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); + } + } +} + +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; + khm_size newsize; + + newsize = UBOUNDSS(row+1,KHUI_CW_ROW_INITIAL, KHUI_CW_ROW_INCREMENT); + newrows = malloc(sizeof(khui_credwnd_row) * newsize); + memcpy(newrows, tbl->rows, sizeof(khui_credwnd_row) * tbl->n_rows); + free(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; + khm_size newsize; + + newsize = UBOUNDSS(row+1,KHUI_CW_ROW_INITIAL, KHUI_CW_ROW_INCREMENT); + newrows = malloc(sizeof(khui_credwnd_row) * newsize); + memcpy(newrows, tbl->rows, sizeof(khui_credwnd_row) * tbl->n_rows); + free(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; +} + +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; + 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; + + /* 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 = malloc(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 = malloc(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) { + 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 = malloc(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->idx_start = i; + ol->length = 0; + ol->flags &= ~CW_EXPSTATE_MASK; + ol->flags &= ~KHUI_CW_O_SHOWFLAG; + ol->flags &= ~KHUI_CW_O_STICKY; + + 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 */ + visible = visible && (ol->flags & KHUI_CW_O_EXPAND); + + flags = cw_get_cred_exp_flags(tbl, thiscred); + + if(visible) { + khm_int32 c_flags; + + cw_set_tbl_row_cred(tbl, n_rows, thiscred, + grouping[n_grouping-1]); + kcdb_cred_get_flags(thiscred, &c_flags); + if(flags) { + tbl->rows[n_rows].flags |= 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++; + } else if(flags) { + khui_credwnd_outline *to; + /* the row that is flagged is not visible. We need to send + the flag upstream until we hit a visible outline node */ + to = ol; + while(to && !(to->flags & KHUI_CW_O_VISIBLE)) { + to = TPARENT(to); + } + if(to) { + to->flags |= KHUI_CW_O_SHOWFLAG; + } + } + + /* and we propagate the flags upstream */ + if(flags) { + khui_credwnd_outline *to; + + to = ol; + while(to) { + if((to->flags & CW_EXPSTATE_MASK) < flags) { + to->flags = (to->flags & ~CW_EXPSTATE_MASK) | flags; + } + to = TPARENT(to); + } + } + + 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 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; + + 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 = malloc(cb_names); + idarray = malloc(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++) { + 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; + } else { + /* not found. create */ + o = cw_new_outline_node(idarray[i]); + o->flags = KHUI_CW_O_VISIBLE; + o->level = 0; + o->col = grouping[0]; + } + + o->flags |= KHUI_CW_O_STICKY; + o->flags &= ~KHUI_CW_O_EXPAND; + o->start = n_rows; + o->length = 1; + o->idx_start = -1; + + cw_set_tbl_row_header(tbl, n_rows, grouping[0], o); + + n_rows ++; + } + + _cleanup_sticky: + if (idnames) + free(idnames); + if (idarray) + free(idarray); + } + + tbl->n_rows = n_rows; + tbl->flags |= KHUI_CW_TBL_ROW_DIRTY; + + tbl->flags &= ~KHUI_CW_TBL_COL_DIRTY; +_exit: + if(grouping) + free(grouping); +} + +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_sel); + SafeDeleteObject(tbl->hb_hdr_bg); + SafeDeleteObject(tbl->hb_hdr_bg_sel); + SafeDeleteObject(tbl->hb_hdr_bg_crit); + SafeDeleteObject(tbl->hb_hdr_bg_exp); + SafeDeleteObject(tbl->hb_hdr_bg_warn); + +#undef SafeDeleteObject + + 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) { + khm_size i; + for(i=0; i < tbl->n_cols; i++) { + if(tbl->cols[i].title) + free(tbl->cols[i].title); + Header_DeleteItem(tbl->hwnd_header, 0); + } + free(tbl->cols); + tbl->cols = NULL; + tbl->n_cols = 0; + tbl->n_total_cols = 0; + } + + if(tbl->rows) { + free(tbl->rows); + tbl->rows = NULL; + tbl->n_rows = 0; + tbl->n_total_rows = 0; + } + + khui_delete_bitmap(&tbl->kbm_logo_shade); +} + +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(col->flags & KHUI_CW_COL_SORT_INC) { + phi->fmt |= HDF_SORTUP; + } else if(col->flags & KHUI_CW_COL_SORT_DEC) { + phi->fmt |= HDF_SORTDOWN; + } + if(col->width < 0) { + /*TODO: come up with a better way to handle this case */ + col->width = 200; + } + phi->cxy = col->width; +} + +/* returns a bitmask indicating which measures were changed */ +int +cw_update_extents(khui_credwnd_tbl * tbl, + khm_boolean update_scroll) { + int ext_x, ext_y; + int i; + + ext_x = 0; + for(i=0; i < (int) tbl->n_cols; i++) { + tbl->cols[i].x = ext_x; + ext_x += tbl->cols[i].width; + } + + if(!tbl->cell_height) { + HDC dc; + HFONT hfold; + SIZE size; + size_t cbbuf; + wchar_t buf[64]; + + dc = GetWindowDC(tbl->hwnd); + if(tbl->hf_normal) + hfold = SelectFont(dc, tbl->hf_normal); + + LoadString(khm_hInstance, IDS_SAMPLE_STRING, buf, sizeof(buf)/sizeof(buf[0])); + StringCchLength(buf, sizeof(buf)/sizeof(buf[0]), &cbbuf); + GetTextExtentPoint32(dc, buf, (int) cbbuf, &size); + + if(tbl->hf_normal) + SelectFont(dc,hfold); + ReleaseDC(tbl->hwnd, dc); + + tbl->cell_height = size.cy + tbl->vpad * 2; + } + + 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; + + if(RectVisible(hdc, r_erase)) { + + 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_sel; + 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 = IntersectRect(&ri, r_erase, &rlogo); + } else { + 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; + + /* each header consists of a 'expose' widget 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; + + selected = o->flags & KHUI_CW_O_SELECTED; + + { + HBRUSH hbr; + if(selected) + hbr = tbl->hb_hdr_bg_sel; + 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 + hbr = tbl->hb_hdr_bg; + + FillRect(hdc, r, hbr); + } + + 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_STICKY) { + /* khui_ilist_draw_id(tbl->ilist, IDB_TK_NEW_SM, hdc, + r->left, r->bottom - KHUI_SMICON_CY, 0); */ + } else if((tbl->mouse_state & CW_MOUSE_OUTLINE) && 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->bottom - KHUI_SMICON_CY, 0); + } else { + khui_ilist_draw_id(tbl->ilist, IDB_WDG_COLLAPSE_HI, hdc, r->left, r->bottom - KHUI_SMICON_CY, 0); + } + } else { + if(o->flags & KHUI_CW_O_EXPAND) { + khui_ilist_draw_id(tbl->ilist, IDB_WDG_EXPAND, hdc, r->left, r->bottom - KHUI_SMICON_CY, 0); + } else { + khui_ilist_draw_id(tbl->ilist, IDB_WDG_COLLAPSE, hdc, r->left, r->bottom - KHUI_SMICON_CY, 0); + } + } + + r->left += KHUI_SMICON_CX * 2; + + /* try to draw the icon, if there is one */ + if(colattr == KCDB_ATTR_ID_NAME) { + khui_ilist_draw_id(tbl->ilist, + ((o->flags & KHUI_CW_O_STICKY)? + IDB_ID_DIS_SM: + IDB_ID_SM), + hdc, + r->left, r->bottom - KHUI_SMICON_CY, + 0); + r->left += KHUI_SMICON_CX ; + } + + /* ok, now o->header contains the string representation of the + outline value */ + /* for now just write out the value */ + SetTextAlign(hdc, TA_BOTTOM | TA_LEFT); + + if(selected) + SetTextColor(hdc, tbl->cr_hdr_sel); + else + SetTextColor(hdc, tbl->cr_hdr_normal); + + TextOut(hdc, r->left, r->bottom - tbl->vpad, o->header, (int) wcslen(o->header)); +} + +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: + { + if(tbl->cols[ph->iItem].flags & KHUI_CW_COL_FIXED_WIDTH) + return TRUE; + else + return FALSE; + } + + case HDN_TRACK: + case HDN_ENDTRACK: + { + int width; + hi.mask = HDI_ORDER; + Header_GetItem(ph->hdr.hwndFrom, ph->iItem, &hi); + Header_GetItemRect(ph->hdr.hwndFrom, ph->iItem, &r); + width = r.right - r.left; + if(width != tbl->cols[hi.iOrder].width) { + tbl->cols[hi.iOrder].width = width; + cw_update_extents(tbl, TRUE); + InvalidateRect(tbl->hwnd, NULL, FALSE); + } + } + break; + + case 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); + + tbl = malloc(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) + + tbl->hwnd_header = CreateWindowEx( + 0, + WC_HEADER, + (LPWSTR) NULL, + WS_CHILD | HDS_BUTTONS | + HDS_FULLDRAG | HDS_HORZ | HDS_HOTTRACK | HDS_FLAT, + 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_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); + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + cw_unload_view(tbl); + + free(tbl); + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +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; + 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; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + if(!GetUpdateRect(hwnd, &r, FALSE)) + goto _exit; + + 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 = tbl->scr_top / tbl->cell_height; + ys = row_s * tbl->cell_height; + row_e = (tbl->scr_top + (r.bottom - r.top)) / tbl->cell_height + 1; + if(row_e > (int) tbl->n_rows) + 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; + + if(tbl->cursor_row == i) + SelectFont(hdc, tbl->hf_bold); + + 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 + tbl->cell_height; + 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_sel); + else + SetTextColor(hdc, tbl->cr_normal); + + x = xs; + rh.top = y; + rh.bottom = y + tbl->cell_height; + 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(!RectVisible(hdc, &rh)) + continue; + + 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); + //TextOut(hdc, x, y + tbl->vpad, buf, (cbbuf / sizeof(wchar_t)) - 1); + } + } + } 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 { + 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_TK_REFRESH_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); + + SelectFont(hdc, tbl->hf_normal); + } + + y += tbl->cell_height; + + } + + 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,(r.bottom - r.top) /2, + WS_EX_TRANSPARENT, + 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); + + EndPaint(hwnd,&ps); +_exit: + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +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, + (rect.bottom - tbl->header_height) / 2, + 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) { + if(m->subtype == KMSG_CRED_ROOTDELTA) { + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_extents(tbl, TRUE); + InvalidateRect(hwnd, NULL, FALSE); + } else if(m->subtype == KMSG_CRED_PP_BEGIN) { + cw_pp_begin((khui_property_sheet *) m->vparam); + } else if(m->subtype == KMSG_CRED_PP_PRECREATE) { + cw_pp_precreate((khui_property_sheet *) m->vparam); + } else if(m->subtype == KMSG_CRED_PP_END) { + cw_pp_end((khui_property_sheet *) m->vparam); + } else if(m->subtype == KMSG_CRED_PP_DESTROY) { + cw_pp_destroy((khui_property_sheet *) m->vparam); + } + } + 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_unselect_all(khui_credwnd_tbl * tbl) +{ + khm_size i; + + for(i=0; i<tbl->n_rows; i++) { + tbl->rows[i].flags &= ~KHUI_CW_ROW_SELECTED; + if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) + kcdb_cred_set_flags((khm_handle) tbl->rows[i].data, + 0, + KCDB_CRED_FLAG_SELECTED); + } + + 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) +{ + khm_size 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 (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) { /* selected an identity */ + khui_context_set(KHUI_SCOPE_IDENT, + (khm_handle) o->data, + KCDB_CREDTYPE_INVALID, + NULL, + NULL, + 0, + tbl->credset); + } else { + 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 { + set_context = FALSE; + } + } + } 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 && + TPARENT(op) == NULL) { + /* credtype under an 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_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; + if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) { + kcdb_cred_set_flags((khm_handle) tbl->rows[i].data, + KCDB_CRED_FLAG_SELECTED, + KCDB_CRED_FLAG_SELECTED); + } + } + } 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; + + if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) { + kcdb_cred_set_flags((khm_handle) tbl->rows[i].data, + (select)?KCDB_CRED_FLAG_SELECTED:0, + KCDB_CRED_FLAG_SELECTED); + } + + } + } 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; + + if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) { + kcdb_cred_set_flags((khm_handle) tbl->rows[i].data, + KCDB_CRED_FLAG_SELECTED, + KCDB_CRED_FLAG_SELECTED); + } + } + + 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 = y / tbl->cell_height; + 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) { + /* are we on a widget then? */ + x -= tbl->cols[tbl->rows[row].col].x; + if(x >= 0 && x < KHUI_SMICON_CX) /* hit */ { + nm_state |= CW_MOUSE_OUTLINE; + } + } + } + + if((tbl->mouse_state & CW_MOUSE_LDOWN) && + (tbl->mouse_state & CW_MOUSE_OUTLINE) && + (nm_row != tbl->mouse_row)) + { + nm_state &= ~CW_MOUSE_OUTLINE; + } + + if(!(nm_state & CW_MOUSE_LDOWN) && + (tbl->mouse_state & CW_MOUSE_LDOWN)) { + + if((nm_state & CW_MOUSE_OUTLINE) && + (tbl->mouse_state & CW_MOUSE_OUTLINE)) { + /* click on a widget */ + khui_credwnd_outline * o; + + o = (khui_credwnd_outline *) tbl->rows[nm_row].data; + tbl->mouse_state = CW_MOUSE_OUTLINE; + + cw_toggle_outline_state(tbl, o); + + return 0; + } else if(nm_row == tbl->mouse_row) { + /* click on a row */ + cw_select_row(tbl, nm_row, wParam); + } + + } + + /*TODO: if a user clicks somewhere and drags on to an exand widget, it activates the widet. should not */ + + /* ok, now if we are changing state, we need to invalidate a few + regions */ + if((tbl->mouse_state ^ nm_state) & CW_MOUSE_OUTLINE) { + if(tbl->mouse_state & CW_MOUSE_OUTLINE) { + 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); + } + + 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_OUTLINE) { + 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); + } + } else if(tbl->mouse_state != nm_state) { + 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); +} + +LRESULT +cw_wm_vscroll(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + khui_credwnd_tbl * tbl; + SCROLLINFO si; + RECT cr; + RECT sr; + RECT lr; + int dy; + int newpos; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + GetClientRect(hwnd, &cr); + cr.top += tbl->header_height; + dy = tbl->scr_top; + + 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); + } + + 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); + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +static INT_PTR CALLBACK +cw_pp_ident_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ) +{ + switch(uMsg) { + case WM_INITDIALOG: + { + khui_property_sheet * s; + 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); + + SendDlgItemMessage(hwnd, + IDC_PP_IDDEF, + BM_SETCHECK, + (WPARAM) ((i & KCDB_IDENT_FLAG_DEFAULT)?BST_CHECKED:BST_UNCHECKED), + 0); + + SendDlgItemMessage( + hwnd, + IDC_PP_IDSEARCH, + BM_SETCHECK, + (WPARAM) ((i & KCDB_IDENT_FLAG_SEARCHABLE)?BST_CHECKED:BST_UNCHECKED), + 0); + + khui_property_wnd_set_record(GetDlgItem(hwnd, IDC_PP_PROPLIST), + ident); + } + return TRUE; + } + 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 = malloc(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, 0, p, NULL); + } + + if(s->cred) { + p = malloc(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, 0, 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) { + free(p->p_page); + p->p_page = NULL; + } + + p = NULL; + + khui_ps_find_page(s, KHUI_PPCT_CREDENTIAL, &p); + if(p) { + free(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) + free((LPWSTR) ps->header.pszCaption); + } + + 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) { + + 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) { + 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 = malloc(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; + + 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 = malloc(t); + kcdb_identity_get_name(ctx.identity, (wchar_t *) ps->header.pszCaption, &t); + } else { + ps->header.pszCaption = NULL; + } + } else { + kcdb_credtype_describe(cred_type, NULL, &t, KCDB_TS_LONG); + if(t > 0) { + ps->header.pszCaption = malloc(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 = malloc(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_ps_destroy_sheet(ps); + } + + khui_context_reset(); + + 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; + wcsncpy(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_ID: + { + 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_extents(tbl, FALSE); + + InvalidateRect(tbl->hwnd, NULL, TRUE); + + khui_check_radio_action(khui_find_menu(KHUI_MENU_LAYOUT), KHUI_ACTION_LAYOUT_ID); + } + break; + + case KHUI_ACTION_LAYOUT_LOC: + { + 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_extents(tbl, FALSE); + + InvalidateRect(tbl->hwnd, NULL, TRUE); + + khui_check_radio_action(khui_find_menu(KHUI_MENU_LAYOUT), + KHUI_ACTION_LAYOUT_LOC); + } + break; + + case KHUI_PACTION_UP: + case KHUI_PACTION_UP_EXTEND: + case KHUI_PACTION_UP_TOGGLE: + { /* cursor up */ + khm_int32 new_row; + WPARAM wp; + + 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; + + 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; +#ifdef DEBUG + else + assert(FALSE); +#endif + + cw_select_row(tbl, new_row, wp); + } + break; + + case KHUI_PACTION_DOWN: + case KHUI_PACTION_DOWN_EXTEND: + case KHUI_PACTION_DOWN_TOGGLE: + { /* cursor down */ + khm_int32 new_row; + WPARAM wp; + + 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; + + 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; +#ifdef DEBUG + else + assert(FALSE); +#endif + cw_select_row(tbl, new_row, wp); + } + 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++; + + 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; + + row = y / tbl->cell_height; + + if(row < 0 || row >= (int) tbl->n_rows) + return FALSE; + + cw_set_row_context(tbl, row); + + 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(); + } + + 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 TRUE; + + case WM_PAINT: + 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_BACKGROUND + 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; + GetClientRect(parent, &r); + return CreateWindowEx( + 0, + MAKEINTATOM(khui_credwnd_cls), + L"", + WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL, + r.left, + r.top, + r.right - r.left, + r.bottom - r.top, + parent, + NULL, + khm_hInstance, + NULL); +} diff --git a/src/windows/identity/ui/credwnd.h b/src/windows/identity/ui/credwnd.h new file mode 100644 index 0000000000..66fc3d2fbc --- /dev/null +++ b/src/windows/identity/ui/credwnd.h @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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 0 +#define CW_EXPSTATE_WARN 1024 +#define CW_EXPSTATE_CRITICAL 2048 +#define CW_EXPSTATE_EXPIRED 3072 + +#define CW_EXPSTATE_MASK 3072 + +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 + +typedef struct khui_credwnd_row_t { + khm_int32 flags; + khm_int32 col; + khm_handle data; + khm_size idx_start; + khm_size idx_end; +} khui_credwnd_row; + +#define KHUI_CW_ROW_CRED 2 +#define KHUI_CW_ROW_HEADER 4 +#define KHUI_CW_ROW_TIMERSET 8 +#define KHUI_CW_ROW_SELECTED 16 + +/* 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 1 +#define KHUI_CW_COL_SORT_INC 2 +#define KHUI_CW_COL_SORT_DEC 4 +#define KHUI_CW_COL_GROUP 8 +#define KHUI_CW_COL_FIXED_WIDTH 16 +#define KHUI_CW_COL_FIXED_POS 32 +#define KHUI_CW_COL_META 64 + +/* 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 khui_credwnd_tbl_t { + HWND hwnd; /* the window that this table belongs to */ + + 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 */ + khm_size n_cols; + khm_size n_total_cols; /* number of columns actually + allocated in cols */ + khm_size n_rows; + khm_size n_total_rows; /* number of rows actually allocated + in rows */ + + khui_credwnd_outline * outline; + + khm_int32 flags; /* combo of KHUI_CW_TBL_* */ + + khm_int32 cursor_row; /* cursor and selection */ + khm_int32 anchor_row; /* anchor, for range selections */ + + /* 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 grey background brush */ + HBRUSH hb_sel; /* selected background brush */ + COLORREF cr_hdr_outline;/* header outline color */ + COLORREF cr_normal; /* normal text color */ + COLORREF cr_sel; /* selected text color */ + COLORREF cr_hdr_normal; /* normal header text color */ + COLORREF cr_hdr_sel; /* selected header text color */ + HBRUSH hb_hdr_bg; /* header background color (normal) */ + HBRUSH hb_hdr_bg_exp; /* header background color (expired) */ + HBRUSH hb_hdr_bg_warn; /* header background color (warn) */ + HBRUSH hb_hdr_bg_crit; /* header background color (critical) */ + HBRUSH hb_hdr_bg_sel; /* header background color (selected) */ + HCURSOR hc_hand; /* the HAND cursor */ + khui_ilist * ilist; /* image list */ + +#if 0 + /* icon indices */ + int idx_expand; /* index of 'expanded' icon in image list */ + int idx_expand_hi; /* index of 'expanded' icon (highlighted) in image list */ + int idx_collapse; /* index of 'collapsed' icon in image list */ + int idx_collapse_hi; /* index of 'collapsed' icon (highlighted) in image list */ + int idx_ident; /* index of 'identity' icon in image list */ +#endif + + /* 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_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 + +/* mouse_state constants */ +#define CW_MOUSE_NONE 0 /* nothing interesting */ +#define CW_MOUSE_OUTLINE 1 /* mouse is highlighting an outline widget */ +#define CW_MOUSE_LDOWN 2 /* left button is down */ +#define CW_MOUSE_ROW 4 /* mouse is acive over a valid row */ + +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); + +#endif diff --git a/src/windows/identity/ui/htmlwnd.h b/src/windows/identity/ui/htmlwnd.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/windows/identity/ui/htwnd.c b/src/windows/identity/ui/htwnd.c new file mode 100644 index 0000000000..9acbac704e --- /dev/null +++ b/src/windows/identity/ui/htwnd.c @@ -0,0 +1,1070 @@ +/* +* Copyright (c) 2004 Massachusetts Institute of Technology +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* $Id$ */ + +#include<khmapp.h> +#include<crtdbg.h> + +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_LEFT}, + {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; + 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; i<n; i++) { + if(!wcsnicmp(tbl[i].string, v, len)) + return tbl[i].value; + } + + return -1; +} + +static void clear_styles(khui_htwnd_data * d) +{ + int i; + + for(i=0; i<d->n_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; i<d->n_styles; i++) { + style = &(d->styles[i]); + + if(style->height == height && + style->variation == variation) + break; + } + + s->stack_top++; + + if(i<d->n_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: + +<a [id="string"] [param="paramstring"]>link text</a> +<b>foo</b> +<u>foo</u> + +<center>foo</center> +<left>foo</left> +<right>foo</right> + +<font [color="color"] [size="normal|large|huge"]>foo</font> +<large>foo</large> +<huge>foo</huge> + +<p [align="left|center|right"]>foo</p> +<settab pos=""> +<tab> +*/ + +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 = malloc(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 = malloc(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); + free(d->links); + d->links = ll; + d->max_links = n_new; + } + + l = d->links[d->n_links]; + if(!l) { + l = malloc(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; + + 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"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; + wchar_t * size_s = NULL; + int size_len; + 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; + + 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); + + if(d->flags & KHUI_HTWND_CLIENTEDGE) + DrawEdge(hdc, &r, EDGE_SUNKEN, BF_ADJUST | BF_RECT | BF_FLAT); + + hbk = CreateSolidBrush(RGB(255,255,255)); + FillRect(hdc, &r, hbk); + DeleteObject(hbk); + + /* 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 = d->scroll_top + r.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) + x += (r.right - r.left)/2 - p_width / 2; + else if(align == ALIGN_RIGHT) + x += (r.right - r.left) - p_width; + + /* begin wet run */ + p = par_start; + format_unwind(&s_stack, s_start); /* unwind format stack */ + + //MoveToEx(hdc, x, y + l_height, NULL); + + p_width = 0; + + while(*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,rt; + + 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 = x + p_width + s.cx; + rd.bottom = y + l_height; + + if(IntersectRect(&rt, &rd, &r)) { + DrawText(hdc, p, (int)(c - p), &rt, DT_BOTTOM | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX); + } + + p_width += s.cx; + + SelectFont(hdc, hfold); + p = c; + } + } + + y += l_height; + par_start = p; + } + + EndPaint(hwnd, &ps); + + 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 = malloc(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; + } + 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 = malloc(cbsize); + StringCbCopy(d->text, cbsize, cs->lpszName); + } + +#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) { + free(d->text); + d->text = NULL; + } + + if(SUCCEEDED(StringCbLength(newtext, KHUI_HTWND_MAXCB_TEXT, &cbsize))) { + cbsize += sizeof(wchar_t); + d->text = malloc(cbsize); + StringCbCopy(d->text, cbsize, newtext); + rv = TRUE; + } else + rv = FALSE; + + clear_styles(d); + + 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) + free(d->text); + d->text = 0; + + if(d->links) { + for(i=0;i<d->max_links;i++) { + if(d->links[i]) + free(d->links[i]); + } + free(d->links); + } + + clear_styles(d); + + free(d); + } + break; + + case WM_ERASEBKGND: + { + khui_htwnd_data * d; + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + if(d->flags & KHUI_HTWND_TRANSPARENT) + return TRUE; + + return FALSE; + } + + case WM_PAINT: + htw_paint(hwnd, uMsg, wParam, lParam); + break; + + 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_MOUSEMOVE: + { + khui_htwnd_data * d; + int i; + POINT p; + int nl; + + p.x = GET_X_LPARAM(lParam); + p.y = GET_Y_LPARAM(lParam); + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + for(i=0; i<d->n_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) { + InvalidateRect(parent, NULL, 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) { + InvalidateRect(parent, NULL, 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((LPWSTR) 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, + (LPWSTR) 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 new file mode 100644 index 0000000000..9e74788038 --- /dev/null +++ b/src/windows/identity/ui/htwnd.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_HTWND_H +#define __KHIMAIRA_HTWND_H + +#include<khuidefs.h> + +/* +We currently support the following tags: + +<a [id="string"] [param="paramstring"]>link text</a> +<center>foo</center> +<left>foo</left> +<right>foo</right> +*/ + +#define KHUI_HTWND_TRANSPARENT 1 +#define KHUI_HTWND_CLIENTEDGE 2 +#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/images/Thumbs.db b/src/windows/identity/ui/images/Thumbs.db new file mode 100644 index 0000000000..a80265f867 Binary files /dev/null and b/src/windows/identity/ui/images/Thumbs.db differ diff --git a/src/windows/identity/ui/images/app_notify_error.ico b/src/windows/identity/ui/images/app_notify_error.ico new file mode 100644 index 0000000000..8dcb29e7a6 Binary files /dev/null and b/src/windows/identity/ui/images/app_notify_error.ico differ diff --git a/src/windows/identity/ui/images/app_notify_info.ico b/src/windows/identity/ui/images/app_notify_info.ico new file mode 100644 index 0000000000..8dcb29e7a6 Binary files /dev/null and b/src/windows/identity/ui/images/app_notify_info.ico differ diff --git a/src/windows/identity/ui/images/app_notify_none.ico b/src/windows/identity/ui/images/app_notify_none.ico new file mode 100644 index 0000000000..8dcb29e7a6 Binary files /dev/null and b/src/windows/identity/ui/images/app_notify_none.ico differ diff --git a/src/windows/identity/ui/images/app_notify_warn.ico b/src/windows/identity/ui/images/app_notify_warn.ico new file mode 100644 index 0000000000..8dcb29e7a6 Binary files /dev/null and b/src/windows/identity/ui/images/app_notify_warn.ico differ diff --git a/src/windows/identity/ui/images/bitmap1.bmp b/src/windows/identity/ui/images/bitmap1.bmp new file mode 100644 index 0000000000..1f07309b90 Binary files /dev/null and b/src/windows/identity/ui/images/bitmap1.bmp differ diff --git a/src/windows/identity/ui/images/cfg_applied.ico b/src/windows/identity/ui/images/cfg_applied.ico new file mode 100644 index 0000000000..4fcdf843c8 Binary files /dev/null and b/src/windows/identity/ui/images/cfg_applied.ico differ diff --git a/src/windows/identity/ui/images/cfg_default.ico b/src/windows/identity/ui/images/cfg_default.ico new file mode 100644 index 0000000000..d6e7f24e0d Binary files /dev/null and b/src/windows/identity/ui/images/cfg_default.ico differ diff --git a/src/windows/identity/ui/images/cfg_deleted.ico b/src/windows/identity/ui/images/cfg_deleted.ico new file mode 100644 index 0000000000..2ef11c7d11 Binary files /dev/null and b/src/windows/identity/ui/images/cfg_deleted.ico differ diff --git a/src/windows/identity/ui/images/cfg_mod.ico b/src/windows/identity/ui/images/cfg_mod.ico new file mode 100644 index 0000000000..65e3691ffe Binary files /dev/null and b/src/windows/identity/ui/images/cfg_mod.ico differ diff --git a/src/windows/identity/ui/images/chpw-dis-sm.bmp b/src/windows/identity/ui/images/chpw-dis-sm.bmp new file mode 100644 index 0000000000..230ad36a40 Binary files /dev/null and b/src/windows/identity/ui/images/chpw-dis-sm.bmp differ diff --git a/src/windows/identity/ui/images/chpw-dis.bmp b/src/windows/identity/ui/images/chpw-dis.bmp new file mode 100644 index 0000000000..43468cb2a9 Binary files /dev/null and b/src/windows/identity/ui/images/chpw-dis.bmp differ diff --git a/src/windows/identity/ui/images/chpw-sm.bmp b/src/windows/identity/ui/images/chpw-sm.bmp new file mode 100644 index 0000000000..309a9178dc Binary files /dev/null and b/src/windows/identity/ui/images/chpw-sm.bmp differ diff --git a/src/windows/identity/ui/images/chpw.bmp b/src/windows/identity/ui/images/chpw.bmp new file mode 100644 index 0000000000..688da40df3 Binary files /dev/null and b/src/windows/identity/ui/images/chpw.bmp differ diff --git a/src/windows/identity/ui/images/disabled.ico b/src/windows/identity/ui/images/disabled.ico new file mode 100644 index 0000000000..6b6a9078c1 Binary files /dev/null and b/src/windows/identity/ui/images/disabled.ico differ diff --git a/src/windows/identity/ui/images/enabled.ico b/src/windows/identity/ui/images/enabled.ico new file mode 100644 index 0000000000..22821a8b78 Binary files /dev/null and b/src/windows/identity/ui/images/enabled.ico differ diff --git a/src/windows/identity/ui/images/flag-critical.bmp b/src/windows/identity/ui/images/flag-critical.bmp new file mode 100644 index 0000000000..0b4c920e61 Binary files /dev/null and b/src/windows/identity/ui/images/flag-critical.bmp differ diff --git a/src/windows/identity/ui/images/flag-warning.bmp b/src/windows/identity/ui/images/flag-warning.bmp new file mode 100644 index 0000000000..f5be298a83 Binary files /dev/null and b/src/windows/identity/ui/images/flag-warning.bmp differ diff --git a/src/windows/identity/ui/images/flag_expired.bmp b/src/windows/identity/ui/images/flag_expired.bmp new file mode 100644 index 0000000000..2815fb4486 Binary files /dev/null and b/src/windows/identity/ui/images/flag_expired.bmp differ diff --git a/src/windows/identity/ui/images/help-sm.bmp b/src/windows/identity/ui/images/help-sm.bmp new file mode 100644 index 0000000000..49e560fb46 Binary files /dev/null and b/src/windows/identity/ui/images/help-sm.bmp differ diff --git a/src/windows/identity/ui/images/help.bmp b/src/windows/identity/ui/images/help.bmp new file mode 100644 index 0000000000..d7d4eafacc Binary files /dev/null and b/src/windows/identity/ui/images/help.bmp differ diff --git a/src/windows/identity/ui/images/icon1.ico b/src/windows/identity/ui/images/icon1.ico new file mode 100644 index 0000000000..c2746b065c Binary files /dev/null and b/src/windows/identity/ui/images/icon1.ico differ diff --git a/src/windows/identity/ui/images/id-delete-dis-sm.bmp b/src/windows/identity/ui/images/id-delete-dis-sm.bmp new file mode 100644 index 0000000000..68850ab879 Binary files /dev/null and b/src/windows/identity/ui/images/id-delete-dis-sm.bmp differ diff --git a/src/windows/identity/ui/images/id-delete-dis.bmp b/src/windows/identity/ui/images/id-delete-dis.bmp new file mode 100644 index 0000000000..11aedd5775 Binary files /dev/null and b/src/windows/identity/ui/images/id-delete-dis.bmp differ diff --git a/src/windows/identity/ui/images/id-delete-sm.bmp b/src/windows/identity/ui/images/id-delete-sm.bmp new file mode 100644 index 0000000000..3447d57a1e Binary files /dev/null and b/src/windows/identity/ui/images/id-delete-sm.bmp differ diff --git a/src/windows/identity/ui/images/id-delete.bmp b/src/windows/identity/ui/images/id-delete.bmp new file mode 100644 index 0000000000..5b1b680300 Binary files /dev/null and b/src/windows/identity/ui/images/id-delete.bmp differ diff --git a/src/windows/identity/ui/images/id-dis-sm.bmp b/src/windows/identity/ui/images/id-dis-sm.bmp new file mode 100644 index 0000000000..ff0c38e4d1 Binary files /dev/null and b/src/windows/identity/ui/images/id-dis-sm.bmp differ diff --git a/src/windows/identity/ui/images/id-dis.bmp b/src/windows/identity/ui/images/id-dis.bmp new file mode 100644 index 0000000000..3c04aa2fa9 Binary files /dev/null and b/src/windows/identity/ui/images/id-dis.bmp differ diff --git a/src/windows/identity/ui/images/id-new-dis-sm.bmp b/src/windows/identity/ui/images/id-new-dis-sm.bmp new file mode 100644 index 0000000000..d2a151c373 Binary files /dev/null and b/src/windows/identity/ui/images/id-new-dis-sm.bmp differ diff --git a/src/windows/identity/ui/images/id-new-dis.bmp b/src/windows/identity/ui/images/id-new-dis.bmp new file mode 100644 index 0000000000..61c2fd21ab Binary files /dev/null and b/src/windows/identity/ui/images/id-new-dis.bmp differ diff --git a/src/windows/identity/ui/images/id-new-sm.bmp b/src/windows/identity/ui/images/id-new-sm.bmp new file mode 100644 index 0000000000..9fb17b98c3 Binary files /dev/null and b/src/windows/identity/ui/images/id-new-sm.bmp differ diff --git a/src/windows/identity/ui/images/id-new.bmp b/src/windows/identity/ui/images/id-new.bmp new file mode 100644 index 0000000000..54830c1830 Binary files /dev/null and b/src/windows/identity/ui/images/id-new.bmp differ diff --git a/src/windows/identity/ui/images/id-refresh-dis.bmp b/src/windows/identity/ui/images/id-refresh-dis.bmp new file mode 100644 index 0000000000..7d79343691 Binary files /dev/null and b/src/windows/identity/ui/images/id-refresh-dis.bmp differ diff --git a/src/windows/identity/ui/images/id-refresh-sm-dis.bmp b/src/windows/identity/ui/images/id-refresh-sm-dis.bmp new file mode 100644 index 0000000000..c9d9addf15 Binary files /dev/null and b/src/windows/identity/ui/images/id-refresh-sm-dis.bmp differ diff --git a/src/windows/identity/ui/images/id-refresh-sm.bmp b/src/windows/identity/ui/images/id-refresh-sm.bmp new file mode 100644 index 0000000000..11d1893b4a Binary files /dev/null and b/src/windows/identity/ui/images/id-refresh-sm.bmp differ diff --git a/src/windows/identity/ui/images/id-refresh.bmp b/src/windows/identity/ui/images/id-refresh.bmp new file mode 100644 index 0000000000..6357fde4f1 Binary files /dev/null and b/src/windows/identity/ui/images/id-refresh.bmp differ diff --git a/src/windows/identity/ui/images/id-sm.bmp b/src/windows/identity/ui/images/id-sm.bmp new file mode 100644 index 0000000000..e507a62d5d Binary files /dev/null and b/src/windows/identity/ui/images/id-sm.bmp differ diff --git a/src/windows/identity/ui/images/id.bmp b/src/windows/identity/ui/images/id.bmp new file mode 100644 index 0000000000..72a93c6a94 Binary files /dev/null and b/src/windows/identity/ui/images/id.bmp differ diff --git a/src/windows/identity/ui/images/id.ico b/src/windows/identity/ui/images/id.ico new file mode 100644 index 0000000000..1f0f676ffd Binary files /dev/null and b/src/windows/identity/ui/images/id.ico differ diff --git a/src/windows/identity/ui/images/ident.png b/src/windows/identity/ui/images/ident.png new file mode 100644 index 0000000000..904f0239bc Binary files /dev/null and b/src/windows/identity/ui/images/ident.png differ diff --git a/src/windows/identity/ui/images/import-dis.bmp b/src/windows/identity/ui/images/import-dis.bmp new file mode 100644 index 0000000000..4257a1ad9e Binary files /dev/null and b/src/windows/identity/ui/images/import-dis.bmp differ diff --git a/src/windows/identity/ui/images/import-sm-dis.bmp b/src/windows/identity/ui/images/import-sm-dis.bmp new file mode 100644 index 0000000000..b9398c3849 Binary files /dev/null and b/src/windows/identity/ui/images/import-sm-dis.bmp differ diff --git a/src/windows/identity/ui/images/import-sm.bmp b/src/windows/identity/ui/images/import-sm.bmp new file mode 100644 index 0000000000..0c9916877c Binary files /dev/null and b/src/windows/identity/ui/images/import-sm.bmp differ diff --git a/src/windows/identity/ui/images/import.bmp b/src/windows/identity/ui/images/import.bmp new file mode 100644 index 0000000000..6a428c979e Binary files /dev/null and b/src/windows/identity/ui/images/import.bmp differ diff --git a/src/windows/identity/ui/images/khimaira-cfg.bmp b/src/windows/identity/ui/images/khimaira-cfg.bmp new file mode 100644 index 0000000000..d20b9eb3d8 Binary files /dev/null and b/src/windows/identity/ui/images/khimaira-cfg.bmp differ diff --git a/src/windows/identity/ui/images/logo_shade.bmp b/src/windows/identity/ui/images/logo_shade.bmp new file mode 100644 index 0000000000..2e36b9bf20 Binary files /dev/null and b/src/windows/identity/ui/images/logo_shade.bmp differ diff --git a/src/windows/identity/ui/images/main_app.ico b/src/windows/identity/ui/images/main_app.ico new file mode 100644 index 0000000000..8dcb29e7a6 Binary files /dev/null and b/src/windows/identity/ui/images/main_app.ico differ diff --git a/src/windows/identity/ui/images/main_app_old.ico b/src/windows/identity/ui/images/main_app_old.ico new file mode 100644 index 0000000000..e3222e7fdd Binary files /dev/null and b/src/windows/identity/ui/images/main_app_old.ico differ diff --git a/src/windows/identity/ui/images/tb-blank-small.bmp b/src/windows/identity/ui/images/tb-blank-small.bmp new file mode 100644 index 0000000000..0718d128bf Binary files /dev/null and b/src/windows/identity/ui/images/tb-blank-small.bmp differ diff --git a/src/windows/identity/ui/images/tb-blank.bmp b/src/windows/identity/ui/images/tb-blank.bmp new file mode 100644 index 0000000000..01adca9e3d Binary files /dev/null and b/src/windows/identity/ui/images/tb-blank.bmp differ diff --git a/src/windows/identity/ui/images/tb-space.bmp b/src/windows/identity/ui/images/tb-space.bmp new file mode 100644 index 0000000000..d85cc5cd74 Binary files /dev/null and b/src/windows/identity/ui/images/tb-space.bmp differ diff --git a/src/windows/identity/ui/images/text1138.png b/src/windows/identity/ui/images/text1138.png new file mode 100644 index 0000000000..cf5ee376c3 Binary files /dev/null and b/src/windows/identity/ui/images/text1138.png differ diff --git a/src/windows/identity/ui/images/tk-delete-dis-sm.bmp b/src/windows/identity/ui/images/tk-delete-dis-sm.bmp new file mode 100644 index 0000000000..00adcf4436 Binary files /dev/null and b/src/windows/identity/ui/images/tk-delete-dis-sm.bmp differ diff --git a/src/windows/identity/ui/images/tk-delete-dis.bmp b/src/windows/identity/ui/images/tk-delete-dis.bmp new file mode 100644 index 0000000000..844fb23a64 Binary files /dev/null and b/src/windows/identity/ui/images/tk-delete-dis.bmp differ diff --git a/src/windows/identity/ui/images/tk-delete-sm.bmp b/src/windows/identity/ui/images/tk-delete-sm.bmp new file mode 100644 index 0000000000..0ac2d6a8e9 Binary files /dev/null and b/src/windows/identity/ui/images/tk-delete-sm.bmp differ diff --git a/src/windows/identity/ui/images/tk-delete.bmp b/src/windows/identity/ui/images/tk-delete.bmp new file mode 100644 index 0000000000..501ff6e241 Binary files /dev/null and b/src/windows/identity/ui/images/tk-delete.bmp differ diff --git a/src/windows/identity/ui/images/tk-dis-sm.bmp b/src/windows/identity/ui/images/tk-dis-sm.bmp new file mode 100644 index 0000000000..9100d9a9c7 Binary files /dev/null and b/src/windows/identity/ui/images/tk-dis-sm.bmp differ diff --git a/src/windows/identity/ui/images/tk-dis.bmp b/src/windows/identity/ui/images/tk-dis.bmp new file mode 100644 index 0000000000..558ba90644 Binary files /dev/null and b/src/windows/identity/ui/images/tk-dis.bmp differ diff --git a/src/windows/identity/ui/images/tk-new-dis-sm.bmp b/src/windows/identity/ui/images/tk-new-dis-sm.bmp new file mode 100644 index 0000000000..d2e1fcdc4e Binary files /dev/null and b/src/windows/identity/ui/images/tk-new-dis-sm.bmp differ diff --git a/src/windows/identity/ui/images/tk-new-dis.bmp b/src/windows/identity/ui/images/tk-new-dis.bmp new file mode 100644 index 0000000000..c6abc4ec57 Binary files /dev/null and b/src/windows/identity/ui/images/tk-new-dis.bmp differ diff --git a/src/windows/identity/ui/images/tk-new-sm.bmp b/src/windows/identity/ui/images/tk-new-sm.bmp new file mode 100644 index 0000000000..f2bf279539 Binary files /dev/null and b/src/windows/identity/ui/images/tk-new-sm.bmp differ diff --git a/src/windows/identity/ui/images/tk-new.bmp b/src/windows/identity/ui/images/tk-new.bmp new file mode 100644 index 0000000000..e0e7bc0d65 Binary files /dev/null and b/src/windows/identity/ui/images/tk-new.bmp differ diff --git a/src/windows/identity/ui/images/tk-refresh-dis-sm.bmp b/src/windows/identity/ui/images/tk-refresh-dis-sm.bmp new file mode 100644 index 0000000000..2745af1510 Binary files /dev/null and b/src/windows/identity/ui/images/tk-refresh-dis-sm.bmp differ diff --git a/src/windows/identity/ui/images/tk-refresh-dis.bmp b/src/windows/identity/ui/images/tk-refresh-dis.bmp new file mode 100644 index 0000000000..45f8099b92 Binary files /dev/null and b/src/windows/identity/ui/images/tk-refresh-dis.bmp differ diff --git a/src/windows/identity/ui/images/tk-refresh-sm.bmp b/src/windows/identity/ui/images/tk-refresh-sm.bmp new file mode 100644 index 0000000000..acf33618d2 Binary files /dev/null and b/src/windows/identity/ui/images/tk-refresh-sm.bmp differ diff --git a/src/windows/identity/ui/images/tk-refresh.bmp b/src/windows/identity/ui/images/tk-refresh.bmp new file mode 100644 index 0000000000..6e39f87748 Binary files /dev/null and b/src/windows/identity/ui/images/tk-refresh.bmp differ diff --git a/src/windows/identity/ui/images/tk-sm.bmp b/src/windows/identity/ui/images/tk-sm.bmp new file mode 100644 index 0000000000..c89285c610 Binary files /dev/null and b/src/windows/identity/ui/images/tk-sm.bmp differ diff --git a/src/windows/identity/ui/images/tk.bmp b/src/windows/identity/ui/images/tk.bmp new file mode 100644 index 0000000000..e689cb830b Binary files /dev/null and b/src/windows/identity/ui/images/tk.bmp differ diff --git a/src/windows/identity/ui/images/vw-refresh-sm.bmp b/src/windows/identity/ui/images/vw-refresh-sm.bmp new file mode 100644 index 0000000000..aabd10ef57 Binary files /dev/null and b/src/windows/identity/ui/images/vw-refresh-sm.bmp differ diff --git a/src/windows/identity/ui/images/vw-refresh.bmp b/src/windows/identity/ui/images/vw-refresh.bmp new file mode 100644 index 0000000000..76b68ddf75 Binary files /dev/null and b/src/windows/identity/ui/images/vw-refresh.bmp differ diff --git a/src/windows/identity/ui/images/wdg_collapsed.bmp b/src/windows/identity/ui/images/wdg_collapsed.bmp new file mode 100644 index 0000000000..f4d82977ca Binary files /dev/null and b/src/windows/identity/ui/images/wdg_collapsed.bmp differ diff --git a/src/windows/identity/ui/images/wdg_collapsed_hi.bmp b/src/windows/identity/ui/images/wdg_collapsed_hi.bmp new file mode 100644 index 0000000000..90ab26d679 Binary files /dev/null and b/src/windows/identity/ui/images/wdg_collapsed_hi.bmp differ diff --git a/src/windows/identity/ui/images/wdg_credtype.bmp b/src/windows/identity/ui/images/wdg_credtype.bmp new file mode 100644 index 0000000000..3bac3fe535 Binary files /dev/null and b/src/windows/identity/ui/images/wdg_credtype.bmp differ diff --git a/src/windows/identity/ui/images/wdg_expanded.bmp b/src/windows/identity/ui/images/wdg_expanded.bmp new file mode 100644 index 0000000000..c590722309 Binary files /dev/null and b/src/windows/identity/ui/images/wdg_expanded.bmp differ diff --git a/src/windows/identity/ui/images/wdg_expanded_hi.bmp b/src/windows/identity/ui/images/wdg_expanded_hi.bmp new file mode 100644 index 0000000000..6b2affc6df Binary files /dev/null and b/src/windows/identity/ui/images/wdg_expanded_hi.bmp differ diff --git a/src/windows/identity/ui/images/wdg_flag.bmp b/src/windows/identity/ui/images/wdg_flag.bmp new file mode 100644 index 0000000000..c563c56e9f Binary files /dev/null and b/src/windows/identity/ui/images/wdg_flag.bmp differ diff --git a/src/windows/identity/ui/images/wgt_arrow_collapse.ico b/src/windows/identity/ui/images/wgt_arrow_collapse.ico new file mode 100644 index 0000000000..b248bd9d6c Binary files /dev/null and b/src/windows/identity/ui/images/wgt_arrow_collapse.ico differ diff --git a/src/windows/identity/ui/images/wgt_arrow_expand.ico b/src/windows/identity/ui/images/wgt_arrow_expand.ico new file mode 100644 index 0000000000..485b537b03 Binary files /dev/null and b/src/windows/identity/ui/images/wgt_arrow_expand.ico differ diff --git a/src/windows/identity/ui/khmapp.h b/src/windows/identity/ui/khmapp.h new file mode 100644 index 0000000000..bd53bde28c --- /dev/null +++ b/src/windows/identity/ui/khmapp.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KHIMAIRA_H +#define __KHIMAIRA_KHIMAIRA_H + +#include<windows.h> +#include<windowsx.h> +#include<strsafe.h> +#include<commctrl.h> + +#define KHERR_HMODULE khm_hInstance +#define KHERR_FACILITY khm_facility +#define KHERR_FACILITY_ID 3 + +#include<khdefs.h> +#include<khlist.h> +#include<kherror.h> +#include<kconfig.h> +#include<kcreddb.h> +#include<kmq.h> +#include<khmsgtypes.h> +#include<kmm.h> +#include<khhelp.h> +#include<khuidefs.h> + +#include<resource.h> +#include<credfuncs.h> +#include<appglobal.h> +#include<mainwnd.h> +#include<mainmenu.h> +#include<toolbar.h> +#include<statusbar.h> +#include<credwnd.h> +#include<htwnd.h> +#include<passwnd.h> +#include<newcredwnd.h> +#include<propertywnd.h> +#include<configwnd.h> +#include<aboutwnd.h> + +#include<reqdaemon.h> +#include<notifier.h> +#include<timer.h> + +#endif diff --git a/src/windows/identity/ui/lang/en_us/khapp.rc b/src/windows/identity/ui/lang/en_us/khapp.rc new file mode 100644 index 0000000000..a1b03b411c --- /dev/null +++ b/src/windows/identity/ui/lang/en_us/khapp.rc @@ -0,0 +1,728 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\..\resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" +#include <khimaira_version.h> +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\..\\resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "#include <khimaira_version.h>\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_MAIN_APP ICON "..\\..\\images\\main_app.ico" +IDI_WGT_COLLAPSE ICON "..\\..\\images\\wgt_arrow_collapse.ico" +IDI_WGT_EXPAND ICON "..\\..\\images\\wgt_arrow_expand.ico" +IDI_ENABLED ICON "..\\..\\images\\enabled.ico" +IDI_DISABLED ICON "..\\..\\images\\disabled.ico" +IDI_NOTIFY_NONE ICON "..\\..\\images\\app_notify_none.ico" +IDI_NOTIFY_INFO ICON "..\\..\\images\\app_notify_info.ico" +IDI_NOTIFY_WARN ICON "..\\..\\images\\app_notify_warn.ico" +IDI_NOTIFY_ERROR ICON "..\\..\\images\\app_notify_error.ico" +IDI_CFG_DEFAULT ICON "..\\..\\images\\cfg_default.ico" +IDI_CFG_MODIFIED ICON "..\\..\\images\\cfg_mod.ico" +IDI_CFG_APPLIED ICON "..\\..\\images\\cfg_applied.ico" +IDI_CFG_DELETED ICON "..\\..\\images\\cfg_deleted.ico" +IDI_ID ICON "..\\..\\images\\id.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,1,1,0 + PRODUCTVERSION 0,1,1,0 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x0L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Massachusetts Institute of Technology" + VALUE "FileDescription", "Network Identity Manager" + VALUE "FileVersion", "0.1.1.0" + VALUE "InternalName", "NetIDMgr" + VALUE "LegalCopyright", "Copyright (C) 2005 Massachusetts Institute of Technology" + VALUE "OriginalFilename", "netidmgr.exe" + VALUE "ProductName", "NetIDMgr" + VALUE "ProductVersion", "0.1.1.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_TK_REFRESH BITMAP "..\\..\\images\\tk-refresh.bmp" +IDB_ID BITMAP "..\\..\\images\\id.bmp" +IDB_ID_DELETE BITMAP "..\\..\\images\\id-delete.bmp" +IDB_ID_NEW BITMAP "..\\..\\images\\id-new.bmp" +IDB_ID_REFRESH BITMAP "..\\..\\images\\id-refresh.bmp" +IDB_TK BITMAP "..\\..\\images\\tk.bmp" +IDB_TK_DELETE BITMAP "..\\..\\images\\tk-delete.bmp" +IDB_TK_NEW BITMAP "..\\..\\images\\tk-new.bmp" +IDB_VW_REFRESH_SM BITMAP "..\\..\\images\\vw-refresh-sm.bmp" +IDB_TB_BLANK BITMAP "..\\..\\images\\tb-blank.bmp" +IDB_TB_BLANK_SM BITMAP "..\\..\\images\\tb-blank-small.bmp" +IDB_VW_REFRESH BITMAP "..\\..\\images\\vw-refresh.bmp" +IDB_ID_DELETE_DIS BITMAP "..\\..\\images\\id-delete-dis.bmp" +IDB_ID_DELETE_DIS_SM BITMAP "..\\..\\images\\id-delete-dis-sm.bmp" +IDB_ID_DELETE_SM BITMAP "..\\..\\images\\id-delete-sm.bmp" +IDB_ID_DIS BITMAP "..\\..\\images\\id-dis.bmp" +IDB_ID_DIS_SM BITMAP "..\\..\\images\\id-dis-sm.bmp" +IDB_ID_NEW_DIS BITMAP "..\\..\\images\\id-new-dis.bmp" +IDB_ID_NEW_DIS_SM BITMAP "..\\..\\images\\id-new-dis-sm.bmp" +IDB_ID_NEW_SM BITMAP "..\\..\\images\\id-new-sm.bmp" +IDB_ID_REFRESH_DIS BITMAP "..\\..\\images\\id-refresh-dis.bmp" +IDB_ID_REFRESH_SM BITMAP "..\\..\\images\\id-refresh-sm.bmp" +IDB_ID_REFRESH_DIS_SM BITMAP "..\\..\\images\\id-refresh-sm-dis.bmp" +IDB_TK_DELETE_DIS BITMAP "..\\..\\images\\tk-delete-dis.bmp" +IDB_TK_DELETE_DIS_SM BITMAP "..\\..\\images\\tk-delete-dis-sm.bmp" +IDB_TK_DELETE_SM BITMAP "..\\..\\images\\tk-delete-sm.bmp" +IDB_TK_DIS_SM BITMAP "..\\..\\images\\tk-dis-sm.bmp" +IDB_TK_NEW_DIS BITMAP "..\\..\\images\\tk-new-dis.bmp" +IDB_TK_NEW_DIS_SM BITMAP "..\\..\\images\\tk-new-dis-sm.bmp" +IDB_TK_NEW_SM BITMAP "..\\..\\images\\tk-new-sm.bmp" +IDB_TK_REFRESH_DIS BITMAP "..\\..\\images\\tk-refresh-dis.bmp" +IDB_TK_REFRESH_DIS_SM BITMAP "..\\..\\images\\tk-refresh-dis-sm.bmp" +IDB_TK_REFRESH_SM BITMAP "..\\..\\images\\tk-refresh-sm.bmp" +IDB_TK_SM BITMAP "..\\..\\images\\tk-sm.bmp" +IDB_HELP_SM BITMAP "..\\..\\images\\help-sm.bmp" +IDB_HELP BITMAP "..\\..\\images\\help.bmp" +IDB_LOGO_SHADE BITMAP "..\\..\\images\\logo_shade.bmp" +IDB_WDG_EXPAND BITMAP "..\\..\\images\\wdg_expanded.bmp" +IDB_WDG_COLLAPSE BITMAP "..\\..\\images\\wdg_collapsed.bmp" +IDB_ID_SM BITMAP "..\\..\\images\\id-sm.bmp" +IDB_WDG_EXPAND_HI BITMAP "..\\..\\images\\wdg_expanded_hi.bmp" +IDB_WDG_COLLAPSE_HI BITMAP "..\\..\\images\\wdg_collapsed_hi.bmp" +IDB_WDG_CREDTYPE BITMAP "..\\..\\images\\wdg_credtype.bmp" +IDB_WDG_FLAG BITMAP "..\\..\\images\\wdg_flag.bmp" +IDB_FLAG_WARN BITMAP "..\\..\\images\\flag-warning.bmp" +IDB_FLAG_EXPIRED BITMAP "..\\..\\images\\flag_expired.bmp" +IDB_FLAG_CRITICAL BITMAP "..\\..\\images\\flag-critical.bmp" +IDB_LOGO_OPAQUE BITMAP "..\\..\\images\\khimaira-cfg.bmp" +IDB_IMPORT_SM_DIS BITMAP "..\\..\\images\\import-sm-dis.bmp" +IDB_IMPORT BITMAP "..\\..\\images\\import.bmp" +IDB_IMPORT_DIS BITMAP "..\\..\\images\\import-dis.bmp" +IDB_IMPORT_SM BITMAP "..\\..\\images\\import-sm.bmp" +IDB_CHPW_SM BITMAP "..\\..\\images\\chpw-sm.bmp" +IDB_CHPW BITMAP "..\\..\\images\\chpw.bmp" +IDB_CHPW_DIS BITMAP "..\\..\\images\\chpw-dis.bmp" +IDB_CHPW_DIS_SM BITMAP "..\\..\\images\\chpw-dis-sm.bmp" +IDB_TB_SPACE BITMAP "..\\..\\images\\tb-space.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_MENU_BAR ACCELERATORS +BEGIN + VK_F10, IDA_ACTIVATE_MENU, VIRTKEY, NOINVERT + VK_UP, IDA_UP, VIRTKEY, NOINVERT + VK_DOWN, IDA_DOWN, VIRTKEY, NOINVERT + VK_LEFT, IDA_LEFT, VIRTKEY, NOINVERT + VK_RIGHT, IDA_RIGHT, VIRTKEY, NOINVERT + VK_ESCAPE, IDA_ESC, VIRTKEY, NOINVERT + VK_EXECUTE, IDA_ENTER, VIRTKEY, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_NC_NEWCRED DIALOGEX 0, 0, 301, 167 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "UI Row2",IDC_NC_TPL_ROW_LG,7,31,287,18,NOT WS_VISIBLE | + WS_BORDER + LTEXT "TplPanel",IDC_NC_TPL_PANEL,7,7,287,153,NOT WS_VISIBLE | + WS_BORDER + LTEXT "UI Row",IDC_NC_TPL_ROW,7,7,287,18,NOT WS_VISIBLE | + WS_BORDER + LTEXT "TplLabel",IDC_NC_TPL_LABEL,7,8,45,10,NOT WS_VISIBLE | + WS_BORDER + LTEXT "TplInput",IDC_NC_TPL_INPUT,54,7,240,13,NOT WS_VISIBLE | + WS_BORDER + LTEXT "TplLabelLg",IDC_NC_TPL_LABEL_LG,7,33,146,10,NOT + WS_VISIBLE | WS_BORDER + LTEXT "TplInputLg",IDC_NC_TPL_INPUT_LG,155,31,139,13,NOT + WS_VISIBLE | WS_BORDER + LTEXT "&Credentials",IDC_NC_CREDTEXT_LABEL,7,66,41,10,NOT + WS_GROUP + CONTROL "",IDC_NC_CREDTEXT,"KhmHtWnd",WS_TABSTOP,54,65,240,73, + WS_EX_CLIENTEDGE + PUSHBUTTON "&Ok",IDOK,57,142,89,18,WS_DISABLED + PUSHBUTTON "&Cancel",IDCANCEL,158,142,54,18 + PUSHBUTTON "&Options >>",IDC_NC_OPTIONS,223,142,71,18 +END + +IDD_NC_BBAR DIALOGEX 0, 0, 60, 181 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "&Ok",IDOK,0,7,53,41,WS_DISABLED + PUSHBUTTON "&Cancel",IDCANCEL,0,58,53,19 + PUSHBUTTON "&Help",IDC_NC_HELP,0,155,53,19 +END + +IDD_NC_TS DIALOGEX 0, 0, 300, 15 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN +END + +IDD_PP_IDENT DIALOGEX 0, 0, 235, 156 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_CAPTION +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Identity" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "Name",IDC_STATIC,7,8,19,12 + LTEXT "IdentityName",IDC_PP_IDNAME,34,7,194,12,NOT WS_GROUP, + WS_EX_CLIENTEDGE + CONTROL "Default identity",IDC_PP_IDDEF,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,34,25,71,12 + CONTROL "Searchable",IDC_PP_IDSEARCH,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,34,43,74,12 + CONTROL "Custom1",IDC_PP_PROPLIST,"NetIDMgrPropertyWnd", + WS_TABSTOP,7,61,221,88 + CONTROL "Always visible (sticky)",IDC_PP_STICKY,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,117,25,85,10 +END + +IDD_PP_CRED DIALOGEX 0, 0, 236, 158 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_CAPTION +CAPTION "Credential" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + CONTROL "Check1",IDC_PP_DUMMY,"Button",BS_AUTOCHECKBOX | NOT + WS_VISIBLE | WS_TABSTOP,0,1,39,10 + CONTROL "Custom1",IDC_PP_CPROPLIST,"NetIDMgrPropertyWnd", + WS_TABSTOP,7,7,222,144 +END + +IDD_CFG_MAIN DIALOGEX 0, 0, 357, 222 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +EXSTYLE WS_EX_CONTEXTHELP +CAPTION "Khimaira Configuration" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Title",IDC_CFG_TITLE,0,0,357,20,SS_CENTERIMAGE + CONTROL "",IDC_CFG_NODELIST,"SysTreeView32",TVS_HASBUTTONS | + TVS_HASLINES | TVS_LINESATROOT | WS_TABSTOP,0,20,100,182 + LTEXT "Static",IDC_CFG_PANE,102,20,255,182,NOT WS_VISIBLE | + WS_BORDER + PUSHBUTTON "&Ok",IDOK,162,205,78,16 + PUSHBUTTON "&Cancel",IDCANCEL,246,205,51,16 + PUSHBUTTON "&Apply",IDAPPLY,303,205,51,16,WS_DISABLED + PUSHBUTTON "C&hange Summary ...",IDC_CFG_SUMMARY,3,205,76,16, + WS_DISABLED +END + +IDD_CFG_GENERIC DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CTEXT "Please select one of the configuration categories on the left.", + IDC_STATIC,21,17,212,18,SS_CENTERIMAGE,WS_EX_TRANSPARENT +END + +IDD_CFG_GENERAL DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Startup",IDC_CFG_STARTUP_GROUP,7,7,241,50 + CONTROL "&Prompt for new credentials if there aren't any at startup", + IDC_CFG_AUTOINIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 16,22,196,10 + CONTROL "&Start NetIDMgr when Windows starts",IDC_CFG_AUTOSTART, + "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,16, + 38,135,10 + GROUPBOX "Other",IDC_CFG_OTHER,7,63,241,70 + CONTROL "&Keep NetIDMgr running after closing window", + IDC_CFG_KEEPRUNNING,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,16,78,158,10 + CONTROL "Detect network connectivity",IDC_CFG_NETDETECT,"Button", + BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,16,96,106,10 + CONTROL "A&utomatically import credentials from Windows", + IDC_CFG_AUTOIMPORT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 16,113,165,10 +END + +IDD_CFG_IDENTITIES DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_CFG_TAB,"SysTabControl32",WS_TABSTOP,7,7,241,168 + LTEXT "Static",IDC_CFG_TARGET,10,21,235,151,NOT WS_VISIBLE | + WS_BORDER +END + +IDD_CFG_NOTIF DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "&Monitor credentials expiration",IDC_NOTIF_MONITOR, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,139,10 + CONTROL "&Renew automatically",IDC_NOTIF_RENEW,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,22,32,82,10 + EDITTEXT IDC_NOTIF_RENEW_THR,122,30,126,14,ES_AUTOHSCROLL + CONTROL "Warn",IDC_NOTIF_WARN1,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,22,57,33,10 + EDITTEXT IDC_NOTIF_WARN1_THR,122,55,126,14,ES_AUTOHSCROLL + CONTROL "Warn again",IDC_NOTIF_WARN2,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,22,82,67,10 + EDITTEXT IDC_NOTIF_WARN2_THR,122,80,126,14,ES_AUTOHSCROLL +END + +IDD_CFG_PLUGINS DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_CFG_PLUGINS,"SysListView32",LVS_ALIGNLEFT | + WS_BORDER | WS_TABSTOP,7,7,75,168 + GROUPBOX "Plugin",IDC_CFG_PLUGINGRP,86,7,162,103 + LTEXT "Description",IDC_CFG_LBL_DESC,90,20,36,8 + EDITTEXT IDC_CFG_DESC,134,17,109,14,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Status",IDC_CFG_LBL_STATE,90,38,22,8 + EDITTEXT IDC_CFG_STATE,134,35,109,14,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Depends on",IDC_CFG_LBL_DEPS,90,52,39,8 + LISTBOX IDC_CFG_DEPS,134,52,109,34,LBS_SORT | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Enable",IDC_CFG_ENABLE,134,90,50,14 + PUSHBUTTON "Disable",IDC_CFG_DISABLE,193,90,50,14 + GROUPBOX "Provided by",IDC_CFG_PROVGRP,86,111,162,47 + LTEXT "Module",IDC_CFG_LBL_MOD,90,124,24,8 + EDITTEXT IDC_CFG_MODULE,134,121,109,14,ES_AUTOHSCROLL | + ES_READONLY + LTEXT "Vendor",IDC_CFG_LBL_VEN,90,142,24,8 + EDITTEXT IDC_CFG_VENDOR,133,139,110,14,ES_AUTOHSCROLL | + ES_READONLY + PUSHBUTTON "Register new plugin ...",IDC_CFG_REGISTER,163,161,85,14, + WS_DISABLED +END + +IDD_CFG_IDENTITY DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_CFG_TAB,"SysTabControl32",WS_TABSTOP,7,7,241,168 + LTEXT "Static",IDC_CFG_TARGET,10,21,235,151,NOT WS_VISIBLE | + WS_BORDER +END + +IDD_CFG_IDS_TAB DIALOGEX 0, 0, 235, 151 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_CFG_IDENTS,"SysListView32",LVS_SHAREIMAGELISTS | + LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,221,72 + GROUPBOX "Selected identity",IDC_CFG_IDENTITY,7,81,221,63 + CONTROL "Monitor credential expiration",IDC_CFG_MONITOR,"Button", + BS_3STATE | WS_TABSTOP,13,92,107,10 + CONTROL "Automatically renew",IDC_CFG_RENEW,"Button",BS_3STATE | + WS_TABSTOP,13,106,81,10 + CONTROL "Always show in the credentials list (Sticky)", + IDC_CFG_STICKY,"Button",BS_3STATE | WS_TABSTOP,13,120, + 151,10 + PUSHBUTTON "&Remove",IDC_CFG_REMOVE,174,126,50,14,WS_DISABLED +END + +IDD_CFG_ID_TAB DIALOGEX 0, 0, 235, 151 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Always show in the credentials list (Sticky)", + IDC_CFG_STICKY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7, + 34,151,10 + CONTROL "Monitor credential expiration",IDC_CFG_MONITOR,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,7,107,10 + CONTROL "Automatically renew",IDC_CFG_RENEW,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,20,81,10 +END + +IDD_ABOUT DIALOGEX 0, 0, 268, 170 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "About Network Identity Manager" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,211,7,50,14 + LTEXT "Productname",IDC_PRODUCT,41,7,163,13,NOT WS_GROUP + LTEXT "© 2005 Massachusetts Institute of Technology", + IDC_COPYRIGHT,41,23,220,18,NOT WS_GROUP + LTEXT "BuildInfo",IDC_BUILDINFO,41,41,220,17,NOT WS_GROUP + ICON IDI_MAIN_APP,IDC_STATIC,6,7,21,20 + CONTROL "",IDC_MODULES,"SysListView32",LVS_ALIGNLEFT | WS_BORDER | + WS_TABSTOP,41,72,220,91 + LTEXT "Loaded modules",IDC_STATIC,41,60,52,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_NC_NEWCRED, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 294 + TOPMARGIN, 7 + BOTTOMMARGIN, 160 + END + + IDD_NC_BBAR, DIALOG + BEGIN + RIGHTMARGIN, 53 + TOPMARGIN, 7 + BOTTOMMARGIN, 174 + END + + IDD_PP_IDENT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + VERTGUIDE, 34 + VERTGUIDE, 117 + TOPMARGIN, 7 + BOTTOMMARGIN, 149 + END + + IDD_PP_CRED, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 229 + TOPMARGIN, 7 + BOTTOMMARGIN, 151 + END + + IDD_CFG_GENERIC, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END + + IDD_CFG_GENERAL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 16 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END + + IDD_CFG_IDENTITIES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 10 + VERTGUIDE, 244 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + HORZGUIDE, 22 + HORZGUIDE, 171 + END + + IDD_CFG_NOTIF, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 22 + VERTGUIDE, 122 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END + + IDD_CFG_PLUGINS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 86 + VERTGUIDE, 90 + VERTGUIDE, 134 + VERTGUIDE, 243 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END + + IDD_CFG_IDENTITY, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END + + IDD_CFG_IDS_TAB, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 144 + END + + IDD_CFG_ID_TAB, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 144 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 6 + RIGHTMARGIN, 261 + VERTGUIDE, 41 + VERTGUIDE, 204 + TOPMARGIN, 7 + BOTTOMMARGIN, 163 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_MAIN_WINDOW_TITLE "Network Identity Manager" + IDS_MENU_FILE "&File" + IDS_MENU_CRED "&Credential" + IDS_MENU_VIEW "&View" +END + +STRINGTABLE +BEGIN + IDS_MENU_OPTIONS "&Options" + IDS_MENU_HELP "&Help" + IDS_ACTION_PROPERTIES "&Properties ..." + IDS_ACTION_EXIT "E&xit" + IDS_CFG_ROOT_NAME "NetIDMgr" + IDS_ACTION_SET_DEF_ID "Set as &default" + IDS_ACTION_SET_SRCH_ID "Allow applications to &search" + IDS_CFG_ROOT_TITLE "NetIDMgr Configuration" + IDS_CFG_GENERAL_SHORT "General" + IDS_ACTION_NEW_CRED "&New credentials ..." + IDS_ACTION_PASSWD_ID "Change &password ..." + IDS_ACTION_CHOOSE_COLS "Choose columns ..." + IDS_ACTION_DEBUG_WINDOW "Debug window ..." + IDS_ACTION_VIEW_REFRESH "Refresh" + IDS_MENU_LAYOUT "Layout" + IDS_MENU_TOOLBARS "Toolbars" +END + +STRINGTABLE +BEGIN + IDS_ACTION_LAYOUT_ID "By identity" + IDS_ACTION_LAYOUT_TYPE "By type" + IDS_ACTION_LAYOUT_LOC "By location" + IDS_ACTION_TB_STANDARD "Standard" + IDS_ACTION_OPT_KHIM "General ..." + IDS_ACTION_OPT_IDENTS "Identities ..." + IDS_ACTION_OPT_NOTIF "Notifications ..." + IDS_ACTION_HELP_CTX "Context" + IDS_ACTION_HELP_CONTENTS "Contents ..." + IDS_ACTION_HELP_INDEX "Index ..." + IDS_ACTION_HELP_ABOUT "About NetIDMgr ..." + IDS_CFG_GENERAL_LONG "General options for NetIDMgr" + IDS_SAMPLE_STRING "Wxy" + IDS_NO_CREDS "<large><center>You currently have no credentials.Click <a id=""NewCreds"">here</a> to obtain new credentials.</center></large>" + IDS_WT_INIT_CREDS "Obtain initial credentials" + IDS_WT_NEW_CREDS "Obtain new credentials" +END + +STRINGTABLE +BEGIN + IDS_NC_IDENTITY "&Identity" + IDS_NC_IDENTS "&Identities" + IDS_NC_CREDTEXT_ID_NONE "<p><b>(No identities specified)</b></p>" + IDS_NC_CREDTEXT_ID_ONE "<p>Selected identity: <b>%s</b></p>" + IDS_NC_CREDTEXT_ID_MANY "<p>Primary identity: <b>%s</b></p><p>Additional identities: <b>%s</b></p>" + IDS_NC_CREDTEXT_ID_INVALID "<font color=""red"">%s (invalid)</font>" + IDS_WTPOST_INIT_CREDS " - Initial credentials" + IDS_WTPOST_NEW_CREDS " - New credentials" + IDS_ACTION_RENEW_CRED "R&enew credentials" + IDS_ACTION_DESTROY_CRED "De&stroy credentials ..." + IDS_DEFAULT_FONT "MS Shell Dlg" + IDS_NC_CREDTEXT_TABS "<settab pos=""15""><settab pos=""30""><settab pos=""45"">" + IDS_NOTIFY_PREFIX "NetIDMgr - " + IDS_NOTIFY_READY "Ready" + IDS_NOTIFY_ATTENTION "Attention" + IDS_ALERT_DEFAULT "Alert" +END + +STRINGTABLE +BEGIN + IDS_PACTION_OK "&Ok" + IDS_PACTION_CANCEL "&Cancel" + IDS_PACTION_CLOSE "&Close" + IDS_ALERT_NOSEL_TITLE "No credentials selected" + IDS_ALERT_NOSEL "Please select a credential, a credential type or an identity." + IDS_NC_CREDTEXT_ID_VALID "<font color=""blue"">%s</font>" + IDS_NC_CREDTEXT_ID_UNCHECKED "<font color=""grey"">%s (Unverified)</font>" + IDS_PROP_COL_PROPERTY "Property" + IDS_PROP_COL_VALUE "Value" + IDS_NC_NEW_IDENT "( New identity ... )" + IDS_NC_CREDTEXT_ID_CHECKING "<font color=""grey"">%s (Checking...)</font>" + IDS_ACTION_OPEN_APP "Open NetIDMgr ..." + IDS_CTX_NEW_IDENT "Obaining new identity" + IDS_CTX_NEW_CREDS "Obtaining new credentials" + IDS_CTX_RENEW_CREDS "Renewing credentials" + IDS_CTX_PROC_NEW_IDENT "Obtaining initial credentials for %1!s!" +END + +STRINGTABLE +BEGIN + IDS_CTX_PROC_NEW_CREDS "Obtaining new credentials for %1!s!" + IDS_CTX_PROC_RENEW_CREDS "Renewing credentials for %1!s!" + IDS_ACTION_CLOSE_APP "Close NetIDMgr window" + IDS_NC_FAILED_TITLE "Failed to acquire credentials" + IDS_CFG_IDENTITIES_SHORT "Identities" + IDS_CFG_IDENTITIES_LONG "Options for all identities" + IDS_CFG_NOTIF_SHORT "Notifications" + IDS_CFG_NOTIF_LONG "Notifications" + IDS_CFG_PLUGINS_SHORT "Plugins" + IDS_CFG_PLUGINS_LONG "Plugins and Modules" + IDS_CFG_IDENTITY_SHORT "%s" + IDS_CFG_IDENTITY_LONG "Options for %s" + IDS_CTX_DESTROY_CREDS "Destroying credentials" + IDS_WARN_EXPIRE "Some of your credentials will expire in %s" + IDS_WARN_TITLE "Credentials expiration warning" + IDS_ALERT_MOREINFO "...\nClick here for more..." +END + +STRINGTABLE +BEGIN + IDS_WARN_EXPIRED "Some of your credentials have expired." + IDS_WARN_EXPIRE_ID "Credentials for %.180s will expire in %s" + IDS_WARN_EXPIRED_ID "Credentials for %.220s have expired" + IDS_WARN_WM_TITLE "NetIDMgr is still running" + IDS_WARN_WM_MSG "Click the NetIDMgr icon below to open the application.\n\nOr right click the icon to access the NetIDMgr menu." + IDS_CFG_ID_TAB_SHORT "General" + IDS_CFG_ID_TAB_LONG "General options for this identity" + IDS_CFG_IDS_TAB_SHORT "General" + IDS_CFG_IDS_TAB_LONG "General options for all identities" + IDS_CFG_IDS_IDENTITY "Identity" + IDS_ACTION_IMPORT "Import Credentials" + IDS_CTX_IMPORT "Importing credentials from Windows" + IDS_CFG_PI_COL_PLUGINS "Plugins" + IDS_PISTATE_FAILUNK "Unknown failure" + IDS_PISTATE_FAILMAX "Maximum failure count reached" + IDS_PISTATE_FAILREG "Not properly registered" +END + +STRINGTABLE +BEGIN + IDS_PISTATE_FAILDIS "Disabled" + IDS_PISTATE_FAILLOD "Failed to initialize" + IDS_PISTATE_PLACEHOLD "Not loaded" + IDS_PISTATE_REG "Not initialized" + IDS_PISTATE_HOLD "Waiting for dependencies" + IDS_PISTATE_INIT "Initializing" + IDS_PISTATE_RUN "Running" + IDS_PISTATE_EXIT "Stopped" + IDS_CTX_PASSWORD "Changing password" + IDS_WT_PASSWORD "Changing password" + IDS_WTPOST_PASSWORD " - Changing password" + IDS_CTX_PROC_PASSWORD "Changing password for %1!s!" + IDS_NC_PWD_FAILED_TITLE "Failed to change password" + IDS_CMDLINE_HELP "Command line options for NetIDMgr are :\n\n-a or --autoinit: Auto initialize credentials\n-i or --kinit: Obtain new credentials\n-d or --destroy: Destroy default identity\n-r or --renew: Renew all credentials" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/windows/identity/ui/main.c b/src/windows/identity/ui/main.c new file mode 100644 index 0000000000..b92c540b5b --- /dev/null +++ b/src/windows/identity/ui/main.c @@ -0,0 +1,442 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> + +#if DEBUG +#include<assert.h> +#endif + +HINSTANCE khm_hInstance; +const wchar_t * khm_facility = L"NetIDMgr"; +int khm_nCmdShow; + +khm_startup_options khm_startup; + +void khm_init_gui(void) { + khui_init_actions(); + khui_init_rescache(); + khui_init_menu(); + khui_init_toolbar(); + khui_init_notifier(); + khm_init_config(); +} + +void khm_exit_gui(void) { + khm_exit_config(); + khui_exit_notifier(); + khui_exit_toolbar(); + khui_exit_menu(); + khui_exit_rescache(); + khui_exit_actions(); +} + +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<wargc; i++) { + if (!wcscmp(wargs[i], L"-i") || + !wcscmp(wargs[i], L"--kinit")) { + khm_startup.init = TRUE; + khm_startup.exit = TRUE; + khm_startup.no_main_window = TRUE; + } + else if (!wcscmp(wargs[i], L"-m") || + !wcscmp(wargs[i], L"--import")) { + khm_startup.import = TRUE; + khm_startup.exit = TRUE; + khm_startup.no_main_window = TRUE; + } + else if (!wcscmp(wargs[i], L"-r") || + !wcscmp(wargs[i], L"--renew")) { + khm_startup.renew = TRUE; + khm_startup.exit = TRUE; + khm_startup.no_main_window = TRUE; + } + else if (!wcscmp(wargs[i], L"-d") || + !wcscmp(wargs[i], L"--destroy")) { + khm_startup.destroy = TRUE; + khm_startup.exit = TRUE; + khm_startup.no_main_window = TRUE; + } + else if (!wcscmp(wargs[i], L"-a") || + !wcscmp(wargs[i], L"--autoinit")) { + khm_startup.autoinit = TRUE; + } + else { + wchar_t help[2048]; + + LoadString(khm_hInstance, IDS_CMDLINE_HELP, + help, ARRAYLENGTH(help)); + + MessageBox(NULL, help, L"NetIDMgr", MB_OK); + + khm_startup.error_exit = TRUE; + break; + } + } +} + +void khm_register_window_classes(void) { + INITCOMMONCONTROLSEX ics; + + ZeroMemory(&ics, sizeof(ics)); + ics.dwSize = sizeof(ics); + ics.dwICC = + ICC_COOL_CLASSES | + ICC_BAR_CLASSES | + ICC_DATE_CLASSES | + ICC_HOTKEY_CLASS | + ICC_LINK_CLASS | + ICC_LISTVIEW_CLASSES | + ICC_STANDARD_CLASSES | + ICC_TAB_CLASSES; + 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; + 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; + /* we set .active=FALSE for now. We don't need this to have a + meaningful value until we enter a modal loop */ + khui_dialogs[n_khui_dialogs].active = FALSE; + n_khui_dialogs++; + } +#if DEBUG + else { + assert(FALSE); + } +#endif +} + +/* should only be called from the UI thread */ +void khm_enter_modal(HWND hwnd) { + int i; + + 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 = IsWindowEnabled(khm_hwnd_main); + EnableWindow(khm_hwnd_main, FALSE); + + khui_modal_dialog = 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) { + EnableWindow(khui_dialogs[i].hwnd, khui_dialogs[i].active); + } + } + + EnableWindow(khm_hwnd_main, khui_main_window_active); + + khui_modal_dialog = NULL; +} + +/* 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; + for(i=0;i<n_khui_dialogs;i++) { + if(IsDialogMessage(khui_dialogs[i].hwnd, pmsg)) + break; + } + + if(i<n_khui_dialogs) + return TRUE; + else + return FALSE; +} + +BOOL khm_is_dialog_active(void) { + HWND hwnd; + int i; + + hwnd = GetForegroundWindow(); + + for (i=0; i<n_khui_dialogs; i++) { + if (khui_dialogs[i].hwnd == hwnd) + return TRUE; + } + + return FALSE; +} + +/* We support at most 256 property sheets simultaneously. 256 + property sheets should be enough for everybody. */ +#define MAX_UI_PROPSHEETS 256 + +khui_property_sheet *_ui_propsheets[MAX_UI_PROPSHEETS]; +int _n_ui_propsheets = 0; + +void khm_add_property_sheet(khui_property_sheet * s) { + if(_n_ui_propsheets < MAX_UI_PROPSHEETS) + _ui_propsheets[_n_ui_propsheets++] = s; +#ifdef DEBUG + else + assert(FALSE); +#endif +} + +void khm_del_property_sheet(khui_property_sheet * s) { + int i; + + for(i=0;i < _n_ui_propsheets; i++) { + if(_ui_propsheets[i] == s) + break; + } + + if(i < _n_ui_propsheets) + _n_ui_propsheets--; + else + return; + + for(;i < _n_ui_propsheets; i++) { + _ui_propsheets[i] = _ui_propsheets[i+1]; + } +} + +BOOL khm_check_ps_message(LPMSG pmsg) { + int i; + khui_property_sheet * ps; + for(i=0;i<_n_ui_propsheets;i++) { + if(khui_ps_check_message(_ui_propsheets[i], pmsg)) { + if(_ui_propsheets[i]->status == 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; +} + +WPARAM khm_message_loop(void) { + int r; + MSG msg; + HACCEL ha_menu; + + ha_menu = khui_create_global_accel_table(); + while(r = GetMessage(&msg, NULL, 0,0)) { + 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); + } + } + DestroyAcceleratorTable(ha_menu); + return msg.wParam; +} + +int WINAPI WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + int rv = 0; + HANDLE h_appmutex; + BOOL slave = FALSE; + + khm_hInstance = hInstance; + khm_nCmdShow = nCmdShow; + + khm_parse_commandline(); + + if (khm_startup.error_exit) + return 0; + + 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); + + if(!slave) { + /* we only open a main window if this is the only instance + of the application that is running. */ + kmq_init(); + kmm_init(); + khm_init_gui(); + + kmq_set_completion_handler(KMSG_CRED, kmsg_cred_completion); + + /* load the standard plugins */ + kmm_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(); + + rv = (int) khm_message_loop(); + + kmq_set_completion_handler(KMSG_CRED, NULL); + + khm_exit_request_daemon(); + + khm_exit_gui(); + khm_unregister_window_classes(); + kmm_exit(); + kmq_exit(); + + CloseHandle(h_appmutex); + } else { + HWND hwnd = NULL; + int retries = 5; + HANDLE hmap; + wchar_t mapname[256]; + DWORD tid; + void * xfer; + + CloseHandle(h_appmutex); + + while (hwnd == NULL && retries) { + hwnd = FindWindowEx(NULL, NULL, KHUI_MAIN_WINDOW_CLASS, NULL); + + if (hwnd) + break; + + retries--; + Sleep(1000); + } + + if (!hwnd) + return 2; + + StringCbPrintf(mapname, sizeof(mapname), + COMMANDLINE_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(khm_startup)); + + if (xfer) { + memcpy(xfer, &khm_startup, sizeof(khm_startup)); + + SendMessage(hwnd, WM_KHUI_ASSIGN_COMMANDLINE, + 0, (LPARAM) tid); + } + + if (xfer) + UnmapViewOfFile(xfer); + + if (hmap) + CloseHandle(hmap); + } + + return rv; +} diff --git a/src/windows/identity/ui/mainmenu.c b/src/windows/identity/ui/mainmenu.c new file mode 100644 index 0000000000..6115204f3b --- /dev/null +++ b/src/windows/identity/ui/mainmenu.c @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +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;i<MAX_ILIST;i++) + il_icon_id[i] = -1; +} + +void khui_exit_menu(void) { + khui_delete_ilist(il_icon); +} + +int khui_get_icon_index(int id) { + int i; + HBITMAP hbm; + + for(i=0;i<MAX_ILIST;i++) + if(il_icon_id[i] == id) { + return i; + } + + hbm = LoadImage(khm_hInstance, + MAKEINTRESOURCE(id), + IMAGE_BITMAP, + ILIST_ICON_X, ILIST_ICON_Y, + LR_DEFAULTCOLOR); + i = khui_ilist_add_masked(il_icon, hbm, KHUI_TOOLBAR_BGCOLOR); + il_icon_id[i] = id; + DeleteObject(hbm); + + return i; +} + +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""; + + mii.cbSize = sizeof(mii); + mii.fMask = 0; + + if(act == NULL) { + mii.fMask = MIIM_FTYPE; + mii.fType = MFT_SEPARATOR; + } else { + khui_menu_def * def; + + LoadString(khm_hInstance, + act->is_caption, + buf, ARRAYLENGTH(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; + } + + def = khui_find_menu(act->cmd); + if(def) { + mii.fMask |= MIIM_SUBMENU; + mii.hSubMenu = mm_create_menu_from_def(def); + } + + if(flags & KHUI_ACTIONREF_DEFAULT) + mii.fState |= MFS_DEFAULT; + } + + InsertMenuItem(hm,idx,TRUE,&mii); +} + +static HMENU mm_create_menu_from_def(khui_menu_def * def) { + HMENU hm; + khui_action_ref * act; + int i; + + hm = CreatePopupMenu(); + act = def->items; + i = 0; + while(act->action != KHUI_MENU_END) { + add_action_to_menu(hm,khui_find_action(act->action),i,act->flags); + act++; i++; + } + + 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); + + 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 */ + khui_statusbar_set_text(KHUI_SBPART_INFO, 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) + khui_statusbar_set_text(KHUI_SBPART_INFO, NULL); + else { + LoadString(khm_hInstance, + act->is_tooltip, + buf, ARRAYLENGTH(buf)); + khui_statusbar_set_text(KHUI_SBPART_INFO, 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; +} + +void khm_menu_create_main(HWND rebar) { + 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( + TBSTYLE_EX_MIXEDBUTTONS, + 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); +#else + return; +#endif + } + + khui_main_menu_toolbar = hwtb; + + SendMessage(hwtb, + TB_BUTTONSTRUCTSIZE, + (WPARAM) sizeof(TBBUTTON), + 0); + + for(i=0; i<nmm; i++) { + khui_add_action_to_toolbar(hwtb, + khui_find_action(mm[i].action), + KHUI_TOOLBAR_ADD_TEXT | + KHUI_TOOLBAR_ADD_DROPDOWN | + KHUI_TOOLBAR_VARSIZE, + NULL); + } + + SendMessage(hwtb, + TB_AUTOSIZE, + 0,0); + + SendMessage(hwtb, + TB_GETMAXSIZE, + 0, + (LPARAM) &sz); + + ZeroMemory(&rbi, sizeof(rbi)); + + rbi.cbSize = sizeof(rbi); + + rbi.fMask = + RBBIM_ID | + RBBIM_STYLE | + RBBIM_CHILD | + RBBIM_CHILDSIZE | + RBBIM_SIZE | + RBBIM_IDEALSIZE; + + rbi.fStyle = + RBBS_USECHEVRON; + + rbi.hwndChild = hwtb; + rbi.wID = KHUI_MENU_MAIN; + rbi.cx = sz.cx; + rbi.cxMinChild = rbi.cx; + rbi.cxIdeal = rbi.cx; + rbi.cyMinChild = sz.cy; + rbi.cyChild = rbi.cyMinChild; + rbi.cyIntegral = rbi.cyMinChild; + rbi.cyMaxChild = rbi.cyMinChild; + + SendMessage(rebar, + RB_INSERTBAND, + 0, + (LPARAM) &rbi); +} diff --git a/src/windows/identity/ui/mainmenu.h b/src/windows/identity/ui/mainmenu.h new file mode 100644 index 0000000000..7cd8e01ca9 --- /dev/null +++ b/src/windows/identity/ui/mainmenu.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_MAINMENU_H +#define __KHIMAIRA_MAINMENU_H + +extern HWND khui_main_menu_toolbar; + +#define MENU_ACTIVATE_DEFAULT -1 +#define MENU_ACTIVATE_LEFT -2 +#define MENU_ACTIVATE_RIGHT -3 +#define MENU_ACTIVATE_NONE -4 + +extern int mm_last_hot_item; +extern BOOL mm_hot_track; + +void khm_menu_create_main(HWND rebar); +LRESULT khm_menu_handle_select(WPARAM wParam, LPARAM lParam); +LRESULT khm_menu_notify_main(LPNMHDR notice); +LRESULT khm_menu_activate(int menu_id); +void khm_menu_show_panel(int id, LONG x, LONG y); +void khm_menu_track_current(void); +LRESULT khm_menu_measure_item(WPARAM wParam, LPARAM lparam); +LRESULT khm_menu_draw_item(WPARAM wParam, LPARAM lparam); + +static HMENU mm_create_menu_from_def(khui_menu_def * def); +static void mm_show_panel_def(khui_menu_def * def, LONG x, LONG y); + +void khui_init_menu(void); +void khui_exit_menu(void); + +#define MENU_SIZE_ICON_X 16 +#define MENU_SIZE_ICON_Y 16 + +#endif diff --git a/src/windows/identity/ui/mainwnd.c b/src/windows/identity/ui/mainwnd.c new file mode 100644 index 0000000000..0f5c7e0439 --- /dev/null +++ b/src/windows/identity/ui/mainwnd.c @@ -0,0 +1,679 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +ATOM khm_main_window_class; +ATOM khm_null_window_class; +HWND khm_hwnd_null; +HWND khm_hwnd_main; +HWND khm_hwnd_rebar; +HWND khm_hwnd_main_cred; + +#define MW_RESIZE_TIMER 1 +#define MW_RESIZE_TIMEOUT 2000 +#define MW_REFRESH_TIMER 2 +#define MW_REFRESH_TIMEOUT 600 + +void +khm_set_dialog_result(HWND hwnd, LRESULT lr) { +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWL_MSGRESULT, lr); +#pragma warning(pop) +} + +static void +mw_restart_refresh_timer(HWND hwnd) { + khm_handle csp_cw; + khm_int32 timeout; + + KillTimer(hwnd, MW_REFRESH_TIMER); + if (KHM_SUCCEEDED(khc_open_space(NULL, + L"CredWindow", + KHM_PERM_READ, + &csp_cw))) { + if (KHM_FAILED(khc_read_int32(csp_cw, + L"RefreshTimeout", + &timeout))) + timeout = MW_REFRESH_TIMEOUT; + khc_close_space(csp_cw); + } else + timeout = MW_REFRESH_TIMEOUT; + + timeout *= 1000; /* convert to milliseconds */ + + SetTimer(hwnd, MW_REFRESH_TIMER, timeout, NULL); +} + +LRESULT CALLBACK khm_main_wnd_proc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ) +{ + LPNMHDR lpnm; + + switch(uMsg) { + case WM_CREATE: + khm_create_main_window_controls(hwnd); + kmq_subscribe_hwnd(KMSG_CRED, hwnd); + kmq_subscribe_hwnd(KMSG_ACT, hwnd); + kmq_subscribe_hwnd(KMSG_KMM, hwnd); + mw_restart_refresh_timer(hwnd); + + if (!kmm_load_pending()) + kmq_post_message(KMSG_ACT, KMSG_ACT_BEGIN_CMDLINE, 0, 0); + break; + + case WM_DESTROY: + kmq_unsubscribe_hwnd(KMSG_ACT, hwnd); + kmq_unsubscribe_hwnd(KMSG_CRED, hwnd); + PostQuitMessage(0); + break; + + case WM_NOTIFY: + lpnm = (LPNMHDR) lParam; + if(lpnm->hwndFrom == khui_main_menu_toolbar) { + return khm_menu_notify_main(lpnm); + } else if(lpnm->hwndFrom == khui_hwnd_standard_toolbar) { + return khm_toolbar_notify(lpnm); + } else if(lpnm->hwndFrom == khm_hwnd_rebar) { + return khm_rebar_notify(lpnm); + } + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + /* general actions */ + case KHUI_ACTION_VIEW_REFRESH: + InvalidateRect(khm_hwnd_main_cred, NULL, FALSE); + kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, NULL); + return 0; + + case KHUI_ACTION_PASSWD_ID: + khm_cred_change_password(NULL); + return 0; + + case KHUI_ACTION_NEW_CRED: + khm_cred_obtain_new_creds(NULL); + return 0; + + case KHUI_ACTION_RENEW_CRED: + khm_cred_renew_creds(); + return 0; + + case KHUI_ACTION_DESTROY_CRED: + khm_cred_destroy_creds(); + return 0; + + case KHUI_ACTION_SET_DEF_ID: + khm_cred_set_default(); + return 0; + + case KHUI_ACTION_EXIT: + DestroyWindow(hwnd); + break; + + case KHUI_ACTION_OPEN_APP: + khm_show_main_window(); + break; + + case KHUI_ACTION_CLOSE_APP: + khm_hide_main_window(); + break; + + case KHUI_ACTION_OPT_KHIM: + khm_show_config_pane(NULL); + break; + + case KHUI_ACTION_OPT_IDENTS: { + khui_config_node node; + + khui_cfg_open(NULL, L"KhmIdentities", &node); + khm_show_config_pane(node); + } + break; + + case KHUI_ACTION_OPT_NOTIF: { + khui_config_node node; + + khui_cfg_open(NULL, L"KhmNotifications", &node); + khm_show_config_pane(node); + } + break; + + case KHUI_ACTION_HELP_ABOUT: + khm_create_about_window(); + break; + + case KHUI_ACTION_PROPERTIES: + /* properties are not handled by the main window. + Just bounce it to credwnd. However, use SendMessage + instead of PostMessage so we don't lose context */ + return SendMessage(khm_hwnd_main_cred, uMsg, + wParam, lParam); + + /* menu commands */ + case KHUI_PACTION_MENU: + if(HIWORD(lParam) == 1) + mm_last_hot_item = LOWORD(lParam); + return khm_menu_activate(MENU_ACTIVATE_DEFAULT); + + /* generic, retargetting */ + case KHUI_PACTION_UP: + case KHUI_PACTION_UP_TOGGLE: + case KHUI_PACTION_UP_EXTEND: + case KHUI_PACTION_DOWN: + case KHUI_PACTION_DOWN_TOGGLE: + case KHUI_PACTION_DOWN_EXTEND: + case KHUI_PACTION_LEFT: + case KHUI_PACTION_RIGHT: + case KHUI_PACTION_ESC: + case KHUI_PACTION_ENTER: + /* menu tracking */ + if(mm_last_hot_item != -1) { + switch(LOWORD(wParam)) { + case KHUI_PACTION_LEFT: + khm_menu_activate(MENU_ACTIVATE_LEFT); + break; + + case KHUI_PACTION_RIGHT: + khm_menu_activate(MENU_ACTIVATE_RIGHT); + break; + + case KHUI_PACTION_ESC: + case KHUI_PACTION_ENTER: + khm_menu_activate(MENU_ACTIVATE_NONE); + break; + + case KHUI_PACTION_DOWN: + khm_menu_track_current(); + break; + } + return 0; + } + + /*FALLTHROUGH*/ + + case KHUI_PACTION_DELETE: + + case KHUI_ACTION_LAYOUT_ID: + case KHUI_ACTION_LAYOUT_TYPE: + case KHUI_ACTION_LAYOUT_LOC: + /* otherwise fallthrough and bounce to the creds window */ + return SendMessage(khm_hwnd_main_cred, uMsg, + wParam, lParam); + } + break; /* WM_COMMAND */ + + case WM_SYSCOMMAND: + switch(wParam & 0xfff0) { + case SC_MINIMIZE: + khm_hide_main_window(); + return 0; + + case SC_CLOSE: + { + khm_handle csp_cw; + BOOL keep_running = FALSE; + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", + KHM_PERM_READ, &csp_cw))) { + khm_int32 t; + + if (KHM_SUCCEEDED(khc_read_int32(csp_cw, L"KeepRunning", + &t))) + keep_running = t; +#ifdef DEBUG + else + assert(FALSE); +#endif + + khc_close_space(csp_cw); + } +#ifdef DEBUG + else + assert(FALSE); +#endif + + if (keep_running) + khm_hide_main_window(); + else + DestroyWindow(hwnd); + } + return 0; + } + break; + + case WM_MEASUREITEM: + /* sent to measure the bitmaps associated with a menu item */ + if(!wParam) /* sent by menu */ + return khm_menu_measure_item(wParam, lParam); + break; + + case WM_DRAWITEM: + /* sent to draw a menu item */ + if(!wParam) + return khm_menu_draw_item(wParam, lParam); + break; + + case WM_ERASEBKGND: + /* Don't erase the background. The whole client area is + covered with children. It doesn't need to be erased */ + return TRUE; + break; + + case WM_SIZE: + if(hwnd == khm_hwnd_main && + (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)) { + int cwidth, cheight; + RECT r_rebar, r_status; + + cwidth = LOWORD(lParam); + cheight = HIWORD(lParam); + + /* resize the rebar control */ + SendMessage(khm_hwnd_rebar, WM_SIZE, 0, 0); + + khui_update_statusbar(hwnd); + + GetWindowRect(khm_hwnd_rebar, &r_rebar); + GetWindowRect(khui_hwnd_statusbar, &r_status); + + /* the cred window fills the area between the rebar + and the status bar */ + MoveWindow(khm_hwnd_main_cred, 0, + r_rebar.bottom - r_rebar.top, + r_status.right - r_status.left, + r_status.top - r_rebar.bottom, TRUE); + + SetTimer(hwnd, + MW_RESIZE_TIMER, + MW_RESIZE_TIMEOUT, + NULL); + return 0; + } + break; + + case WM_MOVE: + { + SetTimer(hwnd, + MW_RESIZE_TIMER, + MW_RESIZE_TIMEOUT, + NULL); + } + break; + + case WM_TIMER: + if (wParam == MW_RESIZE_TIMER) { + RECT r; + khm_handle csp_cw; + khm_handle csp_mw; + + KillTimer(hwnd, wParam); + + GetWindowRect(hwnd, &r); + + if (KHM_SUCCEEDED(khc_open_space(NULL, + L"CredWindow", + KHM_PERM_WRITE, + &csp_cw))) { + if (KHM_SUCCEEDED(khc_open_space(csp_cw, + L"Windows\\Main", + KHM_PERM_WRITE, + &csp_mw))) { + khc_write_int32(csp_mw, L"XPos", r.left); + khc_write_int32(csp_mw, L"YPos", r.top); + khc_write_int32(csp_mw, L"Width", + r.right - r.left); + khc_write_int32(csp_mw, L"Height", + r.bottom - r.top); + + khc_close_space(csp_mw); + } + khc_close_space(csp_cw); + } + } else if (wParam == MW_REFRESH_TIMER) { + kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0); + } + break; + + case WM_MENUSELECT: + return khm_menu_handle_select(wParam, lParam); + break; + + case KMQ_WM_DISPATCH: + { + kmq_message * m; + khm_int32 rv = KHM_ERROR_SUCCESS; + + kmq_wm_begin(lParam, &m); + if (m->type == KMSG_ACT && + m->subtype == KMSG_ACT_REFRESH) { + khm_update_standard_toolbar(); + } else if (m->type == KMSG_ACT && + m->subtype == KMSG_ACT_BEGIN_CMDLINE) { + khm_cred_begin_commandline(); + } else if (m->type == KMSG_CRED && + m->subtype == KMSG_CRED_REFRESH) { + mw_restart_refresh_timer(hwnd); + } else if (m->type == KMSG_KMM && + m->subtype == KMSG_KMM_I_DONE) { + kmq_post_message(KMSG_ACT, KMSG_ACT_BEGIN_CMDLINE, 0, 0); + } + return kmq_wm_end(m, rv); + } + break; + + case WM_KHUI_ASSIGN_COMMANDLINE: + { + HANDLE hmap; + void * xfer; + wchar_t mapname[256]; + + StringCbPrintf(mapname, sizeof(mapname), + COMMANDLINE_MAP_FMT, (DWORD) lParam); + + hmap = OpenFileMapping(FILE_MAP_READ, FALSE, mapname); + + if (hmap == NULL) + return 1; + + xfer = MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, + sizeof(khm_startup)); + + if (xfer) { + memcpy(&khm_startup, xfer, sizeof(khm_startup)); + + UnmapViewOfFile(xfer); + } + + CloseHandle(hmap); + + if(InSendMessage()) + ReplyMessage(0); + + khm_startup.exit = FALSE; + + khm_startup.seen = FALSE; + khm_startup.processing = FALSE; + + khm_cred_begin_commandline(); + } + break; + } + return DefWindowProc(hwnd,uMsg,wParam,lParam); +} + +LRESULT CALLBACK khm_null_wnd_proc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ) { + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +LRESULT khm_rebar_notify(LPNMHDR lpnm) { + switch(lpnm->code) { + case RBN_AUTOBREAK: + { + LPNMREBARAUTOBREAK lpra = (LPNMREBARAUTOBREAK) lpnm; + lpra->fAutoBreak = TRUE; + } + break; + + case RBN_BEGINDRAG: + { + LPNMREBAR lprb = (LPNMREBAR) lpnm; + if ((lprb->dwMask & RBNM_ID) && + lprb->wID == 0) + return 1; + else + return 0; + } + break; + + case NM_CUSTOMDRAW: + return CDRF_DODEFAULT; + break; + } + + return 1; +} + +void khm_create_main_window_controls(HWND hwnd_main) { + REBARINFO rbi; + HWND hwRebar; + + hwRebar = + CreateWindowEx(WS_EX_TOOLWINDOW, + REBARCLASSNAME, + L"Rebar", + WS_CHILD | + WS_VISIBLE| + WS_CLIPSIBLINGS | + WS_CLIPCHILDREN | + CCS_NODIVIDER | + RBS_VARHEIGHT | + RBS_FIXEDORDER, + 0,0,0,0, + hwnd_main, + NULL, + khm_hInstance, + NULL); + + if(!hwRebar) { + DWORD dwe = GetLastError(); + return; + } + + khm_hwnd_rebar = hwRebar; + + rbi.cbSize = sizeof(rbi); + rbi.fMask = 0; + rbi.himl = (HIMAGELIST) NULL; + if(!SendMessage(hwRebar, RB_SETBARINFO, 0, (LPARAM) &rbi)) + return; + + /* self attach */ + khm_menu_create_main(hwRebar); + khm_create_standard_toolbar(hwRebar); + khui_create_statusbar(hwnd_main); + + /* manual attach */ + khm_hwnd_main_cred = khm_create_credwnd(hwnd_main); +} + +void khm_create_main_window(void) { + wchar_t buf[1024]; + khm_handle csp_cw = NULL; + khm_handle csp_mw = NULL; + int x,y,width,height; + + LoadString(khm_hInstance, IDS_MAIN_WINDOW_TITLE, buf, sizeof(buf)/sizeof(buf[0])); + + khm_hwnd_null = + CreateWindow(MAKEINTATOM(khm_null_window_class), + buf, + 0, /* Style */ + 0, 0, /* x, y */ + 100, 100, /* width, height */ + NULL, /* parent */ + NULL, /* menu */ + NULL, /* HINSTANCE */ + 0); /* lparam */ + + if (!khm_hwnd_null) + return; + + x = CW_USEDEFAULT; + y = CW_USEDEFAULT; + width = CW_USEDEFAULT; + height = CW_USEDEFAULT; + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", + KHM_PERM_READ, + &csp_cw))) { + if (KHM_SUCCEEDED(khc_open_space(csp_cw, + L"Windows\\Main", + KHM_PERM_READ, + &csp_mw))) { + khm_int32 t; + + if (KHM_SUCCEEDED(khc_read_int32(csp_mw, L"XPos", &t))) + x = t; + if (KHM_SUCCEEDED(khc_read_int32(csp_mw, L"YPos", &t))) + y = t; + if (KHM_SUCCEEDED(khc_read_int32(csp_mw, L"Width", &t))) + width = t; + if (KHM_SUCCEEDED(khc_read_int32(csp_mw, L"Height", &t))) + height = t; + + khc_close_space(csp_mw); + } + khc_close_space(csp_cw); + } + + khm_hwnd_main = + CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, + MAKEINTATOM(khm_main_window_class), + buf, + WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | + WS_CLIPSIBLINGS, + x, y, width, height, + khm_hwnd_null, + NULL, + NULL, + NULL); + + if (!khm_hwnd_main) + return; +} + +void khm_show_main_window(void) { + + if (khm_nCmdShow == SW_RESTORE) { + HWND hw; + + hw = GetForegroundWindow(); + if (hw != khm_hwnd_main) + SetForegroundWindow(khm_hwnd_main); + } + + ShowWindow(khm_hwnd_main, khm_nCmdShow); + UpdateWindow(khm_hwnd_main); + + khm_nCmdShow = SW_RESTORE; +} + +void khm_hide_main_window(void) { + khm_handle csp_notices = NULL; + khm_int32 show_warning = FALSE; + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow\\Notices", + KHM_PERM_WRITE, &csp_notices)) && + KHM_SUCCEEDED(khc_read_int32(csp_notices, L"MinimizeWarning", + &show_warning)) && + show_warning != 0) { + khui_alert * alert; + wchar_t title[KHUI_MAXCCH_TITLE]; + wchar_t msg[KHUI_MAXCCH_MESSAGE]; + + LoadString(khm_hInstance, IDS_WARN_WM_TITLE, + title, ARRAYLENGTH(title)); + LoadString(khm_hInstance, IDS_WARN_WM_MSG, + msg, ARRAYLENGTH(msg)); + + khui_alert_create_simple(title, msg, KHERR_INFO, &alert); + khui_alert_set_flags(alert, KHUI_ALERT_FLAG_REQUEST_BALLOON, + KHUI_ALERT_FLAG_REQUEST_BALLOON); + + khui_alert_show(alert); + + khc_write_int32(csp_notices, L"MinimizeWarning", 0); + } + + if (csp_notices != NULL) + khc_close_space(csp_notices); + + ShowWindow(khm_hwnd_main, SW_HIDE); +} + +BOOL khm_is_main_window_visible(void) { + return IsWindowVisible(khm_hwnd_main); +} + +BOOL khm_is_main_window_active(void) { + if (!IsWindowVisible(khm_hwnd_main)) + return FALSE; + if (GetForegroundWindow() == khm_hwnd_main) + return TRUE; + return khm_is_dialog_active(); +} + +void khm_register_main_wnd_class(void) { + WNDCLASSEX wc; + + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = 0; + wc.lpfnWndProc = khm_null_wnd_proc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = khm_hInstance; + wc.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP)); + wc.hCursor = LoadCursor((HINSTANCE) NULL, MAKEINTRESOURCE(IDC_ARROW)); + wc.hIconSm = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); + wc.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE); + wc.lpszMenuName = NULL; + wc.lpszClassName = KHUI_NULL_WINDOW_CLASS; + + khm_null_window_class = RegisterClassEx(&wc); + + + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = khm_main_wnd_proc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = khm_hInstance; + wc.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP)); + wc.hCursor = LoadCursor((HINSTANCE) NULL, MAKEINTRESOURCE(IDC_ARROW)); + wc.hIconSm = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); + wc.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE); + wc.lpszMenuName = NULL; + wc.lpszClassName = KHUI_MAIN_WINDOW_CLASS; + + khm_main_window_class = RegisterClassEx(&wc); +} + +void khm_unregister_main_wnd_class(void) { + UnregisterClass(MAKEINTATOM(khm_main_window_class),khm_hInstance); + UnregisterClass(MAKEINTATOM(khm_null_window_class),khm_hInstance); +} diff --git a/src/windows/identity/ui/mainwnd.h b/src/windows/identity/ui/mainwnd.h new file mode 100644 index 0000000000..cdaac1e968 --- /dev/null +++ b/src/windows/identity/ui/mainwnd.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_MAINWND_H +#define __KHIMAIRA_MAINWND_H + +#define KHUI_MAIN_WINDOW_CLASS L"KhmMainWindowClass" +#define KHUI_NULL_WINDOW_CLASS L"KhmNullWindowClass" + +extern ATOM khm_main_window_class; +extern HWND khm_hwnd_main; +extern HWND khm_hwnd_rebar; + +void khm_register_main_wnd_class(void); +void khm_unregister_main_wnd_class(void); +void khm_create_main_window_controls(HWND); +void khm_create_main_window(void); +void khm_show_main_window(void); +void khm_hide_main_window(void); +BOOL khm_is_main_window_visible(void); +BOOL khm_is_main_window_active(void); +LRESULT khm_rebar_notify(LPNMHDR lpnm); + +void +khm_set_dialog_result(HWND hwnd, LRESULT lr); + +LRESULT CALLBACK +khm_main_wnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +#define WM_KHUI_ASSIGN_COMMANDLINE 32808 + +#define COMMANDLINE_MAP_FMT L"Local\\NetIDMgr_Cmdline_%lu" + +#endif diff --git a/src/windows/identity/ui/makeacceldef.pl b/src/windows/identity/ui/makeacceldef.pl new file mode 100644 index 0000000000..f13a3ec180 --- /dev/null +++ b/src/windows/identity/ui/makeacceldef.pl @@ -0,0 +1,29 @@ +# + +die "Please specify input and output filenames" if($#ARGV != 1); + +open INF, '<', $ARGV[0] or die "Can't open input file"; +open OUF, '>', $ARGV[1] or die "Can't open output file"; + +print OUF <<EOS; +#include<khimaira.h> + + khui_accel_def khui_accel_global[] = { +EOS + +# skip first line + <INF>; + +while(<INF>) { + print OUF "{".$_."},\n"; +} + +print OUF <<EOS; +}; + +int khui_n_accel_global = sizeof(khui_accel_global) / sizeof(khui_accel_def); + +EOS + +close INF; +close OUF; diff --git a/src/windows/identity/ui/makeactiondef.pl b/src/windows/identity/ui/makeactiondef.pl new file mode 100644 index 0000000000..a83325b3a0 --- /dev/null +++ b/src/windows/identity/ui/makeactiondef.pl @@ -0,0 +1,29 @@ +# + +die "Please specify input and output filenames" if($#ARGV != 1); + +open INF, '<', $ARGV[0] or die "Can't open input file"; +open OUF, '>', $ARGV[1] or die "Can't open output file"; + +print OUF <<EOS; +#include<khimaira.h> + + khui_action khui_actions[] = { +EOS + +# skip first line + <INF>; + +while(<INF>) { + print OUF "{".$_."},\n"; +} + +print OUF <<EOS; +}; + +int khui_n_actions = sizeof(khui_actions) / sizeof(khui_action); + +EOS + +close INF; +close OUF; diff --git a/src/windows/identity/ui/netidmgr.exe.manifest.i386 b/src/windows/identity/ui/netidmgr.exe.manifest.i386 new file mode 100644 index 0000000000..5e83258c4f --- /dev/null +++ b/src/windows/identity/ui/netidmgr.exe.manifest.i386 @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<assemblyIdentity + version="1.0.0.0" + processorArchitecture="X86" + name="MIT.NetIDMgr.UI" + type="win32" +/> +<description>Khimaira Credentials Manager</description> +<dependency> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.Windows.Common-Controls" + version="6.0.0.0" + processorArchitecture="X86" + publicKeyToken="6595b64144ccf1df" + language="*" + /> + </dependentAssembly> +</dependency> +</assembly> diff --git a/src/windows/identity/ui/netidmgr.manifest.i386.vc7 b/src/windows/identity/ui/netidmgr.manifest.i386.vc7 new file mode 100644 index 0000000000..5e83258c4f --- /dev/null +++ b/src/windows/identity/ui/netidmgr.manifest.i386.vc7 @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<assemblyIdentity + version="1.0.0.0" + processorArchitecture="X86" + name="MIT.NetIDMgr.UI" + type="win32" +/> +<description>Khimaira Credentials Manager</description> +<dependency> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.Windows.Common-Controls" + version="6.0.0.0" + processorArchitecture="X86" + publicKeyToken="6595b64144ccf1df" + language="*" + /> + </dependentAssembly> +</dependency> +</assembly> diff --git a/src/windows/identity/ui/netidmgr.manifest.i386.vc7.debug b/src/windows/identity/ui/netidmgr.manifest.i386.vc7.debug new file mode 100644 index 0000000000..5e83258c4f --- /dev/null +++ b/src/windows/identity/ui/netidmgr.manifest.i386.vc7.debug @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<assemblyIdentity + version="1.0.0.0" + processorArchitecture="X86" + name="MIT.NetIDMgr.UI" + type="win32" +/> +<description>Khimaira Credentials Manager</description> +<dependency> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.Windows.Common-Controls" + version="6.0.0.0" + processorArchitecture="X86" + publicKeyToken="6595b64144ccf1df" + language="*" + /> + </dependentAssembly> +</dependency> +</assembly> diff --git a/src/windows/identity/ui/netidmgr.manifest.i386.vc8 b/src/windows/identity/ui/netidmgr.manifest.i386.vc8 new file mode 100644 index 0000000000..84d91a339e --- /dev/null +++ b/src/windows/identity/ui/netidmgr.manifest.i386.vc8 @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<assemblyIdentity + version="1.0.0.0" + processorArchitecture="X86" + name="MIT.NetIDMgr.UI" + type="win32" +/> +<description>Khimaira Credentials Manager</description> +<dependency> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.Windows.Common-Controls" + version="6.0.0.0" + processorArchitecture="X86" + publicKeyToken="6595b64144ccf1df" + language="*" + /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.VC80.DebugCRT" + version="8.0.50215.4652" + processorArchitecture="x86" + publicKeyToken="1fc8b3b9a1e18e3b" + /> + </dependentAssembly> +</dependency> +</assembly> diff --git a/src/windows/identity/ui/netidmgr.manifest.i386.vc8.debug b/src/windows/identity/ui/netidmgr.manifest.i386.vc8.debug new file mode 100644 index 0000000000..84d91a339e --- /dev/null +++ b/src/windows/identity/ui/netidmgr.manifest.i386.vc8.debug @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<assemblyIdentity + version="1.0.0.0" + processorArchitecture="X86" + name="MIT.NetIDMgr.UI" + type="win32" +/> +<description>Khimaira Credentials Manager</description> +<dependency> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.Windows.Common-Controls" + version="6.0.0.0" + processorArchitecture="X86" + publicKeyToken="6595b64144ccf1df" + language="*" + /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.VC80.DebugCRT" + version="8.0.50215.4652" + processorArchitecture="x86" + publicKeyToken="1fc8b3b9a1e18e3b" + /> + </dependentAssembly> +</dependency> +</assembly> diff --git a/src/windows/identity/ui/newcredwnd.c b/src/windows/identity/ui/newcredwnd.c new file mode 100644 index 0000000000..4b6ce08bf3 --- /dev/null +++ b/src/windows/identity/ui/newcredwnd.c @@ -0,0 +1,1694 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +ATOM khui_newcredwnd_cls; + +/* forward dcl */ +static void +nc_position_credtext(khui_nc_wnd_data * d); + +/* Common dialog procedure. Be careful. This is used by more than + one dialog. */ +static INT_PTR CALLBACK +nc_common_dlg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) { + case WM_INITDIALOG: + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, lParam); +#pragma warning(pop) + + return TRUE; + + case WM_COMMAND: + { + int ctrl_id; + + ctrl_id = LOWORD(wParam); + if (ctrl_id < KHUI_CW_ID_MIN || + ctrl_id > KHUI_CW_ID_MAX) { + /* pump it to the parent */ + PostMessage(GetParent(hwnd), WM_COMMAND, wParam, lParam); + return TRUE; + } /* else we allow the message to fall through and get + passed into the identity provider's message + handler. */ + } + break; + +#if 0 + /* someday this will be used to draw custom tab buttons. But + that's not today */ + case WM_DRAWITEM: + { + khui_nc_wnd_data * d; + int id; + LPDRAWITEMSTRUCT ds; + + d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + id = wParam; + ds = (LPDRAWITEMSTRUCT) lParam; + + if(id >= NC_TS_CTRL_ID_MIN && id <= NC_TS_CTRL_ID_MAX) { + /*TODO: custom draw the buttons */ + } + else + return FALSE; + } + break; +#endif + + case KHUI_WM_NC_NOTIFY: + { + khui_nc_wnd_data * d; + d = (khui_nc_wnd_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + /* message sent by parent to notify us of something */ + switch(HIWORD(wParam)) { + case WMNC_DIALOG_EXPAND: + if(hwnd == d->dlg_main) { + HWND hw; + + if(hw = GetDlgItem(hwnd, IDOK)) + ShowWindow(hw, SW_HIDE); + if(hw = GetDlgItem(hwnd, IDCANCEL)) + ShowWindow(hw, SW_HIDE); + if(hw = GetDlgItem(hwnd, IDC_NC_OPTIONS)) + ShowWindow(hw, SW_HIDE); + + d->r_credtext.bottom = d->r_area.bottom; + + nc_position_credtext(d); + + return TRUE; + } + } + } + return TRUE; + } + + /* check if we have a wnd_data, and if so pass the message on to + the identity provider callback. */ + { + khui_nc_wnd_data * d; + + d = (khui_nc_wnd_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); + } + } + + return FALSE; +} + +static void +nc_position_credtext(khui_nc_wnd_data * d) +{ + HWND hw; + + hw = GetDlgItem(d->dlg_main, IDC_NC_CREDTEXT); +#ifdef DEBUG + assert(hw); +#endif + + if (d->r_credtext.bottom < d->r_credtext.top + d->r_row.bottom * 2) { + /* not enough room */ + if (d->nc->mode == KHUI_NC_MODE_MINI && + d->nc->subtype != KMSG_CRED_PASSWORD) { + PostMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_EXPAND), 0); + return; + } else { + ShowWindow(hw, SW_HIDE); + return; + } + } else { + ShowWindow(hw, SW_SHOW); + } + + SetWindowPos(hw, NULL, + d->r_credtext.left + d->r_n_input.left, /* x */ + d->r_credtext.top, /* y */ + d->r_n_input.right - d->r_n_input.left, /* width */ + d->r_credtext.bottom - d->r_credtext.top, /* height */ + SWP_NOACTIVATE | SWP_NOOWNERZORDER | + SWP_NOZORDER); + + hw = GetDlgItem(d->dlg_main, IDC_NC_CREDTEXT_LABEL); + + SetWindowPos(hw, NULL, + d->r_credtext.left + d->r_n_label.left, /* x */ + d->r_credtext.top, /* y */ + d->r_n_label.right - d->r_n_label.left, /* width */ + d->r_n_label.bottom - d->r_n_label.top, /* height */ + SWP_NOACTIVATE | SWP_NOOWNERZORDER | + SWP_NOZORDER); +} + +/* sorts tab buttons */ +static int __cdecl +nc_tab_sort_func(const void * v1, const void * v2) +{ + /* v1 and v2 and of type : khui_new_creds_by_type ** */ + khui_new_creds_by_type *t1, *t2; + + t1 = *((khui_new_creds_by_type **) v1); + t2 = *((khui_new_creds_by_type **) v2); + + if(t1->ordinal > 0) { + if(t2->ordinal > 0) { + if(t1->ordinal == t2->ordinal) + return wcscmp(t1->name, t2->name); + else + /* safe to convert to an int here */ + return (int) (t1->ordinal - t2->ordinal); + } else + return -1; + } else { + if(t2->ordinal > 0) + return 1; + else if (t1->name && t2->name) + return wcscmp(t1->name, t2->name); + else + return 0; + } +} + +static void +nc_notify_types_async(khui_new_creds * c, UINT uMsg, + WPARAM wParam, LPARAM lParam) +{ + khm_size i; + + for(i=0; i<c->n_types; i++) { + PostMessage(c->types[i]->hwnd_panel, uMsg, wParam, lParam); + } +} + +static void +nc_notify_types(khui_new_creds * c, UINT uMsg, + WPARAM wParam, LPARAM lParam) +{ + khm_size i; + + for(i=0; i<c->n_types; i++) { + SendMessage(c->types[i]->hwnd_panel, uMsg, wParam, lParam); + } +} + +#define NC_MAXCCH_CREDTEXT 16384 +#define NC_MAXCB_CREDTEXT (NC_MAXCCH_CREDTEXT * sizeof(wchar_t)) + +static void +nc_update_credtext(khui_nc_wnd_data * d) +{ + wchar_t * ctbuf = NULL; + wchar_t * buf; + BOOL okEnable = FALSE; + BOOL validId = FALSE; + HWND hw = NULL; + size_t cch = 0; + + ctbuf = malloc(NC_MAXCB_CREDTEXT); + + assert(ctbuf != NULL); + + LoadString(khm_hInstance, IDS_NC_CREDTEXT_TABS, ctbuf, NC_MAXCCH_CREDTEXT); + StringCchLength(ctbuf, NC_MAXCCH_CREDTEXT, &cch); + buf = ctbuf + cch; + nc_notify_types(d->nc, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0); + + /* hopefully all the types have updated their credential texts */ + if(d->nc->n_identities == 1) { + wchar_t main_fmt[256]; + wchar_t id_fmt[256]; + wchar_t id_name[KCDB_IDENT_MAXCCH_NAME]; + wchar_t id_string[KCDB_IDENT_MAXCCH_NAME + 256]; + khm_size cbbuf; + khm_int32 flags; + + + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_ONE, + main_fmt, (int) ARRAYLENGTH(main_fmt)); + + cbbuf = sizeof(id_name); + kcdb_identity_get_name(d->nc->identities[0], id_name, &cbbuf); + + kcdb_identity_get_flags(d->nc->identities[0], &flags); + if (flags & KCDB_IDENT_FLAG_INVALID) { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_INVALID, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } else if(flags & KCDB_IDENT_FLAG_VALID) { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_VALID, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } else if(d->nc->subtype == KMSG_CRED_NEW_CREDS) { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_CHECKING, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } else { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } + + StringCbPrintf(id_string, sizeof(id_string), id_fmt, id_name); + + StringCbPrintf(buf, NC_MAXCB_CREDTEXT - cch*sizeof(wchar_t), + main_fmt, id_string); + + } else if(d->nc->n_identities > 1) { + wchar_t *ids_string; + khm_size cb_ids_string; + + wchar_t id_name[KCDB_IDENT_MAXCCH_NAME]; + wchar_t id_fmt[256]; + wchar_t id_string[KCDB_IDENT_MAXCCH_NAME + 256]; + + wchar_t main_fmt[256]; + khm_size cbbuf; + + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_MANY, + main_fmt, (int) ARRAYLENGTH(main_fmt)); + + /* we are going to concatenate all the identity names into + a comma separated string */ + + /* d->nc->n_identities is at least 2 */ + ids_string = malloc((KCDB_IDENT_MAXCB_NAME + sizeof(id_fmt)) * + (d->nc->n_identities - 1)); + cb_ids_string = + (KCDB_IDENT_MAXCB_NAME + sizeof(id_fmt)) * + (d->nc->n_identities - 1); + + assert(ids_string != NULL); + + ids_string[0] = 0; + + { + khm_size i; + khm_int32 flags; + + for(i=1; i<d->nc->n_identities; i++) { + if(i>1) { + StringCbCat(ids_string, cb_ids_string, L","); + } + + flags = 0; + + cbbuf = sizeof(id_name); + kcdb_identity_get_name(d->nc->identities[i], id_name, &cbbuf); + kcdb_identity_get_flags(d->nc->identities[i], &flags); + if(flags & KCDB_IDENT_FLAG_INVALID) { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_INVALID, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } else if(flags & KCDB_IDENT_FLAG_VALID) { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_VALID, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } else { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } + + StringCbPrintf(id_string, sizeof(id_string), id_fmt, id_name); + StringCbCat(ids_string, cb_ids_string, id_string); + } + + cbbuf = sizeof(id_name); + kcdb_identity_get_name(d->nc->identities[0], id_name, &cbbuf); + kcdb_identity_get_flags(d->nc->identities[0], &flags); + if(flags & KCDB_IDENT_FLAG_INVALID) { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_INVALID, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } else if(flags & KCDB_IDENT_FLAG_VALID) { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_VALID, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } else { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } + StringCbPrintf(id_string, sizeof(id_string), id_fmt, id_name); + + StringCbPrintf(buf, NC_MAXCB_CREDTEXT - cch*sizeof(wchar_t), + main_fmt, id_string, ids_string); + + free(ids_string); + } + } else { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_NONE, + buf, (int)(NC_MAXCCH_CREDTEXT - cch)); + } + + /* now, append the credtext string from each of the cred types */ + { + khm_size i; + size_t cb; + wchar_t * buf; + + cb = NC_MAXCB_CREDTEXT; + buf = ctbuf; + + for(i=0; i<d->nc->n_types; i++) { + if(d->nc->types[i]->credtext != NULL) { + StringCbCatEx(buf, cb, + d->nc->types[i]->credtext, + &buf, &cb, + 0); + } + } + } + + SetDlgItemText(d->dlg_main, IDC_NC_CREDTEXT, ctbuf); + + free(ctbuf); + + /* so depending on whether the primary identity was found to be + invalid, we need to disable the Ok button and set the title to + reflect this */ + + if(d->nc->n_identities > 0) { + khm_int32 flags = 0; + + if(KHM_SUCCEEDED(kcdb_identity_get_flags(d->nc->identities[0], + &flags)) && + (flags & KCDB_IDENT_FLAG_VALID)) { + validId = TRUE; + } + } + + if (d->nc->window_title == NULL) { + if(validId) { + wchar_t wpostfix[256]; + wchar_t wtitle[KCDB_IDENT_MAXCCH_NAME + 256]; + khm_size cbsize; + + cbsize = sizeof(wtitle); + kcdb_identity_get_name(d->nc->identities[0], wtitle, &cbsize); + + if (d->nc->subtype == KMSG_CRED_PASSWORD) + LoadString(khm_hInstance, IDS_WTPOST_PASSWORD, + wpostfix, (int) ARRAYLENGTH(wpostfix)); + else + LoadString(khm_hInstance, IDS_WTPOST_NEW_CREDS, + wpostfix, (int) ARRAYLENGTH(wpostfix)); + + StringCbCat(wtitle, sizeof(wtitle), wpostfix); + + SetWindowText(d->nc->hwnd, wtitle); + } else { + wchar_t wtitle[256]; + + if (d->nc->subtype == KMSG_CRED_PASSWORD) + LoadString(khm_hInstance, IDS_WT_PASSWORD, + wtitle, (int) ARRAYLENGTH(wtitle)); + else + LoadString(khm_hInstance, IDS_WT_NEW_CREDS, + wtitle, (int) ARRAYLENGTH(wtitle)); + + SetWindowText(d->nc->hwnd, wtitle); + } + } + + if(validId || d->nc->subtype == KMSG_CRED_PASSWORD) { + /* TODO: check if all the required fields have valid values + before enabling the Ok button */ + okEnable = TRUE; + } + + hw = GetDlgItem(d->dlg_main, IDOK); + EnableWindow(hw, okEnable); + hw = GetDlgItem(d->dlg_bb, IDOK); + EnableWindow(hw, okEnable); +} + +#define CW_PARAM DWLP_USER + +static LRESULT +nc_handle_wm_create(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + LPCREATESTRUCT lpc; + khui_new_creds * c; + khui_nc_wnd_data * ncd; + int x, y; + int width, height; + RECT r; + + lpc = (LPCREATESTRUCT) lParam; + + ncd = malloc(sizeof(*ncd)); + ZeroMemory(ncd, sizeof(*ncd)); + + c = (khui_new_creds *) lpc->lpCreateParams; + ncd->nc = c; + c->hwnd = hwnd; + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, CW_PARAM, (LONG_PTR) ncd); +#pragma warning(pop) + + /* first try to create the main dialog panel */ + + assert(c->subtype == KMSG_CRED_NEW_CREDS || + c->subtype == KMSG_CRED_PASSWORD); + + ncd->dlg_main = CreateDialogParam(khm_hInstance, + MAKEINTRESOURCE(IDD_NC_PASSWORD), + hwnd, + nc_common_dlg_proc, + (LPARAM) ncd); +#ifdef DEBUG + assert(ncd->dlg_main); +#endif + + { + RECT r_main; + RECT r_area; + RECT r_row; + HWND hw; + + /* pick out metrics for use by the custom prompter stuff */ + GetWindowRect(ncd->dlg_main, &r_main); + + hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_PANEL); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r_area); + OffsetRect(&r_area,-r_main.left, -r_main.top); + CopyRect(&ncd->r_area, &r_area); + + hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_ROW); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + CopyRect(&r_row, &r); + OffsetRect(&r,-r.left, -r.top); + CopyRect(&ncd->r_row, &r); + + hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_LABEL); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + OffsetRect(&r,-r_row.left, -r_row.top); + CopyRect(&ncd->r_n_label, &r); + + hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_INPUT); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + OffsetRect(&r, -r_row.left, -r_row.top); + CopyRect(&ncd->r_n_input, &r); + + hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_ROW_LG); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r_row); + + hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_LABEL_LG); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + OffsetRect(&r, -r_row.left, -r_row.top); + CopyRect(&ncd->r_e_label, &r); + + hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_INPUT_LG); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + OffsetRect(&r, -r_row.left, -r_row.top); + CopyRect(&ncd->r_e_input, &r); + + CopyRect(&ncd->r_credtext, &ncd->r_area); + CopyRect(&ncd->r_idspec, &ncd->r_area); + + ncd->r_idspec.bottom = ncd->r_idspec.top; + + hw = GetDlgItem(ncd->dlg_main, IDC_NC_CREDTEXT); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + OffsetRect(&r, -r_main.left, -r_main.top); + ncd->r_credtext.bottom = r.bottom; + } + + /* if the mode is 'mini'*/ + r.left = 0; + r.top = 0; + if(c->mode == KHUI_NC_MODE_MINI) { + r.right = NCDLG_WIDTH; + r.bottom = NCDLG_HEIGHT; + } else { + r.right = NCDLG_WIDTH + NCDLG_BBAR_WIDTH; + r.bottom = NCDLG_HEIGHT + NCDLG_TAB_HEIGHT; + } + + MapDialogRect(ncd->dlg_main, &r); + + ncd->r_main.left = 0; + ncd->r_main.top = 0; + ncd->r_main.right = NCDLG_WIDTH; + ncd->r_main.bottom = NCDLG_HEIGHT; + + ncd->r_ts.left = 0; + ncd->r_ts.top = ncd->r_main.bottom; + ncd->r_ts.right = ncd->r_main.right; + ncd->r_ts.bottom = ncd->r_ts.top + NCDLG_TAB_HEIGHT; + + ncd->r_bb.left = ncd->r_main.right; + ncd->r_bb.top = 0; + ncd->r_bb.right = ncd->r_bb.left + NCDLG_BBAR_WIDTH; + ncd->r_bb.bottom = ncd->r_ts.bottom; + + MapDialogRect(ncd->dlg_main, &(ncd->r_main)); + MapDialogRect(ncd->dlg_main, &(ncd->r_ts)); + MapDialogRect(ncd->dlg_main, &(ncd->r_bb)); + + /* center the new creds window over the main NetIDMgr window */ + width = r.right - r.left; + height = r.bottom - r.top; + + /* adjust width and height to accomodate NC area */ + { + RECT wr,cr; + + GetWindowRect(hwnd, &wr); + GetClientRect(hwnd, &cr); + + /* the non-client and client areas have already been calculated + at this point. We just use the difference to adjust the width + and height */ + width += (wr.right - wr.left) - (cr.right - cr.left); + height += (wr.bottom - wr.top) - (cr.bottom - cr.top); + } + + GetWindowRect(lpc->hwndParent, &r); + x = (r.right + r.left)/2 - width / 2; + y = (r.top + r.bottom)/2 - height / 2; + + MoveWindow(hwnd, x, y, width, height, FALSE); + + SetWindowPos(ncd->dlg_main, + NULL, + ncd->r_main.left, + ncd->r_main.top, + ncd->r_main.right - ncd->r_main.left, + ncd->r_main.bottom - ncd->r_main.top, + SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOOWNERZORDER | + SWP_NOREDRAW | SWP_NOZORDER); + + /* IDD_NC_BBAR is the button bar that sits on the right of the + dialog when the new creds window is in 'expanded' mode. */ + + ncd->dlg_bb = CreateDialogParam(khm_hInstance, + MAKEINTRESOURCE(IDD_NC_BBAR), + hwnd, + nc_common_dlg_proc, + (LPARAM) ncd); + +#ifdef DEBUG + assert(ncd->dlg_bb); +#endif + + SetWindowPos(ncd->dlg_bb, + NULL, + ncd->r_bb.left, + ncd->r_bb.top, + ncd->r_bb.right - ncd->r_bb.left, + ncd->r_bb.bottom - ncd->r_bb.top, + SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOOWNERZORDER | + SWP_NOREDRAW | SWP_NOZORDER); + + /* IDD_NC_TS is the tab strip that sits below the main panel when + the new creds window is in 'expanded' mode */ + + ncd->dlg_ts = CreateDialogParam(khm_hInstance, + MAKEINTRESOURCE(IDD_NC_TS), + hwnd, + nc_common_dlg_proc, + (LPARAM) ncd); + +#ifdef DEBUG + assert(ncd->dlg_ts); +#endif + + SetWindowPos(ncd->dlg_ts, + NULL, + ncd->r_ts.left, + ncd->r_ts.top, + ncd->r_ts.right - ncd->r_ts.left, + ncd->r_ts.bottom - ncd->r_ts.top, + SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOOWNERZORDER | + SWP_NOREDRAW | SWP_NOZORDER); + + if(c->mode == KHUI_NC_MODE_MINI) { + /* hide and show stuff */ + ShowWindow(ncd->dlg_main, SW_SHOW); + ShowWindow(ncd->dlg_bb, SW_HIDE); + ShowWindow(ncd->dlg_ts, SW_HIDE); + + nc_position_credtext(ncd); + } else { + /* hide and show stuff */ + ShowWindow(ncd->dlg_main, SW_SHOW); + ShowWindow(ncd->dlg_bb, SW_SHOW); + ShowWindow(ncd->dlg_ts, SW_SHOW); + + PostMessage(ncd->dlg_main, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_EXPAND), 0); + } + + /* Call the identity provider callback to set the identity + selector controls */ + c->ident_cb(c, WMNC_IDENT_INIT, NULL, 0, 0, (LPARAM) ncd->dlg_main); + + /* we defer the creation of the tab buttons for later */ + + /* add this to the dialog chain */ + khm_add_dialog(hwnd); + + return TRUE; +} + +static void +nc_add_control_row(khui_nc_wnd_data * d, + HWND label, + HWND input, + khui_control_size size) +{ + RECT r_row; + RECT r_label; + RECT r_input; + HFONT hf; + + hf = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0); + SendMessage(label, WM_SETFONT, (WPARAM) hf, FALSE); + SendMessage(input, WM_SETFONT, (WPARAM) hf, FALSE); + + CopyRect(&r_row, &d->r_row); + OffsetRect(&r_row, d->r_idspec.left, d->r_idspec.bottom); + + if (size == KHUI_CTRLSIZE_SMALL) { + CopyRect(&r_label, &d->r_n_label); + CopyRect(&r_input, &d->r_n_input); + OffsetRect(&r_label, r_row.left, r_row.top); + OffsetRect(&r_input, r_row.left, r_row.top); + } else if (size == KHUI_CTRLSIZE_HALF) { + CopyRect(&r_label, &d->r_e_label); + CopyRect(&r_input, &d->r_e_input); + OffsetRect(&r_label, r_row.left, r_row.top); + OffsetRect(&r_input, r_row.left, r_row.top); + } else if (size == KHUI_CTRLSIZE_FULL) { + CopyRect(&r_label, &d->r_n_label); + r_label.right = d->r_row.right; + CopyRect(&r_input, &d->r_n_input); + OffsetRect(&r_input, r_row.left, r_row.top); + OffsetRect(&r_input, 0, r_input.bottom); + r_row.bottom += r_input.bottom; + OffsetRect(&r_label, r_row.left, r_row.top); + } else { +#ifdef DEBUG + assert(FALSE); +#else + return; +#endif + } + + SetWindowPos(label, + ((d->hwnd_last_idspec != NULL)? + d->hwnd_last_idspec: + HWND_TOP), + r_label.left, r_label.top, + r_label.right - r_label.left, + r_label.bottom - r_label.top, + SWP_DEFERERASE | SWP_NOACTIVATE | + SWP_NOOWNERZORDER); + + SetWindowPos(input, + label, + r_input.left, r_input.top, + r_input.right - r_input.left, + r_input.bottom - r_input.top, + SWP_DEFERERASE | SWP_NOACTIVATE | + SWP_NOOWNERZORDER); + + d->hwnd_last_idspec = input; + + d->r_idspec.bottom = r_row.bottom; + + d->r_credtext.top = r_row.bottom; + + nc_position_credtext(d); +} + + +static LRESULT +nc_handle_wm_destroy(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + khui_nc_wnd_data * d; + khm_size i; + + /* remove self from dialog chain */ + khm_del_dialog(hwnd); + + d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM); + + d->nc->ident_cb(d->nc, WMNC_IDENT_EXIT, NULL, 0, 0, 0); + + if(d->hwnd_tc_main) + DestroyWindow(d->hwnd_tc_main); + for(i=0;i<d->nc->n_types;i++) { + if(d->nc->types[i]->hwnd_tc) { + DestroyWindow(d->nc->types[i]->hwnd_tc); + d->nc->types[i]->hwnd_tc = NULL; + } + } + + if(d->dlg_bb) + DestroyWindow(d->dlg_bb); + if(d->dlg_main) + DestroyWindow(d->dlg_main); + if(d->dlg_ts) + DestroyWindow(d->dlg_ts); + + d->dlg_bb = NULL; + d->dlg_main = NULL; + d->dlg_ts = NULL; + + free(d); + + return TRUE; +} + +static LRESULT +nc_handle_wm_command(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + khui_nc_wnd_data * d; + int id; + + d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM); + + switch(HIWORD(wParam)) { + case BN_CLICKED: + switch(LOWORD(wParam)) { + + case IDOK: + d->nc->result = KHUI_NC_RESULT_GET_CREDS; + + /* fallthrough */ + + case IDCANCEL: + /* the default value for d->nc->result is set to + KHUI_NC_RESULT_CANCEL */ + d->nc->response = 0; + + nc_notify_types(d->nc, + KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_DIALOG_PREPROCESS), + 0); + + khui_cw_sync_prompt_values(d->nc); + + khm_cred_dispatch_process_message(d->nc); + + /* we won't know whether to abort or not until we get + feedback from the plugins, even if the command was + to cancel */ + { + HWND hw; + + hw = GetDlgItem(d->dlg_main, IDOK); + EnableWindow(hw, FALSE); + hw = GetDlgItem(d->dlg_main, IDCANCEL); + EnableWindow(hw, FALSE); + hw = GetDlgItem(d->dlg_bb, IDOK); + EnableWindow(hw, FALSE); + hw = GetDlgItem(d->dlg_bb, IDCANCEL); + EnableWindow(hw, FALSE); + } + return FALSE; + + case IDC_NC_OPTIONS: + /* the Options button in the main window was clicked. we + respond by expanding the dialog. */ + PostMessage(hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_EXPAND), 0); + return FALSE; + + case IDC_NC_CREDTEXT: /* credtext link activated */ + { + khui_htwnd_link * l; + wchar_t sid[KHUI_MAXCCH_HTLINK_FIELD]; + wchar_t sparam[KHUI_MAXCCH_HTLINK_FIELD]; + wchar_t * colon; + + l = (khui_htwnd_link *) lParam; + + /* do we have a valid link? */ + if(l->id == NULL || l->id_len >= ARRAYLENGTH(sid)) + return TRUE; /* nope */ + + StringCchCopyN(sid, ARRAYLENGTH(sid), l->id, l->id_len); + sid[l->id_len] = L'\0'; /* just make sure */ + + if(l->param != NULL && + l->param_len < ARRAYLENGTH(sparam) && + l->param_len > 0) { + + wcsncpy(sparam, l->param, l->param_len); + sparam[l->param_len] = L'\0'; + + } else { + sparam[0] = L'\0'; + } + + /* If the ID is of the form '<credtype>:<link_tag>' + and <credtype> is a valid name of a credentials + type that is participating in the credentials + acquisition process, then we forward the message to + the panel that is providing the UI for that cred + type. We also switch to that panel first. */ + + colon = wcschr(sid, L':'); + if (colon != NULL) { + khm_int32 credtype; + khui_new_creds_by_type * t; + + *colon = L'\0'; + if (KHM_SUCCEEDED(kcdb_credtype_get_id(sid, &credtype)) && + KHM_SUCCEEDED(khui_cw_find_type(d->nc, credtype, &t))){ + *colon = L':'; + + if (t->ordinal != d->ctab) + PostMessage(hwnd, + KHUI_WM_NC_NOTIFY, + MAKEWPARAM(t->ordinal, + WMNC_DIALOG_SWITCH_PANEL), + 0); + + return SendMessage(t->hwnd_panel, + KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_CREDTEXT_LINK), + lParam); + } + } + + /* if it was for us, then we need to process the message */ + if(!wcsicmp(sid, CTLINKID_SWITCH_PANEL)) { + khm_int32 credtype; + khui_new_creds_by_type * t; + + if (KHM_SUCCEEDED(kcdb_credtype_get_id(sparam, + &credtype)) && + KHM_SUCCEEDED(khui_cw_find_type(d->nc, + credtype, &t))) { + if (t->ordinal != d->ctab) + PostMessage(hwnd, + KHUI_WM_NC_NOTIFY, + MAKEWPARAM(t->ordinal, + WMNC_DIALOG_SWITCH_PANEL), + 0); + } + } + } + return FALSE; + + default: + /* if one of the tab strip buttons were pressed, then + we should switch to that panel */ + id = LOWORD(wParam); + if(id >= NC_TS_CTRL_ID_MIN && id <= NC_TS_CTRL_ID_MAX) { + id -= NC_TS_CTRL_ID_MIN; + PostMessage(hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(id, WMNC_DIALOG_SWITCH_PANEL),0); + return FALSE; + } + } + break; + } + + return TRUE; +} + +static LRESULT nc_handle_wm_moving(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + khui_nc_wnd_data * d; + + d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM); + + nc_notify_types(d->nc, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_MOVE), 0); + + return FALSE; +} + +static LRESULT nc_handle_wm_nc_notify(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + khui_nc_wnd_data * d; + RECT r; + int width, height; + khm_size id; + + d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM); + + switch(HIWORD(wParam)) { + + case WMNC_DIALOG_SWITCH_PANEL: + id = LOWORD(wParam); + if(id >= 0 && id <= d->nc->n_types) { + /* one of the tab buttons were pressed */ + if(d->ctab == id) { + return TRUE; /* nothign to do */ + } + + if(d->ctab == 0) { + ShowWindow(d->dlg_main, SW_HIDE); + SendMessage(d->hwnd_tc_main, + BM_SETCHECK, BST_UNCHECKED, 0); + } else { + ShowWindow(d->nc->types[d->ctab - 1]->hwnd_panel, SW_HIDE); + SendMessage(d->nc->types[d->ctab - 1]->hwnd_tc, + BM_SETCHECK, BST_UNCHECKED, 0); + } + + d->ctab = id; + + if(d->ctab == 0) { + ShowWindow(d->dlg_main, SW_SHOW); + SendMessage(d->hwnd_tc_main, + BM_SETCHECK, BST_CHECKED, 0); + } else { + ShowWindow(d->nc->types[id - 1]->hwnd_panel, SW_SHOW); + SendMessage(d->nc->types[id - 1]->hwnd_tc, + BM_SETCHECK, BST_CHECKED, 0); + } + } + + if(d->nc->mode == KHUI_NC_MODE_EXPANDED) + return TRUE; + /*else*/ + /* fallthrough */ + + case WMNC_DIALOG_EXPAND: + /* we are expanding the dialog box */ + + /* nothing to do? */ + if (d->nc->mode == KHUI_NC_MODE_EXPANDED) + break; + + d->nc->mode = KHUI_NC_MODE_EXPANDED; + + r.top = 0; + r.left = 0; + r.right = NCDLG_WIDTH + NCDLG_BBAR_WIDTH; + r.bottom = NCDLG_HEIGHT + NCDLG_TAB_HEIGHT; + + MapDialogRect(d->dlg_main, &r); + + width = r.right - r.left; + height = r.bottom - r.top; + + /* adjust width and height to accomodate NC area */ + { + RECT wr,cr; + + GetWindowRect(hwnd, &wr); + GetClientRect(hwnd, &cr); + + /* the non-client and client areas have already been + calculated at this point. We just use the difference + to adjust the width and height */ + width += (wr.right - wr.left) - (cr.right - cr.left); + height += (wr.bottom - wr.top) - (cr.bottom - cr.top); + } + + SendMessage(d->dlg_main, + KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_DIALOG_EXPAND), + 0); + + SetWindowPos(hwnd, + NULL, + 0, 0, + width, height, + SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOOWNERZORDER | + SWP_NOZORDER); + + ShowWindow(d->dlg_bb, SW_SHOW); + ShowWindow(d->dlg_ts, SW_SHOW); + break; + + case WMNC_DIALOG_SETUP: + if(d->nc->n_types > 0) { + khm_size i; + for(i=0; i < d->nc->n_types;i++) { + + if (d->nc->types[i]->dlg_proc == NULL) { + d->nc->types[i]->hwnd_panel = NULL; + } else { + /* Create the dialog panel */ + d->nc->types[i]->hwnd_panel = + CreateDialogParam(d->nc->types[i]->h_module, + d->nc->types[i]->dlg_template, + d->nc->hwnd, + d->nc->types[i]->dlg_proc, + (LPARAM) d->nc); + +#ifdef DEBUG + assert(d->nc->types[i]->hwnd_panel); +#endif + } + } + } + break; + + case WMNC_DIALOG_ACTIVATE: + { + int x,y,width,height; + RECT r; + int id; + wchar_t wbuf[256]; + HFONT hf; + + /* now we create all the tab strip controls */ + r.left = 0; + r.top = 0; + r.right = NCDLG_TAB_WIDTH; + r.bottom = NCDLG_TAB_HEIGHT; + MapDialogRect(d->dlg_main, &r); + + width = r.right - r.left; + height = r.bottom - r.top; + + x = 0; + y = 0; + + id = NC_TS_CTRL_ID_MIN; + + khui_cw_lock_nc(d->nc); + + /* first, the control for the main panel */ + LoadString(khm_hInstance, IDS_NC_IDENTITY, + wbuf, ARRAYLENGTH(wbuf)); + + d->hwnd_tc_main = + CreateWindow(L"BUTTON", + wbuf, + WS_VISIBLE | WS_CHILD | WS_TABSTOP | + BS_PUSHLIKE | BS_CHECKBOX | BS_TEXT, + x,y,width,height, + d->dlg_ts, + (HMENU)(INT_PTR) id, + khm_hInstance, + NULL); + + hf = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0); + SendMessage(d->hwnd_tc_main, WM_SETFONT, (WPARAM) hf, 0); + SendMessage(d->hwnd_tc_main, BM_SETCHECK, BST_CHECKED, 0); + + id++; + x += width; + + if(d->nc->n_types > 0) { + khm_size i; + /* we should sort the tabs first */ + qsort(d->nc->types, + d->nc->n_types, + sizeof(*(d->nc->types)), + nc_tab_sort_func); + + for(i=0; i < d->nc->n_types;i++) { + wchar_t * name; + + d->nc->types[i]->ordinal = i + 1; + + if(d->nc->types[i]->name) + name = d->nc->types[i]->name; + else { + khm_size cbsize; + + if(kcdb_credtype_describe + (d->nc->types[i]->type, + NULL, + &cbsize, + KCDB_TS_SHORT) == KHM_ERROR_TOO_LONG) { + + name = malloc(cbsize); + kcdb_credtype_describe(d->nc->types[i]->type, + name, + &cbsize, + KCDB_TS_SHORT); + } else { +#ifdef DEBUG + assert(FALSE); +#else + continue; +#endif + } + } + + d->nc->types[i]->hwnd_tc = + CreateWindow(L"BUTTON", + name, + WS_VISIBLE | WS_CHILD | WS_TABSTOP | + BS_PUSHLIKE | BS_CHECKBOX | BS_TEXT | + ((d->nc->types[i]->hwnd_panel == NULL)? + WS_DISABLED : 0), + x,y,width,height, + d->dlg_ts, + (HMENU)(INT_PTR) id, + khm_hInstance, + NULL); + + SendMessage(d->nc->types[i]->hwnd_tc, WM_SETFONT, + (WPARAM)hf, 0); + +#if 0 + if(d->nc->types[i]->flags & KHUI_NCT_FLAG_DISABLED) + SendMessage(d->nc->types[i]->hwnd_tc, + BM_SETIMAGE, + IMAGE_ICON, + LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_DISABLED))); + else + SendMessage(d->nc->types[i]->hwnd_tc, + BM_SETIMAGE, + IMAGE_ICON, + LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_ENABLED))); +#endif + + id++; + x += width; + + if(!(d->nc->types[i]->name)) + free(name); + + /* Now set the position of the type panel */ + ShowWindow(d->nc->types[i]->hwnd_panel, SW_HIDE); + SetWindowPos(d->nc->types[i]->hwnd_panel, + NULL, + d->r_main.left, + d->r_main.top, + d->r_main.right - d->r_main.left, + d->r_main.bottom - d->r_main.top, + SWP_DEFERERASE | SWP_NOACTIVATE | + SWP_NOOWNERZORDER | SWP_NOREDRAW | + SWP_NOZORDER); + + } + } + + khui_cw_unlock_nc(d->nc); + + nc_update_credtext(d); + + ShowWindow(hwnd, SW_SHOW); + SetFocus(hwnd); + + if (d->nc->n_identities == 0) + break; + /* else */ + /* fallthrough */ + } + + case WMNC_IDENTITY_CHANGE: + { + BOOL okEnable = FALSE; + + nc_notify_types(d->nc, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_IDENTITY_CHANGE), 0); + nc_update_credtext(d); + } + break; + + case WMNC_TYPE_STATE: + /* fallthrough */ + case WMNC_UPDATE_CREDTEXT: + nc_update_credtext(d); + break; + + case WMNC_CLEAR_PROMPTS: + { + khm_size i; + + khui_cw_lock_nc(d->nc); + + if(d->hwnd_banner != NULL) { + DestroyWindow(d->hwnd_banner); + d->hwnd_banner = NULL; + } + + if(d->hwnd_name != NULL) { + DestroyWindow(d->hwnd_name); + d->hwnd_name = NULL; + } + + for(i=0;i<d->nc->n_prompts;i++) { + if(!(d->nc->prompts[i]->flags & + KHUI_NCPROMPT_FLAG_STOCK)) { + if(d->nc->prompts[i]->hwnd_static != NULL) + DestroyWindow(d->nc->prompts[i]->hwnd_static); + + if(d->nc->prompts[i]->hwnd_edit != NULL) + DestroyWindow(d->nc->prompts[i]->hwnd_edit); + } + + d->nc->prompts[i]->hwnd_static = NULL; + d->nc->prompts[i]->hwnd_edit = NULL; + } + + khui_cw_unlock_nc(d->nc); + + d->r_credtext.top = d->r_idspec.bottom; + + nc_position_credtext(d); + } + break; + + case WMNC_SET_PROMPTS: + { + khm_size i; + int y; + HWND hw, hw_prev; + HFONT hf, hfold; + HDC hdc; + + /* we assume that WMNC_CLEAR_PROMPTS has already been + received */ + + khui_cw_lock_nc(d->nc); + +#if 0 + /* special case, we have one prompt and it is a password + prompt. very common */ + if(d->nc->n_prompts == 1 && + d->nc->prompts[0]->type == KHUI_NCPROMPT_TYPE_PASSWORD) { + + hw = GetDlgItem(d->dlg_main, IDC_NC_PASSWORD); + EnableWindow(hw, TRUE); + + d->nc->prompts[0]->flags |= KHUI_NCPROMPT_FLAG_STOCK; + d->nc->prompts[0]->hwnd_edit = hw; + d->nc->prompts[0]->hwnd_static = NULL; /* don't care */ + + khui_cw_unlock_nc(d->nc); + break; + } +#endif + /* for everything else */ + + /* hide the stock password controls */ +#if 0 + /* TAGREMOVE */ + hw = GetDlgItem(d->dlg_main, IDC_NC_PASSWORD); + ShowWindow(hw, SW_HIDE); + hw = GetDlgItem(d->dlg_main, IDC_NC_PASSWORD_LABEL); + ShowWindow(hw, SW_HIDE); +#endif + + y = d->r_idspec.bottom; + + hf = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0); + + if (d->nc->pname != NULL) { + hw = + CreateWindowEx + (0, + L"STATIC", + d->nc->pname, + SS_SUNKEN | WS_CHILD, + d->r_area.left, y, + d->r_row.right, + d->r_n_label.bottom - d->r_n_label.top, + d->dlg_main, + NULL, + khm_hInstance, + NULL); + +#ifdef DEBUG + assert(hw); +#endif + d->hwnd_name = hw; + SendMessage(hw, WM_SETFONT, (WPARAM)hf, (LPARAM) TRUE); + ShowWindow(hw, SW_SHOW); + + y += d->r_n_label.bottom - d->r_n_label.top; + } + + if (d->nc->banner != NULL) { + hw = + CreateWindowEx + (0, + L"STATIC", + d->nc->banner, + WS_CHILD, + d->r_area.left, y, + d->r_row.right, d->r_row.bottom, + d->dlg_main, + NULL, + khm_hInstance, + NULL); +#ifdef DEBUG + assert(hw); +#endif + d->hwnd_banner = hw; + SendMessage(hw, WM_SETFONT, (WPARAM)hf, (LPARAM)TRUE); + ShowWindow(hw, SW_SHOW); + y += d->r_row.bottom; + } + + hw_prev = d->hwnd_last_idspec; + + hdc = GetWindowDC(d->dlg_main); + hfold = SelectObject(hdc,hf); + + for(i=0; i<d->nc->n_prompts; i++) { + RECT pr, er; + SIZE s; + int dy; + + if(d->nc->prompts[i]->prompt != NULL) { + GetTextExtentPoint32(hdc, + d->nc->prompts[i]->prompt, + (int) wcslen(d->nc->prompts[i]->prompt), + &s); + if(s.cx < d->r_n_label.right - d->r_n_label.left) { + CopyRect(&pr, &d->r_n_label); + CopyRect(&er, &d->r_n_input); + dy = d->r_row.bottom; + } else if(s.cx < + d->r_e_label.right - d->r_e_label.left) { + CopyRect(&pr, &d->r_e_label); + CopyRect(&er, &d->r_e_input); + dy = d->r_row.bottom; + } else { + /* oops. the prompt doesn't fit in our + controls. we need to use up two lines */ + pr.left = 0; + pr.right = d->r_row.right; + pr.top = 0; + pr.bottom = d->r_n_label.bottom - + d->r_n_label.top; + CopyRect(&er, &d->r_n_input); + OffsetRect(&er, 0, pr.bottom); + dy = er.bottom + (d->r_row.bottom - + d->r_n_input.bottom); + } + } else { + SetRectEmpty(&pr); + CopyRect(&er, &d->r_n_input); + dy = d->r_row.bottom; + } + + if(IsRectEmpty(&pr)) { + d->nc->prompts[i]->hwnd_static = NULL; + } else { + OffsetRect(&pr, d->r_area.left, y); + + hw = CreateWindowEx + (0, + L"STATIC", + d->nc->prompts[i]->prompt, + WS_CHILD, + pr.left, pr.top, + pr.right - pr.left, pr.bottom - pr.top, + d->dlg_main, + NULL, + khm_hInstance, + NULL); +#ifdef DEBUG + assert(hw); +#endif + + SendMessage(hw, WM_SETFONT, + (WPARAM) hf, (LPARAM) TRUE); + + SetWindowPos(hw, hw_prev, + 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | + SWP_NOOWNERZORDER | SWP_NOSIZE | + SWP_SHOWWINDOW); + + d->nc->prompts[i]->hwnd_static = hw; + hw_prev = hw; + } + + OffsetRect(&er, d->r_area.left, y); + + hw = CreateWindowEx + (0, + L"EDIT", + (d->nc->prompts[i]->def ? + d->nc->prompts[i]->def : L""), + WS_CHILD | WS_TABSTOP | + WS_BORDER | + ((d->nc->prompts[i]->flags & + KHUI_NCPROMPT_FLAG_HIDDEN)? ES_PASSWORD:0), + er.left, er.top, + er.right - er.left, er.bottom - er.top, + d->dlg_main, + NULL, + khm_hInstance, + NULL); + +#ifdef DEBUG + assert(hw); +#endif + + SendMessage(hw, WM_SETFONT, + (WPARAM) hf, (LPARAM) TRUE); + + SetWindowPos(hw, hw_prev, + 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | + SWP_NOOWNERZORDER | SWP_NOSIZE | + SWP_SHOWWINDOW); + + d->nc->prompts[i]->hwnd_edit = hw; + + hw_prev = hw; + + y += dy; + } + + SelectObject(hdc, hfold); + ReleaseDC(d->dlg_main, hdc); + + khui_cw_unlock_nc(d->nc); + + d->r_credtext.top = y; + + nc_position_credtext(d); + } + break; + + case WMNC_DIALOG_PROCESS_COMPLETE: + { + khui_new_creds * nc; + + nc = d->nc; + + /* reset state */ + nc->result = KHUI_NC_RESULT_CANCEL; + + if(nc->response & KHUI_NC_RESPONSE_NOEXIT) { + HWND hw; + + hw = GetDlgItem(d->dlg_main, IDOK); + EnableWindow(hw, TRUE); + hw = GetDlgItem(d->dlg_main, IDCANCEL); + EnableWindow(hw, TRUE); + hw = GetDlgItem(d->dlg_bb, IDOK); + EnableWindow(hw, TRUE); + hw = GetDlgItem(d->dlg_bb, IDCANCEL); + EnableWindow(hw, TRUE); + + return TRUE; + } + + DestroyWindow(hwnd); + + kmq_post_message(KMSG_CRED, KMSG_CRED_END, 0, (void *) nc); + } + break; + + /* MUST be called with SendMessage */ + case WMNC_ADD_CONTROL_ROW: + { + khui_control_row * row; + + row = (khui_control_row *) lParam; + +#ifdef DEBUG + assert(row->label); + assert(row->input); +#endif + + nc_add_control_row(d, row->label, row->input, row->size); + } + break; + } /* switch(HIWORD(wParam)) */ + + return TRUE; +} + + +static LRESULT CALLBACK nc_window_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) { + case WM_CREATE: + return nc_handle_wm_create(hwnd, uMsg, wParam, lParam); + + case WM_DESTROY: + return nc_handle_wm_destroy(hwnd, uMsg, wParam, lParam); + + case WM_COMMAND: + return nc_handle_wm_command(hwnd, uMsg, wParam, lParam); + + case WM_MOVE: + case WM_MOVING: + return nc_handle_wm_moving(hwnd, uMsg, wParam, lParam); + + case KHUI_WM_NC_NOTIFY: + return nc_handle_wm_nc_notify(hwnd, uMsg, wParam, lParam); + } + + /* Note that this is technically a dialog box */ + return DefDlgProc(hwnd, uMsg, wParam, lParam); +} + +void khm_register_newcredwnd_class(void) +{ + WNDCLASSEX wcx; + + wcx.cbSize = sizeof(wcx); + wcx.style = CS_DBLCLKS | CS_OWNDC; + wcx.lpfnWndProc = nc_window_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((HINSTANCE) NULL, IDC_ARROW); + wcx.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1); + wcx.lpszMenuName = NULL; + wcx.lpszClassName = KHUI_NEWCREDWND_CLASS; + wcx.hIconSm = NULL; + + khui_newcredwnd_cls = RegisterClassEx(&wcx); +} + +void khm_unregister_newcredwnd_class(void) +{ + UnregisterClass((LPWSTR) khui_newcredwnd_cls, khm_hInstance); +} + +HWND khm_create_newcredwnd(HWND parent, khui_new_creds * c) +{ + wchar_t wtitle[256]; + HWND hwnd; + + if (c->window_title == NULL) { + if (c->subtype == KMSG_CRED_PASSWORD) + LoadString(khm_hInstance, + IDS_WT_PASSWORD, + wtitle, + ARRAYLENGTH(wtitle)); + else + LoadString(khm_hInstance, + IDS_WT_NEW_CREDS, + wtitle, + ARRAYLENGTH(wtitle)); + } + + hwnd = CreateWindowEx(WS_EX_DLGMODALFRAME | WS_EX_CONTEXTHELP, + MAKEINTATOM(khui_newcredwnd_cls), + ((c->window_title)?c->window_title: wtitle), + WS_DLGFRAME | WS_POPUPWINDOW | WS_CLIPCHILDREN, + 0,0,400,400, /* bogus values. the window + is going to resize and + reposition itself + anyway */ + parent, + NULL, + khm_hInstance, + (LPVOID) c); + +#ifdef DEBUG + assert(hwnd != NULL); +#endif + + /* note that the window is not visible yet. That's because, at + this point we don't know what the panels are */ + + return hwnd; +} + +void khm_prep_newcredwnd(HWND hwnd) +{ + SendMessage(hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_SETUP), 0); +} + +void khm_show_newcredwnd(HWND hwnd) +{ + /* add all the panels in and prep UI */ + SendMessage(hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_ACTIVATE), 0); +} diff --git a/src/windows/identity/ui/newcredwnd.h b/src/windows/identity/ui/newcredwnd.h new file mode 100644 index 0000000000..d0b6764221 --- /dev/null +++ b/src/windows/identity/ui/newcredwnd.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_NEWCREDWND_H +#define __KHIMAIRA_NEWCREDWND_H + +#include<khuidefs.h> + +#define KHUI_NEWCREDWND_CLASS L"KhmNewCredWnd" + +typedef struct khui_nc_wnd_data_t { + khui_new_creds * nc; + + HWND dlg_main; /* main dialog */ + RECT r_main; + HWND dlg_bb; /* button bar */ + RECT r_bb; + HWND dlg_ts; /* tab strip */ + RECT r_ts; + + khm_size ctab; /* current tab */ + + HWND hwnd_tc_main; /* tab control button for main dialog */ + + HWND hwnd_banner; /* static control for banner */ + HWND hwnd_name; /* static control for name */ + + HWND hwnd_last_idspec; /* last identity specifier control */ + + /* metrics for custom prompts and identity specifiers */ + + RECT r_idspec; /* Area used by identity specifiers + (relative to client) */ + RECT r_row; /* Metrics for a control row + (top=0,left=0,right=width, + bottom=height) */ + RECT r_area; /* Area available for controls (relative + to client) */ + RECT r_n_label; /* coords of the static control (relative + to row) */ + RECT r_n_input; /* coords of the edit control (relative to + row) */ + RECT r_e_label; /* coords of the extended edit control + (relative to row) */ + RECT r_e_input; /* coords of the extended edit control + (relative to row) */ + RECT r_credtext; /* Area for credtext window (relative to + row) */ +} khui_nc_wnd_data; + +void khm_register_newcredwnd_class(void); +void khm_unregister_newcredwnd_class(void); +HWND khm_create_newcredwnd(HWND parent, khui_new_creds * c); +void khm_prep_newcredwnd(HWND hwnd); +void khm_show_newcredwnd(HWND hwnd); + +/* This is the first control ID that is created in the custom tabstrip + control buttons. Subsequent buttons get consecutive IDs starting + from this one. */ +#define NC_TS_CTRL_ID_MIN 8001 + +/* Maximum number of controls */ +#define NC_TS_MAX_CTRLS 8 + +/* Maximum control ID */ +#define NC_TS_CTRL_ID_MAX (NC_TS_CTRL_ID_MIN + NC_TS_MAX_CTRLS - 1) + +/* the first control ID that may be used by an identity provider */ +#define NC_IS_CTRL_ID_MIN 8016 + +/* the maximum number of controls that may be created by an identity + provider*/ +#define NC_IS_CTRL_MAX_CTRLS 8 + +/* the maximum control ID that may be used by an identity provider */ +#define NC_IS_CTRL_ID_MAX (NC_IS_CTRL_ID_MIN + NC_IS_MAX_CTRLS - 1) + +#endif diff --git a/src/windows/identity/ui/notifier.c b/src/windows/identity/ui/notifier.c new file mode 100644 index 0000000000..0ebdbd4cb3 --- /dev/null +++ b/src/windows/identity/ui/notifier.c @@ -0,0 +1,1079 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#define OEMRESOURCE + +#include<khmapp.h> +#include<assert.h> + +#define KHUI_NOTIFIER_CLASS L"KhuiNotifierMsgWindowClass" +#define KHUI_ALERTER_CLASS L"KhuiAlerterWindowClass" + +#define KHUI_NOTIFIER_WINDOW L"KhuiNotifierMsgWindow" + +/* notifier message for notification icon */ +#define KHUI_WM_NOTIFIER WM_COMMAND + +/* 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; + +/* notifier message window */ +HWND hwnd_notifier = NULL; + +BOOL notifier_ready = FALSE; + +khui_alert * current_alert = NULL; + + +/* forward dcls */ +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); + +/********************************************************************** + Notifier +*********************************************************************** + +The notifier is a message only window that listens for notifier +messages. This window will exist for the lifetime of the application +and will use alerter windows as needed to show application alerts. +*/ + +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: + rv = alert_show((khui_alert *) m->vparam); + khui_alert_release((khui_alert *) m->vparam); + 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; + + GetCursorPos(&pt); + + if (khm_is_main_window_visible()) + menu_id = KHUI_MENU_ICO_CTX_NORMAL; + else + menu_id = KHUI_MENU_ICO_CTX_MIN; + + SetForegroundWindow(khm_hwnd_main); + + khm_menu_show_panel(menu_id, pt.x, pt.y); + + PostMessage(khm_hwnd_main, WM_NULL, 0, 0); + } + break; + + case WM_LBUTTONDOWN: + /* we actually wait for the WM_LBUTTONUP before doing + anything */ + break; + + case WM_LBUTTONUP: + /* fall through */ + + case NIN_SELECT: + case NIN_KEYSELECT: + khm_show_main_window(); + break; + + case NIN_BALLOONUSERCLICK: + if (current_alert) { + if ((current_alert->flags & KHUI_ALERT_FLAG_DEFACTION) && + current_alert->n_alert_commands > 0) { + PostMessage(khm_hwnd_main, WM_COMMAND, + MAKEWPARAM(current_alert->alert_commands[0], 0), + 0); + } else if (current_alert->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW) { + khm_show_main_window(); + alert_show_normal(current_alert); + } + } + /* fallthrough */ + case NIN_BALLOONTIMEOUT: + khui_notify_icon_change(KHERR_NONE); + if (current_alert) { + khui_alert_release(current_alert); + current_alert = NULL; + } + 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); + khm_timer_refresh(hwnd); + } + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +ATOM +khui_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_wnd_data { + khui_alert * alert; + + HWND hwnd; + HFONT hfont; + + BOOL metrics_done; + + HWND hwnd_buttons[KHUI_MAX_ALERT_COMMANDS]; + + /* various metrics */ + + /* calculated during WM_CREATE and adjusted during WM_PAINT */ + int dy_message; + int dy_suggestion; + + /* calculated during WM_CREATE */ + int dx_button; + int dy_button; + int dx_button_incr; + int dx_margin; + int dy_margin; + int dy_bb; + int x_message; + int dx_message; + int dx_icon; + int dy_icon; + int dx_suggest_pad; + + /* calculated during WM_CREATE and adjusted during WM_PAINT */ + int dx_client; + int dy_client; + + /* calculated during WM_PAINT */ + int y_message; + int y_suggestion; + + LDCL(struct tag_alerter_wnd_data); +} alerter_wnd_data; + +alerter_wnd_data * khui_alerts = NULL; + +#define NTF_PARAM DWLP_USER + +/* dialog sizes in base dialog units */ + +#define NTF_MARGIN 5 +#define NTF_WIDTH 200 + +#define NTF_BB_HEIGHT 15 + +#define NTF_ICON_X NTF_MARGIN +#define NTF_ICON_WIDTH 20 +#define NTF_ICON_HEIGHT 20 + +#define NTF_MSG_X (NTF_ICON_X + NTF_ICON_WIDTH + NTF_MARGIN) +#define NTF_MSG_WIDTH ((NTF_WIDTH - NTF_MARGIN) - NTF_MSG_X) +#define NTF_MSG_HEIGHT 15 + +#define NTF_SUG_X NTF_MSG_X +#define NTF_SUG_WIDTH NTF_MSG_WIDTH +#define NTF_SUG_HEIGHT NTF_MSG_HEIGHT +#define NTF_SUG_PAD 2 + +#define NTF_BUTTON_X NTF_MSG_X + +#define NTF_BUTTON_WIDTH ((NTF_MSG_WIDTH - 3*NTF_MARGIN) / 4) +#define NTF_BUTTON_XINCR (NTF_BUTTON_WIDTH + NTF_MARGIN) +#define NTF_BUTTON_HEIGHT (NTF_BB_HEIGHT - NTF_MARGIN) + +#define NTF_TIMEOUT 20000 + +static khm_int32 +alert_show_minimized(khui_alert * a) { + wchar_t tbuf[64]; + wchar_t mbuf[256]; + + if (a->message == NULL) + return KHM_ERROR_SUCCESS; + + 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; + + current_alert = a; + khui_alert_hold(a); + + khui_notify_icon_balloon(a->severity, + tbuf, + mbuf, + NTF_TIMEOUT); + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +alert_show_normal(khui_alert * a) { + HWND hwa; + wchar_t buf[256]; + wchar_t * title; + + if(a->title == NULL) { + LoadString(khm_hInstance, IDS_ALERT_DEFAULT, + buf, ARRAYLENGTH(buf)); + title = buf; + } else + title = a->title; + + /* if we don't have any commands, we just add a "close" button */ + if(a->n_alert_commands == 0) { + khui_alert_add_command(a, KHUI_PACTION_CLOSE); + } + + /* we don't need to keep track of the window handle + because the window procedure adds it to the dialog + list automatically */ + + hwa = + CreateWindowEx(WS_EX_DLGMODALFRAME | WS_EX_CONTEXTHELP, + MAKEINTATOM(atom_alerter), + title, + WS_DLGFRAME | WS_POPUPWINDOW | WS_CLIPCHILDREN | + WS_VISIBLE, + 0, 0, 300, 300, // bogus values + khm_hwnd_main, + (HMENU) NULL, + khm_hInstance, + (LPVOID) a); + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +alert_show(khui_alert * a) { + /* the window has already been shown */ + if((a->flags & KHUI_ALERT_FLAG_DISPLAY_WINDOW) || + ((a->flags & KHUI_ALERT_FLAG_DISPLAY_BALLOON) && + !(a->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW))) + return KHM_ERROR_SUCCESS; + + if(a->err_context != NULL || + a->err_event != NULL) { + khui_alert_lock(a); + a->flags |= KHUI_ALERT_FLAG_VALID_ERROR; + khui_alert_unlock(a); + } + + /* depending on the state of the main window, we + need to either show a window or a balloon */ + if(khm_is_main_window_active() && + !(a->flags & KHUI_ALERT_FLAG_REQUEST_BALLOON)) + return alert_show_normal(a); + else + return alert_show_minimized(a); +} + +/* 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: + { + LONG dlgb; + HWND hwnd_parent; + RECT r_parent; + POINT pos; + SIZE s; + LPCREATESTRUCT lpcs; + khui_alert * a; + alerter_wnd_data * d; + + lpcs = (LPCREATESTRUCT) lParam; + a = (khui_alert *) lpcs->lpCreateParams; + khui_alert_hold(a); + + d = malloc(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + + d->alert = a; + d->hwnd = hwnd; + + khui_alert_lock(a); + + a->flags |= KHUI_ALERT_FLAG_DISPLAY_WINDOW; + LPUSH(&khui_alerts, d); + +#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); + + /* now figure out the size and position of the window */ + + hwnd_parent = GetWindow(hwnd, GW_OWNER); + GetWindowRect(hwnd_parent, &r_parent); + + dlgb = GetDialogBaseUnits(); + +#define DLG2SCNX(x) MulDiv((x), LOWORD(dlgb), 4) +#define DLG2SCNY(y) MulDiv((y), HIWORD(dlgb), 8) + + d->dx_margin = DLG2SCNX(NTF_MARGIN); + d->dy_margin = DLG2SCNY(NTF_MARGIN); + + d->x_message = DLG2SCNX(NTF_MSG_X); + d->dx_message = DLG2SCNX(NTF_MSG_WIDTH); + + if (a->message) { + d->dy_message = DLG2SCNY(NTF_MSG_HEIGHT); + } + + if (a->suggestion) { + d->dy_suggestion = DLG2SCNY(NTF_SUG_HEIGHT); + d->dx_suggest_pad = DLG2SCNX(NTF_SUG_PAD); + } + + d->dy_bb = DLG2SCNY(NTF_BB_HEIGHT); + d->dx_button = DLG2SCNX(NTF_BUTTON_WIDTH); + d->dy_button = DLG2SCNY(NTF_BUTTON_HEIGHT); + d->dx_button_incr = DLG2SCNX(NTF_BUTTON_XINCR); + + d->dx_icon = DLG2SCNX(NTF_ICON_WIDTH); + d->dy_icon = DLG2SCNY(NTF_ICON_HEIGHT); + + d->dx_client = DLG2SCNX(NTF_WIDTH); + d->dy_client = max(d->dy_icon, + d->dy_message + + ((d->dy_suggestion > 0)? + (d->dy_suggestion + d->dy_margin): + 0)) + + d->dy_margin * 3 + d->dy_bb; + + /* adjust for client rect */ + s.cx = d->dx_client; + s.cy = d->dy_client; + + { + RECT c_r; + RECT w_r; + + GetWindowRect(hwnd, &w_r); + GetClientRect(hwnd, &c_r); + + s.cx += (w_r.right - w_r.left) - (c_r.right - c_r.left); + s.cy += (w_r.bottom - w_r.top) - (c_r.bottom - c_r.top); + } + + pos.x = (r_parent.left + r_parent.right - s.cx) / 2; + pos.y = (r_parent.top + r_parent.bottom - s.cy) / 2; + + SetWindowPos(hwnd, + HWND_TOP, + pos.x, pos.y, + s.cx, s.cy, + SWP_SHOWWINDOW); + + { + LOGFONT lf; + HDC hdc_dt; + + hdc_dt = GetDC(NULL); + + lf.lfHeight = -MulDiv(8, + GetDeviceCaps(hdc_dt, LOGPIXELSY), + 72); + lf.lfWidth = 0; + lf.lfEscapement = 0; + lf.lfOrientation = 0; + lf.lfWeight = FW_NORMAL; + lf.lfItalic = FALSE; + lf.lfUnderline = FALSE; + lf.lfStrikeOut = FALSE; + 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->hfont = CreateFontIndirect(&lf); + + ReleaseDC(NULL, hdc_dt); + } + + /* create dialog controls now */ + { + int x,y; + int width, height; + int i; + + x = d->x_message; + y = d->dy_client - d->dy_bb; + width = d->dx_button; + height = d->dy_button; + + for(i=0; i<a->n_alert_commands; i++) { + wchar_t caption[256]; + khui_action * action; + HWND hw_button; + + if(a->alert_commands[i] == 0) + continue; + + action = khui_find_action(a->alert_commands[i]); + if(action == NULL) + continue; + + LoadString(khm_hInstance, action->is_caption, + caption, ARRAYLENGTH(caption)); + + hw_button = + CreateWindowEx(0, + L"BUTTON", + caption, + WS_VISIBLE | WS_CHILD, + x,y,width,height, + hwnd, + (HMENU)(INT_PTR) (action->cmd), + khm_hInstance, + NULL); + + SendMessage(hw_button, WM_SETFONT, + (WPARAM) d->hfont, MAKELPARAM(TRUE, 0)); + + d->hwnd_buttons[i] = hw_button; + + x += d->dx_button_incr; + } + } + + khui_notify_icon_change(a->severity); + + khui_alert_unlock(a); + + d->metrics_done = FALSE; + + 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); + + LDELETE(&khui_alerts, d); + + khui_alert_lock(d->alert); + d->alert->flags &= ~KHUI_ALERT_FLAG_DISPLAY_WINDOW; + khui_alert_unlock(d->alert); + + khui_alert_release(d->alert); + + DeleteObject(d->hfont); + + free(d); + + khui_notify_icon_change(KHERR_NONE); + + return TRUE; + } + break; + + case WM_PAINT: + { + RECT r_update; + PAINTSTRUCT ps; + HDC hdc; + LONG dlgb; + alerter_wnd_data * d; + HFONT hf_old; + BOOL need_resize = FALSE; + + if(!GetUpdateRect(hwnd, &r_update, TRUE)) + return FALSE; + + d = (alerter_wnd_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, NTF_PARAM); + + dlgb = GetDialogBaseUnits(); + + hdc = BeginPaint(hwnd, &ps); + + hf_old = SelectFont(hdc, d->hfont); + + khui_alert_lock(d->alert); + + // draw the severity icon + { + HICON hicon; + int x,y; + int iid; + + /* GOINGHERE! If the metrics for the window haven't + been calculated yet, then calculate them. If the + hight needs to be expanded, then do that and wait + for the next repaint cycle. Also move the button + controls down. */ + x = d->dx_margin; + y = d->dy_margin; + + if(d->alert->severity == KHERR_ERROR) + iid = OIC_HAND; + else if(d->alert->severity == KHERR_WARNING) + iid = OIC_BANG; + else + iid = OIC_NOTE; + + hicon = LoadImage(NULL, + MAKEINTRESOURCE(iid), + IMAGE_ICON, + SM_CXICON, SM_CYICON, + LR_SHARED); + + DrawIcon(hdc, x, y, hicon); + } + + // draw the message + if(d->alert->message) { + RECT r; + int width; + int height; + size_t cch; + + r.left = d->x_message; + r.top = d->dy_margin; + width = d->dx_message; + r.right = r.left + width; + height = d->dy_message; + r.bottom = r.top + height; + + StringCchLength(d->alert->message, + KHUI_MAXCCH_MESSAGE, &cch); + + height = DrawText(hdc, + d->alert->message, + (int) cch, + &r, + DT_WORDBREAK | + DT_CALCRECT); + + if (height > d->dy_message) { + d->dy_message = height; + need_resize = TRUE; + } else { + DrawText(hdc, + d->alert->message, + (int) cch, + &r, + DT_WORDBREAK); + } + + d->y_message = r.top; + } + + // and the suggestion + if (d->alert->suggestion) { + RECT r, ro; + int height; + size_t cch; + HICON h_sug_ico; + + r.left = d->x_message; + r.top = d->y_message + d->dy_message + d->dy_margin; + r.right = r.left + d->dx_message; + r.bottom = r.top + d->dy_suggestion; + + CopyRect(&ro, &r); + + // adjust for icon and padding + r.left += SM_CXICON + d->dx_suggest_pad * 2; + r.top += d->dx_suggest_pad; + r.right -= d->dx_suggest_pad; + r.bottom -= d->dx_suggest_pad; + + StringCchLength(d->alert->suggestion, + KHUI_MAXCCH_SUGGESTION, &cch); + + height = DrawText(hdc, + d->alert->suggestion, + (int) cch, + &r, + DT_WORDBREAK | + DT_CALCRECT); + + if (height > d->dy_suggestion) { + d->dy_suggestion = height; + need_resize = TRUE; + } else { + int old_bk_mode; + + ro.bottom = r.bottom + d->dx_suggest_pad; + + FillRect(hdc, &ro, (HBRUSH) (COLOR_INFOBK + 1)); + DrawEdge(hdc, &ro, EDGE_SUNKEN, BF_FLAT | BF_RECT); + + h_sug_ico = + LoadImage(0, + MAKEINTRESOURCE(OIC_INFORMATION), + IMAGE_ICON, + SM_CXICON, SM_CYICON, + LR_SHARED); + + assert(h_sug_ico != NULL); + + DrawIconEx(hdc, + ro.left + d->dx_suggest_pad, + ro.top + d->dx_suggest_pad, + h_sug_ico, + SM_CXICON, SM_CYICON, + 0, NULL, + DI_NORMAL); + + old_bk_mode = SetBkMode(hdc, TRANSPARENT); + + DrawText(hdc, + d->alert->suggestion, + (int) cch, + &r, + DT_WORDBREAK); + + SetBkMode(hdc, old_bk_mode); + } + + d->y_suggestion = r.top; + } + + khui_alert_unlock(d->alert); + + SelectObject(hdc, hf_old); + + EndPaint(hwnd, &ps); + + if (need_resize) { + RECT r; + int x,y; + int width, height; + int i; + + GetClientRect(hwnd, &r); + + height = max(d->dy_icon, + d->dy_message + + ((d->dy_suggestion > 0)? + (d->dy_suggestion + d->dy_margin): + 0)) + + d->dy_margin * 3 + d->dy_bb; + r.bottom = r.top + height; + + d->dy_client = height; + + AdjustWindowRectEx(&r, + GetWindowLongPtr(hwnd, GWL_STYLE), + FALSE, + GetWindowLongPtr(hwnd, GWL_EXSTYLE)); + + SetWindowPos(hwnd, + NULL, + 0, 0, + r.right - r.left, + r.bottom - r.top, + SWP_NOACTIVATE | SWP_NOCOPYBITS | + SWP_NOMOVE | SWP_NOOWNERZORDER | + SWP_NOZORDER); + + x = d->x_message; + y = d->dy_client - d->dy_bb; + width = d->dx_button; + height = d->dy_button; + + for(i=0; i<d->alert->n_alert_commands; i++) { + MoveWindow(d->hwnd_buttons[i], + x,y, + width,height, + TRUE); + + x += d->dx_button_incr; + } + } + + return FALSE; + } + break; /* not reached */ + + case WM_COMMAND: + { + alerter_wnd_data * d; + + d = (alerter_wnd_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, NTF_PARAM); + + if(HIWORD(wParam) == BN_CLICKED) { + khui_alert_lock(d->alert); + d->alert->response = LOWORD(wParam); + khui_alert_unlock(d->alert); + + khm_leave_modal(); + + DestroyWindow(hwnd); + return 0; + } + } + break; + } + + return DefDlgProc(hwnd, uMsg, wParam, lParam); + //return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +ATOM khui_register_alerter_wnd_class(void) +{ + WNDCLASSEX wcx; + + ZeroMemory(&wcx, sizeof(wcx)); + + wcx.cbSize = sizeof(wcx); + wcx.style = CS_DROPSHADOW | CS_OWNDC; + 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_BACKGROUND + 1); + wcx.lpszMenuName = NULL; + wcx.lpszClassName = KHUI_ALERTER_CLASS; + wcx.hIconSm = NULL; + + atom_alerter = RegisterClassEx(&wcx); + + return atom_alerter; +} + +/********************************************************************** + Notification Icon +***********************************************************************/ + +#define KHUI_NOTIFY_ICON_ID 0 + +void khui_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(IDI_NOTIFY_NONE)); + 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); + + ni.cbSize = sizeof(ni); + ni.uVersion = NOTIFYICON_VERSION; + Shell_NotifyIcon(NIM_SETVERSION, &ni); + + DestroyIcon(ni.hIcon); +} + +void +khui_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 = IDI_NOTIFY_NONE; + } + + 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(ELIPSIS)); + StringCchCat(ni.szInfo, ARRAYLENGTH(ni.szInfo), + ELIPSIS); + } + + if (FAILED(StringCbCopy(ni.szInfoTitle, sizeof(ni.szInfoTitle), + title))) { + StringCchCopyN(ni.szInfoTitle, ARRAYLENGTH(ni.szInfoTitle), + title, + ARRAYLENGTH(ni.szInfoTitle) - ARRAYLENGTH(ELIPSIS)); + StringCchCat(ni.szInfoTitle, ARRAYLENGTH(ni.szInfoTitle), + ELIPSIS); + } + ni.uTimeout = timeout; + + Shell_NotifyIcon(NIM_MODIFY, &ni); + + DestroyIcon(ni.hIcon); +} + +void khui_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 = IDI_NOTIFY_NONE; + + 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 khui_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); +} + +/********************************************************************* + Initialization +**********************************************************************/ + +void khui_init_notifier(void) +{ + if(!khui_register_notifier_wnd_class()) + return; + + if(!khui_register_alerter_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; + + khui_notify_icon_add(); + } +#ifdef DEBUG + else { + assert(hwnd_notifier != NULL); + } +#endif + khm_timer_init(); +} + +void khui_exit_notifier(void) +{ + khm_timer_exit(); + + if(hwnd_notifier != NULL) { + khui_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; + } + + notifier_ready = FALSE; +} diff --git a/src/windows/identity/ui/notifier.h b/src/windows/identity/ui/notifier.h new file mode 100644 index 0000000000..bfe9656b89 --- /dev/null +++ b/src/windows/identity/ui/notifier.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_NOTIFIER_H +#define __KHIMAIRA_NOTIFIER_H + +void +khui_init_notifier(void); + +void +khui_exit_notifier(void); + +void +khui_notify_icon_change(khm_int32 severity); + +void +khui_notify_icon_balloon(khm_int32 severity, + wchar_t * title, + wchar_t * msg, + khm_int32 timeout); + +#endif diff --git a/src/windows/identity/ui/passwnd.c b/src/windows/identity/ui/passwnd.c new file mode 100644 index 0000000000..4084ede413 --- /dev/null +++ b/src/windows/identity/ui/passwnd.c @@ -0,0 +1,133 @@ +#include<khmapp.h> + +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 new file mode 100644 index 0000000000..f8c17f68e1 --- /dev/null +++ b/src/windows/identity/ui/passwnd.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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 new file mode 100644 index 0000000000..fe603c0154 --- /dev/null +++ b/src/windows/identity/ui/propertywnd.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +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 = malloc(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 = malloc(cb_buf); + assert(buffer != NULL); + + for(i=0; i<attr_count; i++) { + if(KHM_FAILED(kcdb_buf_get_attr(d->record, 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); + } + + free(attrs); + free(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 = malloc(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); + free(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_BACKGROUND + 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 new file mode 100644 index 0000000000..67250c96d9 --- /dev/null +++ b/src/windows/identity/ui/propertywnd.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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 new file mode 100644 index 0000000000..b73ec4820b --- /dev/null +++ b/src/windows/identity/ui/reqdaemon.c @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +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); + + } + + do { + if (khm_cred_is_in_dialog()) { + khm_cred_wait_for_dialog(INFINITE, NULL); + } + + 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))) + continue; + else { + lr = (result != KHUI_NC_RESULT_GET_CREDS); + break; + } + } while(TRUE); + + if (pdlginfo) + UnmapViewOfFile(pdlginfo); + if (hmap) + CloseHandle(hmap); + + return lr; + } + +#if 0 + /* 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_PARM; + 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_PARM; + 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_PARM; + 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_PARM; + 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; + DWORD dw; + + 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 new file mode 100644 index 0000000000..13b0ebd2c1 --- /dev/null +++ b/src/windows/identity/ui/reqdaemon.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $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 new file mode 100644 index 0000000000..a58cebb8d3 --- /dev/null +++ b/src/windows/identity/ui/resource.h @@ -0,0 +1,313 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by D:\work\khimaira\src\ui\lang\en_us\khapp.rc +// +#define IDI_MAIN_APP 104 +#define IDD_PROPPAGE_MEDIUM 106 +#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_IDENTITY 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_ACTION_NEW_ID 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 IDS_ACTION_DESTROY_ID 119 +#define IDR_MENU_BAR 119 +#define IDS_CFG_ROOT_TITLE 119 +#define IDS_ACTION_RENEW_ID 120 +#define IDS_CFG_GENERAL_SHORT 120 +#define IDS_ACTION_ADD_CRED 121 +#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 IDS_ACTION_OPT_INIT 133 +#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_ACTIONINFO_NEW_ID 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_PASSWORD 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 IDI_WGT_COLLAPSE 150 +#define IDS_WTPOST_INIT_CREDS 150 +#define IDI_WGT_EXPAND 151 +#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 IDD_NC_PASSWORD 162 +#define IDS_PACTION_CLOSE 162 +#define IDD_NC_NEWCRED 162 +#define IDD_NC_BBAR 163 +#define IDS_ALERT_NOSEL_TITLE 163 +#define IDD_NC_TS 164 +#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_ICON1 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 IDS_CFG_IDS_TAB_SHORT 199 +#define IDS_CFG_IDS_TAB_LONG 200 +#define IDS_CFG_IDS_IDENTITY 201 +#define IDS_ACTION_IMPORT 202 +#define IDS_CTX_IMPORT 203 +#define IDS_CFG_PI_COL_PLUGINS 204 +#define IDS_PISTATE_FAILUNK 205 +#define IDS_PISTATE_FAILMAX 206 +#define IDS_PISTATE_FAILREG 207 +#define IDS_PISTATE_FAILDIS 208 +#define IDS_PISTATE_FAILLOD 209 +#define IDS_PISTATE_PLACEHOLD 210 +#define IDS_PISTATE_REG 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 IDC_NC_USERNAME 1007 +#define IDC_NC_PASSWORD 1008 +#define IDC_NC_CREDTEXT_LABEL 1009 +#define IDC_NC_PASSWORD_LABEL 1010 +#define IDC_NC_USERNAME_LABEL 1011 +#define IDC_NC_CREDTEXT 1012 +#define IDC_NC_HELP 1017 +#define IDC_NC_OPTIONS 1019 +#define IDC_PP_IDNAME 1026 +#define IDC_PP_IDDEF 1027 +#define IDC_PP_IDSEARCH 1028 +#define IDC_PP_IDSTATUS 1029 +#define IDC_PP_IDSTATUSIMG 1030 +#define IDC_PP_IDVALID 1031 +#define IDC_PP_IDRENEW 1032 +#define IDC_NC_IDENTITY 1033 +#define IDC_NC_IDENTITY_LABEL 1034 +#define IDC_PP_PROPLIST 1035 +#define IDC_PP_CPROPLIST 1036 +#define IDC_NC_REALM 1037 +#define IDC_NC_REALM_LABEL 1038 +#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_ROW2 1045 +#define IDC_NC_TPL_ROW_LG 1045 +#define IDC_CFG_NODELIST 1045 +#define IDAPPLY 1048 +#define IDC_CFG_SUMMARY 1049 +#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_IDENTS 1071 +#define IDC_CFG_IDENTITY 1072 +#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_PLUGINGRP 1080 +#define IDC_CFG_LBL_DESC 1083 +#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_PROVGRP 1091 +#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_LIST1 1103 +#define IDC_MODULES 1103 +#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 198 +#define _APS_NEXT_COMMAND_VALUE 40010 +#define _APS_NEXT_CONTROL_VALUE 1104 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/windows/identity/ui/statusbar.c b/src/windows/identity/ui/statusbar.c new file mode 100644 index 0000000000..75f520c575 --- /dev/null +++ b/src/windows/identity/ui/statusbar.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> + +khui_statusbar_part khui_statusbar_parts[] = { + {KHUI_SBPART_INFO, 0, KHUI_SB_WTYPE_FILLER}, + {KHUI_SBPART_NOTICE, 40, KHUI_SB_WTYPE_RELATIVE}, + {KHUI_SBPART_LOC, 40, KHUI_SB_WTYPE_ABSOLUTE} +}; + +int khui_n_statusbar_parts = sizeof(khui_statusbar_parts) / sizeof(khui_statusbar_part); + +HWND khui_hwnd_statusbar = NULL; + +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<khui_n_statusbar_parts;i++) { + if(khui_statusbar_parts[i].wtype == KHUI_SB_WTYPE_ABSOLUTE) { + staticwidth += khui_statusbar_parts[i].width; + } else if(khui_statusbar_parts[i].wtype == KHUI_SB_WTYPE_RELATIVE) { + staticwidth += (khui_statusbar_parts[i].width * width) / 100; + } + } + + fillerwidth = width - staticwidth; + + parts = malloc(sizeof(INT) * khui_n_statusbar_parts); + + lastx = 0; + for(i=0;i<khui_n_statusbar_parts;i++) { + int w; + switch(khui_statusbar_parts[i].wtype) { + case KHUI_SB_WTYPE_ABSOLUTE: + w = khui_statusbar_parts[i].width; + break; + + case KHUI_SB_WTYPE_RELATIVE: + w = (khui_statusbar_parts[i].width * width) / 100; + break; + + case KHUI_SB_WTYPE_FILLER: + w = fillerwidth; + break; + } + lastx += w; + + if(i==khui_n_statusbar_parts - 1) + parts[i] = -1; + else + parts[i] = lastx; + } + + SendMessage( + khui_hwnd_statusbar, + SB_SETPARTS, + khui_n_statusbar_parts, + (LPARAM) parts); + + free(parts); +} + +void khui_create_statusbar(HWND parent) { + HWND hwsb; + + hwsb = CreateWindowEx( + 0, + STATUSCLASSNAME, + NULL, + SBARS_SIZEGRIP | WS_CHILD | WS_VISIBLE, + 0,0,0,0, + parent, + NULL, + khm_hInstance, + NULL); + + if(!hwsb) + return; + + khui_hwnd_statusbar = hwsb; + + khui_statusbar_set_parts(parent); +} + +void khui_update_statusbar(HWND parent) { + MoveWindow(khui_hwnd_statusbar, 0, 0, 0, 0, TRUE); + khui_statusbar_set_parts(parent); +} + +int sb_find_index(int id) { + int i; + + for(i=0;i<khui_n_statusbar_parts;i++) { + if(khui_statusbar_parts[i].id == id) + return i; + } + + return -1; +} + +void khui_statusbar_set_text(int id, wchar_t * text) { + int idx; + + idx = sb_find_index(id); + if(idx < 0) + return; + + SendMessage( + khui_hwnd_statusbar, + SB_SETTEXT, + idx, + (LPARAM) text); +} + diff --git a/src/windows/identity/ui/statusbar.h b/src/windows/identity/ui/statusbar.h new file mode 100644 index 0000000000..b4f2a6e30f --- /dev/null +++ b/src/windows/identity/ui/statusbar.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_STATUSBAR_H +#define __KHIMAIRA_STATUSBAR_H + +typedef struct khui_statusbar_part_t { + int id; + int width; + int wtype; /* one of KHUI_SB_WTYPE_* */ +} khui_statusbar_part; + +#define KHUI_SB_WTYPE_RELATIVE 1 +#define KHUI_SB_WTYPE_ABSOLUTE 2 +#define KHUI_SB_WTYPE_FILLER 4 + +/* statusbar parts */ +#define KHUI_SBPART_INFO 1 +#define KHUI_SBPART_NOTICE 2 +#define KHUI_SBPART_LOC 3 + +extern HWND khui_hwnd_statusbar; +extern khui_statusbar_part khui_statusbar_parts[]; +extern int khui_n_statusbar_parts; + +void khui_create_statusbar(HWND p); +void khui_update_statusbar(HWND parent); +void khui_statusbar_set_text(int id, wchar_t * text); + +#endif \ No newline at end of file diff --git a/src/windows/identity/ui/timer.c b/src/windows/identity/ui/timer.c new file mode 100644 index 0000000000..bd5b30eff6 --- /dev/null +++ b/src/windows/identity/ui/timer.c @@ -0,0 +1,637 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +/* 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 = malloc(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) + free(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; + __int64 curtime; + __int64 err; + __int64 next_event; + int tmr_count[KHUI_N_TTYPES]; + __int64 tmr_offset[KHUI_N_TTYPES]; + int t; + khm_handle eff_ident = NULL; + khui_timer_type eff_type = 0; /* meaningless */ + int fire_count = 0; + + TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR_SMALL, + (LPFILETIME) &err); + GetSystemTimeAsFileTime((LPFILETIME) &curtime); + 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) { + + t = khui_timers[i].type; + + switch(t) { + case KHUI_TTYPE_ID_RENEW: + 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. */ + 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; + } +#ifdef DEBUG + else { + 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]; + __int64 ft_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, (LPFILETIME) &ft_second); + next_event += ft_second / 2; + + cb = sizeof(wtime); + + FtIntervalToString((LPFILETIME) &next_event, + 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 < ft_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 < ft_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_REQUEST_BALLOON); + khui_alert_show(alert); + khui_alert_release(alert); + } +} + +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) { + int i; + + 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 = malloc(sizeof(*nt) * khui_nc_timers); +#ifdef DEBUG + assert(nt); +#endif + memcpy(nt, khui_timers, sizeof(*nt) * khui_n_timers); + + free(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; + + 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 khm_int32 KHMAPI +tmr_cred_apply_proc(khm_handle cred, void * rock) { + khm_handle ident = NULL; + int mark_idx; + int idx; + __int64 ft_expiry; + __int64 ft_current; + __int64 ft_cred_expiry; + __int64 ft; + __int64 fte; + khm_size cb; + + kcdb_cred_get_identity(cred, &ident); +#ifdef DEBUG + assert(ident); +#endif + + /* now get the expiry */ + cb = sizeof(ft_expiry); + if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_EXPIRE, + NULL, + &ft_expiry, &cb))) + 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 */ + kcdb_identity_release(ident); + return KHM_ERROR_SUCCESS; + } + + /* and the current time */ + GetSystemTimeAsFileTime((LPFILETIME) &ft_current); + + 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); + 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 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 (ft_expiry < ft_current) + /* 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"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) { + TimetToFileTimeInterval(to_renew, (LPFILETIME) &ft); + fte = ft_expiry - ft; + + if (fte > ft_current) { + tmr_update(ident, KHUI_TTYPE_ID_RENEW, fte, ft, 0); + renew_done = TRUE; + } + } + + if (monitor && do_warn && !renew_done) { + TimetToFileTimeInterval(to_warn, (LPFILETIME) &ft); + fte = ft_expiry - ft; + + if (fte > ft_current) + tmr_update(ident, KHUI_TTYPE_ID_WARN, fte, ft, 0); + } + + if (monitor && do_crit && !renew_done) { + TimetToFileTimeInterval(to_crit, (LPFILETIME) &ft); + fte = ft_expiry - ft; + + if (fte > ft_current) + tmr_update(ident, KHUI_TTYPE_ID_CRIT, fte, ft, 0); + } + + if (monitor && !renew_done) { + if (ft_expiry > ft_current) + tmr_update(ident, KHUI_TTYPE_ID_EXP, ft_expiry, 0, 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))) + goto _cleanup; + + TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR, (LPFILETIME) &ft); + + if (ft_cred_expiry >= ft_expiry || + (ft_expiry - ft_cred_expiry) < ft) + goto _cleanup; + + if ((idx = tmr_find(ident, KHUI_TTYPE_ID_WARN, 0, 0)) >= 0 && + !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { + + fte = ft_cred_expiry - khui_timers[idx].offset; + if (fte > ft_current) { + tmr_update(cred, KHUI_TTYPE_CRED_WARN, fte, + khui_timers[idx].offset, 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 = ft_cred_expiry - khui_timers[idx].offset; + if (fte > ft_current) { + tmr_update(cred, KHUI_TTYPE_CRED_CRIT, fte, + khui_timers[idx].offset, 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)) { + + fte = ft_cred_expiry - khui_timers[idx].offset; + if (fte > ft_current) { + tmr_update(cred, KHUI_TTYPE_CRED_RENEW, fte, + khui_timers[idx].offset, 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 (ft_cred_expiry > ft_current) { + tmr_update(cred, KHUI_TTYPE_CRED_EXP, ft_cred_expiry, + 0, 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; +} + +void +khm_timer_refresh(HWND hwnd) { + int i; + __int64 next_event = 0; + __int64 curtime; + __int64 diff; + + EnterCriticalSection(&cs_timers); + + KillTimer(hwnd, KHUI_TRIGGER_TIMER_ID); + + 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; + } + + kcdb_credset_apply(NULL, + tmr_cred_apply_proc, + NULL); + + tmr_purge(); + + _check_next_event: + + next_event = 0; + for (i=0; i < (int) khui_n_timers; i++) { + if (next_event == 0 || + (!(khui_timers[i].flags & KHUI_TE_FLAG_EXPIRED) && + khui_timers[i].type != KHUI_TTYPE_ID_MARK && + next_event > khui_timers[i].expire)) + next_event = khui_timers[i].expire; + } + + if (next_event != 0) { + GetSystemTimeAsFileTime((LPFILETIME) &curtime); + + TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR_SMALL, + (LPFILETIME) &diff); + + if (curtime + diff > next_event) { + tmr_fire_timer(); + goto _check_next_event; + } else { + diff = next_event - curtime; + SetTimer(hwnd, + KHUI_TRIGGER_TIMER_ID, + FtIntervalToMilliseconds((LPFILETIME) &diff), + NULL); + } + } + + LeaveCriticalSection(&cs_timers); +} diff --git a/src/windows/identity/ui/timer.h b/src/windows/identity/ui/timer.h new file mode 100644 index 0000000000..921b9dcc53 --- /dev/null +++ b/src/windows/identity/ui/timer.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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; + + __int64 expire; /* time at which the timer expires */ + __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 new file mode 100644 index 0000000000..d1a84e235b --- /dev/null +++ b/src/windows/identity/ui/toolbar.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +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 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.right - r.left) - + KHUI_TOOLBAR_IMAGE_WIDTH) / 2; + r.top += ((r.bottom - r.top) - + KHUI_TOOLBAR_IMAGE_HEIGHT) / 2; + + 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); + bn.fsStyle |= BTNS_SHOWTEXT; + 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 + bn.iBitmap = I_IMAGENONE; + + 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); + + hwtb = CreateWindowEx( + TBSTYLE_EX_MIXEDBUTTONS, + TOOLBARCLASSNAME, + (LPWSTR) NULL, + WS_CHILD | + TBSTYLE_FLAT | + TBSTYLE_AUTOSIZE | + TBSTYLE_LIST | + CCS_NORESIZE | + CCS_NOPARENTALIGN | + CCS_ADJUSTABLE | + CCS_NODIVIDER, + 0, 0, 0, 0, rebar, + (HMENU) NULL, khm_hInstance, + NULL); + + if(!hwtb) { +#ifdef DEBUG + assert(FALSE); +#else + return; +#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, + 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, + 1, + (LPARAM) &rbi); +} diff --git a/src/windows/identity/ui/toolbar.h b/src/windows/identity/ui/toolbar.h new file mode 100644 index 0000000000..65598debce --- /dev/null +++ b/src/windows/identity/ui/toolbar.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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 1 +#define KHUI_TOOLBAR_ADD_BITMAP 2 +#define KHUI_TOOLBAR_ADD_LONGTEXT 5 +#define KHUI_TOOLBAR_ADD_DROPDOWN 8 +#define KHUI_TOOLBAR_ADD_SEP 16 +#define KHUI_TOOLBAR_VARSIZE 32 + +#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 \ No newline at end of file diff --git a/src/windows/identity/ui/uiconfig.csv b/src/windows/identity/ui/uiconfig.csv new file mode 100644 index 0000000000..eeb44bbd38 --- /dev/null +++ b/src/windows/identity/ui/uiconfig.csv @@ -0,0 +1,111 @@ +Name,Type,Value,Description +CredWindow,KC_SPACE,0,Options for the credentials window + AutoInit,KC_INT32,0,Prompt for creds if there arent any + AutoStart,KC_INT32,0,Start Khimaira when Windows starts + AutoImport,KC_INT32,0,Import Windows creds when Khimaira starts + AutoDetectNet,KC_INT32,1,Automatically detect network connectivity changes + KeepRunning,KC_INT32,1,Keep running after closing Khimaira + DefaultView,KC_STRING,ByIdentity, + ViewList,KC_STRING,"ByIdentity,ByLocation", + PaddingHorizontal,KC_INT32,4, + PaddingVertical,KC_INT32,2, + PaddingHeader,KC_INT32,16, + Monitor,KC_INT32,1,Monitor credentials + RefreshTimeout,KC_INT32,60,In seconds + WarnThreshold,KC_INT32,900,In seconds + AllowWarn,KC_INT32,1,Boolean. Enables warning. + CriticalThreshold,KC_INT32,300,In seconds + AllowCritical,KC_INT32,1,Boolean. Enables critical. + AutoRenewThreshold,KC_INT32,600,In seconds + AllowAutoRenew,KC_INT32,1,Boolean. + MaxThreshold,KC_INT32,86400,Max value for a threshold (1 day) + MinThreshold,KC_INT32,10,Min value for a threshold (0) + Windows,KC_SPACE,0,Window parameters + _Schema,KC_SPACE,0,Schema + Width,KC_INT32,0, + Height,KC_INT32,0, + XPos,KC_INT32,0, + YPos,KC_INT32,0, + _Schema,KC_ENDSPACE,0, + Main,KC_SPACE,0,Main window + Main,KC_ENDSPACE,0, + Windows,KC_ENDSPACE,0, + Views,KC_SPACE,0,Preconfigured views for credentials + Custom_0,KC_SPACE,0,First custom view. Additional views have names of the form Custom_N + Custom_0,KC_ENDSPACE,0, + ByIdentity,KC_SPACE,0,The default view + Description,KC_STRING,View grouped by identity and credential type, + ColumnList,KC_STRING,"_CWFlags,_CWTypeIcon,IdentityName,TypeName,Name,TimeLeft", + Columns,KC_SPACE,0,Columns + _CWFlags,KC_SPACE,0, + Width,KC_INT32,20, + Flags,KC_INT32,112, + _CWFlags,KC_ENDSPACE,0, + _CWTypeIcon,KC_SPACE,0, + Width,KC_INT32,20, + Flags,KC_INT32,112, + _CWTypeIcon,KC_ENDSPACE,0, + IdentityName,KC_SPACE,0, + Width,KC_INT32,100, + SortIndex,KC_INT32,0, + Flags,KC_INT32,11, + IdentityName,KC_ENDSPACE,0 + TypeName,KC_SPACE,0 + Width,KC_INT32,100 + SortIndex,KC_INT32,1 + Flags,KC_INT32,11 + TypeName,KC_ENDSPACE,0 + Name,KC_SPACE,0 + Width,KC_INT32,200 + SortIndex,KC_INT32,2 + Flags,KC_INT32,3 + Name,KC_ENDSPACE,0 + TimeLeft,KC_SPACE,0 + Width,KC_INT32,200 + Flags,KC_INT32,1 + TimeLeft,KC_ENDSPACE,0 + Columns,KC_ENDSPACE,0 + ByIdentity,KC_ENDSPACE,0 + ByLocation,KC_SPACE,0,View by location + Description,KC_STRING,View grouped by location, + ColumnList,KC_STRING,"_CWFlags,_CWTypeIcon,Location,IdentityName,TypeName,Name,TimeLeft", + Columns,KC_SPACE,0,Columns + _CWFlags,KC_SPACE,0, + Width,KC_INT32,20, + Flags,KC_INT32,112, + _CWFlags,KC_ENDSPACE,0, + _CWTypeIcon,KC_SPACE,0, + Width,KC_INT32,20, + Flags,KC_INT32,112, + _CWTypeIcon,KC_ENDSPACE,0, + Location,KC_SPACE,0, + Width,KC_INT32,100, + SortIndex,KC_INT32,0, + Flags,KC_INT32,11, + Location,KC_ENDSPACE,0, + IdentityName,KC_SPACE,0, + Width,KC_INT32,100, + SortIndex,KC_INT32,1, + Flags,KC_INT32,11, + IdentityName,KC_ENDSPACE,0 + TypeName,KC_SPACE,0 + Width,KC_INT32,100 + SortIndex,KC_INT32,2 + Flags,KC_INT32,11 + TypeName,KC_ENDSPACE,0 + Name,KC_SPACE,0 + Width,KC_INT32,200 + SortIndex,KC_INT32,3 + Flags,KC_INT32,3 + Name,KC_ENDSPACE,0 + TimeLeft,KC_SPACE,0 + Width,KC_INT32,200 + Flags,KC_INT32,1 + TimeLeft,KC_ENDSPACE,0 + Columns,KC_ENDSPACE,0 + ByLocation,KC_ENDSPACE,0 + Views,KC_ENDSPACE,0 + Notices,KC_SPACE,0,Notices and alerts + MinimizeWarning,KC_INT32,1,Show the minimize warning? + Notices,KC_ENDSPACE,0 +CredWindow,KC_ENDSPACE,0 diff --git a/src/windows/identity/uilib/Makefile b/src/windows/identity/uilib/Makefile new file mode 100644 index 0000000000..4e65600936 --- /dev/null +++ b/src/windows/identity/uilib/Makefile @@ -0,0 +1,61 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=uilib +!include <../config/Makefile.w32> + +UIDLLOBJFILES= \ + $(OBJ)\rescache.obj \ + $(OBJ)\action.obj \ + $(OBJ)\creddlg.obj \ + $(OBJ)\alert.obj \ + $(OBJ)\propsheet.obj \ + $(OBJ)\propwnd.obj \ + $(OBJ)\uilibmain.obj \ + $(OBJ)\actiondef.obj \ + $(OBJ)\acceldef.obj \ + $(OBJ)\configui.obj \ + $(OBJ)\trackerwnd.obj + +INCFILES= \ + $(INCDIR)\khuidefs.h \ + $(INCDIR)\khrescache.h \ + $(INCDIR)\khaction.h \ + $(INCDIR)\khactiondef.h \ + $(INCDIR)\khalerts.h \ + $(INCDIR)\khhtlink.h \ + $(INCDIR)\khnewcred.h \ + $(INCDIR)\khprops.h \ + $(INCDIR)\khconfigui.h \ + $(INCDIR)\khtracker.h \ + $(INCDIR)\khremote.h + +$(OBJ)\actiondef.c: actions.csv actiondef.cfg + $(CCSV) $** $@ + +$(OBJ)\acceldef.c: accel.csv acceldef.cfg + $(CCSV) $** $@ + +all: mkdirs $(INCFILES) $(UIDLLOBJFILES) + diff --git a/src/windows/identity/uilib/accel.csv b/src/windows/identity/uilib/accel.csv new file mode 100644 index 0000000000..80b6ad05f9 --- /dev/null +++ b/src/windows/identity/uilib/accel.csv @@ -0,0 +1,17 @@ +command,mod,key,scope +KHUI_PACTION_MENU,FVIRTKEY,VK_F10,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_UP,FVIRTKEY,VK_UP,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_UP_EXTEND,FVIRTKEY|FSHIFT,VK_UP,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_UP_TOGGLE,FVIRTKEY|FCONTROL,VK_UP,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_DOWN,FVIRTKEY,VK_DOWN,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_DOWN_EXTEND,FVIRTKEY|FSHIFT,VK_DOWN,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_DOWN_TOGGLE,FVIRTKEY|FCONTROL,VK_DOWN,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_LEFT,FVIRTKEY,VK_LEFT,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_RIGHT,FVIRTKEY,VK_RIGHT,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_ENTER,FVIRTKEY,VK_RETURN,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_ESC,FVIRTKEY,VK_ESCAPE,KHUI_ACCEL_SCOPE_GLOBAL +#KHUI_PACTION_DELETE,FVIRTKEY,VK_DELETE,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_ACTION_DESTROY_CRED,FVIRTKEY,VK_DELETE,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_ACTION_EXIT,FCONTROL,\'X\',KHUI_ACCEL_SCOPE_GLOBAL +KHUI_ACTION_VIEW_REFRESH,FVIRTKEY,VK_F5,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_ACTION_NEW_CRED,FCONTROL,\'N\',KHUI_ACCEL_SCOPE_GLOBAL diff --git a/src/windows/identity/uilib/acceldef.cfg b/src/windows/identity/uilib/acceldef.cfg new file mode 100644 index 0000000000..5dc72e6102 --- /dev/null +++ b/src/windows/identity/uilib/acceldef.cfg @@ -0,0 +1,50 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +$file_prefix = <<EOS; +/* +This file was autogenerated from src/ui/acceldef.cfg and src/ui/accel.csv. + +Do not modify directly. +*/ +#include<khuidefs.h> + +khui_accel_def khui_accel_global[] = { +EOS + +$record_prefix = "{"; + +$record_sep = ",\n"; + +$record_postfix = "}"; + +$file_postfix = <<EOS; + +}; + +int khui_n_accel_global = sizeof(khui_accel_global) / sizeof(khui_accel_def); + +EOS + +$skip_lines = 1; diff --git a/src/windows/identity/uilib/action.c b/src/windows/identity/uilib/action.c new file mode 100644 index 0000000000..cc383c689b --- /dev/null +++ b/src/windows/identity/uilib/action.c @@ -0,0 +1,1019 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#define NOEXPORT +#include<khuidefs.h> +#include<assert.h> + +khui_action_ref khui_main_menu[] = { + MENU_ACTION(KHUI_MENU_FILE), + MENU_ACTION(KHUI_MENU_CRED), + MENU_ACTION(KHUI_MENU_VIEW), + MENU_ACTION(KHUI_MENU_OPTIONS), + MENU_ACTION(KHUI_MENU_HELP), + MENU_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_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_DESTROY_CRED), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_SET_DEF_ID), + MENU_ACTION(KHUI_ACTION_SET_SRCH_ID), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_PASSWD_ID), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_IMPORT), + 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_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_CHOOSE_COLS), + MENU_ACTION(KHUI_MENU_LAYOUT), + MENU_ACTION(KHUI_MENU_TOOLBARS), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_DEBUG_WINDOW), + MENU_SEP(), + 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_IDENTS), + MENU_ACTION(KHUI_ACTION_OPT_NOTIF), + MENU_END() +}; + +khui_action_ref khui_menu_help[] = { + MENU_ACTION(KHUI_ACTION_HELP_CTX), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_HELP_CONTENTS), + 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_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_IMPORT), + MENU_ACTION(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_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_DESTROY_CRED), + 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_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_DESTROY_CRED), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_EXIT), + 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_main_menu), + CONSTMENU(KHUI_MENU_FILE, KHUI_MENUSTATE_CONSTANT, khui_menu_file), + CONSTMENU(KHUI_MENU_CRED, KHUI_MENUSTATE_CONSTANT, khui_menu_cred), + CONSTMENU(KHUI_MENU_VIEW, KHUI_MENUSTATE_CONSTANT, khui_menu_view), + CONSTMENU(KHUI_MENU_LAYOUT, KHUI_MENUSTATE_CONSTANT, khui_menu_layout), + CONSTMENU(KHUI_MENU_TOOLBARS, KHUI_MENUSTATE_CONSTANT, khui_menu_toolbars), + CONSTMENU(KHUI_MENU_OPTIONS, KHUI_MENUSTATE_CONSTANT, khui_menu_options), + CONSTMENU(KHUI_MENU_HELP, KHUI_MENUSTATE_CONSTANT, khui_menu_help), + + /* toolbars */ + CONSTMENU(KHUI_TOOLBAR_STANDARD, KHUI_MENUSTATE_CONSTANT, 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), + + /* 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); +CRITICAL_SECTION cs_actions; + +KHMEXP void KHMAPI +khui_init_actions(void) { + InitializeCriticalSection(&cs_actions); +} + +KHMEXP void KHMAPI +khui_exit_actions(void) { + DeleteCriticalSection(&cs_actions); +} + +#define MENU_NC_ITEMS 8 + +KHMEXP khui_menu_def * KHMAPI +khui_menu_create(int cmd) +{ + khui_menu_def * d; + d = malloc(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + + d->cmd = cmd; + d->nc_items = MENU_NC_ITEMS; + d->items = malloc(sizeof(*(d->items)) * d->nc_items); + + d->state = KHUI_MENUSTATE_ALLOCD; + + return d; +} + +KHMEXP khui_menu_def * KHMAPI +khui_menu_dup(khui_menu_def * src) +{ + khui_menu_def * d; + size_t i; + size_t n; + + d = khui_menu_create(src->cmd); + + if(src->n_items == -1) + n = khui_action_list_length(src->items); + else + n = src->n_items; + + for(i=0; i<n; i++) { + if(src->items[i].flags & KHUI_ACTIONREF_PACTION) { + khui_menu_add_paction(d, src->items[i].p_action, src->items[i].flags); + } else { + khui_menu_add_action(d, src->items[i].action); + } + } + + 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)) + return; + + for(i=0; i< (int) d->n_items; i++) { + if(d->items[i].flags & KHUI_ACTIONREF_FREE_PACTION) + free(d->items[i].p_action); + } + + if(d->items) + free(d->items); + free(d); +} + +static void khui_menu_assert_size(khui_menu_def * d, size_t n) +{ + if(n > (int) d->nc_items) { + khui_action_ref * ni; + + d->nc_items = UBOUNDSS(n, MENU_NC_ITEMS, MENU_NC_ITEMS); + ni = malloc(sizeof(*(d->items)) * d->nc_items); + memcpy(ni, d->items, sizeof(*(d->items)) * d->n_items); + free(d->items); + d->items = ni; + } +} + +KHMEXP void KHMAPI khui_menu_add_action(khui_menu_def * d, int id) +{ + khui_menu_assert_size(d, d->n_items + 1); + d->items[d->n_items].flags = 0; + d->items[d->n_items ++].action = id; +} + +KHMEXP void KHMAPI khui_menu_add_paction(khui_menu_def * d, khui_action * act, int flags) +{ + khui_menu_assert_size(d, d->n_items + 1); + d->items[d->n_items].flags = flags | KHUI_ACTIONREF_PACTION; + d->items[d->n_items ++].p_action = act; +} + +KHMEXP khui_menu_def * KHMAPI khui_find_menu(int id) { + khui_menu_def * d; + int i; + + d = khui_all_menus; + for(i=0;i<khui_n_all_menus;i++) { + if(id == d[i].cmd) + return &d[i]; + } + + return NULL; +} + +KHMEXP khui_action * KHMAPI khui_find_action(int id) { + khui_action * act; + int i; + + act = khui_actions; + for(i=0;i<khui_n_actions;i++) { + if(act[i].cmd == id) + return &act[i]; + } + + return NULL; +} + +KHMEXP khui_action * KHMAPI khui_find_named_action(wchar_t * name) { + int i; + khui_action * act; + + if(!name) + return NULL; + + act = khui_actions; + for(i=0;i<khui_n_actions;i++) { + if(!act[i].name) + continue; + if(!wcscmp(act[i].name, name)) + return &act[i]; + } + + return NULL; +} + +KHMEXP size_t KHMAPI khui_action_list_length(khui_action_ref * ref) { + size_t c = 0; + while(ref && ref->action != KHUI_MENU_END) { + c++; + ref++; + } + return c; +} + +KHMEXP void KHMAPI khui_check_radio_action(khui_menu_def * d, khm_int32 cmd) +{ + khui_action_ref * r; + khui_action * act; + + r = d->items; + while(r && r->action != KHUI_MENU_END) { + 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++; + } + + kmq_post_message(KMSG_ACT, KMSG_ACT_CHECK, 0, 0); +} + +KHMEXP void KHMAPI khui_check_action(int cmd, khm_boolean check) { + khui_action * act; + + act = khui_find_action(cmd); + if (!act) + return; + + 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 + return; + + 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; + + r = d->items; + while(r && r->action != KHUI_MENU_END) { + 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++; + } + + if(delta) { + kmq_send_message(KMSG_ACT, KMSG_ACT_ENABLE, 0, 0); + } +} + +KHMEXP void KHMAPI khui_enable_action(int cmd, khm_boolean enable) { + khui_action * act; + + act = khui_find_action(cmd); + if (!act) + return; + + 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 + return; + + kmq_send_message(KMSG_ACT, KMSG_ACT_ENABLE, 0, 0); +} + +KHMEXP HACCEL KHMAPI khui_create_global_accel_table(void) { + int i; + ACCEL * accels; + HACCEL ha; + + accels = malloc(sizeof(ACCEL) * khui_n_accel_global); + for(i=0;i<khui_n_accel_global;i++) { + accels[i].cmd = khui_accel_global[i].cmd; + accels[i].fVirt = khui_accel_global[i].mod; + accels[i].key = khui_accel_global[i].key; + } + + ha = CreateAcceleratorTable(accels, khui_n_accel_global); + + free(accels); + + return ha; +} + +KHMEXP khm_boolean KHMAPI +khui_get_cmd_accel_string(int cmd, + wchar_t * buf, + size_t bufsiz) { + int i; + khui_accel_def * def; + + /* should at least hold 2 characters */ + if(bufsiz < sizeof(wchar_t) * 2) + return FALSE; + + buf[0] = L'\0'; + + for(i=0;i<khui_n_accel_global;i++) { + if(khui_accel_global[i].cmd == cmd) + break; + } + + if(i==khui_n_accel_global) + return FALSE; + + def = &khui_accel_global[i]; + + if(def->mod & 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_F5: + ap = L"F5"; + 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) + free(ctxdest->int_buf); + + ctxdest->int_cb_buf = cb_total; + ctxdest->int_buf = malloc(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 = malloc(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}; + +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; + + 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_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); + } + + khui_enable_action(KHUI_ACTION_PASSWD_ID, TRUE); + } else { + khui_check_action(KHUI_ACTION_SET_DEF_ID, FALSE); + khui_enable_action(KHUI_ACTION_SET_DEF_ID, FALSE); + khui_enable_action(KHUI_ACTION_PASSWD_ID, FALSE); + } + + if (khui_ctx.scope != KHUI_SCOPE_NONE) { + khui_enable_action(KHUI_ACTION_PROPERTIES, TRUE); + khui_enable_action(KHUI_ACTION_DESTROY_CRED, TRUE); + khui_enable_action(KHUI_ACTION_RENEW_CRED, TRUE); + } else { + khui_enable_action(KHUI_ACTION_PROPERTIES, FALSE); + khui_enable_action(KHUI_ACTION_DESTROY_CRED, FALSE); + khui_enable_action(KHUI_ACTION_RENEW_CRED, 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) + free(ctx->int_buf); + ctx->int_buf = NULL; +#if 0 + if (ctx->vparam && ctx->cb_vparam > 0) { + free(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/actiondef.cfg b/src/windows/identity/uilib/actiondef.cfg new file mode 100644 index 0000000000..14600b0b6f --- /dev/null +++ b/src/windows/identity/uilib/actiondef.cfg @@ -0,0 +1,64 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +$file_prefix = <<EOS; +/* +This file was autogenerated from src/ui/actiondef.cfg and src/ui/actions.csv. + +Do not modify directly. +*/ + +#include<khuidefs.h> +#include<khhelp.h> +#include"../ui/resource.h" + +khui_action khui_actions [] = { +EOS + +$record_prefix = "{"; + +$record_sep = ",\n"; + +$record_postfix = "}"; + +$file_postfix = <<EOS; + +}; + +int khui_n_actions = sizeof(khui_actions) / sizeof(khui_action); + +EOS + +$skip_lines = 1; + +sub rec_handler { + $arr = shift; + if($$arr[2] =~ /^$/) { + $$arr[2] = "NULL"; + } else { + $$arr[2] = "L\"".$$arr[2]."\""; + } +} + +$record_parser = \&rec_handler; diff --git a/src/windows/identity/uilib/actions.csv b/src/windows/identity/uilib/actions.csv new file mode 100644 index 0000000000..e317c7cc54 --- /dev/null +++ b/src/windows/identity/uilib/actions.csv @@ -0,0 +1,37 @@ +Command,Type,Name,Img Normal,Img Hot,Img Disabled,Ico Normal,Ico Disabled,Caption,Tooltip,Topic,State +KHUI_MENU_FILE,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_FILE,0,IDH_MENU_FILE,0 +KHUI_MENU_CRED,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_CRED,0,IDH_MENU_CRED,0 +KHUI_MENU_VIEW,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_VIEW,0,IDH_MENU_VIEW,0 +KHUI_MENU_OPTIONS,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_OPTIONS,0,IDH_MENU_OPTIONS,0 +KHUI_MENU_HELP,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_HELP,0,IDH_MENU_HELP,0 +KHUI_MENU_LAYOUT,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_LAYOUT,0,0,0 +KHUI_MENU_TOOLBARS,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_TOOLBARS,0,0,0 +KHUI_ACTION_PROPERTIES,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_PROPERTIES,0,IDH_ACTION_PROPERTIES,0 +KHUI_ACTION_EXIT,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_EXIT,0,IDH_ACTION_EXIT,0 +KHUI_ACTION_SET_DEF_ID,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_SET_DEF_ID,0,IDH_ACTION_SET_DEF_ID,0 +KHUI_ACTION_SET_SRCH_ID,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_SET_SRCH_ID,0,IDH_ACTION_SET_SRCH_ID,KHUI_ACTIONSTATE_DISABLED +KHUI_ACTION_PASSWD_ID,KHUI_ACTIONTYPE_TRIGGER,,IDB_CHPW,0,IDB_CHPW_DIS,IDB_CHPW_SM,IDB_CHPW_DIS_SM,IDS_ACTION_PASSWD_ID,0,IDH_ACTION_PASSWD_ID,0 +KHUI_ACTION_NEW_CRED,KHUI_ACTIONTYPE_TRIGGER,,IDB_TK_NEW,0,IDB_TK_NEW_DIS,IDB_TK_NEW_SM,IDB_TK_NEW_DIS_SM,IDS_ACTION_NEW_CRED,0,IDH_ACTION_NEW_CRED,0 +KHUI_ACTION_RENEW_CRED,KHUI_ACTIONTYPE_TRIGGER,,IDB_TK_REFRESH,0,IDB_TK_REFRESH_DIS,IDB_TK_REFRESH_SM,IDB_TK_REFRESH_DIS_SM,IDS_ACTION_RENEW_CRED,0,0,0 +KHUI_ACTION_DESTROY_CRED,KHUI_ACTIONTYPE_TRIGGER,,IDB_TK_DELETE,0,IDB_TK_DELETE_DIS,IDB_TK_DELETE_SM,IDB_TK_DELETE_DIS_SM,IDS_ACTION_DESTROY_CRED,0,0,0 +KHUI_ACTION_LAYOUT_ID,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_LAYOUT_ID,0,0,KHUI_ACTIONSTATE_CHECKED +KHUI_ACTION_LAYOUT_TYPE,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_LAYOUT_TYPE,0,0,KHUI_ACTIONSTATE_DISABLED +KHUI_ACTION_LAYOUT_LOC,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_LAYOUT_LOC,0,0,0 +KHUI_ACTION_TB_STANDARD,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_TB_STANDARD,0,0,KHUI_ACTIONSTATE_CHECKED +KHUI_ACTION_CHOOSE_COLS,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_CHOOSE_COLS,0,IDH_ACTION_CHOOSE_COLS,KHUI_ACTIONSTATE_DISABLED +KHUI_ACTION_DEBUG_WINDOW,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_DEBUG_WINDOW,0,IDH_ACTION_DEBUG_WINDOW,KHUI_ACTIONSTATE_DISABLED +KHUI_ACTION_VIEW_REFRESH,KHUI_ACTIONTYPE_TRIGGER,,IDB_VW_REFRESH,0,0,IDB_VW_REFRESH_SM,0,IDS_ACTION_VIEW_REFRESH,0,IDH_ACTION_VIEW_REFRESH,0 +KHUI_ACTION_OPT_IDENTS,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_OPT_IDENTS,0,IDH_ACTION_OPT_INIT,0 +KHUI_ACTION_OPT_KHIM,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_OPT_KHIM,0,IDH_ACTION_OPT_KHIM,0 +KHUI_ACTION_OPT_NOTIF,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_OPT_NOTIF,0,IDH_ACTION_OPT_NOTIF,0 +KHUI_ACTION_HELP_CTX,KHUI_ACTIONTYPE_TRIGGER,,IDB_HELP,0,0,IDB_HELP_SM,0,IDS_ACTION_HELP_CTX,0,0,0 +KHUI_ACTION_HELP_CONTENTS,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_HELP_CONTENTS,0,0,0 +KHUI_ACTION_HELP_INDEX,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_HELP_INDEX,0,0,0 +KHUI_ACTION_HELP_ABOUT,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_HELP_ABOUT,0,0,0 +KHUI_ACTION_OPEN_APP,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_OPEN_APP,0,0,0 +KHUI_ACTION_CLOSE_APP,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_CLOSE_APP,0,0,0 +KHUI_ACTION_IMPORT,KHUI_ACTIONTYPE_TRIGGER,,IDB_IMPORT,0,IDB_IMPORT_DIS,IDB_IMPORT_SM,IDB_IMPORT_SM_DIS,IDS_ACTION_IMPORT,0,0,0 +KHUI_PACTION_OK,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_PACTION_OK,0,0,0 +KHUI_PACTION_CANCEL,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_PACTION_CANCEL,0,0,0 +KHUI_PACTION_CLOSE,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_PACTION_CLOSE,0,0,0 +KHUI_PACTION_BLANK,0,,IDB_TB_SPACE,0,IDB_TB_SPACE,IDB_TB_BLANK_SM,IDB_TB_BLANK_SM,0,0,0,KHUI_ACTIONSTATE_DISABLED diff --git a/src/windows/identity/uilib/alert.c b/src/windows/identity/uilib/alert.c new file mode 100644 index 0000000000..69ef01f93c --- /dev/null +++ b/src/windows/identity/uilib/alert.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khuidefs.h> +#include<assert.h> + +/*********************************************************************** + 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 = malloc(sizeof(*a)); + ZeroMemory(a, sizeof(*a)); + + a->magic = KHUI_ALERT_MAGIC; + + /* set defaults */ + a->severity = KHERR_INFO; + a->flags = KHUI_ALERT_FLAG_FREE_STRUCT; + + 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 - sizeof(wchar_t), + &cb))) { + return KHM_ERROR_INVALID_PARM; + } + cb += sizeof(wchar_t); + } + + EnterCriticalSection(&cs_alerts); + if(alert->title && (alert->flags & KHUI_ALERT_FLAG_FREE_TITLE)) { + free(alert->title); + alert->title = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_TITLE; + } + if(title) { + alert->title = malloc(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_PARM; + + 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_PARM; + } + cb += sizeof(wchar_t); + } + + EnterCriticalSection(&cs_alerts); + if(alert->suggestion && + (alert->flags & KHUI_ALERT_FLAG_FREE_SUGGEST)) { + + free(alert->suggestion); + alert->suggestion = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_SUGGEST; + + } + + if(suggestion) { + alert->suggestion = malloc(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_PARM; + } + cb += sizeof(wchar_t); + } + + EnterCriticalSection(&cs_alerts); + if(alert->message && + (alert->flags & KHUI_ALERT_FLAG_FREE_MESSAGE)) { + + free(alert->message); + alert->message = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_MESSAGE; + + } + + if(message) { + alert->message = malloc(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_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_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); + free(alert->title); + alert->title = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_TITLE; + } + if(alert->flags & KHUI_ALERT_FLAG_FREE_MESSAGE) { + assert(alert->message); + free(alert->message); + alert->message = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_MESSAGE; + } + if(alert->flags & KHUI_ALERT_FLAG_FREE_SUGGEST) { + assert(alert->suggestion); + free(alert->suggestion); + alert->suggestion = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_SUGGEST; + } + if(alert->flags & KHUI_ALERT_FLAG_FREE_STRUCT) { + alert->flags &= ~KHUI_ALERT_FLAG_FREE_STRUCT; + alert->magic = 0; + free(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 new file mode 100644 index 0000000000..5c97c701fa --- /dev/null +++ b/src/windows/identity/uilib/configui.c @@ -0,0 +1,1001 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khuidefs.h> +#include<kmm.h> +#include<configui.h> +#include<assert.h> + +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 = malloc(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) + free((void *) node->reg.name); + + if (node->reg.short_desc) + free((void *) node->reg.short_desc); + + if (node->reg.long_desc) + free((void *) node->reg.long_desc); + + node->magic = 0; + + if (node->owner) + kmm_release_plugin(node->owner); + + ZeroMemory(node, sizeof(*node)); + + free(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_PARM; + + 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 = malloc(cb_name); + StringCbCopy(name, cb_name, reg->name); + short_desc = malloc(cb_short_desc); + StringCbCopy(short_desc, cb_short_desc, reg->short_desc); + long_desc = malloc(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); + } + + //node->owner = kmm_this_plugin(); + + EnterCriticalSection(&cs_cfgui); + TADDCHILD(parent, node); + LeaveCriticalSection(&cs_cfgui); + + 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_PARM; + + 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_PARM; + + EnterCriticalSection(&cs_cfgui); + node = cfgui_node_i_from_handle(vnode); + node->flags |= KHUI_CN_FLAG_DELETED; + 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_PARM; + + 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_PARM; + + cfgui_release_node(cfgui_node_i_from_handle(vnode)); + + return KHM_ERROR_SUCCESS; +} + +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_PARM; + + 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 = 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_PARM; + + 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 = 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_PARM; + + 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_PARM; + + 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 = 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_PARM; + + 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_PARM; +} + +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 cfg_node_data * +get_node_data(khui_config_node_i * node, + void * key, + khm_boolean create) { + khm_size i; + + for (i=0; i<node->n_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 = malloc(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)); + free(node->data); + } + node->data = newdata; + } + + node->data[node->n_data].key = key; + 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; + 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) && + hwnd_cfgui != NULL) { + + 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) { + khui_config_node_i * node; + khui_config_node_i * parent; + khm_int32 flags; + khm_size i; + +#ifdef DEBUG + assert(cfgui_is_valid_node_handle(vnode)); +#endif + + node = cfgui_node_i_from_handle(vnode); + + parent = TPARENT(node); +#ifdef DEBUG + assert(parent); +#endif + + flags = 0; + + /* this code is wrong. we need to go through all the subpanels in + the parent and pick the data record corresponding to this node + and then merge the flags from there. */ + /* TODO: fix this */ + for (i=0; i < parent->n_data; i++) { + if (parent->data[i].key == vnode) + flags |= parent->data[i].flags; + } + + flags &= KHUI_CNFLAGMASK_DYNAMIC; + + if ((node->flags & flags) != flags) { + node->flags = flags | + (node->flags & ~KHUI_CNFLAGMASK_DYNAMIC); + + 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); + } + } + } + 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) && + hwnd_cfgui != NULL) { + + 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_PARM; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode) && + hwnd_cfgui != NULL) { + 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_PARM; + } + 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 = malloc(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) { + free(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 new file mode 100644 index 0000000000..37d5e97058 --- /dev/null +++ b/src/windows/identity/uilib/configui.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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 new file mode 100644 index 0000000000..ccc27b4019 --- /dev/null +++ b/src/windows/identity/uilib/creddlg.c @@ -0,0 +1,671 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khuidefs.h> +#include<assert.h> + +#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 = malloc(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; + + *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;i<c->n_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); + free(c->password); + } + + if(c->identities) + free(c->identities); + + if(c->types) + free(c->types); + + if (c->window_title) + free(c->window_title); + + free(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 = malloc(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 = malloc(sizeof(*(c->identities)) * c->nc_identities); + memcpy(ni, c->identities, + sizeof(*(c->identities)) * c->n_identities); + free(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; i<c->n_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 = malloc(sizeof(*(c->types)) * c->nc_types); + c->type_subs = malloc(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 = malloc(sizeof(*(c->types)) * n); + memcpy(t, (void *) c->types, sizeof(*(c->types)) * c->n_types); + free(c->types); + c->types = t; + + t = malloc(sizeof(*(c->type_subs)) * n); + memcpy(t, (void *) c->type_subs, sizeof(*(c->type_subs)) * c->n_types); + free(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;i<c->n_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; + size_t cb_def; + + 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 = malloc(sizeof(*p)); + ZeroMemory(p, sizeof(*p)); + + if(prompt) { + cb_prompt += sizeof(wchar_t); + p->prompt = malloc(cb_prompt); + StringCbCopy(p->prompt, cb_prompt, prompt); + } + + if(def) { + cb_def += sizeof(wchar_t); + p->def = malloc(cb_def); + StringCbCopy(p->def, cb_def, def); + } + + p->value = malloc(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); + free(p->prompt); + } + + if(p->def) { + if(SUCCEEDED(StringCbLength(p->def, KHUI_MAXCB_PROMPT, &cb))) + SecureZeroMemory(p->def, cb); + free(p->def); + } + + if(p->value) { + if(SUCCEEDED(StringCbLength(p->value, KHUI_MAXCB_PROMPT_VALUE, &cb))) + SecureZeroMemory(p->value, cb); + free(p->value); + } + + free(p); +} + +static void +cw_free_prompts(khui_new_creds * c) +{ + khm_size i; + + if(c->banner != NULL) { + free(c->banner); + c->banner = NULL; + } + + if(c->pname != NULL) { + free(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) { + free(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) +{ + 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 = malloc(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 = malloc(cb); + StringCbCopy(c->pname, cb, pname); + + } else { + + c->pname = NULL; + + } + + if(n_prompts > 0) { + + c->prompts = malloc(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_PARM; + } + 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; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_sync_prompt_values(khui_new_creds * c) +{ + khm_size i; + + EnterCriticalSection(&c->cs); + for(i=0;i<c->n_prompts;i++) { + khui_new_creds_prompt * p; + p = c->prompts[i]; + if(p->hwnd_edit) { + /* Ideally, we would retrieve the text to a temporary + buffer with the c->cs released, obtain c->cs and copy the + text to p->value. However, I'm not going to bother as the + code paths we are touching here do not need c->cs while + setting p->value does */ + GetWindowText(p->hwnd_edit, p->value, + KHUI_MAXCCH_PROMPT_VALUE); + } + } + 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_PARM; + } +} diff --git a/src/windows/identity/uilib/khaction.h b/src/windows/identity/uilib/khaction.h new file mode 100644 index 0000000000..7b7c22a57b --- /dev/null +++ b/src/windows/identity/uilib/khaction.h @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_ACTION_H +#define __KHIMAIRA_ACTION_H + +/*! \addtogroup khui + @{*/ +/*! \defgroup khui_actions Actions + @{*/ + +/*! \brief An action */ +typedef struct tag_khui_action { + int cmd; /*!< command id */ + int type; /*!< combination of KHUI_ACTIONTYPE_* */ + wchar_t * name; /*!< name for named actions. NULL if not named. */ + + /* normal, hot and disabled are toolbar sized bitmaps */ + int ib_normal; /*!< normal bitmap (index) */ + int ib_hot; /*!< hot bitmap (index) */ + int ib_disabled; /*!< disabled bitmap (index) */ + + int ib_icon; /*!< index of small (16x16) icon (for menu) */ + int ib_icon_dis; /*!< index of disabled (greyed) icon */ + + int is_caption; /*!< index of string resource for caption */ + int is_tooltip; /*!< same for description / tooltip */ + int ih_topic; /*!< help topic */ + int state; /*!< current state. combination of KHUI_ACTIONSTATE_* */ +} khui_action; + +/*! \brief Unknown action type */ +#define KHUI_ACTIONTYPE_NONE 0 + +/*! \brief A trigger type action */ +#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 */ +#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 + +#ifdef NOEXPORT +#define ACTION_SIMPLE(c,cap,des,top) \ + {c,KHUI_ACTIONTYPE_TRIGGER,0,0,0,0,0,cap,des,top,0} + +#define ACTION_FULL(cmd,type,inormal,ihot,idis,isml,ismld,capt,toolt,topic,state) \ + {cmd,type,inormal,ihot,idis,isml,ismld,capt,toolt,topic,state} + +#define ACTION_SIMPLE_IMAGE(c,inormal, ihot, idis, isml, ismld,cap, des, top) \ + {c,KHUI_ACTIONTYPE_TRIGGER,inormal,ihot,idis,isml,ismld,cap,des,top,0} +#endif + +/*! \brief A reference to an action */ +typedef struct tag_khui_action_ref { + int flags; + union { + int action; + khui_action * p_action; + }; +} khui_action_ref; + +#define KHUI_ACTIONREF_SUBMENU 0x01 +#define KHUI_ACTIONREF_SEP 0x02 +#define KHUI_ACTIONREF_PACTION 0x04 +#define KHUI_ACTIONREF_FREE_PACTION 0x08 +#define KHUI_ACTIONREF_END 0x10 +#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 */ +typedef struct tag_khui_menu_def { + int cmd; /*!< Action associated with menu */ + int state; /*!< combination of KHUI_MENUSTATE_* */ + size_t n_items; /*!< total number of items or -1 if not + set. If this is -1, then the list of + actions must be terminated with a + ACTION_LIST_END entry. */ + size_t nc_items; /*!< max number of items in the buffer + alocated for items. Ignored if + KHUI_MENUSTATE_CONSTANT is 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. */ +} khui_menu_def; + +#ifdef NOEXPORT +#define CONSTMENU(c,s,i) {c,s,-1,-1,i} +#endif + +#define KHUI_MENU_END -2 +#define KHUI_MENU_SEP -1 + +#define KHUI_MENUSTATE_CONSTANT 0 +#define KHUI_MENUSTATE_ALLOCD 1 + +/*! \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 + +#ifdef NOEXPORT + +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 */ + +KHMEXP khui_menu_def * KHMAPI khui_menu_create(int cmd); +KHMEXP khui_menu_def * KHMAPI khui_menu_dup(khui_menu_def * src); +KHMEXP void KHMAPI khui_menu_delete(khui_menu_def * d); +KHMEXP void KHMAPI khui_menu_add_action(khui_menu_def * d, int id); +KHMEXP void KHMAPI khui_menu_add_paction(khui_menu_def * d, khui_action * act, int flags); + +/*! \brief 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 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(int cmd, wchar_t * buf, size_t bufsiz); + +KHMEXP HACCEL KHMAPI khui_create_global_accel_table(void); + +/*! \brief Find a menu by id */ +KHMEXP khui_menu_def * KHMAPI khui_find_menu(int id); + +/*! \brief Find an action by id */ +KHMEXP khui_action * KHMAPI khui_find_action(int id); + +/*! \brief Get the length of the action list */ +KHMEXP size_t KHMAPI khui_action_list_length(khui_action_ref * ref); + +/*! \brief Find an action by name */ +KHMEXP khui_action * KHMAPI khui_find_named_action(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 cmd will either be enabled + or disabled depending on the \a enable parameter. If \a enable is + TRUE then the action is enabled. + */ +KHMEXP void KHMAPI khui_enable_action(int cmd, khm_boolean enable); + +/*! \brief Check an action in an action group + + Marks the action denoted by \a cmd as checked and resets the + checked bit in all other actions. + + \param[in] d A menu definition. + \param[in] cmd A command identifier. Setting this to -1 will + reset the checked bit in all the actions in the menu + definition. + */ +KHMEXP void KHMAPI khui_check_radio_action(khui_menu_def * d, khm_int32 cmd); + +/*!\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 diff --git a/src/windows/identity/uilib/khactiondef.h b/src/windows/identity/uilib/khactiondef.h new file mode 100644 index 0000000000..d01eb2addc --- /dev/null +++ b/src/windows/identity/uilib/khactiondef.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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_CHOOSE_COLS (KHUI_ACTION_BASE + 9) +#define KHUI_ACTION_DEBUG_WINDOW (KHUI_ACTION_BASE + 10) +#define KHUI_ACTION_VIEW_REFRESH (KHUI_ACTION_BASE + 11) +#define KHUI_ACTION_LAYOUT_ID (KHUI_ACTION_BASE + 12) +#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) +/*@}*/ + +/*! \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) +/*@}*/ + +/*! \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_PMENU_TOK_SEL (KHUI_MENU_BASE + 10) +#define KHUI_PMENU_ID_SEL (KHUI_MENU_BASE + 11) + +/* Next menu: 14 */ +/*@}*/ + +/*! \name Toolbars +@{*/ +#define KHUI_TOOLBAR_BASE (KHUI_ACTION_BASE + 2000) + +#define KHUI_TOOLBAR_STANDARD (KHUI_TOOLBAR_BASE + 0) +/*@}*/ + +/* base for user actions */ +#define KHUI_USERACTION_BASE (KHUI_ACTION_BASE + 10000) +/*@}*/ +/*@}*/ + +#endif diff --git a/src/windows/identity/uilib/khalerts.h b/src/windows/identity/uilib/khalerts.h new file mode 100644 index 0000000000..c41dddf1fa --- /dev/null +++ b/src/windows/identity/uilib/khalerts.h @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KHALERTS_H +#define __KHIMAIRA_KHALERTS_H + +/********************************************************************* + Alerter and error reporting +**********************************************************************/ + +/*! \addtogroup khui +@{ */ + +/*!\defgroup khui_alert Alerter and Error Reporting +@{*/ + +#define KHUI_MAX_ALERT_COMMANDS 4 + +/*! \brief An alert + + Describes an alert message that will be shown to the user in a + variety of ways depending on the state of the NetIDMgr + application. + */ +typedef struct tag_khui_alert { + khm_int32 magic; /*!< Magic number. Always set to + KHUI_ALERT_MAGIC */ + + khm_int32 severity; /*!< The severity of the alert. One + of KHERR_ERROR, KHERR_WARNING or + KHERR_INFO. The default is + KHERR_INFO. Do not set directly. + Use khui_alert_set_severity(). */ + + khm_int32 alert_commands[KHUI_MAX_ALERT_COMMANDS]; + /*!< The command buttons associated + with the alert. Use + khui_alert_add_command() to add a + command. The buttons will appear in + the order in which they were added. + The first button will be the + default. Each command should be a + known action identifier. */ + khm_int32 n_alert_commands; + + wchar_t * title; /*!< The title of the alert. Subject + to ::KHUI_MAXCCH_TITLE. Use + khui_alert_set_title() to set. Do + not modify directly. */ + + wchar_t * message; /*!< The main message of the alert. + Subject to ::KHUI_MAXCCH_MESSAGE. + Use khui_alert_set_message() to + set. Do not modify direcly. */ + + wchar_t * suggestion; /*!< A suggestion. Appears below + the message text. Use + khui_alert_set_suggestion() to + set. Do not modify directly. */ + +#ifdef _WIN32 + POINT target; +#endif + + khm_int32 flags; /*!< combination of + ::khui_alert_flags. Do not modify + directly. */ + + kherr_context * err_context; + /*!< If non-NULL at the time the alert + window is shown, this indicates that + the alert window should provide an + error viewer for the given error + context. */ + + kherr_event * err_event; + /*!< If non-NULL at the time the alert + window is shown, this indicates that + the alert window should provide an + error viewer for the given error + event. If an \a err_context is also + given, the error viewer for the + context will be below this error. */ + + khm_int32 response; + /*!< Once the alert is displayed to + the user, when the user clicks one + of the command buttons, the command + ID will be assigned here. */ + + int refcount; /* internal */ + + LDCL(struct tag_khui_alert); /* internal */ +} khui_alert; + +#define KHUI_ALERT_MAGIC 0x48c39ce9 + +/*! \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_VALID_TARGET =0x00010000, + /*!< There is a valid target for the alert */ + + KHUI_ALERT_FLAG_VALID_ERROR =0x00020000, + /*!< 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_FLAGMASK_RDWR =0x0C000010, + /*!< Bit mask of flags that can be set by khui_alert_set_flags() */ +}; + +/*! \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 command. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_add_command(khui_alert * alert, + khm_int32 command_id); + +/*! \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 have the same effect as + choosing the first command in the action. + + 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. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_show(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 + modifying 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 new file mode 100644 index 0000000000..9a96d41f97 --- /dev/null +++ b/src/windows/identity/uilib/khconfigui.h @@ -0,0 +1,588 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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(). */ +}; + +/*! \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 + +#define KHUI_CNFLAG_MODIFIED 0x0010 +#define KHUI_CNFLAG_APPLIED 0x0020 + +#define KHUI_CNFLAGMASK_STATIC 0x000f +#define KHUI_CNFLAGMASK_DYNAMIC 0x00f0 + +/*! \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_PARM 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. + */ +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 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_PARM \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 new file mode 100644 index 0000000000..dcbf328ff6 --- /dev/null +++ b/src/windows/identity/uilib/khhtlink.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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; + wchar_t * id; + int id_len; + wchar_t * param; + int param_len; +} 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 new file mode 100644 index 0000000000..1742f4a1af --- /dev/null +++ b/src/windows/identity/uilib/khnewcred.h @@ -0,0 +1,896 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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 getting expanded. + + 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 */ + + 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. */ +}; + +/*! \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; + + khm_int32 subtype; /*!< Subtype of the request that is + being handled through this object. + One of ::KMSG_CRED_INITIAL_CREDS, + ::KMSG_CRED_NEW_CREDS or + ::KMSG_CRED_RENEW_CREDS */ + + CRITICAL_SECTION cs; + + 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_GET_CREDS 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 set until the dialog ends */ + + /* 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_GET_CREDS 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 + +#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 +*/ +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 */ + + 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. */ + + khm_size n_type_deps; /*!< Number of dependencies listed + above. Should be between 0 and + ::KHUI_MAX_TYPE_DEPS */ + + 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. */ + + HICON icon; /*!< Icon for the panel (optional) */ + + wchar_t *tooltip; /*!< Tooltip for the panel (localized, + optional). If NULL, no tooltip will + be assigned for the panel */ + + HMODULE h_module; /*!< Handle to the module containing + the dialog resource */ + + LPWSTR dlg_template; /*!< The dialog resource */ + DLGPROC dlg_proc; /*!< The dialog procedure */ + + HWND hwnd_panel; /*!< The dialog window */ + HWND hwnd_tc; /*!< Internal use. Do not set */ + + wchar_t *credtext; /*!< A brief description of the + current state of this cred + type. (localized, optional) */ + + LPARAM aux; /*!< auxilliary field. For use by the + credential provider */ +} 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 Width of the button bar in dialog units */ +#define NCDLG_BBAR_WIDTH 60 +/*! \brief Height of a tab button in dialog units */ +#define NCDLG_TAB_HEIGHT 15 +/*! \brief Width of a tab button in dialog units */ +#define NCDLG_TAB_WIDTH 60 + +/*! \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. + + \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 new file mode 100644 index 0000000000..b772690216 --- /dev/null +++ b/src/windows/identity/uilib/khprops.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KHPROPS_H +#define __KHIMAIRA_KHPROPS_H + +/********************************************************************* + 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. + + \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 new file mode 100644 index 0000000000..a5b9d67de3 --- /dev/null +++ b/src/windows/identity/uilib/khremote.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_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 32809 + +#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 new file mode 100644 index 0000000000..96bec88ab8 --- /dev/null +++ b/src/windows/identity/uilib/khrescache.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_RESCACHE_H +#define __KHIMAIRA_RESCACHE_H + +#include<khdefs.h> + +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 new file mode 100644 index 0000000000..f03d2b425f --- /dev/null +++ b/src/windows/identity/uilib/khtracker.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_TRACKERWND_H +#define __KHIMAIRA_TRACKERWND_H + +#include<time.h> + +/*! \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: + +<table> +<tr><td> Range </td><td> Increment</td></tr> +<tr><td> 0..5m </td><td> 1 min </td></tr> +<tr><td> 5m..1hr </td><td> 5 min </td></tr> +<tr><td> 1hr..4hr </td><td> 15 min </td></tr> +<tr><td> 4hr..10hr </td><td> 30 min </td></tr> +<tr><td> 10hr..24hr</td><td> 1 hr </td></tr> +<tr><td> 24hr..4d </td><td> 6 hr </td></tr> +<tr><td> 4d.. </td><td> 1 day </td></tr> +</table> + +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; + + 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 new file mode 100644 index 0000000000..d92eb64444 --- /dev/null +++ b/src/windows/identity/uilib/khuidefs.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KHUIDEFS_H +#define __KHIMAIRA_KHUIDEFS_H + +#include<windows.h> +#include<kmq.h> +#include<kcreddb.h> +#include<kherror.h> +#include<kherr.h> +#include<khmsgtypes.h> + +#include<khaction.h> +#include<khactiondef.h> +#include<khrescache.h> +#include<khhtlink.h> +#include<khnewcred.h> +#include<khprops.h> +#include<khalerts.h> +#include<khconfigui.h> +#include<khtracker.h> + +#include<khremote.h> + +#include<strsafe.h> + +/*! \defgroup khui User Interface + + Functions and data structures for interacting with the user + interface. + +*/ + +#endif diff --git a/src/windows/identity/uilib/propsheet.c b/src/windows/identity/uilib/propsheet.c new file mode 100644 index 0000000000..749aa53bf3 --- /dev/null +++ b/src/windows/identity/uilib/propsheet.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khuidefs.h> +#ifdef DEBUG +#include<assert.h> +#endif + +KHMEXP khm_int32 KHMAPI khui_ps_create_sheet(khui_property_sheet ** sheet) +{ + khui_property_sheet * ps; + + ps = malloc(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 = malloc(sizeof(*p)); + ZeroMemory(p, sizeof(*p)); + + p->credtype = credtype; + p->ordinal = ordinal; + p->p_page = ppage; + + QPUT(sheet, p); + sheet->n_pages++; + + 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; + + p = QTOP(sheet); + + while(p) { + if(p->credtype == credtype) + break; + p = QNEXT(p); + } + + 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) { + /* l is a ** */ + return 0; +} + +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; + + 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; + phpsp[i++] = p->h_page; + p = QNEXT(p); + } + + /*TODO: sort property sheets */ + + s->header.phpage = phpsp; + + prv = PropertySheet(&s->header); + if(prv <= 0) { +#ifdef DEBUG + assert(FALSE); +#endif + /*TODO: better handling for this */ + hw = NULL; + } else { + DWORD dw; + + dw = GetLastError(); + s->status = KHUI_PS_STATUS_RUNNING; + + hw = (HWND) prv; + s->hwnd = hw; + s->hwnd_page = PropSheet_GetCurrentPageHwnd(hw); + } + + 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; + + DestroyWindow(sheet->hwnd); + sheet->hwnd = NULL; + + QGET(sheet, &p); + while(p) { + free(p); + QGET(sheet, &p); + } + + free(sheet); + + return KHM_ERROR_SUCCESS; +} diff --git a/src/windows/identity/uilib/propwnd.c b/src/windows/identity/uilib/propwnd.c new file mode 100644 index 0000000000..4d5d5488d9 --- /dev/null +++ b/src/windows/identity/uilib/propwnd.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khuidefs.h> + + +#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 new file mode 100644 index 0000000000..57ff309078 --- /dev/null +++ b/src/windows/identity/uilib/rescache.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khuidefs.h> +#include<hashtable.h> + +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 = malloc(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 = malloc(sizeof(int) * n); + + return il; +} + +KHMEXP BOOL KHMAPI +khui_delete_ilist(khui_ilist * il) { + DeleteObject(il->img); + DeleteObject(il->mask); + free(il->idlist); + free(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;i<il->nused;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; x<il->cx; 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 new file mode 100644 index 0000000000..04de09641d --- /dev/null +++ b/src/windows/identity/uilib/trackerwnd.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khuidefs.h> +#include<commctrl.h> +#include<assert.h> + +#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 | + TBS_DOWNISLEFT | 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. show the panel */ + if(tc->hw_slider == NULL) { + create_edit_sliders(hwnd, p, tc); + initialize_tracker(p, tc); + } + khui_tracker_reposition(tc); + ShowWindow(tc->hw_slider, SW_SHOWNOACTIVATE); + //SetActiveWindow(p); + } + 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; + + /* 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: + case WM_UNICHAR: + { + 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/uilibmain.c b/src/windows/identity/uilib/uilibmain.c new file mode 100644 index 0000000000..65fa7aff58 --- /dev/null +++ b/src/windows/identity/uilib/uilibmain.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khuidefs.h> + +extern void alert_init(void); +extern void alert_exit(void); + +void +uilib_process_attach(void) { + alert_init(); +} + +void +uilib_process_detach(void) { + alert_exit(); +} + diff --git a/src/windows/identity/util/Makefile b/src/windows/identity/util/Makefile new file mode 100644 index 0000000000..b9fc80e209 --- /dev/null +++ b/src/windows/identity/util/Makefile @@ -0,0 +1,46 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=util +!include <../config/Makefile.w32> + +INCFILES= \ + $(INCDIR)\utils.h \ + $(INCDIR)\hashtable.h \ + $(INCDIR)\mstring.h \ + $(INCDIR)\sync.h + +OBJFILES= \ + $(OBJ)\hashtable.obj \ + $(OBJ)\mstring.obj \ + $(OBJ)\sync.obj + +LIBFILES= + +SDKLIBFILES= + +all: mkdirs $(INCFILES) $(OBJFILES) + +clean:: + $(RM) $(INCFILES) diff --git a/src/windows/identity/util/hashtable.c b/src/windows/identity/util/hashtable.c new file mode 100644 index 0000000000..41f785a952 --- /dev/null +++ b/src/windows/identity/util/hashtable.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<hashtable.h> +#include<stdlib.h> + +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 = malloc(sizeof(hashtable)); + + h->n = n; + h->addr = addr; + h->comp = comp; + h->delr = delr; + h->hash = hash; + + h->bins = calloc(sizeof(hash_bin *), n); + + return h; +} + +KHMEXP void KHMAPI hash_del_hashtable(hashtable * h) { + hash_bin * b; + int i; + + for(i=0;i<h->n;i++) { + LPOP(&h->bins[i], &b); + while(b) { + if(h->delr) + h->delr(b->key, b->data); + free(b); + LPOP(&h->bins[i], &b); + } + } + + free(h); +} + +KHMEXP void KHMAPI hash_add(hashtable * h, 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 = malloc(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, 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); + free(b); + break; + } + b = LNEXT(b); + } +} + +KHMEXP void * KHMAPI hash_lookup(hashtable * h, 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, 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 new file mode 100644 index 0000000000..179d311f8b --- /dev/null +++ b/src/windows/identity/util/hashtable.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_HASHTABLE_H +#define __KHIMAIRA_HASHTABLE_H + +/*! \addtogroup util + @{ */ + +/*! \defgroup util_ht Hashtable + @{*/ + +#include<khdefs.h> +#include<khlist.h> + +/*! \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; + 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, 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, 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, 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, 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 *). + */ +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 *). + */ +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 new file mode 100644 index 0000000000..e9120d6009 --- /dev/null +++ b/src/windows/identity/util/mstring.c @@ -0,0 +1,516 @@ +/* +* Copyright (c) 2004 Massachusetts Institute of Technology +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* $Id$ */ + +#include<mstring.h> +#include<kherror.h> +#include<strsafe.h> +#include<stdlib.h> + +#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_PARM; + + 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_PARM; + + if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s)) || cch_s == 0) + return KHM_ERROR_INVALID_PARM; + cch_s++; + + s = ms; + + while(*s && ((s - ms) < KHM_MAXCCH_STRING)) { + if(FAILED(StringCchLength(s, KHM_MAXCB_STRING, &cch_t))) + return KHM_ERROR_INVALID_PARM; + s += cch_t + 1; + } + + if(*s || (s - ms) >= KHM_MAXCCH_STRING) { + return KHM_ERROR_INVALID_PARM; + } + + /* 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_PARM; + + if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s)) || cch_s == 0) + return KHM_ERROR_INVALID_PARM; + cch_s++; + + if(KHM_FAILED(multi_string_length_cch(ms, + KHM_MAXCCH_STRING, + &cch_r))) + return KHM_ERROR_INVALID_PARM; + + 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_PARM; + + 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_PARM; + e += cch + 1; + + if(!n) + n = e; + } + + if(*e || (e - s) >= KHM_MAXCCH_STRING) + return KHM_ERROR_INVALID_PARM; + + 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_PARM; + + /* 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_PARM; + 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_PARM; + + /* 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_PARM; + + 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_PARM; + + 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_PARM; + + 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_PARM; + + 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_PARM; + + 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 new file mode 100644 index 0000000000..9b4e3800e4 --- /dev/null +++ b/src/windows/identity/util/mstring.h @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_MSTRING_H +#define __KHIMAIRA_MSTRING_H + +#include<khdefs.h> + +/*! \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_PARM 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_PARM 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_PARM 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_PARM 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_PARM 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_PARM 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_PARM 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_PARM 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/sync.c b/src/windows/identity/util/sync.c new file mode 100644 index 0000000000..b50d484daf --- /dev/null +++ b/src/windows/identity/util/sync.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<windows.h> +#include<sync.h> +#include<assert.h> + +#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) +{ + DeleteCriticalSection(&(pLock->cs)); + CloseHandle(pLock->readwx); + CloseHandle(pLock->writewx); +} + +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++; + ResetEvent(pLock->readwx); + 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; + 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 new file mode 100644 index 0000000000..5410d0e522 --- /dev/null +++ b/src/windows/identity/util/sync.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_SYNC_H +#define __KHIMAIRA_SYNC_H + +#include<khdefs.h> + +/*! \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 <b>must</b> 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 new file mode 100644 index 0000000000..2e3b6b7daf --- /dev/null +++ b/src/windows/identity/util/utils.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_UTIL_H +#define __KHIMAIRA_UTIL_H + +/*! \defgroup util Utilities + */ +#include<hashtable.h> +#include<sync.h> +#include<mstring.h> + +#endif