Permission.cxx 4.4 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright 2003-2021 The Music Player Daemon Project
3
 * http://www.musicpd.org
4 5 6 7 8 9 10 11 12 13
 *
 * 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.
14 15 16 17
 *
 * 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.
18 19
 */

20
#include "config.h"
21
#include "Permission.hxx"
22
#include "config/Param.hxx"
23
#include "config/Data.hxx"
24
#include "config/Option.hxx"
25 26 27
#include "net/AddressInfo.hxx"
#include "net/Resolver.hxx"
#include "net/ToString.hxx"
28
#include "util/IterableSplitString.hxx"
29
#include "util/RuntimeError.hxx"
30
#include "util/StringView.hxx"
31

32
#include <cassert>
33 34
#include <map>
#include <string>
35
#include <utility>
36

37
static constexpr char PERMISSION_PASSWORD_CHAR = '@';
38
static constexpr char PERMISSION_SEPARATOR = ',';
Warren Dukes's avatar
Warren Dukes committed
39

40 41 42 43 44 45
static constexpr struct {
	const char *name;
	unsigned value;
} permission_names[] = {
	{ "read", PERMISSION_READ },
	{ "add", PERMISSION_ADD },
46
	{ "player", PERMISSION_PLAYER },
47 48 49 50
	{ "control", PERMISSION_CONTROL },
	{ "admin", PERMISSION_ADMIN },
	{ nullptr, 0 },
};
Warren Dukes's avatar
Warren Dukes committed
51

52
static std::map<std::string, unsigned> permission_passwords;
Warren Dukes's avatar
Warren Dukes committed
53

54
static unsigned permission_default;
Warren Dukes's avatar
Warren Dukes committed
55

56 57 58 59
#ifdef HAVE_UN
static unsigned local_permissions;
#endif

60 61 62 63
#ifdef HAVE_TCP
static std::map<std::string, unsigned> host_passwords;
#endif

64
static unsigned
65
ParsePermission(StringView s)
66 67
{
	for (auto i = permission_names; i->name != nullptr; ++i)
68
		if (s.Equals(i->name))
69 70
			return i->value;

71 72
	throw FormatRuntimeError("unknown permission \"%.*s\"",
				 int(s.size), s.data);
73 74
}

75 76
static unsigned
parsePermissions(std::string_view string)
Avuton Olrich's avatar
Avuton Olrich committed
77
{
78
	unsigned permission = 0;
79 80 81 82

	for (const auto i : IterableSplitString(string, PERMISSION_SEPARATOR))
		if (!i.empty())
			permission |= ParsePermission(i);
Warren Dukes's avatar
Warren Dukes committed
83

84 85 86 87 88
	/* for backwards compatiblity with MPD 0.22 and older,
	   "control" implies "play" */
	if (permission & PERMISSION_CONTROL)
		permission |= PERMISSION_PLAYER;

Warren Dukes's avatar
Warren Dukes committed
89 90 91
	return permission;
}

92 93
void
initPermissions(const ConfigData &config)
Avuton Olrich's avatar
Avuton Olrich committed
94 95
{
	permission_default = PERMISSION_READ | PERMISSION_ADD |
96
		PERMISSION_PLAYER |
Avuton Olrich's avatar
Avuton Olrich committed
97
	    PERMISSION_CONTROL | PERMISSION_ADMIN;
Warren Dukes's avatar
Warren Dukes committed
98

99
	for (const auto &param : config.GetParamList(ConfigOption::PASSWORD)) {
Avuton Olrich's avatar
Avuton Olrich committed
100
		permission_default = 0;
Warren Dukes's avatar
Warren Dukes committed
101

102 103 104 105
		param.With([](const StringView value){
			const auto [password, permissions] =
				value.Split(PERMISSION_PASSWORD_CHAR);
			if (permissions == nullptr)
106 107
				throw FormatRuntimeError("\"%c\" not found in password string",
							 PERMISSION_PASSWORD_CHAR);
Warren Dukes's avatar
Warren Dukes committed
108

109 110
			permission_passwords.emplace(password,
						     parsePermissions(permissions));
111
		});
Warren Dukes's avatar
Warren Dukes committed
112 113
	}

114 115 116 117
	config.With(ConfigOption::DEFAULT_PERMS, [](const char *value){
		if (value != nullptr)
			permission_default = parsePermissions(value);
	});
118 119

#ifdef HAVE_UN
120 121 122 123 124
	local_permissions = config.With(ConfigOption::LOCAL_PERMISSIONS, [](const char *value){
		return value != nullptr
			? parsePermissions(value)
			: permission_default;
	});
125
#endif
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155

#ifdef HAVE_TCP
	for (const auto &param : 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;
Warren Dukes's avatar
Warren Dukes committed
156 157
}

158 159
#endif

160 161
std::optional<unsigned>
GetPermissionFromPassword(const char *password) noexcept
Avuton Olrich's avatar
Avuton Olrich committed
162
{
163 164
	auto i = permission_passwords.find(password);
	if (i == permission_passwords.end())
165
		return std::nullopt;
Warren Dukes's avatar
Warren Dukes committed
166

167
	return i->second;
Warren Dukes's avatar
Warren Dukes committed
168 169
}

170 171
unsigned
getDefaultPermissions() noexcept
Avuton Olrich's avatar
Avuton Olrich committed
172
{
Warren Dukes's avatar
Warren Dukes committed
173 174
	return permission_default;
}
175 176 177 178 179 180 181 182 183 184

#ifdef HAVE_UN

unsigned
GetLocalPermissions() noexcept
{
	return local_permissions;
}

#endif