libzypp  11.13.5
MediaCIFS.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
13 #include <iostream>
14 #include <fstream>
15 
16 #include "zypp/base/Logger.h"
17 #include "zypp/base/Gettext.h"
18 #include "zypp/TmpPath.h"
19 #include "zypp/KVMap.h"
20 #include "zypp/media/Mount.h"
23 #include "zypp/ZYppCallbacks.h"
24 #include "zypp/ZConfig.h"
25 
26 #include "zypp/media/MediaCIFS.h"
27 
28 #include <sys/types.h>
29 #include <sys/mount.h>
30 #include <errno.h>
31 #include <dirent.h>
32 
33 using namespace std;
34 
35 namespace zypp {
36  namespace media {
37 
38  /******************************************************************
39  **
40  **
41  ** FUNCTION NAME : getShare
42  ** FUNCTION TYPE : inline Pathname
43  **
44  ** Get the 1st path component (CIFS share name).
45  */
46  inline string getShare( Pathname spath_r )
47  {
48  if ( spath_r.empty() )
49  return string();
50 
51  string share( spath_r.absolutename().asString() );
52  string::size_type sep = share.find( "/", 1 );
53  if ( sep == string::npos )
54  share = share.erase( 0, 1 ); // nothing but the share name in spath_r
55  else
56  share = share.substr( 1, sep-1 );
57 
58  // deescape %2f in sharename
59  while ( (sep = share.find( "%2f" )) != string::npos ) {
60  share.replace( sep, 3, "/" );
61  }
62 
63  return share;
64  }
65 
66  /******************************************************************
67  **
68  **
69  ** FUNCTION NAME : stripShare
70  ** FUNCTION TYPE : inline Pathname
71  **
72  ** Strip off the 1st path component (CIFS share name).
73  */
74  inline Pathname stripShare( Pathname spath_r )
75  {
76  if ( spath_r.empty() )
77  return Pathname();
78 
79  string striped( spath_r.absolutename().asString() );
80  string::size_type sep = striped.find( "/", 1 );
81  if ( sep == string::npos )
82  return "/"; // nothing but the share name in spath_r
83 
84  return striped.substr( sep );
85  }
86 
88  //
89  // CLASS NAME : MediaCIFS
90  //
92 
94  //
95  //
96  // METHOD NAME : MediaCIFS::MediaCIFS
97  // METHOD TYPE : Constructor
98  //
99  // DESCRIPTION :
100  //
101  MediaCIFS::MediaCIFS( const Url & url_r,
102  const Pathname & attach_point_hint_r )
103  : MediaHandler( url_r, attach_point_hint_r,
104  stripShare( url_r.getPathName() ), // urlpath WITHOUT share name at attachpoint
105  false ) // does_download
106  {
107  MIL << "MediaCIFS::MediaCIFS(" << url_r << ", " << attach_point_hint_r << ")" << endl;
108  }
109 
111  //
112  //
113  // METHOD NAME : MediaCIFS::attachTo
114  // METHOD TYPE : PMError
129  void MediaCIFS::attachTo(bool next)
130  {
131  if(_url.getHost().empty())
133  if(next)
135 
136  string path = "//";
137  path += _url.getHost() + "/" + getShare( _url.getPathName() );
138 
139  MediaSourceRef media( new MediaSource( "cifs", path));
140  AttachedMedia ret( findAttachedMedia( media));
141 
142  if( ret.mediaSource &&
143  ret.attachPoint &&
144  !ret.attachPoint->empty())
145  {
146  DBG << "Using a shared media "
147  << ret.mediaSource->name
148  << " attached on "
149  << ret.attachPoint->path
150  << endl;
151 
155  return;
156  }
157 
158  std::string mountpoint = attachPoint().asString();
160  {
161  mountpoint = createAttachPoint().asString();
162  if( mountpoint.empty())
164  setAttachPoint( mountpoint, true);
165  }
166 
167  Mount mount;
169 
170  Mount::Options options( _url.getQueryParam("mountoptions") );
171  string username = _url.getUsername();
172  string password = _url.getPassword();
173 
174  if ( ! options.has( "rw" ) ) {
175  options["ro"];
176  }
177 
178  // look for a workgroup
179  string workgroup = _url.getQueryParam("workgroup");
180  if ( workgroup.empty() )
181  workgroup = _url.getQueryParam("domain");
182  if ( !workgroup.empty() )
183  options["domain"] = workgroup;
184 
185  // extract 'username', do not overwrite any _url.username
186 
187  Mount::Options::iterator toEnv;
188  toEnv = options.find("username");
189  if ( toEnv != options.end() ) {
190  if ( username.empty() )
191  username = toEnv->second;
192  options.erase( toEnv );
193  }
194 
195  toEnv = options.find("user"); // actually cifs specific
196  if ( toEnv != options.end() ) {
197  if ( username.empty() )
198  username = toEnv->second;
199  options.erase( toEnv );
200  }
201 
202  // extract 'password', do not overwrite any _url.password
203 
204  toEnv = options.find("password");
205  if ( toEnv != options.end() ) {
206  if ( password.empty() )
207  password = toEnv->second;
208  options.erase( toEnv );
209  }
210 
211  toEnv = options.find("pass"); // actually cifs specific
212  if ( toEnv != options.end() ) {
213  if ( password.empty() )
214  password = toEnv->second;
215  options.erase( toEnv );
216  }
217 
218  if ( username.empty() || password.empty() )
219  {
220  AuthData_Ptr c = cm.getCred(_url);
221  if (c)
222  {
223  username = c->username();
224  password = c->password();
225  }
226  }
227 
228  bool firstTry = true;
229  bool authRequired = false;
230  AuthData authdata;
231  do // repeat this while the mount returns "Permission denied" error
232  {
233  // get credentials from authenicate()
234  if ( !firstTry )
235  {
236  username = authdata.username();
237  password = authdata.password();
238  }
239 
240  // pass 'username' and 'password' via environment
241  Mount::Environment environment;
242  if ( !username.empty() )
243  environment["USER"] = username;
244  if ( !password.empty() )
245  environment["PASSWD"] = password;
246 
248  // In case we need a tmpfile, credentials will remove
249  // it in it's destructor after the mout call below.
250  filesystem::TmpPath credentials;
251  if ( !username.empty() || !password.empty() )
252  {
254  ofstream outs( tmp.path().asString().c_str() );
255  outs << "username=" << username << endl;
256  outs << "password=" << password << endl;
257  outs.close();
258 
259  credentials = tmp;
260  options["credentials"] = credentials.path().asString();
261  }
262  else
263  {
264  // Use 'guest' option unless explicitly disabled (bnc #547354)
265  if ( options.has( "noguest" ) )
266  options.erase( "noguest" );
267  else
268  // prevent smbmount from asking for password
269  // only add this option if 'credentials' is not used (bnc #560496)
270  options["guest"];
271  }
272 
273  //
275 
276  try
277  {
278  mount.mount( path, mountpoint, "cifs",
279  options.asString(), environment );
280  setMediaSource(media);
281  break;
282  }
283  catch (const MediaMountException & e)
284  {
285  ZYPP_CAUGHT( e );
286 
287  if ( e.mountError() == "Permission denied" )
288  authRequired = authenticate( authdata, firstTry );
289  else
290  ZYPP_RETHROW( e );
291  }
292 
293  firstTry = false;
294  }
295  while ( authRequired );
296 
297  // wait for /etc/mtab update ...
298  // (shouldn't be needed)
299  int limit = 3;
300  bool mountsucceeded;
301  while( !(mountsucceeded=isAttached()) && --limit)
302  sleep(1);
303 
304  if ( !mountsucceeded )
305  {
307  try
308  {
309  mount.umount(attachPoint().asString());
310  }
311  catch (const MediaException & excpt_r)
312  {
313  ZYPP_CAUGHT(excpt_r);
314  }
316  "Unable to verify that the media was mounted",
317  path, mountpoint
318  ));
319  }
320  }
321 
323  //
324  // METHOD NAME : MediaCIFS::isAttached
325  // METHOD TYPE : bool
326  //
327  // DESCRIPTION : Override check if media is attached.
328  //
329  bool
331  {
332  return checkAttached(true);
333  }
334 
336  //
337  //
338  // METHOD NAME : MediaCIFS::releaseFrom
339  // METHOD TYPE : PMError
340  //
341  // DESCRIPTION : Asserted that media is attached.
342  //
343  void MediaCIFS::releaseFrom( const std::string & ejectDev )
344  {
345  Mount mount;
346  mount.umount(attachPoint().asString());
347  }
348 
350  //
351  // METHOD NAME : MediaCIFS::getFile
352  // METHOD TYPE : PMError
353  //
354  // DESCRIPTION : Asserted that media is attached.
355  //
356  void MediaCIFS::getFile (const Pathname & filename) const
357  {
358  MediaHandler::getFile( filename );
359  }
360 
362  //
363  // METHOD NAME : MediaCIFS::getDir
364  // METHOD TYPE : PMError
365  //
366  // DESCRIPTION : Asserted that media is attached.
367  //
368  void MediaCIFS::getDir( const Pathname & dirname, bool recurse_r ) const
369  {
370  MediaHandler::getDir( dirname, recurse_r );
371  }
372 
374  //
375  //
376  // METHOD NAME : MediaCIFS::getDirInfo
377  // METHOD TYPE : PMError
378  //
379  // DESCRIPTION : Asserted that media is attached and retlist is empty.
380  //
381  void MediaCIFS::getDirInfo( std::list<std::string> & retlist,
382  const Pathname & dirname, bool dots ) const
383  {
384  MediaHandler::getDirInfo( retlist, dirname, dots );
385  }
386 
388  //
389  //
390  // METHOD NAME : MediaCIFS::getDirInfo
391  // METHOD TYPE : PMError
392  //
393  // DESCRIPTION : Asserted that media is attached and retlist is empty.
394  //
396  const Pathname & dirname, bool dots ) const
397  {
398  MediaHandler::getDirInfo( retlist, dirname, dots );
399  }
400 
401  bool MediaCIFS::getDoesFileExist( const Pathname & filename ) const
402  {
403  return MediaHandler::getDoesFileExist( filename );
404  }
405 
406  bool MediaCIFS::authenticate(AuthData & authdata, bool firstTry) const
407  {
410 
411  // get stored credentials
412  AuthData_Ptr cmcred = cm.getCred(_url);
413 
414  AuthData_Ptr smbcred;
415  smbcred.reset(new AuthData());
417 
418  // preset the username if present in current url
419  if (!_url.getUsername().empty() && firstTry)
420  smbcred->setUsername(_url.getUsername());
421  // if CM has found some credentials, preset the username from there
422  else if (cmcred)
423  smbcred->setUsername(cmcred->username());
424 
425  // indicate we have no good credentials from CM
426  cmcred.reset();
427 
428  string prompt_msg = str::form(
430  _("Authentication required for '%s'"), _url.asString().c_str());
431 
432  // ask user
433  if (auth_report->prompt(_url, prompt_msg, *smbcred))
434  {
435  DBG << "callback answer: retry" << endl
436  << "AuthData: " << *smbcred << endl;
437 
438  if (smbcred->valid())
439  {
440  cmcred = smbcred;
441  // if (credentials->username() != _url.getUsername())
442  // _url.setUsername(credentials->username());
450  }
451  }
452  else
453  DBG << "callback answer: cancel" << endl;
454 
455  // set username and password
456  if (cmcred)
457  {
458  authdata.setUsername(cmcred->username());
459  authdata.setPassword(cmcred->password());
460 
461  // save the credentials
462  cmcred->setUrl(_url);
463  cm.addCred(*cmcred);
464  cm.save();
465 
466  return true;
467  }
468 
469  return false;
470  }
471 
472 
473  } // namespace media
474 } // namespace zypp