1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_stoc.hxx"
26 
27 #include <hash_map>
28 
29 #include <osl/diagnose.h>
30 #include <osl/file.h>
31 #include <rtl/byteseq.hxx>
32 #include <rtl/string.hxx>
33 #include <rtl/ustrbuf.hxx>
34 
35 #include <cppuhelper/access_control.hxx>
36 #include <cppuhelper/compbase2.hxx>
37 #include <cppuhelper/implementationentry.hxx>
38 
39 #include <com/sun/star/lang/XServiceInfo.hpp>
40 #include <com/sun/star/security/XAccessController.hpp>
41 #include <com/sun/star/security/XPolicy.hpp>
42 #include <com/sun/star/security/AllPermission.hpp>
43 #include <com/sun/star/security/RuntimePermission.hpp>
44 #include <com/sun/star/io/FilePermission.hpp>
45 #include <com/sun/star/connection/SocketPermission.hpp>
46 
47 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
48 #define SERVICE_NAME "com.sun.star.security.Policy"
49 #define IMPL_NAME "com.sun.star.security.comp.stoc.FilePolicy"
50 
51 
52 using namespace ::osl;
53 using namespace ::rtl;
54 using namespace ::cppu;
55 using namespace ::com::sun::star;
56 using namespace ::com::sun::star::uno;
57 
58 extern ::rtl_StandardModuleCount g_moduleCount;
59 
60 namespace stoc_sec
61 {
62 // static stuff initialized when loading lib
63 static OUString s_implName = OUSTR(IMPL_NAME);
64 static OUString s_serviceName = OUSTR(SERVICE_NAME);
65 
66 static Sequence< OUString > s_serviceNames = Sequence< OUString >( &s_serviceName, 1 );
67 //##################################################################################################
68 
69 //--------------------------------------------------------------------------------------------------
dispose(Reference<XInterface> const & x)70 static inline void dispose( Reference< XInterface > const & x )
71     SAL_THROW( (RuntimeException) )
72 {
73     Reference< lang::XComponent > xComp( x, UNO_QUERY );
74     if (xComp.is())
75     {
76         xComp->dispose();
77     }
78 }
79 
80 //##################################################################################################
81 
82 struct MutexHolder
83 {
84     Mutex m_mutex;
85 };
86 typedef WeakComponentImplHelper2< security::XPolicy, lang::XServiceInfo > t_helper;
87 
88 //==================================================================================================
89 class FilePolicy
90     : public MutexHolder
91     , public t_helper
92 {
93     Reference< XComponentContext > m_xComponentContext;
94     AccessControl m_ac;
95 
96     Sequence< Any > m_defaultPermissions;
97     typedef std::hash_map< OUString, Sequence< Any >, OUStringHash > t_permissions;
98     t_permissions m_userPermissions;
99     bool m_init;
100 
101 protected:
102     virtual void SAL_CALL disposing();
103 
104 public:
105     FilePolicy( Reference< XComponentContext > const & xComponentContext )
106         SAL_THROW( () );
107     virtual ~FilePolicy()
108         SAL_THROW( () );
109 
110     // XPolicy impl
111     virtual Sequence< Any > SAL_CALL getPermissions(
112         OUString const & userId )
113         throw (RuntimeException);
114     virtual Sequence< Any > SAL_CALL getDefaultPermissions()
115         throw (RuntimeException);
116     virtual void SAL_CALL refresh()
117         throw (RuntimeException);
118 
119     // XServiceInfo impl
120     virtual OUString SAL_CALL getImplementationName()
121         throw (RuntimeException);
122     virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName )
123         throw (RuntimeException);
124     virtual Sequence< OUString > SAL_CALL getSupportedServiceNames()
125         throw (RuntimeException);
126 };
127 //__________________________________________________________________________________________________
FilePolicy(Reference<XComponentContext> const & xComponentContext)128 FilePolicy::FilePolicy( Reference< XComponentContext > const & xComponentContext )
129     SAL_THROW( () )
130     : t_helper( m_mutex )
131     , m_xComponentContext( xComponentContext )
132     , m_ac( xComponentContext )
133     , m_init( false )
134 {
135     g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
136 }
137 //__________________________________________________________________________________________________
~FilePolicy()138 FilePolicy::~FilePolicy()
139     SAL_THROW( () )
140 {
141     g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
142 }
143 //__________________________________________________________________________________________________
disposing()144 void FilePolicy::disposing()
145 {
146     m_userPermissions.clear();
147     m_defaultPermissions = Sequence< Any >();
148     m_xComponentContext.clear();
149 }
150 
151 //__________________________________________________________________________________________________
getPermissions(OUString const & userId)152 Sequence< Any > FilePolicy::getPermissions(
153     OUString const & userId )
154     throw (RuntimeException)
155 {
156     if (! m_init)
157     {
158         refresh();
159         m_init = true;
160     }
161 
162     MutexGuard guard( m_mutex );
163     t_permissions::iterator iFind( m_userPermissions.find( userId ) );
164     if (m_userPermissions.end() == iFind)
165     {
166         return Sequence< Any >();
167     }
168     else
169     {
170         return iFind->second;
171     }
172 }
173 //__________________________________________________________________________________________________
getDefaultPermissions()174 Sequence< Any > FilePolicy::getDefaultPermissions()
175     throw (RuntimeException)
176 {
177     if (! m_init)
178     {
179         refresh();
180         m_init = true;
181     }
182 
183     MutexGuard guard( m_mutex );
184     return m_defaultPermissions;
185 }
186 
187 //==================================================================================================
188 class PolicyReader
189 {
190     OUString m_fileName;
191     oslFileHandle m_file;
192 
193     sal_Int32 m_linepos;
194     ByteSequence m_line;
195     sal_Int32 m_pos;
196     sal_Unicode m_back;
197 
198     sal_Unicode get()
199         SAL_THROW( (RuntimeException) );
back(sal_Unicode c)200     inline void back( sal_Unicode c ) SAL_THROW( () )
201         { m_back = c; }
202 
isWhiteSpace(sal_Unicode c)203     inline bool isWhiteSpace( sal_Unicode c ) SAL_THROW( () )
204         { return (' ' == c || '\t' == c || '\n' == c || '\r' == c); }
205     void skipWhiteSpace()
206         SAL_THROW( (RuntimeException) );
207 
isCharToken(sal_Unicode c)208     inline bool isCharToken( sal_Unicode c ) SAL_THROW( () )
209         { return (';' == c || ',' == c || '{' == c || '}' == c); }
210 
211 public:
212     PolicyReader( OUString const & file, AccessControl & ac )
213         SAL_THROW( (RuntimeException) );
214     ~PolicyReader()
215         SAL_THROW( () );
216 
217     void error( OUString const & msg )
218         SAL_THROW( (RuntimeException) );
219 
220     OUString getToken()
221         SAL_THROW( (RuntimeException) );
222     OUString assureToken()
223         SAL_THROW( (RuntimeException) );
224     OUString getQuotedToken()
225         SAL_THROW( (RuntimeException) );
226     OUString assureQuotedToken()
227         SAL_THROW( (RuntimeException) );
228     void assureToken( sal_Unicode token )
229         SAL_THROW( (RuntimeException) );
230 };
231 //__________________________________________________________________________________________________
assureToken(sal_Unicode token)232 void PolicyReader::assureToken( sal_Unicode token )
233     SAL_THROW( (RuntimeException) )
234 {
235     skipWhiteSpace();
236     sal_Unicode c = get();
237     if (c == token)
238         return;
239     OUStringBuffer buf( 16 );
240     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("expected >") );
241     buf.append( c );
242     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("<!") );
243     error( buf.makeStringAndClear() );
244 }
245 //__________________________________________________________________________________________________
assureQuotedToken()246 OUString PolicyReader::assureQuotedToken()
247     SAL_THROW( (RuntimeException) )
248 {
249     OUString token( getQuotedToken() );
250     if (! token.getLength())
251         error( OUSTR("unexpected end of file!") );
252     return token;
253 }
254 //__________________________________________________________________________________________________
getQuotedToken()255 OUString PolicyReader::getQuotedToken()
256     SAL_THROW( (RuntimeException) )
257 {
258     skipWhiteSpace();
259     OUStringBuffer buf( 32 );
260     sal_Unicode c = get();
261     if ('\"' != c)
262         error( OUSTR("expected quoting >\"< character!") );
263     c = get();
264     while ('\0' != c && '\"' != c)
265     {
266         buf.append( c );
267         c = get();
268     }
269     return buf.makeStringAndClear();
270 }
271 //__________________________________________________________________________________________________
assureToken()272 OUString PolicyReader::assureToken()
273     SAL_THROW( (RuntimeException) )
274 {
275     OUString token( getToken() );
276     if (! token.getLength())
277         error( OUSTR("unexpected end of file!") );
278     return token;
279 }
280 //__________________________________________________________________________________________________
getToken()281 OUString PolicyReader::getToken()
282     SAL_THROW( (RuntimeException) )
283 {
284     skipWhiteSpace();
285     sal_Unicode c = get();
286     if (isCharToken( c ))
287         return OUString( &c, 1 );
288     OUStringBuffer buf( 32 );
289     while ('\0' != c && !isCharToken( c ) && !isWhiteSpace( c ))
290     {
291         buf.append( c );
292         c = get();
293     }
294     back( c );
295     return buf.makeStringAndClear();
296 }
297 //__________________________________________________________________________________________________
skipWhiteSpace()298 void PolicyReader::skipWhiteSpace()
299     SAL_THROW( (RuntimeException) )
300 {
301     sal_Unicode c;
302     do
303     {
304         c = get();
305     }
306     while (isWhiteSpace( c )); // seeking next non-whitespace char
307 
308     if ('/' == c) // C/C++ like comment
309     {
310         c = get();
311         if ('/' == c) // C++ like comment
312         {
313             do
314             {
315                 c = get();
316             }
317             while ('\n' != c && '\0' != c); // seek eol/eof
318             skipWhiteSpace(); // cont skip on next line
319         }
320         else if ('*' == c) // C like comment
321         {
322             bool fini = true;
323             do
324             {
325                 c = get();
326                 if ('*' == c)
327                 {
328                     c = get();
329                     fini = ('/' == c || '\0' == c);
330                 }
331                 else
332                 {
333                     fini = ('\0' == c);
334                 }
335             }
336             while (! fini);
337             skipWhiteSpace(); // cont skip on next line
338         }
339         else
340         {
341             error( OUSTR("expected C/C++ like comment!") );
342         }
343     }
344     else if ('#' == c) // script like comment
345     {
346         do
347         {
348             c = get();
349         }
350         while ('\n' != c && '\0' != c); // seek eol/eof
351         skipWhiteSpace(); // cont skip on next line
352     }
353 
354     else // is token char
355     {
356         back( c );
357     }
358 }
359 //__________________________________________________________________________________________________
get()360 sal_Unicode PolicyReader::get()
361     SAL_THROW( (RuntimeException) )
362 {
363     if ('\0' != m_back) // one char push back possible
364     {
365         sal_Unicode c = m_back;
366         m_back = '\0';
367         return c;
368     }
369     else if (m_pos == m_line.getLength()) // provide newline as whitespace
370     {
371         ++m_pos;
372         return '\n';
373     }
374     else if (m_pos > m_line.getLength()) // read new line
375     {
376         sal_Bool eof;
377         oslFileError rc = ::osl_isEndOfFile( m_file, &eof );
378         if (osl_File_E_None != rc)
379             error( OUSTR("checking eof failed!") );
380         if (eof)
381             return '\0';
382 
383         rc = ::osl_readLine( m_file, reinterpret_cast< sal_Sequence ** >( &m_line ) );
384         if (osl_File_E_None != rc)
385             error( OUSTR("read line failed!") );
386         ++m_linepos;
387         if (! m_line.getLength()) // empty line read
388         {
389             m_pos = 1; // read new line next time
390             return '\n';
391         }
392         m_pos = 0;
393     }
394     return (m_line.getConstArray()[ m_pos++ ]);
395 }
396 //__________________________________________________________________________________________________
error(OUString const & msg)397 void PolicyReader::error( OUString const & msg )
398     SAL_THROW( (RuntimeException) )
399 {
400     OUStringBuffer buf( 32 );
401     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("error processing file \"") );
402     buf.append( m_fileName );
403     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\" [line ") );
404     buf.append( m_linepos );
405     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", column ") );
406     buf.append( m_pos );
407     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] ") );
408     buf.append( msg );
409     throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface >() );
410 }
411 //__________________________________________________________________________________________________
PolicyReader(OUString const & fileName,AccessControl & ac)412 PolicyReader::PolicyReader( OUString const & fileName, AccessControl & ac )
413     SAL_THROW( (RuntimeException) )
414     : m_fileName( fileName )
415     , m_linepos( 0 )
416     , m_pos( 1 ) // force readline
417     , m_back( '\0' )
418 {
419     ac.checkFilePermission( m_fileName, OUSTR("read") );
420     if (osl_File_E_None != ::osl_openFile( m_fileName.pData, &m_file, osl_File_OpenFlag_Read ))
421     {
422         OUStringBuffer buf( 32 );
423         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("cannot open file \"") );
424         buf.append( m_fileName );
425         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"!") );
426         throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface >() );
427     }
428 }
429 //__________________________________________________________________________________________________
~PolicyReader()430 PolicyReader::~PolicyReader()
431     SAL_THROW( () )
432 {
433     if ( ::osl_closeFile( m_file ) != osl_File_E_None ) {
434         OSL_ASSERT( false );
435     }
436 }
437 
438 static OUString s_grant = OUSTR("grant");
439 static OUString s_user = OUSTR("user");
440 static OUString s_permission = OUSTR("permission");
441 static OUString s_openBrace = OUSTR("{");
442 static OUString s_closingBrace = OUSTR("}");
443 
444 static OUString s_filePermission = OUSTR("com.sun.star.io.FilePermission");
445 static OUString s_socketPermission = OUSTR("com.sun.star.connection.SocketPermission");
446 static OUString s_runtimePermission = OUSTR("com.sun.star.security.RuntimePermission");
447 static OUString s_allPermission = OUSTR("com.sun.star.security.AllPermission");
448 
449 //__________________________________________________________________________________________________
refresh()450 void FilePolicy::refresh()
451     throw (RuntimeException)
452 {
453     // read out file
454     OUString fileName;
455     m_xComponentContext->getValueByName(
456         OUSTR("/implementations/" IMPL_NAME "/file-name") ) >>= fileName;
457     if (! fileName.getLength())
458     {
459         throw RuntimeException(
460             OUSTR("name of policy file unknown!"),
461             (OWeakObject *)this );
462     }
463 
464     PolicyReader reader( fileName, m_ac );
465 
466     // fill these two
467     Sequence< Any > defaultPermissions;
468     t_permissions userPermissions;
469 
470     OUString token( reader.getToken() );
471     while (token.getLength())
472     {
473         if (! token.equals( s_grant ))
474             reader.error( OUSTR("expected >grant< token!") );
475         OUString userId;
476         token = reader.assureToken();
477         if (token.equals( s_user )) // next token is user-id
478         {
479             userId = reader.assureQuotedToken();
480             token = reader.assureToken();
481         }
482         if (! token.equals( s_openBrace ))
483             reader.error( OUSTR("expected opening brace >{<!") );
484         token = reader.assureToken();
485         // permissions list
486         while (! token.equals( s_closingBrace ))
487         {
488             if (! token.equals( s_permission ))
489                 reader.error( OUSTR("expected >permission< or closing brace >}<!") );
490 
491             token = reader.assureToken(); // permission type
492             Any perm;
493             if (token.equals( s_filePermission )) // FilePermission
494             {
495                 OUString url( reader.assureQuotedToken() );
496                 reader.assureToken( ',' );
497                 OUString actions( reader.assureQuotedToken() );
498                 perm <<= io::FilePermission( url, actions );
499             }
500             else if (token.equals( s_socketPermission )) // SocketPermission
501             {
502                 OUString host( reader.assureQuotedToken() );
503                 reader.assureToken( ',' );
504                 OUString actions( reader.assureQuotedToken() );
505                 perm <<= connection::SocketPermission( host, actions );
506             }
507             else if (token.equals( s_runtimePermission )) // RuntimePermission
508             {
509                 OUString name( reader.assureQuotedToken() );
510                 perm <<= security::RuntimePermission( name );
511             }
512             else if (token.equals( s_allPermission )) // AllPermission
513             {
514                 perm <<= security::AllPermission();
515             }
516             else
517             {
518                 reader.error( OUSTR("expected permission type!") );
519             }
520 
521             reader.assureToken( ';' );
522 
523             // insert
524             if (userId.getLength())
525             {
526                 Sequence< Any > perms( userPermissions[ userId ] );
527                 sal_Int32 len = perms.getLength();
528                 perms.realloc( len +1 );
529                 perms[ len ] = perm;
530                 userPermissions[ userId ] = perms;
531             }
532             else
533             {
534                 sal_Int32 len = defaultPermissions.getLength();
535                 defaultPermissions.realloc( len +1 );
536                 defaultPermissions[ len ] = perm;
537             }
538 
539             token = reader.assureToken(); // next permissions token
540         }
541 
542         reader.assureToken( ';' ); // semi
543         token = reader.getToken(); // next grant token
544     }
545 
546     // assign new ones
547     MutexGuard guard( m_mutex );
548     m_defaultPermissions = defaultPermissions;
549     m_userPermissions = userPermissions;
550 }
551 
552 //__________________________________________________________________________________________________
getImplementationName()553 OUString FilePolicy::getImplementationName()
554     throw (RuntimeException)
555 {
556     return s_implName;
557 }
558 //__________________________________________________________________________________________________
supportsService(OUString const & serviceName)559 sal_Bool FilePolicy::supportsService( OUString const & serviceName )
560     throw (RuntimeException)
561 {
562     OUString const * pNames = s_serviceNames.getConstArray();
563     for ( sal_Int32 nPos = s_serviceNames.getLength(); nPos--; )
564     {
565         if (serviceName.equals( pNames[ nPos ] ))
566         {
567             return sal_True;
568         }
569     }
570     return sal_False;
571 }
572 //__________________________________________________________________________________________________
getSupportedServiceNames()573 Sequence< OUString > FilePolicy::getSupportedServiceNames()
574     throw (RuntimeException)
575 {
576     return s_serviceNames;
577 }
578 }
579 //##################################################################################################
580 namespace stoc_bootstrap
581 {
582 //--------------------------------------------------------------------------------------------------
filepolicy_create(Reference<XComponentContext> const & xComponentContext)583 Reference< XInterface > SAL_CALL filepolicy_create(
584     Reference< XComponentContext > const & xComponentContext )
585     SAL_THROW( (Exception) )
586 {
587     return (OWeakObject *)new stoc_sec::FilePolicy( xComponentContext );
588 }
589 //--------------------------------------------------------------------------------------------------
filepolicy_getSupportedServiceNames()590 Sequence< OUString > filepolicy_getSupportedServiceNames() SAL_THROW( () )
591 {
592     return stoc_sec::s_serviceNames;
593 }
594 //--------------------------------------------------------------------------------------------------
filepolicy_getImplementationName()595 OUString filepolicy_getImplementationName() SAL_THROW( () )
596 {
597     return stoc_sec::s_implName;
598 }
599 }
600