Most of the constructors are supposed to be only a call of new TheInstance(arguments) or an equivalent; so let's just change the constructor caller accordingly, to accept unacquired new instance. If there are exceptions that need to do more heavy lifting, they do not have to use the constructor feature, or there can be a wrapper for the real implementation, doing the additional work in their (C++) constructor. Change-Id: I035c378778aeda60d15af4e56ca3761c586d5ded
991 lines
32 KiB
C++
991 lines
32 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
|
|
#include <vector>
|
|
#include <memory>
|
|
|
|
#include <osl/diagnose.h>
|
|
#include <osl/interlck.h>
|
|
#include <osl/mutex.hxx>
|
|
#include <osl/thread.hxx>
|
|
|
|
#include <rtl/ref.hxx>
|
|
#include <rtl/ustrbuf.hxx>
|
|
|
|
#include <uno/current_context.h>
|
|
#include <uno/lbnames.h>
|
|
|
|
#include <cppuhelper/implbase1.hxx>
|
|
#include <cppuhelper/compbase3.hxx>
|
|
#include <cppuhelper/implementationentry.hxx>
|
|
#include <cppuhelper/supportsservice.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"
|
|
|
|
|
|
#define SERVICE_NAME "com.sun.star.security.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 namespace stoc_sec;
|
|
|
|
namespace {
|
|
|
|
// static stuff initialized when loading lib
|
|
static OUString s_envType = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
|
|
const char s_acRestriction[] = "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 )
|
|
{}
|
|
//__________________________________________________________________________________________________
|
|
acc_Intersection::~acc_Intersection()
|
|
SAL_THROW(())
|
|
{}
|
|
//--------------------------------------------------------------------------------------------------
|
|
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 )
|
|
{}
|
|
//__________________________________________________________________________________________________
|
|
acc_Union::~acc_Union()
|
|
SAL_THROW(())
|
|
{}
|
|
//--------------------------------------------------------------------------------------------------
|
|
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 )
|
|
{}
|
|
//__________________________________________________________________________________________________
|
|
acc_Policy::~acc_Policy()
|
|
SAL_THROW(())
|
|
{}
|
|
//__________________________________________________________________________________________________
|
|
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 )
|
|
{
|
|
if (xRestriction.is())
|
|
{
|
|
m_restriction = makeAny( xRestriction );
|
|
}
|
|
// return empty any otherwise on getValueByName(), not null interface
|
|
}
|
|
//__________________________________________________________________________________________________
|
|
acc_CurrentContext::~acc_CurrentContext()
|
|
SAL_THROW(())
|
|
{}
|
|
//__________________________________________________________________________________________________
|
|
void acc_CurrentContext::acquire()
|
|
throw ()
|
|
{
|
|
osl_atomic_increment( &m_refcount );
|
|
}
|
|
//__________________________________________________________________________________________________
|
|
void acc_CurrentContext::release()
|
|
throw ()
|
|
{
|
|
if (! osl_atomic_decrement( &m_refcount ))
|
|
{
|
|
delete this;
|
|
}
|
|
}
|
|
//__________________________________________________________________________________________________
|
|
Any acc_CurrentContext::getValueByName( OUString const & name )
|
|
throw (RuntimeException)
|
|
{
|
|
if (name.startsWith(s_acRestriction))
|
|
{
|
|
return m_restriction;
|
|
}
|
|
else if (m_xDelegate.is())
|
|
{
|
|
return m_xDelegate->getValueByName( name );
|
|
}
|
|
else
|
|
{
|
|
return Any();
|
|
}
|
|
}
|
|
|
|
//##################################################################################################
|
|
|
|
static inline Reference< security::XAccessControlContext > getDynamicRestriction(
|
|
Reference< XCurrentContext > const & xContext )
|
|
SAL_THROW( (RuntimeException) )
|
|
{
|
|
if (xContext.is())
|
|
{
|
|
Any acc(xContext->getValueByName(OUString(s_acRestriction)));
|
|
if (typelib_TypeClass_INTERFACE == acc.pType->eTypeClass)
|
|
{
|
|
// avoid ref-counting
|
|
OUString const & typeName =
|
|
*reinterpret_cast< OUString const * >( &acc.pType->pTypeName );
|
|
if ( typeName == "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, 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 )
|
|
{
|
|
// The .../mode value had originally been set in
|
|
// cppu::add_access_control_entries (cppuhelper/source/servicefactory.cxx)
|
|
// to something other than "off" depending on various UNO_AC* bootstrap
|
|
// variables that are no longer supported, so this is mostly dead code now:
|
|
OUString mode;
|
|
if (m_xComponentContext->getValueByName( "/services/" SERVICE_NAME "/mode" ) >>= mode)
|
|
{
|
|
if ( mode == "off" )
|
|
{
|
|
m_mode = OFF;
|
|
}
|
|
else if ( mode == "on" )
|
|
{
|
|
m_mode = ON;
|
|
}
|
|
else if ( mode == "dynamic-only" )
|
|
{
|
|
m_mode = DYNAMIC_ONLY;
|
|
}
|
|
else if ( mode == "single-user" )
|
|
{
|
|
m_xComponentContext->getValueByName(
|
|
"/services/" SERVICE_NAME "/single-user-id" ) >>= m_singleUserId;
|
|
if (m_singleUserId.isEmpty())
|
|
{
|
|
throw RuntimeException(
|
|
"expected a user id in component context entry "
|
|
"\"/services/" SERVICE_NAME "/single-user-id\"!",
|
|
(OWeakObject *)this );
|
|
}
|
|
m_mode = SINGLE_USER;
|
|
}
|
|
else if ( mode == "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(
|
|
"/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(())
|
|
{}
|
|
//__________________________________________________________________________________________________
|
|
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(
|
|
"invalid call: ac must be in \"single-user\" mode!", (OWeakObject *)this );
|
|
}
|
|
OUString userId;
|
|
arguments[ 0 ] >>= userId;
|
|
if ( userId.isEmpty() )
|
|
{
|
|
throw RuntimeException(
|
|
"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(
|
|
"/singletons/com.sun.star.security.thePolicy" ) >>= xPolicy;
|
|
if (xPolicy.is())
|
|
{
|
|
MutexGuard guard( m_mutex );
|
|
if (! m_xPolicy.is())
|
|
{
|
|
m_xPolicy = xPolicy;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw SecurityException(
|
|
"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.isEmpty())
|
|
{
|
|
buf.append( "> dumping permissions of user \"" );
|
|
buf.append( userId );
|
|
buf.append( "\":" );
|
|
}
|
|
else
|
|
{
|
|
buf.append( "> dumping default permissions:" );
|
|
}
|
|
OString str( OUStringToOString( buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
|
|
OSL_TRACE( "%s", str.getStr() );
|
|
Sequence< OUString > permissions( collection.toStrings() );
|
|
OUString const * p = permissions.getConstArray();
|
|
for ( sal_Int32 nPos = 0; nPos < permissions.getLength(); ++nPos )
|
|
{
|
|
OString str( OUStringToOString( p[ nPos ], RTL_TEXTENCODING_ASCII_US ) );
|
|
OSL_TRACE( "%s", 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.isEmpty() ); // 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_FAIL( "### 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( USER_CREDS ".id" ) >>= userId;
|
|
}
|
|
if ( userId.isEmpty() )
|
|
{
|
|
throw SecurityException(
|
|
"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_FAIL( "### 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.append( "> info: recurring call of user \"" );
|
|
buf.append( userId );
|
|
buf.append( "\"" );
|
|
OString str(
|
|
OUStringToOString( buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
|
|
OSL_TRACE( "%s", 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 (const security::AccessControlException & exc) // wrapped into DeploymentException
|
|
{
|
|
clearPostPoned(); // safety: exception could have happened before checking postponed?
|
|
OUStringBuffer buf( 64 );
|
|
buf.append( "deployment error (AccessControlException occurred): " );
|
|
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(
|
|
"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(
|
|
"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(
|
|
"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(
|
|
"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 OUString("com.sun.star.security.comp.stoc.AccessController");
|
|
}
|
|
//__________________________________________________________________________________________________
|
|
sal_Bool AccessController::supportsService( OUString const & serviceName )
|
|
throw (RuntimeException)
|
|
{
|
|
return cppu::supportsService(this, serviceName);
|
|
}
|
|
//__________________________________________________________________________________________________
|
|
Sequence< OUString > AccessController::getSupportedServiceNames()
|
|
throw (RuntimeException)
|
|
{
|
|
Sequence< OUString > aSNS( 1 );
|
|
aSNS[0] = OUString(SERVICE_NAME);
|
|
return aSNS;
|
|
}
|
|
|
|
}
|
|
|
|
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
|
|
com_sun_star_security_comp_stoc_AccessController_get_implementation(
|
|
css::uno::XComponentContext *context,
|
|
css::uno::Sequence<css::uno::Any> const &)
|
|
{
|
|
return static_cast<cppu::OWeakObject *>(new AccessController(context));
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|