1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include "sfx2/docmacromode.hxx"
31 #include "sfx2/signaturestate.hxx"
32 #include "sfx2/docfile.hxx"
34 /** === begin UNO includes === **/
35 #include <com/sun/star/document/MacroExecMode.hpp>
36 #include <com/sun/star/task/ErrorCodeRequest.hpp>
37 #include <com/sun/star/task/DocumentMacroConfirmationRequest.hpp>
38 #include <com/sun/star/task/InteractionClassification.hpp>
39 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
40 #include <com/sun/star/script/XLibraryQueryExecutable.hpp>
41 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
42 /** === end UNO includes === **/
44 #include <comphelper/componentcontext.hxx>
45 #include <comphelper/processfactory.hxx>
46 #include <framework/interaction.hxx>
47 #include <osl/file.hxx>
48 #include <rtl/ref.hxx>
49 #include <unotools/securityoptions.hxx>
50 #include <svtools/sfxecode.hxx>
51 #include <tools/diagnose_ex.h>
52 #include <tools/urlobj.hxx>
54 //........................................................................
57 //........................................................................
59 /** === begin UNO using === **/
60 using ::com::sun::star::uno::Reference
;
61 using ::com::sun::star::task::XInteractionHandler
;
62 using ::com::sun::star::uno::Any
;
63 using ::com::sun::star::task::XInteractionHandler
;
64 using ::com::sun::star::uno::Sequence
;
65 using ::com::sun::star::task::XInteractionContinuation
;
66 using ::com::sun::star::task::XInteractionRequest
;
67 using ::com::sun::star::task::DocumentMacroConfirmationRequest
;
68 using ::com::sun::star::task::ErrorCodeRequest
;
69 using ::com::sun::star::uno::Exception
;
70 using ::com::sun::star::security::XDocumentDigitalSignatures
;
71 using ::com::sun::star::security::DocumentSignatureInformation
;
72 using ::com::sun::star::embed::XStorage
;
73 using ::com::sun::star::task::InteractionClassification_QUERY
;
74 using ::com::sun::star::document::XEmbeddedScripts
;
75 using ::com::sun::star::uno::UNO_SET_THROW
;
76 using ::com::sun::star::script::XLibraryContainer
;
77 using ::com::sun::star::script::XLibraryQueryExecutable
;
78 using ::com::sun::star::script::vba::XVBACompatibility
;
79 using ::com::sun::star::container::XNameAccess
;
80 using ::com::sun::star::uno::UNO_QUERY_THROW
;
81 using ::com::sun::star::uno::UNO_QUERY
;
82 /** === end UNO using === **/
83 namespace MacroExecMode
= ::com::sun::star::document::MacroExecMode
;
85 //====================================================================
86 //= DocumentMacroMode_Data
87 //====================================================================
88 struct DocumentMacroMode_Data
90 IMacroDocumentAccess
& m_rDocumentAccess
;
91 sal_Bool m_bMacroDisabledMessageShown
;
92 sal_Bool m_bDocMacroDisabledMessageShown
;
94 DocumentMacroMode_Data( IMacroDocumentAccess
& rDocumentAccess
)
95 :m_rDocumentAccess( rDocumentAccess
)
96 ,m_bMacroDisabledMessageShown( sal_False
)
97 ,m_bDocMacroDisabledMessageShown( sal_False
)
102 //====================================================================
104 //====================================================================
107 //................................................................
108 void lcl_showGeneralSfxErrorOnce( const Reference
< XInteractionHandler
>& rxHandler
, const sal_Int32 nSfxErrorCode
, sal_Bool
& rbAlreadyShown
)
110 if ( rbAlreadyShown
)
113 ErrorCodeRequest aErrorCodeRequest
;
114 aErrorCodeRequest
.ErrCode
= nSfxErrorCode
;
116 SfxMedium::CallApproveHandler( rxHandler
, makeAny( aErrorCodeRequest
), sal_False
);
117 rbAlreadyShown
= sal_True
;
120 //................................................................
121 void lcl_showMacrosDisabledError( const Reference
< XInteractionHandler
>& rxHandler
, sal_Bool
& rbAlreadyShown
)
123 lcl_showGeneralSfxErrorOnce( rxHandler
, ERRCODE_SFX_MACROS_SUPPORT_DISABLED
, rbAlreadyShown
);
126 //................................................................
127 void lcl_showDocumentMacrosDisabledError( const Reference
< XInteractionHandler
>& rxHandler
, sal_Bool
& rbAlreadyShown
)
130 lcl_showGeneralSfxErrorOnce( rxHandler
, ERRCODE_SFX_DOCUMENT_MACRO_DISABLED_MAC
, rbAlreadyShown
);
132 lcl_showGeneralSfxErrorOnce( rxHandler
, ERRCODE_SFX_DOCUMENT_MACRO_DISABLED
, rbAlreadyShown
);
136 //................................................................
137 sal_Bool
lcl_showMacroWarning( const Reference
< XInteractionHandler
>& rxHandler
,
138 const ::rtl::OUString
& rDocumentLocation
)
140 DocumentMacroConfirmationRequest aRequest
;
141 aRequest
.DocumentURL
= rDocumentLocation
;
142 return SfxMedium::CallApproveHandler( rxHandler
, makeAny( aRequest
), sal_True
);
146 //====================================================================
147 //= DocumentMacroMode
148 //====================================================================
149 //--------------------------------------------------------------------
150 DocumentMacroMode::DocumentMacroMode( IMacroDocumentAccess
& rDocumentAccess
)
151 :m_pData( new DocumentMacroMode_Data( rDocumentAccess
) )
155 //--------------------------------------------------------------------
156 DocumentMacroMode::~DocumentMacroMode()
160 //--------------------------------------------------------------------
161 sal_Bool
DocumentMacroMode::allowMacroExecution()
163 m_pData
->m_rDocumentAccess
.setCurrentMacroExecMode( MacroExecMode::ALWAYS_EXECUTE_NO_WARN
);
167 //--------------------------------------------------------------------
168 sal_Bool
DocumentMacroMode::disallowMacroExecution()
170 m_pData
->m_rDocumentAccess
.setCurrentMacroExecMode( MacroExecMode::NEVER_EXECUTE
);
174 //--------------------------------------------------------------------
175 sal_Bool
DocumentMacroMode::adjustMacroMode( const Reference
< XInteractionHandler
>& rxInteraction
)
177 sal_uInt16 nMacroExecutionMode
= m_pData
->m_rDocumentAccess
.getCurrentMacroExecMode();
179 if ( SvtSecurityOptions().IsMacroDisabled() )
181 // no macro should be executed at all
182 lcl_showMacrosDisabledError( rxInteraction
, m_pData
->m_bMacroDisabledMessageShown
);
183 return disallowMacroExecution();
186 // get setting from configuration if required
187 enum AutoConfirmation
193 AutoConfirmation
eAutoConfirm( eNoAutoConfirm
);
195 if ( ( nMacroExecutionMode
== MacroExecMode::USE_CONFIG
)
196 || ( nMacroExecutionMode
== MacroExecMode::USE_CONFIG_REJECT_CONFIRMATION
)
197 || ( nMacroExecutionMode
== MacroExecMode::USE_CONFIG_APPROVE_CONFIRMATION
)
200 SvtSecurityOptions aOpt
;
201 switch ( aOpt
.GetMacroSecurityLevel() )
204 nMacroExecutionMode
= MacroExecMode::FROM_LIST_NO_WARN
;
207 nMacroExecutionMode
= MacroExecMode::FROM_LIST_AND_SIGNED_WARN
;
210 nMacroExecutionMode
= MacroExecMode::ALWAYS_EXECUTE
;
213 nMacroExecutionMode
= MacroExecMode::ALWAYS_EXECUTE_NO_WARN
;
216 OSL_FAIL( "DocumentMacroMode::adjustMacroMode: unexpected macro security level!" );
217 nMacroExecutionMode
= MacroExecMode::NEVER_EXECUTE
;
220 if ( nMacroExecutionMode
== MacroExecMode::USE_CONFIG_REJECT_CONFIRMATION
)
221 eAutoConfirm
= eAutoConfirmReject
;
222 else if ( nMacroExecutionMode
== MacroExecMode::USE_CONFIG_APPROVE_CONFIRMATION
)
223 eAutoConfirm
= eAutoConfirmApprove
;
226 if ( nMacroExecutionMode
== MacroExecMode::NEVER_EXECUTE
)
229 if ( nMacroExecutionMode
== MacroExecMode::ALWAYS_EXECUTE_NO_WARN
)
234 ::rtl::OUString
sReferrer( m_pData
->m_rDocumentAccess
.getDocumentLocation() );
236 // get document location from medium name and check whether it is a trusted one
237 // the service is created ohne document version, since it is not of interest here
238 ::comphelper::ComponentContext
aContext( ::comphelper::getProcessServiceFactory() );
239 Reference
< XDocumentDigitalSignatures
> xSignatures
;
240 if ( aContext
.createComponent( "com.sun.star.security.DocumentDigitalSignatures", xSignatures
) )
242 INetURLObject
aURLReferer( sReferrer
);
244 ::rtl::OUString aLocation
;
245 if ( aURLReferer
.removeSegment() )
246 aLocation
= aURLReferer
.GetMainURL( INetURLObject::NO_DECODE
);
248 if ( !aLocation
.isEmpty() && xSignatures
->isLocationTrusted( aLocation
) )
250 return allowMacroExecution();
254 // at this point it is clear that the document is not in the secure location
255 if ( nMacroExecutionMode
== MacroExecMode::FROM_LIST_NO_WARN
)
257 lcl_showDocumentMacrosDisabledError( rxInteraction
, m_pData
->m_bDocMacroDisabledMessageShown
);
258 return disallowMacroExecution();
261 // check whether the document is signed with trusted certificate
262 if ( nMacroExecutionMode
!= MacroExecMode::FROM_LIST
)
264 // the trusted macro check will also retrieve the signature state ( small optimization )
265 sal_Bool bHasTrustedMacroSignature
= m_pData
->m_rDocumentAccess
.hasTrustedScriptingSignature( nMacroExecutionMode
!= MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN
);
267 sal_uInt16 nSignatureState
= m_pData
->m_rDocumentAccess
.getScriptingSignatureState();
268 if ( nSignatureState
== SIGNATURESTATE_SIGNATURES_BROKEN
)
270 // the signature is broken, no macro execution
271 if ( nMacroExecutionMode
!= MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN
)
272 m_pData
->m_rDocumentAccess
.showBrokenSignatureWarning( rxInteraction
);
274 return disallowMacroExecution();
276 else if ( bHasTrustedMacroSignature
)
278 // there is trusted macro signature, allow macro execution
279 return allowMacroExecution();
281 else if ( nSignatureState
== SIGNATURESTATE_SIGNATURES_OK
282 || nSignatureState
== SIGNATURESTATE_SIGNATURES_NOTVALIDATED
)
284 // there is valid signature, but it is not from the trusted author
285 return disallowMacroExecution();
289 // at this point it is clear that the document is neither in secure location nor signed with trusted certificate
290 if ( ( nMacroExecutionMode
== MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN
)
291 || ( nMacroExecutionMode
== MacroExecMode::FROM_LIST_AND_SIGNED_WARN
)
294 if ( nMacroExecutionMode
== MacroExecMode::FROM_LIST_AND_SIGNED_WARN
)
295 lcl_showDocumentMacrosDisabledError( rxInteraction
, m_pData
->m_bDocMacroDisabledMessageShown
);
297 return disallowMacroExecution();
300 catch ( const Exception
& )
302 if ( ( nMacroExecutionMode
== MacroExecMode::FROM_LIST_NO_WARN
)
303 || ( nMacroExecutionMode
== MacroExecMode::FROM_LIST_AND_SIGNED_WARN
)
304 || ( nMacroExecutionMode
== MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN
)
307 return disallowMacroExecution();
311 // conformation is required
312 sal_Bool bSecure
= sal_False
;
314 if ( eAutoConfirm
== eNoAutoConfirm
)
316 ::rtl::OUString
sReferrer( m_pData
->m_rDocumentAccess
.getDocumentLocation() );
318 ::rtl::OUString aSystemFileURL
;
319 if ( osl::FileBase::getSystemPathFromFileURL( sReferrer
, aSystemFileURL
) == osl::FileBase::E_None
)
320 sReferrer
= aSystemFileURL
;
322 bSecure
= lcl_showMacroWarning( rxInteraction
, sReferrer
);
325 bSecure
= ( eAutoConfirm
== eAutoConfirmApprove
);
327 return ( bSecure
? allowMacroExecution() : disallowMacroExecution() );
330 //--------------------------------------------------------------------
331 sal_Bool
DocumentMacroMode::isMacroExecutionDisallowed() const
333 return m_pData
->m_rDocumentAccess
.getCurrentMacroExecMode() == MacroExecMode::NEVER_EXECUTE
;
336 //--------------------------------------------------------------------
337 sal_Bool
DocumentMacroMode::hasMacroLibrary() const
339 sal_Bool bHasMacroLib
= sal_False
;
340 #ifndef DISABLE_SCRIPTING
343 Reference
< XEmbeddedScripts
> xScripts( m_pData
->m_rDocumentAccess
.getEmbeddedDocumentScripts() );
344 Reference
< XLibraryContainer
> xContainer
;
346 xContainer
.set( xScripts
->getBasicLibraries(), UNO_QUERY_THROW
);
348 Reference
< XVBACompatibility
> xDocVBAMode( xContainer
, UNO_QUERY
);
349 sal_Bool bIsVBAMode
= ( xDocVBAMode
.is() && xDocVBAMode
->getVBACompatibilityMode() );
350 if ( xContainer
.is() )
352 // a library container exists; check if it's empty
354 // if there are libraries except the "Standard" library
355 // we assume that they are not empty (because they have been created by the user)
356 if ( !xContainer
->hasElements() )
357 bHasMacroLib
= sal_False
;
360 ::rtl::OUString
aStdLibName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) );
361 Sequence
< ::rtl::OUString
> aElements
= xContainer
->getElementNames();
362 sal_Int32 nElementCount
= aElements
.getLength();
365 // old check, if more than 1 library or the first library isn't the expected 'Standard'
366 // trigger the security 'nag' dialog
367 if ( !bIsVBAMode
&& ( nElementCount
> 1 || !aElements
[0].equals( aStdLibName
) ) )
368 bHasMacroLib
= sal_True
;
371 // other wise just check all libraries for executeable code
372 Reference
< XLibraryQueryExecutable
> xLib( xContainer
, UNO_QUERY
);
375 const ::rtl::OUString
* pElementName
= aElements
.getConstArray();
376 for ( sal_Int32 index
= 0; index
< nElementCount
; ++index
)
378 bHasMacroLib
= xLib
->HasExecutableCode( pElementName
[index
] );
387 if ( bIsVBAMode
&& !bHasMacroLib
&& xScripts
.is() )
389 Reference
< XLibraryContainer
> xDlgContainer( xScripts
->getDialogLibraries(), UNO_QUERY
);
390 if ( xDlgContainer
.is() && xDlgContainer
->hasElements() )
392 Sequence
< ::rtl::OUString
> aElements
= xDlgContainer
->getElementNames();
393 sal_Int32 nElementCount
= aElements
.getLength();
394 const ::rtl::OUString
* pElementName
= aElements
.getConstArray();
395 for ( sal_Int32 index
= 0; index
< nElementCount
; ++index
)
397 Reference
< XNameAccess
> xNameAccess
;
398 xDlgContainer
->getByName( pElementName
[index
] ) >>= xNameAccess
;
399 if ( xNameAccess
.is() && xNameAccess
->hasElements() )
401 bHasMacroLib
= sal_True
;
408 catch( const Exception
& )
410 DBG_UNHANDLED_EXCEPTION();
416 //--------------------------------------------------------------------
417 sal_Bool
DocumentMacroMode::storageHasMacros( const Reference
< XStorage
>& rxStorage
)
419 sal_Bool bHasMacros
= sal_False
;
420 if ( rxStorage
.is() )
424 static const ::rtl::OUString
s_sBasicStorageName( ::rtl::OUString::intern( RTL_CONSTASCII_USTRINGPARAM( "Basic" ) ) );
425 static const ::rtl::OUString
s_sScriptsStorageName( ::rtl::OUString::intern( RTL_CONSTASCII_USTRINGPARAM( "Scripts" ) ) );
427 bHasMacros
=( ( rxStorage
->hasByName( s_sBasicStorageName
)
428 && rxStorage
->isStorageElement( s_sBasicStorageName
)
430 || ( rxStorage
->hasByName( s_sScriptsStorageName
)
431 && rxStorage
->isStorageElement( s_sScriptsStorageName
)
435 catch ( const Exception
& )
437 DBG_UNHANDLED_EXCEPTION();
443 //--------------------------------------------------------------------
444 sal_Bool
DocumentMacroMode::checkMacrosOnLoading( const Reference
< XInteractionHandler
>& rxInteraction
)
446 sal_Bool bAllow
= sal_False
;
447 if ( SvtSecurityOptions().IsMacroDisabled() )
449 // no macro should be executed at all
450 bAllow
= disallowMacroExecution();
454 if ( m_pData
->m_rDocumentAccess
.documentStorageHasMacros() || hasMacroLibrary() )
456 bAllow
= adjustMacroMode( rxInteraction
);
458 else if ( !isMacroExecutionDisallowed() )
460 // if macros will be added by the user later, the security check is obsolete
461 bAllow
= allowMacroExecution();
467 //........................................................................
469 //........................................................................
471 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */