libzypp  17.28.5
CredentialManager.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include <iostream>
13 #include <fstream>
14 
15 #include <zypp/ZConfig.h>
16 #include <zypp/base/Function.h>
17 #include <zypp/base/Logger.h>
18 #include <zypp/base/Easy.h>
19 #include <zypp/PathInfo.h>
20 
24 
25 #include <boost/interprocess/sync/file_lock.hpp>
26 #include <boost/interprocess/sync/scoped_lock.hpp>
27 #include <boost/interprocess/sync/sharable_lock.hpp>
28 
29 namespace bpci = boost::interprocess;
30 
31 
32 using std::endl;
33 
34 #define USER_CREDENTIALS_FILE ".zypp/credentials.cat"
35 
37 namespace zypp
38 {
39  namespace media
41  {
42 
44  //
45  // CLASS NAME : AuthDataComparator
46  //
48 
49  bool AuthDataComparator::operator()( const AuthData_Ptr & lhs, const AuthData_Ptr & rhs ) const
50  {
51  static const url::ViewOption vopt = url::ViewOption::DEFAULTS
55  // std::less semantic!
56  int cmp = lhs->url().asString(vopt).compare( rhs->url().asString(vopt) );
57  if ( ! cmp )
58  cmp = lhs->username().compare( rhs->username() );
59  return( cmp < 0 );
60  }
61 
63  //
64  // CLASS NAME : CredManagerOptions
65  //
67 
69  : globalCredFilePath(rootdir / ZConfig::instance().credentialsGlobalFile())
70  , customCredFileDir(rootdir / ZConfig::instance().credentialsGlobalDir())
71  {
72  char * homedir = getenv("HOME");
73  if (homedir)
74  userCredFilePath = rootdir / homedir / USER_CREDENTIALS_FILE;
75  }
76 
77 
79  //
80  // CLASS NAME : CredentialManager::Impl
81  //
83  {
84  Impl(const CredManagerOptions & options);
85 
87  {}
88 
90  void init_userCredentials();
91 
92  bool processCredentials(AuthData_Ptr & cred);
93 
94  AuthData_Ptr getCred(const Url & url) const;
96  void saveGlobalCredentials();
97  void saveUserCredentials();
98 
99 
101 
105 
108  };
110 
111 
113  //
114  // CLASS NAME : CredentialManager::Impl
115  //
117 
119  : _options(options)
120  , _globalDirty(false)
121  , _userDirty(false)
122  {
125  }
126 
127 
129  {
130  if (_options.globalCredFilePath.empty())
131  DBG << "global cred file not known";
132  else if (PathInfo(_options.globalCredFilePath).isExist())
133  {
134  /* list<Pathname> entries;
135  if (filesystem::readdir(entries, _options.globalCredFilePath, false) != 0)
136  ZYPP_THROW(Exception("failed to read directory"));
137 
138  for_(it, entries.begin(), entries.end())*/
139 
140  CredentialFileReader(_options.globalCredFilePath,
141  bind(&Impl::processCredentials, this, _1));
142  }
143  else
144  DBG << "global cred file does not exist";
145 
146  _credsGlobal = _credsTmp; _credsTmp.clear();
147  DBG << "Got " << _credsGlobal.size() << " global records." << endl;
148  }
149 
150 
152  {
153  if (_options.userCredFilePath.empty())
154  DBG << "user cred file not known";
155  else if (PathInfo(_options.userCredFilePath).isExist())
156  {
157  /* list<Pathname> entries;
158  if (filesystem::readdir(entries, _options.userCredFilePath, false ) != 0)
159  ZYPP_THROW(Exception("failed to read directory"));
160 
161  for_(it, entries.begin(), entries.end())*/
162  CredentialFileReader(_options.userCredFilePath,
163  bind(&Impl::processCredentials, this, _1));
164  }
165  else
166  DBG << "user cred file does not exist" << endl;
167 
168  _credsUser = _credsTmp; _credsTmp.clear();
169  DBG << "Got " << _credsUser.size() << " user records." << endl;
170  }
171 
172 
174  {
175  _credsTmp.insert(cred);
176  return true;
177  }
178 
179 
181  const Url & url,
182  url::ViewOption vopt)
183  {
184  const std::string & username = url.getUsername();
185  for( CredentialManager::CredentialIterator it = set.begin(); it != set.end(); ++it )
186  {
187  if ( !(*it)->url().isValid() )
188  continue;
189 
190  // this ignores url params - not sure if it is good or bad...
191  if ( url.asString(vopt).find((*it)->url().asString(vopt)) == 0 )
192  {
193  if ( username.empty() || username == (*it)->username() )
194  return *it;
195  }
196  }
197 
198  return AuthData_Ptr();
199  }
200 
201 
203  {
204  AuthData_Ptr result;
205 
206  // compare the urls via asString(), but ignore password
207  // default url::ViewOption will take care of that.
208  // operator==(Url,Url) compares the whole Url
209 
210  url::ViewOption vopt;
211  vopt = vopt
215 
216  // search in global credentials
217  result = findIn(_credsGlobal, url, vopt);
218 
219  // search in home credentials
220  if (!result)
221  result = findIn(_credsUser, url, vopt);
222 
223  if (result)
224  DBG << "Found credentials for '" << url << "':" << endl << *result;
225  else
226  DBG << "No credentials for '" << url << "'" << endl;
227 
228  return result;
229  }
230 
231 
233  {
234  AuthData_Ptr result;
235 
236  Pathname credfile;
237  if (file.absolute())
238  // get from that file
239  credfile = file;
240  else
241  // get from /etc/zypp/credentials.d, delete the leading path
242  credfile = _options.customCredFileDir / file.basename();
243 
244  // make sure only our thread accesses the file
245  bpci::file_lock lockFile ( credfile.c_str() );
246  bpci::scoped_lock lock( lockFile );
247 
248  CredentialFileReader(credfile, bind(&Impl::processCredentials, this, _1));
249  if (_credsTmp.empty())
250  WAR << file << " does not contain valid credentials or is not readable." << endl;
251  else
252  {
253  result = *_credsTmp.begin();
254  _credsTmp.clear();
255  }
256 
257  return result;
258  }
259 
260  static int save_creds_in_file(
262  const Pathname & file,
263  const mode_t mode)
264  {
265  int ret = 0;
267 
268  std::ofstream fs(file.c_str());
269  if (!fs)
270  ret = 1;
271 
272  // make sure only our thread accesses the file
273  bpci::file_lock lockFile ( file.c_str() );
274  bpci::scoped_lock lock( lockFile );
275 
276 
277  for_(it, creds.begin(), creds.end())
278  {
279  (*it)->dumpAsIniOn(fs);
280  (*it)->setLastDatabaseUpdate( time( nullptr ) );
281  fs << endl;
282  }
283  fs.close();
284 
285  filesystem::chmod(file, mode);
286 
287  return ret;
288  }
289 
291  {
292  save_creds_in_file(_credsGlobal, _options.globalCredFilePath, 0640);
293  }
294 
296  {
297  save_creds_in_file(_credsUser, _options.userCredFilePath, 0600);
298  }
299 
300 
302  //
303  // CLASS NAME : CredentialManager
304  //
306 
308  : _pimpl(new Impl(opts))
309  {}
310 
311 
313  {
314  std::string credfile = url.getQueryParam("credentials");
315  if (credfile.empty())
316  return _pimpl->getCred(url);
317  return _pimpl->getCredFromFile(credfile);
318  }
319 
320 
322  { return _pimpl->getCredFromFile(file); }
323 
324 
326  {
327  if ( !cred.url().isValid() )
328  ZYPP_THROW( MediaInvalidCredentialsException( "URL must be valid in order to save AuthData." ) );
329 
330  Pathname credfile = cred.url().getQueryParam("credentials");
331  if (credfile.empty())
333  addUserCred(cred);
334  else
335  saveInFile(cred, credfile);
336  }
337 
338 
340  {
341  if ( !cred.url().isValid() )
342  ZYPP_THROW( MediaInvalidCredentialsException( "URL must be valid in order to save AuthData." ) );
343 
344  AuthData_Ptr c_ptr;
345  c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
346  std::pair<CredentialIterator, bool> ret = _pimpl->_credsGlobal.insert(c_ptr);
347  if (ret.second)
348  _pimpl->_globalDirty = true;
349  else if ((*ret.first)->password() != cred.password())
350  {
351  _pimpl->_credsGlobal.erase(ret.first);
352  _pimpl->_credsGlobal.insert(c_ptr);
353  _pimpl->_globalDirty = true;
354  }
355  }
356 
357 
359  {
360  if ( !cred.url().isValid() )
361  ZYPP_THROW( MediaInvalidCredentialsException( "URL must be valid in order to save AuthData." ) );
362 
363  AuthData_Ptr c_ptr;
364  c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
365  std::pair<CredentialIterator, bool> ret = _pimpl->_credsUser.insert(c_ptr);
366  if (ret.second)
367  _pimpl->_userDirty = true;
368  else if ((*ret.first)->password() != cred.password())
369  {
370  _pimpl->_credsUser.erase(ret.first);
371  _pimpl->_credsUser.insert(c_ptr);
372  _pimpl->_userDirty = true;
373  }
374  }
375 
376 
378  {
379  if (_pimpl->_globalDirty)
381  if (_pimpl->_userDirty)
383  _pimpl->_globalDirty = false;
384  _pimpl->_userDirty = false;
385  }
386 
387 
389  {
390  addGlobalCred(cred);
391  save();
392  }
393 
394 
396  {
397  addUserCred(cred);
398  save();
399  }
400 
401 
402  void CredentialManager::saveInFile(const AuthData & cred, const Pathname & credFile)
403  {
404  AuthData_Ptr c_ptr;
405  c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
406  c_ptr->setUrl(Url()); // don't save url in custom creds file
408  creds.insert(c_ptr);
409 
410  int ret;
411  if (credFile.absolute())
412  ret = save_creds_in_file(creds, credFile, 0640);
413  else
414  ret = save_creds_in_file(
415  creds, _pimpl->_options.customCredFileDir / credFile, 0600);
416 
417  if (!ret)
418  {
420  ERR << "error saving the credentials" << endl;
421  }
422  }
423 
424 
425  void CredentialManager::clearAll(bool global)
426  {
427  if (global)
428  {
430  ERR << "could not delete user credentials file "
431  << _pimpl->_options.globalCredFilePath << endl;
432  _pimpl->_credsUser.clear();
433  }
434  else
435  {
437  ERR << "could not delete global credentials file"
438  << _pimpl->_options.userCredFilePath << endl;
439  _pimpl->_credsGlobal.clear();
440  }
441  }
442 
443 
445  { return _pimpl->_credsGlobal.begin(); }
446 
448  { return _pimpl->_credsGlobal.end(); }
449 
451  { return _pimpl->_credsGlobal.size(); }
452 
454  { return _pimpl->_credsGlobal.empty(); }
455 
456 
458  { return _pimpl->_credsUser.begin(); }
459 
461  { return _pimpl->_credsUser.end(); }
462 
464  { return _pimpl->_credsUser.size(); }
465 
467  { return _pimpl->_credsUser.empty(); }
468 
469 
471  } // media
474 } // zypp
int assert_dir(const Pathname &path, unsigned mode)
Like &#39;mkdir -p&#39;.
Definition: PathInfo.cc:319
AuthData_Ptr getCred(const Url &url) const
static const ViewOption WITH_USERNAME
Option to include username in the URL string.
Definition: UrlBase.h:58
std::string password() const
Definition: MediaUserAuth.h:57
CredentialIterator credsGlobalEnd() const
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:392
void saveInFile(const AuthData &, const Pathname &credFile)
Saves given cred to user specified credentials file.
void save()
Saves any unsaved credentials added via addUserCred() or addGlobalCred() methods. ...
void addGlobalCred(const AuthData &cred)
Add new global credentials.
int chmod(const Pathname &path, mode_t mode)
Like &#39;chmod&#39;.
Definition: PathInfo.cc:1032
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:28
const char * c_str() const
String representation.
Definition: Pathname.h:110
static int save_creds_in_file(const CredentialManager::CredentialSet creds, const Pathname &file, const mode_t mode)
CredentialSet::size_type CredentialSize
AuthData_Ptr getCred(const Url &url)
Get credentials for the specified url.
std::string basename() const
Return the last component of this path.
Definition: Pathname.h:128
void saveInGlobal(const AuthData &cred)
Saves given cred to global credentials file.
Url::asString() view options.
Definition: UrlBase.h:39
Impl(const CredManagerOptions &options)
#define ERR
Definition: Logger.h:98
CredManagerOptions(const Pathname &rootdir="")
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
std::string asString() const
Returns a default string representation of the Url object.
Definition: Url.cc:492
std::string getQueryParam(const std::string &param, EEncoding eflag=zypp::url::E_DECODED) const
Return the value for the specified query parameter.
Definition: Url.cc:655
int unlink(const Pathname &path)
Like &#39;unlink&#39;.
Definition: PathInfo.cc:640
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:279
Pathname dirname() const
Return all but the last component od this path.
Definition: Pathname.h:124
bool processCredentials(AuthData_Ptr &cred)
CredentialSize credsUserSize() const
Interim helper class to collect global options and settings.
Definition: ZConfig.h:61
#define WAR
Definition: Logger.h:97
void addUserCred(const AuthData &cred)
Add new user credentials.
Parse credentials files and catalogs.
bool absolute() const
Test for an absolute path.
Definition: Pathname.h:116
bool isValid() const
Verifies the Url.
Definition: Url.cc:484
CredentialIterator credsGlobalBegin() const
Class for handling media authentication data.
Definition: MediaUserAuth.h:30
static const ViewOption WITH_QUERY_STR
Option to include query string in the URL string.
Definition: UrlBase.h:101
shared_ptr< AuthData > AuthData_Ptr
Definition: MediaUserAuth.h:77
static const ViewOption WITH_PASSWORD
Option to include password in the URL string.
Definition: UrlBase.h:67
std::set< AuthData_Ptr, AuthDataComparator > CredentialSet
CredentialIterator credsUserBegin() const
CredentialSet::const_iterator CredentialIterator
CredentialManager(const CredManagerOptions &opts=CredManagerOptions())
void clearAll(bool global=false)
Remove all global or user credentials from memory and disk.
CredentialIterator credsUserEnd() const
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:218
#define USER_CREDENTIALS_FILE
static const ViewOption DEFAULTS
Default combination of view options.
Definition: UrlBase.h:177
AuthData_Ptr getCredFromFile(const Pathname &file)
Read credentials from a file.
AuthData_Ptr getCredFromFile(const Pathname &file)
CredentialSize credsGlobalSize() const
void addCred(const AuthData &cred)
Add new credentials with user callbacks.
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
static AuthData_Ptr findIn(const CredentialManager::CredentialSet &set, const Url &url, url::ViewOption vopt)
Url manipulation class.
Definition: Url.h:91
bool operator()(const AuthData_Ptr &lhs, const AuthData_Ptr &rhs) const
void saveInUser(const AuthData &cred)
Saves given cred to user&#39;s credentials file.
#define DBG
Definition: Logger.h:95
std::string getUsername(EEncoding eflag=zypp::url::E_DECODED) const
Returns the username from the URL authority.
Definition: Url.cc:567