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