xref: /trunk/main/stoc/source/security/access_controller.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_stoc.hxx"
26 
27 #include <vector>
28 #include <memory>
29 
30 #include <osl/diagnose.h>
31 #include <osl/interlck.h>
32 #include <osl/mutex.hxx>
33 #include <osl/thread.hxx>
34 
35 #include <rtl/ustrbuf.hxx>
36 #include <rtl/string.hxx>
37 
38 #include <uno/current_context.h>
39 
40 #include <cppuhelper/implbase1.hxx>
41 #include <cppuhelper/compbase3.hxx>
42 #include <cppuhelper/factory.hxx>
43 #include <cppuhelper/implementationentry.hxx>
44 
45 #include <com/sun/star/uno/XCurrentContext.hpp>
46 #include <com/sun/star/uno/DeploymentException.hpp>
47 #include <com/sun/star/lang/DisposedException.hpp>
48 #include <com/sun/star/lang/XComponent.hpp>
49 #include <com/sun/star/lang/XServiceInfo.hpp>
50 #include <com/sun/star/lang/XInitialization.hpp>
51 #include <com/sun/star/security/XAccessController.hpp>
52 #include <com/sun/star/security/XPolicy.hpp>
53 
54 #include "lru_cache.h"
55 #include "permissions.h"
56 
57 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
58 #define SERVICE_NAME "com.sun.star.security.AccessController"
59 #define IMPL_NAME "com.sun.star.security.comp.stoc.AccessController"
60 #define USER_CREDS "access-control.user-credentials"
61 
62 
63 using namespace ::std;
64 using namespace ::osl;
65 using namespace ::cppu;
66 using namespace ::com::sun::star;
67 using namespace ::com::sun::star::uno;
68 using ::rtl::OUString;
69 using ::rtl::OUStringBuffer;
70 using ::rtl::OString;
71 
72 extern ::rtl_StandardModuleCount g_moduleCount;
73 
74 namespace stoc_sec
75 {
76 // static stuff initialized when loading lib
77 static OUString s_envType = OUSTR(CPPU_CURRENT_LANGUAGE_BINDING_NAME);
78 static OUString s_implName = OUSTR(IMPL_NAME);
79 static OUString s_serviceName = OUSTR(SERVICE_NAME);
80 static OUString s_acRestriction = OUSTR("access-control.restriction");
81 
82 static Sequence< OUString > s_serviceNames = Sequence< OUString >( &s_serviceName, 1 );
83 
84 //##################################################################################################
85 
86 /** ac context intersects permissions of two ac contexts
87 */
88 class acc_Intersection
89     : public WeakImplHelper1< security::XAccessControlContext >
90 {
91     Reference< security::XAccessControlContext > m_x1, m_x2;
92 
93     inline acc_Intersection(
94         Reference< security::XAccessControlContext > const & x1,
95         Reference< security::XAccessControlContext > const & x2 )
96         SAL_THROW( () );
97 
98 public:
99     virtual ~acc_Intersection()
100         SAL_THROW( () );
101 
102     static inline Reference< security::XAccessControlContext > create(
103         Reference< security::XAccessControlContext > const & x1,
104         Reference< security::XAccessControlContext > const & x2 )
105         SAL_THROW( () );
106 
107     // XAccessControlContext impl
108     virtual void SAL_CALL checkPermission(
109         Any const & perm );
110 };
111 //__________________________________________________________________________________________________
acc_Intersection(Reference<security::XAccessControlContext> const & x1,Reference<security::XAccessControlContext> const & x2)112 inline acc_Intersection::acc_Intersection(
113     Reference< security::XAccessControlContext > const & x1,
114     Reference< security::XAccessControlContext > const & x2 )
115     SAL_THROW( () )
116     : m_x1( x1 )
117     , m_x2( x2 )
118 {
119     g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
120 }
121 //__________________________________________________________________________________________________
~acc_Intersection()122 acc_Intersection::~acc_Intersection()
123     SAL_THROW( () )
124 {
125     g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
126 }
127 //--------------------------------------------------------------------------------------------------
create(Reference<security::XAccessControlContext> const & x1,Reference<security::XAccessControlContext> const & x2)128 inline Reference< security::XAccessControlContext > acc_Intersection::create(
129     Reference< security::XAccessControlContext > const & x1,
130     Reference< security::XAccessControlContext > const & x2 )
131     SAL_THROW( () )
132 {
133     if (! x1.is())
134         return x2;
135     if (! x2.is())
136         return x1;
137     return new acc_Intersection( x1, x2 );
138 }
139 //__________________________________________________________________________________________________
checkPermission(Any const & perm)140 void acc_Intersection::checkPermission(
141     Any const & perm )
142 {
143     m_x1->checkPermission( perm );
144     m_x2->checkPermission( perm );
145 }
146 
147 /** ac context unifies permissions of two ac contexts
148 */
149 class acc_Union
150     : public WeakImplHelper1< security::XAccessControlContext >
151 {
152     Reference< security::XAccessControlContext > m_x1, m_x2;
153 
154     inline acc_Union(
155         Reference< security::XAccessControlContext > const & x1,
156         Reference< security::XAccessControlContext > const & x2 )
157         SAL_THROW( () );
158 
159 public:
160     virtual ~acc_Union()
161         SAL_THROW( () );
162 
163     static inline Reference< security::XAccessControlContext > create(
164         Reference< security::XAccessControlContext > const & x1,
165         Reference< security::XAccessControlContext > const & x2 )
166         SAL_THROW( () );
167 
168     // XAccessControlContext impl
169     virtual void SAL_CALL checkPermission(
170         Any const & perm );
171 };
172 //__________________________________________________________________________________________________
acc_Union(Reference<security::XAccessControlContext> const & x1,Reference<security::XAccessControlContext> const & x2)173 inline acc_Union::acc_Union(
174     Reference< security::XAccessControlContext > const & x1,
175     Reference< security::XAccessControlContext > const & x2 )
176     SAL_THROW( () )
177     : m_x1( x1 )
178     , m_x2( x2 )
179 {
180     g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
181 }
182 //__________________________________________________________________________________________________
~acc_Union()183 acc_Union::~acc_Union()
184     SAL_THROW( () )
185 {
186     g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
187 }
188 //--------------------------------------------------------------------------------------------------
create(Reference<security::XAccessControlContext> const & x1,Reference<security::XAccessControlContext> const & x2)189 inline Reference< security::XAccessControlContext > acc_Union::create(
190     Reference< security::XAccessControlContext > const & x1,
191     Reference< security::XAccessControlContext > const & x2 )
192     SAL_THROW( () )
193 {
194     if (! x1.is())
195         return Reference< security::XAccessControlContext >(); // unrestricted
196     if (! x2.is())
197         return Reference< security::XAccessControlContext >(); // unrestricted
198     return new acc_Union( x1, x2 );
199 }
200 //__________________________________________________________________________________________________
checkPermission(Any const & perm)201 void acc_Union::checkPermission(
202     Any const & perm )
203 {
204     try
205     {
206         m_x1->checkPermission( perm );
207     }
208     catch (security::AccessControlException &)
209     {
210         m_x2->checkPermission( perm );
211     }
212 }
213 
214 /** ac context doing permission checks on static permissions
215 */
216 class acc_Policy
217     : public WeakImplHelper1< security::XAccessControlContext >
218 {
219     PermissionCollection m_permissions;
220 
221 public:
222     inline acc_Policy(
223         PermissionCollection const & permissions )
224         SAL_THROW( () );
225     virtual ~acc_Policy()
226         SAL_THROW( () );
227 
228     // XAccessControlContext impl
229     virtual void SAL_CALL checkPermission(
230         Any const & perm );
231 };
232 //__________________________________________________________________________________________________
acc_Policy(PermissionCollection const & permissions)233 inline acc_Policy::acc_Policy(
234     PermissionCollection const & permissions )
235     SAL_THROW( () )
236     : m_permissions( permissions )
237 {
238     g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
239 }
240 //__________________________________________________________________________________________________
~acc_Policy()241 acc_Policy::~acc_Policy()
242     SAL_THROW( () )
243 {
244     g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
245 }
246 //__________________________________________________________________________________________________
checkPermission(Any const & perm)247 void acc_Policy::checkPermission(
248     Any const & perm )
249 {
250     m_permissions.checkPermission( perm );
251 }
252 
253 /** current context overriding dynamic ac restriction
254 */
255 class acc_CurrentContext
256     : public ImplHelper1< XCurrentContext >
257 {
258     oslInterlockedCount m_refcount;
259 
260     Reference< XCurrentContext > m_xDelegate;
261     Any m_restriction;
262 
263 public:
264     inline acc_CurrentContext(
265         Reference< XCurrentContext > const & xDelegate,
266         Reference< security::XAccessControlContext > const & xRestriction )
267         SAL_THROW( () );
268     virtual ~acc_CurrentContext() SAL_THROW( () );
269 
270     // XInterface impl
271     virtual void SAL_CALL acquire()
272         throw ();
273     virtual void SAL_CALL release()
274         throw ();
275 
276     // XCurrentContext impl
277     virtual Any SAL_CALL getValueByName( OUString const & name );
278 };
279 //__________________________________________________________________________________________________
acc_CurrentContext(Reference<XCurrentContext> const & xDelegate,Reference<security::XAccessControlContext> const & xRestriction)280 inline acc_CurrentContext::acc_CurrentContext(
281     Reference< XCurrentContext > const & xDelegate,
282     Reference< security::XAccessControlContext > const & xRestriction )
283     SAL_THROW( () )
284     : m_refcount( 0 )
285     , m_xDelegate( xDelegate )
286 {
287     g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
288 
289     if (xRestriction.is())
290     {
291         m_restriction = makeAny( xRestriction );
292     }
293     // return empty any otherwise on getValueByName(), not null interface
294 }
295 //__________________________________________________________________________________________________
~acc_CurrentContext()296 acc_CurrentContext::~acc_CurrentContext()
297     SAL_THROW( () )
298 {
299     g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
300 }
301 //__________________________________________________________________________________________________
acquire()302 void acc_CurrentContext::acquire()
303     throw ()
304 {
305     ::osl_incrementInterlockedCount( &m_refcount );
306 }
307 //__________________________________________________________________________________________________
release()308 void acc_CurrentContext::release()
309     throw ()
310 {
311     if (! ::osl_decrementInterlockedCount( &m_refcount ))
312     {
313         delete this;
314     }
315 }
316 //__________________________________________________________________________________________________
getValueByName(OUString const & name)317 Any acc_CurrentContext::getValueByName( OUString const & name )
318 {
319     if (name.equals( s_acRestriction ))
320     {
321         return m_restriction;
322     }
323     else if (m_xDelegate.is())
324     {
325         return m_xDelegate->getValueByName( name );
326     }
327     else
328     {
329         return Any();
330     }
331 }
332 
333 //##################################################################################################
334 
335 //--------------------------------------------------------------------------------------------------
dispose(Reference<XInterface> const & x)336 static inline void dispose( Reference< XInterface > const & x )
337 {
338     Reference< lang::XComponent > xComp( x, UNO_QUERY );
339     if (xComp.is())
340     {
341         xComp->dispose();
342     }
343 }
344 //--------------------------------------------------------------------------------------------------
getDynamicRestriction(Reference<XCurrentContext> const & xContext)345 static inline Reference< security::XAccessControlContext > getDynamicRestriction(
346     Reference< XCurrentContext > const & xContext )
347 {
348     if (xContext.is())
349     {
350         Any acc( xContext->getValueByName( s_acRestriction ) );
351         if (typelib_TypeClass_INTERFACE == acc.pType->eTypeClass)
352         {
353             // avoid ref-counting
354             OUString const & typeName =
355                 *reinterpret_cast< OUString const * >( &acc.pType->pTypeName );
356             if (typeName.equalsAsciiL(
357                     RTL_CONSTASCII_STRINGPARAM("com.sun.star.security.XAccessControlContext") ))
358             {
359                 return Reference< security::XAccessControlContext >(
360                     *reinterpret_cast< security::XAccessControlContext ** const >( acc.pData ) );
361             }
362             else // try to query
363             {
364                 return Reference< security::XAccessControlContext >::query(
365                     *reinterpret_cast< XInterface ** const >( acc.pData ) );
366             }
367         }
368     }
369     return Reference< security::XAccessControlContext >();
370 }
371 //==================================================================================================
372 class cc_reset
373 {
374     void * m_cc;
375 public:
376     inline cc_reset( void * cc ) SAL_THROW( () )
377         : m_cc( cc ) {}
378     inline ~cc_reset() SAL_THROW( () )
379         { ::uno_setCurrentContext( m_cc, s_envType.pData, 0 ); }
380 };
381 
382 //##################################################################################################
383 
384 struct MutexHolder
385 {
386     Mutex m_mutex;
387 };
388 typedef WeakComponentImplHelper3<
389     security::XAccessController, lang::XServiceInfo, lang::XInitialization > t_helper;
390 
391 //==================================================================================================
392 class AccessController
393     : public MutexHolder
394     , public t_helper
395 {
396     Reference< XComponentContext > m_xComponentContext;
397 
398     Reference< security::XPolicy > m_xPolicy;
399     Reference< security::XPolicy > const & getPolicy();
400 
401     // mode
402     enum Mode { OFF, ON, DYNAMIC_ONLY, SINGLE_USER, SINGLE_DEFAULT_USER } m_mode;
403 
404     PermissionCollection m_defaultPermissions;
405     // for single-user mode
406     PermissionCollection m_singleUserPermissions;
407     OUString m_singleUserId;
408     bool m_defaultPerm_init;
409     bool m_singleUser_init;
410     // for multi-user mode
411     lru_cache< OUString, PermissionCollection, ::rtl::OUStringHash, equal_to< OUString > >
412         m_user2permissions;
413 
414     ThreadData m_rec;
415     typedef vector< pair< OUString, Any > > t_rec_vec;
416     inline void clearPostPoned() SAL_THROW( () );
417     void checkAndClearPostPoned();
418 
419     PermissionCollection getEffectivePermissions(
420         Reference< XCurrentContext > const & xContext,
421         Any const & demanded_perm );
422 
423 protected:
424     virtual void SAL_CALL disposing();
425 
426 public:
427     AccessController( Reference< XComponentContext > const & xComponentContext );
428     virtual ~AccessController()
429         SAL_THROW( () );
430 
431     //  XInitialization impl
432     virtual void SAL_CALL initialize(
433         Sequence< Any > const & arguments );
434 
435     // XAccessController impl
436     virtual void SAL_CALL checkPermission(
437         Any const & perm );
438     virtual Any SAL_CALL doRestricted(
439         Reference< security::XAction > const & xAction,
440         Reference< security::XAccessControlContext > const & xRestriction );
441     virtual Any SAL_CALL doPrivileged(
442         Reference< security::XAction > const & xAction,
443         Reference< security::XAccessControlContext > const & xRestriction );
444     virtual Reference< security::XAccessControlContext > SAL_CALL getContext();
445 
446     // XServiceInfo impl
447     virtual OUString SAL_CALL getImplementationName();
448     virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName );
449     virtual Sequence< OUString > SAL_CALL getSupportedServiceNames();
450 };
451 //__________________________________________________________________________________________________
AccessController(Reference<XComponentContext> const & xComponentContext)452 AccessController::AccessController( Reference< XComponentContext > const & xComponentContext )
453     : t_helper( m_mutex )
454     , m_xComponentContext( xComponentContext )
455     , m_mode( ON ) // default
456     , m_defaultPerm_init( false )
457     , m_singleUser_init( false )
458     , m_rec( 0 )
459 {
460     g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
461 
462     OUString mode;
463     if (m_xComponentContext->getValueByName( OUSTR("/services/" SERVICE_NAME "/mode") ) >>= mode)
464     {
465         if (mode.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("off") ))
466         {
467             m_mode = OFF;
468         }
469         else if (mode.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("on") ))
470         {
471             m_mode = ON;
472         }
473         else if (mode.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("dynamic-only") ))
474         {
475             m_mode = DYNAMIC_ONLY;
476         }
477         else if (mode.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("single-user") ))
478         {
479             m_xComponentContext->getValueByName(
480                 OUSTR("/services/" SERVICE_NAME "/single-user-id") ) >>= m_singleUserId;
481             if (! m_singleUserId.getLength())
482             {
483                 throw RuntimeException(
484                     OUSTR("expected a user id in component context entry "
485                           "\"/services/" SERVICE_NAME "/single-user-id\"!"),
486                     (OWeakObject *)this );
487             }
488             m_mode = SINGLE_USER;
489         }
490         else if (mode.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("single-default-user") ))
491         {
492             m_mode = SINGLE_DEFAULT_USER;
493         }
494     }
495 
496     // switch on caching for DYNAMIC_ONLY and ON (sharable multi-user process)
497     if (ON == m_mode || DYNAMIC_ONLY == m_mode)
498     {
499         sal_Int32 cacheSize = 0; // multi-user cache size
500         if (! (m_xComponentContext->getValueByName(
501             OUSTR("/services/" SERVICE_NAME "/user-cache-size") ) >>= cacheSize))
502         {
503             cacheSize = 128; // reasonable default?
504         }
505 #ifdef __CACHE_DIAGNOSE
506         cacheSize = 2;
507 #endif
508         m_user2permissions.setSize( cacheSize );
509     }
510 }
511 //__________________________________________________________________________________________________
~AccessController()512 AccessController::~AccessController()
513     SAL_THROW( () )
514 {
515     g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
516 }
517 //__________________________________________________________________________________________________
disposing()518 void AccessController::disposing()
519 {
520     m_mode = OFF; // avoid checks from now on xxx todo review/ better DYNAMIC_ONLY?
521     m_xPolicy.clear();
522     m_xComponentContext.clear();
523 }
524 
525 // XInitialization impl
526 //__________________________________________________________________________________________________
initialize(Sequence<Any> const & arguments)527 void AccessController::initialize(
528     Sequence< Any > const & arguments )
529 {
530     // xxx todo: review for forking
531     // portal forking hack: re-initialize for another user-id
532     if (SINGLE_USER != m_mode) // only if in single-user mode
533     {
534         throw RuntimeException(
535             OUSTR("invalid call: ac must be in \"single-user\" mode!"), (OWeakObject *)this );
536     }
537     OUString userId;
538     arguments[ 0 ] >>= userId;
539     if (! userId.getLength())
540     {
541         throw RuntimeException(
542             OUSTR("expected a user-id as first argument!"), (OWeakObject *)this );
543     }
544     // assured that no sync is necessary: no check happens at this forking time
545     m_singleUserId = userId;
546     m_singleUser_init = false;
547 }
548 
549 //__________________________________________________________________________________________________
getPolicy()550 Reference< security::XPolicy > const & AccessController::getPolicy()
551 {
552     // get policy singleton
553     if (! m_xPolicy.is())
554     {
555         Reference< security::XPolicy > xPolicy;
556         m_xComponentContext->getValueByName(
557             OUSTR("/singletons/com.sun.star.security.thePolicy") ) >>= xPolicy;
558         if (xPolicy.is())
559         {
560             MutexGuard guard( m_mutex );
561             if (! m_xPolicy.is())
562             {
563                 m_xPolicy = xPolicy;
564             }
565         }
566         else
567         {
568             throw SecurityException(
569                 OUSTR("cannot get policy singleton!"), (OWeakObject *)this );
570         }
571     }
572     return m_xPolicy;
573 }
574 
575 #ifdef __DIAGNOSE
dumpPermissions(PermissionCollection const & collection,OUString const & userId=OUString ())576 static void dumpPermissions(
577     PermissionCollection const & collection, OUString const & userId = OUString() ) SAL_THROW( () )
578 {
579     OUStringBuffer buf( 48 );
580     if (userId.getLength())
581     {
582         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("> dumping permissions of user \"") );
583         buf.append( userId );
584         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\":") );
585     }
586     else
587     {
588         buf.appendAscii(
589             RTL_CONSTASCII_STRINGPARAM("> dumping default permissions:") );
590     }
591     OString str( ::rtl::OUStringToOString( buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
592     OSL_TRACE( str.getStr() );
593     Sequence< OUString > permissions( collection.toStrings() );
594     OUString const * p = permissions.getConstArray();
595     for ( sal_Int32 nPos = 0; nPos < permissions.getLength(); ++nPos )
596     {
597         OString str( ::rtl::OUStringToOString( p[ nPos ], RTL_TEXTENCODING_ASCII_US ) );
598         OSL_TRACE( str.getStr() );
599     }
600     OSL_TRACE( "> permission dump done" );
601 }
602 #endif
603 
604 
605 //__________________________________________________________________________________________________
clearPostPoned()606 inline void AccessController::clearPostPoned() SAL_THROW( () )
607 {
608     delete reinterpret_cast< t_rec_vec * >( m_rec.getData() );
609     m_rec.setData( 0 );
610 }
611 //__________________________________________________________________________________________________
checkAndClearPostPoned()612 void AccessController::checkAndClearPostPoned()
613 {
614     // check postponed permissions
615     auto_ptr< t_rec_vec > rec( reinterpret_cast< t_rec_vec * >( m_rec.getData() ) );
616     m_rec.setData( 0 ); // takeover ownership
617     OSL_ASSERT( rec.get() );
618     if (rec.get())
619     {
620         t_rec_vec const & vec = *rec.get();
621         switch (m_mode)
622         {
623         case SINGLE_USER:
624         {
625             OSL_ASSERT( m_singleUser_init );
626             for ( size_t nPos = 0; nPos < vec.size(); ++nPos )
627             {
628                 pair< OUString, Any > const & p = vec[ nPos ];
629                 OSL_ASSERT( m_singleUserId.equals( p.first ) );
630                 m_singleUserPermissions.checkPermission( p.second );
631             }
632             break;
633         }
634         case SINGLE_DEFAULT_USER:
635         {
636             OSL_ASSERT( m_defaultPerm_init );
637             for ( size_t nPos = 0; nPos < vec.size(); ++nPos )
638             {
639                 pair< OUString, Any > const & p = vec[ nPos ];
640                 OSL_ASSERT( !p.first.getLength() ); // default-user
641                 m_defaultPermissions.checkPermission( p.second );
642             }
643             break;
644         }
645         case ON:
646         {
647             for ( size_t nPos = 0; nPos < vec.size(); ++nPos )
648             {
649                 pair< OUString, Any > const & p = vec[ nPos ];
650                 PermissionCollection const * pPermissions;
651                 // lookup policy for user
652                 {
653                     MutexGuard guard( m_mutex );
654                     pPermissions = m_user2permissions.lookup( p.first );
655                 }
656                 OSL_ASSERT( pPermissions );
657                 if (pPermissions)
658                 {
659                     pPermissions->checkPermission( p.second );
660                 }
661             }
662             break;
663         }
664         default:
665             OSL_ENSURE( 0, "### this should never be called in this ac mode!" );
666             break;
667         }
668     }
669 }
670 //__________________________________________________________________________________________________
671 /** this is the only function calling the policy singleton and thus has to take care
672     of recurring calls!
673 
674     @param demanded_perm (if not empty) is the demanded permission of a checkPermission() call
675                          which will be postponed for recurring calls
676 */
getEffectivePermissions(Reference<XCurrentContext> const & xContext,Any const & demanded_perm)677 PermissionCollection AccessController::getEffectivePermissions(
678     Reference< XCurrentContext > const & xContext,
679     Any const & demanded_perm )
680 {
681     OUString userId;
682 
683     switch (m_mode)
684     {
685     case SINGLE_USER:
686     {
687         if (m_singleUser_init)
688             return m_singleUserPermissions;
689         userId = m_singleUserId;
690         break;
691     }
692     case SINGLE_DEFAULT_USER:
693     {
694         if (m_defaultPerm_init)
695             return m_defaultPermissions;
696         break;
697     }
698     case ON:
699     {
700         if (xContext.is())
701         {
702             xContext->getValueByName( OUSTR(USER_CREDS ".id") ) >>= userId;
703         }
704         if (! userId.getLength())
705         {
706             throw SecurityException(
707                 OUSTR("cannot determine current user in multi-user ac!"), (OWeakObject *)this );
708         }
709 
710         // lookup policy for user
711         MutexGuard guard( m_mutex );
712         PermissionCollection const * pPermissions = m_user2permissions.lookup( userId );
713         if (pPermissions)
714             return *pPermissions;
715         break;
716     }
717     default:
718         OSL_ENSURE( 0, "### this should never be called in this ac mode!" );
719         return PermissionCollection();
720     }
721 
722     // call on policy
723     // iff this is a recurring call for the default user, then grant all permissions
724     t_rec_vec * rec = reinterpret_cast< t_rec_vec * >( m_rec.getData() );
725     if (rec) // tls entry exists => this is recursive call
726     {
727         if (demanded_perm.hasValue())
728         {
729             // enqueue
730             rec->push_back( pair< OUString, Any >( userId, demanded_perm ) );
731         }
732 #ifdef __DIAGNOSE
733         OUStringBuffer buf( 48 );
734         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("> info: recurring call of user \"") );
735         buf.append( userId );
736         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"") );
737         OString str(
738             ::rtl::OUStringToOString( buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
739         OSL_TRACE( str.getStr() );
740 #endif
741         return PermissionCollection( new AllPermission() );
742     }
743     else // no tls
744     {
745         rec = new t_rec_vec;
746         m_rec.setData( rec );
747     }
748 
749     try // calls on API
750     {
751         // init default permissions
752         if (! m_defaultPerm_init)
753         {
754             PermissionCollection defaultPermissions(
755                 getPolicy()->getDefaultPermissions() );
756             // assign
757             MutexGuard guard( m_mutex );
758             if (! m_defaultPerm_init)
759             {
760                 m_defaultPermissions = defaultPermissions;
761                 m_defaultPerm_init = true;
762             }
763 #ifdef __DIAGNOSE
764             dumpPermissions( m_defaultPermissions );
765 #endif
766         }
767 
768         PermissionCollection ret;
769 
770         // init user permissions
771         switch (m_mode)
772         {
773         case SINGLE_USER:
774         {
775             ret = PermissionCollection(
776                 getPolicy()->getPermissions( userId ), m_defaultPermissions );
777             {
778             // assign
779             MutexGuard guard( m_mutex );
780             if (m_singleUser_init)
781             {
782                 ret = m_singleUserPermissions;
783             }
784             else
785             {
786                 m_singleUserPermissions = ret;
787                 m_singleUser_init = true;
788             }
789             }
790 #ifdef __DIAGNOSE
791             dumpPermissions( ret, userId );
792 #endif
793             break;
794         }
795         case SINGLE_DEFAULT_USER:
796         {
797             ret = m_defaultPermissions;
798             break;
799         }
800         case ON:
801         {
802             ret = PermissionCollection(
803                 getPolicy()->getPermissions( userId ), m_defaultPermissions );
804             {
805             // cache
806             MutexGuard guard( m_mutex );
807             m_user2permissions.set( userId, ret );
808             }
809 #ifdef __DIAGNOSE
810             dumpPermissions( ret, userId );
811 #endif
812             break;
813         }
814         default:
815             break;
816         }
817 
818         // check postponed
819         checkAndClearPostPoned();
820         return ret;
821     }
822     catch (security::AccessControlException & exc) // wrapped into DeploymentException
823     {
824         clearPostPoned(); // safety: exception could have happened before checking postponed?
825         OUStringBuffer buf( 64 );
826         buf.appendAscii(
827             RTL_CONSTASCII_STRINGPARAM("deployment error (AccessControlException occurred): ") );
828         buf.append( exc.Message );
829         throw DeploymentException( buf.makeStringAndClear(), exc.Context );
830     }
831     catch (RuntimeException &)
832     {
833         // dont check postponed, just cleanup
834         clearPostPoned();
835         delete reinterpret_cast< t_rec_vec * >( m_rec.getData() );
836         m_rec.setData( 0 );
837         throw;
838     }
839     catch (Exception &)
840     {
841         // check postponed permissions first
842         // => AccessControlExceptions are errors, user exceptions not!
843         checkAndClearPostPoned();
844         throw;
845     }
846     catch (...)
847     {
848         // dont check postponed, just cleanup
849         clearPostPoned();
850         throw;
851     }
852 }
853 
854 // XAccessController impl
855 //__________________________________________________________________________________________________
checkPermission(Any const & perm)856 void AccessController::checkPermission(
857     Any const & perm )
858 {
859     if (rBHelper.bDisposed)
860     {
861         throw lang::DisposedException(
862             OUSTR("checkPermission() call on disposed AccessController!"), (OWeakObject *)this );
863     }
864 
865     if (OFF == m_mode)
866         return;
867 
868     // first dynamic check of ac contexts
869     Reference< XCurrentContext > xContext;
870     ::uno_getCurrentContext( (void **)&xContext, s_envType.pData, 0 );
871     Reference< security::XAccessControlContext > xACC( getDynamicRestriction( xContext ) );
872     if (xACC.is())
873     {
874         xACC->checkPermission( perm );
875     }
876 
877     if (DYNAMIC_ONLY == m_mode)
878         return;
879 
880     // then static check
881     getEffectivePermissions( xContext, perm ).checkPermission( perm );
882 }
883 //__________________________________________________________________________________________________
doRestricted(Reference<security::XAction> const & xAction,Reference<security::XAccessControlContext> const & xRestriction)884 Any AccessController::doRestricted(
885     Reference< security::XAction > const & xAction,
886     Reference< security::XAccessControlContext > const & xRestriction )
887 {
888     if (rBHelper.bDisposed)
889     {
890         throw lang::DisposedException(
891             OUSTR("doRestricted() call on disposed AccessController!"), (OWeakObject *)this );
892     }
893 
894     if (OFF == m_mode) // optimize this way, because no dynamic check will be performed
895         return xAction->run();
896 
897     if (xRestriction.is())
898     {
899         Reference< XCurrentContext > xContext;
900         ::uno_getCurrentContext( (void **)&xContext, s_envType.pData, 0 );
901 
902         // override restriction
903         Reference< XCurrentContext > xNewContext(
904             new acc_CurrentContext( xContext, acc_Intersection::create(
905                                         xRestriction, getDynamicRestriction( xContext ) ) ) );
906         ::uno_setCurrentContext( xNewContext.get(), s_envType.pData, 0 );
907         cc_reset reset( xContext.get() );
908         return xAction->run();
909     }
910     else
911     {
912         return xAction->run();
913     }
914 }
915 //__________________________________________________________________________________________________
doPrivileged(Reference<security::XAction> const & xAction,Reference<security::XAccessControlContext> const & xRestriction)916 Any AccessController::doPrivileged(
917     Reference< security::XAction > const & xAction,
918     Reference< security::XAccessControlContext > const & xRestriction )
919 {
920     if (rBHelper.bDisposed)
921     {
922         throw lang::DisposedException(
923             OUSTR("doPrivileged() call on disposed AccessController!"), (OWeakObject *)this );
924     }
925 
926     if (OFF == m_mode) // no dynamic check will be performed
927     {
928         return xAction->run();
929     }
930 
931     Reference< XCurrentContext > xContext;
932     ::uno_getCurrentContext( (void **)&xContext, s_envType.pData, 0 );
933 
934     Reference< security::XAccessControlContext > xOldRestr(
935         getDynamicRestriction( xContext ) );
936 
937     if (xOldRestr.is()) // previous restriction
938     {
939         // override restriction
940         Reference< XCurrentContext > xNewContext(
941             new acc_CurrentContext( xContext, acc_Union::create( xRestriction, xOldRestr ) ) );
942         ::uno_setCurrentContext( xNewContext.get(), s_envType.pData, 0 );
943         cc_reset reset( xContext.get() );
944         return xAction->run();
945     }
946     else // no previous restriction => never current restriction
947     {
948         return xAction->run();
949     }
950 }
951 //__________________________________________________________________________________________________
getContext()952 Reference< security::XAccessControlContext > AccessController::getContext()
953 {
954     if (rBHelper.bDisposed)
955     {
956         throw lang::DisposedException(
957             OUSTR("getContext() call on disposed AccessController!"), (OWeakObject *)this );
958     }
959 
960     if (OFF == m_mode) // optimize this way, because no dynamic check will be performed
961     {
962         return new acc_Policy( PermissionCollection( new AllPermission() ) );
963     }
964 
965     Reference< XCurrentContext > xContext;
966     ::uno_getCurrentContext( (void **)&xContext, s_envType.pData, 0 );
967 
968     return acc_Intersection::create(
969         getDynamicRestriction( xContext ),
970         new acc_Policy( getEffectivePermissions( xContext, Any() ) ) );
971 }
972 
973 // XServiceInfo impl
974 //__________________________________________________________________________________________________
getImplementationName()975 OUString AccessController::getImplementationName()
976 {
977     return s_implName;
978 }
979 //__________________________________________________________________________________________________
supportsService(OUString const & serviceName)980 sal_Bool AccessController::supportsService( OUString const & serviceName )
981 {
982     OUString const * pNames = s_serviceNames.getConstArray();
983     for ( sal_Int32 nPos = s_serviceNames.getLength(); nPos--; )
984     {
985         if (serviceName.equals( pNames[ nPos ] ))
986         {
987             return sal_True;
988         }
989     }
990     return sal_False;
991 }
992 //__________________________________________________________________________________________________
getSupportedServiceNames()993 Sequence< OUString > AccessController::getSupportedServiceNames()
994 {
995     return s_serviceNames;
996 }
997 }
998 //##################################################################################################
999 namespace stoc_bootstrap {
1000 //--------------------------------------------------------------------------------------------------
ac_create(Reference<XComponentContext> const & xComponentContext)1001 Reference< XInterface > SAL_CALL ac_create(
1002     Reference< XComponentContext > const & xComponentContext )
1003 {
1004     return (OWeakObject *)new stoc_sec::AccessController( xComponentContext );
1005 }
1006 //--------------------------------------------------------------------------------------------------
ac_getSupportedServiceNames()1007 Sequence< OUString > ac_getSupportedServiceNames() SAL_THROW( () )
1008 {
1009     return stoc_sec::s_serviceNames;
1010 }
1011 //--------------------------------------------------------------------------------------------------
ac_getImplementationName()1012 OUString ac_getImplementationName() SAL_THROW( () )
1013 {
1014     return stoc_sec::s_implName;
1015 }
1016 //--------------------------------------------------------------------------------------------------
1017 Reference< XInterface > SAL_CALL filepolicy_create(
1018     Reference< XComponentContext > const & xComponentContext );
1019 //--------------------------------------------------------------------------------------------------
1020 Sequence< OUString > filepolicy_getSupportedServiceNames() SAL_THROW( () );
1021 //--------------------------------------------------------------------------------------------------
1022 OUString filepolicy_getImplementationName() SAL_THROW( () );
1023 }
1024