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