libzypp 9.41.1
|
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