summaryrefslogtreecommitdiff
path: root/stoc/source/security/access_controller.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'stoc/source/security/access_controller.cxx')
-rw-r--r--stoc/source/security/access_controller.cxx1066
1 files changed, 1066 insertions, 0 deletions
diff --git a/stoc/source/security/access_controller.cxx b/stoc/source/security/access_controller.cxx
new file mode 100644
index 000000000000..a63510deeb39
--- /dev/null
+++ b/stoc/source/security/access_controller.cxx
@@ -0,0 +1,1066 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_stoc.hxx"
+
+#include <vector>
+#include <memory>
+
+#include <osl/diagnose.h>
+#include <osl/interlck.h>
+#include <osl/mutex.hxx>
+#include <osl/thread.hxx>
+
+#include <rtl/ustrbuf.hxx>
+#include <rtl/string.hxx>
+
+#include <uno/current_context.h>
+
+#include <cppuhelper/implbase1.hxx>
+#include <cppuhelper/compbase3.hxx>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/implementationentry.hxx>
+
+#include <com/sun/star/uno/XCurrentContext.hpp>
+#include <com/sun/star/uno/DeploymentException.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/security/XAccessController.hpp>
+#include <com/sun/star/security/XPolicy.hpp>
+
+#include "lru_cache.h"
+#include "permissions.h"
+#include "bootstrapservices.hxx"
+
+
+#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
+#define SERVICE_NAME "com.sun.star.security.AccessController"
+#define IMPL_NAME "com.sun.star.security.comp.stoc.AccessController"
+#define USER_CREDS "access-control.user-credentials"
+
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::rtl::OString;
+
+extern ::rtl_StandardModuleCount g_moduleCount;
+
+namespace stoc_sec
+{
+// static stuff initialized when loading lib
+static OUString s_envType = OUSTR(CPPU_CURRENT_LANGUAGE_BINDING_NAME);
+static OUString s_acRestriction = OUSTR("access-control.restriction");
+
+//##################################################################################################
+
+/** ac context intersects permissions of two ac contexts
+*/
+class acc_Intersection
+ : public WeakImplHelper1< security::XAccessControlContext >
+{
+ Reference< security::XAccessControlContext > m_x1, m_x2;
+
+ inline acc_Intersection(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 )
+ SAL_THROW( () );
+
+public:
+ virtual ~acc_Intersection()
+ SAL_THROW( () );
+
+ static inline Reference< security::XAccessControlContext > create(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 )
+ SAL_THROW( () );
+
+ // XAccessControlContext impl
+ virtual void SAL_CALL checkPermission(
+ Any const & perm )
+ throw (RuntimeException);
+};
+//__________________________________________________________________________________________________
+inline acc_Intersection::acc_Intersection(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 )
+ SAL_THROW( () )
+ : m_x1( x1 )
+ , m_x2( x2 )
+{
+ g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
+}
+//__________________________________________________________________________________________________
+acc_Intersection::~acc_Intersection()
+ SAL_THROW( () )
+{
+ g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
+}
+//--------------------------------------------------------------------------------------------------
+inline Reference< security::XAccessControlContext > acc_Intersection::create(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 )
+ SAL_THROW( () )
+{
+ if (! x1.is())
+ return x2;
+ if (! x2.is())
+ return x1;
+ return new acc_Intersection( x1, x2 );
+}
+//__________________________________________________________________________________________________
+void acc_Intersection::checkPermission(
+ Any const & perm )
+ throw (RuntimeException)
+{
+ m_x1->checkPermission( perm );
+ m_x2->checkPermission( perm );
+}
+
+/** ac context unifies permissions of two ac contexts
+*/
+class acc_Union
+ : public WeakImplHelper1< security::XAccessControlContext >
+{
+ Reference< security::XAccessControlContext > m_x1, m_x2;
+
+ inline acc_Union(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 )
+ SAL_THROW( () );
+
+public:
+ virtual ~acc_Union()
+ SAL_THROW( () );
+
+ static inline Reference< security::XAccessControlContext > create(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 )
+ SAL_THROW( () );
+
+ // XAccessControlContext impl
+ virtual void SAL_CALL checkPermission(
+ Any const & perm )
+ throw (RuntimeException);
+};
+//__________________________________________________________________________________________________
+inline acc_Union::acc_Union(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 )
+ SAL_THROW( () )
+ : m_x1( x1 )
+ , m_x2( x2 )
+{
+ g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
+}
+//__________________________________________________________________________________________________
+acc_Union::~acc_Union()
+ SAL_THROW( () )
+{
+ g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
+}
+//--------------------------------------------------------------------------------------------------
+inline Reference< security::XAccessControlContext > acc_Union::create(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 )
+ SAL_THROW( () )
+{
+ if (! x1.is())
+ return Reference< security::XAccessControlContext >(); // unrestricted
+ if (! x2.is())
+ return Reference< security::XAccessControlContext >(); // unrestricted
+ return new acc_Union( x1, x2 );
+}
+//__________________________________________________________________________________________________
+void acc_Union::checkPermission(
+ Any const & perm )
+ throw (RuntimeException)
+{
+ try
+ {
+ m_x1->checkPermission( perm );
+ }
+ catch (security::AccessControlException &)
+ {
+ m_x2->checkPermission( perm );
+ }
+}
+
+/** ac context doing permission checks on static permissions
+*/
+class acc_Policy
+ : public WeakImplHelper1< security::XAccessControlContext >
+{
+ PermissionCollection m_permissions;
+
+public:
+ inline acc_Policy(
+ PermissionCollection const & permissions )
+ SAL_THROW( () );
+ virtual ~acc_Policy()
+ SAL_THROW( () );
+
+ // XAccessControlContext impl
+ virtual void SAL_CALL checkPermission(
+ Any const & perm )
+ throw (RuntimeException);
+};
+//__________________________________________________________________________________________________
+inline acc_Policy::acc_Policy(
+ PermissionCollection const & permissions )
+ SAL_THROW( () )
+ : m_permissions( permissions )
+{
+ g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
+}
+//__________________________________________________________________________________________________
+acc_Policy::~acc_Policy()
+ SAL_THROW( () )
+{
+ g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
+}
+//__________________________________________________________________________________________________
+void acc_Policy::checkPermission(
+ Any const & perm )
+ throw (RuntimeException)
+{
+ m_permissions.checkPermission( perm );
+}
+
+/** current context overriding dynamic ac restriction
+*/
+class acc_CurrentContext
+ : public ImplHelper1< XCurrentContext >
+{
+ oslInterlockedCount m_refcount;
+
+ Reference< XCurrentContext > m_xDelegate;
+ Any m_restriction;
+
+public:
+ inline acc_CurrentContext(
+ Reference< XCurrentContext > const & xDelegate,
+ Reference< security::XAccessControlContext > const & xRestriction )
+ SAL_THROW( () );
+ virtual ~acc_CurrentContext() SAL_THROW( () );
+
+ // XInterface impl
+ virtual void SAL_CALL acquire()
+ throw ();
+ virtual void SAL_CALL release()
+ throw ();
+
+ // XCurrentContext impl
+ virtual Any SAL_CALL getValueByName( OUString const & name )
+ throw (RuntimeException);
+};
+//__________________________________________________________________________________________________
+inline acc_CurrentContext::acc_CurrentContext(
+ Reference< XCurrentContext > const & xDelegate,
+ Reference< security::XAccessControlContext > const & xRestriction )
+ SAL_THROW( () )
+ : m_refcount( 0 )
+ , m_xDelegate( xDelegate )
+{
+ g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
+
+ if (xRestriction.is())
+ {
+ m_restriction = makeAny( xRestriction );
+ }
+ // return empty any otherwise on getValueByName(), not null interface
+}
+//__________________________________________________________________________________________________
+acc_CurrentContext::~acc_CurrentContext()
+ SAL_THROW( () )
+{
+ g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
+}
+//__________________________________________________________________________________________________
+void acc_CurrentContext::acquire()
+ throw ()
+{
+ ::osl_incrementInterlockedCount( &m_refcount );
+}
+//__________________________________________________________________________________________________
+void acc_CurrentContext::release()
+ throw ()
+{
+ if (! ::osl_decrementInterlockedCount( &m_refcount ))
+ {
+ delete this;
+ }
+}
+//__________________________________________________________________________________________________
+Any acc_CurrentContext::getValueByName( OUString const & name )
+ throw (RuntimeException)
+{
+ if (name.equals( s_acRestriction ))
+ {
+ return m_restriction;
+ }
+ else if (m_xDelegate.is())
+ {
+ return m_xDelegate->getValueByName( name );
+ }
+ else
+ {
+ return Any();
+ }
+}
+
+//##################################################################################################
+
+//--------------------------------------------------------------------------------------------------
+static inline void dispose( Reference< XInterface > const & x )
+ SAL_THROW( (RuntimeException) )
+{
+ Reference< lang::XComponent > xComp( x, UNO_QUERY );
+ if (xComp.is())
+ {
+ xComp->dispose();
+ }
+}
+//--------------------------------------------------------------------------------------------------
+static inline Reference< security::XAccessControlContext > getDynamicRestriction(
+ Reference< XCurrentContext > const & xContext )
+ SAL_THROW( (RuntimeException) )
+{
+ if (xContext.is())
+ {
+ Any acc( xContext->getValueByName( s_acRestriction ) );
+ if (typelib_TypeClass_INTERFACE == acc.pType->eTypeClass)
+ {
+ // avoid ref-counting
+ OUString const & typeName =
+ *reinterpret_cast< OUString const * >( &acc.pType->pTypeName );
+ if (typeName.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM("com.sun.star.security.XAccessControlContext") ))
+ {
+ return Reference< security::XAccessControlContext >(
+ *reinterpret_cast< security::XAccessControlContext ** const >( acc.pData ) );
+ }
+ else // try to query
+ {
+ return Reference< security::XAccessControlContext >::query(
+ *reinterpret_cast< XInterface ** const >( acc.pData ) );
+ }
+ }
+ }
+ return Reference< security::XAccessControlContext >();
+}
+//==================================================================================================
+class cc_reset
+{
+ void * m_cc;
+public:
+ inline cc_reset( void * cc ) SAL_THROW( () )
+ : m_cc( cc ) {}
+ inline ~cc_reset() SAL_THROW( () )
+ { ::uno_setCurrentContext( m_cc, s_envType.pData, 0 ); }
+};
+
+//##################################################################################################
+
+struct MutexHolder
+{
+ Mutex m_mutex;
+};
+typedef WeakComponentImplHelper3<
+ security::XAccessController, lang::XServiceInfo, lang::XInitialization > t_helper;
+
+//==================================================================================================
+class AccessController
+ : public MutexHolder
+ , public t_helper
+{
+ Reference< XComponentContext > m_xComponentContext;
+
+ Reference< security::XPolicy > m_xPolicy;
+ Reference< security::XPolicy > const & getPolicy()
+ SAL_THROW( (RuntimeException) );
+
+ // mode
+ enum Mode { OFF, ON, DYNAMIC_ONLY, SINGLE_USER, SINGLE_DEFAULT_USER } m_mode;
+
+ PermissionCollection m_defaultPermissions;
+ // for single-user mode
+ PermissionCollection m_singleUserPermissions;
+ OUString m_singleUserId;
+ bool m_defaultPerm_init;
+ bool m_singleUser_init;
+ // for multi-user mode
+ lru_cache< OUString, PermissionCollection, ::rtl::OUStringHash, equal_to< OUString > >
+ m_user2permissions;
+
+ ThreadData m_rec;
+ typedef vector< pair< OUString, Any > > t_rec_vec;
+ inline void clearPostPoned() SAL_THROW( () );
+ void checkAndClearPostPoned() SAL_THROW( (RuntimeException) );
+
+ PermissionCollection getEffectivePermissions(
+ Reference< XCurrentContext > const & xContext,
+ Any const & demanded_perm )
+ SAL_THROW( (RuntimeException) );
+
+protected:
+ virtual void SAL_CALL disposing();
+
+public:
+ AccessController( Reference< XComponentContext > const & xComponentContext )
+ SAL_THROW( (RuntimeException) );
+ virtual ~AccessController()
+ SAL_THROW( () );
+
+ // XInitialization impl
+ virtual void SAL_CALL initialize(
+ Sequence< Any > const & arguments )
+ throw (Exception);
+
+ // XAccessController impl
+ virtual void SAL_CALL checkPermission(
+ Any const & perm )
+ throw (RuntimeException);
+ virtual Any SAL_CALL doRestricted(
+ Reference< security::XAction > const & xAction,
+ Reference< security::XAccessControlContext > const & xRestriction )
+ throw (Exception);
+ virtual Any SAL_CALL doPrivileged(
+ Reference< security::XAction > const & xAction,
+ Reference< security::XAccessControlContext > const & xRestriction )
+ throw (Exception);
+ virtual Reference< security::XAccessControlContext > SAL_CALL getContext()
+ throw (RuntimeException);
+
+ // XServiceInfo impl
+ virtual OUString SAL_CALL getImplementationName()
+ throw (RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName )
+ throw (RuntimeException);
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames()
+ throw (RuntimeException);
+};
+//__________________________________________________________________________________________________
+AccessController::AccessController( Reference< XComponentContext > const & xComponentContext )
+ SAL_THROW( (RuntimeException) )
+ : t_helper( m_mutex )
+ , m_xComponentContext( xComponentContext )
+ , m_mode( ON ) // default
+ , m_defaultPerm_init( false )
+ , m_singleUser_init( false )
+ , m_rec( 0 )
+{
+ g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
+
+ OUString mode;
+ if (m_xComponentContext->getValueByName( OUSTR("/services/" SERVICE_NAME "/mode") ) >>= mode)
+ {
+ if (mode.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("off") ))
+ {
+ m_mode = OFF;
+ }
+ else if (mode.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("on") ))
+ {
+ m_mode = ON;
+ }
+ else if (mode.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("dynamic-only") ))
+ {
+ m_mode = DYNAMIC_ONLY;
+ }
+ else if (mode.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("single-user") ))
+ {
+ m_xComponentContext->getValueByName(
+ OUSTR("/services/" SERVICE_NAME "/single-user-id") ) >>= m_singleUserId;
+ if (! m_singleUserId.getLength())
+ {
+ throw RuntimeException(
+ OUSTR("expected a user id in component context entry "
+ "\"/services/" SERVICE_NAME "/single-user-id\"!"),
+ (OWeakObject *)this );
+ }
+ m_mode = SINGLE_USER;
+ }
+ else if (mode.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("single-default-user") ))
+ {
+ m_mode = SINGLE_DEFAULT_USER;
+ }
+ }
+
+ // switch on caching for DYNAMIC_ONLY and ON (sharable multi-user process)
+ if (ON == m_mode || DYNAMIC_ONLY == m_mode)
+ {
+ sal_Int32 cacheSize = 0; // multi-user cache size
+ if (! (m_xComponentContext->getValueByName(
+ OUSTR("/services/" SERVICE_NAME "/user-cache-size") ) >>= cacheSize))
+ {
+ cacheSize = 128; // reasonable default?
+ }
+#ifdef __CACHE_DIAGNOSE
+ cacheSize = 2;
+#endif
+ m_user2permissions.setSize( cacheSize );
+ }
+}
+//__________________________________________________________________________________________________
+AccessController::~AccessController()
+ SAL_THROW( () )
+{
+ g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
+}
+//__________________________________________________________________________________________________
+void AccessController::disposing()
+{
+ m_mode = OFF; // avoid checks from now on xxx todo review/ better DYNAMIC_ONLY?
+ m_xPolicy.clear();
+ m_xComponentContext.clear();
+}
+
+// XInitialization impl
+//__________________________________________________________________________________________________
+void AccessController::initialize(
+ Sequence< Any > const & arguments )
+ throw (Exception)
+{
+ // xxx todo: review for forking
+ // portal forking hack: re-initialize for another user-id
+ if (SINGLE_USER != m_mode) // only if in single-user mode
+ {
+ throw RuntimeException(
+ OUSTR("invalid call: ac must be in \"single-user\" mode!"), (OWeakObject *)this );
+ }
+ OUString userId;
+ arguments[ 0 ] >>= userId;
+ if (! userId.getLength())
+ {
+ throw RuntimeException(
+ OUSTR("expected a user-id as first argument!"), (OWeakObject *)this );
+ }
+ // assured that no sync is necessary: no check happens at this forking time
+ m_singleUserId = userId;
+ m_singleUser_init = false;
+}
+
+//__________________________________________________________________________________________________
+Reference< security::XPolicy > const & AccessController::getPolicy()
+ SAL_THROW( (RuntimeException) )
+{
+ // get policy singleton
+ if (! m_xPolicy.is())
+ {
+ Reference< security::XPolicy > xPolicy;
+ m_xComponentContext->getValueByName(
+ OUSTR("/singletons/com.sun.star.security.thePolicy") ) >>= xPolicy;
+ if (xPolicy.is())
+ {
+ MutexGuard guard( m_mutex );
+ if (! m_xPolicy.is())
+ {
+ m_xPolicy = xPolicy;
+ }
+ }
+ else
+ {
+ throw SecurityException(
+ OUSTR("cannot get policy singleton!"), (OWeakObject *)this );
+ }
+ }
+ return m_xPolicy;
+}
+
+#ifdef __DIAGNOSE
+static void dumpPermissions(
+ PermissionCollection const & collection, OUString const & userId = OUString() ) SAL_THROW( () )
+{
+ OUStringBuffer buf( 48 );
+ if (userId.getLength())
+ {
+ buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("> dumping permissions of user \"") );
+ buf.append( userId );
+ buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\":") );
+ }
+ else
+ {
+ buf.appendAscii(
+ RTL_CONSTASCII_STRINGPARAM("> dumping default permissions:") );
+ }
+ OString str( ::rtl::OUStringToOString( buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
+ OSL_TRACE( str.getStr() );
+ Sequence< OUString > permissions( collection.toStrings() );
+ OUString const * p = permissions.getConstArray();
+ for ( sal_Int32 nPos = 0; nPos < permissions.getLength(); ++nPos )
+ {
+ OString str( ::rtl::OUStringToOString( p[ nPos ], RTL_TEXTENCODING_ASCII_US ) );
+ OSL_TRACE( str.getStr() );
+ }
+ OSL_TRACE( "> permission dump done" );
+}
+#endif
+
+
+//__________________________________________________________________________________________________
+inline void AccessController::clearPostPoned() SAL_THROW( () )
+{
+ delete reinterpret_cast< t_rec_vec * >( m_rec.getData() );
+ m_rec.setData( 0 );
+}
+//__________________________________________________________________________________________________
+void AccessController::checkAndClearPostPoned() SAL_THROW( (RuntimeException) )
+{
+ // check postponed permissions
+ auto_ptr< t_rec_vec > rec( reinterpret_cast< t_rec_vec * >( m_rec.getData() ) );
+ m_rec.setData( 0 ); // takeover ownership
+ OSL_ASSERT( rec.get() );
+ if (rec.get())
+ {
+ t_rec_vec const & vec = *rec.get();
+ switch (m_mode)
+ {
+ case SINGLE_USER:
+ {
+ OSL_ASSERT( m_singleUser_init );
+ for ( size_t nPos = 0; nPos < vec.size(); ++nPos )
+ {
+ pair< OUString, Any > const & p = vec[ nPos ];
+ OSL_ASSERT( m_singleUserId.equals( p.first ) );
+ m_singleUserPermissions.checkPermission( p.second );
+ }
+ break;
+ }
+ case SINGLE_DEFAULT_USER:
+ {
+ OSL_ASSERT( m_defaultPerm_init );
+ for ( size_t nPos = 0; nPos < vec.size(); ++nPos )
+ {
+ pair< OUString, Any > const & p = vec[ nPos ];
+ OSL_ASSERT( !p.first.getLength() ); // default-user
+ m_defaultPermissions.checkPermission( p.second );
+ }
+ break;
+ }
+ case ON:
+ {
+ for ( size_t nPos = 0; nPos < vec.size(); ++nPos )
+ {
+ pair< OUString, Any > const & p = vec[ nPos ];
+ PermissionCollection const * pPermissions;
+ // lookup policy for user
+ {
+ MutexGuard guard( m_mutex );
+ pPermissions = m_user2permissions.lookup( p.first );
+ }
+ OSL_ASSERT( pPermissions );
+ if (pPermissions)
+ {
+ pPermissions->checkPermission( p.second );
+ }
+ }
+ break;
+ }
+ default:
+ OSL_ENSURE( 0, "### this should never be called in this ac mode!" );
+ break;
+ }
+ }
+}
+//__________________________________________________________________________________________________
+/** this is the only function calling the policy singleton and thus has to take care
+ of recurring calls!
+
+ @param demanded_perm (if not empty) is the demanded permission of a checkPermission() call
+ which will be postponed for recurring calls
+*/
+PermissionCollection AccessController::getEffectivePermissions(
+ Reference< XCurrentContext > const & xContext,
+ Any const & demanded_perm )
+ SAL_THROW( (RuntimeException) )
+{
+ OUString userId;
+
+ switch (m_mode)
+ {
+ case SINGLE_USER:
+ {
+ if (m_singleUser_init)
+ return m_singleUserPermissions;
+ userId = m_singleUserId;
+ break;
+ }
+ case SINGLE_DEFAULT_USER:
+ {
+ if (m_defaultPerm_init)
+ return m_defaultPermissions;
+ break;
+ }
+ case ON:
+ {
+ if (xContext.is())
+ {
+ xContext->getValueByName( OUSTR(USER_CREDS ".id") ) >>= userId;
+ }
+ if (! userId.getLength())
+ {
+ throw SecurityException(
+ OUSTR("cannot determine current user in multi-user ac!"), (OWeakObject *)this );
+ }
+
+ // lookup policy for user
+ MutexGuard guard( m_mutex );
+ PermissionCollection const * pPermissions = m_user2permissions.lookup( userId );
+ if (pPermissions)
+ return *pPermissions;
+ break;
+ }
+ default:
+ OSL_ENSURE( 0, "### this should never be called in this ac mode!" );
+ return PermissionCollection();
+ }
+
+ // call on policy
+ // iff this is a recurring call for the default user, then grant all permissions
+ t_rec_vec * rec = reinterpret_cast< t_rec_vec * >( m_rec.getData() );
+ if (rec) // tls entry exists => this is recursive call
+ {
+ if (demanded_perm.hasValue())
+ {
+ // enqueue
+ rec->push_back( pair< OUString, Any >( userId, demanded_perm ) );
+ }
+#ifdef __DIAGNOSE
+ OUStringBuffer buf( 48 );
+ buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("> info: recurring call of user \"") );
+ buf.append( userId );
+ buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"") );
+ OString str(
+ ::rtl::OUStringToOString( buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
+ OSL_TRACE( str.getStr() );
+#endif
+ return PermissionCollection( new AllPermission() );
+ }
+ else // no tls
+ {
+ rec = new t_rec_vec;
+ m_rec.setData( rec );
+ }
+
+ try // calls on API
+ {
+ // init default permissions
+ if (! m_defaultPerm_init)
+ {
+ PermissionCollection defaultPermissions(
+ getPolicy()->getDefaultPermissions() );
+ // assign
+ MutexGuard guard( m_mutex );
+ if (! m_defaultPerm_init)
+ {
+ m_defaultPermissions = defaultPermissions;
+ m_defaultPerm_init = true;
+ }
+#ifdef __DIAGNOSE
+ dumpPermissions( m_defaultPermissions );
+#endif
+ }
+
+ PermissionCollection ret;
+
+ // init user permissions
+ switch (m_mode)
+ {
+ case SINGLE_USER:
+ {
+ ret = PermissionCollection(
+ getPolicy()->getPermissions( userId ), m_defaultPermissions );
+ {
+ // assign
+ MutexGuard guard( m_mutex );
+ if (m_singleUser_init)
+ {
+ ret = m_singleUserPermissions;
+ }
+ else
+ {
+ m_singleUserPermissions = ret;
+ m_singleUser_init = true;
+ }
+ }
+#ifdef __DIAGNOSE
+ dumpPermissions( ret, userId );
+#endif
+ break;
+ }
+ case SINGLE_DEFAULT_USER:
+ {
+ ret = m_defaultPermissions;
+ break;
+ }
+ case ON:
+ {
+ ret = PermissionCollection(
+ getPolicy()->getPermissions( userId ), m_defaultPermissions );
+ {
+ // cache
+ MutexGuard guard( m_mutex );
+ m_user2permissions.set( userId, ret );
+ }
+#ifdef __DIAGNOSE
+ dumpPermissions( ret, userId );
+#endif
+ break;
+ }
+ default:
+ break;
+ }
+
+ // check postponed
+ checkAndClearPostPoned();
+ return ret;
+ }
+ catch (security::AccessControlException & exc) // wrapped into DeploymentException
+ {
+ clearPostPoned(); // safety: exception could have happened before checking postponed?
+ OUStringBuffer buf( 64 );
+ buf.appendAscii(
+ RTL_CONSTASCII_STRINGPARAM("deployment error (AccessControlException occured): ") );
+ buf.append( exc.Message );
+ throw DeploymentException( buf.makeStringAndClear(), exc.Context );
+ }
+ catch (RuntimeException &)
+ {
+ // dont check postponed, just cleanup
+ clearPostPoned();
+ delete reinterpret_cast< t_rec_vec * >( m_rec.getData() );
+ m_rec.setData( 0 );
+ throw;
+ }
+ catch (Exception &)
+ {
+ // check postponed permissions first
+ // => AccessControlExceptions are errors, user exceptions not!
+ checkAndClearPostPoned();
+ throw;
+ }
+ catch (...)
+ {
+ // dont check postponed, just cleanup
+ clearPostPoned();
+ throw;
+ }
+}
+
+// XAccessController impl
+//__________________________________________________________________________________________________
+void AccessController::checkPermission(
+ Any const & perm )
+ throw (RuntimeException)
+{
+ if (rBHelper.bDisposed)
+ {
+ throw lang::DisposedException(
+ OUSTR("checkPermission() call on disposed AccessController!"), (OWeakObject *)this );
+ }
+
+ if (OFF == m_mode)
+ return;
+
+ // first dynamic check of ac contexts
+ Reference< XCurrentContext > xContext;
+ ::uno_getCurrentContext( (void **)&xContext, s_envType.pData, 0 );
+ Reference< security::XAccessControlContext > xACC( getDynamicRestriction( xContext ) );
+ if (xACC.is())
+ {
+ xACC->checkPermission( perm );
+ }
+
+ if (DYNAMIC_ONLY == m_mode)
+ return;
+
+ // then static check
+ getEffectivePermissions( xContext, perm ).checkPermission( perm );
+}
+//__________________________________________________________________________________________________
+Any AccessController::doRestricted(
+ Reference< security::XAction > const & xAction,
+ Reference< security::XAccessControlContext > const & xRestriction )
+ throw (Exception)
+{
+ if (rBHelper.bDisposed)
+ {
+ throw lang::DisposedException(
+ OUSTR("doRestricted() call on disposed AccessController!"), (OWeakObject *)this );
+ }
+
+ if (OFF == m_mode) // optimize this way, because no dynamic check will be performed
+ return xAction->run();
+
+ if (xRestriction.is())
+ {
+ Reference< XCurrentContext > xContext;
+ ::uno_getCurrentContext( (void **)&xContext, s_envType.pData, 0 );
+
+ // override restriction
+ Reference< XCurrentContext > xNewContext(
+ new acc_CurrentContext( xContext, acc_Intersection::create(
+ xRestriction, getDynamicRestriction( xContext ) ) ) );
+ ::uno_setCurrentContext( xNewContext.get(), s_envType.pData, 0 );
+ cc_reset reset( xContext.get() );
+ return xAction->run();
+ }
+ else
+ {
+ return xAction->run();
+ }
+}
+//__________________________________________________________________________________________________
+Any AccessController::doPrivileged(
+ Reference< security::XAction > const & xAction,
+ Reference< security::XAccessControlContext > const & xRestriction )
+ throw (Exception)
+{
+ if (rBHelper.bDisposed)
+ {
+ throw lang::DisposedException(
+ OUSTR("doPrivileged() call on disposed AccessController!"), (OWeakObject *)this );
+ }
+
+ if (OFF == m_mode) // no dynamic check will be performed
+ {
+ return xAction->run();
+ }
+
+ Reference< XCurrentContext > xContext;
+ ::uno_getCurrentContext( (void **)&xContext, s_envType.pData, 0 );
+
+ Reference< security::XAccessControlContext > xOldRestr(
+ getDynamicRestriction( xContext ) );
+
+ if (xOldRestr.is()) // previous restriction
+ {
+ // override restriction
+ Reference< XCurrentContext > xNewContext(
+ new acc_CurrentContext( xContext, acc_Union::create( xRestriction, xOldRestr ) ) );
+ ::uno_setCurrentContext( xNewContext.get(), s_envType.pData, 0 );
+ cc_reset reset( xContext.get() );
+ return xAction->run();
+ }
+ else // no previous restriction => never current restriction
+ {
+ return xAction->run();
+ }
+}
+//__________________________________________________________________________________________________
+Reference< security::XAccessControlContext > AccessController::getContext()
+ throw (RuntimeException)
+{
+ if (rBHelper.bDisposed)
+ {
+ throw lang::DisposedException(
+ OUSTR("getContext() call on disposed AccessController!"), (OWeakObject *)this );
+ }
+
+ if (OFF == m_mode) // optimize this way, because no dynamic check will be performed
+ {
+ return new acc_Policy( PermissionCollection( new AllPermission() ) );
+ }
+
+ Reference< XCurrentContext > xContext;
+ ::uno_getCurrentContext( (void **)&xContext, s_envType.pData, 0 );
+
+ return acc_Intersection::create(
+ getDynamicRestriction( xContext ),
+ new acc_Policy( getEffectivePermissions( xContext, Any() ) ) );
+}
+
+// XServiceInfo impl
+//__________________________________________________________________________________________________
+OUString AccessController::getImplementationName()
+ throw (RuntimeException)
+{
+ return stoc_bootstrap::ac_getImplementationName();
+}
+//__________________________________________________________________________________________________
+sal_Bool AccessController::supportsService( OUString const & serviceName )
+ throw (RuntimeException)
+{
+ Sequence< OUString > aSNL = getSupportedServiceNames();
+ const OUString * pNames = aSNL.getConstArray();
+ for ( sal_Int32 nPos = aSNL.getLength(); --nPos; )
+ {
+ if (serviceName.equals( pNames[ nPos ] ))
+ {
+ return sal_True;
+ }
+ }
+ return sal_False;
+}
+//__________________________________________________________________________________________________
+Sequence< OUString > AccessController::getSupportedServiceNames()
+ throw (RuntimeException)
+{
+ return stoc_bootstrap::ac_getSupportedServiceNames();
+}
+}
+//##################################################################################################
+namespace stoc_bootstrap {
+//--------------------------------------------------------------------------------------------------
+Reference< XInterface > SAL_CALL ac_create(
+ Reference< XComponentContext > const & xComponentContext )
+ SAL_THROW( (Exception) )
+{
+ return (OWeakObject *)new stoc_sec::AccessController( xComponentContext );
+}
+//--------------------------------------------------------------------------------------------------
+Sequence< OUString > ac_getSupportedServiceNames() SAL_THROW( () )
+{
+ static OUString s_serviceName = OUSTR(SERVICE_NAME);
+ static Sequence< OUString > s_serviceNames = Sequence< OUString >( &s_serviceName, 1 );
+ return s_serviceNames;
+}
+//--------------------------------------------------------------------------------------------------
+OUString ac_getImplementationName() SAL_THROW( () )
+{
+ static OUString s_implName = OUSTR(IMPL_NAME);
+ return s_implName;
+}
+//--------------------------------------------------------------------------------------------------
+Reference< XInterface > SAL_CALL filepolicy_create(
+ Reference< XComponentContext > const & xComponentContext )
+ SAL_THROW( (Exception) );
+//--------------------------------------------------------------------------------------------------
+Sequence< OUString > filepolicy_getSupportedServiceNames() SAL_THROW( () );
+//--------------------------------------------------------------------------------------------------
+OUString filepolicy_getImplementationName() SAL_THROW( () );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */