desktop/source/lib/init.cxx                    |   25 +++++
 include/osl/file.h                             |   48 +++++++++
 include/osl/file.hxx                           |   52 ++++++++++
 include/sfx2/lokhelper.hxx                     |    3 
 include/svx/PaletteManager.hxx                 |    4 
 include/svx/theme/IThemeColorChanger.hxx       |   10 +-
 include/svx/theme/ThemeColorChangerCommon.hxx  |    5 +
 include/svx/theme/ThemeColorPaletteManager.hxx |    3 
 include/tools/hostfilter.hxx                   |   28 +++++
 include/unotools/pathoptions.hxx               |    1 
 sal/osl/unx/file.cxx                           |  124 +++++++++++++++++++++++++
 sal/osl/unx/file_impl.hxx                      |    2 
 sal/osl/unx/file_misc.cxx                      |   34 ++++++
 sal/osl/unx/file_stat.cxx                      |    6 +
 sal/osl/unx/file_volume.cxx                    |    4 
 sal/osl/unx/pipe.cxx                           |    4 
 sal/osl/unx/process.cxx                        |    5 -
 sal/osl/unx/profile.cxx                        |    4 
 sal/qa/osl/file/osl_File.cxx                   |  118 +++++++++++++++++++++++
 sal/util/sal.map                               |    6 +
 sc/source/core/tool/webservicelink.cxx         |    8 +
 sc/source/filter/html/htmlpars.cxx             |   10 ++
 sc/source/ui/docshell/externalrefmgr.cxx       |    5 -
 sc/source/ui/drawfunc/fuins1.cxx               |   11 ++
 sc/source/ui/inc/ThemeColorChanger.hxx         |    2 
 sc/source/ui/theme/ThemeColorChanger.cxx       |    4 
 sc/source/ui/view/tabvwshc.cxx                 |    9 +
 sd/inc/theme/ThemeColorChanger.hxx             |    2 
 sd/source/core/ThemeColorChanger.cxx           |    4 
 sd/source/ui/func/fuinsert.cxx                 |   14 ++
 sd/source/ui/inc/ViewShellBase.hxx             |    2 
 sd/source/ui/view/ViewShellBase.cxx            |   15 +++
 sd/source/ui/view/drviews2.cxx                 |    8 -
 sfx2/source/view/lokhelper.cxx                 |   17 +++
 svx/source/tbxctrls/PaletteManager.cxx         |   36 +++++++
 svx/source/theme/ThemeColorChangerCommon.cxx   |   56 +++++++----
 svx/source/theme/ThemeColorPaletteManager.cxx  |    9 -
 sw/source/core/inc/ThemeColorChanger.hxx       |    2 
 sw/source/core/model/ThemeColorChanger.cxx     |    4 
 sw/source/filter/html/htmlgrin.cxx             |    6 +
 sw/source/uibase/shells/basesh.cxx             |    7 -
 sw/source/uibase/uiview/view.cxx               |    7 -
 sw/source/uibase/uiview/view2.cxx              |   10 ++
 tools/Library_tl.mk                            |    1 
 tools/source/inet/hostfilter.cxx               |   31 ++++++
 ucb/source/ucp/webdav-curl/CurlSession.cxx     |    7 +
 unotools/source/config/pathoptions.cxx         |    6 +
 47 files changed, 718 insertions(+), 61 deletions(-)

New commits:
commit 88281b55c1d781f73a663188229c639a290c53bc
Author:     Szymon Kłos <szymon.k...@collabora.com>
AuthorDate: Mon Jan 8 18:46:13 2024 +0100
Commit:     Szymon Kłos <szymon.k...@collabora.com>
CommitDate: Mon Jan 15 21:07:28 2024 +0100

    Send document colors with lok callback
    
    First step for publishing any palette for LOK.
    Let's start with Document colors (colors used in the
    document) which can be extracted similar to theme
    colors from SfxViewShell.
    
    Modify generateJSON function so it appends palette into
    existing ptree/JSON.
    
    In the next step we can make it more generic so it will
    be able to send any palette managed by PaletteManager.
    
    Change-Id: Ibb56690af6dfd59ee232e88b28e7a3d312d0e16c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161798
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>
    (cherry picked from commit 0460be8848b0ce02c07183e41dd7137ac3b94164)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161941
    Tested-by: Jenkins
    Reviewed-by: Szymon Kłos <szymon.k...@collabora.com>

diff --git a/include/svx/PaletteManager.hxx b/include/svx/PaletteManager.hxx
index 81f30ea7de76..90fa00de59fe 100644
--- a/include/svx/PaletteManager.hxx
+++ b/include/svx/PaletteManager.hxx
@@ -27,6 +27,7 @@
 #include <deque>
 #include <vector>
 #include <memory>
+#include <set>
 
 namespace com::sun::star::uno { class XComponentContext; }
 namespace svx { class ToolboxButtonColorUpdaterBase; }
@@ -86,6 +87,9 @@ public:
     bool GetLumModOff(sal_uInt16 nThemeIndex, sal_uInt16 nEffect, sal_Int16& 
rLumMod, sal_Int16& rLumOff);
 
     static void DispatchColorCommand(const OUString& aCommand, const 
NamedColor& rColor);
+
+    /// Appends node for Document Colors into the ptree
+    static void generateJSON(boost::property_tree::ptree& aTree, const 
std::set<Color>& rColors);
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/svx/theme/IThemeColorChanger.hxx 
b/include/svx/theme/IThemeColorChanger.hxx
index 0b3b88d60afa..035494f12324 100644
--- a/include/svx/theme/IThemeColorChanger.hxx
+++ b/include/svx/theme/IThemeColorChanger.hxx
@@ -22,7 +22,7 @@ public:
     void apply(std::shared_ptr<model::ColorSet> const& pColorSet)
     {
         doApply(pColorSet);
-        svx::theme::notifyLOK(pColorSet);
+        svx::theme::notifyLOK(pColorSet, std::set<Color>());
     }
 
 private:
diff --git a/include/svx/theme/ThemeColorChangerCommon.hxx 
b/include/svx/theme/ThemeColorChangerCommon.hxx
index 3a585236fbf8..9fa3f4376ddc 100644
--- a/include/svx/theme/ThemeColorChangerCommon.hxx
+++ b/include/svx/theme/ThemeColorChangerCommon.hxx
@@ -9,6 +9,7 @@
 
 #pragma once
 
+#include <set>
 #include <svx/svxdllapi.h>
 #include <docmodel/theme/ColorSet.hxx>
 #include <svx/svdobj.hxx>
@@ -22,7 +23,9 @@ namespace theme
 SVXCORE_DLLPUBLIC void updateSdrObject(model::ColorSet const& rColorSet, 
SdrObject* pObject,
                                        SdrView* pView, SfxUndoManager* 
pUndoManager = nullptr);
 
-SVXCORE_DLLPUBLIC void notifyLOK(std::shared_ptr<model::ColorSet> const& 
pColorSet);
+/// Sends to the LOK updated palettes
+SVXCORE_DLLPUBLIC void notifyLOK(std::shared_ptr<model::ColorSet> const& 
pColorSet,
+                                 const std::set<Color>& rDocumentColors);
 }
 
 } // end svx namespace
diff --git a/include/svx/theme/ThemeColorPaletteManager.hxx 
b/include/svx/theme/ThemeColorPaletteManager.hxx
index 7bb8526a2409..8531021bbc84 100644
--- a/include/svx/theme/ThemeColorPaletteManager.hxx
+++ b/include/svx/theme/ThemeColorPaletteManager.hxx
@@ -14,6 +14,7 @@
 #include <memory>
 #include <tools/color.hxx>
 #include <docmodel/theme/ThemeColorType.hxx>
+#include <boost/property_tree/json_parser.hpp>
 
 namespace model
 {
@@ -60,7 +61,7 @@ class SVXCORE_DLLPUBLIC ThemeColorPaletteManager final
 public:
     ThemeColorPaletteManager(std::shared_ptr<model::ColorSet> const& 
pColorSet);
     ThemePaletteCollection generate();
-    OString generateJSON();
+    void generateJSON(boost::property_tree::ptree& aTree);
 };
 
 } // end svx namespace
diff --git a/sc/source/ui/view/tabvwshc.cxx b/sc/source/ui/view/tabvwshc.cxx
index 3cde75058033..13d852f58630 100644
--- a/sc/source/ui/view/tabvwshc.cxx
+++ b/sc/source/ui/view/tabvwshc.cxx
@@ -479,7 +479,9 @@ void ScTabViewShell::afterCallbackRegistered()
     SfxObjectShell* pDocShell = GetObjectShell();
     if (pDocShell)
     {
-        svx::theme::notifyLOK(pDocShell->GetThemeColors());
+        std::shared_ptr<model::ColorSet> pThemeColors = 
pDocShell->GetThemeColors();
+        std::set<Color> aDocumentColors = pDocShell->GetDocColors();
+        svx::theme::notifyLOK(pThemeColors, aDocumentColors);
     }
 }
 
diff --git a/sd/source/ui/view/ViewShellBase.cxx 
b/sd/source/ui/view/ViewShellBase.cxx
index 6ba412acf7d9..70691ce1133e 100644
--- a/sd/source/ui/view/ViewShellBase.cxx
+++ b/sd/source/ui/view/ViewShellBase.cxx
@@ -1019,7 +1019,9 @@ void ViewShellBase::afterCallbackRegistered()
     SfxObjectShell* pDocShell = GetObjectShell();
     if (pDocShell)
     {
-        svx::theme::notifyLOK(pDocShell->GetThemeColors());
+        std::shared_ptr<model::ColorSet> pThemeColors = 
pDocShell->GetThemeColors();
+        std::set<Color> aDocumentColors = pDocShell->GetDocColors();
+        svx::theme::notifyLOK(pThemeColors, aDocumentColors);
     }
 }
 
diff --git a/svx/source/tbxctrls/PaletteManager.cxx 
b/svx/source/tbxctrls/PaletteManager.cxx
index a98149ff30bb..c9330eec408f 100644
--- a/svx/source/tbxctrls/PaletteManager.cxx
+++ b/svx/source/tbxctrls/PaletteManager.cxx
@@ -50,7 +50,6 @@
 #include <memory>
 #include <array>
 #include <stack>
-#include <set>
 
 PaletteManager::PaletteManager() :
     
mnMaxRecentColors(Application::GetSettings().GetStyleSettings().GetColorValueSetColumnCount()),
@@ -469,4 +468,39 @@ void PaletteManager::DispatchColorCommand(const OUString& 
aCommand, const NamedC
     }
 }
 
+// TODO: make it generic, send any palette
+void PaletteManager::generateJSON(boost::property_tree::ptree& aTree, const 
std::set<Color>& rColors)
+{
+    boost::property_tree::ptree aColorListTree;
+    sal_uInt32 nStartIndex = 1;
+
+    const StyleSettings& rStyleSettings = 
Application::GetSettings().GetStyleSettings();
+    sal_uInt32 nColumnCount = rStyleSettings.GetColorValueSetColumnCount();
+    const OUString 
aNamePrefix(Concat2View(SvxResId(RID_SVXSTR_DOC_COLOR_PREFIX) + " "));
+
+    auto aColorIt = rColors.begin();
+    while (aColorIt != rColors.end())
+    {
+        boost::property_tree::ptree aColorRowTree;
+
+        for (sal_uInt32 nColumn = 0; nColumn < nColumnCount; nColumn++)
+        {
+            boost::property_tree::ptree aColorTree;
+            OUString sName = aNamePrefix + OUString::number(nStartIndex++);
+            aColorTree.put("Value", aColorIt->AsRGBHexString().toUtf8());
+            aColorTree.put("Name", sName);
+
+            aColorRowTree.push_back(std::make_pair("", aColorTree));
+
+            aColorIt++;
+            if (aColorIt == rColors.end())
+                break;
+        }
+
+        aColorListTree.push_back(std::make_pair("", aColorRowTree));
+    }
+
+    aTree.add_child("DocumentColors", aColorListTree);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/theme/ThemeColorChangerCommon.cxx 
b/svx/source/theme/ThemeColorChangerCommon.cxx
index 0e3548ed83cc..bca8ea1a1bb7 100644
--- a/svx/source/theme/ThemeColorChangerCommon.cxx
+++ b/svx/source/theme/ThemeColorChangerCommon.cxx
@@ -22,6 +22,7 @@
 
 #include <sfx2/lokhelper.hxx>
 
+#include <svx/PaletteManager.hxx>
 #include <svx/svdmodel.hxx>
 #include <svx/svdotext.hxx>
 #include <svx/svdundo.hxx>
@@ -171,12 +172,23 @@ void updateSdrObject(model::ColorSet const& rColorSet, 
SdrObject* pObject, SdrVi
         updateEditEngTextSections(rColorSet, pObject, *pView);
 }
 
-void notifyLOK(std::shared_ptr<model::ColorSet> const& pColorSet)
+void notifyLOK(std::shared_ptr<model::ColorSet> const& pColorSet,
+               const std::set<Color>& rDocumentColors)
 {
     if (comphelper::LibreOfficeKit::isActive())
     {
         svx::ThemeColorPaletteManager aManager(pColorSet);
-        SfxLokHelper::notifyAllViews(LOK_CALLBACK_COLOR_PALETTES, 
aManager.generateJSON());
+        std::stringstream aStream;
+        boost::property_tree::ptree aTree;
+
+        if (pColorSet)
+            aManager.generateJSON(aTree);
+        if (rDocumentColors.size())
+            PaletteManager::generateJSON(aTree, rDocumentColors);
+
+        boost::property_tree::write_json(aStream, aTree);
+
+        SfxLokHelper::notifyAllViews(LOK_CALLBACK_COLOR_PALETTES, 
OString(aStream.str()));
     }
 }
 
diff --git a/svx/source/theme/ThemeColorPaletteManager.cxx 
b/svx/source/theme/ThemeColorPaletteManager.cxx
index 0e4f20899645..a89456576736 100644
--- a/svx/source/theme/ThemeColorPaletteManager.cxx
+++ b/svx/source/theme/ThemeColorPaletteManager.cxx
@@ -16,7 +16,6 @@
 #include <svx/strings.hrc>
 #include <docmodel/theme/ColorSet.hxx>
 #include <docmodel/color/ComplexColorJSON.hxx>
-#include <boost/property_tree/json_parser.hpp>
 
 #include <array>
 
@@ -127,11 +126,10 @@ svx::ThemePaletteCollection 
ThemeColorPaletteManager::generate()
     return aThemePaletteCollection;
 }
 
-OString ThemeColorPaletteManager::generateJSON()
+void ThemeColorPaletteManager::generateJSON(boost::property_tree::ptree& aTree)
 {
     svx::ThemePaletteCollection aThemePaletteCollection = generate();
 
-    boost::property_tree::ptree aTree;
     boost::property_tree::ptree aColorListTree;
 
     for (size_t nEffect = 0; nEffect < 6; ++nEffect)
@@ -161,11 +159,6 @@ OString ThemeColorPaletteManager::generateJSON()
     }
 
     aTree.add_child("ThemeColors", aColorListTree);
-
-    std::stringstream aStream;
-    boost::property_tree::write_json(aStream, aTree);
-
-    return OString(aStream.str());
 }
 
 } // end svx namespace
diff --git a/sw/source/uibase/uiview/view.cxx b/sw/source/uibase/uiview/view.cxx
index 0474824e69eb..8583fc004a5a 100644
--- a/sw/source/uibase/uiview/view.cxx
+++ b/sw/source/uibase/uiview/view.cxx
@@ -1218,7 +1218,9 @@ void SwView::afterCallbackRegistered()
     auto* pDocShell = GetDocShell();
     if (pDocShell)
     {
-        svx::theme::notifyLOK(pDocShell->GetThemeColors());
+        std::shared_ptr<model::ColorSet> pThemeColors = 
pDocShell->GetThemeColors();
+        std::set<Color> aDocumentColors = pDocShell->GetDocColors();
+        svx::theme::notifyLOK(pThemeColors, aDocumentColors);
     }
 }
 
commit 035cd913e0361cce9d799eb3b331b6d7bcf7910e
Author:     Szymon Kłos <szymon.k...@collabora.com>
AuthorDate: Sun Jan 7 18:31:22 2024 +0100
Commit:     Szymon Kłos <szymon.k...@collabora.com>
CommitDate: Mon Jan 15 21:07:27 2024 +0100

    sc: announce theme colors with lok callback
    
    As it is done already for Writer. Unfortunately cannot
    move the code from afterCallbackRegistered to base class
    in sfx2 as it is not linked to svx which is needed to
    generate JSON. So at least share generation and sending
    part in ThemeColorChangerCommon.
    
    Signed-off-by: Szymon Kłos <szymon.k...@collabora.com>
    Change-Id: Icbf681230bd4c49698c47d852a0862620d93bcec
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161771
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161927
    Tested-by: Jenkins

diff --git a/include/svx/theme/IThemeColorChanger.hxx 
b/include/svx/theme/IThemeColorChanger.hxx
index d9273238c712..0b3b88d60afa 100644
--- a/include/svx/theme/IThemeColorChanger.hxx
+++ b/include/svx/theme/IThemeColorChanger.hxx
@@ -11,6 +11,7 @@
 
 #include <svx/svxdllapi.h>
 #include <docmodel/theme/ColorSet.hxx>
+#include "ThemeColorChangerCommon.hxx"
 
 namespace svx
 {
@@ -18,7 +19,14 @@ class SVXCORE_DLLPUBLIC IThemeColorChanger
 {
 public:
     virtual ~IThemeColorChanger() = default;
-    virtual void apply(std::shared_ptr<model::ColorSet> const& pColorSet) = 0;
+    void apply(std::shared_ptr<model::ColorSet> const& pColorSet)
+    {
+        doApply(pColorSet);
+        svx::theme::notifyLOK(pColorSet);
+    }
+
+private:
+    virtual void doApply(std::shared_ptr<model::ColorSet> const& pColorSet) = 
0;
 };
 
 } // end svx namespace
diff --git a/include/svx/theme/ThemeColorChangerCommon.hxx 
b/include/svx/theme/ThemeColorChangerCommon.hxx
index febc34ae3873..3a585236fbf8 100644
--- a/include/svx/theme/ThemeColorChangerCommon.hxx
+++ b/include/svx/theme/ThemeColorChangerCommon.hxx
@@ -21,6 +21,8 @@ namespace theme
 {
 SVXCORE_DLLPUBLIC void updateSdrObject(model::ColorSet const& rColorSet, 
SdrObject* pObject,
                                        SdrView* pView, SfxUndoManager* 
pUndoManager = nullptr);
+
+SVXCORE_DLLPUBLIC void notifyLOK(std::shared_ptr<model::ColorSet> const& 
pColorSet);
 }
 
 } // end svx namespace
diff --git a/sc/source/ui/inc/ThemeColorChanger.hxx 
b/sc/source/ui/inc/ThemeColorChanger.hxx
index 57ca91cdb83c..f85401385888 100644
--- a/sc/source/ui/inc/ThemeColorChanger.hxx
+++ b/sc/source/ui/inc/ThemeColorChanger.hxx
@@ -24,7 +24,7 @@ public:
     ThemeColorChanger(ScDocShell& rDocShell);
     virtual ~ThemeColorChanger() override;
 
-    void apply(std::shared_ptr<model::ColorSet> const& pColorSet) override;
+    void doApply(std::shared_ptr<model::ColorSet> const& pColorSet) override;
 };
 
 } // end sc namespace
diff --git a/sc/source/ui/theme/ThemeColorChanger.cxx 
b/sc/source/ui/theme/ThemeColorChanger.cxx
index c9b88652dcc3..2ba881544372 100644
--- a/sc/source/ui/theme/ThemeColorChanger.cxx
+++ b/sc/source/ui/theme/ThemeColorChanger.cxx
@@ -19,7 +19,7 @@
 #include <editeng/boxitem.hxx>
 #include <editeng/borderline.hxx>
 #include <svx/svditer.hxx>
-#include <svx/theme/ThemeColorChangerCommon.hxx>
+#include <svx/theme/IThemeColorChanger.hxx>
 
 #include <undodraw.hxx>
 #include <stlpool.hxx>
@@ -311,7 +311,7 @@ void changeThemeColorInTheDocModel(ScDocShell& rDocShell,
 
 } // end anonymous ns
 
-void ThemeColorChanger::apply(std::shared_ptr<model::ColorSet> const& 
pColorSet)
+void ThemeColorChanger::doApply(std::shared_ptr<model::ColorSet> const& 
pColorSet)
 {
     // Can't change to an empty color set
     if (!pColorSet)
diff --git a/sc/source/ui/view/tabvwshc.cxx b/sc/source/ui/view/tabvwshc.cxx
index 147bf68c4968..3cde75058033 100644
--- a/sc/source/ui/view/tabvwshc.cxx
+++ b/sc/source/ui/view/tabvwshc.cxx
@@ -20,6 +20,7 @@
 #include <scitems.hxx>
 #include <sfx2/childwin.hxx>
 #include <sfx2/dispatch.hxx>
+#include <svx/theme/ThemeColorChangerCommon.hxx>
 #include <editeng/editview.hxx>
 #include <inputhdl.hxx>
 
@@ -474,6 +475,12 @@ void ScTabViewShell::afterCallbackRegistered()
             pInputWindow->NotifyLOKClient();
         }
     }
+
+    SfxObjectShell* pDocShell = GetObjectShell();
+    if (pDocShell)
+    {
+        svx::theme::notifyLOK(pDocShell->GetThemeColors());
+    }
 }
 
 void ScTabViewShell::NotifyCursor(SfxViewShell* pOtherShell) const
diff --git a/sd/inc/theme/ThemeColorChanger.hxx 
b/sd/inc/theme/ThemeColorChanger.hxx
index ff100fd511ce..6a467bc4c47a 100644
--- a/sd/inc/theme/ThemeColorChanger.hxx
+++ b/sd/inc/theme/ThemeColorChanger.hxx
@@ -27,7 +27,7 @@ public:
     ThemeColorChanger(SdrPage* pMasterPage, sd::DrawDocShell* pDocShell);
     virtual ~ThemeColorChanger() override;
 
-    void apply(std::shared_ptr<model::ColorSet> const& pColorSet) override;
+    void doApply(std::shared_ptr<model::ColorSet> const& pColorSet) override;
 };
 
 } // end sd namespace
diff --git a/sd/source/core/ThemeColorChanger.cxx 
b/sd/source/core/ThemeColorChanger.cxx
index 70d14bc37438..b941407881ed 100644
--- a/sd/source/core/ThemeColorChanger.cxx
+++ b/sd/source/core/ThemeColorChanger.cxx
@@ -9,7 +9,7 @@
 
 #include <editeng/colritem.hxx>
 #include <theme/ThemeColorChanger.hxx>
-#include <svx/theme/ThemeColorChangerCommon.hxx>
+#include <svx/theme/IThemeColorChanger.hxx>
 #include <svx/svdmodel.hxx>
 #include <svx/svditer.hxx>
 #include <docmodel/theme/Theme.hxx>
@@ -133,7 +133,7 @@ bool changeStyles(sd::DrawDocShell* pDocShell, 
std::shared_ptr<model::ColorSet>
 
 } // end anonymous ns
 
-void ThemeColorChanger::apply(std::shared_ptr<model::ColorSet> const& 
pColorSet)
+void ThemeColorChanger::doApply(std::shared_ptr<model::ColorSet> const& 
pColorSet)
 {
     auto* pUndoManager = mpDocShell->GetUndoManager();
     sd::ViewShell* pViewShell = mpDocShell->GetViewShell();
diff --git a/sd/source/ui/inc/ViewShellBase.hxx 
b/sd/source/ui/inc/ViewShellBase.hxx
index acdd244c70f3..e31429f6e41a 100644
--- a/sd/source/ui/inc/ViewShellBase.hxx
+++ b/sd/source/ui/inc/ViewShellBase.hxx
@@ -217,6 +217,8 @@ public:
     int getEditMode() const override;
     /// See SfxViewShell::setEditMode().
     void setEditMode(int nMode);
+    /// See SfxViewShell::afterCallbackRegistered().
+    void afterCallbackRegistered() override;
     /// See SfxViewShell::NotifyCursor().
     void NotifyCursor(SfxViewShell* pViewShell) const override;
     /// See SfxViewShell::GetColorConfigColor().
diff --git a/sd/source/ui/view/ViewShellBase.cxx 
b/sd/source/ui/view/ViewShellBase.cxx
index 9e8e7b1aa5d4..6ba412acf7d9 100644
--- a/sd/source/ui/view/ViewShellBase.cxx
+++ b/sd/source/ui/view/ViewShellBase.cxx
@@ -62,6 +62,7 @@
 #include <sfx2/objface.hxx>
 #include <sfx2/viewfrm.hxx>
 #include <svl/whiter.hxx>
+#include <svx/theme/ThemeColorChangerCommon.hxx>
 #include <vcl/commandinfoprovider.hxx>
 #include <vcl/settings.hxx>
 #include <vcl/svapp.hxx>
@@ -1010,6 +1011,18 @@ void ViewShellBase::setEditMode(int nMode)
     }
 }
 
+void ViewShellBase::afterCallbackRegistered()
+{
+    // common tasks
+    SfxViewShell::afterCallbackRegistered();
+
+    SfxObjectShell* pDocShell = GetObjectShell();
+    if (pDocShell)
+    {
+        svx::theme::notifyLOK(pDocShell->GetThemeColors());
+    }
+}
+
 void ViewShellBase::NotifyCursor(SfxViewShell* pOtherShell) const
 {
     ViewShell* pThisShell = 
framework::FrameworkHelper::Instance(*const_cast<ViewShellBase*>(this))->GetViewShell(FrameworkHelper::msCenterPaneURL).get();
diff --git a/sd/source/ui/view/drviews2.cxx b/sd/source/ui/view/drviews2.cxx
index 90cde7c792f5..0847df373f44 100644
--- a/sd/source/ui/view/drviews2.cxx
+++ b/sd/source/ui/view/drviews2.cxx
@@ -188,8 +188,6 @@
 
 #include <theme/ThemeColorChanger.hxx>
 #include <svx/dialog/ThemeDialog.hxx>
-#include <svx/theme/ThemeColorPaletteManager.hxx>
-#include <sfx2/lokhelper.hxx>
 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
 
 #include <ViewShellBase.hxx>
@@ -3562,12 +3560,6 @@ void DrawViewShell::FuTemporary(SfxRequest& rReq)
                 {
                     sd::ThemeColorChanger aChanger(pMasterPage, pDocShell);
                     aChanger.apply(pColorSet);
-
-                    if (comphelper::LibreOfficeKit::isActive())
-                    {
-                        svx::ThemeColorPaletteManager aManager(pColorSet);
-                        
SfxLokHelper::notifyAllViews(LOK_CALLBACK_COLOR_PALETTES, 
aManager.generateJSON());
-                    }
                 }
             });
 
diff --git a/svx/source/theme/ThemeColorChangerCommon.cxx 
b/svx/source/theme/ThemeColorChangerCommon.cxx
index 82f915fef930..0e3548ed83cc 100644
--- a/svx/source/theme/ThemeColorChangerCommon.cxx
+++ b/svx/source/theme/ThemeColorChangerCommon.cxx
@@ -7,30 +7,29 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-#include <svx/theme/ThemeColorChangerCommon.hxx>
+#include <comphelper/lok.hxx>
 
-#include <sal/config.h>
-#include <editeng/colritem.hxx>
-#include <editeng/unoprnms.hxx>
-#include <docmodel/uno/UnoComplexColor.hxx>
 #include <docmodel/theme/ColorSet.hxx>
 
-#include <com/sun/star/text/XTextRange.hpp>
-#include <com/sun/star/container/XEnumerationAccess.hpp>
-#include <com/sun/star/container/XEnumeration.hpp>
-#include <com/sun/star/beans/XPropertySet.hpp>
-#include <com/sun/star/util/XComplexColor.hpp>
-
-#include <svx/xlnclit.hxx>
-#include <svx/xflclit.hxx>
-#include <svx/xdef.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/editeng.hxx>
 #include <editeng/eeitem.hxx>
-#include <svx/svdundo.hxx>
+#include <editeng/section.hxx>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+
+#include <sal/config.h>
+
+#include <sfx2/lokhelper.hxx>
+
 #include <svx/svdmodel.hxx>
 #include <svx/svdotext.hxx>
-
-#include <editeng/editeng.hxx>
-#include <editeng/section.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/theme/ThemeColorChangerCommon.hxx>
+#include <svx/theme/ThemeColorPaletteManager.hxx>
+#include <svx/xdef.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xflclit.hxx>
 
 using namespace css;
 
@@ -172,6 +171,15 @@ void updateSdrObject(model::ColorSet const& rColorSet, 
SdrObject* pObject, SdrVi
         updateEditEngTextSections(rColorSet, pObject, *pView);
 }
 
+void notifyLOK(std::shared_ptr<model::ColorSet> const& pColorSet)
+{
+    if (comphelper::LibreOfficeKit::isActive())
+    {
+        svx::ThemeColorPaletteManager aManager(pColorSet);
+        SfxLokHelper::notifyAllViews(LOK_CALLBACK_COLOR_PALETTES, 
aManager.generateJSON());
+    }
+}
+
 } // end svx::theme namespace
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/inc/ThemeColorChanger.hxx 
b/sw/source/core/inc/ThemeColorChanger.hxx
index 6eeb3a25f612..f919496fd595 100644
--- a/sw/source/core/inc/ThemeColorChanger.hxx
+++ b/sw/source/core/inc/ThemeColorChanger.hxx
@@ -25,7 +25,7 @@ public:
     ThemeColorChanger(SwDocShell* pDocSh);
     virtual ~ThemeColorChanger() override;
 
-    void apply(std::shared_ptr<model::ColorSet> const& pColorSet) override;
+    void doApply(std::shared_ptr<model::ColorSet> const& pColorSet) override;
 };
 
 } // end sw namespace
diff --git a/sw/source/core/model/ThemeColorChanger.cxx 
b/sw/source/core/model/ThemeColorChanger.cxx
index 8cbc0b971066..c61ea96b2a5a 100644
--- a/sw/source/core/model/ThemeColorChanger.cxx
+++ b/sw/source/core/model/ThemeColorChanger.cxx
@@ -34,7 +34,7 @@
 #include <sal/config.h>
 #include <svx/svdpage.hxx>
 #include <svx/svditer.hxx>
-#include <svx/theme/ThemeColorChangerCommon.hxx>
+#include <svx/theme/IThemeColorChanger.hxx>
 #include <docmodel/uno/UnoComplexColor.hxx>
 #include <docmodel/theme/Theme.hxx>
 #include <editeng/unoprnms.hxx>
@@ -322,7 +322,7 @@ ThemeColorChanger::ThemeColorChanger(SwDocShell* pDocSh)
 
 ThemeColorChanger::~ThemeColorChanger() = default;
 
-void ThemeColorChanger::apply(std::shared_ptr<model::ColorSet> const& 
pColorSet)
+void ThemeColorChanger::doApply(std::shared_ptr<model::ColorSet> const& 
pColorSet)
 {
     SwDoc* pDocument = mpDocSh->GetDoc();
     if (!pDocument)
diff --git a/sw/source/uibase/shells/basesh.cxx 
b/sw/source/uibase/shells/basesh.cxx
index 57e7c8299546..52e24b0b6077 100644
--- a/sw/source/uibase/shells/basesh.cxx
+++ b/sw/source/uibase/shells/basesh.cxx
@@ -91,7 +91,6 @@
 #include <SwRewriter.hxx>
 #include <GraphicSizeCheck.hxx>
 #include <svx/galleryitem.hxx>
-#include <svx/theme/ThemeColorPaletteManager.hxx>
 #include <sfx2/devtools/DevelopmentToolChildWindow.hxx>
 #include <com/sun/star/gallery/GalleryItemType.hpp>
 #include <com/sun/star/beans/PropertyValues.hpp>
@@ -102,7 +101,6 @@
 #include <svx/dialog/ThemeDialog.hxx>
 #include <comphelper/scopeguard.hxx>
 #include <comphelper/lok.hxx>
-#include <sfx2/lokhelper.hxx>
 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
 #include <osl/diagnose.h>
 
@@ -2984,11 +2982,6 @@ void SwBaseShell::ExecDlg(SfxRequest &rReq)
                         if (pColorSet)
                         {
                             pChanger->apply(pColorSet);
-                            if (comphelper::LibreOfficeKit::isActive())
-                            {
-                                svx::ThemeColorPaletteManager 
aManager(pColorSet);
-                                
SfxLokHelper::notifyAllViews(LOK_CALLBACK_COLOR_PALETTES, 
aManager.generateJSON());
-                            }
                         }
                     });
                 }
diff --git a/sw/source/uibase/uiview/view.cxx b/sw/source/uibase/uiview/view.cxx
index 2d46cd04f260..0474824e69eb 100644
--- a/sw/source/uibase/uiview/view.cxx
+++ b/sw/source/uibase/uiview/view.cxx
@@ -102,7 +102,7 @@
 #include <PostItMgr.hxx>
 #include <annotsh.hxx>
 #include <swruler.hxx>
-#include <svx/theme/ThemeColorPaletteManager.hxx>
+#include <svx/theme/ThemeColorChangerCommon.hxx>
 #include <com/sun/star/document/XDocumentProperties.hpp>
 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
 
@@ -1218,8 +1218,7 @@ void SwView::afterCallbackRegistered()
     auto* pDocShell = GetDocShell();
     if (pDocShell)
     {
-        svx::ThemeColorPaletteManager aManager(pDocShell->GetThemeColors());
-        libreOfficeKitViewCallback(LOK_CALLBACK_COLOR_PALETTES, 
aManager.generateJSON());
+        svx::theme::notifyLOK(pDocShell->GetThemeColors());
     }
 }
 
commit deec43b36446ac3ac5c77b88bf47e4e0a4ba2057
Author:     Szymon Kłos <szymon.k...@collabora.com>
AuthorDate: Tue Dec 19 19:24:19 2023 +0100
Commit:     Szymon Kłos <szymon.k...@collabora.com>
CommitDate: Mon Jan 15 21:07:27 2024 +0100

    lok: send error on access denied in image import 2
    
    followup for commit     64624d225c71229acce4f889d4863d7c29c52658
    lok: send error on access denied in image import
    
    It shows an error in LOK when we try to insert image
    from remote host blocked by HostFilter
    
    Previously it was showing error in paste case,
    now do the same also on image insertion.
    
    For now disable HandleGraphicFilterError in sd, as it
    crashes, is synchronous and cannot be easily fixed
    - dialog sits inside module not linked to sfx2, needs
    some rework.
    
    Change-Id: I3c15ff5621add97ef9d60d4f4c1305dae2909158
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161001
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161774
    Tested-by: Jenkins
    Reviewed-by: Szymon Kłos <szymon.k...@collabora.com>

diff --git a/include/sfx2/lokhelper.hxx b/include/sfx2/lokhelper.hxx
index 338dda192b8c..3751d6758571 100644
--- a/include/sfx2/lokhelper.hxx
+++ b/include/sfx2/lokhelper.hxx
@@ -227,7 +227,7 @@ public:
     static VclPtr<vcl::Window> getInPlaceDocWindow(SfxViewShell* pViewShell);
 
     /// Sends Network Access error to LOK
-    static void sendNetworkAccessError();
+    static void sendNetworkAccessError(std::string_view rAction);
 
     static void notifyLog(const std::ostringstream& stream);
 
diff --git a/sc/source/filter/html/htmlpars.cxx 
b/sc/source/filter/html/htmlpars.cxx
index 10d31fc84cd4..43ff3cca2de5 100644
--- a/sc/source/filter/html/htmlpars.cxx
+++ b/sc/source/filter/html/htmlpars.cxx
@@ -1325,7 +1325,7 @@ void ScHTMLLayoutParser::Image( HtmlImportInfo* pInfo )
     {
         INetURLObject aURL(pImage->aURL);
         if (HostFilter::isForbidden(aURL.GetHost()))
-            SfxLokHelper::sendNetworkAccessError();
+            SfxLokHelper::sendNetworkAccessError("paste");
     }
 
     sal_uInt16 nFormat;
diff --git a/sc/source/ui/drawfunc/fuins1.cxx b/sc/source/ui/drawfunc/fuins1.cxx
index 72886789b448..9b51a62c5b2a 100644
--- a/sc/source/ui/drawfunc/fuins1.cxx
+++ b/sc/source/ui/drawfunc/fuins1.cxx
@@ -22,6 +22,7 @@
 #include <officecfg/Office/Common.hxx>
 #include <editeng/sizeitem.hxx>
 #include <sal/log.hxx>
+#include <sfx2/lokhelper.hxx>
 #include <sfx2/opengrf.hxx>
 #include <sfx2/viewfrm.hxx>
 #include <svx/svdograf.hxx>
@@ -48,6 +49,9 @@
 #include <globstr.hrc>
 #include <comphelper/lok.hxx>
 
+#include <tools/hostfilter.hxx>
+#include <tools/urlobj.hxx>
+
 #include <com/sun/star/frame/XDispatchProvider.hpp>
 #include <com/sun/star/media/XPlayer.hpp>
 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
@@ -279,6 +283,13 @@ FuInsertGraphic::FuInsertGraphic( ScTabViewShell&   
rViewSh,
         if ( pReqArgs->GetItemState( FN_PARAM_1, true, &pItem ) == 
SfxItemState::SET )
             bAsLink = static_cast<const SfxBoolItem*>(pItem)->GetValue();
 
+        if (comphelper::LibreOfficeKit::isActive())
+        {
+            INetURLObject aURL(aFileName);
+            if (INetProtocol::File != aURL.GetProtocol() && 
HostFilter::isForbidden(aURL.GetHost()))
+                SfxLokHelper::sendNetworkAccessError("insert");
+        }
+
         Graphic aGraphic;
         ErrCode nError = GraphicFilter::LoadGraphic( aFileName, aFilterName, 
aGraphic, &GraphicFilter::GetGraphicFilter() );
         if ( nError == ERRCODE_NONE )
diff --git a/sd/source/ui/func/fuinsert.cxx b/sd/source/ui/func/fuinsert.cxx
index 31b286c822e3..e8409c815b25 100644
--- a/sd/source/ui/func/fuinsert.cxx
+++ b/sd/source/ui/func/fuinsert.cxx
@@ -36,6 +36,7 @@
 
 #include <svl/stritem.hxx>
 #include <sfx2/dispatch.hxx>
+#include <sfx2/lokhelper.hxx>
 #include <sfx2/msgpool.hxx>
 #include <sfx2/msg.hxx>
 #include <svtools/insdlg.hxx>
@@ -60,6 +61,9 @@
 #include <svx/charthelper.hxx>
 #include <svx/svxids.hrc>
 
+#include <tools/hostfilter.hxx>
+#include <tools/urlobj.hxx>
+
 #include <sdresid.hxx>
 #include <View.hxx>
 #include <sdmod.hxx>
@@ -129,6 +133,13 @@ void FuInsertGraphic::DoExecute( SfxRequest& rReq )
         if ( pArgs->GetItemState( FN_PARAM_1, true, &pItem ) == 
SfxItemState::SET )
             bAsLink = static_cast<const SfxBoolItem*>(pItem)->GetValue();
 
+        if (comphelper::LibreOfficeKit::isActive())
+        {
+            INetURLObject aURL(aFileName);
+            if (INetProtocol::File != aURL.GetProtocol() && 
HostFilter::isForbidden(aURL.GetHost()))
+                SfxLokHelper::sendNetworkAccessError("insert");
+        }
+
         nError = GraphicFilter::LoadGraphic( aFileName, aFilterName, aGraphic, 
&GraphicFilter::GetGraphicFilter() );
     }
     else
@@ -188,8 +199,9 @@ void FuInsertGraphic::DoExecute( SfxRequest& rReq )
             }
         }
     }
-    else
+    else if (!comphelper::LibreOfficeKit::isActive())
     {
+        // TODO: enable in LOK, it contains synchronous error window without 
LOKNotifier
         SdGRFFilter::HandleGraphicFilterError( nError, 
GraphicFilter::GetGraphicFilter().GetLastError() );
     }
 }
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index 853b35bb7431..73473dd7640b 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -1075,13 +1075,13 @@ VclPtr<vcl::Window> 
SfxLokHelper::getInPlaceDocWindow(SfxViewShell* pViewShell)
     return {};
 }
 
-void SfxLokHelper::sendNetworkAccessError()
+void SfxLokHelper::sendNetworkAccessError(std::string_view rAction)
 {
     tools::JsonWriter aWriter;
     aWriter.put("code", static_cast<sal_uInt32>(
         ErrCode(ErrCodeArea::Inet, sal_uInt16(ErrCodeClass::Access))));
     aWriter.put("kind", "network");
-    aWriter.put("cmd", "paste");
+    aWriter.put("cmd", rAction);
 
     SfxViewShell* pViewShell = SfxViewShell::Current();
     if (pViewShell)
diff --git a/sw/source/filter/html/htmlgrin.cxx 
b/sw/source/filter/html/htmlgrin.cxx
index 8f04dce5546e..5a61f49ccca1 100644
--- a/sw/source/filter/html/htmlgrin.cxx
+++ b/sw/source/filter/html/htmlgrin.cxx
@@ -513,7 +513,7 @@ IMAGE_SETEVENT:
     else if (m_sBaseURL.isEmpty() || !aGraphicData.isEmpty())
     {
         if (comphelper::LibreOfficeKit::isActive() && 
HostFilter::isForbidden(aGraphicURL.GetHost()))
-            SfxLokHelper::sendNetworkAccessError();
+            SfxLokHelper::sendNetworkAccessError("paste");
 
         // sBaseURL is empty if the source is clipboard
         // aGraphicData is non-empty for <object data="..."> -> not a linked 
graphic.
diff --git a/sw/source/uibase/uiview/view2.cxx 
b/sw/source/uibase/uiview/view2.cxx
index cc6faf78a3c5..a6a6975e984c 100644
--- a/sw/source/uibase/uiview/view2.cxx
+++ b/sw/source/uibase/uiview/view2.cxx
@@ -50,6 +50,7 @@
 #include <svx/statusitem.hxx>
 #include <svx/viewlayoutitem.hxx>
 #include <svx/zoomslideritem.hxx>
+#include <sfx2/lokhelper.hxx>
 #include <sfx2/htmlmode.hxx>
 #include <vcl/svapp.hxx>
 #include <sfx2/app.hxx>
@@ -71,6 +72,7 @@
 #include <svl/ptitem.hxx>
 #include <sfx2/viewfrm.hxx>
 #include <vcl/errinf.hxx>
+#include <tools/hostfilter.hxx>
 #include <tools/urlobj.hxx>
 #include <svx/svdview.hxx>
 #include <swtypes.hxx>
@@ -309,6 +311,14 @@ ErrCode SwView::InsertGraphic( const OUString &rPath, 
const OUString &rFilter,
     {
         pFilter = &GraphicFilter::GetGraphicFilter();
     }
+
+    if (comphelper::LibreOfficeKit::isActive())
+    {
+        INetURLObject aURL(rPath);
+        if (INetProtocol::File != aURL.GetProtocol() && 
HostFilter::isForbidden(aURL.GetHost()))
+            SfxLokHelper::sendNetworkAccessError("insert");
+    }
+
     aResult = GraphicFilter::LoadGraphic( rPath, rFilter, aGraphic, pFilter );
 
     if( ERRCODE_NONE == aResult )
commit cecec662b42b0f47780c2a73c6cd9b61b54419bb
Author:     Szymon Kłos <szymon.k...@collabora.com>
AuthorDate: Mon Dec 4 18:36:29 2023 +0100
Commit:     Szymon Kłos <szymon.k...@collabora.com>
CommitDate: Mon Jan 15 21:07:27 2024 +0100

    lok: send error on access denied in image import
    
    - when we paste HTML with references to external images
      and host filter is configured then we have empty graphics
    - inform client about that so we can show an error to the user
    
    Change-Id: I7d584c256d8d004955c970056341ab42864d1dd3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160319
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Reviewed-by: Szymon Kłos <szymon.k...@collabora.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161773
    Tested-by: Jenkins

diff --git a/include/sfx2/lokhelper.hxx b/include/sfx2/lokhelper.hxx
index dc144503b8dd..338dda192b8c 100644
--- a/include/sfx2/lokhelper.hxx
+++ b/include/sfx2/lokhelper.hxx
@@ -226,6 +226,9 @@ public:
 
     static VclPtr<vcl::Window> getInPlaceDocWindow(SfxViewShell* pViewShell);
 
+    /// Sends Network Access error to LOK
+    static void sendNetworkAccessError();
+
     static void notifyLog(const std::ostringstream& stream);
 
 private:
diff --git a/sc/source/filter/html/htmlpars.cxx 
b/sc/source/filter/html/htmlpars.cxx
index f5f890081592..10d31fc84cd4 100644
--- a/sc/source/filter/html/htmlpars.cxx
+++ b/sc/source/filter/html/htmlpars.cxx
@@ -20,6 +20,7 @@
 #include <memory>
 #include <sal/config.h>
 
+#include <comphelper/lok.hxx>
 #include <comphelper/string.hxx>
 
 #include <scitems.hxx>
@@ -37,6 +38,7 @@
 #include <editeng/justifyitem.hxx>
 #include <sal/log.hxx>
 #include <sfx2/objsh.hxx>
+#include <sfx2/lokhelper.hxx>
 #include <svl/numformat.hxx>
 #include <svl/intitem.hxx>
 #include <utility>
@@ -47,6 +49,7 @@
 
 #include <vcl/outdev.hxx>
 #include <vcl/svapp.hxx>
+#include <tools/hostfilter.hxx>
 #include <tools/urlobj.hxx>
 #include <osl/diagnose.h>
 #include <o3tl/string_view.hxx>
@@ -1318,6 +1321,13 @@ void ScHTMLLayoutParser::Image( HtmlImportInfo* pInfo )
         return ;
     }
 
+    if (comphelper::LibreOfficeKit::isActive())
+    {
+        INetURLObject aURL(pImage->aURL);
+        if (HostFilter::isForbidden(aURL.GetHost()))
+            SfxLokHelper::sendNetworkAccessError();
+    }
+
     sal_uInt16 nFormat;
     std::optional<Graphic> oGraphic(std::in_place);
     GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index 2e3674f7d287..853b35bb7431 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -37,6 +37,7 @@
 #include <comphelper/lok.hxx>
 #include <sfx2/msgpool.hxx>
 #include <comphelper/scopeguard.hxx>
+#include <tools/json_writer.hxx>
 
 #include <boost/property_tree/json_parser.hpp>
 
@@ -1074,4 +1075,20 @@ VclPtr<vcl::Window> 
SfxLokHelper::getInPlaceDocWindow(SfxViewShell* pViewShell)
     return {};
 }
 
+void SfxLokHelper::sendNetworkAccessError()
+{
+    tools::JsonWriter aWriter;
+    aWriter.put("code", static_cast<sal_uInt32>(
+        ErrCode(ErrCodeArea::Inet, sal_uInt16(ErrCodeClass::Access))));
+    aWriter.put("kind", "network");
+    aWriter.put("cmd", "paste");
+
+    SfxViewShell* pViewShell = SfxViewShell::Current();
+    if (pViewShell)
+    {
+        pViewShell->libreOfficeKitViewCallback(
+            LOK_CALLBACK_ERROR, aWriter.finishAndGetAsOString());
+    }
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/html/htmlgrin.cxx 
b/sw/source/filter/html/htmlgrin.cxx
index 072b8945d234..8f04dce5546e 100644
--- a/sw/source/filter/html/htmlgrin.cxx
+++ b/sw/source/filter/html/htmlgrin.cxx
@@ -19,6 +19,7 @@
 
 #include <memory>
 #include <hintids.hxx>
+#include <comphelper/lok.hxx>
 #include <comphelper/string.hxx>
 #include <comphelper/documentinfo.hxx>
 #include <vcl/svapp.hxx>
@@ -34,6 +35,7 @@
 #include <editeng/langitem.hxx>
 #include <sfx2/docfile.hxx>
 #include <sfx2/event.hxx>
+#include <sfx2/lokhelper.hxx>
 #include <vcl/imap.hxx>
 #include <svtools/htmltokn.h>
 #include <svtools/htmlkywd.hxx>
@@ -69,6 +71,7 @@
 
 #include <vcl/graphicfilter.hxx>
 #include <tools/UnitConversion.hxx>
+#include <tools/hostfilter.hxx>
 #include <tools/urlobj.hxx>
 #include <unotools/securityoptions.hxx>
 
@@ -509,6 +512,9 @@ IMAGE_SETEVENT:
     }
     else if (m_sBaseURL.isEmpty() || !aGraphicData.isEmpty())
     {
+        if (comphelper::LibreOfficeKit::isActive() && 
HostFilter::isForbidden(aGraphicURL.GetHost()))
+            SfxLokHelper::sendNetworkAccessError();
+
         // sBaseURL is empty if the source is clipboard
         // aGraphicData is non-empty for <object data="..."> -> not a linked 
graphic.
         if (ERRCODE_NONE == 
GraphicFilter::GetGraphicFilter().ImportGraphic(aGraphic, aGraphicURL))
commit 440dec9a7e854d7d3dced73625db52796700d8e6
Author:     Szymon Kłos <szymon.k...@collabora.com>
AuthorDate: Fri Dec 1 08:35:51 2023 +0100
Commit:     Szymon Kłos <szymon.k...@collabora.com>
CommitDate: Mon Jan 15 21:07:27 2024 +0100

    lok: external data source list
    
    Make possible to filter allowed data sources.
    It is used for WebDAV curl, WEBSERVICE function, cell external
    references.
    
    Change-Id: Ifc82af31ff1123b5656a21e6a27624fb1616db39
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160196
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161772
    Tested-by: Jenkins
    Reviewed-by: Szymon Kłos <szymon.k...@collabora.com>

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 58e0f2d64413..6d141aeca865 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -236,6 +236,8 @@
 #include <com/sun/star/ui/XAcceleratorConfiguration.hpp>
 #include <svtools/acceleratorexecute.hxx>
 
+#include <tools/hostfilter.hxx>
+
 using namespace css;
 using namespace vcl;
 using namespace desktop;
@@ -7763,6 +7765,12 @@ static int lo_initialize(LibreOfficeKit* pThis, const 
char* pAppPath, const char
     }
 #endif
 
+    char* pAllowlist = ::getenv("LOK_HOST_ALLOWLIST");
+    if (pAllowlist)
+    {
+        HostFilter::setAllowedHostsRegex(pAllowlist);
+    }
+
     // What stage are we at ?
     if (pThis == nullptr)
     {
diff --git a/include/tools/hostfilter.hxx b/include/tools/hostfilter.hxx
new file mode 100644
index 000000000000..afbf885b0cb4
--- /dev/null
+++ b/include/tools/hostfilter.hxx
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_TOOLS_HOSTFILTER_HXX
+#define INCLUDED_TOOLS_HOSTFILTER_HXX
+
+#include <rtl/ustring.hxx>
+#include <tools/toolsdllapi.h>
+
+// Helper for filtering allowed hosts for remote connections
+
+class TOOLS_DLLPUBLIC HostFilter
+{
+public:
+    static void setAllowedHostsRegex(const char* sAllowedRegex);
+
+    static bool isForbidden(const OUString& rHost);
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/sc/source/core/tool/webservicelink.cxx 
b/sc/source/core/tool/webservicelink.cxx
index 156048430636..c30f34300edf 100644
--- a/sc/source/core/tool/webservicelink.cxx
+++ b/sc/source/core/tool/webservicelink.cxx
@@ -7,7 +7,6 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-#include <comphelper/lok.hxx>
 #include <comphelper/processfactory.hxx>
 #include <sfx2/linkmgr.hxx>
 #include <sfx2/bindings.hxx>
@@ -16,6 +15,9 @@
 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
 #include <com/sun/star/io/XInputStream.hpp>
 
+#include <tools/hostfilter.hxx>
+#include <tools/urlobj.hxx>
+
 #include <utility>
 #include <webservicelink.hxx>
 #include <brdcst.hxx>
@@ -37,7 +39,9 @@ sfx2::SvBaseLink::UpdateResult 
ScWebServiceLink::DataChanged(const OUString&, co
     aResult.clear();
     bHasResult = false;
 
-    if (comphelper::LibreOfficeKit::isActive())
+    INetURLObject aURLObject(aURL);
+    const OUString sHost = aURLObject.GetHost();
+    if (HostFilter::isForbidden(sHost))
     {
         SAL_WARN("sc.ui", "ScWebServiceLink::DataChanged: blocked access to 
external file: \""
                               << aURL << "\"");
diff --git a/sc/source/ui/docshell/externalrefmgr.cxx 
b/sc/source/ui/docshell/externalrefmgr.cxx
index 01476aababe0..58e10dc77e88 100644
--- a/sc/source/ui/docshell/externalrefmgr.cxx
+++ b/sc/source/ui/docshell/externalrefmgr.cxx
@@ -50,6 +50,7 @@
 #include <svl/urihelper.hxx>
 #include <svl/sharedstringpool.hxx>
 #include <sfx2/linkmgr.hxx>
+#include <tools/hostfilter.hxx>
 #include <tools/urlobj.hxx>
 #include <unotools/charclass.hxx>
 #include <unotools/configmgr.hxx>
@@ -2542,7 +2543,9 @@ SfxObjectShellRef 
ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId, OUSt
     if (!isFileLoadable(aFile))
         return nullptr;
 
-    if (comphelper::LibreOfficeKit::isActive())
+    INetURLObject aURLObject(aFile);
+    const OUString sHost = aURLObject.GetHost();
+    if (HostFilter::isForbidden(sHost))
     {
         SAL_WARN( "sc.ui", "ScExternalRefManager::loadSrcDocument: blocked 
access to external file: \"" << aFile << "\"");
         return nullptr;
diff --git a/tools/Library_tl.mk b/tools/Library_tl.mk
index 8269e6ae98bf..99176a7c0902 100644
--- a/tools/Library_tl.mk
+++ b/tools/Library_tl.mk
@@ -67,6 +67,7 @@ $(eval $(call gb_Library_add_exception_objects,tl,\
     tools/source/inet/inetmime \
     tools/source/inet/inetmsg \
     tools/source/inet/inetstrm \
+    tools/source/inet/hostfilter \
     tools/source/memtools/multisel \
     tools/source/misc/cpuid \
     tools/source/misc/extendapplicationenvironment \
diff --git a/tools/source/inet/hostfilter.cxx b/tools/source/inet/hostfilter.cxx
new file mode 100644
index 000000000000..5bc63d42cfb7
--- /dev/null
+++ b/tools/source/inet/hostfilter.cxx
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <tools/hostfilter.hxx>
+#include <regex>
+
+static std::regex g_AllowedHostsRegex("");
+static bool g_AllowedHostsSet = false;
+
+void HostFilter::setAllowedHostsRegex(const char* sAllowedRegex)
+{
+    g_AllowedHostsSet = sAllowedRegex && sAllowedRegex[0] != '
+    if (g_AllowedHostsSet)
+        g_AllowedHostsRegex = sAllowedRegex;
+}
+
+bool HostFilter::isForbidden(const OUString& rHost)
+{
+    if (!g_AllowedHostsSet)
+        return false;
+
+    return !std::regex_match(rHost.toUtf8().getStr(), g_AllowedHostsRegex);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/ucb/source/ucp/webdav-curl/CurlSession.cxx 
b/ucb/source/ucp/webdav-curl/CurlSession.cxx
index a54e9d1addfb..11dc964fbe00 100644
--- a/ucb/source/ucp/webdav-curl/CurlSession.cxx
+++ b/ucb/source/ucp/webdav-curl/CurlSession.cxx
@@ -37,6 +37,7 @@
 #include <rtl/strbuf.hxx>
 #include <rtl/ustrbuf.hxx>
 #include <systools/curlinit.hxx>
+#include <tools/hostfilter.hxx>
 #include <config_version.h>
 
 #include <map>
@@ -1116,6 +1117,12 @@ auto CurlProcessor::ProcessRequest(
     ::std::pair<::std::vector<OUString> const&, DAVResource&> const* const 
pRequestedHeaders)
     -> void
 {
+    if (HostFilter::isForbidden(rURI.GetHost()))
+    {
+        SAL_WARN("ucb.ucp.webdav.curl", "Access denied to host: " << 
rURI.GetHost());
+        throw uno::RuntimeException("access to host denied");
+    }
+
     if (pEnv)
     { // add custom request headers passed by caller
         for (auto const& rHeader : pEnv->m_aRequestHeaders)
commit e727fc495a8e1bf423105e983ce194924e8ad618
Author:     Szymon Kłos <szymon.k...@collabora.com>
AuthorDate: Thu Nov 30 15:36:57 2023 +0100
Commit:     Szymon Kłos <szymon.k...@collabora.com>
CommitDate: Mon Jan 15 21:07:27 2024 +0100

    lok: import Work path from LOK_WORKDIR
    
    Change-Id: If0c9727f53c1c4dfb78d1ccbd6b3ff602268bbf7
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160156
    Reviewed-by: Michael Meeks <michael.me...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161059
    Tested-by: Jenkins
    Reviewed-by: Szymon Kłos <szymon.k...@collabora.com>

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 0e17568717e6..58e0f2d64413 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -7988,6 +7988,14 @@ static int lo_initialize(LibreOfficeKit* pThis, const 
char* pAppPath, const char
             OUString aNewTemp;
             osl::FileBase::getTempDirURL(aNewTemp);
             aOptions.SetTempPath(aNewTemp);
+            {
+                const char *pWorkPath = getenv("LOK_WORKDIR");
+                if (pWorkPath)
+                {
+                    OString sWorkPath(pWorkPath);
+                    aOptions.SetWorkPath(OStringToOUString(sWorkPath, 
RTL_TEXTENCODING_UTF8));
+                }
+            }
             desktop::Desktop::CreateTemporaryDirectory();
 
             // The RequestHandler is specifically set to be ready when all the 
other
diff --git a/include/unotools/pathoptions.hxx b/include/unotools/pathoptions.hxx
index c7468048d5df..c19a2b34baf4 100644
--- a/include/unotools/pathoptions.hxx
+++ b/include/unotools/pathoptions.hxx
@@ -106,6 +106,7 @@ public:
     void            SetAutoTextPath( const OUString& rPath );
     void            SetBasicPath( const OUString& rPath );
     void            SetTempPath( const OUString& rPath );
+    void            SetWorkPath( const OUString& rPath );
 
     OUString        SubstituteVariable( const OUString& rVar ) const;
     OUString        ExpandMacros( const OUString& rPath ) const;
diff --git a/unotools/source/config/pathoptions.cxx 
b/unotools/source/config/pathoptions.cxx
index 24c1fb323dcc..4234ec903df9 100644
--- a/unotools/source/config/pathoptions.cxx
+++ b/unotools/source/config/pathoptions.cxx
@@ -122,6 +122,7 @@ class SvtPathOptions_Impl
         void            SetAutoTextPath( const OUString& rPath ) { SetPath( 
SvtPathOptions::Paths::AutoText, rPath ); }
         void            SetBasicPath( const OUString& rPath ) { SetPath( 
SvtPathOptions::Paths::Basic, rPath ); }
         void            SetTempPath( const OUString& rPath ) { SetPath( 
SvtPathOptions::Paths::Temp, rPath ); }
+        void            SetWorkPath( const OUString& rPath ) { SetPath( 
SvtPathOptions::Paths::Work, rPath ); }
 
         OUString   SubstVar( const OUString& rVar ) const;
         OUString   ExpandMacros( const OUString& rPath ) const;
@@ -589,6 +590,11 @@ void SvtPathOptions::SetTempPath( const OUString& rPath )
     pImpl->SetTempPath( rPath );
 }
 
+void SvtPathOptions::SetWorkPath( const OUString& rPath )
+{
+    pImpl->SetWorkPath( rPath );
+}
+
 OUString SvtPathOptions::SubstituteVariable( const OUString& rVar ) const
 {
     return pImpl->SubstVar( rVar );
commit 997899472d8644375285593d89ca0ab0bd56ec69
Author:     Michael Meeks <michael.me...@collabora.com>
AuthorDate: Sat Nov 25 21:24:49 2023 +0000
Commit:     Szymon Kłos <szymon.k...@collabora.com>
CommitDate: Mon Jan 15 21:07:27 2024 +0100

    lok: import allowed paths from the SAL_ALLOWED_PATHS.
    
    Do this on second init, in order to be able to reset this for
    each child kit process.
    
    Change-Id: I6939ea3677ea2b84c8944b63a9a9120e880a6bfa
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159961
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Szymon Kłos <szymon.k...@collabora.com>

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index efed041791bf..0e17568717e6 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -7754,6 +7754,15 @@ static int lo_initialize(LibreOfficeKit* pThis, const 
char* pAppPath, const char
         }
     }
 
+#ifdef LINUX
+    {
+        const char *pAllowedPaths = getenv("SAL_ALLOWED_PATHS");
+        if (pAllowedPaths)
+            osl_setAllowedPaths(
+                OUString(pAllowedPaths, strlen(pAllowedPaths), 
RTL_TEXTENCODING_UTF8).pData);
+    }
+#endif
+
     // What stage are we at ?
     if (pThis == nullptr)
     {
commit 5e66863ae42bf0e5b614a8f21dc44a15df727922
Author:     Michael Meeks <michael.me...@collabora.com>
AuthorDate: Wed Nov 22 19:37:38 2023 +0000
Commit:     Szymon Kłos <szymon.k...@collabora.com>
CommitDate: Mon Jan 15 21:07:27 2024 +0100

    sal: initial osl::File sand-boxing commit for Unix.
    
    Change-Id: If2c106fef9640499b82b5cf350cb5169beb219fb
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159838
    Reviewed-by: Szymon Kłos <szymon.k...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Michael Meeks <michael.me...@collabora.com>

diff --git a/include/osl/file.h b/include/osl/file.h
index 07d2beb2ae1f..98ad568550b9 100644
--- a/include/osl/file.h
+++ b/include/osl/file.h
@@ -960,6 +960,54 @@ SAL_DLLPUBLIC oslFileError SAL_CALL osl_readFile(
 SAL_DLLPUBLIC oslFileError SAL_CALL osl_isEndOfFile(
         oslFileHandle Handle, sal_Bool *pIsEOF );
 
+/** Resets the list of paths and associated permissions for osl
+
+    @param[in] pustrFileURLs
+    Contains a ':' delimited list of control strings and paths.
+    Control segments are a short path that refers to the following
+    segments and contain either:
+
+    r: read-only paths follow (the default)
+    w: read & write paths follow
+    x: executable paths follow
+
+    Any real paths (ie. having resolved all symlinks)
+    accessed outside of these paths will cause an
+    osl_File_E_ACCESS error in the relevant method calls.
+
+    This method is Unix specific.
+
+    @see osl_isForbiddenPath
+
+    @since LibreOffice 7.7
+*/
+SAL_DLLPUBLIC void SAL_CALL osl_setAllowedPaths(
+    rtl_uString *pustrFileURLs
+    );
+
+/**
+   Determine if the passed in path is not contained inside
+   the allowed paths, or if no allowed paths are set it
+   will not forbid any access.
+
+   @param[in] pustrFileURL
+   A URL (or path) that we want to check if it is forbidden
+   to access.
+
+   @param[in] nFlags
+   Flags to determine what type of access is requested,
+   osl_File_OpenFlag_Read | Write, or 0x80 for 'execute'.
+
+   This method is Unix specific.
+
+   @see osl_setAllowedPaths
+
+   @since LibreOffice 7.7
+ */
+SAL_DLLPUBLIC sal_Bool SAL_CALL osl_isForbiddenPath(
+    rtl_uString *pustrFileURL, int nFlags
+    );
+
 /** Write a number of bytes to a file.
 
     Writes a number of bytes to a file.
diff --git a/include/osl/file.hxx b/include/osl/file.hxx
index fcbabe96d674..6330247ba818 100644
--- a/include/osl/file.hxx
+++ b/include/osl/file.hxx
@@ -313,6 +313,58 @@ public:
 
         return static_cast< RC >( osl_createTempFile(pustr_dir_url, pHandle, 
ppustr_tmp_file_url) );
     }
+
+
+    /** Resets the list of paths and associated permissions for osl
+
+        @param[in] rPaths
+        Contains a ':' delimited list of control strings and paths.
+        Control segments are a short path that refers to the following
+        segments and contain either:
+
+        r: read-only paths follow (the default)
+        w: read & write paths follow
+        x: executable paths follow
+
+        Any real paths (ie. having resolved all symlinks)
+        accessed outside of these paths will cause an
+        osl_File_E_ACCESS error in the relevant method calls.
+
+        This method is Unix specific.
+
+        @see osl_isForbiddenPath
+
+        @since LibreOffice 7.7
+    */
+
+    static void setAllowedPaths(const OUString &rPaths)
+    {
+        osl_setAllowedPaths(rPaths.pData);
+    }
+
+    /**
+       Determine if the passed in path is not contained inside
+       the allowed paths, or if no allowed paths are set it
+       will not forbid any access.
+
+       @param[in] pustrFileURL
+       A URL (or path) that we want to check if it is forbidden
+       to access.
+
+       @param[in] nFlags
+       Flags to determine what type of access is requested,
+       osl_File_OpenFlag_Read | Write, or 0x80 for 'execute'.
+
+       This method is Unix specific.
+
+       @see osl_setAllowedPaths
+
+       @since LibreOffice 7.7
+    */
+    static bool isForbidden(const OUString &rPath, int nFlags)
+    {
+        return osl_isForbiddenPath(rPath.pData, nFlags);
+    }
 };
 
 
diff --git a/sal/osl/unx/file.cxx b/sal/osl/unx/file.cxx
index eeee7c803fd8..848a586ad2ce 100644
--- a/sal/osl/unx/file.cxx
+++ b/sal/osl/unx/file.cxx
@@ -784,6 +784,125 @@ static bool osl_file_queryLocking(sal_uInt32 uFlags)
     return false;
 }
 
+static bool abortOnForbidden = false;
+static std::vector<OString> allowedPathsRead;
+static std::vector<OString> allowedPathsReadWrite;
+static std::vector<OString> allowedPathsExecute;
+
+SAL_DLLPUBLIC void osl_setAllowedPaths(
+        rtl_uString *pustrFilePaths
+    )
+{
+    allowedPathsRead.clear();
+    allowedPathsReadWrite.clear();
+    allowedPathsExecute.clear();
+
+    if (!pustrFilePaths)
+        return;
+
+    char eType = 'r';
+    sal_Int32 nIndex = 0;
+    OUString aPaths(pustrFilePaths);
+    do
+    {
+        OString aPath = rtl::OUStringToOString(
+            aPaths.getToken(0, ':', nIndex),
+            RTL_TEXTENCODING_UTF8);
+
+        if (aPath.getLength() == 0)
+            continue;
+
+        if (aPath.getLength() == 1)
+        {
+            eType = aPath[0];
+            continue;
+        }
+
+        char resolvedPath[PATH_MAX];
+        if (realpath(aPath.getStr(), resolvedPath))
+        {
+            OString aPushPath = OString(resolvedPath, strlen(resolvedPath));
+            if (eType == 'r')
+                allowedPathsRead.push_back(aPushPath);
+            else if (eType == 'w')
+            {
+                allowedPathsRead.push_back(aPushPath);
+                allowedPathsReadWrite.push_back(aPushPath);
+            }
+            else if (eType == 'x')
+                allowedPathsExecute.push_back(aPushPath);
+        }
+    }
+    while (nIndex != -1);
+
+    abortOnForbidden = !!getenv("SAL_ABORT_ON_FORBIDDEN");
+}
+
+bool isForbidden(const OString &filePath, int nFlags)
+{
+    // avoid realpath cost unless configured
+    if (allowedPathsRead.size() == 0)
+        return false;
+
+    char resolvedPath[PATH_MAX];
+    if (!realpath(filePath.getStr(), resolvedPath))
+    {
+        // write calls path a non-existent path that realpath will
+        // fail to resolve. Thankfully our I/O APIs don't allow
+        // symlink creation to race here.
+        sal_Int32 n = filePath.lastIndexOf('/');
+        OString folderPath;
+        if (n < 1)
+            folderPath = ".";
+        else
+            folderPath = filePath.copy(0, n);
+        if (!realpath(folderPath.getStr(), resolvedPath) ||
+            strlen(resolvedPath) + filePath.getLength() - n + 1 >= PATH_MAX)
+            return true; // too bad
+        else
+            strcat(resolvedPath, filePath.getStr() + n);
+    }
+
+    const std::vector<OString> *pCheckPaths = &allowedPathsRead;
+    if (nFlags & osl_File_OpenFlag_Write ||
+        nFlags & osl_File_OpenFlag_Create)
+        pCheckPaths = &allowedPathsReadWrite;
+    else if (nFlags & 0x80)
+        pCheckPaths = &allowedPathsExecute;
+
+    bool allowed = false;
+    for (const auto &it : *pCheckPaths) {
+        if (!strncmp(resolvedPath, it.getStr(), it.getLength()))
+        {
+            allowed = true;
+            break;
+        }
+    }
+
+    if (!allowed)
+        SAL_WARN("sal.osl", "access outside sandbox to " <<
+                 ((nFlags & osl_File_OpenFlag_Write ||
+                   nFlags & osl_File_OpenFlag_Create) ? "w" :
+                  (nFlags & 0x80) ? "x" : "r") << ":" <<
+                 filePath << " which is really " << resolvedPath <<
+                 (allowed ? " allowed " : " forbidden") <<
+                 " check list: " << pCheckPaths->size());
+
+    if (abortOnForbidden && !allowed)
+        abort(); // a bit abrupt - but don't try to escape.
+
+    return !allowed;
+}
+
+SAL_DLLPUBLIC sal_Bool SAL_CALL osl_isForbiddenPath(
+    rtl_uString *pustrFileURL, int nFlags
+    )
+{
+    return isForbidden(
+        rtl::OUStringToOString(OUString(pustrFileURL),
+                               RTL_TEXTENCODING_UTF8), nFlags);
+}
+
 #ifdef HAVE_O_EXLOCK
 #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK )
 #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR | O_EXLOCK | O_NONBLOCK )
@@ -988,6 +1107,10 @@ oslFileError openFilePath(const OString& filePath, 
oslFileHandle* pHandle,
     if (flags & O_EXCL && !(flags & O_CREAT))
         flags &= ~O_EXCL;
 
+    // Sandboxing hook
+    if (isForbidden( filePath, uFlags ))
+        return osl_File_E_ACCES;
+
     /* open the file */
     int fd = open_c( filePath, flags, mode );
     if (fd == -1)
@@ -1602,4 +1725,5 @@ oslFileError SAL_CALL osl_setFileSize(oslFileHandle 
Handle, sal_uInt64 uSize)
     return pImpl->setSize(uSize);
 }
 
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/osl/unx/file_impl.hxx b/sal/osl/unx/file_impl.hxx
index 4a9a90d4160f..64504296955d 100644
--- a/sal/osl/unx/file_impl.hxx
+++ b/sal/osl/unx/file_impl.hxx
@@ -40,6 +40,8 @@ struct DirectoryItem_Impl
     oslFileType getFileType() const;
 };
 
+bool isForbidden(const OString &filePath, int nFlags);
+
 oslFileError openFile(
     rtl_uString * pustrFileURL, oslFileHandle * pHandle, sal_uInt32 uFlags,
     mode_t mode);
diff --git a/sal/osl/unx/file_misc.cxx b/sal/osl/unx/file_misc.cxx
index 752c85393b86..69ca29cdbaa4 100644
--- a/sal/osl/unx/file_misc.cxx
+++ b/sal/osl/unx/file_misc.cxx
@@ -143,6 +143,9 @@ oslFileError SAL_CALL osl_openDirectory(rtl_uString* 
ustrDirectoryURL, oslDirect
 
     osl_systemPathRemoveSeparator(path.pData);
 
+    if (isForbidden(path.getStr(), osl_File_OpenFlag_Read))
+        return osl_File_E_ACCES;
+
 #ifdef MACOSX
     {
         auto const n = std::max(int(path.getLength() + 1), int(PATH_MAX));
@@ -343,6 +346,9 @@ oslFileError SAL_CALL osl_getDirectoryItem(rtl_uString* 
ustrFileURL, oslDirector
 
     osl_systemPathRemoveSeparator(strSystemPath.pData);
 
+    if (isForbidden(strSystemPath, osl_File_OpenFlag_Read))
+        return osl_File_E_ACCES;
+
     if (osl::access(strSystemPath, F_OK) == -1)
     {
         osl_error = oslTranslateFileError(errno);
@@ -426,6 +432,9 @@ oslFileError SAL_CALL osl_removeDirectory( rtl_uString* 
ustrDirectoryURL )
 
 oslFileError osl_psz_createDirectory(char const * pszPath, sal_uInt32 flags)
 {
+    if (isForbidden(pszPath, osl_File_OpenFlag_Create))
+        return osl_File_E_ACCES;
+
     int nRet=0;
     int mode
         = (((flags & osl_File_OpenFlag_Read) == 0
@@ -455,6 +464,9 @@ oslFileError osl_psz_createDirectory(char const * pszPath, 
sal_uInt32 flags)
 
 static oslFileError osl_psz_removeDirectory( const char* pszPath )
 {
+    if (isForbidden(pszPath, osl_File_OpenFlag_Write))
+        return osl_File_E_ACCES;
+
     int nRet = rmdir(pszPath);
 
     if ( nRet < 0 )
@@ -550,6 +562,9 @@ oslFileError SAL_CALL osl_createDirectoryPath(
 
     osl::systemPathRemoveSeparator(sys_path);
 
+    if (isForbidden(sys_path.getStr(), osl_File_OpenFlag_Create))
+        return osl_File_E_ACCES;
+
     // const_cast because sys_path is a local copy which we want to modify 
inplace instead of
     // copy it into another buffer on the heap again
     return create_dir_recursively_(sys_path.pData->buffer, 
aDirectoryCreationCallbackFunc, pData);
@@ -584,6 +599,10 @@ oslFileError SAL_CALL osl_moveFile( rtl_uString* 
ustrFileURL, rtl_uString* ustrD
     if( eRet != osl_File_E_None )
         return eRet;
 
+    if (isForbidden(srcPath, osl_File_OpenFlag_Read) ||
+        isForbidden(destPath, osl_File_OpenFlag_Create))
+        return osl_File_E_ACCES;
+
 #ifdef MACOSX
     if ( macxp_resolveAlias( srcPath, PATH_MAX ) != 0 || macxp_resolveAlias( 
destPath, PATH_MAX ) != 0 )
       return oslTranslateFileError( errno );
@@ -597,6 +616,10 @@ oslFileError SAL_CALL osl_replaceFile(rtl_uString* 
ustrFileURL, rtl_uString* ust
     int nGid = -1;
     char destPath[PATH_MAX];
     oslFileError eRet = FileURLToPath(destPath, PATH_MAX, ustrDestURL);
+
+    if (isForbidden(destPath, osl_File_OpenFlag_Create))
+        return osl_File_E_ACCES;
+
     if (eRet == osl_File_E_None)
     {
         struct stat aFileStat;
@@ -673,6 +696,9 @@ oslFileError SAL_CALL osl_removeFile(rtl_uString* 
ustrFileURL)
       return oslTranslateFileError(errno);
 #endif/* MACOSX */
 
+    if (isForbidden(path, osl_File_OpenFlag_Write))
+        return osl_File_E_ACCES;
+
     return osl_unlinkFile(path);
 }
 
@@ -728,6 +754,10 @@ static oslFileError osl_unlinkFile(const char* pszPath)
 
 static oslFileError osl_psz_moveFile(const char* pszPath, const char* 
pszDestPath)
 {
+    if (isForbidden(pszPath, osl_File_OpenFlag_Read) ||
+        isForbidden(pszDestPath, osl_File_OpenFlag_Create))
+        return osl_File_E_ACCES;
+
     int nRet = rename(pszPath,pszDestPath);
 
     if (nRet < 0)
@@ -755,6 +785,10 @@ static oslFileError osl_psz_copyFile( const char* pszPath, 
const char* pszDestPa
     size_t nSourceSize=0;
     bool DestFileExists=true;
 
+    if (isForbidden(pszPath, osl_File_OpenFlag_Read) ||
+        isForbidden(pszDestPath, osl_File_OpenFlag_Create))
+        return osl_File_E_ACCES;
+
     /* mfe: does the source file really exists? */
     nRet = lstat_c(pszPath,&aFileStat);
 
diff --git a/sal/osl/unx/file_stat.cxx b/sal/osl/unx/file_stat.cxx
index 5c165132e9f3..3d0754883a11 100644
--- a/sal/osl/unx/file_stat.cxx
+++ b/sal/osl/unx/file_stat.cxx
@@ -274,6 +274,9 @@ static oslFileError osl_psz_setFileAttributes( const char* 
pszFilePath, sal_uInt
 
     OSL_ENSURE(!(osl_File_Attribute_Hidden & uAttributes), 
"osl_File_Attribute_Hidden doesn't work under Unix");
 
+    if (isForbidden(pszFilePath, osl_File_OpenFlag_Write))
+        return osl_File_E_ACCES;
+
     if (uAttributes & osl_File_Attribute_OwnRead)
         nNewMode |= S_IRUSR;
 
@@ -339,6 +342,9 @@ static oslFileError osl_psz_setFileTime (
     struct tm* pTM=0;
 #endif
 
+    if (isForbidden(pszFilePath, osl_File_OpenFlag_Write))
+        return osl_File_E_ACCES;
+
     nRet = lstat_c(pszFilePath,&aFileStat);
 
     if ( nRet < 0 )
diff --git a/sal/osl/unx/file_volume.cxx b/sal/osl/unx/file_volume.cxx
index e20b8a27d00e..0a6183292735 100644
--- a/sal/osl/unx/file_volume.cxx
+++ b/sal/osl/unx/file_volume.cxx
@@ -26,6 +26,7 @@
 
 #include "file_error_transl.hxx"
 #include "file_url.hxx"
+#include "file_impl.hxx"
 #include "system.hxx"
 
 #include <errno.h>
@@ -193,6 +194,9 @@ static oslFileError osl_psz_getVolumeInformation (
     if (!pInfo)
         return osl_File_E_INVAL;
 
+    if (isForbidden(pszDirectory, osl_File_OpenFlag_Read))
+        return osl_File_E_ACCES;
+
     pInfo->uValidFields = 0;
     pInfo->uAttributes  = 0;
     pInfo->uTotalSpace = 0;
diff --git a/sal/osl/unx/pipe.cxx b/sal/osl/unx/pipe.cxx
index 4dfd75ddf662..62897552ed41 100644
--- a/sal/osl/unx/pipe.cxx
+++ b/sal/osl/unx/pipe.cxx
@@ -29,6 +29,7 @@
 
 #include "sockimpl.hxx"
 #include "secimpl.hxx"
+#include "file_impl.hxx"
 #include "unixerrnostring.hxx"
 
 #include <cassert>
@@ -209,6 +210,9 @@ static oslPipe osl_psz_createPipe(const char *pszPipeName, 
oslPipeOptions Option
 
     SAL_INFO("sal.osl.pipe", "new pipe on fd " << pPipe->m_Socket << " '" << 
name << "'");
 
+    if (isForbidden(name.getStr(), osl_File_OpenFlag_Create))
+        return nullptr;
+
     addr.sun_family = AF_UNIX;
     // coverity[fixed_size_dest : FALSE] - safe, see check above
     strcpy(addr.sun_path, name.getStr());
diff --git a/sal/osl/unx/process.cxx b/sal/osl/unx/process.cxx
index cebdc6f35fdb..1d1548129f6d 100644
--- a/sal/osl/unx/process.cxx
+++ b/sal/osl/unx/process.cxx
@@ -19,7 +19,7 @@
 
 #include <sal/config.h>
 #include <rtl/ustring.hxx>
-
+#include "file_impl.hxx"
 #include <cassert>
 #include <fcntl.h>
 #include <limits.h>
@@ -598,6 +598,9 @@ oslProcessError osl_psz_executeProcess(char *pszImageName,
         return osl_Process_E_NotFound;
     }
 
+    if (isForbidden(pszImageName, 0x80 /* execute */))
+        return osl_Process_E_NoPermission;
+
     Data.m_pszArgs[0] = strdup(pszImageName);
     Data.m_pszArgs[1] = nullptr;
 
diff --git a/sal/osl/unx/profile.cxx b/sal/osl/unx/profile.cxx
index 1e7512a24db4..1ef1965b7c14 100644
--- a/sal/osl/unx/profile.cxx
+++ b/sal/osl/unx/profile.cxx
@@ -20,6 +20,7 @@
 #include "system.hxx"
 #include "readwrite_helper.hxx"
 #include "file_url.hxx"
+#include "file_impl.hxx"
 #include "unixerrnostring.hxx"
 
 #include <osl/diagnose.h>
@@ -937,6 +938,9 @@ static osl_TFile* openFileImpl(const char* pszFilename, 
oslProfileOption Profile
     osl_TFile* pFile = static_cast<osl_TFile*>(calloc(1, sizeof(osl_TFile)));
     bool       bWriteable = false;
 
+    if ( isForbidden( pszFilename, osl_File_OpenFlag_Write ) )
+        return nullptr;
+
     if ( ProfileFlags & ( osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ) )
     {
         bWriteable = true;
diff --git a/sal/qa/osl/file/osl_File.cxx b/sal/qa/osl/file/osl_File.cxx
index 6b0c50dfafd8..0de87eeb14a9 100644
--- a/sal/qa/osl/file/osl_File.cxx
+++ b/sal/qa/osl/file/osl_File.cxx
@@ -1313,6 +1313,124 @@ namespace osl_FileBase
     CPPUNIT_REGISTRY_ADD_TO_DEFAULT("osl_osl::FileBase");
 }
 
+#if (defined UNX)
+
+namespace osl_Forbidden
+{
+
+    class Forbidden : public CppUnit::TestFixture
+    {
+        OUString maScratchBad;
+        OUString maScratchGood;
+    public:
+        void setUp() override
+        {
+            // create a directory to play in
+            createTestDirectory(aTmpName3);
+            OUString aBadURL = aTmpName3 + "/bad";
+            OUString aGoodURL = aTmpName3 + "/good";
+            createTestDirectory(aBadURL);
+            createTestDirectory(aGoodURL);
+            File::getSystemPathFromFileURL(aBadURL, maScratchBad);
+            File::getSystemPathFromFileURL(aGoodURL, maScratchGood);
+        }
+
+        void tearDown() override
+        {
+            osl_setAllowedPaths(nullptr);
+            OUString aBadURL = aTmpName3 + "/bad";
+            OUString aGoodURL = aTmpName3 + "/good";
+            deleteTestDirectory(aBadURL);
+            deleteTestDirectory(aGoodURL);
+            deleteTestDirectory(aTmpName3);
+        }
+
+        void forbidden()
+        {
+            File::setAllowedPaths(maScratchGood);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden",
+                                         true, File::isForbidden(maScratchBad, 
osl_File_OpenFlag_Read));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("read from good should be allowed",
+                                         false, 
File::isForbidden(maScratchGood, osl_File_OpenFlag_Read));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to good should be forbidden",
+                                         true, 
File::isForbidden(maScratchGood, osl_File_OpenFlag_Write));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("create in good should be forbidden",
+                                         true, 
File::isForbidden(maScratchGood, osl_File_OpenFlag_Create));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("exec from good should be forbidden",
+                                         true, 
File::isForbidden(maScratchGood, 0x80));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be 
forbidden",
+                                         true, File::isForbidden(maScratchBad 
+ "/notthere", osl_File_OpenFlag_Write));
+
+            File::setAllowedPaths("w:" + maScratchGood + ":x:" + maScratchBad);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden",
+                                         true, File::isForbidden(maScratchBad, 
osl_File_OpenFlag_Read));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("read from good should be allowed", 
// w implies 'r'
+                                         false, 
File::isForbidden(maScratchGood, osl_File_OpenFlag_Read));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("write to good should be allowed",
+                                         false, 
File::isForbidden(maScratchGood, osl_File_OpenFlag_Write));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("exec from good should be forbidden",
+                                         true, 
File::isForbidden(maScratchGood, 0x80));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("exec from bad should be allowed",
+                                         false, 
File::isForbidden(maScratchBad, 0x80));
+        }
+
+        void open()
+        {
+            File::setAllowedPaths(maScratchGood);
+            File testFile(maScratchBad + "/open");
+            auto nError1 = testFile.open(osl_File_OpenFlag_Read | 
osl_File_OpenFlag_Write);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("disabled path allowed", 
osl::FileBase::E_ACCES, nError1);
+            deleteTestFile(testFile.getURL());
+        }
+
+        void copy()
+        {
+            File::setAllowedPaths("w:" + maScratchGood);
+            File testGood(maScratchGood + "/good");
+            File testGoodTo(maScratchGood + "/good_to");
+            File testBad(maScratchBad + "/bad");
+
+            auto nError1 = testGood.open(osl_File_OpenFlag_Create);
+            CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1);
+
+            auto nErrorCopy = File::copy(maScratchGood + "/good", 
maScratchGood + "/good_to");
+            CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nErrorCopy);
+
+            auto nErrorCopyBad = File::copy(maScratchGood + "/good_to", 
maScratchBad + "/bad");
+            CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_ACCES, nErrorCopyBad);
+
+            deleteTestFile(maScratchGood + "/good_to");
+            deleteTestFile(maScratchGood + "/good");
+        }
+
+        void nextTests()
+        {
+            // more entry points to test
+#if 0
+            auto nError1 = File::move(aTmpName4, aCanURL1);
+            auto nError2 = File::remove(aTmpName4);
+            auto nError3 = File::setAttributes(aTmpName6, 
osl_File_Attribute_ReadOnly);
+            bool bOk = osl_getSystemTime(pTV_current);
+            CPPUNIT_ASSERT(bOk);
+            auto nError4 = File::setTime(aTmpName6, *pTV_current, 
*pTV_current, *pTV_current);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE(errorToStr(nError2).getStr(), 
osl::FileBase::E_None, nError2);
+#endif
+        }
+
+        CPPUNIT_TEST_SUITE(Forbidden);
+        CPPUNIT_TEST(forbidden);
+//        CPPUNIT_TEST(open);
+//        CPPUNIT_TEST(copy);
+//        CPPUNIT_TEST(nextTests);
+        CPPUNIT_TEST_SUITE_END();
+    };
+
+    CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Forbidden::Forbidden, 
"osl_Forbidden");
+
+    CPPUNIT_REGISTRY_ADD_TO_DEFAULT("osl_Forbidden");
+}
+#endif
+
 namespace osl_FileStatus
 {
     //  testing the method
diff --git a/sal/util/sal.map b/sal/util/sal.map
index c5c3e4d55641..586a41ee997d 100644
--- a/sal/util/sal.map
+++ b/sal/util/sal.map
@@ -761,6 +761,12 @@ PRIVATE_1.8 { # LibreOffice 7.3
         rtl_uString_newReplaceStrAtUtf16L;
 } PRIVATE_1.7;
 
+PRIVATE_1.9 { # LibreOffice 7.7
+    global:
+        osl_setAllowedPaths;
+        osl_isForbiddenPath;
+} PRIVATE_1.8;
+
 PRIVATE_textenc.1 { # LibreOffice 3.6
     global:
         _ZN3sal6detail7textenc20convertCharToUnicode*;

Reply via email to