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