Commit c8f0c7e9 authored by Max Kellermann's avatar Max Kellermann

*/smbclient: protect all libsmbclient calls with a mutex

libsmbclient is not thread-safe nor reentrant. We must protect all function calls with a global mutex, unfortunately.
parent a7989077
...@@ -415,6 +415,7 @@ libfs_a_SOURCES = \ ...@@ -415,6 +415,7 @@ libfs_a_SOURCES = \
SMBCLIENT_SOURCES = \ SMBCLIENT_SOURCES = \
src/lib/smbclient/Domain.cxx src/lib/smbclient/Domain.hxx \ src/lib/smbclient/Domain.cxx src/lib/smbclient/Domain.hxx \
src/lib/smbclient/Mutex.cxx src/lib/smbclient/Mutex.hxx \
src/lib/smbclient/Init.cxx src/lib/smbclient/Init.hxx src/lib/smbclient/Init.cxx src/lib/smbclient/Init.hxx
if ENABLE_DATABASE if ENABLE_DATABASE
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "config.h" #include "config.h"
#include "SmbclientInputPlugin.hxx" #include "SmbclientInputPlugin.hxx"
#include "lib/smbclient/Init.hxx" #include "lib/smbclient/Init.hxx"
#include "lib/smbclient/Mutex.hxx"
#include "../InputStream.hxx" #include "../InputStream.hxx"
#include "../InputPlugin.hxx" #include "../InputPlugin.hxx"
#include "util/StringUtil.hxx" #include "util/StringUtil.hxx"
...@@ -45,8 +46,10 @@ public: ...@@ -45,8 +46,10 @@ public:
} }
~SmbclientInputStream() { ~SmbclientInputStream() {
smbclient_mutex.lock();
smbc_close(fd); smbc_close(fd);
smbc_free_context(ctx, 1); smbc_free_context(ctx, 1);
smbclient_mutex.unlock();
} }
InputStream *GetBase() { InputStream *GetBase() {
...@@ -58,7 +61,9 @@ public: ...@@ -58,7 +61,9 @@ public:
} }
size_t Read(void *ptr, size_t size, Error &error) { size_t Read(void *ptr, size_t size, Error &error) {
smbclient_mutex.lock();
ssize_t nbytes = smbc_read(fd, ptr, size); ssize_t nbytes = smbc_read(fd, ptr, size);
smbclient_mutex.unlock();
if (nbytes < 0) { if (nbytes < 0) {
error.SetErrno("smbc_read() failed"); error.SetErrno("smbc_read() failed");
nbytes = 0; nbytes = 0;
...@@ -68,7 +73,9 @@ public: ...@@ -68,7 +73,9 @@ public:
} }
bool Seek(InputStream::offset_type offset, int whence, Error &error) { bool Seek(InputStream::offset_type offset, int whence, Error &error) {
smbclient_mutex.lock();
off_t result = smbc_lseek(fd, offset, whence); off_t result = smbc_lseek(fd, offset, whence);
smbclient_mutex.unlock();
if (result < 0) { if (result < 0) {
error.SetErrno("smbc_lseek() failed"); error.SetErrno("smbc_lseek() failed");
return false; return false;
...@@ -105,6 +112,8 @@ input_smbclient_open(const char *uri, ...@@ -105,6 +112,8 @@ input_smbclient_open(const char *uri,
if (!StringStartsWith(uri, "smb://")) if (!StringStartsWith(uri, "smb://"))
return nullptr; return nullptr;
const ScopeLock protect(smbclient_mutex);
SMBCCTX *ctx = smbc_new_context(); SMBCCTX *ctx = smbc_new_context();
if (ctx == nullptr) { if (ctx == nullptr) {
error.SetErrno("smbc_new_context() failed"); error.SetErrno("smbc_new_context() failed");
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include "config.h" #include "config.h"
#include "Init.hxx" #include "Init.hxx"
#include "Mutex.hxx"
#include "thread/Mutex.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include <libsmbclient.h> #include <libsmbclient.h>
...@@ -41,6 +43,8 @@ mpd_smbc_get_auth_data(gcc_unused const char *srv, ...@@ -41,6 +43,8 @@ mpd_smbc_get_auth_data(gcc_unused const char *srv,
bool bool
SmbclientInit(Error &error) SmbclientInit(Error &error)
{ {
const ScopeLock protect(smbclient_mutex);
constexpr int debug = 0; constexpr int debug = 0;
if (smbc_init(mpd_smbc_get_auth_data, debug) < 0) { if (smbc_init(mpd_smbc_get_auth_data, debug) < 0) {
error.SetErrno("smbc_init() failed"); error.SetErrno("smbc_init() failed");
......
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "Mutex.hxx"
#include "thread/Mutex.hxx"
Mutex smbclient_mutex;
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_SMBCLIENT_MUTEX_HXX
#define MPD_SMBCLIENT_MUTEX_HXX
class Mutex;
/**
* Since libsmbclient is not thread-safe, this mutex must be locked
* during all libsmbclient function calls.
*/
extern Mutex smbclient_mutex;
#endif
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "SmbclientNeighborPlugin.hxx" #include "SmbclientNeighborPlugin.hxx"
#include "lib/smbclient/Init.hxx" #include "lib/smbclient/Init.hxx"
#include "lib/smbclient/Domain.hxx" #include "lib/smbclient/Domain.hxx"
#include "lib/smbclient/Mutex.hxx"
#include "neighbor/NeighborPlugin.hxx" #include "neighbor/NeighborPlugin.hxx"
#include "neighbor/Explorer.hxx" #include "neighbor/Explorer.hxx"
#include "neighbor/Listener.hxx" #include "neighbor/Listener.hxx"
...@@ -175,6 +176,7 @@ static NeighborExplorer::List ...@@ -175,6 +176,7 @@ static NeighborExplorer::List
DetectServers() DetectServers()
{ {
NeighborExplorer::List list; NeighborExplorer::List list;
const ScopeLock protect(smbclient_mutex);
ReadServers(list, "smb://"); ReadServers(list, "smb://");
return list; return list;
} }
......
...@@ -22,7 +22,9 @@ ...@@ -22,7 +22,9 @@
#include "storage/StorageInterface.hxx" #include "storage/StorageInterface.hxx"
#include "storage/FileInfo.hxx" #include "storage/FileInfo.hxx"
#include "lib/smbclient/Init.hxx" #include "lib/smbclient/Init.hxx"
#include "lib/smbclient/Mutex.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "thread/Mutex.hxx"
#include <libsmbclient.h> #include <libsmbclient.h>
...@@ -54,7 +56,9 @@ public: ...@@ -54,7 +56,9 @@ public:
:base(_base), ctx(_ctx) {} :base(_base), ctx(_ctx) {}
virtual ~SmbclientStorage() { virtual ~SmbclientStorage() {
smbclient_mutex.lock();
smbc_free_context(ctx, 1); smbc_free_context(ctx, 1);
smbclient_mutex.unlock();
} }
/* virtual methods from class Storage */ /* virtual methods from class Storage */
...@@ -82,7 +86,10 @@ static bool ...@@ -82,7 +86,10 @@ static bool
GetInfo(const char *path, FileInfo &info, Error &error) GetInfo(const char *path, FileInfo &info, Error &error)
{ {
struct stat st; struct stat st;
if (smbc_stat(path, &st) < 0) { smbclient_mutex.lock();
bool success = smbc_stat(path, &st) == 0;
smbclient_mutex.unlock();
if (!success) {
error.SetErrno(); error.SetErrno();
return false; return false;
} }
...@@ -113,7 +120,9 @@ StorageDirectoryReader * ...@@ -113,7 +120,9 @@ StorageDirectoryReader *
SmbclientStorage::OpenDirectory(const char *uri_utf8, Error &error) SmbclientStorage::OpenDirectory(const char *uri_utf8, Error &error)
{ {
std::string mapped = MapUTF8(uri_utf8); std::string mapped = MapUTF8(uri_utf8);
smbclient_mutex.lock();
int handle = smbc_opendir(mapped.c_str()); int handle = smbc_opendir(mapped.c_str());
smbclient_mutex.unlock();
if (handle < 0) { if (handle < 0) {
error.SetErrno(); error.SetErrno();
return nullptr; return nullptr;
...@@ -133,12 +142,16 @@ SkipNameFS(const char *name) ...@@ -133,12 +142,16 @@ SkipNameFS(const char *name)
SmbclientDirectoryReader::~SmbclientDirectoryReader() SmbclientDirectoryReader::~SmbclientDirectoryReader()
{ {
smbclient_mutex.lock();
smbc_close(handle); smbc_close(handle);
smbclient_mutex.unlock();
} }
const char * const char *
SmbclientDirectoryReader::Read() SmbclientDirectoryReader::Read()
{ {
const ScopeLock protect(smbclient_mutex);
struct smbc_dirent *e; struct smbc_dirent *e;
while ((e = smbc_readdir(handle)) != nullptr) { while ((e = smbc_readdir(handle)) != nullptr) {
name = e->name; name = e->name;
...@@ -163,6 +176,7 @@ CreateSmbclientStorage(const char *base, Error &error) ...@@ -163,6 +176,7 @@ CreateSmbclientStorage(const char *base, Error &error)
if (!SmbclientInit(error)) if (!SmbclientInit(error))
return nullptr; return nullptr;
const ScopeLock protect(smbclient_mutex);
SMBCCTX *ctx = smbc_new_context(); SMBCCTX *ctx = smbc_new_context();
if (ctx == nullptr) { if (ctx == nullptr) {
error.SetErrno("smbc_new_context() failed"); error.SetErrno("smbc_new_context() failed");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment