officecfg/registry/schema/org/openoffice/Office/Common.xcs |  125 ++++++++++++
 sfx2/source/doc/docmacromode.cxx                           |   57 +++++
 sw/CppunitTest_sw_odfimport.mk                             |    8 
 sw/qa/extras/odfimport/data/ZoneMacroTest.odt              |binary
 sw/qa/extras/odfimport/odfimport.cxx                       |  130 +++++++++++++
 5 files changed, 320 insertions(+)

New commits:
commit b22bbfa25ab1f0b9cfa1dedc85b8f9874f0a5e5b
Author:     Vasily Melenchuk <vasily.melenc...@cib.de>
AuthorDate: Mon Dec 5 20:32:41 2022 +0300
Commit:     Thorsten Behrens <thorsten.behr...@allotropia.de>
CommitDate: Fri Dec 30 04:24:27 2022 +0000

    Related: tdf#125093 Check Windows Security Zones for macros
    
    In Windows, files get assigned security zones (local, from intranet,
    from internet, etc) after download via browser or email client. This
    is used by MS Word to decide in which mode it is safe to open file.
    
    This patch implements basic support for similar feature: by default
    there are no changes in macro behavior. But it is possible to use
    expert configuration options to tweak default behavior, and for
    example disable macros automatically, if a file is downloaded from
    Internet or other unsafe locations.
    
    Change-Id: I0bf1ae4e54d75dd5d07cab309124a67a85ef2d4d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143680
    Tested-by: Jenkins
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>

diff --git a/officecfg/registry/schema/org/openoffice/Office/Common.xcs 
b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
index 023ed391bfe1..f333657151f5 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Common.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
@@ -2814,6 +2814,131 @@
             <desc>List with trusted authors.</desc>
           </info>
         </set>
+        <group oor:name="WindowsSecurityZone">
+          <info>
+            <desc>Contains security settings regarding Basic scripts.</desc>
+          </info>
+          <prop oor:name="ZoneLocal" oor:type="xs:int" oor:nillable="false">
+            <info>
+              <desc>Action needed for opening document with macro with Windows 
zone 
+              identifier URLZONE_LOCAL_MACHINE (0, local machine).</desc>
+            </info>
+            <constraints>
+              <enumeration oor:value="0">
+                <info>
+                  <desc>Ask</desc>
+                </info>
+              </enumeration>
+              <enumeration oor:value="1">
+                <info>
+                  <desc>Allow</desc>
+                </info>
+              </enumeration>
+              <enumeration oor:value="2">
+                <info>
+                  <desc>Deny</desc>
+                </info>
+              </enumeration>
+            </constraints>
+            <value>0</value>
+          </prop>
+          <prop oor:name="ZoneIntranet" oor:type="xs:int" oor:nillable="false">
+            <info>
+              <desc>Action needed for opening document with macro with Windows 
zone 
+              identifier URLZONE_INTRANET (1, local machine).</desc>
+            </info>
+            <constraints>
+              <enumeration oor:value="0">
+                <info>
+                  <desc>Ask</desc>
+                </info>
+              </enumeration>
+              <enumeration oor:value="1">
+                <info>
+                  <desc>Allow</desc>
+                </info>
+              </enumeration>
+              <enumeration oor:value="2">
+                <info>
+                  <desc>Deny</desc>
+                </info>
+              </enumeration>
+            </constraints>
+            <value>0</value>
+          </prop>
+          <prop oor:name="ZoneTrusted" oor:type="xs:int" oor:nillable="false">
+            <info>
+              <desc>Action needed for opening document with macro with Windows 
zone 
+              identifier URLZONE_TRUSTED (2, trusted).</desc>
+            </info>
+            <constraints>
+              <enumeration oor:value="0">
+                <info>
+                  <desc>Ask</desc>
+                </info>
+              </enumeration>
+              <enumeration oor:value="1">
+                <info>
+                  <desc>Allow</desc>
+                </info>
+              </enumeration>
+              <enumeration oor:value="2">
+                <info>
+                  <desc>Deny</desc>
+                </info>
+              </enumeration>
+            </constraints>
+            <value>0</value>
+          </prop>
+          <prop oor:name="ZoneInternet" oor:type="xs:int" oor:nillable="false">
+            <info>
+              <desc>Action needed for opening document with macro with Windows 
zone 
+              identifier URLZONE_INTERNET (3, internet).</desc>
+            </info>
+            <constraints>
+              <enumeration oor:value="0">
+                <info>
+                  <desc>Ask</desc>
+                </info>
+              </enumeration>
+              <enumeration oor:value="1">
+                <info>
+                  <desc>Allow</desc>
+                </info>
+              </enumeration>
+              <enumeration oor:value="2">
+                <info>
+                  <desc>Deny</desc>
+                </info>
+              </enumeration>
+            </constraints>
+            <value>0</value>
+          </prop>
+          <prop oor:name="ZoneUntrusted" oor:type="xs:int" 
oor:nillable="false">
+            <info>
+              <desc>Action needed for opening document with macro with Windows 
zone 
+              identifier URLZONE_UNTRUSTED (3, untrusted source).</desc>
+            </info>
+            <constraints>
+              <enumeration oor:value="0">
+                <info>
+                  <desc>Ask</desc>
+                </info>
+              </enumeration>
+              <enumeration oor:value="1">
+                <info>
+                  <desc>Allow</desc>
+                </info>
+              </enumeration>
+              <enumeration oor:value="2">
+                <info>
+                  <desc>Deny</desc>
+                </info>
+              </enumeration>
+            </constraints>
+            <value>0</value>
+          </prop>
+        </group>
       </group>
     </group>
     <group oor:name="View">
diff --git a/sfx2/source/doc/docmacromode.cxx b/sfx2/source/doc/docmacromode.cxx
index bdae350b22f5..cbd720132323 100644
--- a/sfx2/source/doc/docmacromode.cxx
+++ b/sfx2/source/doc/docmacromode.cxx
@@ -38,6 +38,10 @@
 #include <comphelper/diagnose_ex.hxx>
 #include <tools/urlobj.hxx>
 
+#if defined(_WIN32)
+#include <systools/win32/comtools.hxx>
+#include <urlmon.h>
+#endif
 
 namespace sfx2
 {
@@ -284,6 +288,59 @@ namespace sfx2
             }
         }
 
+#if defined(_WIN32)
+        // Windows specific: try to decide macros loading depending on Windows 
Security Zones
+        // (is the file local, or it was downloaded from internet, etc?)
+        OUString sURL(m_xData->m_rDocumentAccess.getDocumentLocation());
+        OUString sFilePath;
+        osl::FileBase::getSystemPathFromFileURL(sURL, sFilePath);
+        sal::systools::COMReference<IZoneIdentifier> pZoneId;
+        pZoneId.CoCreateInstance(CLSID_PersistentZoneIdentifier);
+        sal::systools::COMReference<IPersistFile> pPersist(pZoneId, 
sal::systools::COM_QUERY_THROW);
+        DWORD dwZone;
+        if 
(!SUCCEEDED(pPersist->Load(reinterpret_cast<LPCOLESTR>(sFilePath.getStr()), 
STGM_READ)) ||
+            !SUCCEEDED(pZoneId->GetId(&dwZone)))
+        {
+            // no Security Zone info found -> assume a local file, not
+            // from the internet
+            dwZone = 0;
+        }
+
+        // determine action from zone and settings
+        sal_Int32 nAction = 0;
+        switch (dwZone) {
+            case 0:
+                nAction = 
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneLocal::get();
+                break;
+            case 1:
+                nAction = 
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneIntranet::get();
+                break;
+            case 2:
+                nAction = 
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneTrusted::get();
+                break;
+            case 3:
+                nAction = 
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneInternet::get();
+                break;
+            case 4:
+                nAction = 
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneUntrusted::get();
+                break;
+            default:
+                // unknown zone, let's ask the user
+                nAction = 0;
+                break;
+        }
+
+        // act on result
+        switch (nAction)
+        {
+            case 0: // Ask
+                break;
+            case 1: // Allow
+                return allowMacroExecution();
+            case 2: // Deny
+                return disallowMacroExecution();
+        }
+#endif
         // confirmation is required
         bool bSecure = false;
 
diff --git a/sw/CppunitTest_sw_odfimport.mk b/sw/CppunitTest_sw_odfimport.mk
index c57e737ee7f4..c1aeb0b9af7c 100644
--- a/sw/CppunitTest_sw_odfimport.mk
+++ b/sw/CppunitTest_sw_odfimport.mk
@@ -49,6 +49,10 @@ $(eval $(call gb_CppunitTest_set_include,sw_odfimport,\
     $$(INCLUDE) \
 ))
 
+$(eval $(call gb_CppunitTest_use_system_win32_libs,sw_odfimport,\
+       ole32 \
+))
+
 $(eval $(call gb_CppunitTest_use_api,sw_odfimport,\
        udkapi \
        offapi \
@@ -66,4 +70,8 @@ $(eval $(call gb_CppunitTest_add_arguments,sw_odfimport, \
     
-env:arg-env=$(gb_Helper_LIBRARY_PATH_VAR)"$$$${$(gb_Helper_LIBRARY_PATH_VAR)+=$$$$$(gb_Helper_LIBRARY_PATH_VAR)}"
 \
 ))
 
+$(eval $(call gb_CppunitTest_use_custom_headers,sw_odfimport,\
+       officecfg/registry \
+))
+
 # vim: set noet sw=4 ts=4:
diff --git a/sw/qa/extras/odfimport/data/ZoneMacroTest.odt 
b/sw/qa/extras/odfimport/data/ZoneMacroTest.odt
new file mode 100644
index 000000000000..01847632c637
Binary files /dev/null and b/sw/qa/extras/odfimport/data/ZoneMacroTest.odt 
differ
diff --git a/sw/qa/extras/odfimport/odfimport.cxx 
b/sw/qa/extras/odfimport/odfimport.cxx
index 6c8e5ec8230f..67c827b091da 100644
--- a/sw/qa/extras/odfimport/odfimport.cxx
+++ b/sw/qa/extras/odfimport/odfimport.cxx
@@ -41,8 +41,10 @@
 #include <com/sun/star/text/XTextFramesSupplier.hpp>
 #include <com/sun/star/document/XDocumentInsertable.hpp>
 #include <com/sun/star/style/ParagraphAdjust.hpp>
+#include <com/sun/star/document/MacroExecMode.hpp>
 
 #include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
 #include <editeng/boxitem.hxx>
 
 #include <IDocumentSettingAccess.hxx>
@@ -57,6 +59,13 @@
 #include <unotxdoc.hxx>
 #include <frmatr.hxx>
 
+#if defined(_WIN32)
+#include <officecfg/Office/Common.hxx>
+#include <unotools/securityoptions.hxx>
+#include <systools/win32/comtools.hxx>
+#include <urlmon.h>
+#endif
+
 typedef std::map<OUString, css::uno::Sequence< css::table::BorderLine> > 
AllBordersMap;
 typedef std::pair<OUString, css::uno::Sequence< css::table::BorderLine> > 
StringSequencePair;
 
@@ -1368,5 +1377,126 @@ CPPUNIT_TEST_FIXTURE(Test, testForcepoint108)
     mxComponent = 
mxDesktop->loadComponentFromURL(createFileURL(u"forcepoint108.fodt"), 
"_default", 0, {});
 }
 
+#ifdef _WIN32
+template <class T>
+void runWindowsFileZoneTests(css::uno::Reference<css::frame::XDesktop2> 
aDesktop,
+                             const OUString& sFileName, sal_Int32 configValue, 
sal_Int32 zoneId,
+                             sal_Bool expectedResult)
+{
+    // Set desired configuration params
+    auto xChanges = comphelper::ConfigurationChanges::create();
+    T::set(configValue, xChanges);
+    xChanges->commit();
+
+    // Set Windows Security Zone for temp file
+    sal::systools::COMReference<IZoneIdentifier> pZoneId;
+    pZoneId.CoCreateInstance(CLSID_PersistentZoneIdentifier);
+
+    // ignore setting of Zone 0, since at least for Windows Server
+    // setups, that always leads to E_ACCESSDENIED - presumably since
+    // the file is already local?
+    //
+    // See below for the workaround (calling tests for ZONE_LOCAL
+    // first)
+    if( zoneId != 0 )
+    {
+        CPPUNIT_ASSERT(SUCCEEDED(pZoneId->SetId(zoneId)));
+        sal::systools::COMReference<IPersistFile> pPersist(pZoneId, 
sal::systools::COM_QUERY_THROW);
+        OUString sTempFileWinPath;
+        osl::FileBase::getSystemPathFromFileURL(sFileName, sTempFileWinPath);
+        CPPUNIT_ASSERT(
+            
SUCCEEDED(pPersist->Save(reinterpret_cast<LPCOLESTR>(sTempFileWinPath.getStr()),
 TRUE)));
+    }
+
+    // Load doc with default for UI settings: do not suppress macro
+    uno::Sequence<beans::PropertyValue> aLoadArgs{ 
comphelper::makePropertyValue(
+        "MacroExecutionMode", css::document::MacroExecMode::USE_CONFIG) };
+    auto aComponent = aDesktop->loadComponentFromURL(sFileName, "_default", 0, 
aLoadArgs);
+
+    // Are macro enabled in doc?
+    SwXTextDocument* pTextDoc = 
dynamic_cast<SwXTextDocument*>(aComponent.get());
+    CPPUNIT_ASSERT_EQUAL(expectedResult, pTextDoc->getAllowMacroExecution());
+
+    aComponent->dispose();
+}
+#endif
+
+CPPUNIT_TEST_FIXTURE(Test, testWindowsFileZone)
+{
+// This makes sense only for Windows
+#ifdef _WIN32
+    // Create a temp copy of zone test file
+    utl::TempFileNamed aTempFile;
+    aTempFile.EnableKillingFile();
+    SvStream& aStreamDst = *aTempFile.GetStream(StreamMode::WRITE);
+    SvFileStream aStreamSrc(createFileURL(u"ZoneMacroTest.odt"), 
StreamMode::READ);
+    aStreamDst.WriteStream(aStreamSrc);
+    aTempFile.CloseStream();
+
+    // Tweak macro security to 1
+    SvtSecurityOptions::SetMacroSecurityLevel(1);
+
+    // Run all tests: set for temp file security zone and then check if macro 
are enabled
+    // depending on configuration values for given zone
+    // There is no easy way to check default (0) variant, so macro are 
disabled by default in these tests.
+
+    // run tests for ZoneLocal first, since runWindowsFileZoneTests
+    // ignores Zone 0 (see above) - assuming the initial file state is
+    // local after a copy, we're still triggering the expected
+    // behaviour
+    runWindowsFileZoneTests<
+        
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneLocal>(
+        mxDesktop, aTempFile.GetURL(), 0, 0, false);
+    runWindowsFileZoneTests<
+        
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneLocal>(
+        mxDesktop, aTempFile.GetURL(), 1, 0, true);
+    runWindowsFileZoneTests<
+        
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneLocal>(
+        mxDesktop, aTempFile.GetURL(), 2, 0, false);
+
+    // run tests for other zones (these actually set the Windows
+    // Security Zone at the file)
+    runWindowsFileZoneTests<
+        
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneUntrusted>(
+        mxDesktop, aTempFile.GetURL(), 0, 4, false);
+    runWindowsFileZoneTests<
+        
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneUntrusted>(
+        mxDesktop, aTempFile.GetURL(), 1, 4, true);
+    runWindowsFileZoneTests<
+        
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneUntrusted>(
+        mxDesktop, aTempFile.GetURL(), 2, 4, false);
+
+    runWindowsFileZoneTests<
+        
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneInternet>(
+        mxDesktop, aTempFile.GetURL(), 0, 3, false);
+    runWindowsFileZoneTests<
+        
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneInternet>(
+        mxDesktop, aTempFile.GetURL(), 1, 3, true);
+    runWindowsFileZoneTests<
+        
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneInternet>(
+        mxDesktop, aTempFile.GetURL(), 2, 3, false);
+
+    runWindowsFileZoneTests<
+        
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneTrusted>(
+        mxDesktop, aTempFile.GetURL(), 0, 2, false);
+    runWindowsFileZoneTests<
+        
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneTrusted>(
+        mxDesktop, aTempFile.GetURL(), 1, 2, true);
+    runWindowsFileZoneTests<
+        
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneTrusted>(
+        mxDesktop, aTempFile.GetURL(), 2, 2, false);
+
+    runWindowsFileZoneTests<
+        
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneIntranet>(
+        mxDesktop, aTempFile.GetURL(), 0, 1, false);
+    runWindowsFileZoneTests<
+        
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneIntranet>(
+        mxDesktop, aTempFile.GetURL(), 1, 1, true);
+    runWindowsFileZoneTests<
+        
officecfg::Office::Common::Security::Scripting::WindowsSecurityZone::ZoneIntranet>(
+        mxDesktop, aTempFile.GetURL(), 2, 1, false);
+#endif
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to