3 Copyright (C) 2013 PilzAdam <pilzadam@minetest.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "lua_api/l_settings.h"
21 #include "lua_api/l_internal.h"
22 #include "cpp_api/s_security.h"
23 #include "threading/mutex_auto_lock.h"
24 #include "util/string.h" // FlagDesc
30 /* This protects the following from being set:
32 * some security-relevant settings
33 * (better solution pending)
34 * some mapgen settings
35 * (not security-criticial, just to avoid messing up user configs)
37 #define CHECK_SETTING_SECURITY(L, name) \
38 if (o->m_settings == g_settings) { \
39 if (checkSettingSecurity(L, name) == -1) \
43 static inline int checkSettingSecurity(lua_State* L, const std::string &name)
45 if (ScriptApiSecurity::isSecure(L) && name.compare(0, 7, "secure.") == 0)
46 throw LuaError("Attempted to set secure setting.");
48 bool is_mainmenu = false;
50 is_mainmenu = ModApiBase::getGuiEngine(L) != nullptr;
52 if (!is_mainmenu && (name == "mg_name" || name == "mg_flags")) {
53 errorstream << "Tried to set global setting " << name << ", ignoring. "
54 "minetest.set_mapgen_setting() should be used instead." << std::endl;
55 infostream << script_get_backtrace(L) << std::endl;
59 const char *disallowed[] = {
60 "main_menu_script", "shader_path", "texture_path", "screenshot_path",
61 "serverlist_file", "serverlist_url", "map-dir", "contentdb_url",
64 for (const char *name2 : disallowed) {
66 throw LuaError("Attempted to set disallowed setting.");
73 LuaSettings::LuaSettings(Settings *settings, const std::string &filename) :
79 LuaSettings::LuaSettings(const std::string &filename, bool write_allowed) :
81 m_is_own_settings(true),
82 m_write_allowed(write_allowed)
84 m_settings = new Settings();
85 m_settings->readConfigFile(filename.c_str());
88 LuaSettings::~LuaSettings()
90 if (m_is_own_settings)
95 void LuaSettings::create(lua_State *L, Settings *settings,
96 const std::string &filename)
98 LuaSettings *o = new LuaSettings(settings, filename);
99 *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
100 luaL_getmetatable(L, className);
101 lua_setmetatable(L, -2);
106 int LuaSettings::gc_object(lua_State* L)
108 LuaSettings* o = *(LuaSettings **)(lua_touserdata(L, 1));
114 // get(self, key) -> value
115 int LuaSettings::l_get(lua_State* L)
117 NO_MAP_LOCK_REQUIRED;
118 LuaSettings* o = checkobject(L, 1);
120 std::string key = std::string(luaL_checkstring(L, 2));
121 if (o->m_settings->exists(key)) {
122 std::string value = o->m_settings->get(key);
123 lua_pushstring(L, value.c_str());
131 // get_bool(self, key) -> boolean
132 int LuaSettings::l_get_bool(lua_State* L)
134 NO_MAP_LOCK_REQUIRED;
135 LuaSettings* o = checkobject(L, 1);
137 std::string key = std::string(luaL_checkstring(L, 2));
138 if (o->m_settings->exists(key)) {
139 bool value = o->m_settings->getBool(key);
140 lua_pushboolean(L, value);
142 // Push default value
143 if (lua_isboolean(L, 3))
144 lua_pushboolean(L, readParam<bool>(L, 3));
152 // get_np_group(self, key) -> value
153 int LuaSettings::l_get_np_group(lua_State *L)
155 NO_MAP_LOCK_REQUIRED;
156 LuaSettings *o = checkobject(L, 1);
158 std::string key = std::string(luaL_checkstring(L, 2));
159 if (o->m_settings->exists(key)) {
161 o->m_settings->getNoiseParams(key, np);
162 push_noiseparams(L, &np);
170 // get_flags(self, key) -> table or nil
171 int LuaSettings::l_get_flags(lua_State *L)
173 NO_MAP_LOCK_REQUIRED;
174 LuaSettings *o = checkobject(L, 1);
175 std::string key = std::string(luaL_checkstring(L, 2));
178 auto flagdesc = o->m_settings->getFlagDescFallback(key);
179 if (o->m_settings->getFlagStrNoEx(key, flags, flagdesc)) {
181 int table = lua_gettop(L);
182 for (size_t i = 0; flagdesc[i].name; ++i) {
183 lua_pushboolean(L, flags & flagdesc[i].flag);
184 lua_setfield(L, table, flagdesc[i].name);
186 lua_pushvalue(L, table);
194 // set(self, key, value)
195 int LuaSettings::l_set(lua_State* L)
197 NO_MAP_LOCK_REQUIRED;
198 LuaSettings* o = checkobject(L, 1);
200 std::string key = std::string(luaL_checkstring(L, 2));
201 const char* value = luaL_checkstring(L, 3);
203 CHECK_SETTING_SECURITY(L, key);
205 if (!o->m_settings->set(key, value))
206 throw LuaError("Invalid sequence found in setting parameters");
211 // set_bool(self, key, value)
212 int LuaSettings::l_set_bool(lua_State* L)
214 NO_MAP_LOCK_REQUIRED;
215 LuaSettings* o = checkobject(L, 1);
217 std::string key = std::string(luaL_checkstring(L, 2));
218 bool value = readParam<bool>(L, 3);
220 CHECK_SETTING_SECURITY(L, key);
222 o->m_settings->setBool(key, value);
227 // set_np_group(self, key, value)
228 int LuaSettings::l_set_np_group(lua_State *L)
230 NO_MAP_LOCK_REQUIRED;
231 LuaSettings *o = checkobject(L, 1);
233 std::string key = std::string(luaL_checkstring(L, 2));
235 read_noiseparams(L, 3, &value);
237 CHECK_SETTING_SECURITY(L, key);
239 o->m_settings->setNoiseParams(key, value);
244 // remove(self, key) -> success
245 int LuaSettings::l_remove(lua_State* L)
247 NO_MAP_LOCK_REQUIRED;
248 LuaSettings* o = checkobject(L, 1);
250 std::string key = std::string(luaL_checkstring(L, 2));
252 CHECK_SETTING_SECURITY(L, key);
254 bool success = o->m_settings->remove(key);
255 lua_pushboolean(L, success);
260 // get_names(self) -> {key1, ...}
261 int LuaSettings::l_get_names(lua_State* L)
263 NO_MAP_LOCK_REQUIRED;
264 LuaSettings* o = checkobject(L, 1);
266 std::vector<std::string> keys = o->m_settings->getNames();
269 for (unsigned int i=0; i < keys.size(); i++)
271 lua_pushstring(L, keys[i].c_str());
272 lua_rawseti(L, -2, i + 1);
278 // write(self) -> success
279 int LuaSettings::l_write(lua_State* L)
281 NO_MAP_LOCK_REQUIRED;
282 LuaSettings* o = checkobject(L, 1);
284 if (!o->m_write_allowed) {
285 throw LuaError("Settings: writing " + o->m_filename +
286 " not allowed with mod security on.");
289 bool success = o->m_settings->updateConfigFile(o->m_filename.c_str());
290 lua_pushboolean(L, success);
295 static void push_settings_table(lua_State *L, const Settings *settings)
297 std::vector<std::string> keys = settings->getNames();
299 for (const std::string &key : keys) {
301 Settings *group = nullptr;
303 if (settings->getNoEx(key, value)) {
304 lua_pushstring(L, value.c_str());
305 } else if (settings->getGroupNoEx(key, group)) {
306 // Recursively push tables
307 push_settings_table(L, group);
309 // Impossible case (multithreading) due to MutexAutoLock
313 lua_setfield(L, -2, key.c_str());
317 // to_table(self) -> {[key1]=value1,...}
318 int LuaSettings::l_to_table(lua_State* L)
320 NO_MAP_LOCK_REQUIRED;
321 LuaSettings* o = checkobject(L, 1);
323 MutexAutoLock(o->m_settings->m_mutex);
324 push_settings_table(L, o->m_settings);
329 void LuaSettings::Register(lua_State* L)
332 int methodtable = lua_gettop(L);
333 luaL_newmetatable(L, className);
334 int metatable = lua_gettop(L);
336 lua_pushliteral(L, "__metatable");
337 lua_pushvalue(L, methodtable);
338 lua_settable(L, metatable); // hide metatable from Lua getmetatable()
340 lua_pushliteral(L, "__index");
341 lua_pushvalue(L, methodtable);
342 lua_settable(L, metatable);
344 lua_pushliteral(L, "__gc");
345 lua_pushcfunction(L, gc_object);
346 lua_settable(L, metatable);
348 lua_pop(L, 1); // drop metatable
350 luaL_register(L, nullptr, methods); // fill methodtable
351 lua_pop(L, 1); // drop methodtable
353 // Can be created from Lua (Settings(filename))
354 lua_register(L, className, create_object);
357 // LuaSettings(filename)
358 // Creates a LuaSettings and leaves it on top of the stack
359 int LuaSettings::create_object(lua_State* L)
361 NO_MAP_LOCK_REQUIRED;
362 bool write_allowed = true;
363 const char* filename = luaL_checkstring(L, 1);
364 CHECK_SECURE_PATH_POSSIBLE_WRITE(L, filename, &write_allowed);
365 LuaSettings* o = new LuaSettings(filename, write_allowed);
366 *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
367 luaL_getmetatable(L, className);
368 lua_setmetatable(L, -2);
372 LuaSettings* LuaSettings::checkobject(lua_State* L, int narg)
374 NO_MAP_LOCK_REQUIRED;
375 luaL_checktype(L, narg, LUA_TUSERDATA);
376 void *ud = luaL_checkudata(L, narg, className);
378 luaL_typerror(L, narg, className);
379 return *(LuaSettings**) ud; // unbox pointer
382 const char LuaSettings::className[] = "Settings";
383 const luaL_Reg LuaSettings::methods[] = {
384 luamethod(LuaSettings, get),
385 luamethod(LuaSettings, get_bool),
386 luamethod(LuaSettings, get_np_group),
387 luamethod(LuaSettings, get_flags),
388 luamethod(LuaSettings, set),
389 luamethod(LuaSettings, set_bool),
390 luamethod(LuaSettings, set_np_group),
391 luamethod(LuaSettings, remove),
392 luamethod(LuaSettings, get_names),
393 luamethod(LuaSettings, write),
394 luamethod(LuaSettings, to_table),