libzypp 17.37.17
MediaCIFS.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
12
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-core/KVMap>
20#include <zypp-media/Mount>
21#include <zypp-media/auth/AuthData>
22#include <zypp-media/auth/CredentialManager>
23#include <zypp/ZYppCallbacks.h>
24#include <zypp/ZConfig.h>
25
27
28#include <sys/types.h>
29#include <sys/mount.h>
30#include <errno.h>
31#include <dirent.h>
32
33using std::endl;
34
35namespace 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 std::string getShare( const Pathname& spath_r )
47 {
48 if ( spath_r.empty() )
49 return std::string();
50
51 std::string share( spath_r.absolutename().asString() );
52 std::string::size_type sep = share.find( '/', 1 );
53 if ( sep == std::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" )) != std::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( const Pathname& spath_r )
75 {
76 if ( spath_r.empty() )
77 return Pathname();
78
79 std::string striped( spath_r.absolutename().asString() );
80 std::string::size_type sep = striped.find( '/', 1 );
81 if ( sep == std::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 //
102 const Pathname & attach_point_hint_r )
103 : MediaHandler( origin_r,attach_point_hint_r,
104 stripShare( origin_r.authority().url().getPathName() ), // urlpath WITHOUT share name at attachpoint
105 false ) // does_download
106 {
107 MIL << "MediaCIFS::MediaCIFS(" << _origin.authority().url() << ", " << 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(_origin.authority().url().getHost().empty())
133 if(next)
135
136 std::string path = "//";
137 path += _origin.authority().url().getHost() + "/" + getShare( _origin.authority().url().getPathName() );
138
139 MediaSourceRef media( new MediaSource( "cifs", path));
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
159 {
161 }
162 std::string mountpoint( attachPoint().asString() );
163
164 Mount mount;
166
167 Mount::Options options( _origin.authority().url().getQueryParam("mountoptions") );
168 std::string username = _origin.authority().url().getUsername();
169 std::string password = _origin.authority().url().getPassword();
170
171 if ( ! options.has( "rw" ) ) {
172 options["ro"];
173 }
174
175 // look for a workgroup
176 std::string workgroup = _origin.authority().url().getQueryParam("workgroup");
177 if ( workgroup.empty() )
178 workgroup = _origin.authority().url().getQueryParam("domain");
179 if ( !workgroup.empty() )
180 options["domain"] = workgroup;
181
182 // extract 'username', do not overwrite any _origin.authority().username
183
184 Mount::Options::iterator toEnv;
185 toEnv = options.find("username");
186 if ( toEnv != options.end() ) {
187 if ( username.empty() )
188 username = toEnv->second;
189 options.erase( toEnv );
190 }
191
192 toEnv = options.find("user"); // actually cifs specific
193 if ( toEnv != options.end() ) {
194 if ( username.empty() )
195 username = toEnv->second;
196 options.erase( toEnv );
197 }
198
199 // extract 'password', do not overwrite any _origin.authority().password
200
201 toEnv = options.find("password");
202 if ( toEnv != options.end() ) {
203 if ( password.empty() )
204 password = toEnv->second;
205 options.erase( toEnv );
206 }
207
208 toEnv = options.find("pass"); // actually cifs specific
209 if ( toEnv != options.end() ) {
210 if ( password.empty() )
211 password = toEnv->second;
212 options.erase( toEnv );
213 }
214
215 if ( username.empty() || password.empty() )
216 {
217 AuthData_Ptr c = cm.getCred(_origin.authority().url());
218 if (c)
219 {
220 username = c->username();
221 password = c->password();
222 }
223 }
224
225 bool firstTry = true;
226 bool authRequired = false;
227 AuthData authdata;
228 do // repeat this while the mount returns "Permission denied" error
229 {
230 // get credentials from authenicate()
231 if ( !firstTry )
232 {
233 username = authdata.username();
234 password = authdata.password();
235 }
236
237 // pass 'username' and 'password' via environment
238 Mount::Environment environment;
239 if ( !username.empty() )
240 environment["USER"] = username;
241 if ( !password.empty() )
242 environment["PASSWD"] = password;
243
245 // In case we need a tmpfile, credentials will remove
246 // it in its destructor after the mout call below.
247 filesystem::TmpPath credentials;
248 if ( !username.empty() || !password.empty() )
249 {
251 std::ofstream outs( tmp.path().asString().c_str() );
252 outs << "username=" << username << endl;
253 outs << "password=" << password << endl;
254 outs.close();
255
256 credentials = tmp;
257 options["credentials"] = credentials.path().asString();
258 }
259 else
260 {
261 // Use 'guest' option unless explicitly disabled (bnc #547354)
262 if ( options.has( "noguest" ) )
263 options.erase( "noguest" );
264 else
265 // prevent smbmount from asking for password
266 // only add this option if 'credentials' is not used (bnc #560496)
267 options["guest"];
268 }
269
270 //
272
273 try
274 {
275 mount.mount( path, mountpoint, "cifs",
276 options.asString(), environment );
278 break;
279 }
280 catch (const MediaMountException & e)
281 {
282 ZYPP_CAUGHT( e );
283
284 if ( e.mountError() == "Permission denied" )
285 authRequired = authenticate( authdata, firstTry );
286 else
287 ZYPP_RETHROW( e );
288 }
289
290 firstTry = false;
291 }
292 while ( authRequired );
293
294 // wait for /etc/mtab update ...
295 // (shouldn't be needed)
296 int limit = 3;
297 bool mountsucceeded = false;
298 while( !(mountsucceeded=isAttached()) && --limit)
299 sleep(1);
300
301 if ( !mountsucceeded )
302 {
304 try
305 {
306 mount.umount(attachPoint().asString());
307 }
308 catch (const MediaException & excpt_r)
309 {
310 ZYPP_CAUGHT(excpt_r);
311 }
313 "Unable to verify that the media was mounted",
314 path, mountpoint
315 ));
316 }
317 }
318
320 //
321 // METHOD NAME : MediaCIFS::isAttached
322 // METHOD TYPE : bool
323 //
324 // DESCRIPTION : Override check if media is attached.
325 //
326 bool
328 {
329 return checkAttached(true);
330 }
331
333 //
334 //
335 // METHOD NAME : MediaCIFS::releaseFrom
336 // METHOD TYPE : PMError
337 //
338 // DESCRIPTION : Asserted that media is attached.
339 //
340 void MediaCIFS::releaseFrom( const std::string & ejectDev )
341 {
342 Mount mount;
343 mount.umount(attachPoint().asString());
344 }
345
347 //
348 // METHOD NAME : MediaCIFS::getFile
349 // METHOD TYPE : PMError
350 //
351 // DESCRIPTION : Asserted that media is attached.
352 //
353 void MediaCIFS::getFile ( const OnMediaLocation &file ) const
354 {
355 MediaHandler::getFile( file );
356 }
357
359 //
360 // METHOD NAME : MediaCIFS::getDir
361 // METHOD TYPE : PMError
362 //
363 // DESCRIPTION : Asserted that media is attached.
364 //
365 void MediaCIFS::getDir( const Pathname & dirname, bool recurse_r ) const
366 {
367 MediaHandler::getDir( dirname, recurse_r );
368 }
369
371 //
372 //
373 // METHOD NAME : MediaCIFS::getDirInfo
374 // METHOD TYPE : PMError
375 //
376 // DESCRIPTION : Asserted that media is attached and retlist is empty.
377 //
378 void MediaCIFS::getDirInfo( std::list<std::string> & retlist,
379 const Pathname & dirname, bool dots ) const
380 {
381 MediaHandler::getDirInfo( retlist, dirname, dots );
382 }
383
385 //
386 //
387 // METHOD NAME : MediaCIFS::getDirInfo
388 // METHOD TYPE : PMError
389 //
390 // DESCRIPTION : Asserted that media is attached and retlist is empty.
391 //
393 const Pathname & dirname, bool dots ) const
394 {
395 MediaHandler::getDirInfo( retlist, dirname, dots );
396 }
397
398 bool MediaCIFS::getDoesFileExist( const Pathname & filename ) const
399 {
400 return MediaHandler::getDoesFileExist( filename );
401 }
402
403 bool MediaCIFS::authenticate(AuthData & authdata, bool firstTry) const
404 {
407
408 // get stored credentials
409 AuthData_Ptr cmcred = cm.getCred(_origin.authority().url());
410
411 AuthData_Ptr smbcred;
412 smbcred.reset(new AuthData());
414
415 // preset the username if present in current url
416 if (!_origin.authority().url().getUsername().empty() && firstTry)
417 smbcred->setUsername(_origin.authority().url().getUsername());
418 // if CM has found some credentials, preset the username from there
419 else if (cmcred)
420 smbcred->setUsername(cmcred->username());
421
422 // indicate we have no good credentials from CM
423 cmcred.reset();
424
425 std::string prompt_msg = str::form(
427 _("Authentication required for '%s'"), _origin.authority().url().asString().c_str());
428
429 // ask user
430 if (auth_report->prompt(_origin.authority().url(), prompt_msg, *smbcred))
431 {
432 DBG << "callback answer: retry" << endl
433 << "AuthData: " << *smbcred << endl;
434
435 if (smbcred->valid())
436 {
437 cmcred = smbcred;
438 // if (credentials->username() != _origin.authority().getUsername())
439 // _origin.authority().setUsername(credentials->username());
447 }
448 }
449 else
450 DBG << "callback answer: cancel" << endl;
451
452 // set username and password
453 if (cmcred)
454 {
455 authdata.setUsername(cmcred->username());
456 authdata.setPassword(cmcred->password());
457
458 // save the credentials
459 cmcred->setUrl(_origin.authority().url());
460 cm.addCred(*cmcred);
461 cm.save();
462
463 return true;
464 }
465
466 return false;
467 }
468
469
470 } // namespace media
471} // namespace zypp
Manages a data source characterized by an authoritative URL and a list of mirror URLs.
Describes a resource file located on a medium.
static ZConfig & instance()
Singleton ctor.
Definition ZConfig.cc:940
const std::string & asString() const
String representation.
Definition Pathname.h:93
bool empty() const
Test for an empty path.
Definition Pathname.h:116
Pathname absolutename() const
Return this path, adding a leading '/' if relative.
Definition Pathname.h:141
Provide a new empty temporary file and delete it when no longer needed.
Definition TmpPath.h:128
Automaticaly deletes files or directories when no longer needed.
Definition TmpPath.h:41
Pathname path() const
Definition TmpPath.cc:152
Class for handling media authentication data.
Definition authdata.h:31
std::string password() const
Definition authdata.h:57
void setUsername(const std::string &username)
Definition authdata.h:52
void setPassword(const std::string &password)
Definition authdata.h:53
std::string username() const
Definition authdata.h:56
void save()
Saves any unsaved credentials added via addUserCred() or addGlobalCred() methods.
AuthData_Ptr getCred(const Url &url)
Get credentials for the specified url.
void addCred(const AuthData &cred)
Add new credentials with user callbacks.
bool getDoesFileExist(const Pathname &filename) const override
check if a file exists
Definition MediaCIFS.cc:398
void releaseFrom(const std::string &ejectDev) override
Call concrete handler to release the media.
Definition MediaCIFS.cc:340
MediaCIFS(const MirroredOrigin &origin_r, const Pathname &attach_point_hint_r)
Definition MediaCIFS.cc:101
void getDir(const Pathname &dirname, bool recurse_r) const override
Call concrete handler to provide directory content (not recursive!) below attach point.
Definition MediaCIFS.cc:365
bool authenticate(AuthData &authdata, bool firstTry) const
Definition MediaCIFS.cc:403
bool isAttached() const override
True if media is attached.
Definition MediaCIFS.cc:327
void getDirInfo(std::list< std::string > &retlist, const Pathname &dirname, bool dots=true) const override
Call concrete handler to provide a content list of directory on media via retlist.
Definition MediaCIFS.cc:378
void getFile(const OnMediaLocation &file) const override
Call concrete handler to provide file below attach point.
Definition MediaCIFS.cc:353
void attachTo(bool next=false) override
Asserted that not already attached, and attachPoint is a directory.
Definition MediaCIFS.cc:129
Just inherits Exception to separate media exceptions.
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...
virtual void getFile(const OnMediaLocation &file) const
Call concrete handler to provide file below attach point.
MediaHandler(MirroredOrigin origin_r, const Pathname &attach_point_r, Pathname urlpath_below_attachpoint_r, const bool does_download_r)
If the concrete media handler provides a nonempty attach_point, it must be an existing directory.
MirroredOrigin _origin
Contains the authority URL and mirrors.
Url url() const
Primary Url used.
virtual bool getDoesFileExist(const Pathname &filename) const =0
check if a file exists
Pathname createAttachPoint() const
Try to create a default / temporary attach point.
void setMediaSource(const MediaSourceRef &ref)
Set new media source reference.
bool checkAttached(bool matchMountFs) const
Check actual mediaSource attachment against the current mount table of the system.
void removeAttachPoint()
Remove unused attach point.
void setAttachPoint(const Pathname &path, bool temp)
Set a new attach point.
Pathname attachPoint() const
Return the currently used attach point.
virtual void getDir(const Pathname &dirname, bool recurse_r) const =0
Call concrete handler to provide directory content (not recursive!) below attach point.
AttachedMedia findAttachedMedia(const MediaSourceRef &media) const
Ask the media manager if specified media source is already attached.
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.
const std::string & mountError() const
Media source internally used by MediaManager and MediaHandler.
Definition MediaSource.h:38
Interface to the mount program.
Definition mount.h:76
void umount(const std::string &path)
umount device
Definition mount.cc:117
ExternalProgram::Environment Environment
For passing additional environment variables to mount.
Definition mount.h:83
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:62
KVMap< kvmap::KVMapBase::CharSep<'=', ','> > Options
Mount options.
Definition mount.h:88
std::list< DirEntry > DirContent
Returned by readdir.
Definition PathInfo.h:526
std::string getShare(const Pathname &spath_r)
Definition MediaCIFS.cc:46
shared_ptr< AuthData > AuthData_Ptr
Definition authdata.h:81
zypp::RW_pointer< MediaSource > MediaSourceRef
Pathname stripShare(const Pathname &spath_r)
Definition MediaCIFS.cc:74
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition String.cc:39
Easy-to use interface to the ZYPP dependency resolver.
std::string asString(const Patch::Category &obj)
Definition Patch.cc:122
std::string asString() const
Definition kvmap.h:190
bool has(const std::string &key_r) const
Test whether key is set.
Definition kvmap.h:98
A simple structure containing references to a media source and its attach point.
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition Exception.h:479
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition Exception.h:475
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:459
#define _(MSG)
Definition Gettext.h:39
#define DBG
Definition Logger.h:99
#define MIL
Definition Logger.h:100
Interface to gettext.