diff options
Diffstat (limited to 'stoc/source/security/access_controller.cxx')
-rw-r--r-- | stoc/source/security/access_controller.cxx | 1066 |
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: */ |