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