bump product version to 4.2.0.1
[LibreOffice.git] / svl / source / passwordcontainer / passwordcontainer.cxx
blobc59e296c43a605925ce7b085249c2d499ef36a4c
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 <comphelper/processfactory.hxx>
26 #include <comphelper/string.hxx>
27 #include <com/sun/star/registry/XSimpleRegistry.hpp>
28 #include <com/sun/star/beans/PropertyValue.hpp>
29 #include <com/sun/star/task/InteractionHandler.hpp>
30 #include <com/sun/star/task/MasterPasswordRequest.hpp>
31 #include <com/sun/star/task/NoMasterException.hpp>
33 #include <rtl/cipher.h>
34 #include <rtl/digest.h>
35 #include <rtl/byteseq.hxx>
37 using namespace std;
38 using namespace osl;
39 using namespace utl;
40 using namespace com::sun::star;
41 using namespace com::sun::star::uno;
42 using namespace com::sun::star::registry;
43 using namespace com::sun::star::lang;
44 using namespace com::sun::star::task;
45 using namespace com::sun::star::ucb;
48 static OUString createIndex( vector< OUString > lines )
50 OString aResult;
51 const sal_Char* pLine;
53 for( unsigned int i = 0; i < lines.size(); i++ )
55 if( i )
56 aResult += OString( "__" );
57 OString line = OUStringToOString( lines[i], RTL_TEXTENCODING_UTF8 );
58 pLine = line.getStr();
60 while( *pLine )
62 if (comphelper::string::isalnumAscii(*pLine))
64 aResult += OString( *pLine );
66 else
68 aResult += OString("_");
69 aResult += OString::number( *pLine, 16 );
72 pLine++;
76 return OUString::createFromAscii( aResult.getStr() );
80 static vector< OUString > getInfoFromInd( OUString aInd )
82 vector< OUString > aResult;
83 sal_Bool aStart = sal_True;
85 OString line = OUStringToOString( aInd, RTL_TEXTENCODING_ASCII_US );
86 const sal_Char* pLine = line.getStr();
89 OUString newItem;
90 if( !aStart )
91 pLine += 2;
92 else
93 aStart = sal_False;
95 while( *pLine && !( pLine[0] == '_' && pLine[1] == '_' ))
96 if( *pLine != '_' )
98 newItem += OUString( (sal_Unicode) *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!\n" );
112 return aResult;
115 aNum += OUString( (sal_Unicode) pLine[i] );
118 newItem += OUString( (sal_Unicode) aNum.toUInt32( 16 ) );
119 pLine += 3;
122 aResult.push_back( newItem );
123 } while( pLine[0] == '_' && pLine[1] == '_' );
125 if( *pLine )
126 OSL_FAIL( "Wrong index syntax!\n" );
128 return aResult;
132 static sal_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 sal_True;
141 return sal_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] = ( ((sal_uInt8)buf[ind]) >> 4 ) + 'a';
154 outbuf[ind*2+1] = ( ((sal_uInt8)buf[ind]) & 0x0f ) + 'a';
156 outbuf[buf.getLength()*2] = '\0';
158 aResult = OUString::createFromAscii( (sal_Char*)outbuf.getArray() );
160 return aResult;
164 static ::rtl::ByteSequence getBufFromAsciiLine( OUString line )
166 OSL_ENSURE( line.getLength() % 2 == 0, "Wrong syntax!\n" );
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] = ( (sal_uInt8)( tmpLine[ind*2] - 'a' ) << 4 ) | (sal_uInt8)( tmpLine[ind*2+1] - 'a' );
175 return aResult;
179 static Sequence< OUString > copyVectorToSequence( const vector< OUString >& original )
181 Sequence< OUString > newOne ( original.size() );
182 for( unsigned int i = 0; i < original.size() ; i++ )
183 newOne[i] = original[i];
185 return newOne;
188 static vector< OUString > copySequenceToVector( const Sequence< OUString >& original )
190 vector< OUString > newOne ( original.getLength() );
191 for( int i = 0; i < original.getLength() ; i++ )
192 newOne[i] = original[i];
194 return newOne;
198 PassMap StorageItem::getInfo()
200 PassMap aResult;
202 Sequence< OUString > aNodeNames = ConfigItem::GetNodeNames( OUString("Store") );
203 sal_Int32 aNodeCount = aNodeNames.getLength();
204 Sequence< OUString > aPropNames( aNodeCount );
205 sal_Int32 aNodeInd;
207 for( aNodeInd = 0; aNodeInd < aNodeCount; ++aNodeInd )
209 aPropNames[aNodeInd] = "Store/Passwordstorage['" + aNodeNames[aNodeInd] + "']/Password";
212 Sequence< Any > aPropertyValues = ConfigItem::GetProperties( aPropNames );
214 if( aPropertyValues.getLength() != aNodeNames.getLength() )
216 OSL_ENSURE( aPropertyValues.getLength() == aNodeNames.getLength(), "Problems during reading\n" );
217 return aResult;
220 for( aNodeInd = 0; aNodeInd < aNodeCount; ++aNodeInd )
222 vector< OUString > aUrlUsr = getInfoFromInd( aNodeNames[aNodeInd] );
224 if( aUrlUsr.size() == 2 )
226 OUString aUrl = aUrlUsr[0];
227 OUString aName = aUrlUsr[1];
229 OUString aEPasswd;
230 aPropertyValues[aNodeInd] >>= aEPasswd;
232 PassMap::iterator aIter = aResult.find( aUrl );
233 if( aIter != aResult.end() )
234 aIter->second.push_back( NamePassRecord( aName, aEPasswd ) );
235 else
237 NamePassRecord aNewRecord( aName, aEPasswd );
238 list< NamePassRecord > listToAdd( 1, aNewRecord );
240 aResult.insert( PairUrlRecord( aUrl, listToAdd ) );
243 else
244 OSL_FAIL( "Wrong index sintax!\n" );
247 return aResult;
251 void StorageItem::setUseStorage( bool bUse )
253 Sequence< OUString > sendNames(1);
254 Sequence< uno::Any > sendVals(1);
256 sendNames[0] = "UseStorage";
258 sendVals[0] <<= bUse;
260 ConfigItem::SetModified();
261 ConfigItem::PutProperties( sendNames, sendVals );
265 bool StorageItem::useStorage()
267 Sequence< OUString > aNodeNames( 1 );
268 aNodeNames[0] = "UseStorage";
270 Sequence< Any > aPropertyValues = ConfigItem::GetProperties( aNodeNames );
272 if( aPropertyValues.getLength() != aNodeNames.getLength() )
274 OSL_ENSURE( aPropertyValues.getLength() == aNodeNames.getLength(), "Problems during reading\n" );
275 return sal_False;
278 bool aResult = false;
279 aPropertyValues[0] >>= aResult;
281 return aResult;
285 bool StorageItem::getEncodedMP( OUString& aResult )
287 if( hasEncoded )
289 aResult = mEncoded;
290 return true;
293 Sequence< OUString > aNodeNames( 2 );
294 aNodeNames[0] = "HasMaster";
295 aNodeNames[1] = "Master";
297 Sequence< Any > aPropertyValues = ConfigItem::GetProperties( aNodeNames );
299 if( aPropertyValues.getLength() != aNodeNames.getLength() )
301 OSL_ENSURE( aPropertyValues.getLength() == aNodeNames.getLength(), "Problems during reading\n" );
302 return false;
305 aPropertyValues[0] >>= hasEncoded;
306 aPropertyValues[1] >>= mEncoded;
308 aResult = mEncoded;
310 return hasEncoded;
314 void StorageItem::setEncodedMP( const OUString& aEncoded, bool bAcceptEmpty )
316 Sequence< OUString > sendNames(2);
317 Sequence< uno::Any > sendVals(2);
319 sendNames[0] = "HasMaster";
320 sendNames[1] = "Master";
322 sal_Bool bHasMaster = ( !aEncoded.isEmpty() || bAcceptEmpty );
323 sendVals[0] <<= bHasMaster;
324 sendVals[1] <<= aEncoded;
326 ConfigItem::SetModified();
327 ConfigItem::PutProperties( sendNames, sendVals );
329 hasEncoded = bHasMaster;
330 mEncoded = aEncoded;
334 void StorageItem::remove( const OUString& aURL, const OUString& aName )
336 vector < OUString > forIndex;
337 forIndex.push_back( aURL );
338 forIndex.push_back( aName );
340 Sequence< OUString > sendSeq(1);
342 sendSeq[0] = createIndex( forIndex );
344 ConfigItem::ClearNodeElements( OUString("Store"), sendSeq );
348 void StorageItem::clear()
350 ConfigItem::ClearNodeSet( OUString("Store") );
354 void StorageItem::update( const OUString& aURL, const NamePassRecord& aRecord )
356 if ( !aRecord.HasPasswords( PERSISTENT_RECORD ) )
358 OSL_FAIL( "Unexpected storing of a record!" );
359 return;
362 vector < OUString > forIndex;
363 forIndex.push_back( aURL );
364 forIndex.push_back( aRecord.GetUserName() );
366 Sequence< beans::PropertyValue > sendSeq(1);
368 sendSeq[0].Name = "Store/Passwordstorage['" + createIndex( forIndex ) + "']/Password";
370 sendSeq[0].Value <<= aRecord.GetPersPasswords();
372 ConfigItem::SetModified();
373 ConfigItem::SetSetProperties( OUString("Store"), sendSeq );
377 void StorageItem::Notify( const Sequence< OUString >& )
379 // this feature still should not be used
380 if( mainCont )
381 mainCont->Notify();
385 void StorageItem::Commit()
387 // Do nothing, we stored everything we want already
391 PasswordContainer::PasswordContainer( const Reference<XMultiServiceFactory>& xServiceFactory ):
392 m_pStorageFile( NULL )
394 // m_pStorageFile->Notify() can be called
395 ::osl::MutexGuard aGuard( mMutex );
397 mComponent = Reference< XComponent >( xServiceFactory, UNO_QUERY );
398 mComponent->addEventListener( this );
400 m_pStorageFile = new StorageItem( this, OUString("Office.Common/Passwords") );
401 if( m_pStorageFile )
402 if( m_pStorageFile->useStorage() )
403 m_aContainer = m_pStorageFile->getInfo();
407 PasswordContainer::~PasswordContainer()
409 ::osl::MutexGuard aGuard( mMutex );
411 if( m_pStorageFile )
413 delete m_pStorageFile;
414 m_pStorageFile = NULL;
417 if( mComponent.is() )
419 mComponent->removeEventListener(this);
420 mComponent.clear();
425 void SAL_CALL PasswordContainer::disposing( const EventObject& ) throw(RuntimeException)
427 ::osl::MutexGuard aGuard( mMutex );
429 if( m_pStorageFile )
431 delete m_pStorageFile;
432 m_pStorageFile = NULL;
435 if( mComponent.is() )
437 //mComponent->removeEventListener(this);
438 mComponent.clear();
443 vector< OUString > PasswordContainer::DecodePasswords( const OUString& aLine, const OUString& aMasterPasswd ) throw(RuntimeException)
445 if( !aMasterPasswd.isEmpty() )
447 rtlCipher aDecoder = rtl_cipher_create (rtl_Cipher_AlgorithmBF, rtl_Cipher_ModeStream );
448 OSL_ENSURE( aDecoder, "Can't create decoder\n" );
450 if( aDecoder )
452 OSL_ENSURE( aMasterPasswd.getLength() == RTL_DIGEST_LENGTH_MD5 * 2, "Wrong master password format!\n" );
454 unsigned char code[RTL_DIGEST_LENGTH_MD5];
455 for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ )
456 code[ ind ] = (char)(aMasterPasswd.copy( ind*2, 2 ).toUInt32(16));
458 rtlCipherError result = rtl_cipher_init (
459 aDecoder, rtl_Cipher_DirectionDecode,
460 code, RTL_DIGEST_LENGTH_MD5, NULL, 0 );
462 if( result == rtl_Cipher_E_None )
464 ::rtl::ByteSequence aSeq = getBufFromAsciiLine( aLine );
466 ::rtl::ByteSequence resSeq( aSeq.getLength() );
468 result = rtl_cipher_decode ( aDecoder, (sal_uInt8*)aSeq.getArray(), aSeq.getLength(),
469 (sal_uInt8*)resSeq.getArray(), resSeq.getLength() );
471 OUString aPasswd( ( sal_Char* )resSeq.getArray(), resSeq.getLength(), RTL_TEXTENCODING_UTF8 );
473 rtl_cipher_destroy (aDecoder);
475 return getInfoFromInd( aPasswd );
478 rtl_cipher_destroy (aDecoder);
481 else
483 OSL_FAIL( "No master password provided!\n" );
484 // throw special exception
487 // problems with decoding
488 OSL_FAIL( "Problem with decoding\n" );
489 throw RuntimeException("Can't decode!", Reference< XInterface >() );
494 OUString PasswordContainer::EncodePasswords( vector< OUString > lines, const OUString& aMasterPasswd ) throw(RuntimeException)
496 if( !aMasterPasswd.isEmpty() )
498 OString aSeq = OUStringToOString( createIndex( lines ), RTL_TEXTENCODING_UTF8 );
500 rtlCipher aEncoder = rtl_cipher_create (rtl_Cipher_AlgorithmBF, rtl_Cipher_ModeStream );
501 OSL_ENSURE( aEncoder, "Can't create encoder\n" );
503 if( aEncoder )
505 OSL_ENSURE( aMasterPasswd.getLength() == RTL_DIGEST_LENGTH_MD5 * 2, "Wrong master password format!\n" );
507 unsigned char code[RTL_DIGEST_LENGTH_MD5];
508 for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ )
509 code[ ind ] = (char)(aMasterPasswd.copy( ind*2, 2 ).toUInt32(16));
511 rtlCipherError result = rtl_cipher_init (
512 aEncoder, rtl_Cipher_DirectionEncode,
513 code, RTL_DIGEST_LENGTH_MD5, NULL, 0 );
515 if( result == rtl_Cipher_E_None )
517 ::rtl::ByteSequence resSeq(aSeq.getLength()+1);
519 result = rtl_cipher_encode ( aEncoder, (sal_uInt8*)aSeq.getStr(), aSeq.getLength()+1,
520 (sal_uInt8*)resSeq.getArray(), resSeq.getLength() );
523 //test
524 rtlCipherError result = rtl_cipher_init (
525 aEncoder, rtl_Cipher_DirectionDecode,
526 code, RTL_DIGEST_LENGTH_MD5, NULL, 0 );
529 if( result == rtl_Cipher_E_None )
531 OUString testOU = getAsciiLine( resSeq );
532 ::rtl::ByteSequence aSeq1 = getBufFromAsciiLine( testOU );
534 ::rtl::ByteSequence resSeq1( aSeq1.getLength() );
536 if( resSeq.getLength() == aSeq1.getLength() )
538 for( int ind = 0; ind < aSeq1.getLength(); ind++ )
539 if( resSeq[ind] != aSeq1[ind] )
540 testOU = "";
543 result = rtl_cipher_decode ( aEncoder, (sal_uInt8*)aSeq1.getArray(), aSeq1.getLength(),
544 (sal_uInt8*)resSeq1.getArray(), resSeq1.getLength() );
546 OUString aPasswd( ( sal_Char* )resSeq1.getArray(), resSeq1.getLength(), RTL_TEXTENCODING_UTF8 );
550 rtl_cipher_destroy (aEncoder);
552 if( result == rtl_Cipher_E_None )
553 return getAsciiLine( resSeq );
557 rtl_cipher_destroy (aEncoder);
560 else
562 OSL_FAIL( "No master password provided!\n" );
563 // throw special exception
566 // problems with encoding
567 OSL_FAIL( "Problem with encoding\n" );
568 throw RuntimeException("Can't encode!", Reference< XInterface >() );
572 void PasswordContainer::UpdateVector( const OUString& aURL, list< NamePassRecord >& toUpdate, NamePassRecord& aRecord, bool writeFile ) throw(RuntimeException)
574 for( list< NamePassRecord >::iterator aNPIter = toUpdate.begin(); aNPIter != toUpdate.end(); ++aNPIter )
575 if( aNPIter->GetUserName().equals( aRecord.GetUserName() ) )
577 if( aRecord.HasPasswords( MEMORY_RECORD ) )
578 aNPIter->SetMemPasswords( aRecord.GetMemPasswords() );
580 if( aRecord.HasPasswords( PERSISTENT_RECORD ) )
582 aNPIter->SetPersPasswords( aRecord.GetPersPasswords() );
584 if( writeFile )
586 // the password must be already encoded
587 m_pStorageFile->update( aURL, aRecord ); // change existing ( aURL, aName ) record in the configfile
591 return;
595 if( aRecord.HasPasswords( PERSISTENT_RECORD ) && writeFile )
597 // the password must be already encoded
598 m_pStorageFile->update( aURL, aRecord ); // add new aName to the existing url
601 toUpdate.insert( toUpdate.begin(), aRecord );
605 UserRecord PasswordContainer::CopyToUserRecord( const NamePassRecord& aRecord, bool& io_bTryToDecode, const Reference< XInteractionHandler >& aHandler )
607 ::std::vector< OUString > aPasswords;
608 if( aRecord.HasPasswords( MEMORY_RECORD ) )
609 aPasswords = aRecord.GetMemPasswords();
611 if( io_bTryToDecode && aRecord.HasPasswords( PERSISTENT_RECORD ) )
615 ::std::vector< OUString > aDecodedPasswords = DecodePasswords( aRecord.GetPersPasswords(), GetMasterPassword( aHandler ) );
616 aPasswords.insert( aPasswords.end(), aDecodedPasswords.begin(), aDecodedPasswords.end() );
618 catch( NoMasterException& )
620 // if master password could not be detected the entry will be just ignored
621 io_bTryToDecode = false;
625 return UserRecord( aRecord.GetUserName(), copyVectorToSequence( aPasswords ) );
629 Sequence< UserRecord > PasswordContainer::CopyToUserRecordSequence( const list< NamePassRecord >& original, const Reference< XInteractionHandler >& aHandler ) throw(RuntimeException)
631 Sequence< UserRecord > aResult( original.size() );
632 sal_uInt32 nInd = 0;
633 bool bTryToDecode = true;
635 for( list< NamePassRecord >::const_iterator aNPIter = original.begin();
636 aNPIter != original.end();
637 ++aNPIter, ++nInd )
639 aResult[nInd] = CopyToUserRecord( *aNPIter, bTryToDecode, aHandler );
642 return aResult;
646 void SAL_CALL PasswordContainer::add( const OUString& Url, const OUString& UserName, const Sequence< OUString >& Passwords, const Reference< XInteractionHandler >& aHandler ) throw(RuntimeException)
648 ::osl::MutexGuard aGuard( mMutex );
650 PrivateAdd( Url, UserName, Passwords, MEMORY_RECORD, aHandler );
654 void SAL_CALL PasswordContainer::addPersistent( const OUString& Url, const OUString& UserName, const Sequence< OUString >& Passwords, const Reference< XInteractionHandler >& aHandler ) throw(RuntimeException)
656 ::osl::MutexGuard aGuard( mMutex );
658 PrivateAdd( Url, UserName, Passwords, PERSISTENT_RECORD, aHandler );
662 void PasswordContainer::PrivateAdd( const OUString& Url, const OUString& UserName, const Sequence< OUString >& Passwords, char Mode, const Reference< XInteractionHandler >& aHandler ) throw(RuntimeException)
664 NamePassRecord aRecord( UserName );
665 ::std::vector< OUString > aStorePass = copySequenceToVector( Passwords );
667 if( Mode == PERSISTENT_RECORD )
668 aRecord.SetPersPasswords( EncodePasswords( aStorePass, GetMasterPassword( aHandler ) ) );
669 else if( Mode == MEMORY_RECORD )
670 aRecord.SetMemPasswords( aStorePass );
671 else
673 OSL_FAIL( "Unexpected persistence status!" );
674 return;
677 if( !m_aContainer.empty() )
679 PassMap::iterator aIter = m_aContainer.find( Url );
681 if( aIter != m_aContainer.end() )
683 UpdateVector( aIter->first, aIter->second, aRecord, sal_True );
684 return;
688 list< NamePassRecord > listToAdd( 1, aRecord );
689 m_aContainer.insert( PairUrlRecord( Url, listToAdd ) );
691 if( Mode == PERSISTENT_RECORD && m_pStorageFile && m_pStorageFile->useStorage() )
692 m_pStorageFile->update( Url, aRecord );
698 UrlRecord SAL_CALL PasswordContainer::find( const OUString& aURL, const Reference< XInteractionHandler >& aHandler ) throw(RuntimeException)
700 return find( aURL, OUString(), false, aHandler );
704 UrlRecord SAL_CALL PasswordContainer::findForName( const OUString& aURL, const OUString& aName, const Reference< XInteractionHandler >& aHandler ) throw(RuntimeException)
706 return find( aURL, aName, true, aHandler );
710 Sequence< UserRecord > PasswordContainer::FindUsr( const list< NamePassRecord >& userlist, const OUString& aName, const Reference< XInteractionHandler >& aHandler ) throw(RuntimeException)
712 sal_uInt32 nInd = 0;
713 for( list< NamePassRecord >::const_iterator aNPIter = userlist.begin();
714 aNPIter != userlist.end();
715 ++aNPIter, ++nInd )
717 if( aNPIter->GetUserName().equals( aName ) )
719 Sequence< UserRecord > aResult(1);
720 bool bTryToDecode = true;
721 aResult[0] = CopyToUserRecord( *aNPIter, bTryToDecode, aHandler );
723 return aResult;
727 return Sequence< UserRecord >();
731 bool PasswordContainer::createUrlRecord(
732 const PassMap::iterator & rIter,
733 bool bName,
734 const OUString & aName,
735 const Reference< XInteractionHandler >& aHandler,
736 UrlRecord & rRec )
737 throw( RuntimeException )
739 if ( bName )
741 Sequence< UserRecord > aUsrRec
742 = FindUsr( rIter->second, aName, aHandler );
743 if( aUsrRec.getLength() )
745 rRec = UrlRecord( rIter->first, aUsrRec );
746 return true;
749 else
751 rRec = UrlRecord(
752 rIter->first,
753 CopyToUserRecordSequence( rIter->second, aHandler ) );
754 return true;
756 return false;
760 UrlRecord PasswordContainer::find(
761 const OUString& aURL,
762 const OUString& aName,
763 bool bName, // only needed to support empty user names
764 const Reference< XInteractionHandler >& aHandler ) throw(RuntimeException)
766 ::osl::MutexGuard aGuard( mMutex );
768 if( !m_aContainer.empty() && !aURL.isEmpty() )
770 OUString aUrl( aURL );
772 // each iteration remove last '/...' section from the aUrl
773 // while it's possible, up to the most left '://'
776 // first look for <url>/somename and then look for <url>/somename/...
777 PassMap::iterator aIter = m_aContainer.find( aUrl );
778 if( aIter != m_aContainer.end() )
780 UrlRecord aRec;
781 if ( createUrlRecord( aIter, bName, aName, aHandler, aRec ) )
782 return aRec;
784 else
786 OUString tmpUrl( aUrl );
787 if ( !tmpUrl.endsWith("/") )
788 tmpUrl += "/";
790 aIter = m_aContainer.lower_bound( tmpUrl );
791 if( aIter != m_aContainer.end() && aIter->first.match( tmpUrl ) )
793 UrlRecord aRec;
794 if ( createUrlRecord( aIter, bName, aName, aHandler, aRec ) )
795 return aRec;
799 while( shorterUrl( aUrl ) && !aUrl.isEmpty() );
802 return UrlRecord();
805 OUString PasswordContainer::GetDefaultMasterPassword()
807 OUString aResult;
808 for ( sal_Int32 nInd = 0; nInd < RTL_DIGEST_LENGTH_MD5; nInd++ )
809 aResult += "aa";
811 return aResult;
814 OUString PasswordContainer::RequestPasswordFromUser( PasswordRequestMode aRMode, const uno::Reference< task::XInteractionHandler >& xHandler )
816 // empty string means that the call was cancelled or just failed
817 OUString aResult;
819 if ( xHandler.is() )
821 ::rtl::Reference< MasterPasswordRequest_Impl > xRequest = new MasterPasswordRequest_Impl( aRMode );
823 xHandler->handle( xRequest.get() );
825 ::rtl::Reference< ucbhelper::InteractionContinuation > xSelection = xRequest->getSelection();
827 if ( xSelection.is() )
829 Reference< XInteractionAbort > xAbort( xSelection.get(), UNO_QUERY );
830 if ( !xAbort.is() )
832 const ::rtl::Reference< ucbhelper::InteractionSupplyAuthentication > & xSupp
833 = xRequest->getAuthenticationSupplier();
835 aResult = xSupp->getPassword();
840 return aResult;
844 OUString PasswordContainer::GetMasterPassword( const Reference< XInteractionHandler >& aHandler ) throw(RuntimeException)
846 PasswordRequestMode aRMode = PasswordRequestMode_PASSWORD_ENTER;
847 if( !m_pStorageFile || !m_pStorageFile->useStorage() )
848 throw NoMasterException("Password storing is not active!", Reference< XInterface >(), aRMode );
850 if( m_aMasterPasswd.isEmpty() && aHandler.is() )
852 OUString aEncodedMP;
853 sal_Bool bAskAgain = sal_False;
854 sal_Bool bDefaultPassword = sal_False;
856 if( !m_pStorageFile->getEncodedMP( aEncodedMP ) )
857 aRMode = PasswordRequestMode_PASSWORD_CREATE;
858 else if ( aEncodedMP.isEmpty() )
860 m_aMasterPasswd = GetDefaultMasterPassword();
861 bDefaultPassword = sal_True;
864 if ( !bDefaultPassword )
866 do {
867 bAskAgain = sal_False;
869 OUString aPass = RequestPasswordFromUser( aRMode, aHandler );
870 if ( !aPass.isEmpty() )
872 if( aRMode == PasswordRequestMode_PASSWORD_CREATE )
874 m_aMasterPasswd = aPass;
875 vector< OUString > aMaster( 1, m_aMasterPasswd );
877 m_pStorageFile->setEncodedMP( EncodePasswords( aMaster, m_aMasterPasswd ) );
879 else
881 vector< OUString > aRM( DecodePasswords( aEncodedMP, aPass ) );
882 if( aRM.empty() || !aPass.equals( aRM[0] ) )
884 bAskAgain = sal_True;
885 aRMode = PasswordRequestMode_PASSWORD_REENTER;
887 else
888 m_aMasterPasswd = aPass;
892 } while( bAskAgain );
896 if ( m_aMasterPasswd.isEmpty() )
897 throw NoMasterException("No master password!", Reference< XInterface >(), aRMode );
899 return m_aMasterPasswd;
903 void SAL_CALL PasswordContainer::remove( const OUString& aURL, const OUString& aName ) throw(RuntimeException)
905 ::osl::MutexGuard aGuard( mMutex );
907 OUString aUrl( aURL );
908 if( !m_aContainer.empty() )
910 PassMap::iterator aIter = m_aContainer.find( aUrl );
912 if( aIter == m_aContainer.end() )
914 if( aUrl.endsWith("/") )
915 aUrl = aUrl.copy( 0, aUrl.getLength() - 1 );
916 else
917 aUrl += "/";
919 aIter = m_aContainer.find( aUrl );
922 if( aIter != m_aContainer.end() )
924 for( list< NamePassRecord >::iterator aNPIter = aIter->second.begin(); aNPIter != aIter->second.end(); ++aNPIter )
925 if( aNPIter->GetUserName().equals( aName ) )
927 if( aNPIter->HasPasswords( PERSISTENT_RECORD ) && m_pStorageFile )
928 m_pStorageFile->remove( aURL, aName ); // remove record ( aURL, aName )
930 // the iterator will not be used any more so it can be removed directly
931 aIter->second.erase( aNPIter );
933 if( aIter->second.begin() == aIter->second.end() )
934 m_aContainer.erase( aIter );
936 return;
943 void SAL_CALL PasswordContainer::removePersistent( const OUString& aURL, const OUString& aName ) throw(RuntimeException)
945 ::osl::MutexGuard aGuard( mMutex );
947 OUString aUrl( aURL );
948 if( !m_aContainer.empty() )
950 PassMap::iterator aIter = m_aContainer.find( aUrl );
952 if( aIter == m_aContainer.end() )
954 if( aUrl.endsWith("/") )
955 aUrl = aUrl.copy( 0, aUrl.getLength() - 1 );
956 else
957 aUrl += "/";
959 aIter = m_aContainer.find( aUrl );
962 if( aIter != m_aContainer.end() )
964 for( list< NamePassRecord >::iterator aNPIter = aIter->second.begin(); aNPIter != aIter->second.end(); ++aNPIter )
965 if( aNPIter->GetUserName().equals( aName ) )
967 if( aNPIter->HasPasswords( PERSISTENT_RECORD ) )
969 // TODO/LATER: should the password be converted to MemoryPassword?
970 aNPIter->RemovePasswords( PERSISTENT_RECORD );
972 if ( m_pStorageFile )
973 m_pStorageFile->remove( aURL, aName ); // remove record ( aURL, aName )
976 if( !aNPIter->HasPasswords( MEMORY_RECORD ) )
977 aIter->second.erase( aNPIter );
979 if( aIter->second.begin() == aIter->second.end() )
980 m_aContainer.erase( aIter );
982 return;
988 void SAL_CALL PasswordContainer::removeAllPersistent() throw(RuntimeException)
990 ::osl::MutexGuard aGuard( mMutex );
992 if( m_pStorageFile )
993 m_pStorageFile->clear();
995 for( PassMap::iterator aIter = m_aContainer.begin(); aIter != m_aContainer.end(); )
997 for( list< NamePassRecord >::iterator aNPIter = aIter->second.begin(); aNPIter != aIter->second.end(); )
999 if( aNPIter->HasPasswords( PERSISTENT_RECORD ) )
1001 // TODO/LATER: should the password be converted to MemoryPassword?
1002 aNPIter->RemovePasswords( PERSISTENT_RECORD );
1004 if ( m_pStorageFile )
1005 m_pStorageFile->remove( aIter->first, aNPIter->GetUserName() ); // remove record ( aURL, aName )
1008 if( !aNPIter->HasPasswords( MEMORY_RECORD ) )
1010 list< NamePassRecord >::iterator aIterToDelete( aNPIter );
1011 ++aNPIter;
1012 aIter->second.erase( aIterToDelete );
1014 else
1015 ++aNPIter;
1018 if( aIter->second.begin() == aIter->second.end() )
1020 PassMap::iterator aIterToDelete( aIter );
1021 ++aIter;
1022 m_aContainer.erase( aIterToDelete );
1024 else
1025 ++aIter;
1029 Sequence< UrlRecord > SAL_CALL PasswordContainer::getAllPersistent( const Reference< XInteractionHandler >& xHandler ) throw(RuntimeException)
1031 Sequence< UrlRecord > aResult;
1033 ::osl::MutexGuard aGuard( mMutex );
1034 for( PassMap::iterator aIter = m_aContainer.begin(); aIter != m_aContainer.end(); ++aIter )
1036 Sequence< UserRecord > aUsers;
1037 for( list< NamePassRecord >::iterator aNPIter = aIter->second.begin(); aNPIter != aIter->second.end(); ++aNPIter )
1038 if( aNPIter->HasPasswords( PERSISTENT_RECORD ) )
1040 sal_Int32 oldLen = aUsers.getLength();
1041 aUsers.realloc( oldLen + 1 );
1042 aUsers[ oldLen ] = UserRecord( aNPIter->GetUserName(), copyVectorToSequence( DecodePasswords( aNPIter->GetPersPasswords(), GetMasterPassword( xHandler ) ) ) );
1045 if( aUsers.getLength() )
1047 sal_Int32 oldLen = aResult.getLength();
1048 aResult.realloc( oldLen + 1 );
1049 aResult[ oldLen ] = UrlRecord( aIter->first, aUsers );
1053 return aResult;
1056 sal_Bool SAL_CALL PasswordContainer::authorizateWithMasterPassword( const uno::Reference< task::XInteractionHandler >& xHandler )
1057 throw (uno::RuntimeException)
1059 sal_Bool bResult = sal_False;
1060 OUString aEncodedMP;
1061 uno::Reference< task::XInteractionHandler > xTmpHandler = xHandler;
1062 ::osl::MutexGuard aGuard( mMutex );
1064 // the method should fail if there is no master password
1065 if( m_pStorageFile && m_pStorageFile->useStorage() && m_pStorageFile->getEncodedMP( aEncodedMP ) )
1067 if ( aEncodedMP.isEmpty() )
1069 // this is a default master password
1070 // no UI is necessary
1071 bResult = sal_True;
1073 else
1075 if ( !xTmpHandler.is() )
1077 uno::Reference< lang::XMultiServiceFactory > xFactory( mComponent, uno::UNO_QUERY_THROW );
1078 uno::Reference< uno::XComponentContext > xContext( comphelper::getComponentContext(xFactory) );
1079 xTmpHandler.set( InteractionHandler::createWithParent(xContext, 0), uno::UNO_QUERY_THROW );
1082 if ( !m_aMasterPasswd.isEmpty() )
1084 // there is a password, it should be just rechecked
1085 PasswordRequestMode aRMode = PasswordRequestMode_PASSWORD_ENTER;
1086 OUString aPass;
1088 do {
1089 aPass = RequestPasswordFromUser( aRMode, xTmpHandler );
1090 bResult = ( !aPass.isEmpty() && aPass.equals( m_aMasterPasswd ) );
1091 aRMode = PasswordRequestMode_PASSWORD_REENTER; // further questions with error notification
1092 } while( !bResult && !aPass.isEmpty() );
1094 else
1098 // ask for the password, if user provide no correct password an exception will be thrown
1099 bResult = !GetMasterPassword( xTmpHandler ).isEmpty();
1101 catch( uno::Exception& )
1107 return bResult;
1110 sal_Bool SAL_CALL PasswordContainer::changeMasterPassword( const uno::Reference< task::XInteractionHandler >& xHandler )
1111 throw (uno::RuntimeException)
1113 sal_Bool bResult = sal_False;
1114 uno::Reference< task::XInteractionHandler > xTmpHandler = xHandler;
1115 ::osl::MutexGuard aGuard( mMutex );
1117 if ( m_pStorageFile && m_pStorageFile->useStorage() )
1119 if ( !xTmpHandler.is() )
1121 uno::Reference< lang::XMultiServiceFactory > xFactory( mComponent, uno::UNO_QUERY_THROW );
1122 uno::Reference< uno::XComponentContext > xContext( comphelper::getComponentContext(xFactory) );
1123 xTmpHandler.set( InteractionHandler::createWithParent(xContext, 0), uno::UNO_QUERY_THROW );
1126 sal_Bool bCanChangePassword = sal_True;
1127 // if there is already a stored master password it should be entered by the user before the change happen
1128 OUString aEncodedMP;
1129 if( !m_aMasterPasswd.isEmpty() || m_pStorageFile->getEncodedMP( aEncodedMP ) )
1130 bCanChangePassword = authorizateWithMasterPassword( xTmpHandler );
1132 if ( bCanChangePassword )
1134 // ask for the new password, but do not set it
1135 PasswordRequestMode aRMode = PasswordRequestMode_PASSWORD_CREATE;
1136 OUString aPass = RequestPasswordFromUser( aRMode, xTmpHandler );
1138 if ( !aPass.isEmpty() )
1140 // get all the persistent entries if it is possible
1141 Sequence< UrlRecord > aPersistent = getAllPersistent( uno::Reference< task::XInteractionHandler >() );
1143 // remove the master password and the entries persistence
1144 removeMasterPassword();
1146 // store the new master password
1147 m_aMasterPasswd = aPass;
1148 vector< OUString > aMaster( 1, m_aMasterPasswd );
1149 m_pStorageFile->setEncodedMP( EncodePasswords( aMaster, m_aMasterPasswd ) );
1151 // store all the entries with the new password
1152 for ( int nURLInd = 0; nURLInd < aPersistent.getLength(); nURLInd++ )
1153 for ( int nNameInd = 0; nNameInd< aPersistent[nURLInd].UserList.getLength(); nNameInd++ )
1154 addPersistent( aPersistent[nURLInd].Url,
1155 aPersistent[nURLInd].UserList[nNameInd].UserName,
1156 aPersistent[nURLInd].UserList[nNameInd].Passwords,
1157 uno::Reference< task::XInteractionHandler >() );
1159 bResult = sal_True;
1164 return bResult;
1167 void SAL_CALL PasswordContainer::removeMasterPassword()
1168 throw (uno::RuntimeException)
1170 // remove all the stored passwords and the master password
1171 removeAllPersistent();
1173 ::osl::MutexGuard aGuard( mMutex );
1174 if ( m_pStorageFile )
1176 m_aMasterPasswd = "";
1177 m_pStorageFile->setEncodedMP( OUString() ); // let the master password be removed from configuration
1181 ::sal_Bool SAL_CALL PasswordContainer::hasMasterPassword( )
1182 throw (::com::sun::star::uno::RuntimeException)
1184 ::osl::MutexGuard aGuard( mMutex );
1186 if ( !m_pStorageFile )
1187 throw uno::RuntimeException();
1189 OUString aEncodedMP;
1190 return ( m_pStorageFile->useStorage() && m_pStorageFile->getEncodedMP( aEncodedMP ) );
1193 ::sal_Bool SAL_CALL PasswordContainer::allowPersistentStoring( ::sal_Bool bAllow )
1194 throw (::com::sun::star::uno::RuntimeException)
1196 ::osl::MutexGuard aGuard( mMutex );
1198 if ( !m_pStorageFile )
1199 throw uno::RuntimeException();
1201 if ( !bAllow )
1202 removeMasterPassword();
1204 if (m_pStorageFile->useStorage() == static_cast<bool>(bAllow))
1205 return bAllow;
1207 m_pStorageFile->setUseStorage( bAllow );
1208 return !bAllow;
1211 ::sal_Bool SAL_CALL PasswordContainer::isPersistentStoringAllowed()
1212 throw (::com::sun::star::uno::RuntimeException)
1214 ::osl::MutexGuard aGuard( mMutex );
1216 if ( !m_pStorageFile )
1217 throw uno::RuntimeException();
1219 return m_pStorageFile->useStorage();
1222 ::sal_Bool SAL_CALL PasswordContainer::useDefaultMasterPassword( const uno::Reference< task::XInteractionHandler >& xHandler )
1223 throw ( uno::RuntimeException )
1225 sal_Bool bResult = sal_False;
1226 uno::Reference< task::XInteractionHandler > xTmpHandler = xHandler;
1227 ::osl::MutexGuard aGuard( mMutex );
1229 if ( m_pStorageFile && m_pStorageFile->useStorage() )
1231 if ( !xTmpHandler.is() )
1233 uno::Reference< lang::XMultiServiceFactory > xFactory( mComponent, uno::UNO_QUERY_THROW );
1234 uno::Reference< uno::XComponentContext > xContext( comphelper::getComponentContext(xFactory) );
1235 xTmpHandler.set( InteractionHandler::createWithParent(xContext, 0), uno::UNO_QUERY_THROW );
1238 sal_Bool bCanChangePassword = sal_True;
1239 // if there is already a stored nondefault master password it should be entered by the user before the change happen
1240 OUString aEncodedMP;
1241 if( m_pStorageFile->getEncodedMP( aEncodedMP ) && !aEncodedMP.isEmpty() )
1242 bCanChangePassword = authorizateWithMasterPassword( xTmpHandler );
1244 if ( bCanChangePassword )
1246 // generate the default password
1247 OUString aPass = GetDefaultMasterPassword();
1248 if ( !aPass.isEmpty() )
1250 // get all the persistent entries if it is possible
1251 Sequence< UrlRecord > aPersistent = getAllPersistent( uno::Reference< task::XInteractionHandler >() );
1253 // remove the master password and the entries persistence
1254 removeMasterPassword();
1256 // store the empty string to flag the default master password
1257 m_aMasterPasswd = aPass;
1258 m_pStorageFile->setEncodedMP( OUString(), sal_True );
1260 // store all the entries with the new password
1261 for ( int nURLInd = 0; nURLInd < aPersistent.getLength(); nURLInd++ )
1262 for ( int nNameInd = 0; nNameInd< aPersistent[nURLInd].UserList.getLength(); nNameInd++ )
1263 addPersistent( aPersistent[nURLInd].Url,
1264 aPersistent[nURLInd].UserList[nNameInd].UserName,
1265 aPersistent[nURLInd].UserList[nNameInd].Passwords,
1266 uno::Reference< task::XInteractionHandler >() );
1268 bResult = sal_True;
1273 return bResult;
1277 ::sal_Bool SAL_CALL PasswordContainer::isDefaultMasterPasswordUsed()
1278 throw ( uno::RuntimeException )
1280 ::osl::MutexGuard aGuard( mMutex );
1282 if ( !m_pStorageFile )
1283 throw uno::RuntimeException();
1285 OUString aEncodedMP;
1286 return ( m_pStorageFile->useStorage() && m_pStorageFile->getEncodedMP( aEncodedMP ) && aEncodedMP.isEmpty() );
1290 void SAL_CALL PasswordContainer::addUrl( const OUString& Url, ::sal_Bool MakePersistent )
1291 throw (uno::RuntimeException)
1293 mUrlContainer.add( Url, MakePersistent );
1296 OUString SAL_CALL PasswordContainer::findUrl( const OUString& Url )
1297 throw (uno::RuntimeException)
1299 return mUrlContainer.find( Url );
1302 void SAL_CALL PasswordContainer::removeUrl( const OUString& Url )
1303 throw (uno::RuntimeException)
1305 mUrlContainer.remove( Url );
1308 uno::Sequence< OUString > SAL_CALL PasswordContainer::getUrls( ::sal_Bool OnlyPersistent )
1309 throw (uno::RuntimeException)
1311 return mUrlContainer.list( OnlyPersistent );
1315 void PasswordContainer::Notify()
1317 ::osl::MutexGuard aGuard( mMutex );
1319 PassMap::iterator aIter;
1321 // remove the cached persistent values in the memory
1322 for( aIter = m_aContainer.begin(); aIter != m_aContainer.end(); ++aIter )
1324 for( list< NamePassRecord >::iterator aNPIter = aIter->second.begin(); aNPIter != aIter->second.end(); )
1326 if( aNPIter->HasPasswords( PERSISTENT_RECORD ) )
1328 aNPIter->RemovePasswords( PERSISTENT_RECORD );
1330 if ( m_pStorageFile )
1331 m_pStorageFile->remove( aIter->first, aNPIter->GetUserName() ); // remove record ( aURL, aName )
1334 if( !aNPIter->HasPasswords( MEMORY_RECORD ) )
1336 list< NamePassRecord >::iterator aIterToDelete( aNPIter );
1337 ++aNPIter;
1338 aIter->second.erase( aIterToDelete );
1340 else
1341 ++aNPIter;
1345 PassMap addon;
1346 if( m_pStorageFile )
1347 addon = m_pStorageFile->getInfo();
1349 for( aIter = addon.begin(); aIter != addon.end(); ++aIter )
1351 PassMap::iterator aSearchIter = m_aContainer.find( aIter->first );
1352 if( aSearchIter != m_aContainer.end() )
1353 for( list< NamePassRecord >::iterator aNPIter = aIter->second.begin(); aNPIter != aIter->second.end(); ++aNPIter )
1354 UpdateVector( aSearchIter->first, aSearchIter->second, *aNPIter, sal_False );
1355 else
1356 m_aContainer.insert( PairUrlRecord( aIter->first, aIter->second ) );
1361 OUString SAL_CALL PasswordContainer::getImplementationName( ) throw(uno::RuntimeException)
1363 return impl_getStaticImplementationName();
1367 sal_Bool SAL_CALL PasswordContainer::supportsService( const OUString& ServiceName ) throw(uno::RuntimeException)
1369 if ( ServiceName.equalsAscii("com.sun.star.task.PasswordContainer") )
1370 return sal_True;
1371 else
1372 return sal_False;
1376 Sequence< OUString > SAL_CALL PasswordContainer::getSupportedServiceNames( ) throw(uno::RuntimeException)
1378 return impl_getStaticSupportedServiceNames();
1382 Sequence< OUString > SAL_CALL PasswordContainer::impl_getStaticSupportedServiceNames( ) throw(uno::RuntimeException)
1384 Sequence< OUString > aRet(1);
1385 aRet[0] = "com.sun.star.task.PasswordContainer";
1386 return aRet;
1390 OUString SAL_CALL PasswordContainer::impl_getStaticImplementationName() throw(uno::RuntimeException)
1392 return OUString("stardiv.svl.PasswordContainer");
1396 Reference< XInterface > SAL_CALL PasswordContainer::impl_createInstance( const Reference< XMultiServiceFactory >& xServiceManager ) throw( RuntimeException )
1398 return Reference< XInterface >( *new PasswordContainer( xServiceManager ) );
1402 Reference< XSingleServiceFactory > SAL_CALL PasswordContainer::impl_createFactory( const Reference< XMultiServiceFactory >& ServiceManager ) throw(RuntimeException)
1404 Reference< XSingleServiceFactory > xReturn( ::cppu::createOneInstanceFactory( ServiceManager,
1405 PasswordContainer::impl_getStaticImplementationName(),
1406 PasswordContainer::impl_createInstance,
1407 PasswordContainer::impl_getStaticSupportedServiceNames()));
1408 return xReturn ;
1413 MasterPasswordRequest_Impl::MasterPasswordRequest_Impl( PasswordRequestMode Mode )
1415 MasterPasswordRequest aRequest;
1417 aRequest.Classification = InteractionClassification_ERROR;
1418 aRequest.Mode = Mode;
1420 setRequest( makeAny( aRequest ) );
1422 // Fill continuations...
1423 Sequence< RememberAuthentication > aRememberModes( 1 );
1424 aRememberModes[ 0 ] = RememberAuthentication_NO;
1426 m_xAuthSupplier
1427 = new ::ucbhelper::InteractionSupplyAuthentication(
1428 this,
1429 sal_False, // bCanSetRealm
1430 sal_False, // bCanSetUserName
1431 sal_True, // bCanSetPassword
1432 sal_False, // bCanSetAccount
1433 aRememberModes, // rRememberPasswordModes
1434 RememberAuthentication_NO, // eDefaultRememberPasswordMode
1435 aRememberModes, // rRememberAccountModes
1436 RememberAuthentication_NO, // eDefaultRememberAccountMode
1437 sal_False, // bCanUseSystemCredentials
1438 sal_False // bDefaultUseSystemCredentials
1441 Sequence<
1442 Reference< XInteractionContinuation > > aContinuations( 3 );
1443 aContinuations[ 0 ] = new ::ucbhelper::InteractionAbort( this );
1444 aContinuations[ 1 ] = new ::ucbhelper::InteractionRetry( this );
1445 aContinuations[ 2 ] = m_xAuthSupplier.get();
1447 setContinuations( aContinuations );
1451 extern "C"
1453 SAL_DLLPUBLIC_EXPORT void * SAL_CALL passwordcontainer_component_getFactory (
1454 const sal_Char * pImplementationName,
1455 SAL_UNUSED_PARAMETER void * pServiceManager,
1456 SAL_UNUSED_PARAMETER void * /* pRegistryKey */)
1458 void * pResult = 0;
1459 if (pServiceManager)
1461 Reference< XSingleServiceFactory > xFactory;
1462 if (PasswordContainer::impl_getStaticImplementationName().equalsAscii(pImplementationName))
1464 xFactory = PasswordContainer::impl_createFactory (
1465 reinterpret_cast< XMultiServiceFactory* >(pServiceManager));
1467 if (xFactory.is())
1469 xFactory->acquire();
1470 pResult = xFactory.get();
1473 return pResult;
1476 } // extern "C"
1478 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */