diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 17dadc2be..9faf99a1a 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -312,6 +312,7 @@ Properties on Installed Files /prop_inst/CPACK_NEVER_OVERWRITE.rst /prop_inst/CPACK_PERMANENT.rst + /prop_inst/CPACK_WIX_ACL.rst Deprecated Properties on Directories diff --git a/Help/prop_inst/CPACK_WIX_ACL.rst b/Help/prop_inst/CPACK_WIX_ACL.rst new file mode 100644 index 000000000..e7d526aab --- /dev/null +++ b/Help/prop_inst/CPACK_WIX_ACL.rst @@ -0,0 +1,17 @@ +CPACK_WIX_ACL +------------- + +Specifies access permissions for files installed by a WiX installer. + +The property can contain multiple list entries, +each of which has to match the following format. + +:: + + [@]=[,] + +```` and ```` specify the windows user and domain for which the +```` element should be generated. + +```` is any of the YesNoType attributes listed here: +http://wixtoolset.org/documentation/manual/v3/xsd/wix/permission.html diff --git a/Help/release/dev/wix-acl.rst b/Help/release/dev/wix-acl.rst new file mode 100644 index 000000000..bf146d055 --- /dev/null +++ b/Help/release/dev/wix-acl.rst @@ -0,0 +1,6 @@ +wix-acl +------- + +* The :manual:`cpack(1)` ``WiX`` generator learned to support + a :prop_inst:`CPACK_WIX_ACL` installed file property to + specify an Access Control List. diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 99166486f..ff7bc8da9 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -606,13 +606,14 @@ endif() if(WIN32) set(CPACK_SRCS ${CPACK_SRCS} CPack/WiX/cmCPackWIXGenerator.cxx - CPack/WiX/cmWIXSourceWriter.cxx + CPack/WiX/cmWIXAccessControlList.cxx CPack/WiX/cmWIXDirectoriesSourceWriter.cxx CPack/WiX/cmWIXFeaturesSourceWriter.cxx CPack/WiX/cmWIXFilesSourceWriter.cxx - CPack/WiX/cmWIXRichTextFormatWriter.cxx CPack/WiX/cmWIXPatch.cxx CPack/WiX/cmWIXPatchParser.cxx + CPack/WiX/cmWIXRichTextFormatWriter.cxx + CPack/WiX/cmWIXSourceWriter.cxx ) endif() diff --git a/Source/CPack/WiX/cmWIXAccessControlList.cxx b/Source/CPack/WiX/cmWIXAccessControlList.cxx new file mode 100644 index 000000000..aeec96861 --- /dev/null +++ b/Source/CPack/WiX/cmWIXAccessControlList.cxx @@ -0,0 +1,149 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2014 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmWIXAccessControlList.h" + +#include + +#include + +cmWIXAccessControlList::cmWIXAccessControlList( + cmCPackLog *logger, + cmInstalledFile const& installedFile, + cmWIXSourceWriter &sourceWriter): + Logger(logger), + InstalledFile(installedFile), + SourceWriter(sourceWriter) +{ + +} + +bool cmWIXAccessControlList::Apply() +{ + std::vector entries; + this->InstalledFile.GetPropertyAsList("CPACK_WIX_ACL", entries); + + for(size_t i = 0; i < entries.size(); ++i) + { + this->CreatePermissionElement(entries[i]); + } + + return true; +} + +void cmWIXAccessControlList::CreatePermissionElement( + std::string const& entry) +{ + std::string::size_type pos = entry.find('='); + if(pos == std::string::npos) + { + this->ReportError(entry, "Did not find mandatory '='"); + return; + } + + std::string user_and_domain = entry.substr(0, pos); + std::string permission_string = entry.substr(pos + 1); + + pos = user_and_domain.find('@'); + std::string user; + std::string domain; + if(pos != std::string::npos) + { + user = user_and_domain.substr(0, pos); + domain = user_and_domain.substr(pos + 1); + } + else + { + user = user_and_domain; + } + + std::vector permissions = + cmSystemTools::tokenize(permission_string, ","); + + this->SourceWriter.BeginElement("Permission"); + this->SourceWriter.AddAttribute("User", user); + if(domain.size()) + { + this->SourceWriter.AddAttribute("Domain", domain); + } + for(size_t i = 0; i < permissions.size(); ++i) + { + this->EmitBooleanAttribute(entry, + cmSystemTools::TrimWhitespace(permissions[i])); + } + this->SourceWriter.EndElement("Permission"); +} + +void cmWIXAccessControlList::ReportError( + std::string const& entry, + std::string const& message) +{ + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Failed processing ACL entry '" << entry << + "': " << message << std::endl); +} + +bool cmWIXAccessControlList::IsBooleanAttribute(std::string const& name) +{ + static const char* validAttributes[] = + { + "Append", + "ChangePermission", + "CreateChild", + "CreateFile", + "CreateLink", + "CreateSubkeys", + "Delete", + "DeleteChild", + "EnumerateSubkeys", + "Execute", + "FileAllRights", + "GenericAll", + "GenericExecute", + "GenericRead", + "GenericWrite", + "Notify", + "Read", + "ReadAttributes", + "ReadExtendedAttributes", + "ReadPermission", + "SpecificRightsAll", + "Synchronize", + "TakeOwnership", + "Traverse", + "Write", + "WriteAttributes", + "WriteExtendedAttributes", + 0 + }; + + size_t i = 0; + while(validAttributes[i]) + { + if(name == validAttributes[i++]) return true; + } + + return false; +} + +void cmWIXAccessControlList::EmitBooleanAttribute( + std::string const& entry, std::string const& name) +{ + if(!this->IsBooleanAttribute(name)) + { + std::stringstream message; + message << "Unknown boolean attribute '" << name << "'"; + this->ReportError(entry, message.str()); + } + + this->SourceWriter.AddAttribute(name, "yes"); +} diff --git a/Source/CPack/WiX/cmWIXAccessControlList.h b/Source/CPack/WiX/cmWIXAccessControlList.h new file mode 100644 index 000000000..20902f768 --- /dev/null +++ b/Source/CPack/WiX/cmWIXAccessControlList.h @@ -0,0 +1,46 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2014 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmWIXAccessControlList_h +#define cmWIXAccessControlList_h + +#include +#include + +#include "cmWIXSourceWriter.h" + +class cmWIXAccessControlList +{ +public: + cmWIXAccessControlList( + cmCPackLog *logger, + cmInstalledFile const& installedFile, + cmWIXSourceWriter &sourceWriter); + + bool Apply(); + +private: + void CreatePermissionElement(std::string const& entry); + + void ReportError(std::string const& entry, std::string const& message); + + bool IsBooleanAttribute(std::string const& name); + + void EmitBooleanAttribute( + std::string const& entry, std::string const& name); + + cmCPackLog* Logger; + cmInstalledFile const& InstalledFile; + cmWIXSourceWriter &SourceWriter; +}; + +#endif diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx index 451188ecf..0ad5d0c40 100644 --- a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx +++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx @@ -11,6 +11,7 @@ ============================================================================*/ #include "cmWIXFilesSourceWriter.h" +#include "cmWIXAccessControlList.h" #include @@ -175,6 +176,12 @@ std::string cmWIXFilesSourceWriter::EmitComponentFile( AddAttribute("ReadOnly", "yes"); } + if(installedFile) + { + cmWIXAccessControlList acl(Logger, *installedFile, *this); + acl.Apply(); + } + patch.ApplyFragment(fileId, *this); EndElement("File"); diff --git a/Source/CPack/WiX/cmWIXSourceWriter.h b/Source/CPack/WiX/cmWIXSourceWriter.h index 65b724056..3957d9663 100644 --- a/Source/CPack/WiX/cmWIXSourceWriter.h +++ b/Source/CPack/WiX/cmWIXSourceWriter.h @@ -45,6 +45,9 @@ public: static std::string WindowsCodepageToUtf8(std::string const& value); +protected: + cmCPackLog* Logger; + private: enum State { @@ -58,8 +61,6 @@ private: static std::string EscapeAttributeValue(std::string const& value); - cmCPackLog* Logger; - cmsys::ofstream File; State State; diff --git a/Source/cmInstalledFile.cxx b/Source/cmInstalledFile.cxx index 7813fcc5c..3483ecc60 100644 --- a/Source/cmInstalledFile.cxx +++ b/Source/cmInstalledFile.cxx @@ -111,3 +111,14 @@ bool cmInstalledFile::GetPropertyAsBool(const std::string& prop) const bool isSet = this->GetProperty(prop, value); return isSet && cmSystemTools::IsOn(value.c_str()); } + +//---------------------------------------------------------------------------- +void cmInstalledFile::GetPropertyAsList(const std::string& prop, + std::vector& list) const +{ + std::string value; + this->GetProperty(prop, value); + + list.clear(); + cmSystemTools::ExpandListArgument(value, list); +} diff --git a/Source/cmInstalledFile.h b/Source/cmInstalledFile.h index df28221bc..0292cd1bc 100644 --- a/Source/cmInstalledFile.h +++ b/Source/cmInstalledFile.h @@ -66,6 +66,9 @@ public: bool GetPropertyAsBool(const std::string& prop) const; + void GetPropertyAsList(const std::string& prop, + std::vector& list) const; + void SetName(cmMakefile* mf, const std::string& name); std::string const& GetName() const;