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