libzypp 17.37.17
credentialmanager.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
12
13#include "credentialmanager.h"
14
15#include <iostream>
16#include <fstream>
17
18#include <utility>
19#include <zypp-media/MediaConfig>
22#include <zypp-core/base/Easy.h>
24
25#include <zypp-media/auth/CredentialFileReader>
26#include <zypp-media/MediaException>
27
28#include <boost/interprocess/sync/file_lock.hpp>
29#include <boost/interprocess/sync/scoped_lock.hpp>
30#include <boost/interprocess/sync/sharable_lock.hpp>
31
32namespace bpci = boost::interprocess;
33
34
35using std::endl;
36
37#define USER_CREDENTIALS_FILE ".zypp/credentials.cat"
38
40namespace zypp
41{
43 namespace media
44 {
45
47 //
48 // CLASS NAME : AuthDataComparator
49 //
51
52 bool AuthDataComparator::operator()( const AuthData_Ptr & lhs, const AuthData_Ptr & rhs ) const
53 {
54 static const url::ViewOption vopt = url::ViewOption::DEFAULTS
55 - url::ViewOption::WITH_USERNAME
56 - url::ViewOption::WITH_PASSWORD
57 - url::ViewOption::WITH_QUERY_STR;
58 // std::less semantic!
59 int cmp = lhs->url().asString(vopt).compare( rhs->url().asString(vopt) );
60 if ( ! cmp )
61 cmp = lhs->username().compare( rhs->username() );
62 return( cmp < 0 );
63 }
64
66 //
67 // CLASS NAME : CredManagerOptions
68 //
70
72 : globalCredFilePath(rootdir / MediaConfig::instance().credentialsGlobalFile())
73 , customCredFileDir(rootdir / MediaConfig::instance().credentialsGlobalDir())
74 {
75 char * homedir = getenv("HOME");
76 if (homedir)
77 userCredFilePath = rootdir / homedir / USER_CREDENTIALS_FILE;
78 }
79
80
82 //
83 // CLASS NAME : CredentialManager::Impl
84 //
86 {
87 Impl(CredManagerOptions &&options);
88
89 Impl(const Impl &) = delete;
90 Impl(Impl &&) = delete;
91 Impl &operator=(const Impl &) = delete;
92 Impl &operator=(Impl &&) = delete;
93
95 {}
96
99
100 bool processCredentials(AuthData_Ptr & cred);
101
102 AuthData_Ptr getCred(const Url & url) const;
105 void saveUserCredentials();
106
107
109
113
116 };
117
118
119
121 //
122 // CLASS NAME : CredentialManager::Impl
123 //
125
127 : _options(std::move(options))
128 , _globalDirty(false)
129 , _userDirty(false)
130 {
133 }
134
135
137 {
138 if (_options.globalCredFilePath.empty())
139 DBG << "global cred file not known" << endl;
140 else if (PathInfo(_options.globalCredFilePath).isExist())
141 {
142 /* list<Pathname> entries;
143 if (filesystem::readdir(entries, _options.globalCredFilePath, false) != 0)
144 ZYPP_THROW(Exception("failed to read directory"));
145
146 for_(it, entries.begin(), entries.end())*/
147
148 CredentialFileReader(_options.globalCredFilePath,
149 bind(&Impl::processCredentials, this, _1));
150 }
151 else
152 DBG << "global cred file does not exist (" << _options.globalCredFilePath << ")" << endl;
153
155 DBG << "Got " << _credsGlobal.size() << " global records." << endl;
156 }
157
158
160 {
161 if (_options.userCredFilePath.empty())
162 DBG << "user cred file not known" << endl;
163 else if (PathInfo(_options.userCredFilePath).isExist())
164 {
165 /* list<Pathname> entries;
166 if (filesystem::readdir(entries, _options.userCredFilePath, false ) != 0)
167 ZYPP_THROW(Exception("failed to read directory"));
168
169 for_(it, entries.begin(), entries.end())*/
170 CredentialFileReader(_options.userCredFilePath,
171 bind(&Impl::processCredentials, this, _1));
172 }
173 else
174 DBG << "user cred file does not exist (" << _options.userCredFilePath << ")" << endl;
175
176 _credsUser = _credsTmp; _credsTmp.clear();
177 DBG << "Got " << _credsUser.size() << " user records." << endl;
178 }
179
180
182 {
183 _credsTmp.insert(cred);
184 return true;
185 }
186
187
189 const Url & url,
190 url::ViewOption vopt)
191 {
192 const std::string & username = url.getUsername();
193 for( CredentialManager::CredentialIterator it = set.begin(); it != set.end(); ++it )
194 {
195 if ( !(*it)->url().isValid() )
196 continue;
197
198 // this ignores url params - not sure if it is good or bad...
199 if ( url.asString(vopt).find((*it)->url().asString(vopt)) == 0 )
200 {
201 if ( username.empty() || username == (*it)->username() )
202 return *it;
203 }
204 }
205
206 return AuthData_Ptr();
207 }
208
210 {
211 AuthData_Ptr result;
212
213 // compare the urls via asString(), but ignore password
214 // default url::ViewOption will take care of that.
215 // operator==(Url,Url) compares the whole Url
216
217 url::ViewOption vopt;
218 vopt = vopt
219 - url::ViewOption::WITH_USERNAME
220 - url::ViewOption::WITH_PASSWORD
221 - url::ViewOption::WITH_QUERY_STR;
222
223 // search in global credentials
224 result = findIn(_credsGlobal, url, vopt);
225
226 // search in home credentials
227 if (!result)
228 result = findIn(_credsUser, url, vopt);
229
230 if (result)
231 DBG << "Found credentials for '" << url << "':" << endl << *result << endl;
232 else
233 DBG << "No credentials for '" << url << "'" << endl;
234
235 return result;
236 }
237
238
240 {
241 AuthData_Ptr result;
242
243 Pathname credfile;
244 if (file.absolute())
245 // get from that file
246 credfile = file;
247 else
248 // get from /etc/zypp/credentials.d, delete the leading path
249 credfile = _options.customCredFileDir / file.basename();
250
251 PathInfo pi { credfile };
252 if ( pi.userMayR() ) try {
253 // make sure only our thread accesses the file
254 bpci::file_lock lockFile ( credfile.c_str() );
255 bpci::scoped_lock lock( lockFile );
256
257 CredentialFileReader(credfile, bind(&Impl::processCredentials, this, _1));
258 }
259 catch ( ... ) {
260 WAR << pi << " failed to lock file for reading." << endl;
261 }
262
263 if (_credsTmp.empty())
264 WAR << pi << " does not contain valid credentials or is not readable." << endl;
265 else
266 {
267 result = *_credsTmp.begin();
268 _credsTmp.clear();
269 }
270
271 return result;
272 }
273
276 const Pathname & file,
277 const mode_t mode)
278 {
279 int ret = 0;
280 filesystem::assert_file_mode( file, mode );
281
282 const auto now = time( nullptr );
283
284 PathInfo pi { file };
285 if ( pi.userMayRW() ) try {
286 // make sure only our thread accesses the file
287 bpci::file_lock lockFile ( file.c_str() );
288 bpci::scoped_lock lock( lockFile );
289
290 std::ofstream fs(file.c_str());
291 for ( auto& credentials : creds )
292 {
293 credentials->dumpAsIniOn( fs );
294 credentials->setLastDatabaseUpdate( now );
295 fs << endl;
296 }
297 if ( !fs ) {
298 WAR << pi << " failed to write credentials to file." << endl;
299 ret = 1;
300 }
301 fs.close();
302 }
303 catch ( ... ) {
304 WAR << pi << " failed to lock file for writing." << endl;
305 ret = 1;
306 }
307
308 return ret;
309 }
310
315
320
321
323 //
324 // CLASS NAME : CredentialManager
325 //
327
331
332
334 {
335 std::string credfile = url.getQueryParam("credentials");
336 if (credfile.empty())
337 return _pimpl->getCred(url);
338 return _pimpl->getCredFromFile(credfile);
339 }
340
341
343 { return _pimpl->getCredFromFile(file); }
344
345
347 {
348 if ( !cred.url().isValid() )
349 ZYPP_THROW( MediaInvalidCredentialsException( "URL must be valid in order to save AuthData." ) );
350
351 Pathname credfile = cred.url().getQueryParam("credentials");
352 if (credfile.empty())
354 addUserCred(cred);
355 else
356 saveInFile(cred, credfile);
357 }
358
360 {
361 Pathname credfile;
362 if ( url.isValid() ) {
363 credfile = url.getQueryParam("credentials");
364 }
365
366 if (credfile.empty())
367 credfile = _pimpl->_options.userCredFilePath;
368
369 zypp::PathInfo pi(credfile);
370 if ( pi.isExist() && pi.isFile() )
371 return pi.mtime();
372
373 return 0;
374 }
375
377 {
378 if ( !cred.url().isValid() )
379 ZYPP_THROW( MediaInvalidCredentialsException( "URL must be valid in order to save AuthData." ) );
380
381 AuthData_Ptr c_ptr;
382 c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
383 std::pair<CredentialIterator, bool> ret = _pimpl->_credsGlobal.insert(c_ptr);
384 if (ret.second)
385 _pimpl->_globalDirty = true;
386 else if ((*ret.first)->password() != cred.password())
387 {
388 _pimpl->_credsGlobal.erase(ret.first);
389 _pimpl->_credsGlobal.insert(c_ptr);
390 _pimpl->_globalDirty = true;
391 }
392 }
393
394
396 {
397 if ( !cred.url().isValid() )
398 ZYPP_THROW( MediaInvalidCredentialsException( "URL must be valid in order to save AuthData." ) );
399
400 AuthData_Ptr c_ptr;
401 c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
402 std::pair<CredentialIterator, bool> ret = _pimpl->_credsUser.insert(c_ptr);
403 if (ret.second)
404 _pimpl->_userDirty = true;
405 else if ((*ret.first)->password() != cred.password())
406 {
407 _pimpl->_credsUser.erase(ret.first);
408 _pimpl->_credsUser.insert(c_ptr);
409 _pimpl->_userDirty = true;
410 }
411 }
412
413
415 {
416 if (_pimpl->_globalDirty)
417 _pimpl->saveGlobalCredentials();
418 if (_pimpl->_userDirty)
419 _pimpl->saveUserCredentials();
420 _pimpl->_globalDirty = false;
421 _pimpl->_userDirty = false;
422 }
423
424
426 {
427 addGlobalCred(cred);
428 save();
429 }
430
431
433 {
434 addUserCred(cred);
435 save();
436 }
437
438
439 void CredentialManager::saveInFile(const AuthData & cred, const Pathname & credFile)
440 {
441 AuthData_Ptr c_ptr;
442 c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
443 c_ptr->setUrl(Url()); // don't save url in custom creds file
445 creds.insert(c_ptr);
446
447 int ret = 0;
448 if (credFile.absolute())
449 ret = save_creds_in_file(creds, credFile, 0640);
450 else
451 ret = save_creds_in_file(
452 creds, _pimpl->_options.customCredFileDir / credFile, 0600);
453
454 if (!ret)
455 {
457 ERR << "error saving the credentials" << endl;
458 }
459 }
460
461
463 {
464 if (global)
465 {
466 if (!filesystem::unlink(_pimpl->_options.globalCredFilePath))
467 ERR << "could not delete user credentials file "
468 << _pimpl->_options.globalCredFilePath << endl;
469 _pimpl->_credsUser.clear();
470 }
471 else
472 {
473 if (!filesystem::unlink(_pimpl->_options.userCredFilePath))
474 ERR << "could not delete global credentials file"
475 << _pimpl->_options.userCredFilePath << endl;
476 _pimpl->_credsGlobal.clear();
477 }
478 }
479
480
483
486
489
491 { return _pimpl->_credsGlobal.empty(); }
492
493
496
499
502
504 { return _pimpl->_credsUser.empty(); }
505
506
508 } // media
511} // zypp
Url manipulation class.
Definition Url.h:93
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:678
bool isValid() const
Verifies the Url.
Definition Url.cc:507
Wrapper class for stat/lstat.
Definition PathInfo.h:226
bool isExist() const
Return whether valid stat info exists.
Definition PathInfo.h:286
bool absolute() const
Test for an absolute path.
Definition Pathname.h:118
const char * c_str() const
String representation.
Definition Pathname.h:112
std::string basename() const
Return the last component of this path.
Definition Pathname.h:130
bool empty() const
Test for an empty path.
Definition Pathname.h:116
Class for handling media authentication data.
Definition authdata.h:31
std::string password() const
Definition authdata.h:57
Url url() const
Definition authdata.h:55
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)
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)
CredentialManager(CredManagerOptions opts=CredManagerOptions())
std::set< AuthData_Ptr, AuthDataComparator > CredentialSet
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
CredentialSet::const_iterator CredentialIterator
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.
#define USER_CREDENTIALS_FILE
Definition Arch.h:364
int assert_file_mode(const Pathname &path, unsigned mode)
Like assert_file but enforce mode even if the file already exists.
Definition PathInfo.cc:1210
int unlink(const Pathname &path)
Like 'unlink'.
Definition PathInfo.cc:705
shared_ptr< AuthData > AuthData_Ptr
Definition authdata.h:81
static int save_creds_in_file(CredentialManager::CredentialSet &creds, const Pathname &file, const mode_t mode)
Url details namespace.
Definition UrlBase.cc:58
Easy-to use interface to the ZYPP dependency resolver.
bool operator()(const AuthData_Ptr &lhs, const AuthData_Ptr &rhs) const
CredManagerOptions(const Pathname &rootdir="")
AuthData_Ptr getCred(const Url &url) const
Impl & operator=(const Impl &)=delete
Impl(CredManagerOptions &&options)
bool processCredentials(AuthData_Ptr &cred)
AuthData_Ptr getCredFromFile(const Pathname &file)
Impl & operator=(Impl &&)=delete
Url::asString() view options.
Definition UrlBase.h:41
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:459
#define DBG
Definition Logger.h:99
#define ERR
Definition Logger.h:102
#define WAR
Definition Logger.h:101