1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: permissions.cxx,v $
10 * $Revision: 1.11.16.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_stoc.hxx"
36 #include <osl/process.h>
37 #include <osl/socket.hxx>
38 #include <osl/mutex.hxx>
40 #include <rtl/string.hxx>
41 #include <rtl/ustrbuf.hxx>
43 #include <com/sun/star/security/RuntimePermission.hpp>
44 #include <com/sun/star/security/AllPermission.hpp>
45 #include <com/sun/star/io/FilePermission.hpp>
46 #include <com/sun/star/connection/SocketPermission.hpp>
47 #include <com/sun/star/security/AccessControlException.hpp>
49 #include "permissions.h"
51 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
54 using namespace ::std
;
55 using namespace ::osl
;
56 using namespace ::com::sun::star
;
57 using namespace ::com::sun::star::uno
;
58 using ::rtl::OUString
;
59 using ::rtl::OUStringBuffer
;
64 //--------------------------------------------------------------------------------------------------
65 static inline sal_Int32
makeMask(
66 OUString
const & items
, char const * const * strings
) SAL_THROW( () )
73 OUString
item( items
.getToken( 0, ',', n
).trim() );
74 if (! item
.getLength())
77 while (strings
[ nPos
])
79 if (item
.equalsAscii( strings
[ nPos
] ))
81 mask
|= (0x80000000 >> nPos
);
86 #if OSL_DEBUG_LEVEL > 0
87 if (! strings
[ nPos
])
89 OUStringBuffer
buf( 48 );
90 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("### ignoring unknown socket action: ") );
92 ::rtl::OString
str( ::rtl::OUStringToOString(
93 buf
.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US
) );
94 OSL_TRACE( str
.getStr() );
98 while (n
>= 0); // all items
101 //--------------------------------------------------------------------------------------------------
102 static inline OUString
makeStrings(
103 sal_Int32 mask
, char const * const * strings
) SAL_THROW( () )
105 OUStringBuffer
buf( 48 );
108 if (0x80000000 & mask
)
110 buf
.appendAscii( *strings
);
111 if (mask
<< 1) // more items following
112 buf
.append( (sal_Unicode
)',' );
117 return buf
.makeStringAndClear();
120 //##################################################################################################
122 //==================================================================================================
123 class SocketPermission
: public Permission
125 static char const * s_actions
[];
129 sal_Int32 m_lowerPort
;
130 sal_Int32 m_upperPort
;
131 mutable OUString m_ip
;
132 mutable bool m_resolveErr
;
133 mutable bool m_resolvedHost
;
136 inline bool resolveHost() const SAL_THROW( () );
140 connection::SocketPermission
const & perm
,
141 ::rtl::Reference
< Permission
> const & next
= ::rtl::Reference
< Permission
>() )
143 virtual bool implies( Permission
const & perm
) const SAL_THROW( () );
144 virtual OUString
toString() const SAL_THROW( () );
146 //__________________________________________________________________________________________________
147 char const * SocketPermission::s_actions
[] = { "accept", "connect", "listen", "resolve", 0 };
148 //__________________________________________________________________________________________________
149 SocketPermission::SocketPermission(
150 connection::SocketPermission
const & perm
,
151 ::rtl::Reference
< Permission
> const & next
)
153 : Permission( SOCKET
, next
)
154 , m_actions( makeMask( perm
.Actions
, s_actions
) )
155 , m_host( perm
.Host
)
157 , m_upperPort( 65535 )
158 , m_resolveErr( false )
159 , m_resolvedHost( false )
160 , m_wildCardHost( perm
.Host
.getLength() && '*' == perm
.Host
.pData
->buffer
[ 0 ] )
162 if (0xe0000000 & m_actions
) // if any (except resolve) is given => resolve implied
163 m_actions
|= 0x10000000;
165 // separate host from portrange
166 sal_Int32 colon
= m_host
.indexOf( ':' );
167 if (colon
>= 0) // port [range] given
169 sal_Int32 minus
= m_host
.indexOf( '-', colon
+1 );
172 m_lowerPort
= m_upperPort
= m_host
.copy( colon
+1 ).toInt32();
174 else if (minus
== (colon
+1)) // -N
176 m_upperPort
= m_host
.copy( minus
+1 ).toInt32();
178 else if (minus
== (m_host
.getLength() -1)) // N-
180 m_lowerPort
= m_host
.copy( colon
+1, m_host
.getLength() -1 -colon
-1 ).toInt32();
184 m_lowerPort
= m_host
.copy( colon
+1, minus
- colon
-1 ).toInt32();
185 m_upperPort
= m_host
.copy( minus
+1, m_host
.getLength() -minus
-1 ).toInt32();
187 m_host
= m_host
.copy( 0, colon
);
190 //__________________________________________________________________________________________________
191 inline bool SocketPermission::resolveHost() const SAL_THROW( () )
196 if (! m_resolvedHost
)
200 SocketAddr::resolveHostname( m_host
, addr
);
202 m_resolveErr
= (::osl_Socket_Ok
!= ::osl_getDottedInetAddrOfSocketAddr(
203 addr
.getHandle(), &ip
.pData
));
207 MutexGuard
guard( Mutex::getGlobalMutex() );
208 if (! m_resolvedHost
)
211 m_resolvedHost
= true;
214 return m_resolvedHost
;
216 //__________________________________________________________________________________________________
217 bool SocketPermission::implies( Permission
const & perm
) const SAL_THROW( () )
220 if (SOCKET
!= perm
.m_type
)
222 SocketPermission
const & demanded
= static_cast< SocketPermission
const & >( perm
);
225 if ((m_actions
& demanded
.m_actions
) != demanded
.m_actions
)
229 if (demanded
.m_lowerPort
< m_lowerPort
)
231 if (demanded
.m_upperPort
> m_upperPort
)
234 // quick check host (DNS names: RFC 1034/1035)
235 if (m_host
.equalsIgnoreAsciiCase( demanded
.m_host
))
237 // check for host wildcards
240 OUString
const & demanded_host
= demanded
.m_host
;
241 if (demanded_host
.getLength() <= m_host
.getLength())
243 sal_Int32 len
= m_host
.getLength() -1; // skip star
244 return (0 == ::rtl_ustr_compareIgnoreAsciiCase_WithLength(
245 demanded_host
.getStr() + demanded_host
.getLength() - len
, len
,
246 m_host
.pData
->buffer
+ 1, len
));
248 if (demanded
.m_wildCardHost
)
251 // compare IP addresses
254 if (! demanded
.resolveHost())
256 return (sal_False
!= m_ip
.equals( demanded
.m_ip
));
258 //__________________________________________________________________________________________________
259 OUString
SocketPermission::toString() const SAL_THROW( () )
261 OUStringBuffer
buf( 48 );
264 RTL_CONSTASCII_STRINGPARAM("com.sun.star.connection.SocketPermission (host=\"") );
265 buf
.append( m_host
);
268 buf
.append( (sal_Unicode
)'[' );
270 buf
.append( (sal_Unicode
)']' );
273 if (0 != m_lowerPort
|| 65535 != m_upperPort
)
275 buf
.append( (sal_Unicode
)':' );
277 buf
.append( m_lowerPort
);
278 if (m_upperPort
> m_lowerPort
)
280 buf
.append( (sal_Unicode
)'-' );
281 if (m_upperPort
< 65535)
282 buf
.append( m_upperPort
);
286 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("\", actions=\"") );
287 buf
.append( makeStrings( m_actions
, s_actions
) );
288 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("\")") );
289 return buf
.makeStringAndClear();
292 //##################################################################################################
294 //==================================================================================================
295 class FilePermission
: public Permission
297 static char const * s_actions
[];
305 io::FilePermission
const & perm
,
306 ::rtl::Reference
< Permission
> const & next
= ::rtl::Reference
< Permission
>() )
308 virtual bool implies( Permission
const & perm
) const SAL_THROW( () );
309 virtual OUString
toString() const SAL_THROW( () );
311 //__________________________________________________________________________________________________
312 char const * FilePermission::s_actions
[] = { "read", "write", "execute", "delete", 0 };
313 //--------------------------------------------------------------------------------------------------
314 static OUString
const & getWorkingDir() SAL_THROW( () )
316 static OUString
* s_workingDir
= 0;
320 ::osl_getProcessWorkingDir( &workingDir
.pData
);
322 MutexGuard
guard( Mutex::getGlobalMutex() );
325 static OUString
s_dir( workingDir
);
326 s_workingDir
= &s_dir
;
329 return *s_workingDir
;
331 //__________________________________________________________________________________________________
332 FilePermission::FilePermission(
333 io::FilePermission
const & perm
,
334 ::rtl::Reference
< Permission
> const & next
)
336 : Permission( FILE, next
)
337 , m_actions( makeMask( perm
.Actions
, s_actions
) )
339 , m_allFiles( sal_False
!= perm
.URL
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("<<ALL FILES>>")) )
343 if (m_url
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("*") ))
345 OUStringBuffer
buf( 64 );
346 buf
.append( getWorkingDir() );
347 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("/*") );
348 m_url
= buf
.makeStringAndClear();
350 else if (m_url
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("-") ))
352 OUStringBuffer
buf( 64 );
353 buf
.append( getWorkingDir() );
354 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("/-") );
355 m_url
= buf
.makeStringAndClear();
357 else if (0 != m_url
.compareToAscii( RTL_CONSTASCII_STRINGPARAM("file:///") ))
361 oslFileError rc
= ::osl_getAbsoluteFileURL(
362 getWorkingDir().pData
, perm
.URL
.pData
, &out
.pData
);
363 m_url
= (osl_File_E_None
== rc
? out
: perm
.URL
); // fallback
366 // correct win drive letters
367 if (9 < m_url
.getLength() && '|' == m_url
[ 9 ]) // file:///X|
369 static OUString s_colon
= OUSTR(":");
370 // common case in API is a ':' (sal), so convert '|' to ':'
371 m_url
= m_url
.replaceAt( 9, 1, s_colon
);
376 //__________________________________________________________________________________________________
377 bool FilePermission::implies( Permission
const & perm
) const SAL_THROW( () )
380 if (FILE != perm
.m_type
)
382 FilePermission
const & demanded
= static_cast< FilePermission
const & >( perm
);
385 if ((m_actions
& demanded
.m_actions
) != demanded
.m_actions
)
391 if (demanded
.m_allFiles
)
395 if (m_url
.equalsIgnoreAsciiCase( demanded
.m_url
))
398 if (m_url
.equals( demanded
.m_url
))
401 if (m_url
.getLength() > demanded
.m_url
.getLength())
403 // check /- wildcard: all files and recursive in that path
404 if (1 < m_url
.getLength() &&
405 0 == ::rtl_ustr_ascii_compare_WithLength( m_url
.getStr() + m_url
.getLength() - 2, 2, "/-" ))
407 // demanded url must start with granted path (including path trailing path sep)
408 sal_Int32 len
= m_url
.getLength() -1;
410 return (0 == ::rtl_ustr_compareIgnoreAsciiCase_WithLength(
411 demanded
.m_url
.pData
->buffer
, len
, m_url
.pData
->buffer
, len
));
413 return (0 == ::rtl_ustr_reverseCompare_WithLength(
414 demanded
.m_url
.pData
->buffer
, len
, m_url
.pData
->buffer
, len
));
417 // check /* wildcard: all files in that path (not recursive!)
418 if (1 < m_url
.getLength() &&
419 0 == ::rtl_ustr_ascii_compare_WithLength( m_url
.getStr() + m_url
.getLength() - 2, 2, "/*" ))
421 // demanded url must start with granted path (including path trailing path sep)
422 sal_Int32 len
= m_url
.getLength() -1;
424 return ((0 == ::rtl_ustr_compareIgnoreAsciiCase_WithLength(
425 demanded
.m_url
.pData
->buffer
, len
, m_url
.pData
->buffer
, len
)) &&
426 (0 > demanded
.m_url
.indexOf( '/', len
))); // in addition, no deeper pathes
428 return ((0 == ::rtl_ustr_reverseCompare_WithLength(
429 demanded
.m_url
.pData
->buffer
, len
, m_url
.pData
->buffer
, len
)) &&
430 (0 > demanded
.m_url
.indexOf( '/', len
))); // in addition, no deeper pathes
435 //__________________________________________________________________________________________________
436 OUString
FilePermission::toString() const SAL_THROW( () )
438 OUStringBuffer
buf( 48 );
440 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("com.sun.star.io.FilePermission (url=\"") );
443 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("\", actions=\"") );
444 buf
.append( makeStrings( m_actions
, s_actions
) );
445 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("\")") );
446 return buf
.makeStringAndClear();
449 //##################################################################################################
451 //==================================================================================================
452 class RuntimePermission
: public Permission
457 inline RuntimePermission(
458 security::RuntimePermission
const & perm
,
459 ::rtl::Reference
< Permission
> const & next
= ::rtl::Reference
< Permission
>() )
461 : Permission( RUNTIME
, next
)
462 , m_name( perm
.Name
)
464 virtual bool implies( Permission
const & perm
) const SAL_THROW( () );
465 virtual OUString
toString() const SAL_THROW( () );
467 //__________________________________________________________________________________________________
468 bool RuntimePermission::implies( Permission
const & perm
) const SAL_THROW( () )
471 if (RUNTIME
!= perm
.m_type
)
473 RuntimePermission
const & demanded
= static_cast< RuntimePermission
const & >( perm
);
476 return (sal_False
!= m_name
.equals( demanded
.m_name
));
478 //__________________________________________________________________________________________________
479 OUString
RuntimePermission::toString() const SAL_THROW( () )
481 OUStringBuffer
buf( 48 );
483 RTL_CONSTASCII_STRINGPARAM("com.sun.star.security.RuntimePermission (name=\"") );
484 buf
.append( m_name
);
485 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("\")") );
486 return buf
.makeStringAndClear();
489 //##################################################################################################
491 //__________________________________________________________________________________________________
492 bool AllPermission::implies( Permission
const & ) const SAL_THROW( () )
496 //__________________________________________________________________________________________________
497 OUString
AllPermission::toString() const SAL_THROW( () )
499 return OUSTR("com.sun.star.security.AllPermission");
502 //##################################################################################################
504 //__________________________________________________________________________________________________
505 PermissionCollection::PermissionCollection(
506 Sequence
< Any
> const & permissions
, PermissionCollection
const & addition
)
507 SAL_THROW( (RuntimeException
) )
508 : m_head( addition
.m_head
)
510 Any
const * perms
= permissions
.getConstArray();
511 for ( sal_Int32 nPos
= permissions
.getLength(); nPos
--; )
513 Any
const & perm
= perms
[ nPos
];
514 Type
const & perm_type
= perm
.getValueType();
516 // supported permission types
517 if (perm_type
.equals( ::getCppuType( (io::FilePermission
const *)0 ) ))
519 m_head
= new FilePermission(
520 *reinterpret_cast< io::FilePermission
const * >( perm
.pData
), m_head
);
522 else if (perm_type
.equals( ::getCppuType( (connection::SocketPermission
const *)0 ) ))
524 m_head
= new SocketPermission(
525 *reinterpret_cast< connection::SocketPermission
const * >( perm
.pData
), m_head
);
527 else if (perm_type
.equals( ::getCppuType( (security::RuntimePermission
const *)0 ) ))
529 m_head
= new RuntimePermission(
530 *reinterpret_cast< security::RuntimePermission
const * >( perm
.pData
), m_head
);
532 else if (perm_type
.equals( ::getCppuType( (security::AllPermission
const *)0 ) ))
534 m_head
= new AllPermission( m_head
);
538 OUStringBuffer
buf( 48 );
539 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM(
540 "checking for unsupported permission type: ") );
541 buf
.append( perm_type
.getTypeName() );
542 throw RuntimeException(
543 buf
.makeStringAndClear(), Reference
< XInterface
>() );
548 //__________________________________________________________________________________________________
549 Sequence
< OUString
> PermissionCollection::toStrings() const SAL_THROW( () )
551 vector
< OUString
> strings
;
552 strings
.reserve( 8 );
553 for ( Permission
* perm
= m_head
.get(); perm
; perm
= perm
->m_next
.get() )
555 strings
.push_back( perm
->toString() );
557 return Sequence
< OUString
>(
558 strings
.empty() ? 0 : &strings
[ 0 ], strings
.size() );
561 //__________________________________________________________________________________________________
562 inline static bool __implies(
563 ::rtl::Reference
< Permission
> const & head
, Permission
const & demanded
) SAL_THROW( () )
565 for ( Permission
* perm
= head
.get(); perm
; perm
= perm
->m_next
.get() )
567 if (perm
->implies( demanded
))
574 //--------------------------------------------------------------------------------------------------
575 static void demanded_diag(
576 Permission
const & perm
)
579 OUStringBuffer
buf( 48 );
580 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("demanding ") );
581 buf
.append( perm
.toString() );
582 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM(" => ok.") );
584 ::rtl::OUStringToOString( buf
.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US
) );
585 OSL_TRACE( str
.getStr() );
588 //--------------------------------------------------------------------------------------------------
589 static void throwAccessControlException(
590 Permission
const & perm
, Any
const & demanded_perm
)
591 SAL_THROW( (security::AccessControlException
) )
593 OUStringBuffer
buf( 48 );
594 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("access denied: ") );
595 buf
.append( perm
.toString() );
596 throw security::AccessControlException(
597 buf
.makeStringAndClear(), Reference
< XInterface
>(), demanded_perm
);
599 //==================================================================================================
600 void PermissionCollection::checkPermission( Any
const & perm
) const
601 SAL_THROW( (RuntimeException
) )
603 Type
const & demanded_type
= perm
.getValueType();
605 // supported permission types
606 // stack object of SimpleReferenceObject are ok, as long as they are not
607 // assigned to a ::rtl::Reference<> (=> delete this)
608 if (demanded_type
.equals( ::getCppuType( (io::FilePermission
const *)0 ) ))
610 FilePermission
demanded(
611 *reinterpret_cast< io::FilePermission
const * >( perm
.pData
) );
612 if (__implies( m_head
, demanded
))
615 demanded_diag( demanded
);
619 throwAccessControlException( demanded
, perm
);
621 else if (demanded_type
.equals( ::getCppuType( (connection::SocketPermission
const *)0 ) ))
623 SocketPermission
demanded(
624 *reinterpret_cast< connection::SocketPermission
const * >( perm
.pData
) );
625 if (__implies( m_head
, demanded
))
628 demanded_diag( demanded
);
632 throwAccessControlException( demanded
, perm
);
634 else if (demanded_type
.equals( ::getCppuType( (security::RuntimePermission
const *)0 ) ))
636 RuntimePermission
demanded(
637 *reinterpret_cast< security::RuntimePermission
const * >( perm
.pData
) );
638 if (__implies( m_head
, demanded
))
641 demanded_diag( demanded
);
645 throwAccessControlException( demanded
, perm
);
647 else if (demanded_type
.equals( ::getCppuType( (security::AllPermission
const *)0 ) ))
649 AllPermission demanded
;
650 if (__implies( m_head
, demanded
))
653 demanded_diag( demanded
);
657 throwAccessControlException( demanded
, perm
);
661 OUStringBuffer
buf( 48 );
662 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("checking for unsupported permission type: ") );
663 buf
.append( demanded_type
.getTypeName() );
664 throw RuntimeException(
665 buf
.makeStringAndClear(), Reference
< XInterface
>() );