/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define IMPL_NAME "com.sun.star.security.comp.stoc.FilePolicy" using namespace ::osl; using namespace ::cppu; using namespace ::com::sun::star; using namespace css::uno; namespace { struct MutexHolder { Mutex m_mutex; }; typedef WeakComponentImplHelper< security::XPolicy, lang::XServiceInfo > t_helper; class FilePolicy : public MutexHolder , public t_helper { Reference< XComponentContext > m_xComponentContext; AccessControl m_ac; Sequence< Any > m_defaultPermissions; typedef std::unordered_map< OUString, Sequence< Any > > t_permissions; t_permissions m_userPermissions; bool m_init; protected: virtual void SAL_CALL disposing() override; public: explicit FilePolicy( Reference< XComponentContext > const & xComponentContext ); // XPolicy impl virtual Sequence< Any > SAL_CALL getPermissions( OUString const & userId ) override; virtual Sequence< Any > SAL_CALL getDefaultPermissions() override; virtual void SAL_CALL refresh() override; // XServiceInfo impl virtual OUString SAL_CALL getImplementationName() override; virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName ) override; virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; }; FilePolicy::FilePolicy( Reference< XComponentContext > const & xComponentContext ) : t_helper( m_mutex ) , m_xComponentContext( xComponentContext ) , m_ac( xComponentContext ) , m_init( false ) {} void FilePolicy::disposing() { m_userPermissions.clear(); m_defaultPermissions = Sequence< Any >(); m_xComponentContext.clear(); } Sequence< Any > FilePolicy::getPermissions( OUString const & userId ) { if (! m_init) { refresh(); m_init = true; } MutexGuard guard( m_mutex ); t_permissions::iterator iFind( m_userPermissions.find( userId ) ); if (m_userPermissions.end() == iFind) { return Sequence< Any >(); } else { return iFind->second; } } Sequence< Any > FilePolicy::getDefaultPermissions() { if (! m_init) { refresh(); m_init = true; } MutexGuard guard( m_mutex ); return m_defaultPermissions; } class PolicyReader { OUString m_fileName; oslFileHandle m_file; sal_Int32 m_linepos; rtl::ByteSequence m_line; sal_Int32 m_pos; sal_Unicode m_back; sal_Unicode get(); void back( sal_Unicode c ) { m_back = c; } static bool isWhiteSpace( sal_Unicode c ) { return (' ' == c || '\t' == c || '\n' == c || '\r' == c); } void skipWhiteSpace(); static bool isCharToken( sal_Unicode c ) { return (';' == c || ',' == c || '{' == c || '}' == c); } public: PolicyReader( OUString const & file, AccessControl & ac ); ~PolicyReader(); void error( OUString const & msg ); OUString getToken(); OUString assureToken(); OUString getQuotedToken(); OUString assureQuotedToken(); void assureToken( sal_Unicode token ); }; void PolicyReader::assureToken( sal_Unicode token ) { skipWhiteSpace(); sal_Unicode c = get(); if (c == token) return; OUString msg = "expected >" + OUStringChar(c) + "\"< character!" ); c = get(); while ('\0' != c && '\"' != c) { buf.append( c ); c = get(); } return buf.makeStringAndClear(); } OUString PolicyReader::assureToken() { OUString token( getToken() ); if ( token.isEmpty()) error( "unexpected end of file!" ); return token; } OUString PolicyReader::getToken() { skipWhiteSpace(); sal_Unicode c = get(); if (isCharToken( c )) return OUString( &c, 1 ); OUStringBuffer buf( 32 ); while ('\0' != c && !isCharToken( c ) && !isWhiteSpace( c )) { buf.append( c ); c = get(); } back( c ); return buf.makeStringAndClear(); } void PolicyReader::skipWhiteSpace() { sal_Unicode c; do { c = get(); } while (isWhiteSpace( c )); // seeking next non-whitespace char if ('/' == c) // C/C++ like comment { c = get(); if ('/' == c) // C++ like comment { do { c = get(); } while ('\n' != c && '\0' != c); // seek eol/eof skipWhiteSpace(); // cont skip on next line } else if ('*' == c) // C like comment { bool fini = true; do { c = get(); if ('*' == c) { c = get(); fini = ('/' == c || '\0' == c); } else { fini = ('\0' == c); } } while (! fini); skipWhiteSpace(); // cont skip on next line } else { error( "expected C/C++ like comment!" ); } } else if ('#' == c) // script like comment { do { c = get(); } while ('\n' != c && '\0' != c); // seek eol/eof skipWhiteSpace(); // cont skip on next line } else // is token char { back( c ); } } sal_Unicode PolicyReader::get() { if ('\0' != m_back) // one char push back possible { sal_Unicode c = m_back; m_back = '\0'; return c; } else if (m_pos == m_line.getLength()) // provide newline as whitespace { ++m_pos; return '\n'; } else if (m_pos > m_line.getLength()) // read new line { sal_Bool eof; oslFileError rc = ::osl_isEndOfFile( m_file, &eof ); if (osl_File_E_None != rc) error( "checking eof failed!" ); if (eof) return '\0'; rc = ::osl_readLine( m_file, reinterpret_cast< sal_Sequence ** >( &m_line ) ); if (osl_File_E_None != rc) error( "read line failed!" ); ++m_linepos; if (! m_line.getLength()) // empty line read { m_pos = 1; // read new line next time return '\n'; } m_pos = 0; } return (m_line.getConstArray()[ m_pos++ ]); } void PolicyReader::error( OUString const & msg ) { throw RuntimeException( "error processing file \"" + m_fileName + "\" [line " + OUString::number(m_linepos) + ", column " + OUString::number(m_pos) + "] " + msg); } PolicyReader::PolicyReader( OUString const & fileName, AccessControl & ac ) : m_fileName( fileName ) , m_linepos( 0 ) , m_pos( 1 ) // force readline , m_back( '\0' ) { ac.checkFilePermission( m_fileName, "read" ); if (osl_File_E_None != ::osl_openFile( m_fileName.pData, &m_file, osl_File_OpenFlag_Read )) { throw RuntimeException( "cannot open file \"" + m_fileName + "\"!" ); } } PolicyReader::~PolicyReader() { if ( ::osl_closeFile( m_file ) != osl_File_E_None ) { OSL_ASSERT( false ); } } #define s_grant "grant" #define s_user "user" #define s_permission "permission" #define s_openBrace "{" #define s_closingBrace "}" #define s_filePermission "com.sun.star.io.FilePermission" #define s_socketPermission "com.sun.star.connection.SocketPermission" #define s_runtimePermission "com.sun.star.security.RuntimePermission" #define s_allPermission "com.sun.star.security.AllPermission" void FilePolicy::refresh() { // read out file (the .../file-name value had originally been set in // cppu::add_access_control_entries (cppuhelper/source/servicefactory.cxx) // depending on various UNO_AC* bootstrap variables that are no longer // supported, so this is effectively dead code): OUString fileName; m_xComponentContext->getValueByName( "/implementations/" IMPL_NAME "/file-name" ) >>= fileName; if ( fileName.isEmpty() ) { throw RuntimeException( "name of policy file unknown!", static_cast(this) ); } PolicyReader reader( fileName, m_ac ); // fill these two Sequence< Any > defaultPermissions; t_permissions userPermissions; OUString token( reader.getToken() ); while (!token.isEmpty()) { if ( token != s_grant ) reader.error( "expected >grant< token!" ); OUString userId; token = reader.assureToken(); if ( token == s_user ) // next token is user-id { userId = reader.assureQuotedToken(); token = reader.assureToken(); } if ( token != s_openBrace ) reader.error( "expected opening brace >{permission< or closing brace >} perms( userPermissions[ userId ] ); sal_Int32 len = perms.getLength(); perms.realloc( len +1 ); perms[ len ] = perm; userPermissions[ userId ] = perms; } else { sal_Int32 len = defaultPermissions.getLength(); defaultPermissions.realloc( len +1 ); defaultPermissions[ len ] = perm; } token = reader.assureToken(); // next permissions token } reader.assureToken( ';' ); // semi token = reader.getToken(); // next grant token } // assign new ones MutexGuard guard( m_mutex ); m_defaultPermissions = defaultPermissions; m_userPermissions = userPermissions; } OUString FilePolicy::getImplementationName() { return IMPL_NAME; } sal_Bool FilePolicy::supportsService( OUString const & serviceName ) { return cppu::supportsService(this, serviceName); } Sequence< OUString > FilePolicy::getSupportedServiceNames() { return { "com.sun.star.security.Policy" }; } } // namespace extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_security_comp_stoc_FilePolicy_get_implementation( css::uno::XComponentContext *context, css::uno::Sequence const &) { return cppu::acquire(new FilePolicy(context)); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */