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