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