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