1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "passwordcontainer.hxx"
23 #include <cppuhelper/factory.hxx>
24 #include <cppuhelper/supportsservice.hxx>
25 #include <comphelper/processfactory.hxx>
26 #include <comphelper/sequence.hxx>
27 #include <com/sun/star/beans/PropertyValue.hpp>
28 #include <com/sun/star/task/InteractionHandler.hpp>
29 #include <com/sun/star/task/MasterPasswordRequest.hpp>
30 #include <com/sun/star/task/NoMasterException.hpp>
31 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
34 #include <osl/diagnose.h>
35 #include <rtl/character.hxx>
36 #include <rtl/cipher.h>
37 #include <rtl/digest.h>
38 #include <rtl/byteseq.hxx>
39 #include <rtl/ustrbuf.hxx>
43 using namespace com::sun::star
;
44 using namespace com::sun::star::uno
;
45 using namespace com::sun::star::registry
;
46 using namespace com::sun::star::lang
;
47 using namespace com::sun::star::task
;
48 using namespace com::sun::star::ucb
;
50 static OUString
createIndex(const std::vector
< OUString
>& lines
)
52 OUStringBuffer aResult
;
54 for( size_t i
= 0; i
< lines
.size(); i
++ )
58 OString line
= OUStringToOString( lines
[i
], RTL_TEXTENCODING_UTF8
);
59 const char* pLine
= line
.getStr();
63 if (rtl::isAsciiAlphanumeric(static_cast<unsigned char>(*pLine
)))
65 aResult
.append(*pLine
);
69 aResult
.append("_").append( OUString::number( *pLine
, 16 ) );
76 return aResult
.makeStringAndClear();
80 static std::vector
< OUString
> getInfoFromInd( const OUString
& aInd
)
82 std::vector
< OUString
> aResult
;
85 OString line
= OUStringToOString( aInd
, RTL_TEXTENCODING_ASCII_US
);
86 const char* pLine
= line
.getStr();
89 OUStringBuffer newItem
;
95 while( *pLine
&& ( pLine
[0] != '_' || pLine
[1] != '_' ))
98 newItem
.append( *pLine
);
104 for( int i
= 1; i
< 3; i
++ )
107 || ( ( pLine
[i
] < '0' || pLine
[i
] > '9' )
108 && ( pLine
[i
] < 'a' || pLine
[i
] > 'f' )
109 && ( pLine
[i
] < 'A' || pLine
[i
] > 'F' ) ) )
111 OSL_FAIL( "Wrong index syntax!" );
115 aNum
+= OUStringChar( pLine
[i
] );
118 newItem
.append( sal_Unicode( aNum
.toUInt32( 16 ) ) );
122 aResult
.push_back( newItem
.makeStringAndClear() );
123 } while( pLine
[0] == '_' && pLine
[1] == '_' );
126 OSL_FAIL( "Wrong index syntax!" );
132 static bool shorterUrl( OUString
& aURL
)
134 sal_Int32 aInd
= aURL
.lastIndexOf( '/' );
135 if( aInd
> 0 && aURL
.indexOf( "://" ) != aInd
-2 )
137 aURL
= aURL
.copy( 0, aInd
);
145 static OUString
getAsciiLine( const ::rtl::ByteSequence
& buf
)
149 ::rtl::ByteSequence
outbuf( buf
.getLength()*2+1 );
151 for( int ind
= 0; ind
< buf
.getLength(); ind
++ )
153 outbuf
[ind
*2] = ( static_cast<sal_uInt8
>(buf
[ind
]) >> 4 ) + 'a';
154 outbuf
[ind
*2+1] = ( static_cast<sal_uInt8
>(buf
[ind
]) & 0x0f ) + 'a';
156 outbuf
[buf
.getLength()*2] = '\0';
158 aResult
= OUString::createFromAscii( reinterpret_cast<char*>(outbuf
.getArray()) );
164 static ::rtl::ByteSequence
getBufFromAsciiLine( const OUString
& line
)
166 OSL_ENSURE( line
.getLength() % 2 == 0, "Wrong syntax!" );
167 OString tmpLine
= OUStringToOString( line
, RTL_TEXTENCODING_ASCII_US
);
168 ::rtl::ByteSequence
aResult(line
.getLength()/2);
170 for( int ind
= 0; ind
< tmpLine
.getLength()/2; ind
++ )
172 aResult
[ind
] = ( static_cast<sal_uInt8
>( tmpLine
[ind
*2] - 'a' ) << 4 ) | static_cast<sal_uInt8
>( tmpLine
[ind
*2+1] - 'a' );
179 PassMap
StorageItem::getInfo()
183 Sequence
< OUString
> aNodeNames
= ConfigItem::GetNodeNames( "Store" );
184 sal_Int32 aNodeCount
= aNodeNames
.getLength();
185 Sequence
< OUString
> aPropNames( aNodeCount
);
187 std::transform(aNodeNames
.begin(), aNodeNames
.end(), aPropNames
.begin(),
188 [](const OUString
& rName
) -> OUString
{
189 return "Store/Passwordstorage['" + rName
+ "']/Password"; });
191 Sequence
< Any
> aPropertyValues
= ConfigItem::GetProperties( aPropNames
);
193 if( aPropertyValues
.getLength() != aNodeCount
)
195 OSL_FAIL( "Problems during reading" );
199 for( sal_Int32 aNodeInd
= 0; aNodeInd
< aNodeCount
; ++aNodeInd
)
201 std::vector
< OUString
> aUrlUsr
= getInfoFromInd( aNodeNames
[aNodeInd
] );
203 if( aUrlUsr
.size() == 2 )
205 OUString aUrl
= aUrlUsr
[0];
206 OUString aName
= aUrlUsr
[1];
209 aPropertyValues
[aNodeInd
] >>= aEPasswd
;
211 PassMap::iterator aIter
= aResult
.find( aUrl
);
212 if( aIter
!= aResult
.end() )
213 aIter
->second
.emplace_back( aName
, aEPasswd
);
216 NamePassRecord
aNewRecord( aName
, aEPasswd
);
217 std::vector
< NamePassRecord
> listToAdd( 1, aNewRecord
);
219 aResult
.insert( PairUrlRecord( aUrl
, listToAdd
) );
223 OSL_FAIL( "Wrong index syntax!" );
230 void StorageItem::setUseStorage( bool bUse
)
232 Sequence
< OUString
> sendNames(1);
233 Sequence
< uno::Any
> sendVals(1);
235 sendNames
[0] = "UseStorage";
237 sendVals
[0] <<= bUse
;
239 ConfigItem::SetModified();
240 ConfigItem::PutProperties( sendNames
, sendVals
);
244 bool StorageItem::useStorage()
246 Sequence
<OUString
> aNodeNames
{ "UseStorage" };
248 Sequence
< Any
> aPropertyValues
= ConfigItem::GetProperties( aNodeNames
);
250 if( aPropertyValues
.getLength() != aNodeNames
.getLength() )
252 OSL_FAIL( "Problems during reading" );
256 bool aResult
= false;
257 aPropertyValues
[0] >>= aResult
;
263 bool StorageItem::getEncodedMP( OUString
& aResult
)
271 Sequence
< OUString
> aNodeNames( 2 );
272 aNodeNames
[0] = "HasMaster";
273 aNodeNames
[1] = "Master";
275 Sequence
< Any
> aPropertyValues
= ConfigItem::GetProperties( aNodeNames
);
277 if( aPropertyValues
.getLength() != aNodeNames
.getLength() )
279 OSL_FAIL( "Problems during reading" );
283 aPropertyValues
[0] >>= hasEncoded
;
284 aPropertyValues
[1] >>= mEncoded
;
292 void StorageItem::setEncodedMP( const OUString
& aEncoded
, bool bAcceptEmpty
)
294 Sequence
< OUString
> sendNames(2);
295 Sequence
< uno::Any
> sendVals(2);
297 sendNames
[0] = "HasMaster";
298 sendNames
[1] = "Master";
300 bool bHasMaster
= ( !aEncoded
.isEmpty() || bAcceptEmpty
);
301 sendVals
[0] <<= bHasMaster
;
302 sendVals
[1] <<= aEncoded
;
304 ConfigItem::SetModified();
305 ConfigItem::PutProperties( sendNames
, sendVals
);
307 hasEncoded
= bHasMaster
;
312 void StorageItem::remove( const OUString
& aURL
, const OUString
& aName
)
314 std::vector
< OUString
> forIndex
;
315 forIndex
.push_back( aURL
);
316 forIndex
.push_back( aName
);
318 Sequence
< OUString
> sendSeq(1);
320 sendSeq
[0] = createIndex( forIndex
);
322 ConfigItem::ClearNodeElements( "Store", sendSeq
);
326 void StorageItem::clear()
328 ConfigItem::ClearNodeSet( "Store" );
332 void StorageItem::update( const OUString
& aURL
, const NamePassRecord
& aRecord
)
334 if ( !aRecord
.HasPasswords( PERSISTENT_RECORD
) )
336 OSL_FAIL( "Unexpected storing of a record!" );
340 std::vector
< OUString
> forIndex
;
341 forIndex
.push_back( aURL
);
342 forIndex
.push_back( aRecord
.GetUserName() );
344 Sequence
< beans::PropertyValue
> sendSeq(1);
346 sendSeq
[0].Name
= "Store/Passwordstorage['" + createIndex( forIndex
) + "']/Password";
348 sendSeq
[0].Value
<<= aRecord
.GetPersPasswords();
350 ConfigItem::SetModified();
351 ConfigItem::SetSetProperties( "Store", sendSeq
);
355 void StorageItem::Notify( const Sequence
< OUString
>& )
357 // this feature still should not be used
363 void StorageItem::ImplCommit()
365 // Do nothing, we stored everything we want already
369 PasswordContainer::PasswordContainer( const Reference
<XComponentContext
>& rxContext
)
371 // m_pStorageFile->Notify() can be called
372 ::osl::MutexGuard
aGuard( mMutex
);
374 mComponent
.set( rxContext
->getServiceManager(), UNO_QUERY
);
375 mComponent
->addEventListener( this );
377 m_pStorageFile
.reset( new StorageItem( this, "Office.Common/Passwords" ) );
378 if( m_pStorageFile
->useStorage() )
379 m_aContainer
= m_pStorageFile
->getInfo();
383 PasswordContainer::~PasswordContainer()
385 ::osl::MutexGuard
aGuard( mMutex
);
387 m_pStorageFile
.reset();
389 if( mComponent
.is() )
391 mComponent
->removeEventListener(this);
396 void SAL_CALL
PasswordContainer::disposing( const EventObject
& )
398 ::osl::MutexGuard
aGuard( mMutex
);
400 m_pStorageFile
.reset();
402 if( mComponent
.is() )
404 //mComponent->removeEventListener(this);
409 std::vector
< OUString
> PasswordContainer::DecodePasswords( const OUString
& aLine
, const OUString
& aMasterPasswd
, css::task::PasswordRequestMode mode
)
411 if( !aMasterPasswd
.isEmpty() )
413 rtlCipher aDecoder
= rtl_cipher_create (rtl_Cipher_AlgorithmBF
, rtl_Cipher_ModeStream
);
414 OSL_ENSURE( aDecoder
, "Can't create decoder" );
418 OSL_ENSURE( aMasterPasswd
.getLength() == RTL_DIGEST_LENGTH_MD5
* 2, "Wrong master password format!" );
420 unsigned char code
[RTL_DIGEST_LENGTH_MD5
];
421 for( int ind
= 0; ind
< RTL_DIGEST_LENGTH_MD5
; ind
++ )
422 code
[ ind
] = static_cast<char>(aMasterPasswd
.copy( ind
*2, 2 ).toUInt32(16));
424 rtlCipherError result
= rtl_cipher_init (
425 aDecoder
, rtl_Cipher_DirectionDecode
,
426 code
, RTL_DIGEST_LENGTH_MD5
, nullptr, 0 );
428 if( result
== rtl_Cipher_E_None
)
430 ::rtl::ByteSequence aSeq
= getBufFromAsciiLine( aLine
);
432 ::rtl::ByteSequence
resSeq( aSeq
.getLength() );
434 rtl_cipher_decode ( aDecoder
, aSeq
.getArray(), aSeq
.getLength(),
435 reinterpret_cast<sal_uInt8
*>(resSeq
.getArray()), resSeq
.getLength() );
437 OUString
aPasswd( reinterpret_cast<char*>(resSeq
.getArray()), resSeq
.getLength(), RTL_TEXTENCODING_UTF8
);
439 rtl_cipher_destroy (aDecoder
);
441 return getInfoFromInd( aPasswd
);
444 rtl_cipher_destroy (aDecoder
);
449 OSL_FAIL( "No master password provided!" );
450 // throw special exception
453 // problems with decoding
454 OSL_FAIL( "Problem with decoding" );
455 throw css::task::NoMasterException(
456 "Can't decode!", css::uno::Reference
<css::uno::XInterface
>(), mode
);
459 OUString
PasswordContainer::EncodePasswords(const std::vector
< OUString
>& lines
, const OUString
& aMasterPasswd
)
461 if( !aMasterPasswd
.isEmpty() )
463 OString aSeq
= OUStringToOString( createIndex( lines
), RTL_TEXTENCODING_UTF8
);
465 rtlCipher aEncoder
= rtl_cipher_create (rtl_Cipher_AlgorithmBF
, rtl_Cipher_ModeStream
);
466 OSL_ENSURE( aEncoder
, "Can't create encoder" );
470 OSL_ENSURE( aMasterPasswd
.getLength() == RTL_DIGEST_LENGTH_MD5
* 2, "Wrong master password format!" );
472 unsigned char code
[RTL_DIGEST_LENGTH_MD5
];
473 for( int ind
= 0; ind
< RTL_DIGEST_LENGTH_MD5
; ind
++ )
474 code
[ ind
] = static_cast<char>(aMasterPasswd
.copy( ind
*2, 2 ).toUInt32(16));
476 rtlCipherError result
= rtl_cipher_init (
477 aEncoder
, rtl_Cipher_DirectionEncode
,
478 code
, RTL_DIGEST_LENGTH_MD5
, nullptr, 0 );
480 if( result
== rtl_Cipher_E_None
)
482 ::rtl::ByteSequence
resSeq(aSeq
.getLength()+1);
484 result
= rtl_cipher_encode ( aEncoder
, aSeq
.getStr(), aSeq
.getLength()+1,
485 reinterpret_cast<sal_uInt8
*>(resSeq
.getArray()), resSeq
.getLength() );
489 rtlCipherError result = rtl_cipher_init (
490 aEncoder, rtl_Cipher_DirectionDecode,
491 code, RTL_DIGEST_LENGTH_MD5, NULL, 0 );
494 if( result == rtl_Cipher_E_None )
496 OUString testOU = getAsciiLine( resSeq );
497 ::rtl::ByteSequence aSeq1 = getBufFromAsciiLine( testOU );
499 ::rtl::ByteSequence resSeq1( aSeq1.getLength() );
501 if( resSeq.getLength() == aSeq1.getLength() )
503 for( int ind = 0; ind < aSeq1.getLength(); ind++ )
504 if( resSeq[ind] != aSeq1[ind] )
508 result = rtl_cipher_decode ( aEncoder, (sal_uInt8*)aSeq1.getArray(), aSeq1.getLength(),
509 (sal_uInt8*)resSeq1.getArray(), resSeq1.getLength() );
511 OUString aPasswd( ( char* )resSeq1.getArray(), resSeq1.getLength(), RTL_TEXTENCODING_UTF8 );
515 rtl_cipher_destroy (aEncoder
);
517 if( result
== rtl_Cipher_E_None
)
518 return getAsciiLine( resSeq
);
522 rtl_cipher_destroy (aEncoder
);
527 OSL_FAIL( "No master password provided!" );
528 // throw special exception
531 // problems with encoding
532 OSL_FAIL( "Problem with encoding" );
533 throw RuntimeException("Can't encode!" );
536 void PasswordContainer::UpdateVector( const OUString
& aURL
, std::vector
< NamePassRecord
>& toUpdate
, NamePassRecord
const & aRecord
, bool writeFile
)
538 for (auto & aNPIter
: toUpdate
)
539 if( aNPIter
.GetUserName() == aRecord
.GetUserName() )
541 if( aRecord
.HasPasswords( MEMORY_RECORD
) )
542 aNPIter
.SetMemPasswords( aRecord
.GetMemPasswords() );
544 if( aRecord
.HasPasswords( PERSISTENT_RECORD
) )
546 aNPIter
.SetPersPasswords( aRecord
.GetPersPasswords() );
550 // the password must be already encoded
551 m_pStorageFile
->update( aURL
, aRecord
); // change existing ( aURL, aName ) record in the configfile
559 if( aRecord
.HasPasswords( PERSISTENT_RECORD
) && writeFile
)
561 // the password must be already encoded
562 m_pStorageFile
->update( aURL
, aRecord
); // add new aName to the existing url
565 toUpdate
.insert( toUpdate
.begin(), aRecord
);
569 UserRecord
PasswordContainer::CopyToUserRecord( const NamePassRecord
& aRecord
, bool& io_bTryToDecode
, const Reference
< XInteractionHandler
>& aHandler
)
571 ::std::vector
< OUString
> aPasswords
;
572 if( aRecord
.HasPasswords( MEMORY_RECORD
) )
573 aPasswords
= aRecord
.GetMemPasswords();
575 if( io_bTryToDecode
&& aRecord
.HasPasswords( PERSISTENT_RECORD
) )
579 ::std::vector
< OUString
> aDecodedPasswords
= DecodePasswords( aRecord
.GetPersPasswords(), GetMasterPassword( aHandler
), css::task::PasswordRequestMode_PASSWORD_ENTER
);
580 aPasswords
.insert( aPasswords
.end(), aDecodedPasswords
.begin(), aDecodedPasswords
.end() );
582 catch( NoMasterException
& )
584 // if master password could not be detected the entry will be just ignored
585 io_bTryToDecode
= false;
589 return UserRecord( aRecord
.GetUserName(), comphelper::containerToSequence( aPasswords
) );
593 Sequence
< UserRecord
> PasswordContainer::CopyToUserRecordSequence( const std::vector
< NamePassRecord
>& original
, const Reference
< XInteractionHandler
>& aHandler
)
595 Sequence
< UserRecord
> aResult( original
.size() );
597 bool bTryToDecode
= true;
599 for (auto const& aNPIter
: original
)
601 aResult
[nInd
] = CopyToUserRecord( aNPIter
, bTryToDecode
, aHandler
);
609 void SAL_CALL
PasswordContainer::add( const OUString
& Url
, const OUString
& UserName
, const Sequence
< OUString
>& Passwords
, const Reference
< XInteractionHandler
>& aHandler
)
611 ::osl::MutexGuard
aGuard( mMutex
);
613 PrivateAdd( Url
, UserName
, Passwords
, MEMORY_RECORD
, aHandler
);
617 void SAL_CALL
PasswordContainer::addPersistent( const OUString
& Url
, const OUString
& UserName
, const Sequence
< OUString
>& Passwords
, const Reference
< XInteractionHandler
>& aHandler
)
619 ::osl::MutexGuard
aGuard( mMutex
);
621 PrivateAdd( Url
, UserName
, Passwords
, PERSISTENT_RECORD
, aHandler
);
625 void PasswordContainer::PrivateAdd( const OUString
& Url
, const OUString
& UserName
, const Sequence
< OUString
>& Passwords
, char Mode
, const Reference
< XInteractionHandler
>& aHandler
)
627 NamePassRecord
aRecord( UserName
);
628 ::std::vector
< OUString
> aStorePass
= comphelper::sequenceToContainer
< std::vector
<OUString
> >( Passwords
);
630 if( Mode
== PERSISTENT_RECORD
)
631 aRecord
.SetPersPasswords( EncodePasswords( aStorePass
, GetMasterPassword( aHandler
) ) );
632 else if( Mode
== MEMORY_RECORD
)
633 aRecord
.SetMemPasswords( aStorePass
);
636 OSL_FAIL( "Unexpected persistence status!" );
640 if( !m_aContainer
.empty() )
642 PassMap::iterator aIter
= m_aContainer
.find( Url
);
644 if( aIter
!= m_aContainer
.end() )
646 UpdateVector( aIter
->first
, aIter
->second
, aRecord
, true );
651 std::vector
< NamePassRecord
> listToAdd( 1, aRecord
);
652 m_aContainer
.insert( PairUrlRecord( Url
, listToAdd
) );
654 if( Mode
== PERSISTENT_RECORD
&& m_pStorageFile
&& m_pStorageFile
->useStorage() )
655 m_pStorageFile
->update( Url
, aRecord
);
660 UrlRecord SAL_CALL
PasswordContainer::find( const OUString
& aURL
, const Reference
< XInteractionHandler
>& aHandler
)
662 return find( aURL
, OUString(), false, aHandler
);
666 UrlRecord SAL_CALL
PasswordContainer::findForName( const OUString
& aURL
, const OUString
& aName
, const Reference
< XInteractionHandler
>& aHandler
)
668 return find( aURL
, aName
, true, aHandler
);
672 Sequence
< UserRecord
> PasswordContainer::FindUsr( const std::vector
< NamePassRecord
>& userlist
, const OUString
& aName
, const Reference
< XInteractionHandler
>& aHandler
)
675 for (auto const& aNPIter
: userlist
)
677 if( aNPIter
.GetUserName() == aName
)
679 Sequence
< UserRecord
> aResult(1);
680 bool bTryToDecode
= true;
681 aResult
[0] = CopyToUserRecord( aNPIter
, bTryToDecode
, aHandler
);
688 return Sequence
< UserRecord
>();
692 bool PasswordContainer::createUrlRecord(
693 const PassMap::iterator
& rIter
,
695 const OUString
& aName
,
696 const Reference
< XInteractionHandler
>& aHandler
,
701 Sequence
< UserRecord
> aUsrRec
702 = FindUsr( rIter
->second
, aName
, aHandler
);
703 if( aUsrRec
.hasElements() )
705 rRec
= UrlRecord( rIter
->first
, aUsrRec
);
713 CopyToUserRecordSequence( rIter
->second
, aHandler
) );
720 UrlRecord
PasswordContainer::find(
721 const OUString
& aURL
,
722 const OUString
& aName
,
723 bool bName
, // only needed to support empty user names
724 const Reference
< XInteractionHandler
>& aHandler
)
726 ::osl::MutexGuard
aGuard( mMutex
);
728 if( !m_aContainer
.empty() && !aURL
.isEmpty() )
730 OUString
aUrl( aURL
);
732 // each iteration remove last '/...' section from the aUrl
733 // while it's possible, up to the most left '://'
736 // first look for <url>/somename and then look for <url>/somename/...
737 PassMap::iterator aIter
= m_aContainer
.find( aUrl
);
738 if( aIter
!= m_aContainer
.end() )
741 if ( createUrlRecord( aIter
, bName
, aName
, aHandler
, aRec
) )
746 OUString
tmpUrl( aUrl
);
747 if ( !tmpUrl
.endsWith("/") )
750 aIter
= m_aContainer
.lower_bound( tmpUrl
);
751 if( aIter
!= m_aContainer
.end() && aIter
->first
.match( tmpUrl
) )
754 if ( createUrlRecord( aIter
, bName
, aName
, aHandler
, aRec
) )
759 while( shorterUrl( aUrl
) && !aUrl
.isEmpty() );
765 OUString
PasswordContainer::GetDefaultMasterPassword()
767 OUStringBuffer aResult
;
768 for ( sal_Int32 nInd
= 0; nInd
< RTL_DIGEST_LENGTH_MD5
; nInd
++ )
769 aResult
.append("aa");
771 return aResult
.makeStringAndClear();
774 OUString
PasswordContainer::RequestPasswordFromUser( PasswordRequestMode aRMode
, const uno::Reference
< task::XInteractionHandler
>& xHandler
)
776 // empty string means that the call was cancelled or just failed
781 ::rtl::Reference
< MasterPasswordRequest_Impl
> xRequest
= new MasterPasswordRequest_Impl( aRMode
);
783 xHandler
->handle( xRequest
.get() );
785 ::rtl::Reference
< ucbhelper::InteractionContinuation
> xSelection
= xRequest
->getSelection();
787 if ( xSelection
.is() )
789 Reference
< XInteractionAbort
> xAbort( xSelection
.get(), UNO_QUERY
);
792 const ::rtl::Reference
< ucbhelper::InteractionSupplyAuthentication
> & xSupp
793 = xRequest
->getAuthenticationSupplier();
795 aResult
= xSupp
->getPassword();
804 OUString
const & PasswordContainer::GetMasterPassword( const Reference
< XInteractionHandler
>& aHandler
)
806 PasswordRequestMode aRMode
= PasswordRequestMode_PASSWORD_ENTER
;
807 if( !m_pStorageFile
|| !m_pStorageFile
->useStorage() )
808 throw NoMasterException("Password storing is not active!", Reference
< XInterface
>(), aRMode
);
810 if( m_aMasterPasswd
.isEmpty() && aHandler
.is() )
813 bool bDefaultPassword
= false;
815 if( !m_pStorageFile
->getEncodedMP( aEncodedMP
) )
816 aRMode
= PasswordRequestMode_PASSWORD_CREATE
;
817 else if ( aEncodedMP
.isEmpty() )
819 m_aMasterPasswd
= GetDefaultMasterPassword();
820 bDefaultPassword
= true;
823 if ( !bDefaultPassword
)
825 bool bAskAgain
= false;
829 OUString aPass
= RequestPasswordFromUser( aRMode
, aHandler
);
830 if ( !aPass
.isEmpty() )
832 if( aRMode
== PasswordRequestMode_PASSWORD_CREATE
)
834 m_aMasterPasswd
= aPass
;
835 std::vector
< OUString
> aMaster( 1, m_aMasterPasswd
);
837 m_pStorageFile
->setEncodedMP( EncodePasswords( aMaster
, m_aMasterPasswd
) );
841 std::vector
< OUString
> aRM( DecodePasswords( aEncodedMP
, aPass
, aRMode
) );
842 if( aRM
.empty() || aPass
!= aRM
[0] )
845 aRMode
= PasswordRequestMode_PASSWORD_REENTER
;
848 m_aMasterPasswd
= aPass
;
852 } while( bAskAgain
);
856 if ( m_aMasterPasswd
.isEmpty() )
857 throw NoMasterException("No master password!", Reference
< XInterface
>(), aRMode
);
859 return m_aMasterPasswd
;
863 void SAL_CALL
PasswordContainer::remove( const OUString
& aURL
, const OUString
& aName
)
865 ::osl::MutexGuard
aGuard( mMutex
);
867 OUString
aUrl( aURL
);
868 if( m_aContainer
.empty() )
871 PassMap::iterator aIter
= m_aContainer
.find( aUrl
);
873 if( aIter
== m_aContainer
.end() )
875 if( aUrl
.endsWith("/") )
876 aUrl
= aUrl
.copy( 0, aUrl
.getLength() - 1 );
880 aIter
= m_aContainer
.find( aUrl
);
883 if( aIter
== m_aContainer
.end() )
886 auto aNPIter
= std::find_if(aIter
->second
.begin(), aIter
->second
.end(),
887 [&aName
](const NamePassRecord
& rNPRecord
) { return rNPRecord
.GetUserName() == aName
; });
889 if (aNPIter
!= aIter
->second
.end())
891 if( aNPIter
->HasPasswords( PERSISTENT_RECORD
) && m_pStorageFile
)
892 m_pStorageFile
->remove( aURL
, aName
); // remove record ( aURL, aName )
894 // the iterator will not be used any more so it can be removed directly
895 aIter
->second
.erase( aNPIter
);
897 if( aIter
->second
.empty() )
898 m_aContainer
.erase( aIter
);
903 void SAL_CALL
PasswordContainer::removePersistent( const OUString
& aURL
, const OUString
& aName
)
905 ::osl::MutexGuard
aGuard( mMutex
);
907 OUString
aUrl( aURL
);
908 if( m_aContainer
.empty() )
911 PassMap::iterator aIter
= m_aContainer
.find( aUrl
);
913 if( aIter
== m_aContainer
.end() )
915 if( aUrl
.endsWith("/") )
916 aUrl
= aUrl
.copy( 0, aUrl
.getLength() - 1 );
920 aIter
= m_aContainer
.find( aUrl
);
923 if( aIter
== m_aContainer
.end() )
926 auto aNPIter
= std::find_if(aIter
->second
.begin(), aIter
->second
.end(),
927 [&aName
](const NamePassRecord
& rNPRecord
) { return rNPRecord
.GetUserName() == aName
; });
929 if (aNPIter
== aIter
->second
.end())
932 if( aNPIter
->HasPasswords( PERSISTENT_RECORD
) )
934 // TODO/LATER: should the password be converted to MemoryPassword?
935 aNPIter
->RemovePasswords( PERSISTENT_RECORD
);
937 if ( m_pStorageFile
)
938 m_pStorageFile
->remove( aURL
, aName
); // remove record ( aURL, aName )
941 if( !aNPIter
->HasPasswords( MEMORY_RECORD
) )
942 aIter
->second
.erase( aNPIter
);
944 if( aIter
->second
.empty() )
945 m_aContainer
.erase( aIter
);
948 void SAL_CALL
PasswordContainer::removeAllPersistent()
950 ::osl::MutexGuard
aGuard( mMutex
);
953 m_pStorageFile
->clear();
955 for( PassMap::iterator aIter
= m_aContainer
.begin(); aIter
!= m_aContainer
.end(); )
957 for( std::vector
< NamePassRecord
>::iterator aNPIter
= aIter
->second
.begin(); aNPIter
!= aIter
->second
.end(); )
959 if( aNPIter
->HasPasswords( PERSISTENT_RECORD
) )
961 // TODO/LATER: should the password be converted to MemoryPassword?
962 aNPIter
->RemovePasswords( PERSISTENT_RECORD
);
964 if ( m_pStorageFile
)
965 m_pStorageFile
->remove( aIter
->first
, aNPIter
->GetUserName() ); // remove record ( aURL, aName )
968 if( !aNPIter
->HasPasswords( MEMORY_RECORD
) )
970 aNPIter
= aIter
->second
.erase(aNPIter
);
976 if( aIter
->second
.empty() )
978 aIter
= m_aContainer
.erase(aIter
);
985 Sequence
< UrlRecord
> SAL_CALL
PasswordContainer::getAllPersistent( const Reference
< XInteractionHandler
>& xHandler
)
987 Sequence
< UrlRecord
> aResult
;
989 ::osl::MutexGuard
aGuard( mMutex
);
990 for( const auto& rEntry
: m_aContainer
)
992 Sequence
< UserRecord
> aUsers
;
993 for (auto const& aNP
: rEntry
.second
)
994 if( aNP
.HasPasswords( PERSISTENT_RECORD
) )
996 sal_Int32 oldLen
= aUsers
.getLength();
997 aUsers
.realloc( oldLen
+ 1 );
998 aUsers
[ oldLen
] = UserRecord( aNP
.GetUserName(), comphelper::containerToSequence( DecodePasswords( aNP
.GetPersPasswords(), GetMasterPassword( xHandler
), css::task::PasswordRequestMode_PASSWORD_ENTER
) ) );
1001 if( aUsers
.hasElements() )
1003 sal_Int32 oldLen
= aResult
.getLength();
1004 aResult
.realloc( oldLen
+ 1 );
1005 aResult
[ oldLen
] = UrlRecord( rEntry
.first
, aUsers
);
1012 sal_Bool SAL_CALL
PasswordContainer::authorizateWithMasterPassword( const uno::Reference
< task::XInteractionHandler
>& xHandler
)
1014 bool bResult
= false;
1015 OUString aEncodedMP
;
1016 uno::Reference
< task::XInteractionHandler
> xTmpHandler
= xHandler
;
1017 ::osl::MutexGuard
aGuard( mMutex
);
1019 // the method should fail if there is no master password
1020 if( m_pStorageFile
&& m_pStorageFile
->useStorage() && m_pStorageFile
->getEncodedMP( aEncodedMP
) )
1022 if ( aEncodedMP
.isEmpty() )
1024 // this is a default master password
1025 // no UI is necessary
1030 if ( !xTmpHandler
.is() )
1032 uno::Reference
< lang::XMultiServiceFactory
> xFactory( mComponent
, uno::UNO_QUERY_THROW
);
1033 uno::Reference
< uno::XComponentContext
> xContext( comphelper::getComponentContext(xFactory
) );
1034 xTmpHandler
.set( InteractionHandler::createWithParent(xContext
, nullptr), uno::UNO_QUERY_THROW
);
1037 if ( !m_aMasterPasswd
.isEmpty() )
1039 // there is a password, it should be just rechecked
1040 PasswordRequestMode aRMode
= PasswordRequestMode_PASSWORD_ENTER
;
1044 aPass
= RequestPasswordFromUser( aRMode
, xTmpHandler
);
1045 bResult
= ( !aPass
.isEmpty() && aPass
== m_aMasterPasswd
);
1046 aRMode
= PasswordRequestMode_PASSWORD_REENTER
; // further questions with error notification
1047 } while( !bResult
&& !aPass
.isEmpty() );
1053 // ask for the password, if user provide no correct password an exception will be thrown
1054 bResult
= !GetMasterPassword( xTmpHandler
).isEmpty();
1056 catch( uno::Exception
& )
1065 sal_Bool SAL_CALL
PasswordContainer::changeMasterPassword( const uno::Reference
< task::XInteractionHandler
>& xHandler
)
1067 bool bResult
= false;
1068 uno::Reference
< task::XInteractionHandler
> xTmpHandler
= xHandler
;
1069 ::osl::MutexGuard
aGuard( mMutex
);
1071 if ( m_pStorageFile
&& m_pStorageFile
->useStorage() )
1073 if ( !xTmpHandler
.is() )
1075 uno::Reference
< lang::XMultiServiceFactory
> xFactory( mComponent
, uno::UNO_QUERY_THROW
);
1076 uno::Reference
< uno::XComponentContext
> xContext( comphelper::getComponentContext(xFactory
) );
1077 xTmpHandler
.set( InteractionHandler::createWithParent(xContext
, nullptr), uno::UNO_QUERY_THROW
);
1080 bool bCanChangePassword
= true;
1081 // if there is already a stored master password it should be entered by the user before the change happen
1082 OUString aEncodedMP
;
1083 if( !m_aMasterPasswd
.isEmpty() || m_pStorageFile
->getEncodedMP( aEncodedMP
) )
1084 bCanChangePassword
= authorizateWithMasterPassword( xTmpHandler
);
1086 if ( bCanChangePassword
)
1088 // ask for the new password, but do not set it
1089 OUString aPass
= RequestPasswordFromUser( PasswordRequestMode_PASSWORD_CREATE
, xTmpHandler
);
1091 if ( !aPass
.isEmpty() )
1093 // get all the persistent entries if it is possible
1094 const Sequence
< UrlRecord
> aPersistent
= getAllPersistent( uno::Reference
< task::XInteractionHandler
>() );
1096 // remove the master password and the entries persistence
1097 removeMasterPassword();
1099 // store the new master password
1100 m_aMasterPasswd
= aPass
;
1101 std::vector
< OUString
> aMaster( 1, m_aMasterPasswd
);
1102 m_pStorageFile
->setEncodedMP( EncodePasswords( aMaster
, m_aMasterPasswd
) );
1104 // store all the entries with the new password
1105 for ( const auto& rURL
: aPersistent
)
1106 for ( const auto& rUser
: rURL
.UserList
)
1107 addPersistent( rURL
.Url
, rUser
.UserName
, rUser
.Passwords
,
1108 uno::Reference
< task::XInteractionHandler
>() );
1118 void SAL_CALL
PasswordContainer::removeMasterPassword()
1120 // remove all the stored passwords and the master password
1121 removeAllPersistent();
1123 ::osl::MutexGuard
aGuard( mMutex
);
1124 if ( m_pStorageFile
)
1126 m_aMasterPasswd
.clear();
1127 m_pStorageFile
->setEncodedMP( OUString() ); // let the master password be removed from configuration
1131 sal_Bool SAL_CALL
PasswordContainer::hasMasterPassword( )
1133 ::osl::MutexGuard
aGuard( mMutex
);
1135 if ( !m_pStorageFile
)
1136 throw uno::RuntimeException();
1138 OUString aEncodedMP
;
1139 return ( m_pStorageFile
->useStorage() && m_pStorageFile
->getEncodedMP( aEncodedMP
) );
1142 sal_Bool SAL_CALL
PasswordContainer::allowPersistentStoring( sal_Bool bAllow
)
1144 ::osl::MutexGuard
aGuard( mMutex
);
1146 if ( !m_pStorageFile
)
1147 throw uno::RuntimeException();
1150 removeMasterPassword();
1152 if (m_pStorageFile
->useStorage() == static_cast<bool>(bAllow
))
1155 m_pStorageFile
->setUseStorage( bAllow
);
1159 sal_Bool SAL_CALL
PasswordContainer::isPersistentStoringAllowed()
1161 ::osl::MutexGuard
aGuard( mMutex
);
1163 if ( !m_pStorageFile
)
1164 throw uno::RuntimeException();
1166 return m_pStorageFile
->useStorage();
1169 sal_Bool SAL_CALL
PasswordContainer::useDefaultMasterPassword( const uno::Reference
< task::XInteractionHandler
>& xHandler
)
1171 bool bResult
= false;
1172 uno::Reference
< task::XInteractionHandler
> xTmpHandler
= xHandler
;
1173 ::osl::MutexGuard
aGuard( mMutex
);
1175 if ( m_pStorageFile
&& m_pStorageFile
->useStorage() )
1177 if ( !xTmpHandler
.is() )
1179 uno::Reference
< lang::XMultiServiceFactory
> xFactory( mComponent
, uno::UNO_QUERY_THROW
);
1180 uno::Reference
< uno::XComponentContext
> xContext( comphelper::getComponentContext(xFactory
) );
1181 xTmpHandler
.set( InteractionHandler::createWithParent(xContext
, nullptr), uno::UNO_QUERY_THROW
);
1184 bool bCanChangePassword
= true;
1185 // if there is already a stored nondefault master password it should be entered by the user before the change happen
1186 OUString aEncodedMP
;
1187 if( m_pStorageFile
->getEncodedMP( aEncodedMP
) && !aEncodedMP
.isEmpty() )
1188 bCanChangePassword
= authorizateWithMasterPassword( xTmpHandler
);
1190 if ( bCanChangePassword
)
1192 // generate the default password
1193 OUString aPass
= GetDefaultMasterPassword();
1194 if ( !aPass
.isEmpty() )
1196 // get all the persistent entries if it is possible
1197 const Sequence
< UrlRecord
> aPersistent
= getAllPersistent( uno::Reference
< task::XInteractionHandler
>() );
1199 // remove the master password and the entries persistence
1200 removeMasterPassword();
1202 // store the empty string to flag the default master password
1203 m_aMasterPasswd
= aPass
;
1204 m_pStorageFile
->setEncodedMP( OUString(), true );
1206 // store all the entries with the new password
1207 for ( const auto& rURL
: aPersistent
)
1208 for ( const auto& rUser
: rURL
.UserList
)
1209 addPersistent( rURL
.Url
, rUser
.UserName
, rUser
.Passwords
,
1210 uno::Reference
< task::XInteractionHandler
>() );
1221 sal_Bool SAL_CALL
PasswordContainer::isDefaultMasterPasswordUsed()
1223 ::osl::MutexGuard
aGuard( mMutex
);
1225 if ( !m_pStorageFile
)
1226 throw uno::RuntimeException();
1228 OUString aEncodedMP
;
1229 return ( m_pStorageFile
->useStorage() && m_pStorageFile
->getEncodedMP( aEncodedMP
) && aEncodedMP
.isEmpty() );
1233 void SAL_CALL
PasswordContainer::addUrl( const OUString
& Url
, sal_Bool MakePersistent
)
1235 mUrlContainer
.add( Url
, MakePersistent
);
1238 OUString SAL_CALL
PasswordContainer::findUrl( const OUString
& Url
)
1240 return mUrlContainer
.find( Url
);
1243 void SAL_CALL
PasswordContainer::removeUrl( const OUString
& Url
)
1245 mUrlContainer
.remove( Url
);
1248 uno::Sequence
< OUString
> SAL_CALL
PasswordContainer::getUrls( sal_Bool OnlyPersistent
)
1250 return mUrlContainer
.list( OnlyPersistent
);
1254 void PasswordContainer::Notify()
1256 ::osl::MutexGuard
aGuard( mMutex
);
1258 // remove the cached persistent values in the memory
1259 for( auto& rEntry
: m_aContainer
)
1261 for( std::vector
< NamePassRecord
>::iterator aNPIter
= rEntry
.second
.begin(); aNPIter
!= rEntry
.second
.end(); )
1263 if( aNPIter
->HasPasswords( PERSISTENT_RECORD
) )
1265 aNPIter
->RemovePasswords( PERSISTENT_RECORD
);
1267 if ( m_pStorageFile
)
1268 m_pStorageFile
->remove( rEntry
.first
, aNPIter
->GetUserName() ); // remove record ( aURL, aName )
1271 if( !aNPIter
->HasPasswords( MEMORY_RECORD
) )
1273 aNPIter
= rEntry
.second
.erase(aNPIter
);
1281 if( m_pStorageFile
)
1282 addon
= m_pStorageFile
->getInfo();
1284 for( const auto& rEntry
: addon
)
1286 PassMap::iterator aSearchIter
= m_aContainer
.find( rEntry
.first
);
1287 if( aSearchIter
!= m_aContainer
.end() )
1288 for (auto const& aNP
: rEntry
.second
)
1289 UpdateVector( aSearchIter
->first
, aSearchIter
->second
, aNP
, false );
1291 m_aContainer
.insert( PairUrlRecord( rEntry
.first
, rEntry
.second
) );
1295 OUString SAL_CALL
PasswordContainer::getImplementationName( )
1297 return "stardiv.svl.PasswordContainer";
1300 sal_Bool SAL_CALL
PasswordContainer::supportsService( const OUString
& ServiceName
)
1302 return cppu::supportsService( this, ServiceName
);
1305 Sequence
< OUString
> SAL_CALL
PasswordContainer::getSupportedServiceNames( )
1307 return { "com.sun.star.task.PasswordContainer" };
1310 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
1311 svl_PasswordContainer_get_implementation(
1312 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
1314 return cppu::acquire(new PasswordContainer(context
));
1318 MasterPasswordRequest_Impl::MasterPasswordRequest_Impl( PasswordRequestMode Mode
)
1320 MasterPasswordRequest aRequest
;
1322 aRequest
.Classification
= InteractionClassification_ERROR
;
1323 aRequest
.Mode
= Mode
;
1325 setRequest( makeAny( aRequest
) );
1327 // Fill continuations...
1328 Sequence
< RememberAuthentication
> aRememberModes( 1 );
1329 aRememberModes
[ 0 ] = RememberAuthentication_NO
;
1332 = new ::ucbhelper::InteractionSupplyAuthentication(
1334 false, // bCanSetRealm
1335 false, // bCanSetUserName
1336 true, // bCanSetPassword
1337 false, // bCanSetAccount
1338 aRememberModes
, // rRememberPasswordModes
1339 RememberAuthentication_NO
, // eDefaultRememberPasswordMode
1340 aRememberModes
, // rRememberAccountModes
1341 RememberAuthentication_NO
, // eDefaultRememberAccountMode
1342 false // bCanUseSystemCredentials
1346 Reference
< XInteractionContinuation
> > aContinuations( 3 );
1347 aContinuations
[ 0 ] = new ::ucbhelper::InteractionAbort( this );
1348 aContinuations
[ 1 ] = new ::ucbhelper::InteractionRetry( this );
1349 aContinuations
[ 2 ] = m_xAuthSupplier
.get();
1351 setContinuations( aContinuations
);
1356 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */