xref: /trunk/main/sfx2/source/doc/docmacromode.cxx (revision 4018d3b8)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sfx2.hxx"
26 
27 #include "sfx2/docmacromode.hxx"
28 #include "sfx2/signaturestate.hxx"
29 #include "sfx2/docfile.hxx"
30 
31 /** === begin UNO includes === **/
32 #include <com/sun/star/document/MacroExecMode.hpp>
33 #include <com/sun/star/task/ErrorCodeRequest.hpp>
34 #include <com/sun/star/task/DocumentMacroConfirmationRequest.hpp>
35 #include <com/sun/star/task/InteractionClassification.hpp>
36 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
37 /** === end UNO includes === **/
38 
39 #include <comphelper/componentcontext.hxx>
40 #include <comphelper/processfactory.hxx>
41 #include <framework/interaction.hxx>
42 #include <osl/file.hxx>
43 #include <rtl/ref.hxx>
44 #include <unotools/securityoptions.hxx>
45 #include <svtools/sfxecode.hxx>
46 #include <tools/diagnose_ex.h>
47 #include <tools/urlobj.hxx>
48 
49 //........................................................................
50 namespace sfx2
51 {
52 //........................................................................
53 
54 	/** === begin UNO using === **/
55     using ::com::sun::star::uno::Reference;
56     using ::com::sun::star::task::XInteractionHandler;
57     using ::com::sun::star::uno::Any;
58     using ::com::sun::star::task::XInteractionHandler;
59     using ::com::sun::star::uno::Sequence;
60     using ::com::sun::star::task::XInteractionContinuation;
61     using ::com::sun::star::task::XInteractionRequest;
62     using ::com::sun::star::task::DocumentMacroConfirmationRequest;
63     using ::com::sun::star::task::ErrorCodeRequest;
64     using ::com::sun::star::uno::Exception;
65     using ::com::sun::star::security::XDocumentDigitalSignatures;
66     using ::com::sun::star::security::DocumentSignatureInformation;
67     using ::com::sun::star::embed::XStorage;
68     using ::com::sun::star::task::InteractionClassification_QUERY;
69     using ::com::sun::star::document::XEmbeddedScripts;
70     using ::com::sun::star::uno::UNO_SET_THROW;
71     using ::com::sun::star::script::XLibraryContainer;
72     using ::com::sun::star::container::XNameAccess;
73     using ::com::sun::star::uno::UNO_QUERY_THROW;
74 	/** === end UNO using === **/
75     namespace MacroExecMode = ::com::sun::star::document::MacroExecMode;
76 
77 	//====================================================================
78 	//= DocumentMacroMode_Data
79 	//====================================================================
80     struct DocumentMacroMode_Data
81     {
82         IMacroDocumentAccess&       m_rDocumentAccess;
83         sal_Bool                    m_bMacroDisabledMessageShown;
84         sal_Bool                    m_bDocMacroDisabledMessageShown;
85 
DocumentMacroMode_Datasfx2::DocumentMacroMode_Data86         DocumentMacroMode_Data( IMacroDocumentAccess& rDocumentAccess )
87             :m_rDocumentAccess( rDocumentAccess )
88             ,m_bMacroDisabledMessageShown( sal_False )
89             ,m_bDocMacroDisabledMessageShown( sal_False )
90         {
91         }
92     };
93 
94 	//====================================================================
95 	//= helper
96 	//====================================================================
97     namespace
98     {
99         //................................................................
lcl_showGeneralSfxErrorOnce(const Reference<XInteractionHandler> & rxHandler,const sal_Int32 nSfxErrorCode,sal_Bool & rbAlreadyShown)100         void lcl_showGeneralSfxErrorOnce( const Reference< XInteractionHandler >& rxHandler, const sal_Int32 nSfxErrorCode, sal_Bool& rbAlreadyShown )
101         {
102             if ( rbAlreadyShown )
103                 return;
104 
105             ErrorCodeRequest aErrorCodeRequest;
106             aErrorCodeRequest.ErrCode = nSfxErrorCode;
107 
108             SfxMedium::CallApproveHandler( rxHandler, makeAny( aErrorCodeRequest ), sal_False );
109             rbAlreadyShown = sal_True;
110         }
111 
112 	    //................................................................
lcl_showMacrosDisabledError(const Reference<XInteractionHandler> & rxHandler,sal_Bool & rbAlreadyShown)113         void lcl_showMacrosDisabledError( const Reference< XInteractionHandler >& rxHandler, sal_Bool& rbAlreadyShown )
114         {
115             lcl_showGeneralSfxErrorOnce( rxHandler, ERRCODE_SFX_MACROS_SUPPORT_DISABLED, rbAlreadyShown );
116         }
117 
118         //................................................................
lcl_showDocumentMacrosDisabledError(const Reference<XInteractionHandler> & rxHandler,sal_Bool & rbAlreadyShown)119         void lcl_showDocumentMacrosDisabledError( const Reference< XInteractionHandler >& rxHandler, sal_Bool& rbAlreadyShown )
120         {
121             lcl_showGeneralSfxErrorOnce( rxHandler, ERRCODE_SFX_DOCUMENT_MACRO_DISABLED, rbAlreadyShown );
122         }
123 
124         //................................................................
lcl_showMacroWarning(const Reference<XInteractionHandler> & rxHandler,const::rtl::OUString & rDocumentLocation)125         sal_Bool lcl_showMacroWarning( const Reference< XInteractionHandler >& rxHandler,
126             const ::rtl::OUString& rDocumentLocation )
127         {
128             DocumentMacroConfirmationRequest aRequest;
129             aRequest.DocumentURL = rDocumentLocation;
130             return SfxMedium::CallApproveHandler( rxHandler, makeAny( aRequest ), sal_True );
131         }
132     }
133 
134 	//====================================================================
135 	//= DocumentMacroMode
136 	//====================================================================
137 	//--------------------------------------------------------------------
DocumentMacroMode(IMacroDocumentAccess & rDocumentAccess)138     DocumentMacroMode::DocumentMacroMode( IMacroDocumentAccess& rDocumentAccess )
139         :m_pData( new DocumentMacroMode_Data( rDocumentAccess ) )
140     {
141     }
142 
143 	//--------------------------------------------------------------------
~DocumentMacroMode()144     DocumentMacroMode::~DocumentMacroMode()
145     {
146     }
147 
148 	//--------------------------------------------------------------------
allowMacroExecution()149     sal_Bool DocumentMacroMode::allowMacroExecution()
150     {
151         m_pData->m_rDocumentAccess.setCurrentMacroExecMode( MacroExecMode::ALWAYS_EXECUTE_NO_WARN );
152         return sal_True;
153     }
154 
155 	//--------------------------------------------------------------------
disallowMacroExecution()156     sal_Bool DocumentMacroMode::disallowMacroExecution()
157     {
158         m_pData->m_rDocumentAccess.setCurrentMacroExecMode( MacroExecMode::NEVER_EXECUTE );
159         return sal_False;
160     }
161 
162     /** Change the indicated macro execution mode depending on the current macro security level.
163      *
164      * @param nMacroExecutionMode current execution mode (must be one of MacroExecMode::USE_XXX).
165      *
166      * Changes nMacroExecutionMode according to the current security options, if applicable.
167      */
adjustMacroExecModeSecurity(sal_uInt16 & nMacroExecutionMode)168     static void adjustMacroExecModeSecurity(sal_uInt16 &nMacroExecutionMode)
169     {
170         if  (   ( nMacroExecutionMode == MacroExecMode::USE_CONFIG )
171             ||  ( nMacroExecutionMode == MacroExecMode::USE_CONFIG_REJECT_CONFIRMATION )
172             ||  ( nMacroExecutionMode == MacroExecMode::USE_CONFIG_APPROVE_CONFIRMATION )
173             )
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_ENSURE( sal_False, "DocumentMacroMode::adjustMacroMode: unexpected macro security level!" );
192                     nMacroExecutionMode = MacroExecMode::NEVER_EXECUTE;
193             }
194 
195         }
196     }
197 
198 	//--------------------------------------------------------------------
adjustMacroMode(const Reference<XInteractionHandler> & rxInteraction)199     sal_Bool DocumentMacroMode::adjustMacroMode( const Reference< XInteractionHandler >& rxInteraction )
200     {
201         sal_uInt16 nMacroExecutionMode = m_pData->m_rDocumentAccess.getCurrentMacroExecMode();
202 
203         if ( SvtSecurityOptions().IsMacroDisabled() )
204         {
205             // no macro should be executed at all
206             lcl_showMacrosDisabledError( rxInteraction, m_pData->m_bMacroDisabledMessageShown );
207             return disallowMacroExecution();
208         }
209 
210         // get setting from configuration if required
211         enum AutoConfirmation
212         {
213             eNoAutoConfirm,
214             eAutoConfirmApprove,
215             eAutoConfirmReject
216         };
217         AutoConfirmation eAutoConfirm( eNoAutoConfirm );
218 
219         adjustMacroExecModeSecurity(nMacroExecutionMode);
220         if ( nMacroExecutionMode == MacroExecMode::USE_CONFIG_REJECT_CONFIRMATION )
221             eAutoConfirm = eAutoConfirmReject;
222         else if ( nMacroExecutionMode == MacroExecMode::USE_CONFIG_APPROVE_CONFIRMATION )
223             eAutoConfirm = eAutoConfirmApprove;
224 
225         if ( nMacroExecutionMode == MacroExecMode::NEVER_EXECUTE )
226             return sal_False;
227 
228         if ( nMacroExecutionMode == MacroExecMode::ALWAYS_EXECUTE_NO_WARN )
229             return sal_True;
230 
231         try
232         {
233             ::rtl::OUString sReferrer( m_pData->m_rDocumentAccess.getDocumentLocation() );
234 
235             // get document location from medium name and check whether it is a trusted one
236             // the service is created ohne document version, since it is not of interest here
237             ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() );
238             Reference< XDocumentDigitalSignatures > xSignatures;
239             if ( aContext.createComponent( "com.sun.star.security.DocumentDigitalSignatures", xSignatures ) )
240             {
241                 INetURLObject aURLReferer( sReferrer );
242 
243                 ::rtl::OUString aLocation;
244                 if ( aURLReferer.removeSegment() )
245                     aLocation = aURLReferer.GetMainURL( INetURLObject::NO_DECODE );
246 
247                 if ( aLocation.getLength() && xSignatures->isLocationTrusted( aLocation ) )
248                 {
249                     return allowMacroExecution();
250                 }
251             }
252 
253             // at this point it is clear that the document is not in the secure location
254             if ( nMacroExecutionMode == MacroExecMode::FROM_LIST_NO_WARN )
255             {
256                 lcl_showDocumentMacrosDisabledError( rxInteraction, m_pData->m_bDocMacroDisabledMessageShown );
257                 return disallowMacroExecution();
258             }
259 
260             // check whether the document is signed with trusted certificate
261             if ( nMacroExecutionMode != MacroExecMode::FROM_LIST )
262             {
263                 // the trusted macro check will also retrieve the signature state (small optimization)
264                 sal_Bool bHasTrustedMacroSignature = m_pData->m_rDocumentAccess.hasTrustedScriptingSignature( nMacroExecutionMode != MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN );
265 
266                 sal_uInt16 nSignatureState = m_pData->m_rDocumentAccess.getScriptingSignatureState();
267                 if ( nSignatureState == SIGNATURESTATE_SIGNATURES_BROKEN )
268                 {
269                     // the signature is broken, no macro execution
270                     if ( nMacroExecutionMode != MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN )
271                         m_pData->m_rDocumentAccess.showBrokenSignatureWarning( rxInteraction );
272 
273                     return disallowMacroExecution();
274                 }
275                 else if ( bHasTrustedMacroSignature )
276                 {
277                     // there is trusted macro signature, allow macro execution
278                     return allowMacroExecution();
279                 }
280                 else if ( nSignatureState == SIGNATURESTATE_SIGNATURES_OK
281                        || nSignatureState == SIGNATURESTATE_SIGNATURES_NOTVALIDATED )
282                 {
283                     // there is valid signature, but it is not from the trusted author
284                     return disallowMacroExecution();
285                 }
286             }
287 
288             // at this point it is clear that the document is neither in secure location nor signed with trusted certificate
289             if  (   ( nMacroExecutionMode == MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN )
290                 ||  ( nMacroExecutionMode == MacroExecMode::FROM_LIST_AND_SIGNED_WARN )
291                 )
292             {
293                 if  ( nMacroExecutionMode == MacroExecMode::FROM_LIST_AND_SIGNED_WARN )
294                     lcl_showDocumentMacrosDisabledError( rxInteraction, m_pData->m_bDocMacroDisabledMessageShown );
295 
296                 return disallowMacroExecution();
297             }
298         }
299         catch ( Exception& )
300         {
301             if  (   ( nMacroExecutionMode == MacroExecMode::FROM_LIST_NO_WARN )
302                 ||  ( nMacroExecutionMode == MacroExecMode::FROM_LIST_AND_SIGNED_WARN )
303                 ||  ( nMacroExecutionMode == MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN )
304                 )
305             {
306                 return disallowMacroExecution();
307             }
308         }
309 
310         // confirmation is required
311         sal_Bool bSecure = sal_False;
312 
313         if ( eAutoConfirm == eNoAutoConfirm )
314         {
315             ::rtl::OUString sReferrer( m_pData->m_rDocumentAccess.getDocumentLocation() );
316 
317             ::rtl::OUString aSystemFileURL;
318             if ( osl::FileBase::getSystemPathFromFileURL( sReferrer, aSystemFileURL ) == osl::FileBase::E_None )
319                 sReferrer = aSystemFileURL;
320 
321             bSecure = lcl_showMacroWarning( rxInteraction, sReferrer );
322         }
323         else
324             bSecure = ( eAutoConfirm == eAutoConfirmApprove );
325 
326         return ( bSecure ? allowMacroExecution() : disallowMacroExecution() );
327     }
328 
329 	//--------------------------------------------------------------------
isMacroExecutionDisallowed() const330     sal_Bool DocumentMacroMode::isMacroExecutionDisallowed() const
331     {
332         return m_pData->m_rDocumentAccess.getCurrentMacroExecMode() == MacroExecMode::NEVER_EXECUTE;
333     }
334 
335     //--------------------------------------------------------------------
hasMacroLibrary() const336     sal_Bool DocumentMacroMode::hasMacroLibrary() const
337     {
338         sal_Bool bHasMacroLib = sal_False;
339         try
340         {
341             Reference< XEmbeddedScripts > xScripts( m_pData->m_rDocumentAccess.getEmbeddedDocumentScripts() );
342             Reference< XLibraryContainer > xContainer;
343             if ( xScripts.is() )
344                 xContainer.set( xScripts->getBasicLibraries(), UNO_QUERY_THROW );
345 
346             if ( xContainer.is() )
347             {
348                 // a library container exists; check if it's empty
349 
350 			    // if there are libraries except the "Standard" library
351 			    // we assume that they are not empty (because they have been created by the user)
352 			    if ( !xContainer->hasElements() )
353                     bHasMacroLib = sal_False;
354                 else
355 			    {
356 				    ::rtl::OUString aStdLibName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) );
357 				    Sequence< ::rtl::OUString > aElements = xContainer->getElementNames();
358 				    if ( aElements.getLength() )
359 				    {
360 					    if ( aElements.getLength() > 1 || !aElements[0].equals( aStdLibName ) )
361 						    bHasMacroLib = sal_True;
362 					    else
363 					    {
364 						    // usually a "Standard" library is always present (design)
365 						    // for this reason we must check if it's empty
366                             //
367                             // Note: Since #i73229#, this is not true anymore. There's no default
368                             // "Standard" lib anymore. Wouldn't it be time to get completely
369                             // rid of the "Standard" thingie - this shouldn't be necessary
370                             // anymore, should it?
371                             // 2007-01-25 / frank.schoenheit@sun.com
372 						    Reference < XNameAccess > xLib;
373 						    Any aAny = xContainer->getByName( aStdLibName );
374 						    aAny >>= xLib;
375 						    if ( xLib.is() )
376 							    bHasMacroLib = xLib->hasElements();
377 					    }
378 				    }
379 			    }
380 		    }
381         }
382         catch( const Exception& )
383         {
384             DBG_UNHANDLED_EXCEPTION();
385         }
386 
387         return bHasMacroLib;
388     }
389 
390 	//--------------------------------------------------------------------
storageHasMacros(const Reference<XStorage> & rxStorage)391     sal_Bool DocumentMacroMode::storageHasMacros( const Reference< XStorage >& rxStorage )
392     {
393 	    sal_Bool bHasMacros = sal_False;
394 	    if ( rxStorage.is() )
395 	    {
396 		    try
397 		    {
398                 static const ::rtl::OUString s_sBasicStorageName( ::rtl::OUString::intern( RTL_CONSTASCII_USTRINGPARAM( "Basic" ) ) );
399                 static const ::rtl::OUString s_sScriptsStorageName( ::rtl::OUString::intern( RTL_CONSTASCII_USTRINGPARAM( "Scripts" ) ) );
400 
401                 bHasMacros =(   (   rxStorage->hasByName( s_sBasicStorageName )
402                                 &&  rxStorage->isStorageElement( s_sBasicStorageName )
403                                 )
404                             ||  (   rxStorage->hasByName( s_sScriptsStorageName )
405                                 &&  rxStorage->isStorageElement( s_sScriptsStorageName )
406                                 )
407                             );
408 		    }
409 		    catch ( const Exception& )
410 		    {
411 			    DBG_UNHANDLED_EXCEPTION();
412 		    }
413 	    }
414         return bHasMacros;
415     }
416 
417 	//--------------------------------------------------------------------
checkMacrosOnLoading(const Reference<XInteractionHandler> & rxInteraction)418     sal_Bool DocumentMacroMode::checkMacrosOnLoading( const Reference< XInteractionHandler >& rxInteraction )
419     {
420         sal_Bool bAllow = sal_False;
421         if ( SvtSecurityOptions().IsMacroDisabled() )
422         {
423             // no macro should be executed at all
424             bAllow = disallowMacroExecution();
425         }
426         else
427         {
428             if ( m_pData->m_rDocumentAccess.documentStorageHasMacros() || hasMacroLibrary() )
429             {
430                 bAllow = adjustMacroMode( rxInteraction );
431             }
432             else if ( !isMacroExecutionDisallowed() )
433             {
434                 // There are no macros (yet) but we want to be careful anyway
435                 sal_uInt16 nMacroExecutionMode = m_pData->m_rDocumentAccess.getCurrentMacroExecMode();
436                 adjustMacroExecModeSecurity(nMacroExecutionMode);
437                 switch (nMacroExecutionMode) {
438                 case MacroExecMode::NEVER_EXECUTE:
439                 case MacroExecMode::USE_CONFIG:
440                 case MacroExecMode::USE_CONFIG_REJECT_CONFIRMATION:
441                 case MacroExecMode::FROM_LIST_NO_WARN:
442                 case MacroExecMode::FROM_LIST_AND_SIGNED_WARN:
443                 case MacroExecMode::FROM_LIST_AND_SIGNED_NO_WARN:
444                     bAllow = sal_False;
445                     break;
446                 case MacroExecMode::FROM_LIST:
447                 case MacroExecMode::ALWAYS_EXECUTE:
448                 case MacroExecMode::ALWAYS_EXECUTE_NO_WARN:
449                 case MacroExecMode::USE_CONFIG_APPROVE_CONFIRMATION:
450                     bAllow = sal_True;
451                     break;
452                 }
453             }
454         }
455         return bAllow;
456     }
457 
458 //........................................................................
459 } // namespace sfx2
460 //........................................................................
461