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