Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / stoc / source / security / file_policy.cxx
blob31bdcdbcc7c1ec1ceb6c738087a8cf708a4cbc2d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
27 #include <cppuhelper/access_control.hxx>
28 #include <cppuhelper/compbase.hxx>
29 #include <cppuhelper/implementationentry.hxx>
30 #include <cppuhelper/supportsservice.hxx>
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>
40 #include <unordered_map>
42 #define IMPL_NAME "com.sun.star.security.comp.stoc.FilePolicy"
44 using namespace ::osl;
45 using namespace ::cppu;
46 using namespace ::com::sun::star;
47 using namespace css::uno;
49 namespace {
51 struct MutexHolder
53 Mutex m_mutex;
55 typedef WeakComponentImplHelper< security::XPolicy, lang::XServiceInfo > t_helper;
58 class FilePolicy
59 : public MutexHolder
60 , public t_helper
62 Reference< XComponentContext > m_xComponentContext;
63 AccessControl m_ac;
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;
70 protected:
71 virtual void SAL_CALL disposing() override;
73 public:
74 explicit FilePolicy( Reference< XComponentContext > const & xComponentContext );
76 // XPolicy impl
77 virtual Sequence< Any > SAL_CALL getPermissions(
78 OUString const & userId ) override;
79 virtual Sequence< Any > SAL_CALL getDefaultPermissions() override;
80 virtual void SAL_CALL refresh() override;
82 // XServiceInfo impl
83 virtual OUString SAL_CALL getImplementationName() override;
84 virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName ) override;
85 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
88 FilePolicy::FilePolicy( Reference< XComponentContext > const & xComponentContext )
89 : t_helper( m_mutex )
90 , m_xComponentContext( xComponentContext )
91 , m_ac( xComponentContext )
92 , m_init( false )
95 void FilePolicy::disposing()
97 m_userPermissions.clear();
98 m_defaultPermissions = Sequence< Any >();
99 m_xComponentContext.clear();
103 Sequence< Any > FilePolicy::getPermissions(
104 OUString const & userId )
106 if (! m_init)
108 refresh();
109 m_init = true;
112 MutexGuard guard( m_mutex );
113 t_permissions::iterator iFind( m_userPermissions.find( userId ) );
114 if (m_userPermissions.end() == iFind)
116 return Sequence< Any >();
118 else
120 return iFind->second;
124 Sequence< Any > FilePolicy::getDefaultPermissions()
126 if (! m_init)
128 refresh();
129 m_init = true;
132 MutexGuard guard( m_mutex );
133 return m_defaultPermissions;
137 class PolicyReader
139 OUString m_fileName;
140 oslFileHandle m_file;
142 sal_Int32 m_linepos;
143 rtl::ByteSequence m_line;
144 sal_Int32 m_pos;
145 sal_Unicode m_back;
147 sal_Unicode get();
148 void back( sal_Unicode c )
149 { m_back = c; }
151 static bool isWhiteSpace( sal_Unicode c )
152 { return (' ' == c || '\t' == c || '\n' == c || '\r' == c); }
153 void skipWhiteSpace();
155 static bool isCharToken( sal_Unicode c )
156 { return (';' == c || ',' == c || '{' == c || '}' == c); }
158 public:
159 PolicyReader( OUString const & file, AccessControl & ac );
160 ~PolicyReader();
162 void error( OUString const & msg );
164 OUString getToken();
165 OUString assureToken();
166 OUString getQuotedToken();
167 OUString assureQuotedToken();
168 void assureToken( sal_Unicode token );
171 void PolicyReader::assureToken( sal_Unicode token )
173 skipWhiteSpace();
174 sal_Unicode c = get();
175 if (c == token)
176 return;
177 OUStringBuffer buf( 16 );
178 buf.append( "expected >" );
179 buf.append( c );
180 buf.append( "<!" );
181 error( buf.makeStringAndClear() );
184 OUString PolicyReader::assureQuotedToken()
186 OUString token( getQuotedToken() );
187 if (token.isEmpty())
188 error( "unexpected end of file!" );
189 return token;
192 OUString PolicyReader::getQuotedToken()
194 skipWhiteSpace();
195 OUStringBuffer buf( 32 );
196 sal_Unicode c = get();
197 if ('\"' != c)
198 error( "expected quoting >\"< character!" );
199 c = get();
200 while ('\0' != c && '\"' != c)
202 buf.append( c );
203 c = get();
205 return buf.makeStringAndClear();
208 OUString PolicyReader::assureToken()
210 OUString token( getToken() );
211 if ( token.isEmpty())
212 error( "unexpected end of file!" );
213 return token;
216 OUString PolicyReader::getToken()
218 skipWhiteSpace();
219 sal_Unicode c = get();
220 if (isCharToken( c ))
221 return OUString( &c, 1 );
222 OUStringBuffer buf( 32 );
223 while ('\0' != c && !isCharToken( c ) && !isWhiteSpace( c ))
225 buf.append( c );
226 c = get();
228 back( c );
229 return buf.makeStringAndClear();
232 void PolicyReader::skipWhiteSpace()
234 sal_Unicode c;
237 c = get();
239 while (isWhiteSpace( c )); // seeking next non-whitespace char
241 if ('/' == c) // C/C++ like comment
243 c = get();
244 if ('/' == c) // C++ like comment
248 c = get();
250 while ('\n' != c && '\0' != c); // seek eol/eof
251 skipWhiteSpace(); // cont skip on next line
253 else if ('*' == c) // C like comment
255 bool fini = true;
258 c = get();
259 if ('*' == c)
261 c = get();
262 fini = ('/' == c || '\0' == c);
264 else
266 fini = ('\0' == c);
269 while (! fini);
270 skipWhiteSpace(); // cont skip on next line
272 else
274 error( "expected C/C++ like comment!" );
277 else if ('#' == c) // script like comment
281 c = get();
283 while ('\n' != c && '\0' != c); // seek eol/eof
284 skipWhiteSpace(); // cont skip on next line
287 else // is token char
289 back( c );
293 sal_Unicode PolicyReader::get()
295 if ('\0' != m_back) // one char push back possible
297 sal_Unicode c = m_back;
298 m_back = '\0';
299 return c;
301 else if (m_pos == m_line.getLength()) // provide newline as whitespace
303 ++m_pos;
304 return '\n';
306 else if (m_pos > m_line.getLength()) // read new line
308 sal_Bool eof;
309 oslFileError rc = ::osl_isEndOfFile( m_file, &eof );
310 if (osl_File_E_None != rc)
311 error( "checking eof failed!" );
312 if (eof)
313 return '\0';
315 rc = ::osl_readLine( m_file, reinterpret_cast< sal_Sequence ** >( &m_line ) );
316 if (osl_File_E_None != rc)
317 error( "read line failed!" );
318 ++m_linepos;
319 if (! m_line.getLength()) // empty line read
321 m_pos = 1; // read new line next time
322 return '\n';
324 m_pos = 0;
326 return (m_line.getConstArray()[ m_pos++ ]);
329 void PolicyReader::error( OUString const & msg )
331 throw RuntimeException(
332 "error processing file \"" + m_fileName +
333 "\" [line " + OUString::number(m_linepos) +
334 ", column " + OUString::number(m_pos) +
335 "] " + msg);
338 PolicyReader::PolicyReader( OUString const & fileName, AccessControl & ac )
339 : m_fileName( fileName )
340 , m_linepos( 0 )
341 , m_pos( 1 ) // force readline
342 , m_back( '\0' )
344 ac.checkFilePermission( m_fileName, "read" );
345 if (osl_File_E_None != ::osl_openFile( m_fileName.pData, &m_file, osl_File_OpenFlag_Read ))
347 throw RuntimeException( "cannot open file \"" + m_fileName + "\"!" );
351 PolicyReader::~PolicyReader()
353 if ( ::osl_closeFile( m_file ) != osl_File_E_None ) {
354 OSL_ASSERT( false );
358 #define s_grant "grant"
359 #define s_user "user"
360 #define s_permission "permission"
361 #define s_openBrace "{"
362 #define s_closingBrace "}"
364 #define s_filePermission "com.sun.star.io.FilePermission"
365 #define s_socketPermission "com.sun.star.connection.SocketPermission"
366 #define s_runtimePermission "com.sun.star.security.RuntimePermission"
367 #define s_allPermission "com.sun.star.security.AllPermission"
370 void FilePolicy::refresh()
372 // read out file (the .../file-name value had originally been set in
373 // cppu::add_access_control_entries (cppuhelper/source/servicefactory.cxx)
374 // depending on various UNO_AC* bootstrap variables that are no longer
375 // supported, so this is effectively dead code):
376 OUString fileName;
377 m_xComponentContext->getValueByName(
378 "/implementations/" IMPL_NAME "/file-name" ) >>= fileName;
379 if ( fileName.isEmpty() )
381 throw RuntimeException(
382 "name of policy file unknown!",
383 static_cast<OWeakObject *>(this) );
386 PolicyReader reader( fileName, m_ac );
388 // fill these two
389 Sequence< Any > defaultPermissions;
390 t_permissions userPermissions;
392 OUString token( reader.getToken() );
393 while (!token.isEmpty())
395 if ( token != s_grant )
396 reader.error( "expected >grant< token!" );
397 OUString userId;
398 token = reader.assureToken();
399 if ( token == s_user ) // next token is user-id
401 userId = reader.assureQuotedToken();
402 token = reader.assureToken();
404 if ( token != s_openBrace )
405 reader.error( "expected opening brace >{<!" );
406 token = reader.assureToken();
407 // permissions list
408 while ( token != s_closingBrace )
410 if ( token != s_permission )
411 reader.error( "expected >permission< or closing brace >}<!" );
413 token = reader.assureToken(); // permission type
414 Any perm;
415 if ( token == s_filePermission ) // FilePermission
417 OUString url( reader.assureQuotedToken() );
418 reader.assureToken( ',' );
419 OUString actions( reader.assureQuotedToken() );
420 perm <<= io::FilePermission( url, actions );
422 else if ( token == s_socketPermission ) // SocketPermission
424 OUString host( reader.assureQuotedToken() );
425 reader.assureToken( ',' );
426 OUString actions( reader.assureQuotedToken() );
427 perm <<= connection::SocketPermission( host, actions );
429 else if ( token == s_runtimePermission ) // RuntimePermission
431 OUString name( reader.assureQuotedToken() );
432 perm <<= security::RuntimePermission( name );
434 else if ( token == s_allPermission ) // AllPermission
436 perm <<= security::AllPermission();
438 else
440 reader.error( "expected permission type!" );
443 reader.assureToken( ';' );
445 // insert
446 if (!userId.isEmpty())
448 Sequence< Any > perms( userPermissions[ userId ] );
449 sal_Int32 len = perms.getLength();
450 perms.realloc( len +1 );
451 perms[ len ] = perm;
452 userPermissions[ userId ] = perms;
454 else
456 sal_Int32 len = defaultPermissions.getLength();
457 defaultPermissions.realloc( len +1 );
458 defaultPermissions[ len ] = perm;
461 token = reader.assureToken(); // next permissions token
464 reader.assureToken( ';' ); // semi
465 token = reader.getToken(); // next grant token
468 // assign new ones
469 MutexGuard guard( m_mutex );
470 m_defaultPermissions = defaultPermissions;
471 m_userPermissions = userPermissions;
475 OUString FilePolicy::getImplementationName()
477 return OUString(IMPL_NAME);
480 sal_Bool FilePolicy::supportsService( OUString const & serviceName )
482 return cppu::supportsService(this, serviceName);
485 Sequence< OUString > FilePolicy::getSupportedServiceNames()
487 Sequence<OUString> aSNS { "com.sun.star.security.Policy" };
488 return aSNS;
491 } // namespace
493 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
494 com_sun_star_security_comp_stoc_FilePolicy_get_implementation(
495 css::uno::XComponentContext *context,
496 css::uno::Sequence<css::uno::Any> const &)
498 return cppu::acquire(new FilePolicy(context));
501 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */