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