xref: /trunk/main/scripting/source/storage/ScriptSecurityManager.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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_scripting.hxx"
26 
27 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
28 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
29 #include <com/sun/star/lang/XComponent.hpp>
30 #include <com/sun/star/lang/WrappedTargetException.hpp>
31 #include <com/sun/star/beans/XPropertySet.hpp>
32 #include <com/sun/star/beans/PropertyValue.hpp>
33 #include <com/sun/star/beans/UnknownPropertyException.hpp>
34 #include <com/sun/star/container/XNameReplace.hpp>
35 #include <com/sun/star/util/XChangesBatch.hpp>
36 #include <com/sun/star/util/XMacroExpander.hpp>
37 #include <com/sun/star/util/XStringSubstitution.hpp>
38 #include <com/sun/star/awt/XDialog.hpp>
39 #include <com/sun/star/security/AccessControlException.hpp>
40 #include <com/sun/star/security/RuntimePermission.hpp>
41 #include <drafts/com/sun/star/script/framework/storage/XScriptStorageManager.hpp>
42 #include <drafts/com/sun/star/script/framework/storage/XScriptInfoAccess.hpp>
43 #include "ScriptSecurityManager.hxx"
44 #include <util/util.hxx>
45 #include <util/scriptingconstants.hxx>
46 #include <tools/diagnose_ex.h>
47 
48 using namespace ::rtl;
49 using namespace ::osl;
50 using namespace ::com::sun::star;
51 using namespace ::com::sun::star::uno;
52 using namespace ::drafts::com::sun::star::script::framework;
53 
54 // is this in the utils?
55 const char* const SCRIPTSTORAGEMANAGER_SERVICE =
56     "/singletons/drafts.com.sun.star.script.framework.storage.theScriptStorageManager";
57 
58 namespace scripting_securitymgr
59 {
60 
61 static OUString s_configProv = ::rtl::OUString::createFromAscii(
62     "com.sun.star.configuration.ConfigurationProvider");
63 
64 static OUString s_configAccess = ::rtl::OUString::createFromAscii(
65     "com.sun.star.configuration.ConfigurationAccess");
66 
67 static OUString s_configUpdate = ::rtl::OUString::createFromAscii(
68     "com.sun.star.configuration.ConfigurationUpdateAccess");
69 
70 static OUString s_securityDialog = ::rtl::OUString::createFromAscii(
71     "com.sun.star.script.framework.security.SecurityDialog");
72 
73 static const int PERMISSION_NEVER = 0;
74 static const int PERMISSION_PATHLIST = 1;
75 static const int PERMISSION_ALWAYS = 2;
76 
77 static const int ALLOW_RUN = 1;
78 static const int ADD_TO_PATH = 2;
79 
80 //*************************************************************************
81 // ScriptSecurityManager Constructor
ScriptSecurityManager(const Reference<XComponentContext> & xContext)82 ScriptSecurityManager::ScriptSecurityManager(
83     const Reference< XComponentContext > & xContext )
84     : m_xContext( xContext, UNO_SET_THROW )
85 {
86     OSL_TRACE( "< ScriptSecurityManager ctor called >\n" );
87 
88     // get the service manager from the context
89     Reference< lang::XMultiComponentFactory > xMgr( m_xContext->getServiceManager(), UNO_SET_THROW );
90 
91     // create an instance of the ConfigurationProvider
92     m_xConfigProvFactory.set( xMgr->createInstanceWithContext( s_configProv, m_xContext ), UNO_QUERY_THROW );
93 }
94 
addScriptStorage(rtl::OUString scriptStorageURL,sal_Int32 storageID)95 void ScriptSecurityManager::addScriptStorage( rtl::OUString scriptStorageURL,
96     sal_Int32 storageID)
97 {
98     Permission_Hash::const_iterator ph_it = m_permissionSettings.find( scriptStorageURL );
99     if ( ph_it != m_permissionSettings.end() )
100     {
101         OSL_TRACE( "ScriptSecurityManager::addScriptStorage: already called for %s",
102             ::rtl::OUStringToOString( scriptStorageURL,
103                 RTL_TEXTENCODING_ASCII_US ).pData->buffer);
104         return;
105     }
106     StoragePerm newPerm;
107     newPerm.scriptStorageURL=scriptStorageURL;
108     newPerm.storageID=storageID;
109 
110     // we err on the side of caution!!
111     newPerm.execPermission=sal_False;
112 
113     //need to check if storage has any scripts
114     try
115     {
116         // we have some scripts so read config & decide on that basis
117         // Setup flags: m_runMacroSetting, m_warning, m_confirmationRequired,
118         readConfiguration();
119     }
120     catch ( RuntimeException & rte )
121     {
122         OSL_TRACE( "ScriptSecurityManager::addScriptStorage: caught RuntimeException: %s",
123             ::rtl::OUStringToOString( rte.Message,
124                 RTL_TEXTENCODING_ASCII_US ).pData->buffer);
125         throw RuntimeException(
126             OUSTR( "ScriptSecurityManager::addScriptStorage: caught RuntimeException" ).concat( rte.Message ),
127         Reference< XInterface >() );
128     }
129 
130     switch( m_runMacroSetting )
131     {
132         case PERMISSION_NEVER:         // never
133         {
134             OSL_TRACE("never run");
135             break;
136         }
137         case PERMISSION_PATHLIST:         // according to path list
138         {
139             OSL_TRACE("according to path");
140             // check path
141             rtl::OUString path = scriptStorageURL.copy( 0, scriptStorageURL.lastIndexOf( '/' ) );
142             OSL_TRACE( "no of elts in path list = %d",
143                 (int)m_secureURL.getLength() );
144             bool match = isSecureURL( path );
145             if( match &&  ( m_warning == sal_True ) )
146             {
147                 OSL_TRACE("path match & warning dialog");
148                 int result = (int)executeStandardDialog();
149                 OSL_TRACE("result = %d", (int)result);
150                 if ( (result&ALLOW_RUN) == ALLOW_RUN )
151                 {
152                     newPerm.execPermission=sal_True;
153                 }
154                 break;
155             }
156             else if ( match )
157             {
158                 OSL_TRACE("path match & no warning dialog");
159                 newPerm.execPermission=sal_True;
160                 break;
161             }
162             else if( m_confirmationRequired == sal_True )
163             {
164                 OSL_TRACE("no path match & confirmation dialog");
165                 int result = (int)executePathDialog( path );
166                 OSL_TRACE("result = %d", (int)result);
167                 if ( (result&ALLOW_RUN) == ALLOW_RUN )
168                 {
169                     newPerm.execPermission=sal_True;
170                 }
171                 if ( (result&ADD_TO_PATH) == ADD_TO_PATH )
172                 {
173                     /* if checkbox clicked then need to add path to registry*/
174                     addToSecurePaths(path);
175                 }
176             }
177             break;
178         }
179         case PERMISSION_ALWAYS:         // always
180             if( m_warning == sal_True )
181             {
182                 OSL_TRACE("always & warning dialog");
183                 short result = executeStandardDialog();
184                 if ( (result&ALLOW_RUN) == ALLOW_RUN )
185                 {
186                     newPerm.execPermission=sal_True;
187                 }
188             }
189             else
190             {
191                 OSL_TRACE("always & no warning dialog");
192                 newPerm.execPermission=sal_True;
193             }
194             break;
195         default:
196                 //
197                 throw RuntimeException(
198                     OUSTR( "ScriptSecurityManager::addScriptStorage got invalid OfficeBasic setting"),
199                     Reference< XInterface > ());
200     }
201 
202     if ( newPerm.execPermission == sal_True )
203     {
204         OSL_TRACE("setting exec permission to true for %s",
205             ::rtl::OUStringToOString( scriptStorageURL,
206                 RTL_TEXTENCODING_ASCII_US ).pData->buffer );
207     }
208     else
209     {
210         OSL_TRACE("setting exec permission to false for %s",
211             ::rtl::OUStringToOString( scriptStorageURL,
212                 RTL_TEXTENCODING_ASCII_US ).pData->buffer );
213     }
214 
215     m_permissionSettings[ scriptStorageURL ] = newPerm;
216 }
217 
isSecureURL(const OUString & path)218 bool ScriptSecurityManager::isSecureURL( const OUString & path )
219 {
220     bool match = false;
221     OSL_TRACE( "no of elts in path list = %d",
222         (int)m_secureURL.getLength() );
223     OSL_TRACE("document path: %s",
224         ::rtl::OUStringToOString( path,
225             RTL_TEXTENCODING_ASCII_US ).pData->buffer);
226     int length = m_secureURL.getLength();
227     for( int j = 0; j < length ; j++ )
228     {
229         OSL_TRACE("path list element: %s",
230             ::rtl::OUStringToOString( m_secureURL[j],
231                 RTL_TEXTENCODING_ASCII_US ).pData->buffer);
232 #ifdef WIN32
233         OSL_TRACE("case insensitive comparison");
234         if( path.equalsIgnoreAsciiCase( m_secureURL[j] ) )
235 #else
236         OSL_TRACE("case sensitive comparison");
237         if( path.equals( m_secureURL[j] ) )
238 #endif
239         {
240             match = true;
241             break;
242         }
243     }
244     return match;
245 }
246 
executeStandardDialog()247 short ScriptSecurityManager::executeStandardDialog()
248 {
249     OUString dummyString;
250     return executeDialog( dummyString );
251 }
252 
executePathDialog(const OUString & path)253 short ScriptSecurityManager::executePathDialog( const OUString & path )
254 {
255     return executeDialog( path );
256 }
257 
executeDialog(const OUString & path)258 short ScriptSecurityManager::executeDialog( const OUString & path )
259 {
260     Sequence < Any > aArgs;
261     if( path.getLength() != 0 )
262     {
263         OSL_TRACE("reallocing");
264         aArgs.realloc(1);
265         aArgs[ 0 ] <<= path;
266     }
267     short result;
268     try
269     {
270         Reference< lang::XMultiComponentFactory > xMgr( m_xContext->getServiceManager(), UNO_SET_THROW );
271         Reference< awt::XDialog > xDialog(
272             xMgr->createInstanceWithArgumentsAndContext( s_securityDialog, aArgs, m_xContext ),
273             UNO_QUERY_THROW );
274         result = xDialog->execute();
275         Reference< lang::XComponent > xComponent( xDialog, UNO_QUERY_THROW );
276         xComponent->dispose();
277     }
278     catch ( RuntimeException & rte )
279     {
280         throw RuntimeException(
281             OUSTR( "ScriptSecurityManager::executeDialog: caught RuntimeException: ").concat( rte.Message ),
282             Reference< XInterface > ());
283     }
284     catch ( Exception & e )
285     {
286         throw RuntimeException(
287             OUSTR( "ScriptSecurityManager::executeDialog: caught Exception: ").concat( e.Message ),
288             Reference< XInterface > ());
289     }
290     return result;
291 }
292 
293 /**
294  * checks to see whether the requested ScriptPermission is allowed.
295  * This was modelled after the Java AccessController, but at this time
296  * we can't see a good reason not to return a bool, rather than throw
297  * an exception if the request is not granted (as is the case in Java).
298  */
checkPermission(const OUString & scriptStorageURL,const OUString & permissionRequest)299 void ScriptSecurityManager::checkPermission( const OUString & scriptStorageURL,
300     const OUString & permissionRequest )
301 {
302     if( permissionRequest.equals( OUString::createFromAscii( "execute" ) ) )
303     {
304         OSL_TRACE(
305             "ScriptSecurityManager::checkPermission: execute permission request for %s",
306             ::rtl::OUStringToOString( scriptStorageURL,
307                 RTL_TEXTENCODING_ASCII_US ).pData->buffer);
308         Permission_Hash::const_iterator ph_it = m_permissionSettings.find( scriptStorageURL );
309         Permission_Hash::const_iterator ph_itend =
310             m_permissionSettings.end();
311         if ( ph_it != ph_itend )
312         {
313             if ( ph_it->second.execPermission )
314             {
315                 return;
316             }
317             else
318             {
319                 OSL_TRACE( "permission refused" );
320                 Any aPermission;
321                 security::RuntimePermission permission;
322                 permission.Name = OUString::createFromAscii( "execute" ).concat( scriptStorageURL );
323                 aPermission <<= permission;
324                 throw security::AccessControlException(
325                     OUString::createFromAscii( "ScriptSecurityManager::checkPermission: no execute permission for URL" ).concat( scriptStorageURL ),
326                     Reference< XInterface > (), aPermission );
327             }
328         }
329         // we should never get here!!
330         throw lang::IllegalArgumentException( OUString::createFromAscii( "ScriptSecurityManager::checkPermission: storageURL not found" ), Reference< XInterface > (), 0 );
331     }
332     // inappropriate permission request
333     throw lang::IllegalArgumentException( OUString::createFromAscii( "ScriptSecurityManager::checkPermission: storageURL not found" ), Reference< XInterface > (), 1 );
334 }
335 
removePermissionSettings(::rtl::OUString & scriptStorageURL)336 void ScriptSecurityManager::removePermissionSettings ( ::rtl::OUString & scriptStorageURL )
337 {
338     Permission_Hash::const_iterator ph_it =
339         m_permissionSettings.find( scriptStorageURL );
340 
341     if ( ph_it == m_permissionSettings.end() )
342     {
343         OSL_TRACE( "Entry for storage url %s doesn't exist in map",
344             ::rtl::OUStringToOString( scriptStorageURL,
345                 RTL_TEXTENCODING_ASCII_US ).pData->buffer);
346         return;
347     }
348 
349     // erase the entry from the hash
350     m_permissionSettings.erase( scriptStorageURL );
351 
352 }
353 
readConfiguration()354 void ScriptSecurityManager::readConfiguration()
355 {
356     try
357     {
358         beans::PropertyValue configPath;
359         configPath.Name = ::rtl::OUString::createFromAscii( "nodepath" );
360         configPath.Value <<= ::rtl::OUString::createFromAscii( "org.openoffice.Office.Common/Security/Scripting" );
361         Sequence < Any > aargs( 1 );
362         aargs[ 0 ] <<= configPath;
363         ENSURE_OR_THROW( m_xConfigProvFactory.is(),
364             "ScriptSecurityManager::readConfiguration: ConfigProviderFactory no longer valid!" );
365         // get the XPropertySet interface from the ConfigurationAccess service
366         Reference < beans::XPropertySet > xPropSet( m_xConfigProvFactory->createInstanceWithArguments( s_configAccess, aargs ), UNO_QUERY_THROW );
367 
368         m_confirmationRequired = sal_True;
369         OSL_VERIFY( xPropSet->getPropertyValue( OUSTR( "Confirmation" ) ) >>= m_confirmationRequired );
370         if ( m_confirmationRequired == sal_True )
371         {
372             OSL_TRACE( "ScriptSecurityManager:readConfiguration: confirmation is true" );
373         }
374         else
375         {
376             OSL_TRACE( "ScriptSecurityManager:readConfiguration: confirmation is false" );
377         }
378 
379         m_warning = true;
380         OSL_VERIFY( xPropSet->getPropertyValue( OUSTR( "Warning" ) ) >>= m_warning );
381 
382         if ( m_warning == sal_True )
383         {
384             OSL_TRACE( "ScriptSecurityManager:readConfiguration: warning is true" );
385         }
386         else
387         {
388             OSL_TRACE( "ScriptSecurityManager:readConfiguration: warning is false" );
389         }
390 
391         m_runMacroSetting = sal_True;
392         OSL_VERIFY( xPropSet->getPropertyValue( OUSTR( "OfficeBasic" ) ) >>= m_runMacroSetting );
393         OSL_TRACE( "ScriptSecurityManager:readConfiguration: OfficeBasic = %d", m_runMacroSetting );
394 
395         m_secureURL = ::rtl::OUString();
396         OSL_VERIFY( xPropSet->getPropertyValue( OUSTR( "SecureURL" ) ) >>= m_secureURL );
397     }
398     catch ( beans::UnknownPropertyException & upe )
399     {
400         throw RuntimeException(
401             OUSTR( "ScriptSecurityManager:readConfiguration: Attempt to read unknown property: " ).concat( upe.Message ),
402             Reference< XInterface > () );
403     }
404     catch ( lang::WrappedTargetException & wte )
405     {
406         throw RuntimeException(
407             OUSTR( "ScriptSecurityManager:readConfiguration: wrapped target exception? :" ).concat( wte.Message ),
408             Reference< XInterface > () );
409     }
410     catch ( Exception & e )
411     {
412         OSL_TRACE( "Unknown exception in readconf: %s",
413             ::rtl::OUStringToOString(e.Message ,
414             RTL_TEXTENCODING_ASCII_US ).pData->buffer  );
415         throw RuntimeException(
416             OUSTR( "ScriptSecurityManager:readConfiguration: exception? :" ).concat( e.Message ),
417             Reference< XInterface > () );
418     }
419 #ifdef _DEBUG
420     catch ( ... )
421     {
422         OSL_TRACE( "Completely Unknown exception in readconf!!!!!!");
423         throw RuntimeException(
424             OUSTR( "ScriptSecurityManager:readConfiguration: exception? :" ),
425             Reference< XInterface > () );
426     }
427 #endif
428 
429     int length = m_secureURL.getLength();
430 
431     // PathSubstitution needed to interpret variables found in config
432     Reference< lang::XMultiComponentFactory > xMgr( m_xContext->getServiceManager(), UNO_SET_THROW );
433     Reference< XInterface > xInterface = );
434     Reference< util::XStringSubstitution > xStringSubstitution(
435         xMgr->createInstanceWithContext(
436             ::rtl::OUString::createFromAscii( "com.sun.star.util.PathSubstitution" ), m_xContext
437         ),
438         UNO_QUERY_THROW
439     );
440     for( int i = 0; i < length; i++ )
441     {
442         OSL_TRACE( "ScriptSecurityManager:readConfiguration path = %s",
443             ::rtl::OUStringToOString(m_secureURL[i] ,
444             RTL_TEXTENCODING_ASCII_US ).pData->buffer  );
445 
446         OSL_TRACE( "ScriptSecurityManager: subpath = %s",
447             ::rtl::OUStringToOString(
448             xStringSubstitution->substituteVariables( m_secureURL[i], true ),
449             RTL_TEXTENCODING_ASCII_US ).pData->buffer );
450         m_secureURL[i] = xStringSubstitution->substituteVariables( m_secureURL[i], true );
451     }
452 #ifdef _DEBUG
453     int length2 = m_secureURL.getLength();
454     for( int j = 0; j < length2 ; j++ )
455     {
456         OSL_TRACE( "ScriptSecurityManager: path = %s",
457             ::rtl::OUStringToOString(m_secureURL[j] ,
458             RTL_TEXTENCODING_ASCII_US ).pData->buffer  );
459     }
460 #endif
461 }
462 
addToSecurePaths(const OUString & path)463 void ScriptSecurityManager::addToSecurePaths( const OUString & path )
464 {
465     OSL_TRACE( "--->ScriptSecurityManager::addToSecurePaths" );
466     beans::PropertyValue configPath;
467     configPath.Name = ::rtl::OUString::createFromAscii( "nodepath" );
468     configPath.Value <<= ::rtl::OUString::createFromAscii( "org.openoffice.Office.Common/Security/Scripting" );
469     Sequence < Any > aargs( 1 );
470     aargs[ 0 ] <<= configPath;
471     Reference < container::XNameReplace > xNameReplace(
472         m_xConfigProvFactory->createInstanceWithArguments( s_configUpdate, aargs ), UNO_QUERY_THROW );
473     Reference < util::XChangesBatch > xChangesBatch( xNameReplace, UNO_QUERY_THROW );
474 
475     OSL_TRACE( "--->ScriptSecurityManager::addToSecurePaths: after if stuff" );
476     Reference < beans::XPropertySet > xPropSet( xInterface, UNO_QUERY );
477     css::uno::Sequence< rtl::OUString > newSecureURL;
478     Any value;
479     OUString pathListPropName = OUSTR ( "SecureURL" );
480     value=xPropSet->getPropertyValue( pathListPropName );
481     if ( sal_False == ( value >>= newSecureURL ) )
482     {
483         throw RuntimeException(
484             OUSTR( "ScriptSecurityManager::addToSecurePaths: can't get SecureURL setting" ),
485             Reference< XInterface > () );
486     }
487     try
488     {
489         sal_Int32 length = newSecureURL.getLength();
490         newSecureURL.realloc( length + 1 );
491         newSecureURL[ length ] = path;
492         Any aNewSecureURL;
493         aNewSecureURL <<= newSecureURL;
494         xNameReplace->replaceByName( pathListPropName, aNewSecureURL );
495         xChangesBatch->commitChanges();
496         m_secureURL = newSecureURL;
497     }
498     catch ( Exception & e )
499     {
500         OSL_TRACE( "Error updating secure paths: " );
501         throw RuntimeException(
502             OUSTR( "ScriptSecurityManager::addToSecurePaths: error updating SecureURL setting" ).concat( e.Message ),
503             Reference< XInterface > () );
504     }
505 }
506 
507 //*************************************************************************
508 // ScriptSecurityManager Destructor
~ScriptSecurityManager()509 ScriptSecurityManager::~ScriptSecurityManager()
510 {
511     OSL_TRACE( "< ScriptSecurityManager dtor called >\n" );
512 }
513 
514 } // Namespace
515