Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/stoc/source/security/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 24 kB image not shown  

Quelle  access_controller.cxx   Sprache: 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 <utility>
#include <vector>

#include <osl/diagnose.h>
#include <osl/mutex.hxx>
#include <osl/thread.hxx>

#include <rtl/ustrbuf.hxx>
#include <sal/log.hxx>

#include <uno/current_context.h>
#include <uno/lbnames.h>

#include <cppuhelper/basemutex.hxx>
#include <cppuhelper/implbase.hxx>
#include <cppuhelper/compbase.hxx>
#include <cppuhelper/supportsservice.hxx>

#include <com/sun/star/uno/XCurrentContext.hpp>
#include <com/sun/star/uno/DeploymentException.hpp>
#include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/lang/DisposedException.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 <memory>

constexpr OUString SERVICE_NAME = u"com.sun.star.security.AccessController"_ustr;
constexpr OUStringLiteral USER_CREDS  = u"access-control.user-credentials.id";


using namespace ::osl;
using namespace ::cppu;
using namespace ::com::sun::star;
using namespace css::uno;
using namespace stoc_sec;

namespace {

// static stuff initialized when loading lib
OUString s_envType = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
constexpr OUString s_acRestriction = u"access-control.restriction"_ustr;


/** ac context intersects permissions of two ac contexts
*/

class acc_Intersection
    : public WeakImplHelper< security::XAccessControlContext >
{
    Reference< security::XAccessControlContext > m_x1, m_x2;

    acc_Intersection(
        Reference< security::XAccessControlContext > const & x1,
        Reference< security::XAccessControlContext > const & x2 );

public:
    static Reference< security::XAccessControlContext > create(
        Reference< security::XAccessControlContext > const & x1,
        Reference< security::XAccessControlContext > const & x2 );

    // XAccessControlContext impl
    virtual void SAL_CALL checkPermission(
        Any const & perm ) override;
};

acc_Intersection::acc_Intersection(
    Reference< security::XAccessControlContext > const & x1,
    Reference< security::XAccessControlContext > const & x2 )
    : m_x1( x1 )
    , m_x2( x2 )
{}

Reference< security::XAccessControlContext > acc_Intersection::create(
    Reference< security::XAccessControlContext > const & x1,
    Reference< security::XAccessControlContext > const & x2 )
{
    if (! x1.is())
        return x2;
    if (! x2.is())
        return x1;
    return new acc_Intersection( x1, x2 );
}

void acc_Intersection::checkPermission(
    Any const & perm )
{
    m_x1->checkPermission( perm );
    m_x2->checkPermission( perm );
}

/** ac context unifies permissions of two ac contexts
*/

class acc_Union
    : public WeakImplHelper< security::XAccessControlContext >
{
    Reference< security::XAccessControlContext > m_x1, m_x2;

    acc_Union(
        Reference< security::XAccessControlContext > const & x1,
        Reference< security::XAccessControlContext > const & x2 );

public:
    static Reference< security::XAccessControlContext > create(
        Reference< security::XAccessControlContext > const & x1,
        Reference< security::XAccessControlContext > const & x2 );

    // XAccessControlContext impl
    virtual void SAL_CALL checkPermission(
        Any const & perm ) override;
};

acc_Union::acc_Union(
    Reference< security::XAccessControlContext > const & x1,
    Reference< security::XAccessControlContext > const & x2 )
    : m_x1( x1 )
    , m_x2( x2 )
{}

Reference< security::XAccessControlContext > acc_Union::create(
    Reference< security::XAccessControlContext > const & x1,
    Reference< security::XAccessControlContext > const & x2 )
{
    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 )
{
    try
    {
        m_x1->checkPermission( perm );
    }
    catch (security::AccessControlException &)
    {
        m_x2->checkPermission( perm );
    }
}

/** ac context doing permission checks on static permissions
*/

class acc_Policy
    : public WeakImplHelper< security::XAccessControlContext >
{
    PermissionCollection m_permissions;

public:
    explicit acc_Policy(
        PermissionCollection permissions )
        : m_permissions(std::move( permissions ))
    {}

    // XAccessControlContext impl
    virtual void SAL_CALL checkPermission(
        Any const & perm ) override;
};

void acc_Policy::checkPermission(
    Any const & perm )
{
    m_permissions.checkPermission( perm );
}

/** current context overriding dynamic ac restriction
*/

class acc_CurrentContext
    : public WeakImplHelper< XCurrentContext >
{
    Reference< XCurrentContext > m_xDelegate;
    Any m_restriction;

public:
    acc_CurrentContext(
        Reference< XCurrentContext > const & xDelegate,
        Reference< security::XAccessControlContext > const & xRestriction );

    // XCurrentContext impl
    virtual Any SAL_CALL getValueByName( OUString const & name ) override;
};

acc_CurrentContext::acc_CurrentContext(
    Reference< XCurrentContext > const & xDelegate,
    Reference< security::XAccessControlContext > const & xRestriction )
    : m_xDelegate( xDelegate )
{
    if (xRestriction.is())
    {
        m_restriction <<= xRestriction;
    }
    // return empty any otherwise on getValueByName(), not null interface
}

Any acc_CurrentContext::getValueByName( OUString const & name )
{
    if (name == s_acRestriction)
    {
        return m_restriction;
    }
    else if (m_xDelegate.is())
    {
        return m_xDelegate->getValueByName( name );
    }
    else
    {
        return Any();
    }
}


Reference< security::XAccessControlContext > getDynamicRestriction(
    Reference< XCurrentContext > const & xContext )
{
    if (xContext.is())
    {
        Any acc(xContext->getValueByName(s_acRestriction));
        if (typelib_TypeClass_INTERFACE == acc.pType->eTypeClass)
        {
            // avoid ref-counting
            OUString const & typeName =
                OUString::unacquired( &acc.pType->pTypeName );
            if ( typeName == "com.sun.star.security.XAccessControlContext" )
            {
                return Reference< security::XAccessControlContext >(
                    *static_cast< security::XAccessControlContext ** >( acc.pData ) );
            }
            else // try to query
            {
                return Reference< security::XAccessControlContext >::query(
                    *static_cast< XInterface ** >( acc.pData ) );
            }
        }
    }
    return Reference< security::XAccessControlContext >();
}

class cc_reset
{
    void * m_cc;
public:
    explicit cc_reset( void * cc )
        : m_cc( cc ) {}
    ~cc_reset()
        { ::uno_setCurrentContext( m_cc, s_envType.pData, nullptr ); }
};

typedef WeakComponentImplHelper<
    security::XAccessController, lang::XServiceInfo, lang::XInitialization > t_helper;


class AccessController
    : public cppu::BaseMutex
    , public t_helper
{
    Reference< XComponentContext > m_xComponentContext;

    Reference< security::XPolicy > m_xPolicy;
    Reference< security::XPolicy > const & getPolicy();

    // mode
    enum class Mode { Off, On, DynamicOnly, SingleUser, SingleDefaultUser };
    Mode 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, std::equal_to< OUString > >
        m_user2permissions;

    ThreadData m_rec;
    typedef std::vector< std::pair< OUString, Any > > t_rec_vec;
    void clearPostPoned();
    void checkAndClearPostPoned();

    PermissionCollection getEffectivePermissions(
        Reference< XCurrentContext > const & xContext,
        Any const & demanded_perm );

protected:
    virtual void SAL_CALL disposing() override;

public:
    explicit AccessController( Reference< XComponentContext > const & xComponentContext );

    //  XInitialization impl
    virtual void SAL_CALL initialize(
        Sequence< Any > const & arguments ) override;

    // XAccessController impl
    virtual void SAL_CALL checkPermission(
        Any const & perm ) override;
    virtual Any SAL_CALL doRestricted(
        Reference< security::XAction > const & xAction,
        Reference< security::XAccessControlContext > const & xRestriction ) override;
    virtual Any SAL_CALL doPrivileged(
        Reference< security::XAction > const & xAction,
        Reference< security::XAccessControlContext > const & xRestriction ) override;
    virtual Reference< security::XAccessControlContext > SAL_CALL getContext() override;

    // XServiceInfo impl
    virtual OUString SAL_CALL getImplementationName() override;
    virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName ) override;
    virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
};

AccessController::AccessController( Reference< XComponentContext > const & xComponentContext )
    : t_helper( m_aMutex )
    , m_xComponentContext( xComponentContext )
    , m_mode( Mode::On ) // default
    , m_defaultPerm_init( false )
    , m_singleUser_init( false )
    , m_rec( nullptr )
{
    // 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 = Mode::Off;
        }
        else if ( mode == "on" )
        {
            m_mode = Mode::On;
        }
        else if ( mode == "dynamic-only" )
        {
            m_mode = Mode::DynamicOnly;
        }
        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\"!",
                    getXWeak() );
            }
            m_mode = Mode::SingleUser;
        }
        else if ( mode == "single-default-user" )
        {
            m_mode = Mode::SingleDefaultUser;
        }
    }

    // switch on caching for Mode::DynamicOnly and Mode::On (shareable multi-user process)
    if (Mode::On != m_mode && Mode::DynamicOnly != m_mode)
        return;

    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 );
}

void AccessController::disposing()
{
    m_mode = Mode::Off; // avoid checks from now on xxx todo review/ better Mode::DynamicOnly?
    m_xPolicy.clear();
    m_xComponentContext.clear();
}

// XInitialization impl

void AccessController::initialize(
    Sequence< Any > const & arguments )
{
    // xxx todo: review for forking
    // portal forking hack: re-initialize for another user-id
    if (Mode::SingleUser != m_mode) // only if in single-user mode
    {
        throw RuntimeException(
            u"invalid call: ac must be in \"single-user\" mode!"_ustr, getXWeak() );
    }
    OUString userId;
    arguments[ 0 ] >>= userId;
    if ( userId.isEmpty() )
    {
        throw RuntimeException(
            u"expected a user-id as first argument!"_ustr, getXWeak() );
    }
    // 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()
{
    // get policy singleton
    if (! m_xPolicy.is())
    {
        Reference< security::XPolicy > xPolicy;
        m_xComponentContext->getValueByName(
            u"/singletons/com.sun.star.security.thePolicy"_ustr ) >>= xPolicy;
        if (!xPolicy.is())
        {
            throw SecurityException(
                u"cannot get policy singleton!"_ustr, getXWeak() );
        }

        MutexGuard guard( m_aMutex );
        if (! m_xPolicy.is())
        {
            m_xPolicy = std::move(xPolicy);
        }
    }
    return m_xPolicy;
}

#ifdef __DIAGNOSE
static void dumpPermissions(
    PermissionCollection const & collection, OUString const & userId = OUString() )
{
    OUStringBuffer buf( 48 );
    if (!userId.isEmpty())
    {
        buf.append( "> dumping permissions of user \"" );
        buf.append( userId );
        buf.append( "\":" );
    }
    else
    {
        buf.append( "> dumping default permissions:" );
    }
    SAL_INFO("stoc", buf.makeStringAndClear() );
    Sequence< OUString > permissions( collection.toStrings() );
    OUString const * p = permissions.getConstArray();
    for ( sal_Int32 nPos = 0; nPos < permissions.getLength(); ++nPos )
    {
        SAL_INFO("stoc", p[ nPos ] );
    }
    SAL_INFO("stoc""> permission dump done" );
}
#endif


void AccessController::clearPostPoned()
{
    delete static_cast< t_rec_vec * >( m_rec.getData() );
    m_rec.setData( nullptr );
}

void AccessController::checkAndClearPostPoned()
{
    // check postponed permissions
    std::unique_ptr< t_rec_vec > rec( static_cast< t_rec_vec * >( m_rec.getData() ) );
    m_rec.setData( nullptr ); // takeover ownership
    OSL_ASSERT(rec);
    if (!rec)
        return;

    t_rec_vec const& vec = *rec;
    switch (m_mode)
    {
    case Mode::SingleUser:
    {
        OSL_ASSERT( m_singleUser_init );
        for (const auto & p : vec)
        {
            OSL_ASSERT( m_singleUserId == p.first );
            m_singleUserPermissions.checkPermission( p.second );
        }
        break;
    }
    case Mode::SingleDefaultUser:
    {
        OSL_ASSERT( m_defaultPerm_init );
        for (const auto & p : vec)
        {
            OSL_ASSERT( p.first.isEmpty() ); // default-user
            m_defaultPermissions.checkPermission( p.second );
        }
        break;
    }
    case Mode::On:
    {
        for (const auto & p : vec)
        {
            PermissionCollection const * pPermissions;
            // lookup policy for user
            {
                MutexGuard guard( m_aMutex );
                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 )
{
    OUString userId;

    switch (m_mode)
    {
    case Mode::SingleUser:
    {
        if (m_singleUser_init)
            return m_singleUserPermissions;
        userId = m_singleUserId;
        break;
    }
    case Mode::SingleDefaultUser:
    {
        if (m_defaultPerm_init)
            return m_defaultPermissions;
        break;
    }
    case Mode::On:
    {
        if (xContext.is())
        {
            xContext->getValueByName( USER_CREDS ) >>= userId;
        }
        if ( userId.isEmpty() )
        {
            throw SecurityException(
                u"cannot determine current user in multi-user ac!"_ustr, getXWeak() );
        }

        // lookup policy for user
        MutexGuard guard( m_aMutex );
        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 = static_cast< t_rec_vec * >( m_rec.getData() );
    if (rec) // tls entry exists => this is recursive call
    {
        if (demanded_perm.hasValue())
        {
            // enqueue
            rec->push_back( std::pair< OUString, Any >( userId, demanded_perm ) );
        }
#ifdef __DIAGNOSE
        SAL_INFO("stoc""> info: recurring call of user: " << userId );
#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_aMutex );
            if (! m_defaultPerm_init)
            {
                m_defaultPermissions = std::move(defaultPermissions);
                m_defaultPerm_init = true;
            }
#ifdef __DIAGNOSE
            dumpPermissions( m_defaultPermissions );
#endif
        }

        PermissionCollection ret;

        // init user permissions
        switch (m_mode)
        {
        case Mode::SingleUser:
        {
            ret = PermissionCollection(
                getPolicy()->getPermissions( userId ), m_defaultPermissions );
            {
            // assign
            MutexGuard guard( m_aMutex );
            if (m_singleUser_init)
            {
                ret = m_singleUserPermissions;
            }
            else
            {
                m_singleUserPermissions = ret;
                m_singleUser_init = true;
            }
            }
#ifdef __DIAGNOSE
            dumpPermissions( ret, userId );
#endif
            break;
        }
        case Mode::SingleDefaultUser:
        {
            ret = m_defaultPermissions;
            break;
        }
        case Mode::On:
        {
            ret = PermissionCollection(
                getPolicy()->getPermissions( userId ), m_defaultPermissions );
            {
            // cache
            MutexGuard guard( m_aMutex );
            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?
        throw DeploymentException( "deployment error (AccessControlException occurred): " + exc.Message, exc.Context );
    }
    catch (RuntimeException &)
    {
        // don't check postponed, just cleanup
        clearPostPoned();
        delete static_cast< t_rec_vec * >( m_rec.getData() );
        m_rec.setData( nullptr );
        throw;
    }
    catch (Exception &)
    {
        // check postponed permissions first
        // => AccessControlExceptions are errors, user exceptions not!
        checkAndClearPostPoned();
        throw;
    }
    catch (...)
    {
        // don't check postponed, just cleanup
        clearPostPoned();
        throw;
    }
}

// XAccessController impl

void AccessController::checkPermission(
    Any const & perm )
{
    if (rBHelper.bDisposed)
    {
        throw lang::DisposedException(
            u"checkPermission() call on disposed AccessController!"_ustr, getXWeak() );
    }

    if (Mode::Off == m_mode)
        return;

    // first dynamic check of ac contexts
    Reference< XCurrentContext > xContext;
    ::uno_getCurrentContext( reinterpret_cast<void **>(&xContext), s_envType.pData, nullptr );
    Reference< security::XAccessControlContext > xACC( getDynamicRestriction( xContext ) );
    if (xACC.is())
    {
        xACC->checkPermission( perm );
    }

    if (Mode::DynamicOnly == m_mode)
        return;

    // then static check
    getEffectivePermissions( xContext, perm ).checkPermission( perm );
}

Any AccessController::doRestricted(
    Reference< security::XAction > const & xAction,
    Reference< security::XAccessControlContext > const & xRestriction )
{
    if (rBHelper.bDisposed)
    {
        throw lang::DisposedException(
            u"doRestricted() call on disposed AccessController!"_ustr, getXWeak() );
    }

    if (Mode::Off == m_mode) // optimize this way, because no dynamic check will be performed
        return xAction->run();

    if (xRestriction.is())
    {
        Reference< XCurrentContext > xContext;
        ::uno_getCurrentContext( reinterpret_cast<void **>(&xContext), s_envType.pData, nullptr );

        // override restriction
        Reference< XCurrentContext > xNewContext(
            new acc_CurrentContext( xContext, acc_Intersection::create(
                                        xRestriction, getDynamicRestriction( xContext ) ) ) );
        ::uno_setCurrentContext( xNewContext.get(), s_envType.pData, nullptr );
        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 )
{
    if (rBHelper.bDisposed)
    {
        throw lang::DisposedException(
            u"doPrivileged() call on disposed AccessController!"_ustr, getXWeak() );
    }

    if (Mode::Off == m_mode) // no dynamic check will be performed
    {
        return xAction->run();
    }

    Reference< XCurrentContext > xContext;
    ::uno_getCurrentContext( reinterpret_cast<void **>(&xContext), s_envType.pData, nullptr );

    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, nullptr );
        cc_reset reset( xContext.get() );
        return xAction->run();
    }
    else // no previous restriction => never current restriction
    {
        return xAction->run();
    }
}

Reference< security::XAccessControlContext > AccessController::getContext()
{
    if (rBHelper.bDisposed)
    {
        throw lang::DisposedException(
            u"getContext() call on disposed AccessController!"_ustr, getXWeak() );
    }

    if (Mode::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( reinterpret_cast<void **>(&xContext), s_envType.pData, nullptr );

    return acc_Intersection::create(
        getDynamicRestriction( xContext ),
        new acc_Policy( getEffectivePermissions( xContext, Any() ) ) );
}

// XServiceInfo impl

OUString AccessController::getImplementationName()
{
    return u"com.sun.star.security.comp.stoc.AccessController"_ustr;
}

sal_Bool AccessController::supportsService( OUString const & serviceName )
{
    return cppu::supportsService(this, serviceName);
}

Sequence< OUString > AccessController::getSupportedServiceNames()
{
    Sequence<OUString> aSNS { SERVICE_NAME };
    return aSNS;
}

}

extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
com_sun_star_security_comp_stoc_AccessController_get_implementation(
    css::uno::XComponentContext *context,
    css::uno::Sequence<css::uno::Any> const &)
{
    return cppu::acquire(new AccessController(context));
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=94 H=95 G=94

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.