bump product version to 6.3.0.0.beta1
[LibreOffice.git] / svl / source / passwordcontainer / passwordcontainer.cxx
blob5c59f976d8ec3d3b47684150481a5b84a777abb6
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 <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>
42 using namespace osl;
43 using namespace utl;
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++ )
57 if( i )
58 aResult.append("__");
59 OString line = OUStringToOString( lines[i], RTL_TEXTENCODING_UTF8 );
60 const sal_Char* pLine = line.getStr();
62 while( *pLine )
64 if (rtl::isAsciiAlphanumeric(static_cast<unsigned char>(*pLine)))
66 aResult.append(*pLine);
68 else
70 aResult.append("_").append( OUString::number( *pLine, 16 ) );
73 pLine++;
77 return aResult.makeStringAndClear();
81 static std::vector< OUString > getInfoFromInd( const OUString& aInd )
83 std::vector< OUString > aResult;
84 bool aStart = true;
86 OString line = OUStringToOString( aInd, RTL_TEXTENCODING_ASCII_US );
87 const sal_Char* pLine = line.getStr();
90 OUStringBuffer newItem;
91 if( !aStart )
92 pLine += 2;
93 else
94 aStart = false;
96 while( *pLine && !( pLine[0] == '_' && pLine[1] == '_' ))
97 if( *pLine != '_' )
99 newItem.append( *pLine );
100 pLine++;
102 else
104 OUString aNum;
105 for( int i = 1; i < 3; i++ )
107 if( !pLine[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!" );
113 return aResult;
116 aNum += OUStringLiteral1( pLine[i] );
119 newItem.append( OUStringLiteral1( aNum.toUInt32( 16 ) ) );
120 pLine += 3;
123 aResult.push_back( newItem.makeStringAndClear() );
124 } while( pLine[0] == '_' && pLine[1] == '_' );
126 if( *pLine )
127 OSL_FAIL( "Wrong index syntax!" );
129 return aResult;
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 );
139 return true;
142 return false;
146 static OUString getAsciiLine( const ::rtl::ByteSequence& buf )
148 OUString aResult;
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()) );
161 return aResult;
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' );
176 return aResult;
180 PassMap StorageItem::getInfo()
182 PassMap aResult;
184 Sequence< OUString > aNodeNames = ConfigItem::GetNodeNames( "Store" );
185 sal_Int32 aNodeCount = aNodeNames.getLength();
186 Sequence< OUString > aPropNames( aNodeCount );
187 sal_Int32 aNodeInd;
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" );
199 return aResult;
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];
211 OUString aEPasswd;
212 aPropertyValues[aNodeInd] >>= aEPasswd;
214 PassMap::iterator aIter = aResult.find( aUrl );
215 if( aIter != aResult.end() )
216 aIter->second.emplace_back( aName, aEPasswd );
217 else
219 NamePassRecord aNewRecord( aName, aEPasswd );
220 std::vector< NamePassRecord > listToAdd( 1, aNewRecord );
222 aResult.insert( PairUrlRecord( aUrl, listToAdd ) );
225 else
226 OSL_FAIL( "Wrong index syntax!" );
229 return aResult;
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" );
256 return false;
259 bool aResult = false;
260 aPropertyValues[0] >>= aResult;
262 return aResult;
266 bool StorageItem::getEncodedMP( OUString& aResult )
268 if( hasEncoded )
270 aResult = mEncoded;
271 return true;
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" );
283 return false;
286 aPropertyValues[0] >>= hasEncoded;
287 aPropertyValues[1] >>= mEncoded;
289 aResult = mEncoded;
291 return hasEncoded;
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;
311 mEncoded = aEncoded;
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!" );
340 return;
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
361 if( mainCont )
362 mainCont->Notify();
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);
395 mComponent.clear();
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);
408 mComponent.clear();
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" );
419 if( aDecoder )
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);
450 else
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" );
471 if( aEncoder )
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() );
491 //test
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] )
508 testOU = "";
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);
528 else
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() );
551 if( writeFile )
553 // the password must be already encoded
554 m_pStorageFile->update( aURL, aRecord ); // change existing ( aURL, aName ) record in the configfile
558 return;
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() );
599 sal_uInt32 nInd = 0;
600 bool bTryToDecode = true;
602 for (auto const& aNPIter : original)
604 aResult[nInd] = CopyToUserRecord( aNPIter, bTryToDecode, aHandler );
605 ++nInd;
608 return aResult;
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 );
637 else
639 OSL_FAIL( "Unexpected persistence status!" );
640 return;
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 );
650 return;
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 )
677 sal_uInt32 nInd = 0;
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 );
686 return aResult;
688 ++nInd;
691 return Sequence< UserRecord >();
695 bool PasswordContainer::createUrlRecord(
696 const PassMap::iterator & rIter,
697 bool bName,
698 const OUString & aName,
699 const Reference< XInteractionHandler >& aHandler,
700 UrlRecord & rRec )
702 if ( bName )
704 Sequence< UserRecord > aUsrRec
705 = FindUsr( rIter->second, aName, aHandler );
706 if( aUsrRec.hasElements() )
708 rRec = UrlRecord( rIter->first, aUsrRec );
709 return true;
712 else
714 rRec = UrlRecord(
715 rIter->first,
716 CopyToUserRecordSequence( rIter->second, aHandler ) );
717 return true;
719 return false;
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() )
743 UrlRecord aRec;
744 if ( createUrlRecord( aIter, bName, aName, aHandler, aRec ) )
745 return aRec;
747 else
749 OUString tmpUrl( aUrl );
750 if ( !tmpUrl.endsWith("/") )
751 tmpUrl += "/";
753 aIter = m_aContainer.lower_bound( tmpUrl );
754 if( aIter != m_aContainer.end() && aIter->first.match( tmpUrl ) )
756 UrlRecord aRec;
757 if ( createUrlRecord( aIter, bName, aName, aHandler, aRec ) )
758 return aRec;
762 while( shorterUrl( aUrl ) && !aUrl.isEmpty() );
765 return UrlRecord();
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
780 OUString aResult;
782 if ( xHandler.is() )
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 );
793 if ( !xAbort.is() )
795 const ::rtl::Reference< ucbhelper::InteractionSupplyAuthentication > & xSupp
796 = xRequest->getAuthenticationSupplier();
798 aResult = xSupp->getPassword();
803 return aResult;
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() )
815 OUString aEncodedMP;
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;
829 do {
830 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 ) );
842 else
844 std::vector< OUString > aRM( DecodePasswords( aEncodedMP, aPass, aRMode ) );
845 if( aRM.empty() || aPass != aRM[0] )
847 bAskAgain = true;
848 aRMode = PasswordRequestMode_PASSWORD_REENTER;
850 else
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() )
872 return;
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 );
880 else
881 aUrl += "/";
883 aIter = m_aContainer.find( aUrl );
886 if( aIter == m_aContainer.end() )
887 return;
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() )
912 return;
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 );
920 else
921 aUrl += "/";
923 aIter = m_aContainer.find( aUrl );
926 if( aIter == m_aContainer.end() )
927 return;
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 );
955 if( m_pStorageFile )
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);
975 else
976 ++aNPIter;
979 if( aIter->second.empty() )
981 aIter = m_aContainer.erase(aIter);
983 else
984 ++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 );
1012 return aResult;
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
1029 bResult = true;
1031 else
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;
1044 OUString aPass;
1046 do {
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() );
1052 else
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& )
1065 return bResult;
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 >() );
1115 bResult = true;
1120 return bResult;
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();
1154 if ( !bAllow )
1155 removeMasterPassword();
1157 if (m_pStorageFile->useStorage() == static_cast<bool>(bAllow))
1158 return bAllow;
1160 m_pStorageFile->setUseStorage( bAllow );
1161 return !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 >() );
1219 bResult = true;
1224 return bResult;
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);
1282 else
1283 ++aNPIter;
1287 PassMap addon;
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 );
1297 else
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" };
1320 return aRet;
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()));
1339 return xReturn ;
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;
1357 m_xAuthSupplier
1358 = new ::ucbhelper::InteractionSupplyAuthentication(
1359 this,
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
1371 Sequence<
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 );
1381 extern "C"
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));
1397 if (xFactory.is())
1399 xFactory->acquire();
1400 pResult = xFactory.get();
1403 return pResult;
1406 } // extern "C"
1408 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */