libzypp 17.31.23
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-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( 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( 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 //
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 std::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
159 {
161 }
162 std::string mountpoint( attachPoint().asString() );
163
164 Mount mount;
166
167 Mount::Options options( _url.getQueryParam("mountoptions") );
168 std::string username = _url.getUsername();
169 std::string password = _url.getPassword();
170
171 if ( ! options.has( "rw" ) ) {
172 options["ro"];
173 }
174
175 // look for a workgroup
176 std::string workgroup = _url.getQueryParam("workgroup");
177 if ( workgroup.empty() )
178 workgroup = _url.getQueryParam("domain");
179 if ( !workgroup.empty() )
180 options["domain"] = workgroup;
181
182 // extract 'username', do not overwrite any _url.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 _url.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(_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 );
277 setMediaSource(media);
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;
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(_url);
410
411 AuthData_Ptr smbcred;
412 smbcred.reset(new AuthData());
414
415 // preset the username if present in current url
416 if (!_url.getUsername().empty() && firstTry)
417 smbcred->setUsername(_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'"), _url.asString().c_str());
428
429 // ask user
430 if (auth_report->prompt(_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() != _url.getUsername())
439 // _url.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(_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
Describes a resource file located on a medium.
Url manipulation class.
Definition: Url.h:92
std::string asString() const
Returns a default string representation of the Url object.
Definition: Url.cc:497
std::string getUsername(EEncoding eflag=zypp::url::E_DECODED) const
Returns the username from the URL authority.
Definition: Url.cc:572
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
Definition: Url.cc:604
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:660
std::string getHost(EEncoding eflag=zypp::url::E_DECODED) const
Returns the hostname or IP from the URL authority.
Definition: Url.cc:588
std::string getPassword(EEncoding eflag=zypp::url::E_DECODED) const
Returns the password from the URL authority.
Definition: Url.cc:580
static ZConfig & instance()
Singleton ctor.
Definition: ZConfig.cc:922
const std::string & asString() const
String representation.
Definition: Pathname.h:91
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
Pathname absolutename() const
Return this path, adding a leading '/' if relative.
Definition: Pathname.h:139
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:146
Class for handling media authentication data.
Definition: authdata.h:29
std::string password() const
Definition: authdata.h:55
void setUsername(const std::string &username)
Definition: authdata.h:50
void setPassword(const std::string &password)
Definition: authdata.h:51
std::string username() const
Definition: authdata.h:54
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.
virtual bool getDoesFileExist(const Pathname &filename) const override
check if a file exists
Definition: MediaCIFS.cc:398
virtual void releaseFrom(const std::string &ejectDev) override
Call concrete handler to release the media.
Definition: MediaCIFS.cc:340
virtual 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
virtual bool isAttached() const override
True if media is attached.
Definition: MediaCIFS.cc:327
virtual 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
virtual void getFile(const OnMediaLocation &file) const override
Call concrete handler to provide file below attach point.
Definition: MediaCIFS.cc:353
MediaCIFS(const Url &url_r, const Pathname &attach_point_hint_r)
Definition: MediaCIFS.cc:101
virtual 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.
Abstract base class for 'physical' MediaHandler like MediaCD, etc.
Definition: MediaHandler.h:51
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.
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.
const Url _url
Url to handle.
Definition: MediaHandler.h:113
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:37
Interface to the mount program.
Definition: mount.h:75
void umount(const std::string &path)
umount device
Definition: mount.cc:117
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
ExternalProgram::Environment Environment
For passing additional environment variables to mount.
Definition: mount.h:82
std::list< DirEntry > DirContent
Returned by readdir.
Definition: PathInfo.h:518
std::string getShare(Pathname spath_r)
Definition: MediaCIFS.cc:46
zypp::RW_pointer< MediaSource > MediaSourceRef
Definition: MediaSource.h:124
shared_ptr< AuthData > AuthData_Ptr
Definition: authdata.h:79
Pathname stripShare(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:36
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
A map of (key,value) strings.
Definition: kvmap.h:173
std::string asString() const
Definition: kvmap.h:189
bool has(const std::string &key_r) const
Test whether key is set.
Definition: kvmap.h:97
A simple structure containing references to a media source and its attach point.
Definition: MediaSource.h:134
MediaSourceRef mediaSource
Definition: MediaSource.h:144
AttachPointRef attachPoint
Definition: MediaSource.h:145
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition: Exception.h:440
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:436
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:428
#define _(MSG)
Definition: Gettext.h:37
#define DBG
Definition: Logger.h:95
#define MIL
Definition: Logger.h:96