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