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 <unotools/pathoptions.hxx>
24 #include <cppuhelper/factory.hxx>
25 #include <cppuhelper/supportsservice.hxx>
26 #include <comphelper/processfactory.hxx>
27 #include <comphelper/sequence.hxx>
28 #include <com/sun/star/registry/XSimpleRegistry.hpp>
29 #include <com/sun/star/beans/PropertyValue.hpp>
30 #include <com/sun/star/task/InteractionHandler.hpp>
31 #include <com/sun/star/task/MasterPasswordRequest.hpp>
32 #include <com/sun/star/task/NoMasterException.hpp>
33 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
35 #include <osl/diagnose.h>
36 #include <rtl/character.hxx>
37 #include <rtl/cipher.h>
38 #include <rtl/digest.h>
39 #include <rtl/byteseq.hxx>
40 #include <rtl/ustrbuf.hxx>
44 using namespace com::sun::star
;
45 using namespace com::sun::star::uno
;
46 using namespace com::sun::star::registry
;
47 using namespace com::sun::star::lang
;
48 using namespace com::sun::star::task
;
49 using namespace com::sun::star::ucb
;
51 static OUString
createIndex(const std::vector
< OUString
>& lines
)
53 OUStringBuffer aResult
;
55 for( size_t i
= 0; i
< lines
.size(); i
++ )
59 OString line
= OUStringToOString( lines
[i
], RTL_TEXTENCODING_UTF8
);
60 const sal_Char
* pLine
= line
.getStr();
64 if (rtl::isAsciiAlphanumeric(static_cast<unsigned char>(*pLine
)))
66 aResult
.append(*pLine
);
70 aResult
.append("_").append( OUString::number( *pLine
, 16 ) );
77 return aResult
.makeStringAndClear();
81 static std::vector
< OUString
> getInfoFromInd( const OUString
& aInd
)
83 std::vector
< OUString
> aResult
;
86 OString line
= OUStringToOString( aInd
, RTL_TEXTENCODING_ASCII_US
);
87 const sal_Char
* pLine
= line
.getStr();
90 OUStringBuffer newItem
;
96 while( *pLine
&& !( pLine
[0] == '_' && pLine
[1] == '_' ))
99 newItem
.append( *pLine
);
105 for( int i
= 1; i
< 3; i
++ )
108 || ( ( pLine
[i
] < '0' || pLine
[i
] > '9' )
109 && ( pLine
[i
] < 'a' || pLine
[i
] > 'f' )
110 && ( pLine
[i
] < 'A' || pLine
[i
] > 'F' ) ) )
112 OSL_FAIL( "Wrong index syntax!" );
116 aNum
+= OUStringLiteral1( pLine
[i
] );
119 newItem
.append( OUStringLiteral1( aNum
.toUInt32( 16 ) ) );
123 aResult
.push_back( newItem
.makeStringAndClear() );
124 } while( pLine
[0] == '_' && pLine
[1] == '_' );
127 OSL_FAIL( "Wrong index syntax!" );
133 static bool shorterUrl( OUString
& aURL
)
135 sal_Int32 aInd
= aURL
.lastIndexOf( '/' );
136 if( aInd
> 0 && aURL
.indexOf( "://" ) != aInd
-2 )
138 aURL
= aURL
.copy( 0, aInd
);
146 static OUString
getAsciiLine( const ::rtl::ByteSequence
& buf
)
150 ::rtl::ByteSequence
outbuf( buf
.getLength()*2+1 );
152 for( int ind
= 0; ind
< buf
.getLength(); ind
++ )
154 outbuf
[ind
*2] = ( static_cast<sal_uInt8
>(buf
[ind
]) >> 4 ) + 'a';
155 outbuf
[ind
*2+1] = ( static_cast<sal_uInt8
>(buf
[ind
]) & 0x0f ) + 'a';
157 outbuf
[buf
.getLength()*2] = '\0';
159 aResult
= OUString::createFromAscii( reinterpret_cast<char*>(outbuf
.getArray()) );
165 static ::rtl::ByteSequence
getBufFromAsciiLine( const OUString
& line
)
167 OSL_ENSURE( line
.getLength() % 2 == 0, "Wrong syntax!" );
168 OString tmpLine
= OUStringToOString( line
, RTL_TEXTENCODING_ASCII_US
);
169 ::rtl::ByteSequence
aResult(line
.getLength()/2);
171 for( int ind
= 0; ind
< tmpLine
.getLength()/2; ind
++ )
173 aResult
[ind
] = ( static_cast<sal_uInt8
>( tmpLine
[ind
*2] - 'a' ) << 4 ) | static_cast<sal_uInt8
>( tmpLine
[ind
*2+1] - 'a' );
180 PassMap
StorageItem::getInfo()
184 Sequence
< OUString
> aNodeNames
= ConfigItem::GetNodeNames( "Store" );
185 sal_Int32 aNodeCount
= aNodeNames
.getLength();
186 Sequence
< OUString
> aPropNames( aNodeCount
);
189 for( aNodeInd
= 0; aNodeInd
< aNodeCount
; ++aNodeInd
)
191 aPropNames
[aNodeInd
] = "Store/Passwordstorage['" + aNodeNames
[aNodeInd
] + "']/Password";
194 Sequence
< Any
> aPropertyValues
= ConfigItem::GetProperties( aPropNames
);
196 if( aPropertyValues
.getLength() != aNodeNames
.getLength() )
198 OSL_ENSURE( aPropertyValues
.getLength() == aNodeNames
.getLength(), "Problems during reading" );
202 for( aNodeInd
= 0; aNodeInd
< aNodeCount
; ++aNodeInd
)
204 std::vector
< OUString
> aUrlUsr
= getInfoFromInd( aNodeNames
[aNodeInd
] );
206 if( aUrlUsr
.size() == 2 )
208 OUString aUrl
= aUrlUsr
[0];
209 OUString aName
= aUrlUsr
[1];
212 aPropertyValues
[aNodeInd
] >>= aEPasswd
;
214 PassMap::iterator aIter
= aResult
.find( aUrl
);
215 if( aIter
!= aResult
.end() )
216 aIter
->second
.emplace_back( aName
, aEPasswd
);
219 NamePassRecord
aNewRecord( aName
, aEPasswd
);
220 std::vector
< NamePassRecord
> listToAdd( 1, aNewRecord
);
222 aResult
.insert( PairUrlRecord( aUrl
, listToAdd
) );
226 OSL_FAIL( "Wrong index syntax!" );
233 void StorageItem::setUseStorage( bool bUse
)
235 Sequence
< OUString
> sendNames(1);
236 Sequence
< uno::Any
> sendVals(1);
238 sendNames
[0] = "UseStorage";
240 sendVals
[0] <<= bUse
;
242 ConfigItem::SetModified();
243 ConfigItem::PutProperties( sendNames
, sendVals
);
247 bool StorageItem::useStorage()
249 Sequence
<OUString
> aNodeNames
{ "UseStorage" };
251 Sequence
< Any
> aPropertyValues
= ConfigItem::GetProperties( aNodeNames
);
253 if( aPropertyValues
.getLength() != aNodeNames
.getLength() )
255 OSL_ENSURE( aPropertyValues
.getLength() == aNodeNames
.getLength(), "Problems during reading" );
259 bool aResult
= false;
260 aPropertyValues
[0] >>= aResult
;
266 bool StorageItem::getEncodedMP( OUString
& aResult
)
274 Sequence
< OUString
> aNodeNames( 2 );
275 aNodeNames
[0] = "HasMaster";
276 aNodeNames
[1] = "Master";
278 Sequence
< Any
> aPropertyValues
= ConfigItem::GetProperties( aNodeNames
);
280 if( aPropertyValues
.getLength() != aNodeNames
.getLength() )
282 OSL_ENSURE( aPropertyValues
.getLength() == aNodeNames
.getLength(), "Problems during reading" );
286 aPropertyValues
[0] >>= hasEncoded
;
287 aPropertyValues
[1] >>= mEncoded
;
295 void StorageItem::setEncodedMP( const OUString
& aEncoded
, bool bAcceptEmpty
)
297 Sequence
< OUString
> sendNames(2);
298 Sequence
< uno::Any
> sendVals(2);
300 sendNames
[0] = "HasMaster";
301 sendNames
[1] = "Master";
303 bool bHasMaster
= ( !aEncoded
.isEmpty() || bAcceptEmpty
);
304 sendVals
[0] <<= bHasMaster
;
305 sendVals
[1] <<= aEncoded
;
307 ConfigItem::SetModified();
308 ConfigItem::PutProperties( sendNames
, sendVals
);
310 hasEncoded
= bHasMaster
;
315 void StorageItem::remove( const OUString
& aURL
, const OUString
& aName
)
317 std::vector
< OUString
> forIndex
;
318 forIndex
.push_back( aURL
);
319 forIndex
.push_back( aName
);
321 Sequence
< OUString
> sendSeq(1);
323 sendSeq
[0] = createIndex( forIndex
);
325 ConfigItem::ClearNodeElements( "Store", sendSeq
);
329 void StorageItem::clear()
331 ConfigItem::ClearNodeSet( "Store" );
335 void StorageItem::update( const OUString
& aURL
, const NamePassRecord
& aRecord
)
337 if ( !aRecord
.HasPasswords( PERSISTENT_RECORD
) )
339 OSL_FAIL( "Unexpected storing of a record!" );
343 std::vector
< OUString
> forIndex
;
344 forIndex
.push_back( aURL
);
345 forIndex
.push_back( aRecord
.GetUserName() );
347 Sequence
< beans::PropertyValue
> sendSeq(1);
349 sendSeq
[0].Name
= "Store/Passwordstorage['" + createIndex( forIndex
) + "']/Password";
351 sendSeq
[0].Value
<<= aRecord
.GetPersPasswords();
353 ConfigItem::SetModified();
354 ConfigItem::SetSetProperties( "Store", sendSeq
);
358 void StorageItem::Notify( const Sequence
< OUString
>& )
360 // this feature still should not be used
366 void StorageItem::ImplCommit()
368 // Do nothing, we stored everything we want already
372 PasswordContainer::PasswordContainer( const Reference
<XMultiServiceFactory
>& xServiceFactory
)
374 // m_pStorageFile->Notify() can be called
375 ::osl::MutexGuard
aGuard( mMutex
);
377 mComponent
.set( xServiceFactory
, UNO_QUERY
);
378 mComponent
->addEventListener( this );
380 m_pStorageFile
.reset( new StorageItem( this, "Office.Common/Passwords" ) );
381 if( m_pStorageFile
->useStorage() )
382 m_aContainer
= m_pStorageFile
->getInfo();
386 PasswordContainer::~PasswordContainer()
388 ::osl::MutexGuard
aGuard( mMutex
);
390 m_pStorageFile
.reset();
392 if( mComponent
.is() )
394 mComponent
->removeEventListener(this);
399 void SAL_CALL
PasswordContainer::disposing( const EventObject
& )
401 ::osl::MutexGuard
aGuard( mMutex
);
403 m_pStorageFile
.reset();
405 if( mComponent
.is() )
407 //mComponent->removeEventListener(this);
412 std::vector
< OUString
> PasswordContainer::DecodePasswords( const OUString
& aLine
, const OUString
& aMasterPasswd
, css::task::PasswordRequestMode mode
)
414 if( !aMasterPasswd
.isEmpty() )
416 rtlCipher aDecoder
= rtl_cipher_create (rtl_Cipher_AlgorithmBF
, rtl_Cipher_ModeStream
);
417 OSL_ENSURE( aDecoder
, "Can't create decoder" );
421 OSL_ENSURE( aMasterPasswd
.getLength() == RTL_DIGEST_LENGTH_MD5
* 2, "Wrong master password format!" );
423 unsigned char code
[RTL_DIGEST_LENGTH_MD5
];
424 for( int ind
= 0; ind
< RTL_DIGEST_LENGTH_MD5
; ind
++ )
425 code
[ ind
] = static_cast<char>(aMasterPasswd
.copy( ind
*2, 2 ).toUInt32(16));
427 rtlCipherError result
= rtl_cipher_init (
428 aDecoder
, rtl_Cipher_DirectionDecode
,
429 code
, RTL_DIGEST_LENGTH_MD5
, nullptr, 0 );
431 if( result
== rtl_Cipher_E_None
)
433 ::rtl::ByteSequence aSeq
= getBufFromAsciiLine( aLine
);
435 ::rtl::ByteSequence
resSeq( aSeq
.getLength() );
437 rtl_cipher_decode ( aDecoder
, aSeq
.getArray(), aSeq
.getLength(),
438 reinterpret_cast<sal_uInt8
*>(resSeq
.getArray()), resSeq
.getLength() );
440 OUString
aPasswd( reinterpret_cast<char*>(resSeq
.getArray()), resSeq
.getLength(), RTL_TEXTENCODING_UTF8
);
442 rtl_cipher_destroy (aDecoder
);
444 return getInfoFromInd( aPasswd
);
447 rtl_cipher_destroy (aDecoder
);
452 OSL_FAIL( "No master password provided!" );
453 // throw special exception
456 // problems with decoding
457 OSL_FAIL( "Problem with decoding" );
458 throw css::task::NoMasterException(
459 "Can't decode!", css::uno::Reference
<css::uno::XInterface
>(), mode
);
462 OUString
PasswordContainer::EncodePasswords(const std::vector
< OUString
>& lines
, const OUString
& aMasterPasswd
)
464 if( !aMasterPasswd
.isEmpty() )
466 OString aSeq
= OUStringToOString( createIndex( lines
), RTL_TEXTENCODING_UTF8
);
468 rtlCipher aEncoder
= rtl_cipher_create (rtl_Cipher_AlgorithmBF
, rtl_Cipher_ModeStream
);
469 OSL_ENSURE( aEncoder
, "Can't create encoder" );
473 OSL_ENSURE( aMasterPasswd
.getLength() == RTL_DIGEST_LENGTH_MD5
* 2, "Wrong master password format!" );
475 unsigned char code
[RTL_DIGEST_LENGTH_MD5
];
476 for( int ind
= 0; ind
< RTL_DIGEST_LENGTH_MD5
; ind
++ )
477 code
[ ind
] = static_cast<char>(aMasterPasswd
.copy( ind
*2, 2 ).toUInt32(16));
479 rtlCipherError result
= rtl_cipher_init (
480 aEncoder
, rtl_Cipher_DirectionEncode
,
481 code
, RTL_DIGEST_LENGTH_MD5
, nullptr, 0 );
483 if( result
== rtl_Cipher_E_None
)
485 ::rtl::ByteSequence
resSeq(aSeq
.getLength()+1);
487 result
= rtl_cipher_encode ( aEncoder
, aSeq
.getStr(), aSeq
.getLength()+1,
488 reinterpret_cast<sal_uInt8
*>(resSeq
.getArray()), resSeq
.getLength() );
492 rtlCipherError result = rtl_cipher_init (
493 aEncoder, rtl_Cipher_DirectionDecode,
494 code, RTL_DIGEST_LENGTH_MD5, NULL, 0 );
497 if( result == rtl_Cipher_E_None )
499 OUString testOU = getAsciiLine( resSeq );
500 ::rtl::ByteSequence aSeq1 = getBufFromAsciiLine( testOU );
502 ::rtl::ByteSequence resSeq1( aSeq1.getLength() );
504 if( resSeq.getLength() == aSeq1.getLength() )
506 for( int ind = 0; ind < aSeq1.getLength(); ind++ )
507 if( resSeq[ind] != aSeq1[ind] )
511 result = rtl_cipher_decode ( aEncoder, (sal_uInt8*)aSeq1.getArray(), aSeq1.getLength(),
512 (sal_uInt8*)resSeq1.getArray(), resSeq1.getLength() );
514 OUString aPasswd( ( sal_Char* )resSeq1.getArray(), resSeq1.getLength(), RTL_TEXTENCODING_UTF8 );
518 rtl_cipher_destroy (aEncoder
);
520 if( result
== rtl_Cipher_E_None
)
521 return getAsciiLine( resSeq
);
525 rtl_cipher_destroy (aEncoder
);
530 OSL_FAIL( "No master password provided!" );
531 // throw special exception
534 // problems with encoding
535 OSL_FAIL( "Problem with encoding" );
536 throw RuntimeException("Can't encode!" );
539 void PasswordContainer::UpdateVector( const OUString
& aURL
, std::vector
< NamePassRecord
>& toUpdate
, NamePassRecord
const & aRecord
, bool writeFile
)
541 for (auto & aNPIter
: toUpdate
)
542 if( aNPIter
.GetUserName() == aRecord
.GetUserName() )
544 if( aRecord
.HasPasswords( MEMORY_RECORD
) )
545 aNPIter
.SetMemPasswords( aRecord
.GetMemPasswords() );
547 if( aRecord
.HasPasswords( PERSISTENT_RECORD
) )
549 aNPIter
.SetPersPasswords( aRecord
.GetPersPasswords() );
553 // the password must be already encoded
554 m_pStorageFile
->update( aURL
, aRecord
); // change existing ( aURL, aName ) record in the configfile
562 if( aRecord
.HasPasswords( PERSISTENT_RECORD
) && writeFile
)
564 // the password must be already encoded
565 m_pStorageFile
->update( aURL
, aRecord
); // add new aName to the existing url
568 toUpdate
.insert( toUpdate
.begin(), aRecord
);
572 UserRecord
PasswordContainer::CopyToUserRecord( const NamePassRecord
& aRecord
, bool& io_bTryToDecode
, const Reference
< XInteractionHandler
>& aHandler
)
574 ::std::vector
< OUString
> aPasswords
;
575 if( aRecord
.HasPasswords( MEMORY_RECORD
) )
576 aPasswords
= aRecord
.GetMemPasswords();
578 if( io_bTryToDecode
&& aRecord
.HasPasswords( PERSISTENT_RECORD
) )
582 ::std::vector
< OUString
> aDecodedPasswords
= DecodePasswords( aRecord
.GetPersPasswords(), GetMasterPassword( aHandler
), css::task::PasswordRequestMode_PASSWORD_ENTER
);
583 aPasswords
.insert( aPasswords
.end(), aDecodedPasswords
.begin(), aDecodedPasswords
.end() );
585 catch( NoMasterException
& )
587 // if master password could not be detected the entry will be just ignored
588 io_bTryToDecode
= false;
592 return UserRecord( aRecord
.GetUserName(), comphelper::containerToSequence( aPasswords
) );
596 Sequence
< UserRecord
> PasswordContainer::CopyToUserRecordSequence( const std::vector
< NamePassRecord
>& original
, const Reference
< XInteractionHandler
>& aHandler
)
598 Sequence
< UserRecord
> aResult( original
.size() );
600 bool bTryToDecode
= true;
602 for (auto const& aNPIter
: original
)
604 aResult
[nInd
] = CopyToUserRecord( aNPIter
, bTryToDecode
, aHandler
);
612 void SAL_CALL
PasswordContainer::add( const OUString
& Url
, const OUString
& UserName
, const Sequence
< OUString
>& Passwords
, const Reference
< XInteractionHandler
>& aHandler
)
614 ::osl::MutexGuard
aGuard( mMutex
);
616 PrivateAdd( Url
, UserName
, Passwords
, MEMORY_RECORD
, aHandler
);
620 void SAL_CALL
PasswordContainer::addPersistent( const OUString
& Url
, const OUString
& UserName
, const Sequence
< OUString
>& Passwords
, const Reference
< XInteractionHandler
>& aHandler
)
622 ::osl::MutexGuard
aGuard( mMutex
);
624 PrivateAdd( Url
, UserName
, Passwords
, PERSISTENT_RECORD
, aHandler
);
628 void PasswordContainer::PrivateAdd( const OUString
& Url
, const OUString
& UserName
, const Sequence
< OUString
>& Passwords
, char Mode
, const Reference
< XInteractionHandler
>& aHandler
)
630 NamePassRecord
aRecord( UserName
);
631 ::std::vector
< OUString
> aStorePass
= comphelper::sequenceToContainer
< std::vector
<OUString
> >( Passwords
);
633 if( Mode
== PERSISTENT_RECORD
)
634 aRecord
.SetPersPasswords( EncodePasswords( aStorePass
, GetMasterPassword( aHandler
) ) );
635 else if( Mode
== MEMORY_RECORD
)
636 aRecord
.SetMemPasswords( aStorePass
);
639 OSL_FAIL( "Unexpected persistence status!" );
643 if( !m_aContainer
.empty() )
645 PassMap::iterator aIter
= m_aContainer
.find( Url
);
647 if( aIter
!= m_aContainer
.end() )
649 UpdateVector( aIter
->first
, aIter
->second
, aRecord
, true );
654 std::vector
< NamePassRecord
> listToAdd( 1, aRecord
);
655 m_aContainer
.insert( PairUrlRecord( Url
, listToAdd
) );
657 if( Mode
== PERSISTENT_RECORD
&& m_pStorageFile
&& m_pStorageFile
->useStorage() )
658 m_pStorageFile
->update( Url
, aRecord
);
663 UrlRecord SAL_CALL
PasswordContainer::find( const OUString
& aURL
, const Reference
< XInteractionHandler
>& aHandler
)
665 return find( aURL
, OUString(), false, aHandler
);
669 UrlRecord SAL_CALL
PasswordContainer::findForName( const OUString
& aURL
, const OUString
& aName
, const Reference
< XInteractionHandler
>& aHandler
)
671 return find( aURL
, aName
, true, aHandler
);
675 Sequence
< UserRecord
> PasswordContainer::FindUsr( const std::vector
< NamePassRecord
>& userlist
, const OUString
& aName
, const Reference
< XInteractionHandler
>& aHandler
)
678 for (auto const& aNPIter
: userlist
)
680 if( aNPIter
.GetUserName() == aName
)
682 Sequence
< UserRecord
> aResult(1);
683 bool bTryToDecode
= true;
684 aResult
[0] = CopyToUserRecord( aNPIter
, bTryToDecode
, aHandler
);
691 return Sequence
< UserRecord
>();
695 bool PasswordContainer::createUrlRecord(
696 const PassMap::iterator
& rIter
,
698 const OUString
& aName
,
699 const Reference
< XInteractionHandler
>& aHandler
,
704 Sequence
< UserRecord
> aUsrRec
705 = FindUsr( rIter
->second
, aName
, aHandler
);
706 if( aUsrRec
.hasElements() )
708 rRec
= UrlRecord( rIter
->first
, aUsrRec
);
716 CopyToUserRecordSequence( rIter
->second
, aHandler
) );
723 UrlRecord
PasswordContainer::find(
724 const OUString
& aURL
,
725 const OUString
& aName
,
726 bool bName
, // only needed to support empty user names
727 const Reference
< XInteractionHandler
>& aHandler
)
729 ::osl::MutexGuard
aGuard( mMutex
);
731 if( !m_aContainer
.empty() && !aURL
.isEmpty() )
733 OUString
aUrl( aURL
);
735 // each iteration remove last '/...' section from the aUrl
736 // while it's possible, up to the most left '://'
739 // first look for <url>/somename and then look for <url>/somename/...
740 PassMap::iterator aIter
= m_aContainer
.find( aUrl
);
741 if( aIter
!= m_aContainer
.end() )
744 if ( createUrlRecord( aIter
, bName
, aName
, aHandler
, aRec
) )
749 OUString
tmpUrl( aUrl
);
750 if ( !tmpUrl
.endsWith("/") )
753 aIter
= m_aContainer
.lower_bound( tmpUrl
);
754 if( aIter
!= m_aContainer
.end() && aIter
->first
.match( tmpUrl
) )
757 if ( createUrlRecord( aIter
, bName
, aName
, aHandler
, aRec
) )
762 while( shorterUrl( aUrl
) && !aUrl
.isEmpty() );
768 OUString
PasswordContainer::GetDefaultMasterPassword()
770 OUStringBuffer aResult
;
771 for ( sal_Int32 nInd
= 0; nInd
< RTL_DIGEST_LENGTH_MD5
; nInd
++ )
772 aResult
.append("aa");
774 return aResult
.makeStringAndClear();
777 OUString
PasswordContainer::RequestPasswordFromUser( PasswordRequestMode aRMode
, const uno::Reference
< task::XInteractionHandler
>& xHandler
)
779 // empty string means that the call was cancelled or just failed
784 ::rtl::Reference
< MasterPasswordRequest_Impl
> xRequest
= new MasterPasswordRequest_Impl( aRMode
);
786 xHandler
->handle( xRequest
.get() );
788 ::rtl::Reference
< ucbhelper::InteractionContinuation
> xSelection
= xRequest
->getSelection();
790 if ( xSelection
.is() )
792 Reference
< XInteractionAbort
> xAbort( xSelection
.get(), UNO_QUERY
);
795 const ::rtl::Reference
< ucbhelper::InteractionSupplyAuthentication
> & xSupp
796 = xRequest
->getAuthenticationSupplier();
798 aResult
= xSupp
->getPassword();
807 OUString
const & PasswordContainer::GetMasterPassword( const Reference
< XInteractionHandler
>& aHandler
)
809 PasswordRequestMode aRMode
= PasswordRequestMode_PASSWORD_ENTER
;
810 if( !m_pStorageFile
|| !m_pStorageFile
->useStorage() )
811 throw NoMasterException("Password storing is not active!", Reference
< XInterface
>(), aRMode
);
813 if( m_aMasterPasswd
.isEmpty() && aHandler
.is() )
816 bool bDefaultPassword
= false;
818 if( !m_pStorageFile
->getEncodedMP( aEncodedMP
) )
819 aRMode
= PasswordRequestMode_PASSWORD_CREATE
;
820 else if ( aEncodedMP
.isEmpty() )
822 m_aMasterPasswd
= GetDefaultMasterPassword();
823 bDefaultPassword
= true;
826 if ( !bDefaultPassword
)
828 bool bAskAgain
= false;
832 OUString aPass
= RequestPasswordFromUser( aRMode
, aHandler
);
833 if ( !aPass
.isEmpty() )
835 if( aRMode
== PasswordRequestMode_PASSWORD_CREATE
)
837 m_aMasterPasswd
= aPass
;
838 std::vector
< OUString
> aMaster( 1, m_aMasterPasswd
);
840 m_pStorageFile
->setEncodedMP( EncodePasswords( aMaster
, m_aMasterPasswd
) );
844 std::vector
< OUString
> aRM( DecodePasswords( aEncodedMP
, aPass
, aRMode
) );
845 if( aRM
.empty() || aPass
!= aRM
[0] )
848 aRMode
= PasswordRequestMode_PASSWORD_REENTER
;
851 m_aMasterPasswd
= aPass
;
855 } while( bAskAgain
);
859 if ( m_aMasterPasswd
.isEmpty() )
860 throw NoMasterException("No master password!", Reference
< XInterface
>(), aRMode
);
862 return m_aMasterPasswd
;
866 void SAL_CALL
PasswordContainer::remove( const OUString
& aURL
, const OUString
& aName
)
868 ::osl::MutexGuard
aGuard( mMutex
);
870 OUString
aUrl( aURL
);
871 if( m_aContainer
.empty() )
874 PassMap::iterator aIter
= m_aContainer
.find( aUrl
);
876 if( aIter
== m_aContainer
.end() )
878 if( aUrl
.endsWith("/") )
879 aUrl
= aUrl
.copy( 0, aUrl
.getLength() - 1 );
883 aIter
= m_aContainer
.find( aUrl
);
886 if( aIter
== m_aContainer
.end() )
889 auto aNPIter
= std::find_if(aIter
->second
.begin(), aIter
->second
.end(),
890 [&aName
](const NamePassRecord
& rNPRecord
) { return rNPRecord
.GetUserName() == aName
; });
892 if (aNPIter
!= aIter
->second
.end())
894 if( aNPIter
->HasPasswords( PERSISTENT_RECORD
) && m_pStorageFile
)
895 m_pStorageFile
->remove( aURL
, aName
); // remove record ( aURL, aName )
897 // the iterator will not be used any more so it can be removed directly
898 aIter
->second
.erase( aNPIter
);
900 if( aIter
->second
.empty() )
901 m_aContainer
.erase( aIter
);
906 void SAL_CALL
PasswordContainer::removePersistent( const OUString
& aURL
, const OUString
& aName
)
908 ::osl::MutexGuard
aGuard( mMutex
);
910 OUString
aUrl( aURL
);
911 if( m_aContainer
.empty() )
914 PassMap::iterator aIter
= m_aContainer
.find( aUrl
);
916 if( aIter
== m_aContainer
.end() )
918 if( aUrl
.endsWith("/") )
919 aUrl
= aUrl
.copy( 0, aUrl
.getLength() - 1 );
923 aIter
= m_aContainer
.find( aUrl
);
926 if( aIter
== m_aContainer
.end() )
929 auto aNPIter
= std::find_if(aIter
->second
.begin(), aIter
->second
.end(),
930 [&aName
](const NamePassRecord
& rNPRecord
) { return rNPRecord
.GetUserName() == aName
; });
932 if (aNPIter
!= aIter
->second
.end())
934 if( aNPIter
->HasPasswords( PERSISTENT_RECORD
) )
936 // TODO/LATER: should the password be converted to MemoryPassword?
937 aNPIter
->RemovePasswords( PERSISTENT_RECORD
);
939 if ( m_pStorageFile
)
940 m_pStorageFile
->remove( aURL
, aName
); // remove record ( aURL, aName )
943 if( !aNPIter
->HasPasswords( MEMORY_RECORD
) )
944 aIter
->second
.erase( aNPIter
);
946 if( aIter
->second
.empty() )
947 m_aContainer
.erase( aIter
);
951 void SAL_CALL
PasswordContainer::removeAllPersistent()
953 ::osl::MutexGuard
aGuard( mMutex
);
956 m_pStorageFile
->clear();
958 for( PassMap::iterator aIter
= m_aContainer
.begin(); aIter
!= m_aContainer
.end(); )
960 for( std::vector
< NamePassRecord
>::iterator aNPIter
= aIter
->second
.begin(); aNPIter
!= aIter
->second
.end(); )
962 if( aNPIter
->HasPasswords( PERSISTENT_RECORD
) )
964 // TODO/LATER: should the password be converted to MemoryPassword?
965 aNPIter
->RemovePasswords( PERSISTENT_RECORD
);
967 if ( m_pStorageFile
)
968 m_pStorageFile
->remove( aIter
->first
, aNPIter
->GetUserName() ); // remove record ( aURL, aName )
971 if( !aNPIter
->HasPasswords( MEMORY_RECORD
) )
973 aNPIter
= aIter
->second
.erase(aNPIter
);
979 if( aIter
->second
.empty() )
981 aIter
= m_aContainer
.erase(aIter
);
988 Sequence
< UrlRecord
> SAL_CALL
PasswordContainer::getAllPersistent( const Reference
< XInteractionHandler
>& xHandler
)
990 Sequence
< UrlRecord
> aResult
;
992 ::osl::MutexGuard
aGuard( mMutex
);
993 for( const auto& rEntry
: m_aContainer
)
995 Sequence
< UserRecord
> aUsers
;
996 for (auto const& aNP
: rEntry
.second
)
997 if( aNP
.HasPasswords( PERSISTENT_RECORD
) )
999 sal_Int32 oldLen
= aUsers
.getLength();
1000 aUsers
.realloc( oldLen
+ 1 );
1001 aUsers
[ oldLen
] = UserRecord( aNP
.GetUserName(), comphelper::containerToSequence( DecodePasswords( aNP
.GetPersPasswords(), GetMasterPassword( xHandler
), css::task::PasswordRequestMode_PASSWORD_ENTER
) ) );
1004 if( aUsers
.hasElements() )
1006 sal_Int32 oldLen
= aResult
.getLength();
1007 aResult
.realloc( oldLen
+ 1 );
1008 aResult
[ oldLen
] = UrlRecord( rEntry
.first
, aUsers
);
1015 sal_Bool SAL_CALL
PasswordContainer::authorizateWithMasterPassword( const uno::Reference
< task::XInteractionHandler
>& xHandler
)
1017 bool bResult
= false;
1018 OUString aEncodedMP
;
1019 uno::Reference
< task::XInteractionHandler
> xTmpHandler
= xHandler
;
1020 ::osl::MutexGuard
aGuard( mMutex
);
1022 // the method should fail if there is no master password
1023 if( m_pStorageFile
&& m_pStorageFile
->useStorage() && m_pStorageFile
->getEncodedMP( aEncodedMP
) )
1025 if ( aEncodedMP
.isEmpty() )
1027 // this is a default master password
1028 // no UI is necessary
1033 if ( !xTmpHandler
.is() )
1035 uno::Reference
< lang::XMultiServiceFactory
> xFactory( mComponent
, uno::UNO_QUERY_THROW
);
1036 uno::Reference
< uno::XComponentContext
> xContext( comphelper::getComponentContext(xFactory
) );
1037 xTmpHandler
.set( InteractionHandler::createWithParent(xContext
, nullptr), uno::UNO_QUERY_THROW
);
1040 if ( !m_aMasterPasswd
.isEmpty() )
1042 // there is a password, it should be just rechecked
1043 PasswordRequestMode aRMode
= PasswordRequestMode_PASSWORD_ENTER
;
1047 aPass
= RequestPasswordFromUser( aRMode
, xTmpHandler
);
1048 bResult
= ( !aPass
.isEmpty() && aPass
== m_aMasterPasswd
);
1049 aRMode
= PasswordRequestMode_PASSWORD_REENTER
; // further questions with error notification
1050 } while( !bResult
&& !aPass
.isEmpty() );
1056 // ask for the password, if user provide no correct password an exception will be thrown
1057 bResult
= !GetMasterPassword( xTmpHandler
).isEmpty();
1059 catch( uno::Exception
& )
1068 sal_Bool SAL_CALL
PasswordContainer::changeMasterPassword( const uno::Reference
< task::XInteractionHandler
>& xHandler
)
1070 bool bResult
= false;
1071 uno::Reference
< task::XInteractionHandler
> xTmpHandler
= xHandler
;
1072 ::osl::MutexGuard
aGuard( mMutex
);
1074 if ( m_pStorageFile
&& m_pStorageFile
->useStorage() )
1076 if ( !xTmpHandler
.is() )
1078 uno::Reference
< lang::XMultiServiceFactory
> xFactory( mComponent
, uno::UNO_QUERY_THROW
);
1079 uno::Reference
< uno::XComponentContext
> xContext( comphelper::getComponentContext(xFactory
) );
1080 xTmpHandler
.set( InteractionHandler::createWithParent(xContext
, nullptr), uno::UNO_QUERY_THROW
);
1083 bool bCanChangePassword
= true;
1084 // if there is already a stored master password it should be entered by the user before the change happen
1085 OUString aEncodedMP
;
1086 if( !m_aMasterPasswd
.isEmpty() || m_pStorageFile
->getEncodedMP( aEncodedMP
) )
1087 bCanChangePassword
= authorizateWithMasterPassword( xTmpHandler
);
1089 if ( bCanChangePassword
)
1091 // ask for the new password, but do not set it
1092 OUString aPass
= RequestPasswordFromUser( PasswordRequestMode_PASSWORD_CREATE
, xTmpHandler
);
1094 if ( !aPass
.isEmpty() )
1096 // get all the persistent entries if it is possible
1097 Sequence
< UrlRecord
> aPersistent
= getAllPersistent( uno::Reference
< task::XInteractionHandler
>() );
1099 // remove the master password and the entries persistence
1100 removeMasterPassword();
1102 // store the new master password
1103 m_aMasterPasswd
= aPass
;
1104 std::vector
< OUString
> aMaster( 1, m_aMasterPasswd
);
1105 m_pStorageFile
->setEncodedMP( EncodePasswords( aMaster
, m_aMasterPasswd
) );
1107 // store all the entries with the new password
1108 for ( int nURLInd
= 0; nURLInd
< aPersistent
.getLength(); nURLInd
++ )
1109 for ( int nNameInd
= 0; nNameInd
< aPersistent
[nURLInd
].UserList
.getLength(); nNameInd
++ )
1110 addPersistent( aPersistent
[nURLInd
].Url
,
1111 aPersistent
[nURLInd
].UserList
[nNameInd
].UserName
,
1112 aPersistent
[nURLInd
].UserList
[nNameInd
].Passwords
,
1113 uno::Reference
< task::XInteractionHandler
>() );
1123 void SAL_CALL
PasswordContainer::removeMasterPassword()
1125 // remove all the stored passwords and the master password
1126 removeAllPersistent();
1128 ::osl::MutexGuard
aGuard( mMutex
);
1129 if ( m_pStorageFile
)
1131 m_aMasterPasswd
.clear();
1132 m_pStorageFile
->setEncodedMP( OUString() ); // let the master password be removed from configuration
1136 sal_Bool SAL_CALL
PasswordContainer::hasMasterPassword( )
1138 ::osl::MutexGuard
aGuard( mMutex
);
1140 if ( !m_pStorageFile
)
1141 throw uno::RuntimeException();
1143 OUString aEncodedMP
;
1144 return ( m_pStorageFile
->useStorage() && m_pStorageFile
->getEncodedMP( aEncodedMP
) );
1147 sal_Bool SAL_CALL
PasswordContainer::allowPersistentStoring( sal_Bool bAllow
)
1149 ::osl::MutexGuard
aGuard( mMutex
);
1151 if ( !m_pStorageFile
)
1152 throw uno::RuntimeException();
1155 removeMasterPassword();
1157 if (m_pStorageFile
->useStorage() == static_cast<bool>(bAllow
))
1160 m_pStorageFile
->setUseStorage( bAllow
);
1164 sal_Bool SAL_CALL
PasswordContainer::isPersistentStoringAllowed()
1166 ::osl::MutexGuard
aGuard( mMutex
);
1168 if ( !m_pStorageFile
)
1169 throw uno::RuntimeException();
1171 return m_pStorageFile
->useStorage();
1174 sal_Bool SAL_CALL
PasswordContainer::useDefaultMasterPassword( const uno::Reference
< task::XInteractionHandler
>& xHandler
)
1176 bool bResult
= false;
1177 uno::Reference
< task::XInteractionHandler
> xTmpHandler
= xHandler
;
1178 ::osl::MutexGuard
aGuard( mMutex
);
1180 if ( m_pStorageFile
&& m_pStorageFile
->useStorage() )
1182 if ( !xTmpHandler
.is() )
1184 uno::Reference
< lang::XMultiServiceFactory
> xFactory( mComponent
, uno::UNO_QUERY_THROW
);
1185 uno::Reference
< uno::XComponentContext
> xContext( comphelper::getComponentContext(xFactory
) );
1186 xTmpHandler
.set( InteractionHandler::createWithParent(xContext
, nullptr), uno::UNO_QUERY_THROW
);
1189 bool bCanChangePassword
= true;
1190 // if there is already a stored nondefault master password it should be entered by the user before the change happen
1191 OUString aEncodedMP
;
1192 if( m_pStorageFile
->getEncodedMP( aEncodedMP
) && !aEncodedMP
.isEmpty() )
1193 bCanChangePassword
= authorizateWithMasterPassword( xTmpHandler
);
1195 if ( bCanChangePassword
)
1197 // generate the default password
1198 OUString aPass
= GetDefaultMasterPassword();
1199 if ( !aPass
.isEmpty() )
1201 // get all the persistent entries if it is possible
1202 Sequence
< UrlRecord
> aPersistent
= getAllPersistent( uno::Reference
< task::XInteractionHandler
>() );
1204 // remove the master password and the entries persistence
1205 removeMasterPassword();
1207 // store the empty string to flag the default master password
1208 m_aMasterPasswd
= aPass
;
1209 m_pStorageFile
->setEncodedMP( OUString(), true );
1211 // store all the entries with the new password
1212 for ( int nURLInd
= 0; nURLInd
< aPersistent
.getLength(); nURLInd
++ )
1213 for ( int nNameInd
= 0; nNameInd
< aPersistent
[nURLInd
].UserList
.getLength(); nNameInd
++ )
1214 addPersistent( aPersistent
[nURLInd
].Url
,
1215 aPersistent
[nURLInd
].UserList
[nNameInd
].UserName
,
1216 aPersistent
[nURLInd
].UserList
[nNameInd
].Passwords
,
1217 uno::Reference
< task::XInteractionHandler
>() );
1228 sal_Bool SAL_CALL
PasswordContainer::isDefaultMasterPasswordUsed()
1230 ::osl::MutexGuard
aGuard( mMutex
);
1232 if ( !m_pStorageFile
)
1233 throw uno::RuntimeException();
1235 OUString aEncodedMP
;
1236 return ( m_pStorageFile
->useStorage() && m_pStorageFile
->getEncodedMP( aEncodedMP
) && aEncodedMP
.isEmpty() );
1240 void SAL_CALL
PasswordContainer::addUrl( const OUString
& Url
, sal_Bool MakePersistent
)
1242 mUrlContainer
.add( Url
, MakePersistent
);
1245 OUString SAL_CALL
PasswordContainer::findUrl( const OUString
& Url
)
1247 return mUrlContainer
.find( Url
);
1250 void SAL_CALL
PasswordContainer::removeUrl( const OUString
& Url
)
1252 mUrlContainer
.remove( Url
);
1255 uno::Sequence
< OUString
> SAL_CALL
PasswordContainer::getUrls( sal_Bool OnlyPersistent
)
1257 return mUrlContainer
.list( OnlyPersistent
);
1261 void PasswordContainer::Notify()
1263 ::osl::MutexGuard
aGuard( mMutex
);
1265 // remove the cached persistent values in the memory
1266 for( auto& rEntry
: m_aContainer
)
1268 for( std::vector
< NamePassRecord
>::iterator aNPIter
= rEntry
.second
.begin(); aNPIter
!= rEntry
.second
.end(); )
1270 if( aNPIter
->HasPasswords( PERSISTENT_RECORD
) )
1272 aNPIter
->RemovePasswords( PERSISTENT_RECORD
);
1274 if ( m_pStorageFile
)
1275 m_pStorageFile
->remove( rEntry
.first
, aNPIter
->GetUserName() ); // remove record ( aURL, aName )
1278 if( !aNPIter
->HasPasswords( MEMORY_RECORD
) )
1280 aNPIter
= rEntry
.second
.erase(aNPIter
);
1288 if( m_pStorageFile
)
1289 addon
= m_pStorageFile
->getInfo();
1291 for( const auto& rEntry
: addon
)
1293 PassMap::iterator aSearchIter
= m_aContainer
.find( rEntry
.first
);
1294 if( aSearchIter
!= m_aContainer
.end() )
1295 for (auto const& aNP
: rEntry
.second
)
1296 UpdateVector( aSearchIter
->first
, aSearchIter
->second
, aNP
, false );
1298 m_aContainer
.insert( PairUrlRecord( rEntry
.first
, rEntry
.second
) );
1302 OUString SAL_CALL
PasswordContainer::getImplementationName( )
1304 return impl_getStaticImplementationName();
1307 sal_Bool SAL_CALL
PasswordContainer::supportsService( const OUString
& ServiceName
)
1309 return cppu::supportsService( this, ServiceName
);
1312 Sequence
< OUString
> SAL_CALL
PasswordContainer::getSupportedServiceNames( )
1314 return impl_getStaticSupportedServiceNames();
1317 Sequence
< OUString
> PasswordContainer::impl_getStaticSupportedServiceNames( )
1319 Sequence
< OUString
> aRet
{ "com.sun.star.task.PasswordContainer" };
1323 OUString
PasswordContainer::impl_getStaticImplementationName()
1325 return OUString("stardiv.svl.PasswordContainer");
1328 Reference
< XInterface
> SAL_CALL
PasswordContainer::impl_createInstance( const Reference
< XMultiServiceFactory
>& xServiceManager
)
1330 return Reference
< XInterface
>( *new PasswordContainer( xServiceManager
) );
1333 Reference
< XSingleServiceFactory
> PasswordContainer::impl_createFactory( const Reference
< XMultiServiceFactory
>& ServiceManager
)
1335 Reference
< XSingleServiceFactory
> xReturn( ::cppu::createOneInstanceFactory( ServiceManager
,
1336 PasswordContainer::impl_getStaticImplementationName(),
1337 PasswordContainer::impl_createInstance
,
1338 PasswordContainer::impl_getStaticSupportedServiceNames()));
1344 MasterPasswordRequest_Impl::MasterPasswordRequest_Impl( PasswordRequestMode Mode
)
1346 MasterPasswordRequest aRequest
;
1348 aRequest
.Classification
= InteractionClassification_ERROR
;
1349 aRequest
.Mode
= Mode
;
1351 setRequest( makeAny( aRequest
) );
1353 // Fill continuations...
1354 Sequence
< RememberAuthentication
> aRememberModes( 1 );
1355 aRememberModes
[ 0 ] = RememberAuthentication_NO
;
1358 = new ::ucbhelper::InteractionSupplyAuthentication(
1360 false, // bCanSetRealm
1361 false, // bCanSetUserName
1362 true, // bCanSetPassword
1363 false, // bCanSetAccount
1364 aRememberModes
, // rRememberPasswordModes
1365 RememberAuthentication_NO
, // eDefaultRememberPasswordMode
1366 aRememberModes
, // rRememberAccountModes
1367 RememberAuthentication_NO
, // eDefaultRememberAccountMode
1368 false // bCanUseSystemCredentials
1372 Reference
< XInteractionContinuation
> > aContinuations( 3 );
1373 aContinuations
[ 0 ] = new ::ucbhelper::InteractionAbort( this );
1374 aContinuations
[ 1 ] = new ::ucbhelper::InteractionRetry( this );
1375 aContinuations
[ 2 ] = m_xAuthSupplier
.get();
1377 setContinuations( aContinuations
);
1383 SAL_DLLPUBLIC_EXPORT
void * passwordcontainer_component_getFactory (
1384 const sal_Char
* pImplementationName
,
1385 SAL_UNUSED_PARAMETER
void * pServiceManager
,
1386 SAL_UNUSED_PARAMETER
void * /* pRegistryKey */)
1388 void * pResult
= nullptr;
1389 if (pServiceManager
)
1391 Reference
< XSingleServiceFactory
> xFactory
;
1392 if (PasswordContainer::impl_getStaticImplementationName().equalsAscii(pImplementationName
))
1394 xFactory
= PasswordContainer::impl_createFactory (
1395 static_cast< XMultiServiceFactory
* >(pServiceManager
));
1399 xFactory
->acquire();
1400 pResult
= xFactory
.get();
1408 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */