nss: upgrade to release 3.73
[LibreOffice.git] / svl / source / passwordcontainer / passwordcontainer.cxx
blob51fb129cddb1cda9a08987988a1a91566a0b4424
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
41 using namespace osl;
42 using namespace utl;
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++ )
56 if( i )
57 aResult.append("__");
58 OString line = OUStringToOString( lines[i], RTL_TEXTENCODING_UTF8 );
59 const char* pLine = line.getStr();
61 while( *pLine )
63 if (rtl::isAsciiAlphanumeric(static_cast<unsigned char>(*pLine)))
65 aResult.append(*pLine);
67 else
69 aResult.append("_").append( OUString::number( *pLine, 16 ) );
72 pLine++;
76 return aResult.makeStringAndClear();
80 static std::vector< OUString > getInfoFromInd( const OUString& aInd )
82 std::vector< OUString > aResult;
83 bool aStart = true;
85 OString line = OUStringToOString( aInd, RTL_TEXTENCODING_ASCII_US );
86 const char* pLine = line.getStr();
89 OUStringBuffer newItem;
90 if( !aStart )
91 pLine += 2;
92 else
93 aStart = false;
95 while( *pLine && ( pLine[0] != '_' || pLine[1] != '_' ))
96 if( *pLine != '_' )
98 newItem.append( *pLine );
99 pLine++;
101 else
103 OUString aNum;
104 for( int i = 1; i < 3; i++ )
106 if( !pLine[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!" );
112 return aResult;
115 aNum += OUStringChar( pLine[i] );
118 newItem.append( sal_Unicode( aNum.toUInt32( 16 ) ) );
119 pLine += 3;
122 aResult.push_back( newItem.makeStringAndClear() );
123 } while( pLine[0] == '_' && pLine[1] == '_' );
125 if( *pLine )
126 OSL_FAIL( "Wrong index syntax!" );
128 return aResult;
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 );
138 return true;
141 return false;
145 static OUString getAsciiLine( const ::rtl::ByteSequence& buf )
147 OUString aResult;
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()) );
160 return aResult;
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' );
175 return aResult;
179 PassMap StorageItem::getInfo()
181 PassMap aResult;
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" );
196 return aResult;
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];
208 OUString aEPasswd;
209 aPropertyValues[aNodeInd] >>= aEPasswd;
211 PassMap::iterator aIter = aResult.find( aUrl );
212 if( aIter != aResult.end() )
213 aIter->second.emplace_back( aName, aEPasswd );
214 else
216 NamePassRecord aNewRecord( aName, aEPasswd );
217 std::vector< NamePassRecord > listToAdd( 1, aNewRecord );
219 aResult.insert( PairUrlRecord( aUrl, listToAdd ) );
222 else
223 OSL_FAIL( "Wrong index syntax!" );
226 return aResult;
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" );
253 return false;
256 bool aResult = false;
257 aPropertyValues[0] >>= aResult;
259 return aResult;
263 bool StorageItem::getEncodedMP( OUString& aResult )
265 if( hasEncoded )
267 aResult = mEncoded;
268 return true;
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" );
280 return false;
283 aPropertyValues[0] >>= hasEncoded;
284 aPropertyValues[1] >>= mEncoded;
286 aResult = mEncoded;
288 return hasEncoded;
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;
308 mEncoded = aEncoded;
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!" );
337 return;
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
358 if( mainCont )
359 mainCont->Notify();
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);
392 mComponent.clear();
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);
405 mComponent.clear();
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" );
416 if( aDecoder )
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);
447 else
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" );
468 if( aEncoder )
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() );
488 //test
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] )
505 testOU = "";
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);
525 else
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() );
548 if( writeFile )
550 // the password must be already encoded
551 m_pStorageFile->update( aURL, aRecord ); // change existing ( aURL, aName ) record in the configfile
555 return;
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() );
596 sal_uInt32 nInd = 0;
597 bool bTryToDecode = true;
599 for (auto const& aNPIter : original)
601 aResult[nInd] = CopyToUserRecord( aNPIter, bTryToDecode, aHandler );
602 ++nInd;
605 return aResult;
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 );
634 else
636 OSL_FAIL( "Unexpected persistence status!" );
637 return;
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 );
647 return;
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 )
674 sal_uInt32 nInd = 0;
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 );
683 return aResult;
685 ++nInd;
688 return Sequence< UserRecord >();
692 bool PasswordContainer::createUrlRecord(
693 const PassMap::iterator & rIter,
694 bool bName,
695 const OUString & aName,
696 const Reference< XInteractionHandler >& aHandler,
697 UrlRecord & rRec )
699 if ( bName )
701 Sequence< UserRecord > aUsrRec
702 = FindUsr( rIter->second, aName, aHandler );
703 if( aUsrRec.hasElements() )
705 rRec = UrlRecord( rIter->first, aUsrRec );
706 return true;
709 else
711 rRec = UrlRecord(
712 rIter->first,
713 CopyToUserRecordSequence( rIter->second, aHandler ) );
714 return true;
716 return false;
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() )
740 UrlRecord aRec;
741 if ( createUrlRecord( aIter, bName, aName, aHandler, aRec ) )
742 return aRec;
744 else
746 OUString tmpUrl( aUrl );
747 if ( !tmpUrl.endsWith("/") )
748 tmpUrl += "/";
750 aIter = m_aContainer.lower_bound( tmpUrl );
751 if( aIter != m_aContainer.end() && aIter->first.match( tmpUrl ) )
753 UrlRecord aRec;
754 if ( createUrlRecord( aIter, bName, aName, aHandler, aRec ) )
755 return aRec;
759 while( shorterUrl( aUrl ) && !aUrl.isEmpty() );
762 return UrlRecord();
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
777 OUString aResult;
779 if ( xHandler.is() )
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 );
790 if ( !xAbort.is() )
792 const ::rtl::Reference< ucbhelper::InteractionSupplyAuthentication > & xSupp
793 = xRequest->getAuthenticationSupplier();
795 aResult = xSupp->getPassword();
800 return aResult;
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() )
812 OUString aEncodedMP;
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;
826 do {
827 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 ) );
839 else
841 std::vector< OUString > aRM( DecodePasswords( aEncodedMP, aPass, aRMode ) );
842 if( aRM.empty() || aPass != aRM[0] )
844 bAskAgain = true;
845 aRMode = PasswordRequestMode_PASSWORD_REENTER;
847 else
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() )
869 return;
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 );
877 else
878 aUrl += "/";
880 aIter = m_aContainer.find( aUrl );
883 if( aIter == m_aContainer.end() )
884 return;
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() )
909 return;
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 );
917 else
918 aUrl += "/";
920 aIter = m_aContainer.find( aUrl );
923 if( aIter == m_aContainer.end() )
924 return;
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())
930 return;
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 );
952 if( m_pStorageFile )
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);
972 else
973 ++aNPIter;
976 if( aIter->second.empty() )
978 aIter = m_aContainer.erase(aIter);
980 else
981 ++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 );
1009 return aResult;
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
1026 bResult = true;
1028 else
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;
1041 OUString aPass;
1043 do {
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() );
1049 else
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& )
1062 return bResult;
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 >() );
1110 bResult = true;
1115 return bResult;
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();
1149 if ( !bAllow )
1150 removeMasterPassword();
1152 if (m_pStorageFile->useStorage() == static_cast<bool>(bAllow))
1153 return bAllow;
1155 m_pStorageFile->setUseStorage( bAllow );
1156 return !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 >() );
1212 bResult = true;
1217 return bResult;
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);
1275 else
1276 ++aNPIter;
1280 PassMap addon;
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 );
1290 else
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;
1331 m_xAuthSupplier
1332 = new ::ucbhelper::InteractionSupplyAuthentication(
1333 this,
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
1345 Sequence<
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: */