1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 
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.
9 
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.
14 
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.
18 */
19 
20 #include "lua_api/l_util.h"
21 #include "lua_api/l_internal.h"
22 #include "lua_api/l_settings.h"
23 #include "common/c_converter.h"
24 #include "common/c_content.h"
25 #include "cpp_api/s_async.h"
26 #include "serialization.h"
27 #include <json/json.h>
28 #include "cpp_api/s_security.h"
29 #include "porting.h"
30 #include "convert_json.h"
31 #include "debug.h"
32 #include "log.h"
33 #include "tool.h"
34 #include "filesys.h"
35 #include "settings.h"
36 #include "util/auth.h"
37 #include "util/base64.h"
38 #include "config.h"
39 #include "version.h"
40 #include "util/hex.h"
41 #include "util/sha1.h"
42 #include <algorithm>
43 
44 
45 // log([level,] text)
46 // Writes a line to the logger.
47 // The one-argument version logs to LL_NONE.
48 // The two-argument version accepts a log level.
49 // Either the special case "deprecated" for deprecation notices, or any specified in
50 // Logger::stringToLevel(name).
l_log(lua_State * L)51 int ModApiUtil::l_log(lua_State *L)
52 {
53 	NO_MAP_LOCK_REQUIRED;
54 	std::string text;
55 	LogLevel level = LL_NONE;
56 	if (lua_isnone(L, 2)) {
57 		text = luaL_checkstring(L, 1);
58 	} else {
59 		std::string name = luaL_checkstring(L, 1);
60 		text = luaL_checkstring(L, 2);
61 		if (name == "deprecated") {
62 			log_deprecated(L, text, 2);
63 			return 0;
64 		}
65 		level = Logger::stringToLevel(name);
66 		if (level == LL_MAX) {
67 			warningstream << "Tried to log at unknown level '" << name
68 				<< "'.  Defaulting to \"none\"." << std::endl;
69 			level = LL_NONE;
70 		}
71 	}
72 	g_logger.log(level, text);
73 	return 0;
74 }
75 
76 // get_us_time()
l_get_us_time(lua_State * L)77 int ModApiUtil::l_get_us_time(lua_State *L)
78 {
79 	NO_MAP_LOCK_REQUIRED;
80 	lua_pushnumber(L, porting::getTimeUs());
81 	return 1;
82 }
83 
84 // parse_json(str[, nullvalue])
l_parse_json(lua_State * L)85 int ModApiUtil::l_parse_json(lua_State *L)
86 {
87 	NO_MAP_LOCK_REQUIRED;
88 
89 	const char *jsonstr = luaL_checkstring(L, 1);
90 
91 	// Use passed nullvalue or default to nil
92 	int nullindex = 2;
93 	if (lua_isnone(L, nullindex)) {
94 		lua_pushnil(L);
95 		nullindex = lua_gettop(L);
96 	}
97 
98 	Json::Value root;
99 
100 	{
101 		std::istringstream stream(jsonstr);
102 
103 		Json::CharReaderBuilder builder;
104 		builder.settings_["collectComments"] = false;
105 		std::string errs;
106 
107 		if (!Json::parseFromStream(builder, stream, &root, &errs)) {
108 			errorstream << "Failed to parse json data " << errs << std::endl;
109 			size_t jlen = strlen(jsonstr);
110 			if (jlen > 100) {
111 				errorstream << "Data (" << jlen
112 					<< " bytes) printed to warningstream." << std::endl;
113 				warningstream << "data: \"" << jsonstr << "\"" << std::endl;
114 			} else {
115 				errorstream << "data: \"" << jsonstr << "\"" << std::endl;
116 			}
117 			lua_pushnil(L);
118 			return 1;
119 		}
120 	}
121 
122 	if (!push_json_value(L, root, nullindex)) {
123 		errorstream << "Failed to parse json data, "
124 			<< "depth exceeds lua stack limit" << std::endl;
125 		errorstream << "data: \"" << jsonstr << "\"" << std::endl;
126 		lua_pushnil(L);
127 	}
128 	return 1;
129 }
130 
131 // write_json(data[, styled]) -> string or nil and error message
l_write_json(lua_State * L)132 int ModApiUtil::l_write_json(lua_State *L)
133 {
134 	NO_MAP_LOCK_REQUIRED;
135 
136 	bool styled = false;
137 	if (!lua_isnone(L, 2)) {
138 		styled = readParam<bool>(L, 2);
139 		lua_pop(L, 1);
140 	}
141 
142 	Json::Value root;
143 	try {
144 		read_json_value(L, root, 1);
145 	} catch (SerializationError &e) {
146 		lua_pushnil(L);
147 		lua_pushstring(L, e.what());
148 		return 2;
149 	}
150 
151 	std::string out;
152 	if (styled) {
153 		out = root.toStyledString();
154 	} else {
155 		out = fastWriteJson(root);
156 	}
157 	lua_pushlstring(L, out.c_str(), out.size());
158 	return 1;
159 }
160 
161 // get_dig_params(groups, tool_capabilities)
l_get_dig_params(lua_State * L)162 int ModApiUtil::l_get_dig_params(lua_State *L)
163 {
164 	NO_MAP_LOCK_REQUIRED;
165 	ItemGroupList groups;
166 	read_groups(L, 1, groups);
167 	ToolCapabilities tp = read_tool_capabilities(L, 2);
168 	push_dig_params(L, getDigParams(groups, &tp));
169 	return 1;
170 }
171 
172 // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
l_get_hit_params(lua_State * L)173 int ModApiUtil::l_get_hit_params(lua_State *L)
174 {
175 	NO_MAP_LOCK_REQUIRED;
176 	std::unordered_map<std::string, int> groups;
177 	read_groups(L, 1, groups);
178 	ToolCapabilities tp = read_tool_capabilities(L, 2);
179 	if(lua_isnoneornil(L, 3))
180 		push_hit_params(L, getHitParams(groups, &tp));
181 	else
182 		push_hit_params(L, getHitParams(groups, &tp, readParam<float>(L, 3)));
183 	return 1;
184 }
185 
186 // check_password_entry(name, entry, password)
l_check_password_entry(lua_State * L)187 int ModApiUtil::l_check_password_entry(lua_State *L)
188 {
189 	NO_MAP_LOCK_REQUIRED;
190 	std::string name = luaL_checkstring(L, 1);
191 	std::string entry = luaL_checkstring(L, 2);
192 	std::string password = luaL_checkstring(L, 3);
193 
194 	if (base64_is_valid(entry)) {
195 		std::string hash = translate_password(name, password);
196 		lua_pushboolean(L, hash == entry);
197 		return 1;
198 	}
199 
200 	std::string salt;
201 	std::string verifier;
202 
203 	if (!decode_srp_verifier_and_salt(entry, &verifier, &salt)) {
204 		// invalid format
205 		warningstream << "Invalid password format for " << name << std::endl;
206 		lua_pushboolean(L, false);
207 		return 1;
208 	}
209 	std::string gen_verifier = generate_srp_verifier(name, password, salt);
210 
211 	lua_pushboolean(L, gen_verifier == verifier);
212 	return 1;
213 }
214 
215 // get_password_hash(name, raw_password)
l_get_password_hash(lua_State * L)216 int ModApiUtil::l_get_password_hash(lua_State *L)
217 {
218 	NO_MAP_LOCK_REQUIRED;
219 	std::string name = luaL_checkstring(L, 1);
220 	std::string raw_password = luaL_checkstring(L, 2);
221 	std::string hash = translate_password(name, raw_password);
222 	lua_pushstring(L, hash.c_str());
223 	return 1;
224 }
225 
226 // is_yes(arg)
l_is_yes(lua_State * L)227 int ModApiUtil::l_is_yes(lua_State *L)
228 {
229 	NO_MAP_LOCK_REQUIRED;
230 
231 	lua_getglobal(L, "tostring"); // function to be called
232 	lua_pushvalue(L, 1); // 1st argument
233 	lua_call(L, 1, 1); // execute function
234 	std::string str = readParam<std::string>(L, -1); // get result
235 	lua_pop(L, 1);
236 
237 	bool yes = is_yes(str);
238 	lua_pushboolean(L, yes);
239 	return 1;
240 }
241 
242 // get_builtin_path()
l_get_builtin_path(lua_State * L)243 int ModApiUtil::l_get_builtin_path(lua_State *L)
244 {
245 	NO_MAP_LOCK_REQUIRED;
246 
247 	std::string path = porting::path_share + DIR_DELIM + "builtin" + DIR_DELIM;
248 	lua_pushstring(L, path.c_str());
249 
250 	return 1;
251 }
252 
253 // get_user_path()
l_get_user_path(lua_State * L)254 int ModApiUtil::l_get_user_path(lua_State *L)
255 {
256 	NO_MAP_LOCK_REQUIRED;
257 
258 	std::string path = porting::path_user;
259 	lua_pushstring(L, path.c_str());
260 
261 	return 1;
262 }
263 
264 // compress(data, method, level)
l_compress(lua_State * L)265 int ModApiUtil::l_compress(lua_State *L)
266 {
267 	NO_MAP_LOCK_REQUIRED;
268 
269 	size_t size;
270 	const char *data = luaL_checklstring(L, 1, &size);
271 
272 	int level = -1;
273 	if (!lua_isnone(L, 3) && !lua_isnil(L, 3))
274 		level = readParam<float>(L, 3);
275 
276 	std::ostringstream os;
277 	compressZlib(std::string(data, size), os, level);
278 
279 	std::string out = os.str();
280 
281 	lua_pushlstring(L, out.data(), out.size());
282 	return 1;
283 }
284 
285 // decompress(data, method)
l_decompress(lua_State * L)286 int ModApiUtil::l_decompress(lua_State *L)
287 {
288 	NO_MAP_LOCK_REQUIRED;
289 
290 	size_t size;
291 	const char *data = luaL_checklstring(L, 1, &size);
292 
293 	std::istringstream is(std::string(data, size));
294 	std::ostringstream os;
295 	decompressZlib(is, os);
296 
297 	std::string out = os.str();
298 
299 	lua_pushlstring(L, out.data(), out.size());
300 	return 1;
301 }
302 
303 // encode_base64(string)
l_encode_base64(lua_State * L)304 int ModApiUtil::l_encode_base64(lua_State *L)
305 {
306 	NO_MAP_LOCK_REQUIRED;
307 
308 	size_t size;
309 	const char *data = luaL_checklstring(L, 1, &size);
310 
311 	std::string out = base64_encode((const unsigned char *)(data), size);
312 
313 	lua_pushlstring(L, out.data(), out.size());
314 	return 1;
315 }
316 
317 // decode_base64(string)
l_decode_base64(lua_State * L)318 int ModApiUtil::l_decode_base64(lua_State *L)
319 {
320 	NO_MAP_LOCK_REQUIRED;
321 
322 	size_t size;
323 	const char *d = luaL_checklstring(L, 1, &size);
324 	const std::string data = std::string(d, size);
325 
326 	if (!base64_is_valid(data))
327 		return 0;
328 
329 	std::string out = base64_decode(data);
330 
331 	lua_pushlstring(L, out.data(), out.size());
332 	return 1;
333 }
334 
335 // mkdir(path)
l_mkdir(lua_State * L)336 int ModApiUtil::l_mkdir(lua_State *L)
337 {
338 	NO_MAP_LOCK_REQUIRED;
339 	const char *path = luaL_checkstring(L, 1);
340 	CHECK_SECURE_PATH(L, path, true);
341 	lua_pushboolean(L, fs::CreateAllDirs(path));
342 	return 1;
343 }
344 
345 // get_dir_list(path, is_dir)
l_get_dir_list(lua_State * L)346 int ModApiUtil::l_get_dir_list(lua_State *L)
347 {
348 	NO_MAP_LOCK_REQUIRED;
349 	const char *path = luaL_checkstring(L, 1);
350 	bool list_all = !lua_isboolean(L, 2); // if its not a boolean list all
351 	bool list_dirs = readParam<bool>(L, 2); // true: list dirs, false: list files
352 
353 	CHECK_SECURE_PATH(L, path, false);
354 
355 	std::vector<fs::DirListNode> list = fs::GetDirListing(path);
356 
357 	int index = 0;
358 	lua_newtable(L);
359 
360 	for (const fs::DirListNode &dln : list) {
361 		if (list_all || list_dirs == dln.dir) {
362 			lua_pushstring(L, dln.name.c_str());
363 			lua_rawseti(L, -2, ++index);
364 		}
365 	}
366 
367 	return 1;
368 }
369 
370 // safe_file_write(path, content)
l_safe_file_write(lua_State * L)371 int ModApiUtil::l_safe_file_write(lua_State *L)
372 {
373 	NO_MAP_LOCK_REQUIRED;
374 	const char *path = luaL_checkstring(L, 1);
375 	size_t size;
376 	const char *content = luaL_checklstring(L, 2, &size);
377 
378 	CHECK_SECURE_PATH(L, path, true);
379 
380 	bool ret = fs::safeWriteToFile(path, std::string(content, size));
381 	lua_pushboolean(L, ret);
382 
383 	return 1;
384 }
385 
386 // request_insecure_environment()
l_request_insecure_environment(lua_State * L)387 int ModApiUtil::l_request_insecure_environment(lua_State *L)
388 {
389 	NO_MAP_LOCK_REQUIRED;
390 
391 	// Just return _G if security is disabled
392 	if (!ScriptApiSecurity::isSecure(L)) {
393 		lua_getglobal(L, "_G");
394 		return 1;
395 	}
396 
397 	// We have to make sure that this function is being called directly by
398 	// a mod, otherwise a malicious mod could override this function and
399 	// steal its return value.
400 	lua_Debug info;
401 	// Make sure there's only one item below this function on the stack...
402 	if (lua_getstack(L, 2, &info)) {
403 		return 0;
404 	}
405 	FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed");
406 	FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed");
407 	// ...and that that item is the main file scope.
408 	if (strcmp(info.what, "main") != 0) {
409 		return 0;
410 	}
411 
412 	// Get mod name
413 	lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
414 	if (!lua_isstring(L, -1)) {
415 		return 0;
416 	}
417 
418 	// Check secure.trusted_mods
419 	std::string mod_name = readParam<std::string>(L, -1);
420 	std::string trusted_mods = g_settings->get("secure.trusted_mods");
421 	trusted_mods.erase(std::remove_if(trusted_mods.begin(),
422 			trusted_mods.end(), static_cast<int(*)(int)>(&std::isspace)),
423 			trusted_mods.end());
424 	std::vector<std::string> mod_list = str_split(trusted_mods, ',');
425 	if (std::find(mod_list.begin(), mod_list.end(), mod_name) ==
426 			mod_list.end()) {
427 		return 0;
428 	}
429 
430 	// Push insecure environment
431 	lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
432 	return 1;
433 }
434 
435 // get_version()
l_get_version(lua_State * L)436 int ModApiUtil::l_get_version(lua_State *L)
437 {
438 	lua_createtable(L, 0, 3);
439 	int table = lua_gettop(L);
440 
441 	lua_pushstring(L, PROJECT_NAME_C);
442 	lua_setfield(L, table, "project");
443 
444 	lua_pushstring(L, g_version_string);
445 	lua_setfield(L, table, "string");
446 
447 	if (strcmp(g_version_string, g_version_hash) != 0) {
448 		lua_pushstring(L, g_version_hash);
449 		lua_setfield(L, table, "hash");
450 	}
451 
452 	return 1;
453 }
454 
l_sha1(lua_State * L)455 int ModApiUtil::l_sha1(lua_State *L)
456 {
457 	NO_MAP_LOCK_REQUIRED;
458 	size_t size;
459 	const char *data = luaL_checklstring(L, 1, &size);
460 	bool hex = !lua_isboolean(L, 2) || !readParam<bool>(L, 2);
461 
462 	// Compute actual checksum of data
463 	std::string data_sha1;
464 	{
465 		SHA1 ctx;
466 		ctx.addBytes(data, size);
467 		unsigned char *data_tmpdigest = ctx.getDigest();
468 		data_sha1.assign((char*) data_tmpdigest, 20);
469 		free(data_tmpdigest);
470 	}
471 
472 	if (hex) {
473 		std::string sha1_hex = hex_encode(data_sha1);
474 		lua_pushstring(L, sha1_hex.c_str());
475 	} else {
476 		lua_pushlstring(L, data_sha1.data(), data_sha1.size());
477 	}
478 
479 	return 1;
480 }
481 
Initialize(lua_State * L,int top)482 void ModApiUtil::Initialize(lua_State *L, int top)
483 {
484 	API_FCT(log);
485 
486 	API_FCT(get_us_time);
487 
488 	API_FCT(parse_json);
489 	API_FCT(write_json);
490 
491 	API_FCT(get_dig_params);
492 	API_FCT(get_hit_params);
493 
494 	API_FCT(check_password_entry);
495 	API_FCT(get_password_hash);
496 
497 	API_FCT(is_yes);
498 
499 	API_FCT(get_builtin_path);
500 	API_FCT(get_user_path);
501 
502 	API_FCT(compress);
503 	API_FCT(decompress);
504 
505 	API_FCT(mkdir);
506 	API_FCT(get_dir_list);
507 	API_FCT(safe_file_write);
508 
509 	API_FCT(request_insecure_environment);
510 
511 	API_FCT(encode_base64);
512 	API_FCT(decode_base64);
513 
514 	API_FCT(get_version);
515 	API_FCT(sha1);
516 
517 	LuaSettings::create(L, g_settings, g_settings_path);
518 	lua_setfield(L, top, "settings");
519 }
520 
InitializeClient(lua_State * L,int top)521 void ModApiUtil::InitializeClient(lua_State *L, int top)
522 {
523 	API_FCT(log);
524 
525 	API_FCT(get_us_time);
526 
527 	API_FCT(parse_json);
528 	API_FCT(write_json);
529 
530 	API_FCT(is_yes);
531 
532 	API_FCT(compress);
533 	API_FCT(decompress);
534 
535 	API_FCT(encode_base64);
536 	API_FCT(decode_base64);
537 
538 	API_FCT(get_version);
539 	API_FCT(sha1);
540 }
541 
InitializeAsync(lua_State * L,int top)542 void ModApiUtil::InitializeAsync(lua_State *L, int top)
543 {
544 	API_FCT(log);
545 
546 	API_FCT(get_us_time);
547 
548 	API_FCT(parse_json);
549 	API_FCT(write_json);
550 
551 	API_FCT(is_yes);
552 
553 	API_FCT(get_builtin_path);
554 	API_FCT(get_user_path);
555 
556 	API_FCT(compress);
557 	API_FCT(decompress);
558 
559 	API_FCT(mkdir);
560 	API_FCT(get_dir_list);
561 
562 	API_FCT(encode_base64);
563 	API_FCT(decode_base64);
564 
565 	API_FCT(get_version);
566 	API_FCT(sha1);
567 
568 	LuaSettings::create(L, g_settings, g_settings_path);
569 	lua_setfield(L, top, "settings");
570 }
571 
572