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