1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <config_features.h> 21 22 #include <sfx2/docmacromode.hxx> 23 #include <sfx2/signaturestate.hxx> 24 #include <sfx2/docfile.hxx> 25 26 #include <com/sun/star/document/MacroExecMode.hpp> 27 #include <com/sun/star/task/ErrorCodeRequest.hpp> 28 #include <com/sun/star/task/DocumentMacroConfirmationRequest.hpp> 29 #include <com/sun/star/security/DocumentDigitalSignatures.hpp> 30 #include <com/sun/star/script/XLibraryContainer.hpp> 31 #include <com/sun/star/document/XEmbeddedScripts.hpp> 32 33 #include <comphelper/processfactory.hxx> 34 #include <framework/interaction.hxx> 35 #include <osl/file.hxx> 36 #include <unotools/securityoptions.hxx> 37 #include <svtools/sfxecode.hxx> 38 #include <tools/diagnose_ex.h> 39 #include <tools/urlobj.hxx> 40 41 42 namespace sfx2 43 { 44 45 46 using ::com::sun::star::uno::Reference; 47 using ::com::sun::star::task::XInteractionHandler; 48 using ::com::sun::star::uno::Any; 49 using ::com::sun::star::uno::Sequence; 50 using ::com::sun::star::task::DocumentMacroConfirmationRequest; 51 using ::com::sun::star::task::ErrorCodeRequest; 52 using ::com::sun::star::uno::Exception; 53 using ::com::sun::star::security::DocumentDigitalSignatures; 54 using ::com::sun::star::security::XDocumentDigitalSignatures; 55 using ::com::sun::star::embed::XStorage; 56 using ::com::sun::star::document::XEmbeddedScripts; 57 using ::com::sun::star::script::XLibraryContainer; 58 using ::com::sun::star::container::XNameAccess; 59 using ::com::sun::star::uno::UNO_QUERY_THROW; 60 61 namespace MacroExecMode = ::com::sun::star::document::MacroExecMode; 62 63 64 //= DocumentMacroMode_Data 65 66 struct DocumentMacroMode_Data 67 { 68 IMacroDocumentAccess& m_rDocumentAccess; 69 bool m_bMacroDisabledMessageShown; 70 bool m_bDocMacroDisabledMessageShown; 71 DocumentMacroMode_Datasfx2::DocumentMacroMode_Data72 explicit DocumentMacroMode_Data( IMacroDocumentAccess& rDocumentAccess ) 73 :m_rDocumentAccess( rDocumentAccess ) 74 ,m_bMacroDisabledMessageShown( false ) 75 ,m_bDocMacroDisabledMessageShown( false ) 76 { 77 } 78 }; 79 80 81 //= helper 82 83 namespace 84 { 85 lcl_showGeneralSfxErrorOnce(const Reference<XInteractionHandler> & rxHandler,ErrCode nSfxErrorCode,bool & rbAlreadyShown)86 void lcl_showGeneralSfxErrorOnce( const Reference< XInteractionHandler >& rxHandler, ErrCode nSfxErrorCode, bool& rbAlreadyShown ) 87 { 88 if ( rbAlreadyShown ) 89 return; 90 91 ErrorCodeRequest aErrorCodeRequest; 92 aErrorCodeRequest.ErrCode = sal_uInt32(nSfxErrorCode); 93 94 SfxMedium::CallApproveHandler( rxHandler, makeAny( aErrorCodeRequest ), false ); 95 rbAlreadyShown = true; 96 } 97 98 lcl_showMacrosDisabledError(const Reference<XInteractionHandler> & rxHandler,bool & rbAlreadyShown)99 void lcl_showMacrosDisabledError( const Reference< XInteractionHandler >& rxHandler, bool& rbAlreadyShown ) 100 { 101 lcl_showGeneralSfxErrorOnce( rxHandler, ERRCODE_SFX_MACROS_SUPPORT_DISABLED, rbAlreadyShown ); 102 } 103 104 lcl_showDocumentMacrosDisabledError(const Reference<XInteractionHandler> & rxHandler,bool & rbAlreadyShown)105 void lcl_showDocumentMacrosDisabledError( const Reference< XInteractionHandler >& rxHandler, bool& rbAlreadyShown ) 106 { 107 #ifdef MACOSX 108 lcl_showGeneralSfxErrorOnce( rxHandler, ERRCODE_SFX_DOCUMENT_MACRO_DISABLED_MAC, rbAlreadyShown ); 109 #else 110 lcl_showGeneralSfxErrorOnce( rxHandler, ERRCODE_SFX_DOCUMENT_MACRO_DISABLED, rbAlreadyShown ); 111 #endif 112 } 113 lcl_showMacrosDisabledUnsignedContentError(const Reference<XInteractionHandler> & rxHandler,bool & rbAlreadyShown)114 void lcl_showMacrosDisabledUnsignedContentError( const Reference< XInteractionHandler >& rxHandler, bool& rbAlreadyShown ) 115 { 116 lcl_showGeneralSfxErrorOnce( rxHandler, ERRCODE_SFX_DOCUMENT_MACRO_DISABLED_CONTENT_UNSIGNED, rbAlreadyShown ); 117 } 118 lcl_showMacroWarning(const Reference<XInteractionHandler> & rxHandler,const OUString & rDocumentLocation)119 bool lcl_showMacroWarning( const Reference< XInteractionHandler >& rxHandler, 120 const OUString& rDocumentLocation ) 121 { 122 DocumentMacroConfirmationRequest aRequest; 123 aRequest.DocumentURL = rDocumentLocation; 124 return SfxMedium::CallApproveHandler( rxHandler, makeAny( aRequest ), true ); 125 } 126 } 127 128 //= DocumentMacroMode DocumentMacroMode(IMacroDocumentAccess & rDocumentAccess)129 DocumentMacroMode::DocumentMacroMode( IMacroDocumentAccess& rDocumentAccess ) 130 :m_xData( std::make_shared<DocumentMacroMode_Data>( rDocumentAccess ) ) 131 { 132 } 133 allowMacroExecution()134 bool DocumentMacroMode::allowMacroExecution() 135 { 136 m_xData->m_rDocumentAccess.setCurrentMacroExecMode( MacroExecMode::ALWAYS_EXECUTE_NO_WARN ); 137 return true; 138 } 139 disallowMacroExecution()140 bool DocumentMacroMode::disallowMacroExecution() 141 { 142 m_xData->m_rDocumentAccess.setCurrentMacroExecMode( MacroExecMode::NEVER_EXECUTE ); 143 return false; 144 } 145 adjustMacroMode(const Reference<XInteractionHandler> & rxInteraction,bool bHasValidContentSignature)146 bool DocumentMacroMode::adjustMacroMode( const Reference< XInteractionHandler >& rxInteraction, bool bHasValidContentSignature ) 147 { 148 sal_uInt16 nMacroExecutionMode = m_xData->m_rDocumentAccess.getCurrentMacroExecMode(); 149 150 if ( SvtSecurityOptions().IsMacroDisabled() ) 151 { 152 // no macro should be executed at all 153 lcl_showMacrosDisabledError( rxInteraction, m_xData->m_bMacroDisabledMessageShown ); 154 return disallowMacroExecution(); 155 } 156 157 // get setting from configuration if required 158 enum AutoConfirmation 159 { 160 eNoAutoConfirm, 161 eAutoConfirmApprove, 162 eAutoConfirmReject 163 }; 164 AutoConfirmation eAutoConfirm( eNoAutoConfirm ); 165 166 if ( ( nMacroExecutionMode == MacroExecMode::USE_CONFIG ) 167 || ( nMacroExecutionMode == MacroExecMode::USE_CONFIG_REJECT_CONFIRMATION ) 168 || ( nMacroExecutionMode == MacroExecMode::USE_CONFIG_APPROVE_CONFIRMATION ) 169 ) 170 { 171 // check confirm first, as nMacroExecutionMode is always overwritten by the GetMacroSecurityLevel() switch 172 if (nMacroExecutionMode == MacroExecMode::USE_CONFIG_REJECT_CONFIRMATION) 173 eAutoConfirm = eAutoConfirmReject; 174 else if (nMacroExecutionMode == MacroExecMode::USE_CONFIG_APPROVE_CONFIRMATION) 175 eAutoConfirm = eAutoConfirmApprove; 176 177 SvtSecurityOptions aOpt; 178 switch ( aOpt.GetMacroSecurityLevel() ) 179 { 180 case 3: 181 nMacroExecutionMode = MacroExecMode::FROM_LIST_NO_WARN; 182 break; 183 case 2: 184 nMacroExecutionMode = MacroExecMode::FROM_LIST_AND_SIGNED_WARN; 185 break; 186 case 1: 187 nMacroExecutionMode = MacroExecMode::ALWAYS_EXECUTE; 188 break; 189 case 0: 190 nMacroExecutionMode = MacroExecMode::ALWAYS_EXECUTE_NO_WARN; 191 break; 192 default: 193 OSL_FAIL( "DocumentMacroMode::adjustMacroMode: unexpected macro security level!" ); 194 nMacroExecutionMode = MacroExecMode::NEVER_EXECUTE; 195 } 196 } 197 198 if ( nMacroExecutionMode == MacroExecMode::NEVER_EXECUTE ) 199 return false; 200 201 if ( nMacroExecutionMode == MacroExecMode::ALWAYS_EXECUTE_NO_WARN ) 202 return true; 203 204 try 205 { 206 // get document location from medium name and check whether it is a trusted one 207 // the service is created without document version, since it is not of interest here 208 Reference< XDocumentDigitalSignatures > xSignatures(DocumentDigitalSignatures::createDefault(::comphelper::getProcessComponentContext())); 209 INetURLObject aURLReferer( m_xData->m_rDocumentAccess.getDocumentLocation() ); 210 211 OUString aLocation; 212 if ( aURLReferer.removeSegment() ) 213 aLocation = aURLReferer.GetMainURL( INetURLObject::DecodeMechanism::NONE ); 214 215 if ( !aLocation.isEmpty() && xSignatures->isLocationTrusted( aLocation ) ) 216 { 217 return allowMacroExecution(); 218 } 219 220 // at this point it is clear that the document is not in the secure location 221 if ( nMacroExecutionMode == MacroExecMode::FROM_LIST_NO_WARN ) 222 { 223 lcl_showDocumentMacrosDisabledError( rxInteraction, m_xData->m_bDocMacroDisabledMessageShown ); 224 return disallowMacroExecution(); 225 } 226 227 // check whether the document is signed with trusted certificate 228 if ( nMacroExecutionMode != MacroExecMode::FROM_LIST ) 229 { 230 // the trusted macro check will also retrieve the signature state ( small optimization ) 231 const SvtSecurityOptions aSecOption; 232 const bool bAllowUIToAddAuthor = nMacroExecutionMode != MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN 233 && (nMacroExecutionMode == MacroExecMode::ALWAYS_EXECUTE 234 || !aSecOption.IsReadOnly(SvtSecurityOptions::EOption::MacroTrustedAuthors)); 235 const bool bHasTrustedMacroSignature = m_xData->m_rDocumentAccess.hasTrustedScriptingSignature(bAllowUIToAddAuthor); 236 237 SignatureState nSignatureState = m_xData->m_rDocumentAccess.getScriptingSignatureState(); 238 if ( nSignatureState == SignatureState::BROKEN ) 239 { 240 if (!bAllowUIToAddAuthor) 241 lcl_showDocumentMacrosDisabledError(rxInteraction, m_xData->m_bDocMacroDisabledMessageShown); 242 return disallowMacroExecution(); 243 } 244 else if ( m_xData->m_rDocumentAccess.macroCallsSeenWhileLoading() && 245 bHasTrustedMacroSignature && 246 !bHasValidContentSignature) 247 { 248 // When macros are signed, and the document has events which call macros, the document content needs to be signed too. 249 lcl_showMacrosDisabledUnsignedContentError(rxInteraction, m_xData->m_bDocMacroDisabledMessageShown); 250 return disallowMacroExecution(); 251 } 252 else if ( bHasTrustedMacroSignature ) 253 { 254 // there is trusted macro signature, allow macro execution 255 return allowMacroExecution(); 256 } 257 else if ( nSignatureState == SignatureState::OK 258 || nSignatureState == SignatureState::NOTVALIDATED ) 259 { 260 // there is valid signature, but it is not from the trusted author 261 if (!bAllowUIToAddAuthor) 262 lcl_showDocumentMacrosDisabledError(rxInteraction, m_xData->m_bDocMacroDisabledMessageShown); 263 return disallowMacroExecution(); 264 } 265 } 266 267 // at this point it is clear that the document is neither in secure location nor signed with trusted certificate 268 if ( ( nMacroExecutionMode == MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN ) 269 || ( nMacroExecutionMode == MacroExecMode::FROM_LIST_AND_SIGNED_WARN ) 270 ) 271 { 272 if ( nMacroExecutionMode == MacroExecMode::FROM_LIST_AND_SIGNED_WARN ) 273 lcl_showDocumentMacrosDisabledError( rxInteraction, m_xData->m_bDocMacroDisabledMessageShown ); 274 275 return disallowMacroExecution(); 276 } 277 } 278 catch ( const Exception& ) 279 { 280 if ( ( nMacroExecutionMode == MacroExecMode::FROM_LIST_NO_WARN ) 281 || ( nMacroExecutionMode == MacroExecMode::FROM_LIST_AND_SIGNED_WARN ) 282 || ( nMacroExecutionMode == MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN ) 283 ) 284 { 285 return disallowMacroExecution(); 286 } 287 } 288 289 // confirmation is required 290 bool bSecure = false; 291 292 if ( eAutoConfirm == eNoAutoConfirm ) 293 { 294 OUString sReferrer( m_xData->m_rDocumentAccess.getDocumentLocation() ); 295 296 OUString aSystemFileURL; 297 if ( osl::FileBase::getSystemPathFromFileURL( sReferrer, aSystemFileURL ) == osl::FileBase::E_None ) 298 sReferrer = aSystemFileURL; 299 300 bSecure = lcl_showMacroWarning( rxInteraction, sReferrer ); 301 } 302 else 303 bSecure = ( eAutoConfirm == eAutoConfirmApprove ); 304 305 return ( bSecure ? allowMacroExecution() : disallowMacroExecution() ); 306 } 307 308 isMacroExecutionDisallowed() const309 bool DocumentMacroMode::isMacroExecutionDisallowed() const 310 { 311 return m_xData->m_rDocumentAccess.getCurrentMacroExecMode() == MacroExecMode::NEVER_EXECUTE; 312 } 313 314 containerHasBasicMacros(const Reference<XLibraryContainer> & xContainer)315 bool DocumentMacroMode::containerHasBasicMacros( const Reference< XLibraryContainer >& xContainer ) 316 { 317 bool bHasMacroLib = false; 318 try 319 { 320 if ( xContainer.is() ) 321 { 322 // a library container exists; check if it's empty 323 324 // if there are libraries except the "Standard" library 325 // we assume that they are not empty (because they have been created by the user) 326 if ( !xContainer->hasElements() ) 327 bHasMacroLib = false; 328 else 329 { 330 static const OUStringLiteral aStdLibName( u"Standard" ); 331 static const OUStringLiteral aVBAProject( u"VBAProject" ); 332 const Sequence< OUString > aElements = xContainer->getElementNames(); 333 for( const OUString& aElement : aElements ) 334 { 335 if( aElement == aStdLibName || aElement == aVBAProject ) 336 { 337 Reference < XNameAccess > xLib; 338 Any aAny = xContainer->getByName( aElement ); 339 aAny >>= xLib; 340 if ( xLib.is() && xLib->hasElements() ) 341 return true; 342 } 343 else 344 return true; 345 } 346 } 347 } 348 } 349 catch( const Exception& ) 350 { 351 DBG_UNHANDLED_EXCEPTION("sfx.doc"); 352 } 353 return bHasMacroLib; 354 } 355 356 hasMacroLibrary() const357 bool DocumentMacroMode::hasMacroLibrary() const 358 { 359 bool bHasMacroLib = false; 360 #if HAVE_FEATURE_SCRIPTING 361 try 362 { 363 Reference< XEmbeddedScripts > xScripts( m_xData->m_rDocumentAccess.getEmbeddedDocumentScripts() ); 364 Reference< XLibraryContainer > xContainer; 365 if ( xScripts.is() ) 366 xContainer.set( xScripts->getBasicLibraries(), UNO_QUERY_THROW ); 367 bHasMacroLib = containerHasBasicMacros( xContainer ); 368 369 } 370 catch( const Exception& ) 371 { 372 DBG_UNHANDLED_EXCEPTION("sfx.doc"); 373 } 374 #endif 375 return bHasMacroLib; 376 } 377 378 storageHasMacros(const Reference<XStorage> & rxStorage)379 bool DocumentMacroMode::storageHasMacros( const Reference< XStorage >& rxStorage ) 380 { 381 bool bHasMacros = false; 382 if ( rxStorage.is() ) 383 { 384 try 385 { 386 const OUString s_sBasicStorageName( OUString::intern( RTL_CONSTASCII_USTRINGPARAM( "Basic" ) ) ); 387 const OUString s_sScriptsStorageName( OUString::intern( RTL_CONSTASCII_USTRINGPARAM( "Scripts" ) ) ); 388 389 bHasMacros =( ( rxStorage->hasByName( s_sBasicStorageName ) 390 && rxStorage->isStorageElement( s_sBasicStorageName ) 391 ) 392 || ( rxStorage->hasByName( s_sScriptsStorageName ) 393 && rxStorage->isStorageElement( s_sScriptsStorageName ) 394 ) 395 ); 396 } 397 catch ( const Exception& ) 398 { 399 DBG_UNHANDLED_EXCEPTION("sfx.doc"); 400 } 401 } 402 return bHasMacros; 403 } 404 405 checkMacrosOnLoading(const Reference<XInteractionHandler> & rxInteraction,bool bHasValidContentSignature)406 bool DocumentMacroMode::checkMacrosOnLoading( const Reference< XInteractionHandler >& rxInteraction, bool bHasValidContentSignature ) 407 { 408 bool bAllow = false; 409 if ( SvtSecurityOptions().IsMacroDisabled() ) 410 { 411 // no macro should be executed at all 412 bAllow = disallowMacroExecution(); 413 } 414 else 415 { 416 if (m_xData->m_rDocumentAccess.documentStorageHasMacros() || hasMacroLibrary() || m_xData->m_rDocumentAccess.macroCallsSeenWhileLoading()) 417 { 418 bAllow = adjustMacroMode( rxInteraction, bHasValidContentSignature ); 419 } 420 else if ( !isMacroExecutionDisallowed() ) 421 { 422 // if macros will be added by the user later, the security check is obsolete 423 bAllow = allowMacroExecution(); 424 } 425 } 426 return bAllow; 427 } 428 429 430 } // namespace sfx2 431 432 433 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 434