Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / stoc / source / security / access_controller.cxx
blob6772d2ba2a8ad43b8c1a2947f8f2aed9e5f867d4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <vector>
23 #include <osl/diagnose.h>
24 #include <osl/mutex.hxx>
25 #include <osl/thread.hxx>
27 #include <rtl/ref.hxx>
28 #include <rtl/ustrbuf.hxx>
30 #include <uno/current_context.h>
31 #include <uno/lbnames.h>
33 #include <cppuhelper/implbase.hxx>
34 #include <cppuhelper/compbase.hxx>
35 #include <cppuhelper/implementationentry.hxx>
36 #include <cppuhelper/supportsservice.hxx>
38 #include <com/sun/star/uno/XCurrentContext.hpp>
39 #include <com/sun/star/uno/DeploymentException.hpp>
40 #include <com/sun/star/lang/DisposedException.hpp>
41 #include <com/sun/star/lang/XComponent.hpp>
42 #include <com/sun/star/lang/XServiceInfo.hpp>
43 #include <com/sun/star/lang/XInitialization.hpp>
44 #include <com/sun/star/security/XAccessController.hpp>
45 #include <com/sun/star/security/XPolicy.hpp>
47 #include "lru_cache.h"
48 #include "permissions.h"
50 #include <memory>
52 #define SERVICE_NAME "com.sun.star.security.AccessController"
53 #define USER_CREDS "access-control.user-credentials"
56 using namespace ::std;
57 using namespace ::osl;
58 using namespace ::cppu;
59 using namespace ::com::sun::star;
60 using namespace css::uno;
61 using namespace stoc_sec;
63 namespace {
65 // static stuff initialized when loading lib
66 static OUString s_envType = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
67 const char s_acRestriction[] = "access-control.restriction";
70 /** ac context intersects permissions of two ac contexts
72 class acc_Intersection
73 : public WeakImplHelper< security::XAccessControlContext >
75 Reference< security::XAccessControlContext > m_x1, m_x2;
77 inline acc_Intersection(
78 Reference< security::XAccessControlContext > const & x1,
79 Reference< security::XAccessControlContext > const & x2 );
81 public:
82 static inline Reference< security::XAccessControlContext > create(
83 Reference< security::XAccessControlContext > const & x1,
84 Reference< security::XAccessControlContext > const & x2 );
86 // XAccessControlContext impl
87 virtual void SAL_CALL checkPermission(
88 Any const & perm ) override;
91 inline acc_Intersection::acc_Intersection(
92 Reference< security::XAccessControlContext > const & x1,
93 Reference< security::XAccessControlContext > const & x2 )
94 : m_x1( x1 )
95 , m_x2( x2 )
98 inline Reference< security::XAccessControlContext > acc_Intersection::create(
99 Reference< security::XAccessControlContext > const & x1,
100 Reference< security::XAccessControlContext > const & x2 )
102 if (! x1.is())
103 return x2;
104 if (! x2.is())
105 return x1;
106 return new acc_Intersection( x1, x2 );
109 void acc_Intersection::checkPermission(
110 Any const & perm )
112 m_x1->checkPermission( perm );
113 m_x2->checkPermission( perm );
116 /** ac context unifies permissions of two ac contexts
118 class acc_Union
119 : public WeakImplHelper< security::XAccessControlContext >
121 Reference< security::XAccessControlContext > m_x1, m_x2;
123 inline acc_Union(
124 Reference< security::XAccessControlContext > const & x1,
125 Reference< security::XAccessControlContext > const & x2 );
127 public:
128 static inline Reference< security::XAccessControlContext > create(
129 Reference< security::XAccessControlContext > const & x1,
130 Reference< security::XAccessControlContext > const & x2 );
132 // XAccessControlContext impl
133 virtual void SAL_CALL checkPermission(
134 Any const & perm ) override;
137 inline acc_Union::acc_Union(
138 Reference< security::XAccessControlContext > const & x1,
139 Reference< security::XAccessControlContext > const & x2 )
140 : m_x1( x1 )
141 , m_x2( x2 )
144 inline Reference< security::XAccessControlContext > acc_Union::create(
145 Reference< security::XAccessControlContext > const & x1,
146 Reference< security::XAccessControlContext > const & x2 )
148 if (! x1.is())
149 return Reference< security::XAccessControlContext >(); // unrestricted
150 if (! x2.is())
151 return Reference< security::XAccessControlContext >(); // unrestricted
152 return new acc_Union( x1, x2 );
155 void acc_Union::checkPermission(
156 Any const & perm )
160 m_x1->checkPermission( perm );
162 catch (security::AccessControlException &)
164 m_x2->checkPermission( perm );
168 /** ac context doing permission checks on static permissions
170 class acc_Policy
171 : public WeakImplHelper< security::XAccessControlContext >
173 PermissionCollection m_permissions;
175 public:
176 explicit acc_Policy(
177 PermissionCollection const & permissions )
178 : m_permissions( permissions )
181 // XAccessControlContext impl
182 virtual void SAL_CALL checkPermission(
183 Any const & perm ) override;
186 void acc_Policy::checkPermission(
187 Any const & perm )
189 m_permissions.checkPermission( perm );
192 /** current context overriding dynamic ac restriction
194 class acc_CurrentContext
195 : public WeakImplHelper< XCurrentContext >
197 Reference< XCurrentContext > m_xDelegate;
198 Any m_restriction;
200 public:
201 inline acc_CurrentContext(
202 Reference< XCurrentContext > const & xDelegate,
203 Reference< security::XAccessControlContext > const & xRestriction );
205 // XCurrentContext impl
206 virtual Any SAL_CALL getValueByName( OUString const & name ) override;
209 inline acc_CurrentContext::acc_CurrentContext(
210 Reference< XCurrentContext > const & xDelegate,
211 Reference< security::XAccessControlContext > const & xRestriction )
212 : m_xDelegate( xDelegate )
214 if (xRestriction.is())
216 m_restriction <<= xRestriction;
218 // return empty any otherwise on getValueByName(), not null interface
221 Any acc_CurrentContext::getValueByName( OUString const & name )
223 if (name == s_acRestriction)
225 return m_restriction;
227 else if (m_xDelegate.is())
229 return m_xDelegate->getValueByName( name );
231 else
233 return Any();
238 inline Reference< security::XAccessControlContext > getDynamicRestriction(
239 Reference< XCurrentContext > const & xContext )
241 if (xContext.is())
243 Any acc(xContext->getValueByName(s_acRestriction));
244 if (typelib_TypeClass_INTERFACE == acc.pType->eTypeClass)
246 // avoid ref-counting
247 OUString const & typeName =
248 OUString::unacquired( &acc.pType->pTypeName );
249 if ( typeName == "com.sun.star.security.XAccessControlContext" )
251 return Reference< security::XAccessControlContext >(
252 *static_cast< security::XAccessControlContext ** const >( acc.pData ) );
254 else // try to query
256 return Reference< security::XAccessControlContext >::query(
257 *static_cast< XInterface ** const >( acc.pData ) );
261 return Reference< security::XAccessControlContext >();
264 class cc_reset
266 void * m_cc;
267 public:
268 explicit cc_reset( void * cc )
269 : m_cc( cc ) {}
270 ~cc_reset()
271 { ::uno_setCurrentContext( m_cc, s_envType.pData, nullptr ); }
274 struct MutexHolder
276 Mutex m_mutex;
278 typedef WeakComponentImplHelper<
279 security::XAccessController, lang::XServiceInfo, lang::XInitialization > t_helper;
282 class AccessController
283 : public MutexHolder
284 , public t_helper
286 Reference< XComponentContext > m_xComponentContext;
288 Reference< security::XPolicy > m_xPolicy;
289 Reference< security::XPolicy > const & getPolicy();
291 // mode
292 enum Mode { OFF, ON, DYNAMIC_ONLY, SINGLE_USER, SINGLE_DEFAULT_USER } m_mode;
294 PermissionCollection m_defaultPermissions;
295 // for single-user mode
296 PermissionCollection m_singleUserPermissions;
297 OUString m_singleUserId;
298 bool m_defaultPerm_init;
299 bool m_singleUser_init;
300 // for multi-user mode
301 lru_cache< OUString, PermissionCollection, OUStringHash, equal_to< OUString > >
302 m_user2permissions;
304 ThreadData m_rec;
305 typedef vector< pair< OUString, Any > > t_rec_vec;
306 inline void clearPostPoned();
307 void checkAndClearPostPoned();
309 PermissionCollection getEffectivePermissions(
310 Reference< XCurrentContext > const & xContext,
311 Any const & demanded_perm );
313 protected:
314 virtual void SAL_CALL disposing() override;
316 public:
317 explicit AccessController( Reference< XComponentContext > const & xComponentContext );
319 // XInitialization impl
320 virtual void SAL_CALL initialize(
321 Sequence< Any > const & arguments ) override;
323 // XAccessController impl
324 virtual void SAL_CALL checkPermission(
325 Any const & perm ) override;
326 virtual Any SAL_CALL doRestricted(
327 Reference< security::XAction > const & xAction,
328 Reference< security::XAccessControlContext > const & xRestriction ) override;
329 virtual Any SAL_CALL doPrivileged(
330 Reference< security::XAction > const & xAction,
331 Reference< security::XAccessControlContext > const & xRestriction ) override;
332 virtual Reference< security::XAccessControlContext > SAL_CALL getContext() override;
334 // XServiceInfo impl
335 virtual OUString SAL_CALL getImplementationName() override;
336 virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName ) override;
337 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
340 AccessController::AccessController( Reference< XComponentContext > const & xComponentContext )
341 : t_helper( m_mutex )
342 , m_xComponentContext( xComponentContext )
343 , m_mode( ON ) // default
344 , m_defaultPerm_init( false )
345 , m_singleUser_init( false )
346 , m_rec( nullptr )
348 // The .../mode value had originally been set in
349 // cppu::add_access_control_entries (cppuhelper/source/servicefactory.cxx)
350 // to something other than "off" depending on various UNO_AC* bootstrap
351 // variables that are no longer supported, so this is mostly dead code now:
352 OUString mode;
353 if (m_xComponentContext->getValueByName( "/services/" SERVICE_NAME "/mode" ) >>= mode)
355 if ( mode == "off" )
357 m_mode = OFF;
359 else if ( mode == "on" )
361 m_mode = ON;
363 else if ( mode == "dynamic-only" )
365 m_mode = DYNAMIC_ONLY;
367 else if ( mode == "single-user" )
369 m_xComponentContext->getValueByName(
370 "/services/" SERVICE_NAME "/single-user-id" ) >>= m_singleUserId;
371 if (m_singleUserId.isEmpty())
373 throw RuntimeException(
374 "expected a user id in component context entry "
375 "\"/services/" SERVICE_NAME "/single-user-id\"!",
376 static_cast<OWeakObject *>(this) );
378 m_mode = SINGLE_USER;
380 else if ( mode == "single-default-user" )
382 m_mode = SINGLE_DEFAULT_USER;
386 // switch on caching for DYNAMIC_ONLY and ON (shareable multi-user process)
387 if (ON == m_mode || DYNAMIC_ONLY == m_mode)
389 sal_Int32 cacheSize = 0; // multi-user cache size
390 if (! (m_xComponentContext->getValueByName(
391 "/services/" SERVICE_NAME "/user-cache-size" ) >>= cacheSize))
393 cacheSize = 128; // reasonable default?
395 #ifdef __CACHE_DIAGNOSE
396 cacheSize = 2;
397 #endif
398 m_user2permissions.setSize( cacheSize );
402 void AccessController::disposing()
404 m_mode = OFF; // avoid checks from now on xxx todo review/ better DYNAMIC_ONLY?
405 m_xPolicy.clear();
406 m_xComponentContext.clear();
409 // XInitialization impl
411 void AccessController::initialize(
412 Sequence< Any > const & arguments )
414 // xxx todo: review for forking
415 // portal forking hack: re-initialize for another user-id
416 if (SINGLE_USER != m_mode) // only if in single-user mode
418 throw RuntimeException(
419 "invalid call: ac must be in \"single-user\" mode!", static_cast<OWeakObject *>(this) );
421 OUString userId;
422 arguments[ 0 ] >>= userId;
423 if ( userId.isEmpty() )
425 throw RuntimeException(
426 "expected a user-id as first argument!", static_cast<OWeakObject *>(this) );
428 // assured that no sync is necessary: no check happens at this forking time
429 m_singleUserId = userId;
430 m_singleUser_init = false;
434 Reference< security::XPolicy > const & AccessController::getPolicy()
436 // get policy singleton
437 if (! m_xPolicy.is())
439 Reference< security::XPolicy > xPolicy;
440 m_xComponentContext->getValueByName(
441 "/singletons/com.sun.star.security.thePolicy" ) >>= xPolicy;
442 if (xPolicy.is())
444 MutexGuard guard( m_mutex );
445 if (! m_xPolicy.is())
447 m_xPolicy = xPolicy;
450 else
452 throw SecurityException(
453 "cannot get policy singleton!", static_cast<OWeakObject *>(this) );
456 return m_xPolicy;
459 #ifdef __DIAGNOSE
460 static void dumpPermissions(
461 PermissionCollection const & collection, OUString const & userId = OUString() )
463 OUStringBuffer buf( 48 );
464 if (!userId.isEmpty())
466 buf.append( "> dumping permissions of user \"" );
467 buf.append( userId );
468 buf.append( "\":" );
470 else
472 buf.append( "> dumping default permissions:" );
474 SAL_INFO("stoc", buf.makeStringAndClear() );
475 Sequence< OUString > permissions( collection.toStrings() );
476 OUString const * p = permissions.getConstArray();
477 for ( sal_Int32 nPos = 0; nPos < permissions.getLength(); ++nPos )
479 SAL_INFO("stoc", p[ nPos ] );
481 SAL_INFO("stoc", "> permission dump done" );
483 #endif
486 inline void AccessController::clearPostPoned()
488 delete static_cast< t_rec_vec * >( m_rec.getData() );
489 m_rec.setData( nullptr );
492 void AccessController::checkAndClearPostPoned()
494 // check postponed permissions
495 std::unique_ptr< t_rec_vec > rec( static_cast< t_rec_vec * >( m_rec.getData() ) );
496 m_rec.setData( nullptr ); // takeover ownership
497 OSL_ASSERT( rec.get() );
498 if (rec.get())
500 t_rec_vec const & vec = *rec.get();
501 switch (m_mode)
503 case SINGLE_USER:
505 OSL_ASSERT( m_singleUser_init );
506 for (const auto & p : vec)
508 OSL_ASSERT( m_singleUserId.equals( p.first ) );
509 m_singleUserPermissions.checkPermission( p.second );
511 break;
513 case SINGLE_DEFAULT_USER:
515 OSL_ASSERT( m_defaultPerm_init );
516 for (const auto & p : vec)
518 OSL_ASSERT( p.first.isEmpty() ); // default-user
519 m_defaultPermissions.checkPermission( p.second );
521 break;
523 case ON:
525 for (const auto & p : vec)
527 PermissionCollection const * pPermissions;
528 // lookup policy for user
530 MutexGuard guard( m_mutex );
531 pPermissions = m_user2permissions.lookup( p.first );
533 OSL_ASSERT( pPermissions );
534 if (pPermissions)
536 pPermissions->checkPermission( p.second );
539 break;
541 default:
542 OSL_FAIL( "### this should never be called in this ac mode!" );
543 break;
548 /** this is the only function calling the policy singleton and thus has to take care
549 of recurring calls!
551 @param demanded_perm (if not empty) is the demanded permission of a checkPermission() call
552 which will be postponed for recurring calls
554 PermissionCollection AccessController::getEffectivePermissions(
555 Reference< XCurrentContext > const & xContext,
556 Any const & demanded_perm )
558 OUString userId;
560 switch (m_mode)
562 case SINGLE_USER:
564 if (m_singleUser_init)
565 return m_singleUserPermissions;
566 userId = m_singleUserId;
567 break;
569 case SINGLE_DEFAULT_USER:
571 if (m_defaultPerm_init)
572 return m_defaultPermissions;
573 break;
575 case ON:
577 if (xContext.is())
579 xContext->getValueByName( USER_CREDS ".id" ) >>= userId;
581 if ( userId.isEmpty() )
583 throw SecurityException(
584 "cannot determine current user in multi-user ac!", static_cast<OWeakObject *>(this) );
587 // lookup policy for user
588 MutexGuard guard( m_mutex );
589 PermissionCollection const * pPermissions = m_user2permissions.lookup( userId );
590 if (pPermissions)
591 return *pPermissions;
592 break;
594 default:
595 OSL_FAIL( "### this should never be called in this ac mode!" );
596 return PermissionCollection();
599 // call on policy
600 // iff this is a recurring call for the default user, then grant all permissions
601 t_rec_vec * rec = static_cast< t_rec_vec * >( m_rec.getData() );
602 if (rec) // tls entry exists => this is recursive call
604 if (demanded_perm.hasValue())
606 // enqueue
607 rec->push_back( pair< OUString, Any >( userId, demanded_perm ) );
609 #ifdef __DIAGNOSE
610 OUStringBuffer buf( 48 );
611 buf.append( "> info: recurring call of user \"" );
612 buf.append( userId );
613 buf.append( "\"" );
614 OString str(
615 OUStringToOString( buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
616 SAL_INFO("stoc",( "%s", str.getStr() );
617 #endif
618 return PermissionCollection( new AllPermission() );
620 else // no tls
622 rec = new t_rec_vec;
623 m_rec.setData( rec );
626 try // calls on API
628 // init default permissions
629 if (! m_defaultPerm_init)
631 PermissionCollection defaultPermissions(
632 getPolicy()->getDefaultPermissions() );
633 // assign
634 MutexGuard guard( m_mutex );
635 if (! m_defaultPerm_init)
637 m_defaultPermissions = defaultPermissions;
638 m_defaultPerm_init = true;
640 #ifdef __DIAGNOSE
641 dumpPermissions( m_defaultPermissions );
642 #endif
645 PermissionCollection ret;
647 // init user permissions
648 switch (m_mode)
650 case SINGLE_USER:
652 ret = PermissionCollection(
653 getPolicy()->getPermissions( userId ), m_defaultPermissions );
655 // assign
656 MutexGuard guard( m_mutex );
657 if (m_singleUser_init)
659 ret = m_singleUserPermissions;
661 else
663 m_singleUserPermissions = ret;
664 m_singleUser_init = true;
667 #ifdef __DIAGNOSE
668 dumpPermissions( ret, userId );
669 #endif
670 break;
672 case SINGLE_DEFAULT_USER:
674 ret = m_defaultPermissions;
675 break;
677 case ON:
679 ret = PermissionCollection(
680 getPolicy()->getPermissions( userId ), m_defaultPermissions );
682 // cache
683 MutexGuard guard( m_mutex );
684 m_user2permissions.set( userId, ret );
686 #ifdef __DIAGNOSE
687 dumpPermissions( ret, userId );
688 #endif
689 break;
691 default:
692 break;
695 // check postponed
696 checkAndClearPostPoned();
697 return ret;
699 catch (const security::AccessControlException & exc) // wrapped into DeploymentException
701 clearPostPoned(); // safety: exception could have happened before checking postponed?
702 throw DeploymentException( "deployment error (AccessControlException occurred): " + exc.Message, exc.Context );
704 catch (RuntimeException &)
706 // don't check postponed, just cleanup
707 clearPostPoned();
708 delete static_cast< t_rec_vec * >( m_rec.getData() );
709 m_rec.setData( nullptr );
710 throw;
712 catch (Exception &)
714 // check postponed permissions first
715 // => AccessControlExceptions are errors, user exceptions not!
716 checkAndClearPostPoned();
717 throw;
719 catch (...)
721 // don't check postponed, just cleanup
722 clearPostPoned();
723 throw;
727 // XAccessController impl
729 void AccessController::checkPermission(
730 Any const & perm )
732 if (rBHelper.bDisposed)
734 throw lang::DisposedException(
735 "checkPermission() call on disposed AccessController!", static_cast<OWeakObject *>(this) );
738 if (OFF == m_mode)
739 return;
741 // first dynamic check of ac contexts
742 Reference< XCurrentContext > xContext;
743 ::uno_getCurrentContext( reinterpret_cast<void **>(&xContext), s_envType.pData, nullptr );
744 Reference< security::XAccessControlContext > xACC( getDynamicRestriction( xContext ) );
745 if (xACC.is())
747 xACC->checkPermission( perm );
750 if (DYNAMIC_ONLY == m_mode)
751 return;
753 // then static check
754 getEffectivePermissions( xContext, perm ).checkPermission( perm );
757 Any AccessController::doRestricted(
758 Reference< security::XAction > const & xAction,
759 Reference< security::XAccessControlContext > const & xRestriction )
761 if (rBHelper.bDisposed)
763 throw lang::DisposedException(
764 "doRestricted() call on disposed AccessController!", static_cast<OWeakObject *>(this) );
767 if (OFF == m_mode) // optimize this way, because no dynamic check will be performed
768 return xAction->run();
770 if (xRestriction.is())
772 Reference< XCurrentContext > xContext;
773 ::uno_getCurrentContext( reinterpret_cast<void **>(&xContext), s_envType.pData, nullptr );
775 // override restriction
776 Reference< XCurrentContext > xNewContext(
777 new acc_CurrentContext( xContext, acc_Intersection::create(
778 xRestriction, getDynamicRestriction( xContext ) ) ) );
779 ::uno_setCurrentContext( xNewContext.get(), s_envType.pData, nullptr );
780 cc_reset reset( xContext.get() );
781 return xAction->run();
783 else
785 return xAction->run();
789 Any AccessController::doPrivileged(
790 Reference< security::XAction > const & xAction,
791 Reference< security::XAccessControlContext > const & xRestriction )
793 if (rBHelper.bDisposed)
795 throw lang::DisposedException(
796 "doPrivileged() call on disposed AccessController!", static_cast<OWeakObject *>(this) );
799 if (OFF == m_mode) // no dynamic check will be performed
801 return xAction->run();
804 Reference< XCurrentContext > xContext;
805 ::uno_getCurrentContext( reinterpret_cast<void **>(&xContext), s_envType.pData, nullptr );
807 Reference< security::XAccessControlContext > xOldRestr(
808 getDynamicRestriction( xContext ) );
810 if (xOldRestr.is()) // previous restriction
812 // override restriction
813 Reference< XCurrentContext > xNewContext(
814 new acc_CurrentContext( xContext, acc_Union::create( xRestriction, xOldRestr ) ) );
815 ::uno_setCurrentContext( xNewContext.get(), s_envType.pData, nullptr );
816 cc_reset reset( xContext.get() );
817 return xAction->run();
819 else // no previous restriction => never current restriction
821 return xAction->run();
825 Reference< security::XAccessControlContext > AccessController::getContext()
827 if (rBHelper.bDisposed)
829 throw lang::DisposedException(
830 "getContext() call on disposed AccessController!", static_cast<OWeakObject *>(this) );
833 if (OFF == m_mode) // optimize this way, because no dynamic check will be performed
835 return new acc_Policy( PermissionCollection( new AllPermission() ) );
838 Reference< XCurrentContext > xContext;
839 ::uno_getCurrentContext( reinterpret_cast<void **>(&xContext), s_envType.pData, nullptr );
841 return acc_Intersection::create(
842 getDynamicRestriction( xContext ),
843 new acc_Policy( getEffectivePermissions( xContext, Any() ) ) );
846 // XServiceInfo impl
848 OUString AccessController::getImplementationName()
850 return OUString("com.sun.star.security.comp.stoc.AccessController");
853 sal_Bool AccessController::supportsService( OUString const & serviceName )
855 return cppu::supportsService(this, serviceName);
858 Sequence< OUString > AccessController::getSupportedServiceNames()
860 Sequence<OUString> aSNS { SERVICE_NAME };
861 return aSNS;
866 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
867 com_sun_star_security_comp_stoc_AccessController_get_implementation(
868 css::uno::XComponentContext *context,
869 css::uno::Sequence<css::uno::Any> const &)
871 return cppu::acquire(new AccessController(context));
874 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */