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