2b44f94908
See tdf#42949 for motivation Change-Id: If710445176681de8e0a0b6c65f58ecaca19dbccf Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132768 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
357 lines
14 KiB
C++
357 lines
14 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* 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/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <unotools/securityoptions.hxx>
|
|
#include <unotools/configmgr.hxx>
|
|
#include <unotools/configitem.hxx>
|
|
#include <unotools/ucbhelper.hxx>
|
|
#include <com/sun/star/uno/Any.hxx>
|
|
#include <com/sun/star/uno/Sequence.hxx>
|
|
|
|
#include <com/sun/star/beans/PropertyValue.hpp>
|
|
#include <comphelper/propertyvalue.hxx>
|
|
#include <comphelper/sequence.hxx>
|
|
#include <tools/urlobj.hxx>
|
|
|
|
#include <unotools/pathoptions.hxx>
|
|
#include <officecfg/Office/Common.hxx>
|
|
|
|
// namespaces
|
|
|
|
using namespace ::com::sun::star::uno;
|
|
|
|
constexpr OUStringLiteral PROPERTYNAME_MACRO_TRUSTEDAUTHORS = u"TrustedAuthors";
|
|
constexpr OUStringLiteral PROPERTYNAME_TRUSTEDAUTHOR_SUBJECTNAME = u"SubjectName";
|
|
constexpr OUStringLiteral PROPERTYNAME_TRUSTEDAUTHOR_SERIALNUMBER = u"SerialNumber";
|
|
constexpr OUStringLiteral PROPERTYNAME_TRUSTEDAUTHOR_RAWDATA = u"RawData";
|
|
|
|
|
|
namespace SvtSecurityOptions
|
|
{
|
|
|
|
bool IsReadOnly( EOption eOption )
|
|
{
|
|
bool bReadonly;
|
|
switch(eOption)
|
|
{
|
|
case SvtSecurityOptions::EOption::SecureUrls :
|
|
bReadonly = officecfg::Office::Common::Security::Scripting::SecureURL::isReadOnly();
|
|
break;
|
|
case SvtSecurityOptions::EOption::DocWarnSaveOrSend:
|
|
bReadonly = officecfg::Office::Common::Security::Scripting::WarnSaveOrSendDoc::isReadOnly();
|
|
break;
|
|
case SvtSecurityOptions::EOption::DocWarnSigning:
|
|
bReadonly = officecfg::Office::Common::Security::Scripting::WarnSignDoc::isReadOnly();
|
|
break;
|
|
case SvtSecurityOptions::EOption::DocWarnPrint:
|
|
bReadonly = officecfg::Office::Common::Security::Scripting::WarnPrintDoc::isReadOnly();
|
|
break;
|
|
case SvtSecurityOptions::EOption::DocWarnCreatePdf:
|
|
bReadonly = officecfg::Office::Common::Security::Scripting::WarnCreatePDF::isReadOnly();
|
|
break;
|
|
case SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo:
|
|
bReadonly = officecfg::Office::Common::Security::Scripting::RemovePersonalInfoOnSaving::isReadOnly();
|
|
break;
|
|
case SvtSecurityOptions::EOption::DocWarnRecommendPassword:
|
|
bReadonly = officecfg::Office::Common::Security::Scripting::RecommendPasswordProtection::isReadOnly();
|
|
break;
|
|
case SvtSecurityOptions::EOption::MacroSecLevel:
|
|
bReadonly = officecfg::Office::Common::Security::Scripting::MacroSecurityLevel::isReadOnly();
|
|
break;
|
|
case SvtSecurityOptions::EOption::MacroTrustedAuthors:
|
|
bReadonly = false; // TODO? officecfg::Office::Common::Security::Scripting::TrustedAuthors::isReadOnly();
|
|
break;
|
|
case SvtSecurityOptions::EOption::CtrlClickHyperlink:
|
|
bReadonly = officecfg::Office::Common::Security::Scripting::HyperlinksWithCtrlClick::isReadOnly();
|
|
break;
|
|
case SvtSecurityOptions::EOption::BlockUntrustedRefererLinks:
|
|
bReadonly = officecfg::Office::Common::Security::Scripting::BlockUntrustedRefererLinks::isReadOnly();
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
bReadonly = true;
|
|
}
|
|
|
|
return bReadonly;
|
|
}
|
|
|
|
std::vector< OUString > GetSecureURLs()
|
|
{
|
|
if (utl::ConfigManager::IsFuzzing())
|
|
return {};
|
|
std::vector<OUString> aRet = comphelper::sequenceToContainer<std::vector<OUString>>(
|
|
officecfg::Office::Common::Security::Scripting::SecureURL::get());
|
|
SvtPathOptions aOpt;
|
|
std::transform(aRet.begin(), aRet.end(), aRet.begin(),
|
|
[&aOpt](const OUString& rUrl) -> OUString { return aOpt.SubstituteVariable( rUrl ); });
|
|
return aRet;
|
|
}
|
|
|
|
void SetSecureURLs( std::vector< OUString >&& urlList )
|
|
{
|
|
// DBG_ASSERT(!officecfg::SecureURL::isReadOnly(), "SvtSecurityOptions_Impl::SetSecureURLs()\nYou tried to write on a readonly value!\n");
|
|
// if (officecfg::SecureURL::isReadOnly())
|
|
// return;
|
|
std::vector< OUString > lURLs( std::move(urlList) );
|
|
SvtPathOptions aOpt;
|
|
std::transform(lURLs.begin(), lURLs.end(), lURLs.begin(),
|
|
[&aOpt](const OUString& rUrl) -> OUString { return aOpt.UseVariable( rUrl ); });
|
|
std::shared_ptr<comphelper::ConfigurationChanges> xChanges = comphelper::ConfigurationChanges::create();
|
|
officecfg::Office::Common::Security::Scripting::SecureURL::set(comphelper::containerToSequence(lURLs), xChanges);
|
|
xChanges->commit();
|
|
}
|
|
|
|
bool isSecureMacroUri(
|
|
OUString const & uri, OUString const & referer)
|
|
{
|
|
switch (INetURLObject(uri).GetProtocol()) {
|
|
case INetProtocol::Macro:
|
|
if (uri.startsWithIgnoreAsciiCase("macro:///")) {
|
|
// Denotes an App-BASIC macro (see SfxMacroLoader::loadMacro), which
|
|
// is considered safe:
|
|
return true;
|
|
}
|
|
[[fallthrough]];
|
|
case INetProtocol::Slot:
|
|
return referer.equalsIgnoreAsciiCase("private:user")
|
|
|| isTrustedLocationUri(referer);
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool isUntrustedReferer(OUString const & referer)
|
|
{
|
|
return IsOptionSet(EOption::BlockUntrustedRefererLinks)
|
|
&& !(referer.isEmpty() || referer.startsWithIgnoreAsciiCase("private:")
|
|
|| isTrustedLocationUri(referer));
|
|
}
|
|
|
|
bool isTrustedLocationUri(OUString const & uri)
|
|
{
|
|
for (const auto & url : GetSecureURLs())
|
|
{
|
|
if (utl::UCBContentHelper::IsSubPath(url, uri))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool isTrustedLocationUriForUpdatingLinks(OUString const & uri)
|
|
{
|
|
return GetMacroSecurityLevel() == 0 || uri.isEmpty()
|
|
|| uri.startsWithIgnoreAsciiCase("private:")
|
|
|| isTrustedLocationUri(uri);
|
|
}
|
|
|
|
sal_Int32 GetMacroSecurityLevel()
|
|
{
|
|
return officecfg::Office::Common::Security::Scripting::MacroSecurityLevel::get();
|
|
}
|
|
|
|
void SetMacroSecurityLevel( sal_Int32 _nLevel )
|
|
{
|
|
if( officecfg::Office::Common::Security::Scripting::MacroSecurityLevel::isReadOnly() )
|
|
return;
|
|
|
|
if( _nLevel > 3 || _nLevel < 0 )
|
|
_nLevel = 3;
|
|
|
|
std::shared_ptr<comphelper::ConfigurationChanges> xChanges = comphelper::ConfigurationChanges::create();
|
|
officecfg::Office::Common::Security::Scripting::MacroSecurityLevel::set(_nLevel, xChanges);
|
|
xChanges->commit();
|
|
}
|
|
|
|
bool IsMacroDisabled()
|
|
{
|
|
return officecfg::Office::Common::Security::Scripting::DisableMacrosExecution::get();
|
|
}
|
|
|
|
std::vector< SvtSecurityOptions::Certificate > GetTrustedAuthors()
|
|
{
|
|
Reference<css::container::XHierarchicalNameAccess> xHierarchyAccess = utl::ConfigManager::acquireTree(u"Office.Common/Security/Scripting");
|
|
const Sequence< OUString > lAuthors = utl::ConfigItem::GetNodeNames( xHierarchyAccess, PROPERTYNAME_MACRO_TRUSTEDAUTHORS, utl::ConfigNameFormat::LocalPath );
|
|
sal_Int32 c1 = lAuthors.getLength();
|
|
if( !c1 )
|
|
return {};
|
|
|
|
sal_Int32 c2 = c1 * 3; // 3 Properties inside Struct TrustedAuthor
|
|
Sequence< OUString > lAllAuthors( c2 );
|
|
auto plAllAuthors = lAllAuthors.getArray();
|
|
sal_Int32 i2 = 0;
|
|
OUString aSep( "/" );
|
|
for( const auto& rAuthor : lAuthors )
|
|
{
|
|
plAllAuthors[ i2 ] = PROPERTYNAME_MACRO_TRUSTEDAUTHORS + aSep + rAuthor + aSep + PROPERTYNAME_TRUSTEDAUTHOR_SUBJECTNAME;
|
|
++i2;
|
|
plAllAuthors[ i2 ] = PROPERTYNAME_MACRO_TRUSTEDAUTHORS + aSep + rAuthor + aSep + PROPERTYNAME_TRUSTEDAUTHOR_SERIALNUMBER;
|
|
++i2;
|
|
plAllAuthors[ i2 ] = PROPERTYNAME_MACRO_TRUSTEDAUTHORS + aSep + rAuthor + aSep + PROPERTYNAME_TRUSTEDAUTHOR_RAWDATA;
|
|
++i2;
|
|
}
|
|
|
|
Sequence< Any > lValues = utl::ConfigItem::GetProperties( xHierarchyAccess, lAllAuthors, /*bAllLocales*/false );
|
|
if( lValues.getLength() != c2 )
|
|
return {};
|
|
|
|
std::vector< SvtSecurityOptions::Certificate > aTrustedAuthors;
|
|
SvtSecurityOptions::Certificate aCert;
|
|
i2 = 0;
|
|
for( sal_Int32 i1 = 0; i1 < c1; ++i1 )
|
|
{
|
|
lValues[ i2 ] >>= aCert.SubjectName;
|
|
++i2;
|
|
lValues[ i2 ] >>= aCert.SerialNumber;
|
|
++i2;
|
|
lValues[ i2 ] >>= aCert.RawData;
|
|
++i2;
|
|
// Filter out TrustedAuthor entries with empty RawData, which
|
|
// would cause an unexpected std::bad_alloc in
|
|
// SecurityEnvironment_NssImpl::createCertificateFromAscii and
|
|
// have been observed in the wild (fdo#55019):
|
|
if( !aCert.RawData.isEmpty() )
|
|
{
|
|
aTrustedAuthors.push_back( aCert );
|
|
}
|
|
}
|
|
return aTrustedAuthors;
|
|
}
|
|
|
|
void SetTrustedAuthors( const std::vector< Certificate >& rAuthors )
|
|
{
|
|
// DBG_ASSERT(!m_bROTrustedAuthors, "SvtSecurityOptions_Impl::SetTrustedAuthors()\nYou tried to write on a readonly value!\n");
|
|
// if( m_bROTrustedAuthors )
|
|
// return;
|
|
|
|
Reference<css::container::XHierarchicalNameAccess> xHierarchyAccess = utl::ConfigManager::acquireTree(u"Office.Common/Security/Scripting");
|
|
sal_Int32 nCnt = rAuthors.size();
|
|
for( sal_Int32 i = 0; i < nCnt; ++i )
|
|
{
|
|
OUString aPrefix(
|
|
PROPERTYNAME_MACRO_TRUSTEDAUTHORS + "/a"
|
|
+ OUString::number(i) + "/");
|
|
Sequence< css::beans::PropertyValue > lPropertyValues{
|
|
comphelper::makePropertyValue(aPrefix + PROPERTYNAME_TRUSTEDAUTHOR_SUBJECTNAME,
|
|
rAuthors[i].SubjectName),
|
|
comphelper::makePropertyValue(aPrefix + PROPERTYNAME_TRUSTEDAUTHOR_SERIALNUMBER,
|
|
rAuthors[i].SerialNumber),
|
|
comphelper::makePropertyValue(aPrefix + PROPERTYNAME_TRUSTEDAUTHOR_RAWDATA,
|
|
rAuthors[i].RawData)
|
|
};
|
|
|
|
utl::ConfigItem::SetSetProperties( xHierarchyAccess, PROPERTYNAME_MACRO_TRUSTEDAUTHORS, lPropertyValues );
|
|
}
|
|
}
|
|
|
|
bool IsOptionSet( EOption eOption )
|
|
{
|
|
if (utl::ConfigManager::IsFuzzing())
|
|
return false;
|
|
bool bSet = false;
|
|
switch(eOption)
|
|
{
|
|
case SvtSecurityOptions::EOption::DocWarnSaveOrSend:
|
|
bSet = officecfg::Office::Common::Security::Scripting::WarnSaveOrSendDoc::get();
|
|
break;
|
|
case SvtSecurityOptions::EOption::DocWarnSigning:
|
|
bSet = officecfg::Office::Common::Security::Scripting::WarnSignDoc::get();
|
|
break;
|
|
case SvtSecurityOptions::EOption::DocWarnPrint:
|
|
bSet = officecfg::Office::Common::Security::Scripting::WarnPrintDoc::get();
|
|
break;
|
|
case SvtSecurityOptions::EOption::DocWarnCreatePdf:
|
|
bSet = officecfg::Office::Common::Security::Scripting::WarnCreatePDF::get();
|
|
break;
|
|
case SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo:
|
|
bSet = officecfg::Office::Common::Security::Scripting::RemovePersonalInfoOnSaving::get();
|
|
break;
|
|
case SvtSecurityOptions::EOption::DocWarnRecommendPassword:
|
|
bSet = officecfg::Office::Common::Security::Scripting::RecommendPasswordProtection::get();
|
|
break;
|
|
case SvtSecurityOptions::EOption::CtrlClickHyperlink:
|
|
bSet = officecfg::Office::Common::Security::Scripting::HyperlinksWithCtrlClick::get();
|
|
break;
|
|
case SvtSecurityOptions::EOption::BlockUntrustedRefererLinks:
|
|
bSet = officecfg::Office::Common::Security::Scripting::BlockUntrustedRefererLinks::get();
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
}
|
|
|
|
return bSet;
|
|
}
|
|
|
|
void SetOption( EOption eOption, bool bValue )
|
|
{
|
|
std::shared_ptr<comphelper::ConfigurationChanges> xChanges = comphelper::ConfigurationChanges::create();
|
|
switch(eOption)
|
|
{
|
|
case SvtSecurityOptions::EOption::DocWarnSaveOrSend:
|
|
officecfg::Office::Common::Security::Scripting::WarnSaveOrSendDoc::set(bValue, xChanges);
|
|
break;
|
|
case SvtSecurityOptions::EOption::DocWarnSigning:
|
|
officecfg::Office::Common::Security::Scripting::WarnSignDoc::set(bValue, xChanges);
|
|
break;
|
|
case SvtSecurityOptions::EOption::DocWarnPrint:
|
|
officecfg::Office::Common::Security::Scripting::WarnPrintDoc::set(bValue, xChanges);
|
|
break;
|
|
case SvtSecurityOptions::EOption::DocWarnCreatePdf:
|
|
officecfg::Office::Common::Security::Scripting::WarnCreatePDF::set(bValue, xChanges);
|
|
break;
|
|
case SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo:
|
|
officecfg::Office::Common::Security::Scripting::RemovePersonalInfoOnSaving::set(bValue, xChanges);
|
|
break;
|
|
case SvtSecurityOptions::EOption::DocWarnRecommendPassword:
|
|
officecfg::Office::Common::Security::Scripting::RecommendPasswordProtection::set(bValue, xChanges);
|
|
break;
|
|
case SvtSecurityOptions::EOption::CtrlClickHyperlink:
|
|
officecfg::Office::Common::Security::Scripting::HyperlinksWithCtrlClick::set(bValue, xChanges);
|
|
break;
|
|
case SvtSecurityOptions::EOption::BlockUntrustedRefererLinks:
|
|
officecfg::Office::Common::Security::Scripting::BlockUntrustedRefererLinks::set(bValue, xChanges);
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
}
|
|
xChanges->commit();
|
|
}
|
|
|
|
} // namespace SvtSecurityOptions
|
|
|
|
|
|
// map personal info strings to 1, 2, ... to remove personal info
|
|
size_t SvtSecurityMapPersonalInfo::GetInfoID( const OUString sPersonalInfo )
|
|
{
|
|
auto aIter = aInfoIDs.find( sPersonalInfo );
|
|
if ( aIter == aInfoIDs.end() )
|
|
{
|
|
size_t nNewID = aInfoIDs.size() + 1;
|
|
aInfoIDs[sPersonalInfo] = nNewID;
|
|
return nNewID;
|
|
}
|
|
|
|
return aIter->second;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|