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