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