Permission: add option "host_permissions"
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1115
This commit is contained in:
parent
a636d2127a
commit
77d74b404e
1
NEWS
1
NEWS
|
@ -25,6 +25,7 @@ ver 0.23 (not yet released)
|
|||
* tags
|
||||
- new tags "ComposerSort", "Ensemble", "Movement", "MovementNumber", and "Location"
|
||||
* split permission "player" from "control"
|
||||
* add option "host_permissions"
|
||||
* new build-time dependency: libfmt
|
||||
|
||||
ver 0.22.11 (2021/08/24)
|
||||
|
|
|
@ -650,6 +650,9 @@ By default, all clients are unauthenticated and have a full set of permissions.
|
|||
|
||||
:code:`local_permissions` may be used to assign other permissions to clients connecting on a local socket.
|
||||
|
||||
:code:`host_permissions` may be used to assign permissions to clients
|
||||
with a certain IP address.
|
||||
|
||||
:code:`password` allows the client to send a password to gain other permissions. This option may be specified multiple times with different passwords.
|
||||
|
||||
Note that the :code:`password` option is not secure: passwords are sent in clear-text over the connection, and the client cannot verify the server's identity.
|
||||
|
@ -659,6 +662,8 @@ Example:
|
|||
.. code-block:: none
|
||||
|
||||
default_permissions "read"
|
||||
host_permissions "192.168.0.100 read,add,control,admin"
|
||||
host_permissions "2003:1234:4567::1 read,add,control,admin"
|
||||
password "the_password@read,add,control"
|
||||
password "the_admin_password@read,add,control,admin"
|
||||
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#include "config/Param.hxx"
|
||||
#include "config/Data.hxx"
|
||||
#include "config/Option.hxx"
|
||||
#include "net/AddressInfo.hxx"
|
||||
#include "net/Resolver.hxx"
|
||||
#include "net/ToString.hxx"
|
||||
#include "util/IterableSplitString.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/StringView.hxx"
|
||||
|
@ -55,6 +58,10 @@ static unsigned permission_default;
|
|||
static unsigned local_permissions;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TCP
|
||||
static std::map<std::string, unsigned> host_passwords;
|
||||
#endif
|
||||
|
||||
static unsigned
|
||||
ParsePermission(StringView s)
|
||||
{
|
||||
|
@ -66,10 +73,9 @@ ParsePermission(StringView s)
|
|||
int(s.size), s.data);
|
||||
}
|
||||
|
||||
static unsigned parsePermissions(const char *string)
|
||||
static unsigned
|
||||
parsePermissions(std::string_view string)
|
||||
{
|
||||
assert(string != nullptr);
|
||||
|
||||
unsigned permission = 0;
|
||||
|
||||
for (const auto i : IterableSplitString(string, PERMISSION_SEPARATOR))
|
||||
|
@ -120,8 +126,40 @@ initPermissions(const ConfigData &config)
|
|||
: permission_default;
|
||||
});
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TCP
|
||||
for (const auto ¶m : config.GetParamList(ConfigOption::HOST_PERMISSIONS)) {
|
||||
permission_default = 0;
|
||||
|
||||
param.With([](StringView value){
|
||||
auto [host_sv, permissions_s] = value.Split(' ');
|
||||
unsigned permissions = parsePermissions(permissions_s);
|
||||
|
||||
const std::string host_s{host_sv};
|
||||
|
||||
for (const auto &i : Resolve(host_s.c_str(), 0,
|
||||
AI_PASSIVE, SOCK_STREAM))
|
||||
host_passwords.emplace(HostToString(i),
|
||||
permissions);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_TCP
|
||||
|
||||
int
|
||||
GetPermissionsFromAddress(SocketAddress address) noexcept
|
||||
{
|
||||
if (auto i = host_passwords.find(HostToString(address));
|
||||
i != host_passwords.end())
|
||||
return i->second;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int
|
||||
getPermissionFromPassword(const char *password, unsigned *permission) noexcept
|
||||
{
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "config.h"
|
||||
|
||||
struct ConfigData;
|
||||
class SocketAddress;
|
||||
|
||||
static constexpr unsigned PERMISSION_NONE = 0;
|
||||
static constexpr unsigned PERMISSION_READ = 1;
|
||||
|
@ -45,6 +46,12 @@ unsigned
|
|||
GetLocalPermissions() noexcept;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TCP
|
||||
[[gnu::pure]]
|
||||
int
|
||||
GetPermissionsFromAddress(SocketAddress address) noexcept;
|
||||
#endif
|
||||
|
||||
void
|
||||
initPermissions(const ConfigData &config);
|
||||
|
||||
|
|
|
@ -32,8 +32,12 @@ GetPermissions(SocketAddress address, int uid) noexcept
|
|||
#ifdef HAVE_UN
|
||||
if (address.GetFamily() == AF_LOCAL)
|
||||
return GetLocalPermissions();
|
||||
#else
|
||||
(void)address;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TCP
|
||||
if (int permissions = GetPermissionsFromAddress(address);
|
||||
permissions >= 0)
|
||||
return permissions;
|
||||
#endif
|
||||
|
||||
return getDefaultPermissions();
|
||||
|
|
|
@ -48,6 +48,7 @@ enum class ConfigOption {
|
|||
ZEROCONF_NAME,
|
||||
ZEROCONF_ENABLED,
|
||||
PASSWORD,
|
||||
HOST_PERMISSIONS,
|
||||
LOCAL_PERMISSIONS,
|
||||
DEFAULT_PERMS,
|
||||
AUDIO_OUTPUT_FORMAT,
|
||||
|
|
|
@ -44,6 +44,7 @@ const ConfigTemplate config_param_templates[] = {
|
|||
{ "zeroconf_name" },
|
||||
{ "zeroconf_enabled" },
|
||||
{ "password", true },
|
||||
{ "host_permissions", true },
|
||||
{ "local_permissions" },
|
||||
{ "default_permissions" },
|
||||
{ "audio_output_format" },
|
||||
|
|
|
@ -116,3 +116,32 @@ ToString(SocketAddress address) noexcept
|
|||
result.append(serv);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string
|
||||
HostToString(SocketAddress address) noexcept
|
||||
{
|
||||
if (address.IsNull())
|
||||
return "null";
|
||||
|
||||
#ifdef HAVE_UN
|
||||
if (address.GetFamily() == AF_LOCAL)
|
||||
/* return path of local socket */
|
||||
return LocalAddressToString(address.CastTo<struct sockaddr_un>(),
|
||||
address.GetSize());
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_IPV6) && defined(IN6_IS_ADDR_V4MAPPED)
|
||||
IPv4Address ipv4_buffer;
|
||||
if (address.IsV4Mapped())
|
||||
address = ipv4_buffer = address.UnmapV4();
|
||||
#endif
|
||||
|
||||
char host[NI_MAXHOST], serv[NI_MAXSERV];
|
||||
int ret = getnameinfo(address.GetAddress(), address.GetSize(),
|
||||
host, sizeof(host), serv, sizeof(serv),
|
||||
NI_NUMERICHOST|NI_NUMERICSERV);
|
||||
if (ret != 0)
|
||||
return "unknown";
|
||||
|
||||
return host;
|
||||
}
|
||||
|
|
|
@ -42,4 +42,12 @@ class SocketAddress;
|
|||
std::string
|
||||
ToString(SocketAddress address) noexcept;
|
||||
|
||||
/**
|
||||
* Generates the string representation of a #SocketAddress into the
|
||||
* specified buffer, without the port number.
|
||||
*/
|
||||
[[gnu::pure]]
|
||||
std::string
|
||||
HostToString(SocketAddress address) noexcept;
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue