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