/* ----- libdazuko.c ----------------------------------------- */ /* * lua extension to interface with Dazuko */ /* * Copyright (c) 2005 Gerhard Sittig * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of Dazuko nor the names of its contributors may be used * to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "lua.h" #include "lauxlib.h" #include "lualib.h" #include #if 0 #define dbg(x) printf x; #else #define dbg(x) /* EMPTY */ #endif #define MODULE_NAME "libdazuko" /* * we need to pass pointers to the caller, although the data is * (should be) opaque (ATM: registered Dazuko ID, not accesses) * * ideally this should be done by means of the USERDATA type, but we * just pass them as integers until somebody will fix this ugly hack * * once we have a container we could add some safety belts like the * Ruby binding has (read only vs deny checks, reflecting successfully * configured properties, auto unregister in the GC hook, ...) */ #include /* gets group and mode, returns id or nil */ static int libdazuko_register(lua_State *L) { int argc, ok; const char *group, *mode; dazuko_id_t *id; intptr_t idnum; int rc; /* check arguments */ ok = 1; argc = lua_gettop(L); if ((argc < 1) || (argc > 2)) ok = 0; if (! lua_isstring(L, 1)) ok = 0; if ((argc == 2) && (! lua_isstring(L, 2))) ok = 0; if (! ok) { lua_pushstring(L, "invalid call for " MODULE_NAME ".register(), need one or two strings"); lua_error(L); } /* call dazuko function */ group = lua_tostring(L, 1); mode = (argc > 1) ? lua_tostring(L, 2) : "r"; id = NULL; dbg(("calling dazukoRegister_TS(&%p, \"%s\", \"%s\")", id, group, mode)) rc = dazukoRegister_TS(&id, group, mode); dbg((" => rc %d, id %p\n", rc, id)) /* XXX TODO pass id as userdata */ if (rc == 0) { idnum = (intptr_t)id; lua_pushnumber(L, idnum); } else { lua_pushnil(L); } return(1); } /* common routine to get version info */ enum version_type { GET_VERS_KERNEL, GET_VERS_IOLIB, }; static int libdazuko_getversion(lua_State *L, const enum version_type type) { int argc; int ok; int (*func)(struct dazuko_version *); struct dazuko_version ver; int rc; /* check arguments */ ok = 1; argc = lua_gettop(L); if (argc > 0) ok = 0; if (! ok) { lua_pushstring(L, "invalid call for " MODULE_NAME ".getversion()"); lua_error(L); } /* call dazuko function */ switch (type) { case GET_VERS_KERNEL: func = dazukoVersion; break; case GET_VERS_IOLIB: func = dazukoIOVersion; break; default: func = NULL; break; } if (func == NULL) { lua_pushstring(L, "invalid call for " MODULE_NAME ".getversion()"); lua_error(L); } memset(&ver, 0, sizeof(ver)); dbg(("calling dazuko*Version()")) rc = func(&ver); dbg((" => rc %d\n", rc)) /* bail out on error */ if (rc != 0) { lua_pushstring(L, "failed to get version info"); lua_error(L); } /* return a table on success */ lua_newtable(L); lua_pushliteral(L, "text"); lua_pushstring(L, ver.text); lua_settable(L, -3); lua_pushliteral(L, "major"); lua_pushnumber(L, ver.major); lua_settable(L, -3); lua_pushliteral(L, "minor"); lua_pushnumber(L, ver.minor); lua_settable(L, -3); lua_pushliteral(L, "revision"); lua_pushnumber(L, ver.revision); lua_settable(L, -3); lua_pushliteral(L, "release"); lua_pushnumber(L, ver.release); lua_settable(L, -3); return(1); } /* gets nothing, returns kernel module version */ static int libdazuko_version(lua_State *L) { return(libdazuko_getversion(L, GET_VERS_KERNEL)); } /* gets nothing, returns io library version */ static int libdazuko_ioversion(lua_State *L) { return(libdazuko_getversion(L, GET_VERS_IOLIB)); } /* gets id and mask, returns boolean */ static int libdazuko_setmask(lua_State *L) { int argc; int ok; intptr_t idnum; dazuko_id_t *id; int mask; int rc; /* check arguments */ ok = 1; argc = lua_gettop(L); if (argc != 2) ok = 0; if (! lua_isnumber(L, 1)) ok = 0; if (! lua_isnumber(L, 2)) ok = 0; if (! ok) { lua_pushstring(L, "invalid call for " MODULE_NAME ".setmask(), need two integers"); lua_error(L); } /* call dazuko function */ idnum = lua_tonumber(L, 1); id = (dazuko_id_t *)idnum; mask = lua_tonumber(L, 2); dbg(("calling dazukoSetAccessMask_TS(%p, %d)", id, mask)) rc = dazukoSetAccessMask_TS(id, mask); dbg((" => rc %d\n", rc)) /* return success */ lua_pushboolean(L, (rc == 0) ? 1 : 0); return(1); } /* gets id and path spec(s), returns boolean */ static int libdazuko_addincl(lua_State *L) { int argc; int ok; intptr_t idnum; dazuko_id_t *id; int idx; const char *path; int rc; /* check arguments */ ok = 1; argc = lua_gettop(L); if (argc < 2) ok = 0; if (! lua_isnumber(L, 1)) ok = 0; for (idx = 2; idx <= argc; idx++) { if (! lua_isstring(L, idx)) ok = 0; } if (! ok) { lua_pushstring(L, "invalid call for " MODULE_NAME ".addincl(), need one integer and one or more strings"); lua_error(L); } /* call dazuko function */ idnum = lua_tonumber(L, 1); id = (dazuko_id_t *)idnum; for (idx = 2; idx <= argc; idx++) { path = lua_tostring(L, idx); dbg(("calling dazukoAddIncludePath_TS(%p, \"%s\")", id, path)) rc = dazukoAddIncludePath_TS(id, path); dbg((" => rc %d\n", rc)) if (rc != 0) { /* return failure */ lua_pushboolean(L, 0); return(1); } } /* return success */ lua_pushboolean(L, 1); return(1); } /* gets id and path spec(s), returns boolean */ static int libdazuko_addexcl(lua_State *L) { int argc; int ok; intptr_t idnum; dazuko_id_t *id; int idx; const char *path; int rc; /* check arguments */ ok = 1; argc = lua_gettop(L); if (argc < 2) ok = 0; if (! lua_isnumber(L, 1)) ok = 0; for (idx = 2; idx <= argc; idx++) { if (! lua_isstring(L, idx)) ok = 0; } if (! ok) { lua_pushstring(L, "invalid call for " MODULE_NAME ".addexcl(), need one integer and one or more strings"); lua_error(L); } /* call dazuko function */ idnum = lua_tonumber(L, 1); id = (dazuko_id_t *)idnum; for (idx = 2; idx <= argc; idx++) { path = lua_tostring(L, idx); dbg(("calling dazukoAddExcludePath_TS(%p, \"%s\")", id, path)) rc = dazukoAddExcludePath_TS(id, path); dbg((" => rc %d\n", rc)) if (rc != 0) { /* return failure */ lua_pushboolean(L, 0); return(1); } } /* return success */ lua_pushboolean(L, 1); return(1); } /* gets id, returns boolean */ static int libdazuko_removeall(lua_State *L) { int argc; int ok; intptr_t idnum; dazuko_id_t *id; int rc; /* check arguments */ ok = 1; argc = lua_gettop(L); if (argc != 1) ok = 0; if (! lua_isnumber(L, 1)) ok = 0; if (! ok) { lua_pushstring(L, "invalid call for " MODULE_NAME ".removeall(), need one integer"); lua_error(L); } /* call dazuko function */ idnum = lua_tonumber(L, 1); id = (dazuko_id_t *)idnum; dbg(("calling dazukoRemoveAllPaths_TS(%p)", id)) rc = dazukoRemoveAllPaths_TS(id); dbg((" => rc %d\n", rc)) /* return success */ lua_pushboolean(L, (rc == 0) ? 1 : 0); return(1); } /* gets id and function, calls handler with access details, return boolean */ static int libdazuko_getaccess(lua_State *L) { int argc; int ok; intptr_t idnum; dazuko_id_t *id; struct dazuko_access *acc; int rc; int idx; /* check arguments */ ok = 1; argc = lua_gettop(L); if (argc < 2) ok = 0; if (! lua_isnumber(L, 1)) ok = 0; if (! lua_isfunction(L, 2)) ok = 0; if (! ok) { lua_pushstring(L, "invalid call for " MODULE_NAME ".getaccess(), need one integer and a function"); lua_error(L); } /* call dazuko function */ idnum = lua_tonumber(L, 1); id = (dazuko_id_t *)idnum; acc = NULL; dbg(("calling dazukoGetAccess_TS(%p, &%p)", id, acc)) fflush(stdout); rc = dazukoGetAccess_TS(id, &acc); dbg((" => rc %d, acc %p\n", rc, acc)) if (rc != 0) { dbg(("error getting access\n")) lua_pushboolean(L, 0); return(1); } else if (acc == NULL) { dbg(("got no access\n")) lua_pushboolean(L, 0); return(1); } else if (acc->event == 0) { dbg(("got no event\n")) rc = dazukoReturnAccess_TS(id, &acc); lua_pushboolean(L, 0); return(1); } dbg(("got event, collecting data")) /* prepare access details for the handler */ lua_pushvalue(L, 2); /* handler function */ #define IF_SET(key) \ if (acc->set_ ##key) #define ADD_DETAIL_I(key) do { \ lua_pushliteral(L, #key); \ lua_pushnumber(L, acc->key); \ lua_settable(L, -3); \ } while(0) #define ADD_DETAIL_S(key) do { \ lua_pushliteral(L, #key); \ lua_pushstring(L, acc->key); \ lua_settable(L, -3); \ } while(0) lua_newtable(L); /* access details */ ADD_DETAIL_I(deny); IF_SET(event) ADD_DETAIL_I(event); IF_SET(flags) ADD_DETAIL_I(flags); IF_SET(mode) ADD_DETAIL_I(mode); IF_SET(uid) ADD_DETAIL_I(uid); IF_SET(pid) ADD_DETAIL_I(pid); IF_SET(filename) ADD_DETAIL_S(filename); IF_SET(file_size) ADD_DETAIL_I(file_size); IF_SET(file_uid) ADD_DETAIL_I(file_uid); IF_SET(file_gid) ADD_DETAIL_I(file_gid); IF_SET(file_mode) ADD_DETAIL_I(file_mode); IF_SET(file_device) ADD_DETAIL_I(file_device); /* as a friendly service: pass all excess params to the handler */ for (idx = 3; idx <= argc; idx++) { lua_pushvalue(L, idx); } /* call the handler */ dbg((", calling handler\n")) rc = lua_pcall(L, 1 + (argc - 2), 1, 0); /* determine deny state */ if (rc != 0) { const char *err; err = lua_tostring(L, -1); fprintf(stderr, "error in access handler [%s], will grant access\n", err); acc->deny = 0; } else if (lua_isnil(L, -1)) { acc->deny = 0; } else if (lua_isboolean(L, -1)) { int b; b = lua_toboolean(L, -1); acc->deny = (b) ? 1 : 0; } else if (lua_isnumber(L, -1)) { int n; n = lua_tonumber(L, -1); acc->deny = (n != 0) ? 1 : 0; } else { fprintf(stderr, "unknown return type from access handler (%d), will grant access\n", lua_type(L, -1)); acc->deny = 0; } /* return access to the kernel */ dbg(("calling dazukoReturnAccess_TS(%p, &%p), deny %d", id, acc, acc->deny)) rc = dazukoReturnAccess_TS(id, &acc); dbg((" => rc %d\n", rc)) /* return success */ lua_pushboolean(L, 1); return(1); } /* gets id, returns boolean */ static int libdazuko_unregister(lua_State *L) { int argc; int ok; intptr_t idnum; dazuko_id_t *id; int rc; /* check arguments */ ok = 1; argc = lua_gettop(L); if (argc != 1) ok = 0; if (! lua_isnumber(L, 1)) ok = 0; if (! ok) { lua_pushstring(L, "invalid call for " MODULE_NAME ".unregister(), need one integer"); lua_error(L); } /* call dazuko function */ idnum = lua_tonumber(L, 1); id = (dazuko_id_t *)idnum; dbg(("calling dazukoUnregister_TS(&%p)", id)) rc = dazukoUnregister_TS(&id); dbg((" => rc %d\n", rc)) /* return success */ lua_pushboolean(L, (rc == 0) ? 1 : 0); return(1); } /* * swallow signals to not disturb the program's flow * (i.e. don't leave out unregister() when signals arrive) */ static void sighandler(const int sig) { /* EMPTY */ signal(sig, sighandler); } static int libdazuko_swallowsig(lua_State *L) { signal(SIGHUP , sighandler); signal(SIGINT , sighandler); signal(SIGTERM, sighandler); signal(SIGQUIT, sighandler); return(0); } /* mapping of Lua names to C routines */ static const luaL_reg libdazuko[] = { { "register", libdazuko_register, }, { "setmask", libdazuko_setmask, }, { "addincl", libdazuko_addincl, }, { "addexcl", libdazuko_addexcl, }, { "removeall", libdazuko_removeall, }, { "getaccess", libdazuko_getaccess, }, { "unregister", libdazuko_unregister, }, { "version", libdazuko_version, }, { "ioversion", libdazuko_ioversion, }, { "swallowsig", libdazuko_swallowsig, }, { NULL, NULL, } }; /* library initialization */ LUALIB_API int luaopen_libdazuko(lua_State *L) { /* check if we would be able to work */ if (sizeof(intptr_t) < sizeof(void *)) { lua_pushstring(L, "cannot map pointers to integers, " MODULE_NAME" will NOT be available (adjust intptr_t to make it work)"); lua_error(L); } /* register C functions */ luaL_openlib(L, MODULE_NAME, libdazuko, 0); /* register constants */ #define ADD_CONST(c) do { \ lua_pushliteral(L, #c); \ lua_pushnumber(L, c); \ lua_settable(L, -3); \ } while(0) ADD_CONST(DAZUKO_ON_OPEN); ADD_CONST(DAZUKO_ON_CLOSE); ADD_CONST(DAZUKO_ON_EXEC); ADD_CONST(DAZUKO_ON_CLOSE_MODIFIED); ADD_CONST(DAZUKO_ON_UNLINK); ADD_CONST(DAZUKO_ON_RMDIR); /* done, return module's table */ return(1); } /* ----- E O F ----------------------------------------------- */