xref: /trunk/main/stoc/source/security/file_policy.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 {
72     Reference< lang::XComponent > xComp( x, UNO_QUERY );
73     if (xComp.is())
74     {
75         xComp->dispose();
76     }
77 }
78 
79 //##################################################################################################
80 
81 struct MutexHolder
82 {
83     Mutex m_mutex;
84 };
85 typedef WeakComponentImplHelper2< security::XPolicy, lang::XServiceInfo > t_helper;
86 
87 //==================================================================================================
88 class FilePolicy
89     : public MutexHolder
90     , public t_helper
91 {
92     Reference< XComponentContext > m_xComponentContext;
93     AccessControl m_ac;
94 
95     Sequence< Any > m_defaultPermissions;
96     typedef std::hash_map< OUString, Sequence< Any >, OUStringHash > t_permissions;
97     t_permissions m_userPermissions;
98     bool m_init;
99 
100 protected:
101     virtual void SAL_CALL disposing();
102 
103 public:
104     FilePolicy( Reference< XComponentContext > const & xComponentContext )
105         SAL_THROW( () );
106     virtual ~FilePolicy()
107         SAL_THROW( () );
108 
109     // XPolicy impl
110     virtual Sequence< Any > SAL_CALL getPermissions(
111         OUString const & userId );
112     virtual Sequence< Any > SAL_CALL getDefaultPermissions();
113     virtual void SAL_CALL refresh();
114 
115     // XServiceInfo impl
116     virtual OUString SAL_CALL getImplementationName();
117     virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName );
118     virtual Sequence< OUString > SAL_CALL getSupportedServiceNames();
119 };
120 //__________________________________________________________________________________________________
FilePolicy(Reference<XComponentContext> const & xComponentContext)121 FilePolicy::FilePolicy( Reference< XComponentContext > const & xComponentContext )
122     SAL_THROW( () )
123     : t_helper( m_mutex )
124     , m_xComponentContext( xComponentContext )
125     , m_ac( xComponentContext )
126     , m_init( false )
127 {
128     g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
129 }
130 //__________________________________________________________________________________________________
~FilePolicy()131 FilePolicy::~FilePolicy()
132     SAL_THROW( () )
133 {
134     g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
135 }
136 //__________________________________________________________________________________________________
disposing()137 void FilePolicy::disposing()
138 {
139     m_userPermissions.clear();
140     m_defaultPermissions = Sequence< Any >();
141     m_xComponentContext.clear();
142 }
143 
144 //__________________________________________________________________________________________________
getPermissions(OUString const & userId)145 Sequence< Any > FilePolicy::getPermissions(
146     OUString const & userId )
147 {
148     if (! m_init)
149     {
150         refresh();
151         m_init = true;
152     }
153 
154     MutexGuard guard( m_mutex );
155     t_permissions::iterator iFind( m_userPermissions.find( userId ) );
156     if (m_userPermissions.end() == iFind)
157     {
158         return Sequence< Any >();
159     }
160     else
161     {
162         return iFind->second;
163     }
164 }
165 //__________________________________________________________________________________________________
getDefaultPermissions()166 Sequence< Any > FilePolicy::getDefaultPermissions()
167 {
168     if (! m_init)
169     {
170         refresh();
171         m_init = true;
172     }
173 
174     MutexGuard guard( m_mutex );
175     return m_defaultPermissions;
176 }
177 
178 //==================================================================================================
179 class PolicyReader
180 {
181     OUString m_fileName;
182     oslFileHandle m_file;
183 
184     sal_Int32 m_linepos;
185     ByteSequence m_line;
186     sal_Int32 m_pos;
187     sal_Unicode m_back;
188 
189     sal_Unicode get();
back(sal_Unicode c)190     inline void back( sal_Unicode c ) SAL_THROW( () )
191         { m_back = c; }
192 
isWhiteSpace(sal_Unicode c)193     inline bool isWhiteSpace( sal_Unicode c ) SAL_THROW( () )
194         { return (' ' == c || '\t' == c || '\n' == c || '\r' == c); }
195     void skipWhiteSpace();
196 
isCharToken(sal_Unicode c)197     inline bool isCharToken( sal_Unicode c ) SAL_THROW( () )
198         { return (';' == c || ',' == c || '{' == c || '}' == c); }
199 
200 public:
201     PolicyReader( OUString const & file, AccessControl & ac );
202     ~PolicyReader()
203         SAL_THROW( () );
204 
205     void error( OUString const & msg );
206 
207     OUString getToken();
208     OUString assureToken();
209     OUString getQuotedToken();
210     OUString assureQuotedToken();
211     void assureToken( sal_Unicode token );
212 };
213 //__________________________________________________________________________________________________
assureToken(sal_Unicode token)214 void PolicyReader::assureToken( sal_Unicode token )
215 {
216     skipWhiteSpace();
217     sal_Unicode c = get();
218     if (c == token)
219         return;
220     OUStringBuffer buf( 16 );
221     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("expected >") );
222     buf.append( c );
223     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("<!") );
224     error( buf.makeStringAndClear() );
225 }
226 //__________________________________________________________________________________________________
assureQuotedToken()227 OUString PolicyReader::assureQuotedToken()
228 {
229     OUString token( getQuotedToken() );
230     if (! token.getLength())
231         error( OUSTR("unexpected end of file!") );
232     return token;
233 }
234 //__________________________________________________________________________________________________
getQuotedToken()235 OUString PolicyReader::getQuotedToken()
236 {
237     skipWhiteSpace();
238     OUStringBuffer buf( 32 );
239     sal_Unicode c = get();
240     if ('\"' != c)
241         error( OUSTR("expected quoting >\"< character!") );
242     c = get();
243     while ('\0' != c && '\"' != c)
244     {
245         buf.append( c );
246         c = get();
247     }
248     return buf.makeStringAndClear();
249 }
250 //__________________________________________________________________________________________________
assureToken()251 OUString PolicyReader::assureToken()
252 {
253     OUString token( getToken() );
254     if (! token.getLength())
255         error( OUSTR("unexpected end of file!") );
256     return token;
257 }
258 //__________________________________________________________________________________________________
getToken()259 OUString PolicyReader::getToken()
260 {
261     skipWhiteSpace();
262     sal_Unicode c = get();
263     if (isCharToken( c ))
264         return OUString( &c, 1 );
265     OUStringBuffer buf( 32 );
266     while ('\0' != c && !isCharToken( c ) && !isWhiteSpace( c ))
267     {
268         buf.append( c );
269         c = get();
270     }
271     back( c );
272     return buf.makeStringAndClear();
273 }
274 //__________________________________________________________________________________________________
skipWhiteSpace()275 void PolicyReader::skipWhiteSpace()
276 {
277     sal_Unicode c;
278     do
279     {
280         c = get();
281     }
282     while (isWhiteSpace( c )); // seeking next non-whitespace char
283 
284     if ('/' == c) // C/C++ like comment
285     {
286         c = get();
287         if ('/' == c) // C++ like comment
288         {
289             do
290             {
291                 c = get();
292             }
293             while ('\n' != c && '\0' != c); // seek eol/eof
294             skipWhiteSpace(); // cont skip on next line
295         }
296         else if ('*' == c) // C like comment
297         {
298             bool fini = true;
299             do
300             {
301                 c = get();
302                 if ('*' == c)
303                 {
304                     c = get();
305                     fini = ('/' == c || '\0' == c);
306                 }
307                 else
308                 {
309                     fini = ('\0' == c);
310                 }
311             }
312             while (! fini);
313             skipWhiteSpace(); // cont skip on next line
314         }
315         else
316         {
317             error( OUSTR("expected C/C++ like comment!") );
318         }
319     }
320     else if ('#' == c) // script like comment
321     {
322         do
323         {
324             c = get();
325         }
326         while ('\n' != c && '\0' != c); // seek eol/eof
327         skipWhiteSpace(); // cont skip on next line
328     }
329 
330     else // is token char
331     {
332         back( c );
333     }
334 }
335 //__________________________________________________________________________________________________
get()336 sal_Unicode PolicyReader::get()
337 {
338     if ('\0' != m_back) // one char push back possible
339     {
340         sal_Unicode c = m_back;
341         m_back = '\0';
342         return c;
343     }
344     else if (m_pos == m_line.getLength()) // provide newline as whitespace
345     {
346         ++m_pos;
347         return '\n';
348     }
349     else if (m_pos > m_line.getLength()) // read new line
350     {
351         sal_Bool eof;
352         oslFileError rc = ::osl_isEndOfFile( m_file, &eof );
353         if (osl_File_E_None != rc)
354             error( OUSTR("checking eof failed!") );
355         if (eof)
356             return '\0';
357 
358         rc = ::osl_readLine( m_file, reinterpret_cast< sal_Sequence ** >( &m_line ) );
359         if (osl_File_E_None != rc)
360             error( OUSTR("read line failed!") );
361         ++m_linepos;
362         if (! m_line.getLength()) // empty line read
363         {
364             m_pos = 1; // read new line next time
365             return '\n';
366         }
367         m_pos = 0;
368     }
369     return (m_line.getConstArray()[ m_pos++ ]);
370 }
371 //__________________________________________________________________________________________________
error(OUString const & msg)372 void PolicyReader::error( OUString const & msg )
373 {
374     OUStringBuffer buf( 32 );
375     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("error processing file \"") );
376     buf.append( m_fileName );
377     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\" [line ") );
378     buf.append( m_linepos );
379     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", column ") );
380     buf.append( m_pos );
381     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] ") );
382     buf.append( msg );
383     throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface >() );
384 }
385 //__________________________________________________________________________________________________
PolicyReader(OUString const & fileName,AccessControl & ac)386 PolicyReader::PolicyReader( OUString const & fileName, AccessControl & ac )
387     : m_fileName( fileName )
388     , m_linepos( 0 )
389     , m_pos( 1 ) // force readline
390     , m_back( '\0' )
391 {
392     ac.checkFilePermission( m_fileName, OUSTR("read") );
393     if (osl_File_E_None != ::osl_openFile( m_fileName.pData, &m_file, osl_File_OpenFlag_Read ))
394     {
395         OUStringBuffer buf( 32 );
396         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("cannot open file \"") );
397         buf.append( m_fileName );
398         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"!") );
399         throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface >() );
400     }
401 }
402 //__________________________________________________________________________________________________
~PolicyReader()403 PolicyReader::~PolicyReader()
404     SAL_THROW( () )
405 {
406     if ( ::osl_closeFile( m_file ) != osl_File_E_None ) {
407         OSL_ASSERT( false );
408     }
409 }
410 
411 static OUString s_grant = OUSTR("grant");
412 static OUString s_user = OUSTR("user");
413 static OUString s_permission = OUSTR("permission");
414 static OUString s_openBrace = OUSTR("{");
415 static OUString s_closingBrace = OUSTR("}");
416 
417 static OUString s_filePermission = OUSTR("com.sun.star.io.FilePermission");
418 static OUString s_socketPermission = OUSTR("com.sun.star.connection.SocketPermission");
419 static OUString s_runtimePermission = OUSTR("com.sun.star.security.RuntimePermission");
420 static OUString s_allPermission = OUSTR("com.sun.star.security.AllPermission");
421 
422 //__________________________________________________________________________________________________
refresh()423 void FilePolicy::refresh()
424 {
425     // read out file
426     OUString fileName;
427     m_xComponentContext->getValueByName(
428         OUSTR("/implementations/" IMPL_NAME "/file-name") ) >>= fileName;
429     if (! fileName.getLength())
430     {
431         throw RuntimeException(
432             OUSTR("name of policy file unknown!"),
433             (OWeakObject *)this );
434     }
435 
436     PolicyReader reader( fileName, m_ac );
437 
438     // fill these two
439     Sequence< Any > defaultPermissions;
440     t_permissions userPermissions;
441 
442     OUString token( reader.getToken() );
443     while (token.getLength())
444     {
445         if (! token.equals( s_grant ))
446             reader.error( OUSTR("expected >grant< token!") );
447         OUString userId;
448         token = reader.assureToken();
449         if (token.equals( s_user )) // next token is user-id
450         {
451             userId = reader.assureQuotedToken();
452             token = reader.assureToken();
453         }
454         if (! token.equals( s_openBrace ))
455             reader.error( OUSTR("expected opening brace >{<!") );
456         token = reader.assureToken();
457         // permissions list
458         while (! token.equals( s_closingBrace ))
459         {
460             if (! token.equals( s_permission ))
461                 reader.error( OUSTR("expected >permission< or closing brace >}<!") );
462 
463             token = reader.assureToken(); // permission type
464             Any perm;
465             if (token.equals( s_filePermission )) // FilePermission
466             {
467                 OUString url( reader.assureQuotedToken() );
468                 reader.assureToken( ',' );
469                 OUString actions( reader.assureQuotedToken() );
470                 perm <<= io::FilePermission( url, actions );
471             }
472             else if (token.equals( s_socketPermission )) // SocketPermission
473             {
474                 OUString host( reader.assureQuotedToken() );
475                 reader.assureToken( ',' );
476                 OUString actions( reader.assureQuotedToken() );
477                 perm <<= connection::SocketPermission( host, actions );
478             }
479             else if (token.equals( s_runtimePermission )) // RuntimePermission
480             {
481                 OUString name( reader.assureQuotedToken() );
482                 perm <<= security::RuntimePermission( name );
483             }
484             else if (token.equals( s_allPermission )) // AllPermission
485             {
486                 perm <<= security::AllPermission();
487             }
488             else
489             {
490                 reader.error( OUSTR("expected permission type!") );
491             }
492 
493             reader.assureToken( ';' );
494 
495             // insert
496             if (userId.getLength())
497             {
498                 Sequence< Any > perms( userPermissions[ userId ] );
499                 sal_Int32 len = perms.getLength();
500                 perms.realloc( len +1 );
501                 perms[ len ] = perm;
502                 userPermissions[ userId ] = perms;
503             }
504             else
505             {
506                 sal_Int32 len = defaultPermissions.getLength();
507                 defaultPermissions.realloc( len +1 );
508                 defaultPermissions[ len ] = perm;
509             }
510 
511             token = reader.assureToken(); // next permissions token
512         }
513 
514         reader.assureToken( ';' ); // semi
515         token = reader.getToken(); // next grant token
516     }
517 
518     // assign new ones
519     MutexGuard guard( m_mutex );
520     m_defaultPermissions = defaultPermissions;
521     m_userPermissions = userPermissions;
522 }
523 
524 //__________________________________________________________________________________________________
getImplementationName()525 OUString FilePolicy::getImplementationName()
526 {
527     return s_implName;
528 }
529 //__________________________________________________________________________________________________
supportsService(OUString const & serviceName)530 sal_Bool FilePolicy::supportsService( OUString const & serviceName )
531 {
532     OUString const * pNames = s_serviceNames.getConstArray();
533     for ( sal_Int32 nPos = s_serviceNames.getLength(); nPos--; )
534     {
535         if (serviceName.equals( pNames[ nPos ] ))
536         {
537             return sal_True;
538         }
539     }
540     return sal_False;
541 }
542 //__________________________________________________________________________________________________
getSupportedServiceNames()543 Sequence< OUString > FilePolicy::getSupportedServiceNames()
544 {
545     return s_serviceNames;
546 }
547 }
548 //##################################################################################################
549 namespace stoc_bootstrap
550 {
551 //--------------------------------------------------------------------------------------------------
filepolicy_create(Reference<XComponentContext> const & xComponentContext)552 Reference< XInterface > SAL_CALL filepolicy_create(
553     Reference< XComponentContext > const & xComponentContext )
554 {
555     return (OWeakObject *)new stoc_sec::FilePolicy( xComponentContext );
556 }
557 //--------------------------------------------------------------------------------------------------
filepolicy_getSupportedServiceNames()558 Sequence< OUString > filepolicy_getSupportedServiceNames() SAL_THROW( () )
559 {
560     return stoc_sec::s_serviceNames;
561 }
562 //--------------------------------------------------------------------------------------------------
filepolicy_getImplementationName()563 OUString filepolicy_getImplementationName() SAL_THROW( () )
564 {
565     return stoc_sec::s_implName;
566 }
567 }
568