- set 600 on user creds and 640 permissions on global creds file
[platform/upstream/libzypp.git] / zypp / media / CredentialManager.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/media/CredentialManager.h
10  *
11  */
12 #include <iostream>
13 #include <fstream>
14
15 #include "zypp/base/Function.h"
16 #include "zypp/base/Logger.h"
17 #include "zypp/base/Easy.h"
18 #include "zypp/PathInfo.h"
19
20 #include "zypp/media/CredentialFileReader.h"
21
22 #include "zypp/media/CredentialManager.h"
23
24 #define CUSTOM_CREDENTIALS_FILE_DIR "/etc/zypp/credentials.d"
25 #define GLOBAL_CREDENTIALS_FILE "/etc/zypp/credentials.cat" 
26 #define USER_CREDENTIALS_FILE   ".zypp/credentials.cat"
27
28 using namespace std;
29
30 //////////////////////////////////////////////////////////////////////
31 namespace zypp 
32 { ////////////////////////////////////////////////////////////////////
33   //////////////////////////////////////////////////////////////////////
34   namespace media
35   { ////////////////////////////////////////////////////////////////////
36
37
38   //////////////////////////////////////////////////////////////////////
39   //
40   // CLASS NAME : CredManagerOptions 
41   //
42   //////////////////////////////////////////////////////////////////////
43
44   CredManagerOptions::CredManagerOptions(const Pathname & rootdir)
45     : globalCredFilePath(rootdir / GLOBAL_CREDENTIALS_FILE)
46     , customCredFileDir(rootdir / CUSTOM_CREDENTIALS_FILE_DIR)
47   {
48     char * homedir = getenv("HOME");
49     if (homedir)
50       userCredFilePath = rootdir / homedir / USER_CREDENTIALS_FILE;
51   }
52
53
54   //////////////////////////////////////////////////////////////////////
55   //
56   // CLASS NAME : CredentialManager::Impl 
57   //
58   struct CredentialManager::Impl
59   {
60     Impl(const CredManagerOptions & options);
61
62     ~Impl()
63     {}
64     
65     void init_globalCredentials();
66     void init_userCredentials();
67
68     bool processCredentials(AuthData_Ptr & cred);
69
70     AuthData_Ptr getCred(const Url & url) const;
71     AuthData_Ptr getCredFromFile(const Pathname & file);
72     void saveGlobalCredentials();
73     void saveUserCredentials();
74
75
76     CredManagerOptions _options;
77
78     CredentialSet _credsGlobal;
79     CredentialSet _credsUser;
80     CredentialSet _credsTmp;
81   };
82   //////////////////////////////////////////////////////////////////////
83
84
85   //////////////////////////////////////////////////////////////////////
86   //
87   // CLASS NAME : CredentialManager::Impl 
88   //
89   //////////////////////////////////////////////////////////////////////
90
91   CredentialManager::Impl::Impl(const CredManagerOptions & options)
92     : _options(options)
93   {
94     init_globalCredentials();
95     init_userCredentials();
96   }
97
98
99   void CredentialManager::Impl::init_globalCredentials()
100   {
101     if (_options.globalCredFilePath.empty())
102       DBG << "global cred file not known";
103     else if (PathInfo(_options.globalCredFilePath).isExist())
104     {
105     /*  list<Pathname> entries;
106       if (filesystem::readdir(entries, _options.globalCredFilePath, false) != 0)
107         ZYPP_THROW(Exception("failed to read directory"));
108
109       for_(it, entries.begin(), entries.end())*/
110
111       CredentialFileReader(_options.globalCredFilePath,
112           bind(&Impl::processCredentials, this, _1));
113     }
114     else
115       DBG << "global cred file does not exist";
116
117     _credsGlobal = _credsTmp; _credsTmp.clear();
118     DBG << "Got " << _credsGlobal.size() << " global records." << endl;
119   }
120
121
122   void CredentialManager::Impl::init_userCredentials()
123   {
124     if (_options.userCredFilePath.empty())
125       DBG << "user cred file not known";
126     else if (PathInfo(_options.userCredFilePath).isExist())
127     {
128     /*  list<Pathname> entries;
129       if (filesystem::readdir(entries, _options.userCredFilePath, false ) != 0)
130         ZYPP_THROW(Exception("failed to read directory"));
131
132       for_(it, entries.begin(), entries.end())*/
133       CredentialFileReader(_options.userCredFilePath,
134           bind(&Impl::processCredentials, this, _1));
135     }
136     else
137       DBG << "user cred file does not exist";
138
139     _credsUser = _credsTmp; _credsTmp.clear();
140     DBG << "Got " << _credsUser.size() << " user records." << endl;
141   }
142
143
144   bool CredentialManager::Impl::processCredentials(AuthData_Ptr & cred)
145   {
146     _credsTmp.insert(cred);
147     return true;
148   }
149
150
151   static AuthData_Ptr findIn(const CredentialManager::CredentialSet & set,
152                              const Url & url,
153                              url::ViewOption vopt)
154   {
155     for(CredentialManager::CredentialIterator it = set.begin(); it != set.end(); ++it)
156     {
157       if (url.asString(vopt) == (*it)->url().asString(vopt))
158         return *it;
159     }
160     
161     return AuthData_Ptr();
162   }
163
164
165   AuthData_Ptr CredentialManager::Impl::getCred(const Url & url) const
166   {
167     AuthData_Ptr result;
168
169     // compare the urls via asString(), but ignore password
170     // default url::ViewOption will take care of that.
171     // operator==(Url,Url) compares the whole Url
172
173     // if the wanted URL does not contain username, ignore that, too
174     url::ViewOption vopt;
175 //    if (url.getUsername().empty())
176       vopt = vopt - url::ViewOption::WITH_USERNAME;
177
178     // search in global credentials
179     result = findIn(_credsGlobal, url, vopt);
180
181     // search in home credentials
182     if (!result)
183       result = findIn(_credsUser, url, vopt);
184
185     if (result)
186       DBG << "Found credentials for '" << url << "':" << endl << *result;
187     else
188       DBG << "No credentials for '" << url << "'" << endl;
189
190     return result;
191   }
192
193
194   AuthData_Ptr CredentialManager::Impl::getCredFromFile(const Pathname & file)
195   {
196     AuthData_Ptr result;
197     
198     Pathname credfile;
199     if (file.absolute())
200       // get from that file
201       credfile = file;
202     else
203       // get from /etc/zypp/credentials.d
204       credfile = _options.customCredFileDir / file;
205
206     CredentialFileReader(credfile, bind(&Impl::processCredentials, this, _1));
207     if (_credsTmp.empty())
208       WAR << file << " does not contain valid credentials or is not readable." << endl;
209     else
210     {
211       result = *_credsTmp.begin();
212       _credsTmp.clear();
213     }
214
215     return result;
216   }
217
218   static int save_creds_in_file(
219       const CredentialManager::CredentialSet creds,
220       const Pathname & file,
221       const mode_t mode)
222   {
223     int ret = 0;
224     filesystem::assert_dir(file.dirname());
225
226     std::ofstream fs(file.c_str());
227     if (!fs)
228       ret = 1;
229
230     for_(it, creds.begin(), creds.end())
231     {
232       (*it)->dumpAsIniOn(fs);
233       fs << endl;
234     }
235     fs.close();
236
237     filesystem::chmod(file, mode);
238
239     return ret;
240   }
241
242   void  CredentialManager::Impl::saveGlobalCredentials()
243   {
244     save_creds_in_file(_credsGlobal, _options.globalCredFilePath, 0640);
245   }
246
247   void  CredentialManager::Impl::saveUserCredentials()
248   {
249     save_creds_in_file(_credsUser, _options.userCredFilePath, 0600);
250   }
251
252
253   //////////////////////////////////////////////////////////////////////
254   //
255   // CLASS NAME : CredentialManager 
256   //
257   //////////////////////////////////////////////////////////////////////
258
259   CredentialManager::CredentialManager(const CredManagerOptions & opts)
260     : _pimpl(new Impl(opts))
261   {}
262
263
264   AuthData_Ptr CredentialManager::getCred(const Url & url)
265   { return _pimpl->getCred(url); }
266
267
268   AuthData_Ptr CredentialManager::getCredFromFile(const Pathname & file)
269   { return _pimpl->getCredFromFile(file); }
270
271
272   void CredentialManager::save(const AuthData & cred, bool global)
273   { global ? saveInGlobal(cred) : saveInUser(cred); }
274
275
276   void CredentialManager::saveInGlobal(const AuthData & cred)
277   {
278     AuthData_Ptr c_ptr;
279     c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
280     _pimpl->_credsGlobal.insert(c_ptr); //! \todo avoid adding duplicates
281     _pimpl->saveGlobalCredentials();
282   }
283
284
285   void CredentialManager::saveInUser(const AuthData & cred)
286   {
287     AuthData_Ptr c_ptr;
288     c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
289     _pimpl->_credsUser.insert(c_ptr); //! \todo avoid adding duplicates
290     _pimpl->saveUserCredentials();
291   }
292
293
294   void CredentialManager::saveIn(const AuthData & cred, const Pathname & credFile)
295   {
296     AuthData_Ptr c_ptr;
297     c_ptr.reset(new AuthData(cred)); // FIX for child classes if needed
298     CredentialManager::CredentialSet creds;
299     creds.insert(c_ptr);
300
301     int ret;
302     if (credFile.absolute())
303       ret = save_creds_in_file(creds, credFile, 0640);
304     else
305       ret = save_creds_in_file(
306           creds, _pimpl->_options.customCredFileDir / credFile, 0600);
307
308     if (!ret)
309     {
310       //! \todo figure out the reason(?), call back to user
311       ERR << "error saving the credentials" << endl;
312     }
313   }
314
315
316   void CredentialManager::clearAll(bool global)
317   {
318     if (global)
319     {
320       if (!filesystem::unlink(_pimpl->_options.globalCredFilePath))
321         ERR << "could not delete user credentials file "
322             << _pimpl->_options.globalCredFilePath << endl;
323       _pimpl->_credsUser.clear();
324     }
325     else
326     {
327       if (!filesystem::unlink(_pimpl->_options.userCredFilePath))
328         ERR << "could not delete global credentials file"
329             << _pimpl->_options.userCredFilePath << endl;
330       _pimpl->_credsGlobal.clear();
331     }
332   }
333
334
335   CredentialManager::CredentialIterator CredentialManager::credsGlobalBegin() const
336   { return _pimpl->_credsGlobal.begin(); }
337
338   CredentialManager::CredentialIterator CredentialManager::credsGlobalEnd() const
339   { return _pimpl->_credsGlobal.end(); }
340
341   CredentialManager::CredentialSize CredentialManager::credsGlobalSize() const
342   { return _pimpl->_credsGlobal.size(); }
343
344   bool CredentialManager::credsGlobalEmpty() const
345   { return _pimpl->_credsGlobal.empty(); }
346
347
348   CredentialManager::CredentialIterator CredentialManager::credsUserBegin() const
349   { return _pimpl->_credsUser.begin(); }
350
351   CredentialManager::CredentialIterator CredentialManager::credsUserEnd() const
352   { return _pimpl->_credsUser.end(); }
353
354   CredentialManager::CredentialSize CredentialManager::credsUserSize() const
355   { return _pimpl->_credsUser.size(); }
356
357   bool CredentialManager::credsUserEmpty() const
358   { return _pimpl->_credsUser.empty(); }
359
360
361     ////////////////////////////////////////////////////////////////////
362   } // media
363   //////////////////////////////////////////////////////////////////////
364   ////////////////////////////////////////////////////////////////////
365 } // zypp
366 //////////////////////////////////////////////////////////////////////