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_svl.hxx"
30 #include <svl/restrictedpaths.hxx>
31 
32 #include <algorithm>
33 #include <osl/process.h>
34 #include <tools/urlobj.hxx>
35 #include <unotools/localfilehelper.hxx>
36 #include <unotools/syslocale.hxx>
37 
38 namespace svt
39 {
40     namespace
41     {
42         // ----------------------------------------------------------------
43         /** retrieves the value of an environment variable
44             @return <TRUE/> if and only if the retrieved string value is not empty
45         */
46         bool lcl_getEnvironmentValue( const sal_Char* _pAsciiEnvName, ::rtl::OUString& _rValue )
47         {
48             _rValue = ::rtl::OUString();
49             ::rtl::OUString sEnvName = ::rtl::OUString::createFromAscii( _pAsciiEnvName );
50             osl_getEnvironment( sEnvName.pData, &_rValue.pData );
51             return _rValue.getLength() != 0;
52         }
53 
54         //-----------------------------------------------------------------
55         void lcl_convertStringListToUrls( const String& _rColonSeparatedList, ::std::vector< String >& _rTokens, bool _bFinalSlash )
56         {
57             const sal_Unicode s_cSeparator =
58     #if defined(WNT)
59                 ';'
60     #else
61                 ':'
62     #endif
63                 ;
64             xub_StrLen nTokens = _rColonSeparatedList.GetTokenCount( s_cSeparator );
65             _rTokens.resize( 0 ); _rTokens.reserve( nTokens );
66             for ( xub_StrLen i=0; i<nTokens; ++i )
67             {
68                 // the current token in the list
69                 String sCurrentToken = _rColonSeparatedList.GetToken( i, s_cSeparator );
70                 if ( !sCurrentToken.Len() )
71                     continue;
72 
73                 INetURLObject aCurrentURL;
74 
75                 String sURL;
76                 if ( ::utl::LocalFileHelper::ConvertPhysicalNameToURL( sCurrentToken, sURL ) )
77                     aCurrentURL = INetURLObject( sURL );
78                 else
79                 {
80                     // smart URL parsing, assuming FILE protocol
81                     aCurrentURL = INetURLObject( sCurrentToken, INET_PROT_FILE );
82                 }
83 
84                 if ( _bFinalSlash )
85                     aCurrentURL.setFinalSlash( );
86                 else
87                     aCurrentURL.removeFinalSlash( );
88                 _rTokens.push_back( aCurrentURL.GetMainURL( INetURLObject::NO_DECODE ) );
89             }
90         }
91 
92     }
93 
94     //=====================================================================
95     //= CheckURLAllowed
96     //=====================================================================
97     struct CheckURLAllowed
98     {
99     protected:
100     #ifdef WNT
101         SvtSysLocale    m_aSysLocale;
102     #endif
103         String          m_sCheckURL;    // the URL to check
104         bool            m_bAllowParent;
105     public:
106         inline CheckURLAllowed( const String& _rCheckURL, bool bAllowParent = true )
107             :m_sCheckURL( _rCheckURL ), m_bAllowParent( bAllowParent )
108         {
109     #ifdef WNT
110             // on windows, assume that the relevant file systems are case insensitive,
111             // thus normalize the URL
112             m_sCheckURL = m_aSysLocale.GetCharClass().toLower( m_sCheckURL, 0, m_sCheckURL.Len() );
113     #endif
114         }
115 
116         bool operator()( const String& _rApprovedURL )
117         {
118     #ifdef WNT
119             // on windows, assume that the relevant file systems are case insensitive,
120             // thus normalize the URL
121             String sApprovedURL( m_aSysLocale.GetCharClass().toLower( _rApprovedURL, 0, _rApprovedURL.Len() ) );
122     #else
123             String sApprovedURL( _rApprovedURL );
124     #endif
125 
126             xub_StrLen nLenApproved = sApprovedURL.Len();
127             xub_StrLen nLenChecked  = m_sCheckURL.Len();
128 
129             if ( nLenApproved > nLenChecked )
130             {
131                 if ( m_bAllowParent )
132                 {
133                     if ( sApprovedURL.Search( m_sCheckURL ) == 0 )
134                     {
135                         if ( ( m_sCheckURL.GetChar( nLenChecked - 1 ) == '/' )
136                             || ( sApprovedURL.GetChar( nLenChecked ) == '/' ) )
137                             return true;
138                     }
139                 }
140                 else
141                 {
142                     // just a difference in final slash?
143                     if ( ( nLenApproved == ( nLenChecked + 1 ) ) &&
144                         ( sApprovedURL.GetChar( nLenApproved - 1 ) == '/' ) )
145                         return true;
146                 }
147                 return false;
148             }
149             else if ( nLenApproved < nLenChecked )
150             {
151                 if ( m_sCheckURL.Search( sApprovedURL ) == 0 )
152                 {
153                     if ( ( sApprovedURL.GetChar( nLenApproved - 1 ) == '/' )
154                         || ( m_sCheckURL.GetChar( nLenApproved ) == '/' ) )
155                         return true;
156                 }
157                 return false;
158             }
159             else
160             {
161                 // strings have equal length
162                 return ( sApprovedURL == m_sCheckURL );
163             }
164         }
165     };
166 
167     //=====================================================================
168     //= RestrictedPaths
169     //=====================================================================
170     //---------------------------------------------------------------------
171     RestrictedPaths::RestrictedPaths()
172         :m_bFilterIsEnabled( true )
173     {
174         ::rtl::OUString sRestrictedPathList;
175         if ( lcl_getEnvironmentValue( "RestrictedPath", sRestrictedPathList ) )
176             // append a final slash. This ensures that when we later on check
177             // for unrestricted paths, we don't allow paths like "/home/user35" just because
178             // "/home/user3" is allowed - with the final slash, we make it "/home/user3/".
179             lcl_convertStringListToUrls( sRestrictedPathList, m_aUnrestrictedURLs, true );
180     }
181 
182     RestrictedPaths::~RestrictedPaths() {}
183 
184     // --------------------------------------------------------------------
185     bool RestrictedPaths::isUrlAllowed( const String& _rURL ) const
186     {
187         if ( m_aUnrestrictedURLs.empty() || !m_bFilterIsEnabled )
188             return true;
189 
190         ::std::vector< String >::const_iterator aApprovedURL = ::std::find_if(
191             m_aUnrestrictedURLs.begin(),
192             m_aUnrestrictedURLs.end(),
193             CheckURLAllowed( _rURL, true )
194         );
195 
196         return ( aApprovedURL != m_aUnrestrictedURLs.end() );
197     }
198 
199     // --------------------------------------------------------------------
200     bool RestrictedPaths::isUrlAllowed( const String& _rURL, bool allowParents ) const
201     {
202         if ( m_aUnrestrictedURLs.empty() || !m_bFilterIsEnabled )
203             return true;
204 
205         ::std::vector< String >::const_iterator aApprovedURL = ::std::find_if(
206             m_aUnrestrictedURLs.begin(),
207             m_aUnrestrictedURLs.end(),
208             CheckURLAllowed( _rURL, allowParents )
209         );
210 
211         return ( aApprovedURL != m_aUnrestrictedURLs.end() );
212     }
213 
214 }   // namespace svt
215