Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <boost/unordered_map.hpp>
22 :
23 : #include <osl/diagnose.h>
24 : #include <osl/file.h>
25 : #include <rtl/byteseq.hxx>
26 : #include <rtl/string.hxx>
27 : #include <rtl/ustrbuf.hxx>
28 :
29 : #include <cppuhelper/access_control.hxx>
30 : #include <cppuhelper/compbase2.hxx>
31 : #include <cppuhelper/implementationentry.hxx>
32 :
33 : #include <com/sun/star/lang/XServiceInfo.hpp>
34 : #include <com/sun/star/security/XAccessController.hpp>
35 : #include <com/sun/star/security/XPolicy.hpp>
36 : #include <com/sun/star/security/AllPermission.hpp>
37 : #include <com/sun/star/security/RuntimePermission.hpp>
38 : #include <com/sun/star/io/FilePermission.hpp>
39 : #include <com/sun/star/connection/SocketPermission.hpp>
40 :
41 : #include "bootstrapservices.hxx"
42 :
43 : #define SERVICE_NAME "com.sun.star.security.Policy"
44 : #define IMPL_NAME "com.sun.star.security.comp.stoc.FilePolicy"
45 :
46 : using namespace ::osl;
47 : using namespace ::rtl;
48 : using namespace ::cppu;
49 : using namespace ::com::sun::star;
50 : using namespace ::com::sun::star::uno;
51 :
52 : namespace stoc_sec
53 : {
54 : //--------------------------------------------------------------------------------------------------
55 : static inline void dispose( Reference< XInterface > const & x )
56 : SAL_THROW( (RuntimeException) )
57 : {
58 : Reference< lang::XComponent > xComp( x, UNO_QUERY );
59 : if (xComp.is())
60 : {
61 : xComp->dispose();
62 : }
63 : }
64 :
65 : //##################################################################################################
66 :
67 0 : struct MutexHolder
68 : {
69 : Mutex m_mutex;
70 : };
71 : typedef WeakComponentImplHelper2< security::XPolicy, lang::XServiceInfo > t_helper;
72 :
73 : //==================================================================================================
74 : class FilePolicy
75 : : public MutexHolder
76 : , public t_helper
77 : {
78 : Reference< XComponentContext > m_xComponentContext;
79 : AccessControl m_ac;
80 :
81 : Sequence< Any > m_defaultPermissions;
82 : typedef boost::unordered_map< OUString, Sequence< Any >, OUStringHash > t_permissions;
83 : t_permissions m_userPermissions;
84 : bool m_init;
85 :
86 : protected:
87 : virtual void SAL_CALL disposing();
88 :
89 : public:
90 : FilePolicy( Reference< XComponentContext > const & xComponentContext )
91 : SAL_THROW(());
92 : virtual ~FilePolicy()
93 : SAL_THROW(());
94 :
95 : // XPolicy impl
96 : virtual Sequence< Any > SAL_CALL getPermissions(
97 : OUString const & userId )
98 : throw (RuntimeException);
99 : virtual Sequence< Any > SAL_CALL getDefaultPermissions()
100 : throw (RuntimeException);
101 : virtual void SAL_CALL refresh()
102 : throw (RuntimeException);
103 :
104 : // XServiceInfo impl
105 : virtual OUString SAL_CALL getImplementationName()
106 : throw (RuntimeException);
107 : virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName )
108 : throw (RuntimeException);
109 : virtual Sequence< OUString > SAL_CALL getSupportedServiceNames()
110 : throw (RuntimeException);
111 : };
112 : //__________________________________________________________________________________________________
113 0 : FilePolicy::FilePolicy( Reference< XComponentContext > const & xComponentContext )
114 : SAL_THROW(())
115 : : t_helper( m_mutex )
116 : , m_xComponentContext( xComponentContext )
117 : , m_ac( xComponentContext )
118 0 : , m_init( false )
119 0 : {}
120 : //__________________________________________________________________________________________________
121 0 : FilePolicy::~FilePolicy()
122 : SAL_THROW(())
123 0 : {}
124 : //__________________________________________________________________________________________________
125 0 : void FilePolicy::disposing()
126 : {
127 0 : m_userPermissions.clear();
128 0 : m_defaultPermissions = Sequence< Any >();
129 0 : m_xComponentContext.clear();
130 0 : }
131 :
132 : //__________________________________________________________________________________________________
133 0 : Sequence< Any > FilePolicy::getPermissions(
134 : OUString const & userId )
135 : throw (RuntimeException)
136 : {
137 0 : if (! m_init)
138 : {
139 0 : refresh();
140 0 : m_init = true;
141 : }
142 :
143 0 : MutexGuard guard( m_mutex );
144 0 : t_permissions::iterator iFind( m_userPermissions.find( userId ) );
145 0 : if (m_userPermissions.end() == iFind)
146 : {
147 0 : return Sequence< Any >();
148 : }
149 : else
150 : {
151 0 : return iFind->second;
152 0 : }
153 : }
154 : //__________________________________________________________________________________________________
155 0 : Sequence< Any > FilePolicy::getDefaultPermissions()
156 : throw (RuntimeException)
157 : {
158 0 : if (! m_init)
159 : {
160 0 : refresh();
161 0 : m_init = true;
162 : }
163 :
164 0 : MutexGuard guard( m_mutex );
165 0 : return m_defaultPermissions;
166 : }
167 :
168 : //==================================================================================================
169 : class PolicyReader
170 : {
171 : OUString m_fileName;
172 : oslFileHandle m_file;
173 :
174 : sal_Int32 m_linepos;
175 : ByteSequence m_line;
176 : sal_Int32 m_pos;
177 : sal_Unicode m_back;
178 :
179 : sal_Unicode get()
180 : SAL_THROW( (RuntimeException) );
181 0 : inline void back( sal_Unicode c ) SAL_THROW(())
182 0 : { m_back = c; }
183 :
184 0 : inline bool isWhiteSpace( sal_Unicode c ) const SAL_THROW(())
185 0 : { return (' ' == c || '\t' == c || '\n' == c || '\r' == c); }
186 : void skipWhiteSpace()
187 : SAL_THROW( (RuntimeException) );
188 :
189 0 : inline bool isCharToken( sal_Unicode c ) const SAL_THROW(())
190 0 : { return (';' == c || ',' == c || '{' == c || '}' == c); }
191 :
192 : public:
193 : PolicyReader( OUString const & file, AccessControl & ac )
194 : SAL_THROW( (RuntimeException) );
195 : ~PolicyReader()
196 : SAL_THROW(());
197 :
198 : void error( OUString const & msg )
199 : SAL_THROW( (RuntimeException) );
200 :
201 : OUString getToken()
202 : SAL_THROW( (RuntimeException) );
203 : OUString assureToken()
204 : SAL_THROW( (RuntimeException) );
205 : OUString getQuotedToken()
206 : SAL_THROW( (RuntimeException) );
207 : OUString assureQuotedToken()
208 : SAL_THROW( (RuntimeException) );
209 : void assureToken( sal_Unicode token )
210 : SAL_THROW( (RuntimeException) );
211 : };
212 : //__________________________________________________________________________________________________
213 0 : void PolicyReader::assureToken( sal_Unicode token )
214 : SAL_THROW( (RuntimeException) )
215 : {
216 0 : skipWhiteSpace();
217 0 : sal_Unicode c = get();
218 0 : if (c == token)
219 0 : return;
220 0 : OUStringBuffer buf( 16 );
221 0 : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("expected >") );
222 0 : buf.append( c );
223 0 : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("<!") );
224 0 : error( buf.makeStringAndClear() );
225 : }
226 : //__________________________________________________________________________________________________
227 0 : OUString PolicyReader::assureQuotedToken()
228 : SAL_THROW( (RuntimeException) )
229 : {
230 0 : OUString token( getQuotedToken() );
231 0 : if (token.isEmpty())
232 0 : error( "unexpected end of file!" );
233 0 : return token;
234 : }
235 : //__________________________________________________________________________________________________
236 0 : OUString PolicyReader::getQuotedToken()
237 : SAL_THROW( (RuntimeException) )
238 : {
239 0 : skipWhiteSpace();
240 0 : OUStringBuffer buf( 32 );
241 0 : sal_Unicode c = get();
242 0 : if ('\"' != c)
243 0 : error( "expected quoting >\"< character!" );
244 0 : c = get();
245 0 : while ('\0' != c && '\"' != c)
246 : {
247 0 : buf.append( c );
248 0 : c = get();
249 : }
250 0 : return buf.makeStringAndClear();
251 : }
252 : //__________________________________________________________________________________________________
253 0 : OUString PolicyReader::assureToken()
254 : SAL_THROW( (RuntimeException) )
255 : {
256 0 : OUString token( getToken() );
257 0 : if ( token.isEmpty())
258 0 : error( "unexpected end of file!" );
259 0 : return token;
260 : }
261 : //__________________________________________________________________________________________________
262 0 : OUString PolicyReader::getToken()
263 : SAL_THROW( (RuntimeException) )
264 : {
265 0 : skipWhiteSpace();
266 0 : sal_Unicode c = get();
267 0 : if (isCharToken( c ))
268 0 : return OUString( &c, 1 );
269 0 : OUStringBuffer buf( 32 );
270 0 : while ('\0' != c && !isCharToken( c ) && !isWhiteSpace( c ))
271 : {
272 0 : buf.append( c );
273 0 : c = get();
274 : }
275 0 : back( c );
276 0 : return buf.makeStringAndClear();
277 : }
278 : //__________________________________________________________________________________________________
279 0 : void PolicyReader::skipWhiteSpace()
280 : SAL_THROW( (RuntimeException) )
281 : {
282 : sal_Unicode c;
283 0 : do
284 : {
285 0 : c = get();
286 : }
287 0 : while (isWhiteSpace( c )); // seeking next non-whitespace char
288 :
289 0 : if ('/' == c) // C/C++ like comment
290 : {
291 0 : c = get();
292 0 : if ('/' == c) // C++ like comment
293 : {
294 0 : do
295 : {
296 0 : c = get();
297 : }
298 0 : while ('\n' != c && '\0' != c); // seek eol/eof
299 0 : skipWhiteSpace(); // cont skip on next line
300 : }
301 0 : else if ('*' == c) // C like comment
302 : {
303 0 : bool fini = true;
304 0 : do
305 : {
306 0 : c = get();
307 0 : if ('*' == c)
308 : {
309 0 : c = get();
310 0 : fini = ('/' == c || '\0' == c);
311 : }
312 : else
313 : {
314 0 : fini = ('\0' == c);
315 : }
316 : }
317 0 : while (! fini);
318 0 : skipWhiteSpace(); // cont skip on next line
319 : }
320 : else
321 : {
322 0 : error( "expected C/C++ like comment!" );
323 : }
324 : }
325 0 : else if ('#' == c) // script like comment
326 : {
327 0 : do
328 : {
329 0 : c = get();
330 : }
331 0 : while ('\n' != c && '\0' != c); // seek eol/eof
332 0 : skipWhiteSpace(); // cont skip on next line
333 : }
334 :
335 : else // is token char
336 : {
337 0 : back( c );
338 : }
339 0 : }
340 : //__________________________________________________________________________________________________
341 0 : sal_Unicode PolicyReader::get()
342 : SAL_THROW( (RuntimeException) )
343 : {
344 0 : if ('\0' != m_back) // one char push back possible
345 : {
346 0 : sal_Unicode c = m_back;
347 0 : m_back = '\0';
348 0 : return c;
349 : }
350 0 : else if (m_pos == m_line.getLength()) // provide newline as whitespace
351 : {
352 0 : ++m_pos;
353 0 : return '\n';
354 : }
355 0 : else if (m_pos > m_line.getLength()) // read new line
356 : {
357 : sal_Bool eof;
358 0 : oslFileError rc = ::osl_isEndOfFile( m_file, &eof );
359 0 : if (osl_File_E_None != rc)
360 0 : error( "checking eof failed!" );
361 0 : if (eof)
362 0 : return '\0';
363 :
364 0 : rc = ::osl_readLine( m_file, reinterpret_cast< sal_Sequence ** >( &m_line ) );
365 0 : if (osl_File_E_None != rc)
366 0 : error( "read line failed!" );
367 0 : ++m_linepos;
368 0 : if (! m_line.getLength()) // empty line read
369 : {
370 0 : m_pos = 1; // read new line next time
371 0 : return '\n';
372 : }
373 0 : m_pos = 0;
374 : }
375 0 : return (m_line.getConstArray()[ m_pos++ ]);
376 : }
377 : //__________________________________________________________________________________________________
378 0 : void PolicyReader::error( OUString const & msg )
379 : SAL_THROW( (RuntimeException) )
380 : {
381 0 : OUStringBuffer buf( 32 );
382 0 : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("error processing file \"") );
383 0 : buf.append( m_fileName );
384 0 : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\" [line ") );
385 0 : buf.append( m_linepos );
386 0 : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", column ") );
387 0 : buf.append( m_pos );
388 0 : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] ") );
389 0 : buf.append( msg );
390 0 : throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface >() );
391 : }
392 : //__________________________________________________________________________________________________
393 0 : PolicyReader::PolicyReader( OUString const & fileName, AccessControl & ac )
394 : SAL_THROW( (RuntimeException) )
395 : : m_fileName( fileName )
396 : , m_linepos( 0 )
397 : , m_pos( 1 ) // force readline
398 0 : , m_back( '\0' )
399 : {
400 0 : ac.checkFilePermission( m_fileName, "read" );
401 0 : if (osl_File_E_None != ::osl_openFile( m_fileName.pData, &m_file, osl_File_OpenFlag_Read ))
402 : {
403 0 : OUStringBuffer buf( 32 );
404 0 : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("cannot open file \"") );
405 0 : buf.append( m_fileName );
406 0 : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"!") );
407 0 : throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface >() );
408 : }
409 0 : }
410 : //__________________________________________________________________________________________________
411 0 : PolicyReader::~PolicyReader()
412 : SAL_THROW(())
413 : {
414 0 : if ( ::osl_closeFile( m_file ) != osl_File_E_None ) {
415 : OSL_ASSERT( false );
416 : }
417 0 : }
418 :
419 : #define s_grant "grant"
420 : #define s_user "user"
421 : #define s_permission "permission"
422 : #define s_openBrace "{"
423 : #define s_closingBrace "}"
424 :
425 : #define s_filePermission "com.sun.star.io.FilePermission"
426 : #define s_socketPermission "com.sun.star.connection.SocketPermission"
427 : #define s_runtimePermission "com.sun.star.security.RuntimePermission"
428 : #define s_allPermission "com.sun.star.security.AllPermission"
429 :
430 : //__________________________________________________________________________________________________
431 0 : void FilePolicy::refresh()
432 : throw (RuntimeException)
433 : {
434 : // read out file (the .../file-name value had originally been set in
435 : // cppu::add_access_control_entries (cppuhelper/source/servicefactory.cxx)
436 : // depending on various UNO_AC* bootstrap variables that are no longer
437 : // supported, so this is effectively dead code):
438 0 : OUString fileName;
439 0 : m_xComponentContext->getValueByName(
440 0 : "/implementations/" IMPL_NAME "/file-name" ) >>= fileName;
441 0 : if ( fileName.isEmpty() )
442 : {
443 : throw RuntimeException(
444 : "name of policy file unknown!",
445 0 : (OWeakObject *)this );
446 : }
447 :
448 0 : PolicyReader reader( fileName, m_ac );
449 :
450 : // fill these two
451 0 : Sequence< Any > defaultPermissions;
452 0 : t_permissions userPermissions;
453 :
454 0 : OUString token( reader.getToken() );
455 0 : while (!token.isEmpty())
456 : {
457 0 : if ( token != s_grant )
458 0 : reader.error( "expected >grant< token!" );
459 0 : OUString userId;
460 0 : token = reader.assureToken();
461 0 : if ( token == s_user ) // next token is user-id
462 : {
463 0 : userId = reader.assureQuotedToken();
464 0 : token = reader.assureToken();
465 : }
466 0 : if ( token != s_openBrace )
467 0 : reader.error( "expected opening brace >{<!" );
468 0 : token = reader.assureToken();
469 : // permissions list
470 0 : while ( token != s_closingBrace )
471 : {
472 0 : if ( token != s_permission )
473 0 : reader.error( "expected >permission< or closing brace >}<!" );
474 :
475 0 : token = reader.assureToken(); // permission type
476 0 : Any perm;
477 0 : if ( token == s_filePermission ) // FilePermission
478 : {
479 0 : OUString url( reader.assureQuotedToken() );
480 0 : reader.assureToken( ',' );
481 0 : OUString actions( reader.assureQuotedToken() );
482 0 : perm <<= io::FilePermission( url, actions );
483 : }
484 0 : else if ( token == s_socketPermission ) // SocketPermission
485 : {
486 0 : OUString host( reader.assureQuotedToken() );
487 0 : reader.assureToken( ',' );
488 0 : OUString actions( reader.assureQuotedToken() );
489 0 : perm <<= connection::SocketPermission( host, actions );
490 : }
491 0 : else if ( token == s_runtimePermission ) // RuntimePermission
492 : {
493 0 : OUString name( reader.assureQuotedToken() );
494 0 : perm <<= security::RuntimePermission( name );
495 : }
496 0 : else if ( token == s_allPermission ) // AllPermission
497 : {
498 0 : perm <<= security::AllPermission();
499 : }
500 : else
501 : {
502 0 : reader.error( "expected permission type!" );
503 : }
504 :
505 0 : reader.assureToken( ';' );
506 :
507 : // insert
508 0 : if (!userId.isEmpty())
509 : {
510 0 : Sequence< Any > perms( userPermissions[ userId ] );
511 0 : sal_Int32 len = perms.getLength();
512 0 : perms.realloc( len +1 );
513 0 : perms[ len ] = perm;
514 0 : userPermissions[ userId ] = perms;
515 : }
516 : else
517 : {
518 0 : sal_Int32 len = defaultPermissions.getLength();
519 0 : defaultPermissions.realloc( len +1 );
520 0 : defaultPermissions[ len ] = perm;
521 : }
522 :
523 0 : token = reader.assureToken(); // next permissions token
524 0 : }
525 :
526 0 : reader.assureToken( ';' ); // semi
527 0 : token = reader.getToken(); // next grant token
528 0 : }
529 :
530 : // assign new ones
531 0 : MutexGuard guard( m_mutex );
532 0 : m_defaultPermissions = defaultPermissions;
533 0 : m_userPermissions = userPermissions;
534 0 : }
535 :
536 : //__________________________________________________________________________________________________
537 0 : OUString FilePolicy::getImplementationName()
538 : throw (RuntimeException)
539 : {
540 0 : return stoc_bootstrap::filepolicy_getImplementationName();
541 : }
542 : //__________________________________________________________________________________________________
543 0 : sal_Bool FilePolicy::supportsService( OUString const & serviceName )
544 : throw (RuntimeException)
545 : {
546 0 : Sequence< OUString > aSNL = getSupportedServiceNames();
547 0 : const OUString * pNames = aSNL.getConstArray();
548 0 : for ( sal_Int32 nPos = aSNL.getLength(); --nPos; )
549 : {
550 0 : if (serviceName.equals( pNames[ nPos ] ))
551 : {
552 0 : return sal_True;
553 : }
554 : }
555 0 : return sal_False;
556 : }
557 : //__________________________________________________________________________________________________
558 0 : Sequence< OUString > FilePolicy::getSupportedServiceNames()
559 : throw (RuntimeException)
560 : {
561 0 : return stoc_bootstrap::filepolicy_getSupportedServiceNames();
562 : }
563 : }
564 : //##################################################################################################
565 : namespace stoc_bootstrap
566 : {
567 : //--------------------------------------------------------------------------------------------------
568 0 : Reference< XInterface > SAL_CALL filepolicy_create(
569 : Reference< XComponentContext > const & xComponentContext )
570 : SAL_THROW( (Exception) )
571 : {
572 0 : return (OWeakObject *)new stoc_sec::FilePolicy( xComponentContext );
573 : }
574 : //--------------------------------------------------------------------------------------------------
575 0 : Sequence< OUString > filepolicy_getSupportedServiceNames() SAL_THROW(())
576 : {
577 0 : Sequence< OUString > aSNS( 1 );
578 0 : aSNS.getArray()[0] = OUString(SERVICE_NAME);
579 0 : return aSNS;
580 : }
581 : //--------------------------------------------------------------------------------------------------
582 7 : OUString filepolicy_getImplementationName() SAL_THROW(())
583 : {
584 7 : return OUString(IMPL_NAME);
585 : }
586 : }
587 :
588 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|