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 #include "syscreds.hxx"
29 #include "com/sun/star/beans/PropertyValue.hpp"
30 
31 using namespace com::sun::star;
32 
33 SysCredentialsConfigItem::SysCredentialsConfigItem(
34     SysCredentialsConfig * pOwner )
35 : utl::ConfigItem( rtl::OUString::createFromAscii( "Office.Common/Passwords" ),
36                    CONFIG_MODE_IMMEDIATE_UPDATE ),
37   m_bInited( false ),
38   m_pOwner( pOwner )
39 {
40     uno::Sequence< ::rtl::OUString > aNode( 1 );
41     aNode[ 0 ] = rtl::OUString::createFromAscii(
42         "Office.Common/Passwords/AuthenticateUsingSystemCredentials" );
43     EnableNotification( aNode );
44 }
45 
46 //virtual
47 void SysCredentialsConfigItem::Notify(
48     const uno::Sequence< rtl::OUString > & /*seqPropertyNames*/ )
49 {
50     {
51         ::osl::MutexGuard aGuard( m_aMutex );
52         m_bInited = false;
53         // rebuild m_seqURLs
54         getSystemCredentialsURLs();
55     }
56     m_pOwner->persistentConfigChanged();
57 }
58 
59 void SysCredentialsConfigItem::Commit()
60 {
61 	// does nothing
62 }
63 
64 uno::Sequence< rtl::OUString >
65 SysCredentialsConfigItem::getSystemCredentialsURLs()
66 {
67     ::osl::MutexGuard aGuard( m_aMutex );
68     if ( !m_bInited )
69     {
70         // read config item
71         uno::Sequence< ::rtl::OUString > aPropNames( 1 );
72         aPropNames[ 0 ] = rtl::OUString::createFromAscii(
73             "AuthenticateUsingSystemCredentials" );
74         uno::Sequence< uno::Any > aAnyValues(
75             utl::ConfigItem::GetProperties( aPropNames ) );
76 
77         OSL_ENSURE(
78             aAnyValues.getLength() == 1,
79             "SysCredentialsConfigItem::getSystemCredentialsURLs: "
80             "Error reading config item!" );
81 
82         uno::Sequence< rtl::OUString > aValues;
83         if ( ( aAnyValues[ 0 ] >>= aValues ) ||
84              ( !aAnyValues[ 0 ].hasValue() ) )
85         {
86             m_seqURLs = aValues;
87             m_bInited = true;
88         }
89     }
90     return m_seqURLs;
91 }
92 
93 void SysCredentialsConfigItem::setSystemCredentialsURLs(
94     const uno::Sequence< rtl::OUString > & seqURLList )
95 {
96     ::osl::MutexGuard aGuard( m_aMutex );
97 
98     // write config item.
99     uno::Sequence< rtl::OUString > aPropNames( 1 );
100     uno::Sequence< uno::Any > aPropValues( 1 );
101     aPropNames[ 0 ]
102         = ::rtl::OUString::createFromAscii(
103             "AuthenticateUsingSystemCredentials" );
104     aPropValues[ 0 ] <<= seqURLList;
105 
106     utl::ConfigItem::SetModified();
107     utl::ConfigItem::PutProperties( aPropNames, aPropValues );
108 
109     m_seqURLs = seqURLList;
110     m_bInited = true;
111 }
112 
113 //============================================================================
114 
115 namespace
116 {
117     // TODO: This code is actually copied from svl/source/passwordcontainer.cxx
118     bool removeLastSegment( ::rtl::OUString & aURL )
119     {
120         sal_Int32 aInd = aURL.lastIndexOf( sal_Unicode( '/' ) );
121 
122         if( aInd > 0  )
123         {
124             sal_Int32 aPrevInd = aURL.lastIndexOf( sal_Unicode( '/' ), aInd );
125             if ( aURL.indexOf( ::rtl::OUString::createFromAscii( "://" ) )
126                     != aPrevInd - 2 ||
127                  aInd != aURL.getLength() - 1 )
128             {
129                 aURL = aURL.copy( 0, aInd );
130                 return true;
131             }
132         }
133 
134         return false;
135     }
136 
137     bool findURL( StringSet const & rContainer, rtl::OUString const & aURL, rtl::OUString & aResult )
138     {
139         // TODO: This code is actually copied from svl/source/passwordcontainer.cxx
140         if( !rContainer.empty() && aURL.getLength() )
141         {
142             ::rtl::OUString aUrl( aURL );
143 
144             // each iteration remove last '/...' section from the aUrl
145             // while it's possible, up to the most left '://'
146             do
147             {
148                 // first look for <url>/somename and then look for <url>/somename/...
149                 StringSet::const_iterator aIter = rContainer.find( aUrl );
150                 if( aIter != rContainer.end() )
151                 {
152                     aResult = *aIter;
153                     return true;
154                 }
155                 else
156                 {
157                     ::rtl::OUString tmpUrl( aUrl );
158                     if ( tmpUrl.getStr()[tmpUrl.getLength() - 1] != (sal_Unicode)'/' )
159                       tmpUrl += ::rtl::OUString::createFromAscii( "/" );
160 
161                     aIter = rContainer.lower_bound( tmpUrl );
162                     if( aIter != rContainer.end() && aIter->match( tmpUrl ) )
163                     {
164                         aResult = *aIter;
165                         return true;
166                     }
167                 }
168             }
169             while( removeLastSegment( aUrl ) && aUrl.getLength() );
170         }
171         aResult = rtl::OUString();
172         return false;
173     }
174 
175 } // namespace
176 
177 SysCredentialsConfig::SysCredentialsConfig()
178 : m_aConfigItem( this ),
179   m_bCfgInited( false )
180 {
181 }
182 
183 void SysCredentialsConfig::initCfg()
184 {
185     osl::MutexGuard aGuard( m_aMutex );
186     if ( !m_bCfgInited )
187     {
188         uno::Sequence< rtl::OUString > aURLs(
189             m_aConfigItem.getSystemCredentialsURLs() );
190         for ( sal_Int32 n = 0; n < aURLs.getLength(); ++n )
191             m_aCfgContainer.insert( aURLs[ n ] );
192 
193         m_bCfgInited = true;
194     }
195 }
196 
197 void SysCredentialsConfig::writeCfg()
198 {
199     osl::MutexGuard aGuard( m_aMutex );
200 
201     OSL_ENSURE( m_bCfgInited, "SysCredentialsConfig::writeCfg : not initialized!" );
202 
203     uno::Sequence< rtl::OUString > aURLs( m_aCfgContainer.size() );
204     StringSet::const_iterator it = m_aCfgContainer.begin();
205     const StringSet::const_iterator end = m_aCfgContainer.end();
206     sal_Int32 n = 0;
207 
208     while ( it != end )
209     {
210         aURLs[ n ] = *it;
211         ++it;
212         ++n;
213     }
214 
215     m_aConfigItem.setSystemCredentialsURLs( aURLs );
216 }
217 
218 rtl::OUString SysCredentialsConfig::find( rtl::OUString const & aURL )
219 {
220     osl::MutexGuard aGuard( m_aMutex );
221     rtl::OUString aResult;
222     if ( findURL( m_aMemContainer, aURL, aResult ) )
223         return aResult;
224 
225     initCfg();
226     if ( findURL( m_aCfgContainer, aURL, aResult ) )
227         return aResult;
228 
229     return rtl::OUString();
230 }
231 
232 void SysCredentialsConfig::add( rtl::OUString const & rURL, bool bPersistent )
233 {
234     ::osl::MutexGuard aGuard( m_aMutex );
235 
236     if ( bPersistent )
237     {
238         m_aMemContainer.erase( rURL );
239 
240         initCfg();
241         m_aCfgContainer.insert( rURL );
242         writeCfg();
243     }
244     else
245     {
246         initCfg();
247         if ( m_aCfgContainer.erase( rURL ) > 0 )
248             writeCfg();
249 
250         m_aMemContainer.insert( rURL );
251     }
252 }
253 
254 void SysCredentialsConfig::remove( rtl::OUString const & rURL )
255 {
256     m_aMemContainer.erase( rURL );
257 
258     initCfg();
259     if ( m_aCfgContainer.erase( rURL ) > 0 )
260         writeCfg();
261 }
262 
263 uno::Sequence< rtl::OUString > SysCredentialsConfig::list( bool bOnlyPersistent )
264 {
265     initCfg();
266     sal_Int32 nCount = m_aCfgContainer.size()
267                      + ( bOnlyPersistent ? 0 : m_aMemContainer.size() );
268     uno::Sequence< rtl::OUString > aResult( nCount );
269 
270     StringSet::const_iterator it = m_aCfgContainer.begin();
271     StringSet::const_iterator end = m_aCfgContainer.end();
272     sal_Int32 n = 0;
273 
274     while ( it != end )
275     {
276         aResult[ n ] = *it;
277         ++it;
278         ++n;
279     }
280 
281     if ( !bOnlyPersistent )
282     {
283         it = m_aMemContainer.begin();
284         end = m_aMemContainer.end();
285 
286         while ( it != end )
287         {
288             aResult[ n ] = *it;
289             ++it;
290             ++n;
291         }
292     }
293     return aResult;
294 }
295 
296 void SysCredentialsConfig::persistentConfigChanged()
297 {
298     ::osl::MutexGuard aGuard( m_aMutex );
299     m_bCfgInited = false; // re-init on demand.
300 }
301