From 19a7a8e8b4595b92cd8819d239d83189c2dc6481 Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Tue, 1 Nov 2016 10:38:54 +0900 Subject: [PATCH] Imported Upstream version 14.43.0 Change-Id: I01cc7c962b6e5102c093e37d2bc05b8bfa860958 Signed-off-by: DongHun Kwak --- VERSION.cmake | 6 +- doc/autoinclude/FeatureTest.doc | 2 + libzypp.spec.cmake | 4 +- package/libzypp.changes | 12 +++ zypp/RepoInfo.cc | 3 + zypp/RepoInfo.h | 4 + zypp/RepoManager.cc | 168 ++++++++++++++++++++++++----------- zypp/media/CredentialFileReader.cc | 176 +++++++++++++++++++++++-------------- zypp/media/CredentialFileReader.h | 54 +++++------- zypp/media/CredentialManager.cc | 26 +++--- zypp/media/MediaUserAuth.cc | 11 ++- 11 files changed, 290 insertions(+), 176 deletions(-) diff --git a/VERSION.cmake b/VERSION.cmake index 0e07d87..c48853b 100644 --- a/VERSION.cmake +++ b/VERSION.cmake @@ -60,9 +60,9 @@ # SET(LIBZYPP_MAJOR "14") SET(LIBZYPP_COMPATMINOR "39") -SET(LIBZYPP_MINOR "42") -SET(LIBZYPP_PATCH "7") +SET(LIBZYPP_MINOR "43") +SET(LIBZYPP_PATCH "0") # -# LAST RELEASED: 14.42.7 (39) +# LAST RELEASED: 14.43.0 (39) # (The number in parenthesis is LIBZYPP_COMPATMINOR) #======= diff --git a/doc/autoinclude/FeatureTest.doc b/doc/autoinclude/FeatureTest.doc index 8a2090b..3a34b32 100644 --- a/doc/autoinclude/FeatureTest.doc +++ b/doc/autoinclude/FeatureTest.doc @@ -41,6 +41,8 @@ Packages requiring a feature may use the corresponding \c Requires: in their .sp
\ref plugin-services
version 0
Provide a client a list of repositories.
+
version 1
+
Support multiple repo baseurls in plugin services.
plugin:system
diff --git a/libzypp.spec.cmake b/libzypp.spec.cmake index 6899e4d..62fddb6 100644 --- a/libzypp.spec.cmake +++ b/libzypp.spec.cmake @@ -35,7 +35,7 @@ Obsoletes: yast2-packagemanager Provides: libzypp(plugin) = 0 Provides: libzypp(plugin:appdata) = 0 Provides: libzypp(plugin:commit) = 1 -Provides: libzypp(plugin:services) = 0 +Provides: libzypp(plugin:services) = 1 Provides: libzypp(plugin:system) = 1 Provides: libzypp(plugin:urlresolver) = 0 Provides: libzypp(repovarexpand) = 0 @@ -246,6 +246,7 @@ mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/repos.d mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/services.d mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/vendors.d mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/multiversion.d +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/zypp/credentials.d mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/zypp/plugins/appdata @@ -342,6 +343,7 @@ rm -rf "$RPM_BUILD_ROOT" %dir %{_sysconfdir}/zypp/services.d %dir %{_sysconfdir}/zypp/vendors.d %dir %{_sysconfdir}/zypp/multiversion.d +%dir %{_sysconfdir}/zypp/credentials.d %config(noreplace) %{_sysconfdir}/zypp/zypp.conf %config(noreplace) %{_sysconfdir}/zypp/systemCheck %config(noreplace) %{_sysconfdir}/logrotate.d/zypp-history.lr diff --git a/package/libzypp.changes b/package/libzypp.changes index 47c088a..3e61ead 100644 --- a/package/libzypp.changes +++ b/package/libzypp.changes @@ -1,4 +1,16 @@ ------------------------------------------------------------------- +Tue Apr 26 12:38:14 CEST 2016 - ma@suse.de + +- Provide 'libzypp(plugin:services) = 1' after fixing bsc#933760 +- Fix credential file parser losing entries with known URL but + different user name (bsc#933760) +- RepoManager: allow extraction of multiple baseurls for service + repos (bsc#964932) +- addRepository: fix to use the correct history file for logging +- specfile: add /etc/zypp/credentials.d to the file list +- version 14.43.0 (39) + +------------------------------------------------------------------- Fri Apr 15 11:28:42 CEST 2016 - ma@suse.de - DiskUsageCounter: Limit estimated waste per file (bsc#974275) diff --git a/zypp/RepoInfo.cc b/zypp/RepoInfo.cc index 353bd49..e81c584 100644 --- a/zypp/RepoInfo.cc +++ b/zypp/RepoInfo.cc @@ -332,6 +332,9 @@ namespace zypp _pimpl->baseUrls().raw().push_back( url_r ); } + void RepoInfo::setBaseUrls( url_set urls ) + { _pimpl->baseUrls().raw().swap( urls ); } + void RepoInfo::setPath( const Pathname &path ) { _pimpl->path = path; } diff --git a/zypp/RepoInfo.h b/zypp/RepoInfo.h index 3fc3e1e..616bf60 100644 --- a/zypp/RepoInfo.h +++ b/zypp/RepoInfo.h @@ -155,6 +155,10 @@ namespace zypp * Clears current base URL list and adds \a url. */ void setBaseUrl( const Url &url ); + /** + * Clears current base URL list and adds an \ref url_set. + */ + void setBaseUrls( url_set urls ); /** * \short Repository path diff --git a/zypp/RepoManager.cc b/zypp/RepoManager.cc index 6b5480a..922154a 100644 --- a/zypp/RepoManager.cc +++ b/zypp/RepoManager.cc @@ -64,6 +64,76 @@ namespace zypp /////////////////////////////////////////////////////////////////// namespace { + /////////////////////////////////////////////////////////////////// + /// \class UrlCredentialExtractor + /// \brief Extract credentials in \ref Url authority and store them via \ref CredentialManager. + /// + /// Lazy init CredentialManager and save collected credentials when + /// going out of scope. + /// + /// Methods return whether a password has been collected/extracted. + /// + /// \code + /// UrlCredentialExtractor( "/rootdir" ).collect( oneUrlOrUrlContainer ); + /// \endcode + /// \code + /// { + /// UrlCredentialExtractor extractCredentials; + /// extractCredentials.collect( oneUrlOrUrlContainer ); + /// extractCredentials.extract( oneMoreUrlOrUrlContainer ); + /// .... + /// } + /// \endcode + /// + class UrlCredentialExtractor + { + public: + UrlCredentialExtractor( Pathname & root_r ) + : _root( root_r ) + {} + + ~UrlCredentialExtractor() + { if ( _cmPtr ) _cmPtr->save(); } + + /** Remember credentials stored in URL authority leaving the password in \a url_r. */ + bool collect( const Url & url_r ) + { + bool ret = url_r.hasCredentialsInAuthority(); + if ( ret ) + { + if ( !_cmPtr ) _cmPtr.reset( new media::CredentialManager( _root ) ); + _cmPtr->addUserCred( url_r ); + } + return ret; + } + /** \overload operating on Url container */ + template + bool collect( const TContainer & urls_r ) + { bool ret = false; for ( const Url & url : urls_r ) { if ( collect( url ) && !ret ) ret = true; } return ret; } + + /** Remember credentials stored in URL authority stripping the passowrd from \a url_r. */ + bool extract( Url & url_r ) + { + bool ret = collect( url_r ); + if ( ret ) + url_r.setPassword( std::string() ); + return ret; + } + /** \overload operating on Url container */ + template + bool extract( TContainer & urls_r ) + { bool ret = false; for ( Url & url : urls_r ) { if ( extract( url ) && !ret ) ret = true; } return ret; } + + private: + const Pathname & _root; + scoped_ptr _cmPtr; + }; + } // namespace + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + namespace + { /** Simple media mounter to access non-downloading URLs e.g. for non-local plaindir repos. * \ingroup g_RAII */ @@ -1589,26 +1659,9 @@ namespace zypp progress.set(90); // check for credentials in Urls - bool havePasswords = false; - for_( urlit, tosave.baseUrlsBegin(), tosave.baseUrlsEnd() ) - if ( urlit->hasCredentialsInAuthority() ) - { - havePasswords = true; - break; - } - // save the credentials - if ( havePasswords ) - { - media::CredentialManager cm( - media::CredManagerOptions(_options.rootDir) ); - - for_(urlit, tosave.baseUrlsBegin(), tosave.baseUrlsEnd()) - if (urlit->hasCredentialsInAuthority()) - //! \todo use a method calling UI callbacks to ask where to save creds? - cm.saveInUser(media::AuthData(*urlit)); - } + UrlCredentialExtractor( _options.rootDir ).collect( tosave.baseUrls() ); - HistoryLog().addRepository(tosave); + HistoryLog(_options.rootDir).addRepository(tosave); progress.toMax(); MIL << "done" << endl; @@ -1808,6 +1861,8 @@ namespace zypp newinfo.setFilepath(toedit.filepath()); reposManip().erase(toedit); reposManip().insert(newinfo); + // check for credentials in Urls + UrlCredentialExtractor( _options.rootDir ).collect( newinfo.baseUrls() ); HistoryLog(_options.rootDir).modifyRepository(toedit, newinfo); MIL << "repo " << alias << " modified" << endl; } @@ -1861,15 +1916,8 @@ namespace zypp saveService( toSave ); _services.insert( toSave ); - // check for credentials in Url (username:password, not ?credentials param) - if ( toSave.url().hasCredentialsInAuthority() ) - { - media::CredentialManager cm( - media::CredManagerOptions(_options.rootDir) ); - - //! \todo use a method calling UI callbacks to ask where to save creds? - cm.saveInUser(media::AuthData(toSave.url())); - } + // check for credentials in Url + UrlCredentialExtractor( _options.rootDir ).collect( toSave.url() ); MIL << "added service " << toSave.alias() << endl; } @@ -2009,34 +2057,41 @@ namespace zypp { // First of all: Prepend service alias: it->setAlias( str::form( "%s:%s", service.alias().c_str(), it->alias().c_str() ) ); - // set refrence to the parent service + // set reference to the parent service it->setService( service.alias() ); // remember the new parsed repo state newRepoStates[it->alias()] = *it; - // if the repo url was not set by the repoindex parser, set service's url - Url url; - if ( it->baseUrlsEmpty() ) - url = service.rawUrl(); - else + // - If the repo url was not set by the repoindex parser, set service's url. + // - Libzypp currently has problem with separate url + path handling so just + // append a path, if set, to the baseurls + // - Credentials in the url authority will be extracted later, either if the + // repository is added or if we check for changed urls. + Pathname path; + if ( !it->path().empty() ) { - // service repo can contain only one URL now, so no need to iterate. - url = it->rawUrl(); // raw! + if ( it->path() != "/" ) + path = it->path(); + it->setPath(""); } - // libzypp currently has problem with separate url + path handling - // so just append the path to the baseurl - if ( !it->path().empty() ) + if ( it->baseUrlsEmpty() ) { - Pathname path(url.getPathName()); - path /= it->path(); - url.setPathName( path.asString() ); - it->setPath(""); + Url url( service.rawUrl() ); + if ( !path.empty() ) + url.setPathName( url.getPathName() / path ); + it->setBaseUrl( std::move(url) ); + } + else if ( !path.empty() ) + { + RepoInfo::url_set urls( it->rawBaseUrls() ); + for ( Url & url : urls ) + { + url.setPathName( url.getPathName() / path ); + } + it->setBaseUrls( std::move(urls) ); } - - // save the url - it->setBaseUrl( url ); } //////////////////////////////////////////////////////////////////////////// @@ -2072,7 +2127,8 @@ namespace zypp } //////////////////////////////////////////////////////////////////////////// - // create missing repositories and modify exising ones if needed... + // create missing repositories and modify existing ones if needed... + UrlCredentialExtractor urlCredentialExtractor( _options.rootDir ); // To collect any credentials stored in repo URLs for_( it, collector.repos.begin(), collector.repos.end() ) { // User explicitly requested the repo being enabled? @@ -2197,13 +2253,16 @@ namespace zypp } // changed url? - // service repo can contain only one URL now, so no need to iterate. - if ( oldRepo->rawUrl() != it->rawUrl() ) { - DBG << "Service repo " << it->alias() << " gets new URL " << it->rawUrl() << endl; - oldRepo->setBaseUrl( it->rawUrl() ); - oldRepoModified = true; - } + RepoInfo::url_set newUrls( it->rawBaseUrls() ); + urlCredentialExtractor.extract( newUrls ); // Extract! to prevent passwds from disturbing the comparison below + if ( oldRepo->rawBaseUrls() != newUrls ) + { + DBG << "Service repo " << it->alias() << " gets new URLs " << newUrls << endl; + oldRepo->setBaseUrls( std::move(newUrls) ); + oldRepoModified = true; + } + } // changed gpg check settings? // ATM only plugin services can set GPG values. @@ -2302,6 +2361,9 @@ namespace zypp _services.erase(oldAlias); _services.insert(service); + // check for credentials in Urls + UrlCredentialExtractor( _options.rootDir ).collect( service.url() ); + // changed properties affecting also repositories if ( oldAlias != service.alias() // changed alias diff --git a/zypp/media/CredentialFileReader.cc b/zypp/media/CredentialFileReader.cc index 853a587..d6a07ea 100644 --- a/zypp/media/CredentialFileReader.cc +++ b/zypp/media/CredentialFileReader.cc @@ -22,79 +22,123 @@ using std::endl; #undef ZYPP_BASE_LOGGER_LOGGROUP #define ZYPP_BASE_LOGGER_LOGGROUP "parser" - /////////////////////////////////////////////////////////////////// namespace zypp -{ ///////////////////////////////////////////////////////////////// +{ /////////////////////////////////////////////////////////////////// namespace media - { ///////////////////////////////////////////////////////////////// - - - ////////////////////////////////////////////////////////////////////// - // - // CLASS NAME : CredentialFileReader - // - ////////////////////////////////////////////////////////////////////// - - CredentialFileReader::CredentialFileReader( - const Pathname & crfile, - const ProcessCredentials & callback) { - InputStream is(crfile); - parser::IniDict dict(is); - for (parser::IniDict::section_const_iterator its = dict.sectionsBegin(); - its != dict.sectionsEnd(); - ++its) + /////////////////////////////////////////////////////////////////// + namespace { - Url storedUrl; - if (!its->empty()) - { - try { storedUrl = Url(*its); } - catch (const url::UrlException &) - { - ERR << "invalid URL '" << *its << "' in credentials in file: " - << crfile << endl; - continue; - } - } - - AuthData_Ptr credentials; - credentials.reset(new AuthData()); - - // set url - if (storedUrl.isValid()) - credentials->setUrl(storedUrl); - - for (parser::IniDict::entry_const_iterator it = dict.entriesBegin(*its); - it != dict.entriesEnd(*its); - ++it) + // Looks like INI but allows multiple sections for the same URL + // but different user (in .cat files). So don't use an Ini + // Also support a global section without '[URL]' which is used + // in credential files. + // ------------------------------------- + // username = emptyUSER + // password = emptyPASS + // ------------------------------------- + // [http://server/tmp/sumafake222] + // username = USER + // password = PASS + // + // [http://server/tmp/sumafake222] + // username = USER2 + // password = PASS + // ------------------------------------- + struct CredentialFileReaderImpl : public parser::IniParser { - if (it->first == "username") - credentials->setUsername(it->second); - else if (it->first == "password") - credentials->setPassword(it->second); - else - ERR << "Unknown attribute in [" << crfile << "]: " - << it->second << " ignored" << endl; - } - - if (credentials->valid()) - callback(credentials); - else - ERR << "invalid credentials in file: " << crfile << endl; - } // sections - } - - - CredentialFileReader::~CredentialFileReader() - {} - - - ///////////////////////////////////////////////////////////////// - } // media + typedef CredentialFileReader::ProcessCredentials ProcessCredentials; + + struct StopParsing {}; + + CredentialFileReaderImpl( const Pathname & input_r, const ProcessCredentials & callback_r ) + : _input( input_r ) + , _callback( callback_r ) + { + try + { + parse( input_r ); + } + catch ( StopParsing ) + { /* NO error but consumer aborted parsing */ } + } + + // NO-OP; new sections are opened in consume() + virtual void beginParse() + { /*EMPTY*/ } + + // start a new section [url] + virtual void consume( const std::string & section_r ) + { + endParse(); // close any open section + _secret.reset( new AuthData ); + try + { + _secret->setUrl( Url(section_r) ); + } + catch ( const url::UrlException & ) + { + ERR << "Ignore invalid URL '" << section_r << "' in file " << _input << endl; + _secret.reset(); // ignore this section + } + } + + virtual void consume( const std::string & section_r, const std::string & key_r, const std::string & value_r ) + { + if ( !_secret && section_r.empty() ) + _secret.reset( new AuthData ); // a initial global section without [URL] + + if ( _secret ) + { + if ( key_r == "username" ) + _secret->setUsername( value_r ); + else if ( key_r == "password" ) + _secret->setPassword( value_r ); + else + WAR << "Ignore unknown attribute '" << key_r << "=" << value_r << "' in file " << _input << endl; + } + // else: ignored section due to wrong URL + } + + // send any valid pending section + virtual void endParse() + { + if ( _secret ) + { + if ( _secret->valid() ) + { + if ( !_callback( _secret ) ) + throw( StopParsing() ); + } + else + ERR << "Ignore invalid credentials for URL '" << _secret->url() << "' in file " << _input << endl; + } + } + + private: + const Pathname & _input; + const ProcessCredentials & _callback; + AuthData_Ptr _secret; + }; + } // namespace + /////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////// + // + // CLASS NAME : CredentialFileReader + // + ////////////////////////////////////////////////////////////////////// + + CredentialFileReader::CredentialFileReader( const Pathname & crfile_r, const ProcessCredentials & callback_r ) + { CredentialFileReaderImpl( crfile_r, callback_r ); } + + CredentialFileReader::~CredentialFileReader() + {} + + } // namespace media /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////// -} // zypp +} // namespace zypp /////////////////////////////////////////////////////////////////// diff --git a/zypp/media/CredentialFileReader.h b/zypp/media/CredentialFileReader.h index fba8e60..f9a3574 100644 --- a/zypp/media/CredentialFileReader.h +++ b/zypp/media/CredentialFileReader.h @@ -20,43 +20,31 @@ /////////////////////////////////////////////////////////////////// namespace zypp -{ ///////////////////////////////////////////////////////////////// +{ /////////////////////////////////////////////////////////////////// namespace media - { ///////////////////////////////////////////////////////////////// - - - ////////////////////////////////////////////////////////////////////// - // - // CLASS NAME : CredentialFileReader - // - class CredentialFileReader { - public: - /** - * Callback definition. - * First parameter is the \ref Url with which the credentials are - * associated, the second are the credentials. - * - * Return false from the callback to get a \ref AbortRequestException - * to be thrown and the processing to be cancelled. - */ - typedef function ProcessCredentials; - - CredentialFileReader(const Pathname & crfile, - const ProcessCredentials & callback); - ~CredentialFileReader(); - private: - ProcessCredentials _callback; - }; - ////////////////////////////////////////////////////////////////////// - - - ///////////////////////////////////////////////////////////////// - } // media + ////////////////////////////////////////////////////////////////////// + /// \class CredentialFileReader + /// \brief Parse credentials files and catalogs + class CredentialFileReader + { + public: + /** Callback invoked for each entry found in the file. + * Return \c false to abort parsing. + */ + typedef function ProcessCredentials; + + CredentialFileReader( const Pathname & crfile_r, const ProcessCredentials & callback_r ); + ~CredentialFileReader(); + private: + ProcessCredentials _callback; + }; + ////////////////////////////////////////////////////////////////////// + + } // namespace media /////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////// -} // zypp +} // namespace zypp /////////////////////////////////////////////////////////////////// #endif /* ZYPP_MEDIA_CREDENTIALFILEREADER_H */ diff --git a/zypp/media/CredentialManager.cc b/zypp/media/CredentialManager.cc index 4ff8dc1..9e52d2e 100644 --- a/zypp/media/CredentialManager.cc +++ b/zypp/media/CredentialManager.cc @@ -39,23 +39,17 @@ namespace zypp // ////////////////////////////////////////////////////////////////////// - bool - AuthDataComparator::operator()( - const AuthData_Ptr & lhs, const AuthData_Ptr & rhs) + bool AuthDataComparator::operator()( const AuthData_Ptr & lhs, const AuthData_Ptr & rhs ) { - static const url::ViewOption vopt = - url::ViewOption::DEFAULTS - - url::ViewOption::WITH_USERNAME - - url::ViewOption::WITH_PASSWORD - - url::ViewOption::WITH_QUERY_STR; - - if (lhs->username() != rhs->username()) - return true; - - if (lhs->url().asString(vopt) != rhs->url().asString(vopt)) - return true; - - return false; + static const url::ViewOption vopt = url::ViewOption::DEFAULTS + - url::ViewOption::WITH_USERNAME + - url::ViewOption::WITH_PASSWORD + - url::ViewOption::WITH_QUERY_STR; + // std::less semantic! + int cmp = lhs->url().asString(vopt).compare( rhs->url().asString(vopt) ); + if ( ! cmp ) + cmp = lhs->username().compare( rhs->username() ); + return( cmp < 0 ); } ////////////////////////////////////////////////////////////////////// diff --git a/zypp/media/MediaUserAuth.cc b/zypp/media/MediaUserAuth.cc index d599a71..323b22a 100644 --- a/zypp/media/MediaUserAuth.cc +++ b/zypp/media/MediaUserAuth.cc @@ -43,9 +43,12 @@ bool AuthData::valid() const std::ostream & AuthData::dumpOn( std::ostream & str ) const { + if (_url.isValid()) + str << "[" << _url.asString( url::ViewOptions() - url::ViewOptions::WITH_USERNAME - url::ViewOptions::WITH_PASSWORD ) << "]" << endl; + else + str << "[]" << endl; str << "username: '" << _username << "'" << std::endl - << "password: " << (_password.empty() ? "" : "") - << std::endl; + << "password: " << (_password.empty() ? "" : ""); return str; } @@ -85,8 +88,8 @@ bool CurlAuthData::valid() const std::ostream & CurlAuthData::dumpOn( std::ostream & str ) const { - AuthData::dumpOn(str) << " auth_type: " << _auth_type_str - << " (" << _auth_type << ")" << std::endl; + AuthData::dumpOn(str) << endl + << " auth_type: " << _auth_type_str << " (" << _auth_type << ")"; return str; } -- 2.7.4