libzypp 9.41.1

CredentialManager.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <fstream>
00014 
00015 #include "zypp/ZConfig.h"
00016 #include "zypp/base/Function.h"
00017 #include "zypp/base/Logger.h"
00018 #include "zypp/base/Easy.h"
00019 #include "zypp/PathInfo.h"
00020 
00021 #include "zypp/media/CredentialFileReader.h"
00022 
00023 #include "zypp/media/CredentialManager.h"
00024 
00025 #define USER_CREDENTIALS_FILE ".zypp/credentials.cat"
00026 
00027 using namespace std;
00028 
00030 namespace zypp
00031 { 
00032 
00033   namespace media
00034   { 
00035 
00037   //
00038   // CLASS NAME : AuthDataComparator
00039   //
00041 
00042   bool AuthDataComparator::operator()( const AuthData_Ptr & lhs, const AuthData_Ptr & rhs )
00043   {
00044     static const url::ViewOption vopt = url::ViewOption::DEFAULTS
00045                                       - url::ViewOption::WITH_USERNAME
00046                                       - url::ViewOption::WITH_PASSWORD
00047                                       - url::ViewOption::WITH_QUERY_STR;
00048     // std::less semantic!
00049     int cmp = lhs->url().asString(vopt).compare( rhs->url().asString(vopt) );
00050     if ( ! cmp )
00051       cmp = lhs->username().compare( rhs->username() );
00052     return( cmp < 0 );
00053   }
00054 
00056   //
00057   // CLASS NAME : CredManagerOptions
00058   //
00060 
00061   CredManagerOptions::CredManagerOptions(const Pathname & rootdir)
00062     : globalCredFilePath(rootdir / ZConfig::instance().credentialsGlobalFile())
00063     , customCredFileDir(rootdir / ZConfig::instance().credentialsGlobalDir())
00064   {
00065     char * homedir = getenv("HOME");
00066     if (homedir)
00067       userCredFilePath = rootdir / homedir / USER_CREDENTIALS_FILE;
00068   }
00069 
00070 
00072   //
00073   // CLASS NAME : CredentialManager::Impl
00074   //
00075   struct CredentialManager::Impl
00076   {
00077     Impl(const CredManagerOptions & options);
00078 
00079     ~Impl()
00080     {}
00081 
00082     void init_globalCredentials();
00083     void init_userCredentials();
00084 
00085     bool processCredentials(AuthData_Ptr & cred);
00086 
00087     AuthData_Ptr getCred(const Url & url) const;
00088     AuthData_Ptr getCredFromFile(const Pathname & file);
00089     void saveGlobalCredentials();
00090     void saveUserCredentials();
00091 
00092 
00093     CredManagerOptions _options;
00094 
00095     CredentialSet _credsGlobal;
00096     CredentialSet _credsUser;
00097     CredentialSet _credsTmp;
00098 
00099     bool _globalDirty;
00100     bool _userDirty;
00101   };
00103 
00104 
00106   //
00107   // CLASS NAME : CredentialManager::Impl
00108   //
00110 
00111   CredentialManager::Impl::Impl(const CredManagerOptions & options)
00112     : _options(options)
00113     , _globalDirty(false)
00114     , _userDirty(false)
00115   {
00116     init_globalCredentials();
00117     init_userCredentials();
00118   }
00119 
00120 
00121   void CredentialManager::Impl::init_globalCredentials()
00122   {
00123     if (_options.globalCredFilePath.empty())
00124       DBG << "global cred file not known";
00125     else if (PathInfo(_options.globalCredFilePath).isExist())
00126     {
00127     /*  list<Pathname> entries;
00128       if (filesystem::readdir(entries, _options.globalCredFilePath, false) != 0)
00129         ZYPP_THROW(Exception("failed to read directory"));
00130 
00131       for_(it, entries.begin(), entries.end())*/
00132 
00133       CredentialFileReader(_options.globalCredFilePath,
00134           bind(&Impl::processCredentials, this, _1));
00135     }
00136     else
00137       DBG << "global cred file does not exist";
00138 
00139     _credsGlobal = _credsTmp; _credsTmp.clear();
00140     DBG << "Got " << _credsGlobal.size() << " global records." << endl;
00141   }
00142 
00143 
00144   void CredentialManager::Impl::init_userCredentials()
00145   {
00146     if (_options.userCredFilePath.empty())
00147       DBG << "user cred file not known";
00148     else if (PathInfo(_options.userCredFilePath).isExist())
00149     {
00150     /*  list<Pathname> entries;
00151       if (filesystem::readdir(entries, _options.userCredFilePath, false ) != 0)
00152         ZYPP_THROW(Exception("failed to read directory"));
00153 
00154       for_(it, entries.begin(), entries.end())*/
00155       CredentialFileReader(_options.userCredFilePath,
00156           bind(&Impl::processCredentials, this, _1));
00157     }
00158     else
00159       DBG << "user cred file does not exist" << endl;
00160 
00161     _credsUser = _credsTmp; _credsTmp.clear();
00162     DBG << "Got " << _credsUser.size() << " user records." << endl;
00163   }
00164 
00165 
00166   bool CredentialManager::Impl::processCredentials(AuthData_Ptr & cred)
00167   {
00168     _credsTmp.insert(cred);
00169     return true;
00170   }
00171 
00172 
00173   static AuthData_Ptr findIn(const CredentialManager::CredentialSet & set,
00174                              const Url & url,
00175                              url::ViewOption vopt)
00176   {
00177     const string & username = url.getUsername();
00178     for(CredentialManager::CredentialIterator it = set.begin(); it != set.end(); ++it)
00179     {
00180       // this ignores url params - not sure if it is good or bad...
00181       if (url.asString(vopt).find((*it)->url().asString(vopt)) == 0)
00182       {
00183         if (username.empty() || username == (*it)->username())
00184           return *it;
00185       }
00186     }
00187 
00188     return AuthData_Ptr();
00189   }
00190 
00191 
00192   AuthData_Ptr CredentialManager::Impl::getCred(const Url & url) const
00193   {
00194     AuthData_Ptr result;
00195 
00196     // compare the urls via asString(), but ignore password
00197     // default url::ViewOption will take care of that.
00198     // operator==(Url,Url) compares the whole Url
00199 
00200     url::ViewOption vopt;
00201     vopt = vopt
00202       - url::ViewOption::WITH_USERNAME
00203       - url::ViewOption::WITH_PASSWORD
00204       - url::ViewOption::WITH_QUERY_STR;
00205 
00206     // search in global credentials
00207     result = findIn(_credsGlobal, url, vopt);
00208 
00209     // search in home credentials
00210     if (!result)
00211       result = findIn(_credsUser, url, vopt);
00212 
00213     if (result)
00214       DBG << "Found credentials for '" << url << "':" << endl << *result;
00215     else
00216       DBG << "No credentials for '" << url << "'" << endl;
00217 
00218     return result;
00219   }
00220 
00221 
00222   AuthData_Ptr CredentialManager::Impl::getCredFromFile(const Pathname & file)
00223   {
00224     AuthData_Ptr result;
00225 
00226     Pathname credfile;
00227     if (file.absolute())
00228       // get from that file
00229       credfile = file;
00230     else
00231       // get from /etc/zypp/credentials.d, delete the leading path
00232       credfile = _options.customCredFileDir / file.basename();
00233 
00234     CredentialFileReader(credfile, bind(&Impl::processCredentials, this, _1));
00235     if (_credsTmp.empty())
00236       WAR << file << " does not contain valid credentials or is not readable." << endl;
00237     else
00238     {
00239       result = *_credsTmp.begin();
00240       _credsTmp.clear();
00241     }
00242 
00243     return result;
00244   }
00245 
00246   static int save_creds_in_file(
00247       const CredentialManager::CredentialSet creds,
00248       const Pathname & file,
00249       const mode_t mode)
00250   {
00251     int ret = 0;
00252     filesystem::assert_dir(file.dirname());
00253 
00254     std::ofstream fs(file.c_str());
00255     if (!fs)
00256       ret = 1;
00257 
00258     for_(it, creds.begin(), creds.end())
00259     {
00260       (*it)->dumpAsIniOn(fs);
00261       fs << endl;
00262     }
00263     fs.close();
00264 
00265     filesystem::chmod(file, mode);
00266 
00267     return ret;
00268   }
00269 
00270   void  CredentialManager::Impl::saveGlobalCredentials()
00271   {
00272     save_creds_in_file(_credsGlobal, _options.globalCredFilePath, 0640);
00273   }
00274 
00275   void  CredentialManager::Impl::saveUserCredentials()
00276   {
00277     save_creds_in_file(_credsUser, _options.userCredFilePath, 0600);
00278   }
00279 
00280 
00282   //
00283   // CLASS NAME : CredentialManager
00284   //
00286 
00287   CredentialManager::CredentialManager(const CredManagerOptions & opts)
00288     : _pimpl(new Impl(opts))
00289   {}
00290 
00291 
00292   AuthData_Ptr CredentialManager::getCred(const Url & url)
00293   {
00294     string credfile = url.getQueryParam("credentials");
00295     if (credfile.empty())
00296       return _pimpl->getCred(url);
00297     return _pimpl->getCredFromFile(credfile);
00298   }
00299 
00300 
00301   AuthData_Ptr CredentialManager::getCredFromFile(const Pathname & file)
00302   { return _pimpl->getCredFromFile(file); }
00303 
00304 
00305   void CredentialManager::addCred(const AuthData & cred)
00306   {
00307     Pathname credfile = cred.url().getQueryParam("credentials");
00308     if (credfile.empty())
00310       addUserCred(cred);
00311     else
00312       saveInFile(cred, credfile);
00313   }
00314 
00315 
00316   void CredentialManager::addGlobalCred(const AuthData & cred)
00317   {
00318     AuthData_Ptr c_ptr;
00319     c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
00320     pair<CredentialIterator, bool> ret = _pimpl->_credsGlobal.insert(c_ptr);
00321     if (ret.second)
00322       _pimpl->_globalDirty = true;
00323     else if ((*ret.first)->password() != cred.password())
00324     {
00325       _pimpl->_credsGlobal.erase(ret.first);
00326       _pimpl->_credsGlobal.insert(c_ptr);
00327       _pimpl->_globalDirty = true;
00328     }
00329   }
00330 
00331 
00332   void CredentialManager::addUserCred(const AuthData & cred)
00333   {
00334     AuthData_Ptr c_ptr;
00335     c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
00336     pair<CredentialIterator, bool> ret = _pimpl->_credsUser.insert(c_ptr);
00337     if (ret.second)
00338       _pimpl->_userDirty = true;
00339     else if ((*ret.first)->password() != cred.password())
00340     {
00341       _pimpl->_credsUser.erase(ret.first);
00342       _pimpl->_credsUser.insert(c_ptr);
00343       _pimpl->_userDirty = true;
00344     }
00345   }
00346 
00347 
00348   void CredentialManager::save()
00349   {
00350     if (_pimpl->_globalDirty)
00351       _pimpl->saveGlobalCredentials();
00352     if (_pimpl->_userDirty)
00353       _pimpl->saveUserCredentials();
00354     _pimpl->_globalDirty = false;
00355     _pimpl->_userDirty = false;
00356   }
00357 
00358 
00359   void CredentialManager::saveInGlobal(const AuthData & cred)
00360   {
00361     addGlobalCred(cred);
00362     save();
00363   }
00364 
00365 
00366   void CredentialManager::saveInUser(const AuthData & cred)
00367   {
00368     addUserCred(cred);
00369     save();
00370   }
00371 
00372 
00373   void CredentialManager::saveInFile(const AuthData & cred, const Pathname & credFile)
00374   {
00375     AuthData_Ptr c_ptr;
00376     c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
00377     c_ptr->setUrl(Url()); // don't save url in custom creds file
00378     CredentialManager::CredentialSet creds;
00379     creds.insert(c_ptr);
00380 
00381     int ret;
00382     if (credFile.absolute())
00383       ret = save_creds_in_file(creds, credFile, 0640);
00384     else
00385       ret = save_creds_in_file(
00386           creds, _pimpl->_options.customCredFileDir / credFile, 0600);
00387 
00388     if (!ret)
00389     {
00391       ERR << "error saving the credentials" << endl;
00392     }
00393   }
00394 
00395 
00396   void CredentialManager::clearAll(bool global)
00397   {
00398     if (global)
00399     {
00400       if (!filesystem::unlink(_pimpl->_options.globalCredFilePath))
00401         ERR << "could not delete user credentials file "
00402             << _pimpl->_options.globalCredFilePath << endl;
00403       _pimpl->_credsUser.clear();
00404     }
00405     else
00406     {
00407       if (!filesystem::unlink(_pimpl->_options.userCredFilePath))
00408         ERR << "could not delete global credentials file"
00409             << _pimpl->_options.userCredFilePath << endl;
00410       _pimpl->_credsGlobal.clear();
00411     }
00412   }
00413 
00414 
00415   CredentialManager::CredentialIterator CredentialManager::credsGlobalBegin() const
00416   { return _pimpl->_credsGlobal.begin(); }
00417 
00418   CredentialManager::CredentialIterator CredentialManager::credsGlobalEnd() const
00419   { return _pimpl->_credsGlobal.end(); }
00420 
00421   CredentialManager::CredentialSize CredentialManager::credsGlobalSize() const
00422   { return _pimpl->_credsGlobal.size(); }
00423 
00424   bool CredentialManager::credsGlobalEmpty() const
00425   { return _pimpl->_credsGlobal.empty(); }
00426 
00427 
00428   CredentialManager::CredentialIterator CredentialManager::credsUserBegin() const
00429   { return _pimpl->_credsUser.begin(); }
00430 
00431   CredentialManager::CredentialIterator CredentialManager::credsUserEnd() const
00432   { return _pimpl->_credsUser.end(); }
00433 
00434   CredentialManager::CredentialSize CredentialManager::credsUserSize() const
00435   { return _pimpl->_credsUser.size(); }
00436 
00437   bool CredentialManager::credsUserEmpty() const
00438   { return _pimpl->_credsUser.empty(); }
00439 
00440 
00442   } // media
00445 } // zypp