libzypp  13.10.6
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
virtual bool isAttached() const
True if media is attached.
Definition: MediaCIFS.cc:330
Interface to gettext.
#define MIL
Definition: Logger.h:47
Interface to the mount program.
Definition: Mount.h:69
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:320
static ZConfig & instance()
Singleton ctor.
Definition: ZConfig.cc:655
Pathname path() const
Definition: TmpPath.cc:146
void setPassword(const std::string &password)
Definition: MediaUserAuth.h:53
virtual void getDir(const Pathname &dirname, bool recurse_r) const =0
Call concrete handler to provide directory content (not recursive!) below attach point.
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
Definition: Url.cc:598
std::string getHost(EEncoding eflag=zypp::url::E_DECODED) const
Returns the hostname or IP from the URL authority.
Definition: Url.cc:582
zypp::RW_pointer< MediaSource > MediaSourceRef
Definition: MediaSource.h:124
const std::string & asString() const
String representation.
Definition: Pathname.h:90
void save()
Saves any unsaved credentials added via addUserCred() or addGlobalCred() methods. ...
void setAttachPoint(const Pathname &path, bool temp)
Set a new attach point.
Pathname createAttachPoint() const
Try to create a default / temporary attach point.
bool authenticate(AuthData &authdata, bool firstTry) const
Definition: MediaCIFS.cc:406
ExternalProgram::Environment Environment
For passing additional environment variables to mount.
Definition: Mount.h:77
Pathname stripShare(Pathname spath_r)
Definition: MediaCIFS.cc:74
std::string getUsername(EEncoding eflag=zypp::url::E_DECODED) const
Returns the username from the URL authority.
Definition: Url.cc:566
AuthData_Ptr getCred(const Url &url)
Get credentials for the specified url.
virtual bool getDoesFileExist(const Pathname &filename) const
check if a file exists
Definition: MediaCIFS.cc:401
Provide a new empty temporary file and delete it when no longer needed.
Definition: TmpPath.h:126
virtual void getFile(const Pathname &filename) const
Call concrete handler to provide file below attach point.
Definition: MediaCIFS.cc:356
std::string asString() const
Returns a default string representation of the Url object.
Definition: Url.cc:491
void mount(const std::string &source, const std::string &target, const std::string &filesystem, const std::string &options, const Environment &environment=Environment())
mount device
Definition: Mount.cc:66
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition: Exception.h:328
AttachPointRef attachPoint
Definition: MediaSource.h:145
AttachedMedia findAttachedMedia(const MediaSourceRef &media) const
Ask the media manager if specified media source is already attached.
MediaSourceRef mediaSource
Definition: MediaSource.h:144
Abstract base class for &#39;physical&#39; MediaHandler like MediaCD, etc.
Definition: MediaHandler.h:45
A simple structure containing references to a media source and its attach point.
Definition: MediaSource.h:133
std::string username() const
Definition: MediaUserAuth.h:56
const Url _url
Url to handle.
Definition: MediaHandler.h:110
void setMediaSource(const MediaSourceRef &ref)
Set new media source reference.
Just inherits Exception to separate media exceptions.
std::list< DirEntry > DirContent
Returned by readdir.
Definition: PathInfo.h:544
#define _(MSG)
Return translated text.
Definition: Gettext.h:21
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:654
bool isUseableAttachPoint(const Pathname &path, bool mtab=true) const
Ask media manager, if the specified path is already used as attach point or if there are another atta...
const std::string & mountError() const
Class for handling media authentication data.
Definition: MediaUserAuth.h:30
void removeAttachPoint()
Remove unused attach point.
SolvableIdType size_type
Definition: PoolMember.h:99
std::string asString(const Patch::SeverityFlag &obj)
Definition: Patch.cc:149
Media source internally used by MediaManager and MediaHandler.
Definition: MediaSource.h:36
virtual void releaseFrom(const std::string &ejectDev)
Call concrete handler to release the media.
Definition: MediaCIFS.cc:343
string getShare(Pathname spath_r)
Definition: MediaCIFS.cc:46
virtual void getDir(const Pathname &dirname, bool recurse_r) const
Call concrete handler to provide directory content (not recursive!) below attach point.
Definition: MediaCIFS.cc:368
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:324
std::string form(const char *format,...)
Printf style construction of std::string.
Definition: String.cc:34
shared_ptr< AuthData > AuthData_Ptr
Definition: MediaUserAuth.h:69
virtual void attachTo(bool next=false)
Asserted that not already attached, and attachPoint is a directory.
Definition: MediaCIFS.cc:129
virtual void getDirInfo(std::list< std::string > &retlist, const Pathname &dirname, bool dots=true) const =0
Call concrete handler to provide a content list of directory on media via retlist.
virtual bool getDoesFileExist(const Pathname &filename) const =0
check if a file exists
Pathname attachPoint() const
Return the currently used attach point.
virtual void getFile(const Pathname &filename) const =0
Call concrete handler to provide file below attach point.
Automaticaly deletes files or directories when no longer needed.
Definition: TmpPath.h:39
bool checkAttached(bool matchMountFs) const
Check actual mediaSource attachment against the current mount table of the system.
A map of (key,value) strings.
Definition: KVMap.h:176
std::string password() const
Definition: MediaUserAuth.h:57
void setUsername(const std::string &username)
Definition: MediaUserAuth.h:52
void addCred(const AuthData &cred)
Add new credentials with user callbacks.
Url url() const
Url used.
Definition: MediaHandler.h:506
Convenience interface for handling authentication data of media user.
Url manipulation class.
Definition: Url.h:87
void umount(const std::string &path)
umount device
Definition: Mount.cc:162
#define DBG
Definition: Logger.h:46
virtual void getDirInfo(std::list< std::string > &retlist, const Pathname &dirname, bool dots=true) const
Call concrete handler to provide a content list of directory on media via retlist.
Definition: MediaCIFS.cc:381
std::string getPassword(EEncoding eflag=zypp::url::E_DECODED) const
Returns the password from the URL authority.
Definition: Url.cc:574