diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index f6d16b2af047c..f84f722506a18 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -19865,7 +19865,49 @@ msgctxt "#36620"
msgid "Enable high quality downscaling of pictures (uses more memory and has moderate performance impact)."
msgstr ""
-#empty strings from id 36621 to 36899
+#. Label of a setting, allow the maximum smbclient protocol to be configured
+#: system/settings/settings.xml
+msgctxt "#36621"
+msgid "Maximum protocol version"
+msgstr ""
+
+#. Description of setting with label #36621 "Maximum protocol version"
+#: system/settings/settings.xml
+msgctxt "#36622"
+msgid "Set the maximum SMB protocol version to negotiate when making connections. Forcing SMBv2 or SMBv1 compatibility may be required with older NAS and Windows shares."
+msgstr ""
+
+#. Values for setting with label #36621 "Maximum protocol version" - none means "no protocol version is forced"
+#: system/settings/settings.xml
+msgctxt "#36623"
+msgid "None"
+msgstr ""
+
+#. Values for setting with label #36621 "Maximum protocol version"
+#: system/settings/settings.xml
+msgctxt "#36624"
+msgid "SMBv1"
+msgstr ""
+
+#. Values for setting with label #36621 "Maximum protocol version"
+#: system/settings/settings.xml
+msgctxt "#36625"
+msgid "SMBv2"
+msgstr ""
+
+#. Values for setting with label #36621 "Maximum protocol version"
+#: system/settings/settings.xml
+msgctxt "#36626"
+msgid "SMBv3"
+msgstr ""
+
+#. Label of a group, that allows configuration of the system SMB client
+#: system/settings/settings.xml
+msgctxt "#36627"
+msgid "Client"
+msgstr ""
+
+#empty strings from id 36628 to 36899
#: xbmc/media/MediaType.cpp
msgctxt "#36900"
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index ff62c05c7d2f0..c5b75215d02d1 100755
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -1921,15 +1921,30 @@
HAS_FILESYSTEM_SMB
+
+ 2
+ WORKGROUP
+
+
+
+
2
0.0.0.0
-
+
2
- WORKGROUP
-
+ 3
+
+
+
+
+
+
+
+
+
diff --git a/xbmc/filesystem/SMBFile.cpp b/xbmc/filesystem/SMBFile.cpp
index 99d1590ef3dea..a6c8f5d47f460 100644
--- a/xbmc/filesystem/SMBFile.cpp
+++ b/xbmc/filesystem/SMBFile.cpp
@@ -28,6 +28,7 @@
#include "ServiceBroker.h"
#include "SMBDirectory.h"
#include
+#include "filesystem/SpecialProtocol.h"
#include "settings/AdvancedSettings.h"
#include "settings/Settings.h"
#include "threads/SingleLock.h"
@@ -92,33 +93,39 @@ void CSMB::Deinit()
void CSMB::Init()
{
CSingleLock lock(*this);
+
if (!m_context)
{
- // Create ~/.smb/smb.conf. This file is used by libsmbclient.
+ // force libsmbclient to use our own smb.conf by overriding HOME
+ std::string truehome(getenv("HOME"));
+ setenv("HOME", CSpecialProtocol::TranslatePath("special://home").c_str(), 1);
+
+ // Create ~/.kodi/.smb/smb.conf. This file is used by libsmbclient.
// http://us1.samba.org/samba/docs/man/manpages-3/libsmbclient.7.html
// http://us1.samba.org/samba/docs/man/manpages-3/smb.conf.5.html
- char smb_conf[MAX_PATH];
+ std::string smb_conf;
std::string home(getenv("HOME"));
URIUtils::RemoveSlashAtEnd(home);
- snprintf(smb_conf, sizeof(smb_conf), "%s/.smb", home.c_str());
- if (mkdir(smb_conf, 0755) == 0)
+ smb_conf = home + "/.smb";
+ int result = mkdir(smb_conf.c_str(), 0755);
+ if (result == 0 || (errno == EEXIST && IsFirstInit))
{
- snprintf(smb_conf, sizeof(smb_conf), "%s/.smb/smb.conf", getenv("HOME"));
- FILE* f = fopen(smb_conf, "w");
+ smb_conf += "/smb.conf";
+ FILE* f = fopen(smb_conf.c_str(), "w");
if (f != NULL)
{
fprintf(f, "[global]\n");
- // make sure we're not acting like a server
- fprintf(f, "\tpreferred master = no\n");
- fprintf(f, "\tlocal master = no\n");
- fprintf(f, "\tdomain master = no\n");
-
- // use the weaker LANMAN password hash in order to be compatible with older servers
- fprintf(f, "\tclient lanman auth = yes\n");
- fprintf(f, "\tlanman auth = yes\n");
+ fprintf(f, "\tlock directory = %s/.smb/\n", home.c_str());
- fprintf(f, "\tlock directory = %s/.smb/\n", getenv("HOME"));
+ // set maximum smbclient protocol version
+ if (CServiceBroker::GetSettings().GetInt(CSettings::SETTING_SMB_MAXPROTOCOL) > 0)
+ {
+ if (CServiceBroker::GetSettings().GetInt(CSettings::SETTING_SMB_MAXPROTOCOL) == 1)
+ fprintf(f, "\tclient max protocol = NT1\n");
+ else
+ fprintf(f, "\tclient max protocol = SMB%d\n", CServiceBroker::GetSettings().GetInt(CSettings::SETTING_SMB_MAXPROTOCOL));
+ }
// set wins server if there's one. name resolve order defaults to 'lmhosts host wins bcast'.
// if no WINS server has been specified the wins method will be ignored.
@@ -135,6 +142,9 @@ void CSMB::Init()
if (g_advancedSettings.m_sambadoscodepage.length() > 0)
fprintf(f, "\tdos charset = %s\n", g_advancedSettings.m_sambadoscodepage.c_str());
+ // include users configuration if available
+ fprintf(f, "\tinclude = %s/.smb/user.conf\n", home.c_str());
+
fclose(f);
}
}
@@ -151,6 +161,10 @@ void CSMB::Init()
// setup our context
m_context = smbc_new_context();
+
+ // restore HOME
+ setenv("HOME", truehome.c_str(), 1);
+
#ifdef DEPRECATED_SMBC_INTERFACE
smbc_setDebug(m_context, g_advancedSettings.CanLogComponent(LOGSAMBA) ? 10 : 0);
smbc_setFunctionAuthData(m_context, xb_smbc_auth);
@@ -647,3 +661,4 @@ int CSMBFile::IoControl(EIoControl request, void* param)
return -1;
}
+
diff --git a/xbmc/network/NetworkServices.cpp b/xbmc/network/NetworkServices.cpp
index 95ca6559cc1ed..bb5f2c7f753c3 100644
--- a/xbmc/network/NetworkServices.cpp
+++ b/xbmc/network/NetworkServices.cpp
@@ -118,6 +118,7 @@ CNetworkServices::CNetworkServices()
, m_httpWebinterfaceAddonsHandler(*new CHTTPWebinterfaceAddonsHandler)
#endif // HAS_WEB_INTERFACE
#endif // HAS_WEB_SERVER
+
{
#ifdef HAS_WEB_SERVER
m_webserver.RegisterRequestHandler(&m_httpImageHandler);
@@ -456,7 +457,8 @@ void CNetworkServices::OnSettingChanged(std::shared_ptr setting)
else
#endif // HAS_WEB_SERVER
if (settingId == CSettings::SETTING_SMB_WINSSERVER ||
- settingId == CSettings::SETTING_SMB_WORKGROUP)
+ settingId == CSettings::SETTING_SMB_WORKGROUP ||
+ settingId == CSettings::SETTING_SMB_MAXPROTOCOL)
{
// okey we really don't need to restart, only deinit samba, but that could be damn hard if something is playing
//! @todo - General way of handling setting changes that require restart
diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp
index a6636cc1e452a..6c3f1d3180ede 100644
--- a/xbmc/settings/Settings.cpp
+++ b/xbmc/settings/Settings.cpp
@@ -332,6 +332,7 @@ const std::string CSettings::SETTING_SERVICES_AIRPLAYPASSWORD = "services.airpla
const std::string CSettings::SETTING_SERVICES_AIRPLAYVIDEOSUPPORT = "services.airplayvideosupport";
const std::string CSettings::SETTING_SMB_WINSSERVER = "smb.winsserver";
const std::string CSettings::SETTING_SMB_WORKGROUP = "smb.workgroup";
+const std::string CSettings::SETTING_SMB_MAXPROTOCOL = "smb.maxprotocol";
const std::string CSettings::SETTING_VIDEOSCREEN_MONITOR = "videoscreen.monitor";
const std::string CSettings::SETTING_VIDEOSCREEN_SCREEN = "videoscreen.screen";
const std::string CSettings::SETTING_VIDEOSCREEN_RESOLUTION = "videoscreen.resolution";
@@ -990,6 +991,7 @@ void CSettings::InitializeISettingCallbacks()
settingSet.insert(CSettings::SETTING_SERVICES_ESCONTINUOUSDELAY);
settingSet.insert(CSettings::SETTING_SMB_WINSSERVER);
settingSet.insert(CSettings::SETTING_SMB_WORKGROUP);
+ settingSet.insert(CSettings::SETTING_SMB_MAXPROTOCOL);
GetSettingsManager()->RegisterCallback(&CNetworkServices::GetInstance(), settingSet);
settingSet.clear();
diff --git a/xbmc/settings/Settings.h b/xbmc/settings/Settings.h
index 919321aec4415..200606e477cb6 100644
--- a/xbmc/settings/Settings.h
+++ b/xbmc/settings/Settings.h
@@ -278,6 +278,7 @@ class CSettings : public CSettingsBase, public CSettingCreator, public CSettingC
static const std::string SETTING_SERVICES_AIRPLAYVIDEOSUPPORT;
static const std::string SETTING_SMB_WINSSERVER;
static const std::string SETTING_SMB_WORKGROUP;
+ static const std::string SETTING_SMB_MAXPROTOCOL;
static const std::string SETTING_VIDEOSCREEN_MONITOR;
static const std::string SETTING_VIDEOSCREEN_SCREEN;
static const std::string SETTING_VIDEOSCREEN_RESOLUTION;