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