From 9a766f4cd98feb9edbce522ddcf48b54c6a4e663 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 14 Oct 2021 14:16:34 +0200 Subject: [PATCH] Permission: split permission "player" from "control" Some users want certain clients to fully control playback, but do not want them to be able to trigger database update. Closes https://github.com/MusicPlayerDaemon/MPD/issues/1124 --- NEWS | 1 + doc/user.rst | 3 ++ src/Permission.cxx | 6 ++++ src/Permission.hxx | 1 + src/command/AllCommands.cxx | 60 ++++++++++++++++++------------------- 5 files changed, 41 insertions(+), 30 deletions(-) diff --git a/NEWS b/NEWS index 1579d0e0f..b85d12751 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,7 @@ ver 0.23 (not yet released) - snapcast: new plugin * tags - new tags "ComposerSort", "Ensemble", "Movement", "MovementNumber", and "Location" +* split permission "player" from "control" * new build-time dependency: libfmt ver 0.22.11 (2021/08/24) diff --git a/doc/user.rst b/doc/user.rst index a3d318102..4b26ff192 100644 --- a/doc/user.rst +++ b/doc/user.rst @@ -639,6 +639,9 @@ By default, all clients are unauthenticated and have a full set of permissions. - Allows reading of the database, displaying the current playlist, and current status of :program:`MPD`. * - **add** - Allows adding songs and loading playlists. + * - **player** + - Allows any player and queue manipulation (start/pause/stop + playback etc.). * - **control** - Allows all other player and playlist manipulations. * - **admin** diff --git a/src/Permission.cxx b/src/Permission.cxx index f04bef042..a76feb195 100644 --- a/src/Permission.cxx +++ b/src/Permission.cxx @@ -41,6 +41,7 @@ static constexpr struct { } permission_names[] = { { "read", PERMISSION_READ }, { "add", PERMISSION_ADD }, + { "player", PERMISSION_PLAYER }, { "control", PERMISSION_CONTROL }, { "admin", PERMISSION_ADMIN }, { nullptr, 0 }, @@ -75,6 +76,11 @@ static unsigned parsePermissions(const char *string) if (!i.empty()) permission |= ParsePermission(i); + /* for backwards compatiblity with MPD 0.22 and older, + "control" implies "play" */ + if (permission & PERMISSION_CONTROL) + permission |= PERMISSION_PLAYER; + return permission; } diff --git a/src/Permission.hxx b/src/Permission.hxx index cd333e748..79202cb32 100644 --- a/src/Permission.hxx +++ b/src/Permission.hxx @@ -29,6 +29,7 @@ static constexpr unsigned PERMISSION_READ = 1; static constexpr unsigned PERMISSION_ADD = 2; static constexpr unsigned PERMISSION_CONTROL = 4; static constexpr unsigned PERMISSION_ADMIN = 8; +static constexpr unsigned PERMISSION_PLAYER = 16; int getPermissionFromPassword(const char *password, unsigned *permission) noexcept; diff --git a/src/command/AllCommands.cxx b/src/command/AllCommands.cxx index 2b9b07fdb..f90f696d0 100644 --- a/src/command/AllCommands.cxx +++ b/src/command/AllCommands.cxx @@ -91,21 +91,21 @@ static constexpr struct command commands[] = { { "albumart", PERMISSION_READ, 2, 2, handle_album_art }, { "binarylimit", PERMISSION_NONE, 1, 1, handle_binary_limit }, { "channels", PERMISSION_READ, 0, 0, handle_channels }, - { "clear", PERMISSION_CONTROL, 0, 0, handle_clear }, - { "clearerror", PERMISSION_CONTROL, 0, 0, handle_clearerror }, + { "clear", PERMISSION_PLAYER, 0, 0, handle_clear }, + { "clearerror", PERMISSION_PLAYER, 0, 0, handle_clearerror }, { "cleartagid", PERMISSION_ADD, 1, 2, handle_cleartagid }, { "close", PERMISSION_NONE, -1, -1, handle_close }, { "commands", PERMISSION_NONE, 0, 0, handle_commands }, { "config", PERMISSION_ADMIN, 0, 0, handle_config }, - { "consume", PERMISSION_CONTROL, 1, 1, handle_consume }, + { "consume", PERMISSION_PLAYER, 1, 1, handle_consume }, #ifdef ENABLE_DATABASE { "count", PERMISSION_READ, 1, -1, handle_count }, #endif - { "crossfade", PERMISSION_CONTROL, 1, 1, handle_crossfade }, + { "crossfade", PERMISSION_PLAYER, 1, 1, handle_crossfade }, { "currentsong", PERMISSION_READ, 0, 0, handle_currentsong }, { "decoders", PERMISSION_READ, 0, 0, handle_decoders }, - { "delete", PERMISSION_CONTROL, 1, 1, handle_delete }, - { "deleteid", PERMISSION_CONTROL, 1, 1, handle_deleteid }, + { "delete", PERMISSION_PLAYER, 1, 1, handle_delete }, + { "deleteid", PERMISSION_PLAYER, 1, 1, handle_deleteid }, { "delpartition", PERMISSION_ADMIN, 1, 1, handle_delpartition }, { "disableoutput", PERMISSION_ADMIN, 1, 1, handle_disableoutput }, { "enableoutput", PERMISSION_ADMIN, 1, 1, handle_enableoutput }, @@ -137,25 +137,25 @@ static constexpr struct command commands[] = { { "listplaylists", PERMISSION_READ, 0, 0, handle_listplaylists }, { "load", PERMISSION_ADD, 1, 2, handle_load }, { "lsinfo", PERMISSION_READ, 0, 1, handle_lsinfo }, - { "mixrampdb", PERMISSION_CONTROL, 1, 1, handle_mixrampdb }, - { "mixrampdelay", PERMISSION_CONTROL, 1, 1, handle_mixrampdelay }, + { "mixrampdb", PERMISSION_PLAYER, 1, 1, handle_mixrampdb }, + { "mixrampdelay", PERMISSION_PLAYER, 1, 1, handle_mixrampdelay }, #ifdef ENABLE_DATABASE { "mount", PERMISSION_ADMIN, 2, 2, handle_mount }, #endif - { "move", PERMISSION_CONTROL, 2, 2, handle_move }, - { "moveid", PERMISSION_CONTROL, 2, 2, handle_moveid }, + { "move", PERMISSION_PLAYER, 2, 2, handle_move }, + { "moveid", PERMISSION_PLAYER, 2, 2, handle_moveid }, { "moveoutput", PERMISSION_ADMIN, 1, 1, handle_moveoutput }, { "newpartition", PERMISSION_ADMIN, 1, 1, handle_newpartition }, - { "next", PERMISSION_CONTROL, 0, 0, handle_next }, + { "next", PERMISSION_PLAYER, 0, 0, handle_next }, { "notcommands", PERMISSION_NONE, 0, 0, handle_not_commands }, { "outputs", PERMISSION_READ, 0, 0, handle_devices }, { "outputset", PERMISSION_ADMIN, 3, 3, handle_outputset }, { "partition", PERMISSION_READ, 1, 1, handle_partition }, { "password", PERMISSION_NONE, 1, 1, handle_password }, - { "pause", PERMISSION_CONTROL, 0, 1, handle_pause }, + { "pause", PERMISSION_PLAYER, 0, 1, handle_pause }, { "ping", PERMISSION_NONE, 0, 0, handle_ping }, - { "play", PERMISSION_CONTROL, 0, 1, handle_play }, - { "playid", PERMISSION_CONTROL, 0, 1, handle_playid }, + { "play", PERMISSION_PLAYER, 0, 1, handle_play }, + { "playid", PERMISSION_PLAYER, 0, 1, handle_playid }, { "playlist", PERMISSION_READ, 0, 0, handle_playlist }, { "playlistadd", PERMISSION_CONTROL, 2, 2, handle_playlistadd }, { "playlistclear", PERMISSION_CONTROL, 1, 1, handle_playlistclear }, @@ -167,17 +167,17 @@ static constexpr struct command commands[] = { { "playlistsearch", PERMISSION_READ, 1, -1, handle_playlistsearch }, { "plchanges", PERMISSION_READ, 1, 2, handle_plchanges }, { "plchangesposid", PERMISSION_READ, 1, 2, handle_plchangesposid }, - { "previous", PERMISSION_CONTROL, 0, 0, handle_previous }, - { "prio", PERMISSION_CONTROL, 2, -1, handle_prio }, - { "prioid", PERMISSION_CONTROL, 2, -1, handle_prioid }, - { "random", PERMISSION_CONTROL, 1, 1, handle_random }, + { "previous", PERMISSION_PLAYER, 0, 0, handle_previous }, + { "prio", PERMISSION_PLAYER, 2, -1, handle_prio }, + { "prioid", PERMISSION_PLAYER, 2, -1, handle_prioid }, + { "random", PERMISSION_PLAYER, 1, 1, handle_random }, { "rangeid", PERMISSION_ADD, 2, 2, handle_rangeid }, { "readcomments", PERMISSION_READ, 1, 1, handle_read_comments }, { "readmessages", PERMISSION_READ, 0, 0, handle_read_messages }, { "readpicture", PERMISSION_READ, 2, 2, handle_read_picture }, { "rename", PERMISSION_CONTROL, 2, 2, handle_rename }, - { "repeat", PERMISSION_CONTROL, 1, 1, handle_repeat }, - { "replay_gain_mode", PERMISSION_CONTROL, 1, 1, + { "repeat", PERMISSION_PLAYER, 1, 1, handle_repeat }, + { "replay_gain_mode", PERMISSION_PLAYER, 1, 1, handle_replay_gain_mode }, { "replay_gain_status", PERMISSION_READ, 0, 0, handle_replay_gain_status }, @@ -189,22 +189,22 @@ static constexpr struct command commands[] = { { "searchadd", PERMISSION_ADD, 1, -1, handle_searchadd }, { "searchaddpl", PERMISSION_CONTROL, 2, -1, handle_searchaddpl }, #endif - { "seek", PERMISSION_CONTROL, 2, 2, handle_seek }, - { "seekcur", PERMISSION_CONTROL, 1, 1, handle_seekcur }, - { "seekid", PERMISSION_CONTROL, 2, 2, handle_seekid }, + { "seek", PERMISSION_PLAYER, 2, 2, handle_seek }, + { "seekcur", PERMISSION_PLAYER, 1, 1, handle_seekcur }, + { "seekid", PERMISSION_PLAYER, 2, 2, handle_seekid }, { "sendmessage", PERMISSION_CONTROL, 2, 2, handle_send_message }, - { "setvol", PERMISSION_CONTROL, 1, 1, handle_setvol }, - { "shuffle", PERMISSION_CONTROL, 0, 1, handle_shuffle }, - { "single", PERMISSION_CONTROL, 1, 1, handle_single }, + { "setvol", PERMISSION_PLAYER, 1, 1, handle_setvol }, + { "shuffle", PERMISSION_PLAYER, 0, 1, handle_shuffle }, + { "single", PERMISSION_PLAYER, 1, 1, handle_single }, { "stats", PERMISSION_READ, 0, 0, handle_stats }, { "status", PERMISSION_READ, 0, 0, handle_status }, #ifdef ENABLE_SQLITE { "sticker", PERMISSION_ADMIN, 3, -1, handle_sticker }, #endif - { "stop", PERMISSION_CONTROL, 0, 0, handle_stop }, + { "stop", PERMISSION_PLAYER, 0, 0, handle_stop }, { "subscribe", PERMISSION_READ, 1, 1, handle_subscribe }, - { "swap", PERMISSION_CONTROL, 2, 2, handle_swap }, - { "swapid", PERMISSION_CONTROL, 2, 2, handle_swapid }, + { "swap", PERMISSION_PLAYER, 2, 2, handle_swap }, + { "swapid", PERMISSION_PLAYER, 2, 2, handle_swapid }, { "tagtypes", PERMISSION_NONE, 0, -1, handle_tagtypes }, { "toggleoutput", PERMISSION_ADMIN, 1, 1, handle_toggleoutput }, #ifdef ENABLE_DATABASE @@ -213,7 +213,7 @@ static constexpr struct command commands[] = { { "unsubscribe", PERMISSION_READ, 1, 1, handle_unsubscribe }, { "update", PERMISSION_CONTROL, 0, 1, handle_update }, { "urlhandlers", PERMISSION_READ, 0, 0, handle_urlhandlers }, - { "volume", PERMISSION_CONTROL, 1, 1, handle_volume }, + { "volume", PERMISSION_PLAYER, 1, 1, handle_volume }, }; static constexpr unsigned num_commands = std::size(commands);