engine.c 23.9 KB
Newer Older
1
/*  Copyright (C) 2015-2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2 3 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 3 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.

    You should have received a copy of the GNU General Public License
14
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
15 16
 */

17
#include <contrib/cleanup.h>
18
#include <ccan/json/json.h>
19
#include <ccan/asprintf/asprintf.h>
20 21
#include <uv.h>
#include <unistd.h>
22 23
#include <grp.h>
#include <pwd.h>
24
#include <zscanner/scanner.h>
25 26

#include "daemon/engine.h"
27
#include "daemon/bindings.h"
28
#include "daemon/ffimodule.h"
29
#include "lib/nsrep.h"
30 31
#include "lib/cache.h"
#include "lib/defines.h"
32
#include "lib/cdb_lmdb.h"
33
#include "lib/dnssec/ta.h"
34

35 36 37 38 39
/** @internal Compatibility wrapper for Lua < 5.2 */
#if LUA_VERSION_NUM < 502
#define lua_rawlen(L, obj) lua_objlen((L), (obj))
#endif

40 41 42
/** @internal Annotate for static checkers. */
KR_NORETURN int lua_error (lua_State *L);

43 44 45
/* Cleanup engine state every 5 minutes */
const size_t CLEANUP_TIMER = 5*60*1000;

46 47 48 49
/*
 * Global bindings.
 */

50
/** Register module callback into Lua world. */
51
#define REGISTER_MODULE_CALL(L, module, cb, name) do { \
52 53 54
	lua_pushlightuserdata((L), (module)); \
	lua_pushlightuserdata((L), (cb)); \
	lua_pushcclosure((L), l_trampoline, 2); \
55 56
	lua_setfield((L), -2, (name)); \
	} while (0)
57

58 59 60
/** Print help and available commands. */
static int l_help(lua_State *L)
{
61
	static const char *help_str =
62 63
		"help()\n    show this help\n"
		"quit()\n    quit\n"
64
		"hostname()\n    hostname\n"
65
		"user(name[, group])\n    change process user (and group)\n"
66
		"verbose(true|false)\n    toggle verbose mode\n"
67
		"option(opt[, new_val])\n    get/set server option\n"
68
		"mode(strict|normal|permissive)\n    set resolver strictness level\n"
69
		"reorder_RR([true|false])\n    set/get reordering of RRs within RRsets\n"
70 71
		"resolve(name, type[, class, flags, callback])\n    resolve query, callback when it's finished\n"
		"todname(name)\n    convert name to wire format\n"
72
		"tojson(val)\n    convert value to JSON\n"
73
		"map(expr)\n    run expression on all workers\n"
74 75 76 77
		"net\n    network configuration\n"
		"cache\n    network configuration\n"
		"modules\n    modules configuration\n"
		"kres\n    resolver services\n"
78
		"trust_anchors\n    configure trust anchors\n"
79
		;
80 81
	lua_pushstring(L, help_str);
	return 1;
82 83
}

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
static bool update_privileges(int uid, int gid)
{
	if ((gid_t)gid != getgid()) {
		if (setregid(gid, gid) < 0) {
			return false;
		}
	}
	if ((uid_t)uid != getuid()) {
		if (setreuid(uid, uid) < 0) {
			return false;
		}
	}
	return true;
}

/** Set process user/group. */
static int l_setuser(lua_State *L)
{
	int n = lua_gettop(L);
	if (n < 1 || !lua_isstring(L, 1)) {
		lua_pushliteral(L, "user(user[, group)");
		lua_error(L);
	}
	/* Fetch UID/GID based on string identifiers. */
	struct passwd *user_pw = getpwnam(lua_tostring(L, 1));
	if (!user_pw) {
		lua_pushliteral(L, "invalid user name");
		lua_error(L);
	}
	int uid = user_pw->pw_uid;
	int gid = getgid();
	if (n > 1 && lua_isstring(L, 2)) {
		struct group *group_pw = getgrnam(lua_tostring(L, 2));
		if (!group_pw) {
			lua_pushliteral(L, "invalid group name");
			lua_error(L);
		}
		gid = group_pw->gr_gid;
	}
	/* Drop privileges */
	bool ret = update_privileges(uid, gid);
	if (!ret) {
		lua_pushstring(L, strerror(errno));
		lua_error(L);
	}
	lua_pushboolean(L, ret);
	return 1;
}

133 134 135 136 137 138 139
/** Quit current executable. */
static int l_quit(lua_State *L)
{
	engine_stop(engine_luaget(L));
	return 0;
}

140 141 142 143
/** Toggle verbose mode. */
static int l_verbose(lua_State *L)
{
	if (lua_isboolean(L, 1) || lua_isnumber(L, 1)) {
144
		kr_verbose_set(lua_toboolean(L, 1));
145
	}
146
	lua_pushboolean(L, kr_verbose_status);
147 148 149
	return 1;
}

150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
char *engine_get_hostname(struct engine *engine) {
	static char hostname_str[KNOT_DNAME_MAXLEN];
	if (!engine) {
		return NULL;
	}

	if (!engine->hostname) {
		if (gethostname(hostname_str, sizeof(hostname_str)) != 0)
			return NULL;
		return hostname_str;
	}
	return engine->hostname;
}

int engine_set_hostname(struct engine *engine, const char *hostname) {
	if (!engine || !hostname) {
		return kr_error(EINVAL);
	}

	char *new_hostname = strdup(hostname);
	if (!new_hostname) {
		return kr_error(ENOMEM);
	}
	if (engine->hostname) {
		free(engine->hostname);
	}
	engine->hostname = new_hostname;
177
	network_new_hostname(&engine->net, engine);
178 179 180 181

	return 0;
}

182 183 184
/** Return hostname. */
static int l_hostname(lua_State *L)
{
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
	struct engine *engine = engine_luaget(L);
	if (lua_gettop(L) == 0) {
		lua_pushstring(L, engine_get_hostname(engine));
		return 1;
	}
	if ((lua_gettop(L) != 1) || !lua_isstring(L, 1)) {
		lua_pushstring(L, "hostname takes at most one parameter: (\"fqdn\")");
		lua_error(L);
	}

	if (engine_set_hostname(engine, lua_tostring(L, 1)) != 0) {
		lua_pushstring(L, "setting hostname failed");
		lua_error(L);
	}

	lua_pushstring(L, engine_get_hostname(engine));	
201 202 203
	return 1;
}

204 205 206 207 208 209 210 211
/** Get/set context option. */
static int l_option(lua_State *L)
{
	struct engine *engine = engine_luaget(L);
	/* Look up option name */
	unsigned opt_code = 0;
	if (lua_isstring(L, 1)) {
		const char *opt = lua_tostring(L, 1);
212
		for (const knot_lookup_t *it = kr_query_flag_names(); it->name; ++it) {
213 214 215 216 217 218 219 220 221 222 223
			if (strcmp(it->name, opt) == 0) {
				opt_code = it->id;
				break;
			}
		}
		if (!opt_code) {
			lua_pushstring(L, "invalid option name");
			lua_error(L);
		}
	}
	/* Get or set */
224
	if (lua_isboolean(L, 2) || lua_isnumber(L, 2)) {
225 226 227 228 229 230 231 232 233 234
		if (lua_toboolean(L, 2)) {
			engine->resolver.options |= opt_code;
		} else {
			engine->resolver.options &= ~opt_code; 
		}
	}
	lua_pushboolean(L, engine->resolver.options & opt_code);
	return 1;
}

235 236 237 238 239 240 241 242 243
/** @internal for l_trustanchor: */
static void ta_add(zs_scanner_t *zs)
{
	map_t *ta = zs->process.data;
	if (!ta)
		return;
	if (kr_ta_add(ta, zs->r_owner, zs->r_type, zs->r_ttl, zs->r_data, zs->r_data_length))
		zs->process.data = NULL; /* error signalling */
}
244 245 246 247 248 249
/** Enable/disable trust anchor. */
static int l_trustanchor(lua_State *L)
{
	struct engine *engine = engine_luaget(L);
	const char *anchor = lua_tostring(L, 1);
	bool enable = lua_isboolean(L, 2) ? lua_toboolean(L, 2) : true;
250
	if (!anchor || strlen(anchor) == 0) {
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
		return 0;
	}
	/* If disabling, parse the owner string only. */
	if (!enable) {
		knot_dname_t *owner = knot_dname_from_str(NULL, anchor, KNOT_DNAME_MAXLEN);
		if (!owner) {
			lua_pushstring(L, "invalid trust anchor owner");
			lua_error(L);
		}
		lua_pushboolean(L, kr_ta_del(&engine->resolver.trust_anchors, owner) == 0);
		free(owner);
		return 1;
	}

	/* Parse the record */
	zs_scanner_t *zs = malloc(sizeof(*zs));
	if (!zs || zs_init(zs, ".", 1, 0) != 0) {
		free(zs);
		lua_pushstring(L, "not enough memory");
		lua_error(L);
	}
272 273 274 275 276
	zs_set_processing(zs, ta_add, NULL, &engine->resolver.trust_anchors);
	bool ok = zs_set_input_string(zs, anchor, strlen(anchor)) == 0
		&& zs_parse_all(zs) == 0;
	ok = ok && zs->process.data; /* reset to NULL on error in ta_add */

277 278 279 280 281 282 283 284 285 286
	zs_deinit(zs);
	free(zs);
	/* Report errors */
	if (!ok) {
		lua_pushstring(L, "failed to process trust anchor RR");
		lua_error(L);
	}
	lua_pushboolean(L, true);
	return 1;
}
287 288 289
/** Unpack JSON object to table */
static void l_unpack_json(lua_State *L, JsonNode *table)
{
290 291 292 293 294 295 296 297
	/* Unpack POD */
	switch(table->tag) {
		case JSON_STRING: lua_pushstring(L, table->string_); return;
		case JSON_NUMBER: lua_pushnumber(L, table->number_); return;
		case JSON_BOOL:   lua_pushboolean(L, table->bool_); return;
		default: break;
	}
	/* Unpack object or array into table */
298 299 300 301 302 303 304 305 306
	lua_newtable(L);
	JsonNode *node = NULL;
	json_foreach(node, table) {
		/* Push node value */
		switch(node->tag) {
		case JSON_OBJECT: /* as array */
		case JSON_ARRAY:  l_unpack_json(L, node); break;
		case JSON_STRING: lua_pushstring(L, node->string_); break;
		case JSON_NUMBER: lua_pushnumber(L, node->number_); break;
307
		case JSON_BOOL:   lua_pushboolean(L, node->bool_); break;
308 309 310 311 312 313 314 315 316 317 318
		default: continue;
		}
		/* Set table key */
		if (node->key) {
			lua_setfield(L, -2, node->key);
		} else {
			lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
		}
	}
}

319
/** @internal Recursive Lua/JSON serialization. */
320 321
static JsonNode *l_pack_elem(lua_State *L, int top)
{
322 323 324 325 326 327
	switch(lua_type(L, top)) {
	case LUA_TSTRING:  return json_mkstring(lua_tostring(L, top));
	case LUA_TNUMBER:  return json_mknumber(lua_tonumber(L, top));
	case LUA_TBOOLEAN: return json_mkbool(lua_toboolean(L, top));
	case LUA_TTABLE:   break; /* Table, iterate it. */
	default:           return json_mknull();
328
	}
329 330 331 332
	/* Use absolute indexes here, as the table may be nested. */
	JsonNode *node = NULL;
	lua_pushnil(L);
	while(lua_next(L, top) != 0) {
333
		bool is_array = false;
334
		if (!node) {
335
			is_array = (lua_type(L, top + 1) == LUA_TNUMBER);
336
			node = is_array ? json_mkarray() : json_mkobject();
337 338 339
			if (!node) {
				return NULL;
			}
340 341
		} else {
			is_array = node->tag == JSON_ARRAY;
342
		}
343

344 345 346
		/* Insert to array/table. */
		JsonNode *val = l_pack_elem(L, top + 2);
		if (is_array) {
347 348
			json_append_element(node, val);
		} else {
349 350
			const char *key = lua_tostring(L, top + 1);
			json_append_member(node, key, val);
351 352
		}
		lua_pop(L, 1);
353
	}
354 355
	/* Return empty object for empty tables. */
	return node ? node : json_mkobject();
356 357
}

358
/** @internal Serialize to string */
359 360
static char *l_pack_json(lua_State *L, int top)
{
361
	JsonNode *root = l_pack_elem(L, top);
362 363 364 365 366 367 368 369
	if (!root) {
		return NULL;
	}
	char *result = json_encode(root);
	json_delete(root);
	return result;
}

370 371
static int l_tojson(lua_State *L)
{
372
	auto_free char *json_str = l_pack_json(L, lua_gettop(L));
373 374 375 376 377 378 379
	if (!json_str) {
		return 0;
	}
	lua_pushstring(L, json_str);
	return 1;
}

380 381 382 383 384 385
/** @internal Throw Lua error if expr is false */
#define expr_checked(expr) \
	if (!(expr)) { lua_pushboolean(L, false); lua_rawseti(L, -2, lua_rawlen(L, -2) + 1); continue; }

static int l_map(lua_State *L)
{
386 387 388 389 390
	if (lua_gettop(L) != 1 || !lua_isstring(L, 1)) {
		lua_pushliteral(L, "map('string with a lua expression')");
		lua_error(L);
	}

391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
	struct engine *engine = engine_luaget(L);
	const char *cmd = lua_tostring(L, 1);
	uint32_t len = strlen(cmd);
	lua_newtable(L);

	/* Execute on leader instance */
	int ntop = lua_gettop(L);
	engine_cmd(L, cmd, true);
	lua_settop(L, ntop + 1); /* Push only one return value to table */
	lua_rawseti(L, -2, 1);

	for (size_t i = 0; i < engine->ipc_set.len; ++i) {
		int fd = engine->ipc_set.at[i];
		/* Send command */
		expr_checked(write(fd, &len, sizeof(len)) == sizeof(len));
		expr_checked(write(fd, cmd, len) == len);
		/* Read response */
		uint32_t rlen = 0;
		if (read(fd, &rlen, sizeof(rlen)) == sizeof(rlen)) {
410
			expr_checked(rlen < UINT32_MAX);
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
			auto_free char *rbuf = malloc(rlen + 1);
			expr_checked(rbuf != NULL);
			expr_checked(read(fd, rbuf, rlen) == rlen);
			rbuf[rlen] = '\0';
			/* Unpack from JSON */
			JsonNode *root_node = json_decode(rbuf);
			if (root_node) {
				l_unpack_json(L, root_node);
			} else {
				lua_pushlstring(L, rbuf, rlen);
			}
			json_delete(root_node);
			lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
			continue;
		}
		/* Didn't respond */
		lua_pushboolean(L, false);
		lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
	}
	return 1;
}

#undef expr_checked


436
/** Trampoline function for module properties. */
437 438
static int l_trampoline(lua_State *L)
{
439 440
	struct kr_module *module = lua_touserdata(L, lua_upvalueindex(1));
	void* callback = lua_touserdata(L, lua_upvalueindex(2));
441
	struct engine *engine = engine_luaget(L);
442 443 444 445
	if (!module) {
		lua_pushstring(L, "module closure missing upvalue");
		lua_error(L);
	}
446

447 448 449
	/* Now we only have property callback or config,
	 * if we expand the callables, we might need a callback_type.
	 */
450
	const char *args = NULL;
451
	auto_free char *cleanup_args = NULL;
452
	if (lua_gettop(L) > 0) {
453 454 455 456 457 458
		if (lua_istable(L, 1)) {
			cleanup_args = l_pack_json(L, 1);
			args = cleanup_args;
		} else {
			args = lua_tostring(L, 1);
		}
459
	}
460
	if (callback == module->config) {
461
		module->config(module, args);
462 463
	} else {
		kr_prop_cb *prop = (kr_prop_cb *)callback;
464 465 466 467 468
		auto_free char *ret = prop(engine, module, args);
		if (!ret) { /* No results */
			return 0;
		}
		JsonNode *root_node = json_decode(ret);
469
		if (root_node) {
470 471 472 473 474
			l_unpack_json(L, root_node);
		} else {
			lua_pushstring(L, ret);
		}
		json_delete(root_node);
475
		return 1;
476
	}
477

478 479 480 481 482 483 484 485 486 487 488
	/* No results */
	return 0;
}

/*
 * Engine API.
 */

static int init_resolver(struct engine *engine)
{
	/* Open resolution context */
489
	engine->resolver.trust_anchors = map_make();
490
	engine->resolver.negative_anchors = map_make();
491
	engine->resolver.pool = engine->pool;
492
	engine->resolver.modules = &engine->modules;
493 494 495 496 497 498
	/* Create OPT RR */
	engine->resolver.opt_rr = mm_alloc(engine->pool, sizeof(knot_rrset_t));
	if (!engine->resolver.opt_rr) {
		return kr_error(ENOMEM);
	}
	knot_edns_init(engine->resolver.opt_rr, KR_EDNS_PAYLOAD, 0, KR_EDNS_VERSION, engine->pool);
Ondřej Surý's avatar
Ondřej Surý committed
499 500
	/* Set default TLS padding */
	engine->resolver.tls_padding = KR_DEFAULT_TLS_PADDING;
501 502 503
	/* Set default root hints */
	kr_zonecut_init(&engine->resolver.root_hints, (const uint8_t *)"", engine->pool);
	kr_zonecut_set_sbelt(&engine->resolver, &engine->resolver.root_hints);
504
	/* Open NS rtt + reputation cache */
505 506 507
	lru_create(&engine->resolver.cache_rtt, LRU_RTT_SIZE, engine->pool, NULL);
	lru_create(&engine->resolver.cache_rep, LRU_REP_SIZE, engine->pool, NULL);
	lru_create(&engine->resolver.cache_cookie, LRU_COOKIES_SIZE, engine->pool, NULL);
508 509

	/* Load basic modules */
510 511 512 513
	engine_register(engine, "iterate", NULL, NULL);
	engine_register(engine, "validate", NULL, NULL);
	engine_register(engine, "rrcache", NULL, NULL);
	engine_register(engine, "pktcache", NULL, NULL);
514

515
	return array_push(engine->backends, kr_cdb_lmdb());
516 517 518 519 520 521 522 523 524 525
}

static int init_state(struct engine *engine)
{
	/* Initialize Lua state */
	engine->L = luaL_newstate();
	if (engine->L == NULL) {
		return kr_error(ENOMEM);
	}
	/* Initialize used libraries. */
526
	lua_gc(engine->L, LUA_GCSTOP, 0);
527 528 529 530 531 532
	luaL_openlibs(engine->L);
	/* Global functions */
	lua_pushcfunction(engine->L, l_help);
	lua_setglobal(engine->L, "help");
	lua_pushcfunction(engine->L, l_quit);
	lua_setglobal(engine->L, "quit");
533 534
	lua_pushcfunction(engine->L, l_hostname);
	lua_setglobal(engine->L, "hostname");
535 536 537 538
	lua_pushcfunction(engine->L, l_verbose);
	lua_setglobal(engine->L, "verbose");
	lua_pushcfunction(engine->L, l_option);
	lua_setglobal(engine->L, "option");
539 540
	lua_pushcfunction(engine->L, l_setuser);
	lua_setglobal(engine->L, "user");
541 542
	lua_pushcfunction(engine->L, l_trustanchor);
	lua_setglobal(engine->L, "trustanchor");
543 544 545 546
	lua_pushliteral(engine->L, libknot_SONAME);
	lua_setglobal(engine->L, "libknot_SONAME");
	lua_pushliteral(engine->L, libzscanner_SONAME);
	lua_setglobal(engine->L, "libzscanner_SONAME");
547 548
	lua_pushcfunction(engine->L, l_tojson);
	lua_setglobal(engine->L, "tojson");
549 550
	lua_pushcfunction(engine->L, l_map);
	lua_setglobal(engine->L, "map");
551
	lua_pushliteral(engine->L, MODULEDIR);
552
	lua_setglobal(engine->L, "moduledir");
553 554 555 556 557
	lua_pushlightuserdata(engine->L, engine);
	lua_setglobal(engine->L, "__engine");
	return kr_ok();
}

558 559 560 561 562 563 564
static enum lru_apply_do update_stat_item(const char *key, uint len,
						unsigned *rtt, void *baton)
{
	return *rtt > KR_NS_LONG ? LRU_APPLY_DO_EVICT : LRU_APPLY_DO_NOTHING;
}
/** @internal Walk RTT table, clearing all entries with bad score
 *    to compensate for intermittent network issues or temporary bad behaviour. */
565 566 567
static void update_state(uv_timer_t *handle)
{
	struct engine *engine = handle->data;
568
	lru_apply(engine->resolver.cache_rtt, update_stat_item, NULL);
569 570
}

571
int engine_init(struct engine *engine, knot_mm_t *pool)
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
{
	if (engine == NULL) {
		return kr_error(EINVAL);
	}

	memset(engine, 0, sizeof(*engine));
	engine->pool = pool;

	/* Initialize state */
	int ret = init_state(engine);
	if (ret != 0) {
		engine_deinit(engine);
	}
	/* Initialize resolver */
	ret = init_resolver(engine);
	if (ret != 0) {
588
		engine_deinit(engine);
589 590
		return ret;
	}
591 592
	/* Initialize network */
	network_init(&engine->net, uv_default_loop());
593 594 595 596

	return ret;
}

597 598 599 600 601 602 603 604 605 606 607 608 609
static void engine_unload(struct engine *engine, struct kr_module *module)
{
	/* Unregister module */
	auto_free char *name = strdup(module->name);
	kr_module_unload(module);
	/* Clear in Lua world */
	if (name) {
		lua_pushnil(engine->L);
		lua_setglobal(engine->L, name);
	}
	free(module);
}

610 611 612 613 614 615
void engine_deinit(struct engine *engine)
{
	if (engine == NULL) {
		return;
	}

616 617
	/* Only close sockets and services,
	 * no need to clean up mempool. */
618
	network_deinit(&engine->net);
619
	kr_zonecut_deinit(&engine->resolver.root_hints);
620
	kr_cache_close(&engine->resolver.cache);
621 622 623 624 625

	/* The lru keys are currently malloc-ated and need to be freed. */
	lru_free(engine->resolver.cache_rtt);
	lru_free(engine->resolver.cache_rep);
	lru_free(engine->resolver.cache_cookie);
626

627 628 629 630 631
	/* Clear IPC pipes */
	for (size_t i = 0; i < engine->ipc_set.len; ++i) {
		close(engine->ipc_set.at[i]);
	}

632
	/* Unload modules and engine. */
633
	for (size_t i = 0; i < engine->modules.len; ++i) {
634
		engine_unload(engine, engine->modules.at[i]);
635 636 637 638 639
	}
	if (engine->L) {
		lua_close(engine->L);
	}

640 641
	/* Free data structures */
	array_clear(engine->modules);
642
	array_clear(engine->backends);
643
	array_clear(engine->ipc_set);
644 645
	kr_ta_clear(&engine->resolver.trust_anchors);
	kr_ta_clear(&engine->resolver.negative_anchors);
646 647
}

648
int engine_pcall(lua_State *L, int argc)
649 650 651
{
#if LUA_VERSION_NUM >= 502
	lua_getglobal(L, "_SANDBOX");
652
	lua_setupvalue(L, -(2 + argc), 1);
653
#endif
654
	return lua_pcall(L, argc, LUA_MULTRET, 0);
655 656
}

657
int engine_cmd(lua_State *L, const char *str, bool raw)
658
{
659
	if (L == NULL) {
660 661 662 663
		return kr_error(ENOEXEC);
	}

	/* Evaluate results */
664 665 666
	lua_getglobal(L, "eval_cmd");
	lua_pushstring(L, str);
	lua_pushboolean(L, raw);
667 668

	/* Check result. */
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685
	return engine_pcall(L, 2);
}

int engine_ipc(struct engine *engine, const char *expr)
{
	if (engine == NULL || engine->L == NULL) {
		return kr_error(ENOEXEC);
	}

	/* Run expression and serialize response. */
	engine_cmd(engine->L, expr, true);
	if (lua_gettop(engine->L) > 0) {
		l_tojson(engine->L);
		return 1;
	} else {
		return 0;
	}
686 687
}

688 689 690
/* Execute byte code */
#define l_dobytecode(L, arr, len, name) \
	(luaL_loadbuffer((L), (arr), (len), (name)) || lua_pcall((L), 0, LUA_MULTRET, 0))
691 692
/** Load file in a sandbox environment. */
#define l_dosandboxfile(L, filename) \
693
	(luaL_loadfile((L), (filename)) || engine_pcall((L), 0))
694

695
static int engine_loadconf(struct engine *engine, const char *config_path)
696
{
697
	/* Use module path for including Lua scripts */
698
	static const char l_paths[] = "package.path = '" MODULEDIR "/?.lua;'..package.path";
699 700 701 702
	int ret = l_dobytecode(engine->L, l_paths, sizeof(l_paths) - 1, "");
	if (ret != 0) {
		lua_pop(engine->L, 1);
	}
703
	/* Init environment */
704 705 706 707
	static const char sandbox_bytecode[] = {
		#include "daemon/lua/sandbox.inc"
	};
	if (l_dobytecode(engine->L, sandbox_bytecode, sizeof(sandbox_bytecode), "init") != 0) {
708 709
		fprintf(stderr, "[system] error %s\n", lua_tostring(engine->L, -1));
		lua_pop(engine->L, 1);
710 711
		return kr_error(ENOEXEC);
	}
712
	/* Load config file */
713 714 715
	if (strcmp(config_path, "-") == 0) {
		return ret; /* No config, no defaults. */
	}
716 717
	if(access(config_path, F_OK ) != -1 ) {
		ret = l_dosandboxfile(engine->L, config_path);
718 719
	}
	if (ret == 0) {
720
		/* Load defaults */
721 722 723 724
		static const char config_bytecode[] = {
			#include "daemon/lua/config.inc"
		};
		ret = l_dobytecode(engine->L, config_bytecode, sizeof(config_bytecode), "config");
725 726 727 728
	}

	/* Evaluate */
	if (ret != 0) {
729
		fprintf(stderr, "%s\n", lua_tostring(engine->L, -1));
730 731
		lua_pop(engine->L, 1);
	}
732
	return ret;
733 734
}

735
int engine_start(struct engine *engine, const char *config_path)
736 737
{
	/* Load configuration. */
738
	int ret = engine_loadconf(engine, config_path);
739 740 741 742
	if (ret != 0) {
		return ret;
	}

743 744 745
	/* Clean up stack and restart GC */
	lua_settop(engine->L, 0);
	lua_gc(engine->L, LUA_GCCOLLECT, 0);
746
	lua_gc(engine->L, LUA_GCSETSTEPMUL, 50);
747 748
	lua_gc(engine->L, LUA_GCSETPAUSE, 400);
	lua_gc(engine->L, LUA_GCRESTART, 0);
749 750 751 752 753 754 755 756 757 758

	/* Set up periodic update function */
	uv_timer_t *timer = malloc(sizeof(*timer));
	if (timer) {
		uv_timer_init(uv_default_loop(), timer);
		timer->data = engine;
		engine->updater = timer;
		uv_timer_start(timer, update_state, CLEANUP_TIMER, CLEANUP_TIMER);
	}

759
	return kr_ok();
760 761 762 763
}

void engine_stop(struct engine *engine)
{
764 765 766 767 768 769 770
	if (!engine) {
		return;
	}
	if (engine->updater) {
		uv_timer_stop(engine->updater);
		uv_close((uv_handle_t *)engine->updater, (uv_close_cb) free);
	}
771 772 773
	uv_stop(uv_default_loop());
}

774
/** Register module properties in Lua environment, if any. */
775 776
static int register_properties(struct engine *engine, struct kr_module *module)
{
777 778 779
	if (!module->config && !module->props) {
		return kr_ok();
	}
780 781 782 783
	lua_newtable(engine->L);
	if (module->config != NULL) {
		REGISTER_MODULE_CALL(engine->L, module, module->config, "config");
	}
784 785 786 787

	const struct kr_prop *p = module->props == NULL ? NULL : module->props();
	for (; p && p->name; ++p) {
		if (p->cb != NULL) {
788 789 790 791 792 793 794 795
			REGISTER_MODULE_CALL(engine->L, module, p->cb, p->name);
		}
	}
	lua_setglobal(engine->L, module->name);

	/* Register module in Lua env */
	lua_getglobal(engine->L, "modules_register");
	lua_getglobal(engine->L, module->name);
796
	if (engine_pcall(engine->L, 1) != 0) {
797 798 799 800 801 802
		lua_pop(engine->L, 1);
	}

	return kr_ok();
}

803 804 805 806 807 808 809 810 811 812 813 814 815 816 817
/** @internal Find matching module */
static size_t module_find(module_array_t *mod_list, const char *name)
{
	size_t found = mod_list->len;
	for (size_t i = 0; i < mod_list->len; ++i) {
		struct kr_module *mod = mod_list->at[i];
		if (strcmp(mod->name, name) == 0) {
			found = i;
			break;
		}
	}
	return found;
}

int engine_register(struct engine *engine, const char *name, const char *precedence, const char* ref)
818 819 820 821
{
	if (engine == NULL || name == NULL) {
		return kr_error(EINVAL);
	}
822 823
	/* Make sure module is unloaded */
	(void) engine_unregister(engine, name);
824 825 826 827 828 829 830 831 832
	/* Find the index of referenced module. */
	module_array_t *mod_list = &engine->modules;
	size_t ref_pos = mod_list->len;
	if (precedence && ref) {
		ref_pos = module_find(mod_list, ref);
		if (ref_pos >= mod_list->len) {
			return kr_error(EIDRM);
		}
	}
833
	/* Attempt to load binary module */
834 835 836 837
	struct kr_module *module = malloc(sizeof(*module));
	if (!module) {
		return kr_error(ENOMEM);
	}
838
	module->data = engine;
839
	int ret = kr_module_load(module, name, NULL);
840 841
	/* Load Lua module if not a binary */
	if (ret == kr_error(ENOENT)) {
842
		ret = ffimodule_register_lua(engine, module, name);
843 844 845
	} else if (ret == kr_error(ENOTSUP)) {
		/* Print a more helpful message when module is linked against an old resolver ABI. */
		fprintf(stderr, "[system] module '%s' links to unsupported ABI, please rebuild it\n", name);
846
	}
847
	if (ret != 0) {
848
		free(module);
849
		return ret;
850 851 852 853
	}
	if (array_push(engine->modules, module) < 0) {
		engine_unload(engine, module);
		return kr_error(ENOMEM);
854
	}
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
	/* Evaluate precedence operator */
	if (precedence) {
		struct kr_module **arr = mod_list->at;
		size_t emplacement = mod_list->len;
		if (strcasecmp(precedence, ">") == 0) {
			if (ref_pos + 1 < mod_list->len)
				emplacement = ref_pos + 1; /* Insert after target */
		}
		if (strcasecmp(precedence, "<") == 0) {
			emplacement = ref_pos; /* Insert at target */
		}
		/* Move the tail if it has some elements. */
		if (emplacement + 1 < mod_list->len) {
			memmove(&arr[emplacement + 1], &arr[emplacement], sizeof(*arr) * (mod_list->len - (emplacement + 1)));
			arr[emplacement] = module;
		}
871
	}
872

873
	return register_properties(engine, module);
874 875 876 877
}

int engine_unregister(struct engine *engine, const char *name)
{
878
	module_array_t *mod_list = &engine->modules;
879
	size_t found = module_find(mod_list, name);
880
	if (found < mod_list->len) {
881
		engine_unload(engine, mod_list->at[found]);
882 883 884 885 886 887 888 889 890 891
		array_del(*mod_list, found);
		return kr_ok();
	}

	return kr_error(ENOENT);
}

void engine_lualib(struct engine *engine, const char *name, lua_CFunction lib_cb)
{
	if (engine != NULL) {
892
#if LUA_VERSION_NUM >= 502
893 894
		luaL_requiref(engine->L, name, lib_cb, 1);
		lua_pop(engine->L, 1);
895 896
#else
		lib_cb(engine->L);
897 898 899 900 901 902
#endif
	}
}

struct engine *engine_luaget(lua_State *L)
{
903
	lua_getglobal(L, "__engine");
904
	struct engine *engine = lua_touserdata(L, -1);
905
	lua_pop(L, 1);
906
	return engine;
907
}