diff options
Diffstat (limited to 'libs/luci-lib-nixio/src')
28 files changed, 6493 insertions, 0 deletions
diff --git a/libs/luci-lib-nixio/src/Makefile b/libs/luci-lib-nixio/src/Makefile new file mode 100644 index 000000000..aaa4292bd --- /dev/null +++ b/libs/luci-lib-nixio/src/Makefile @@ -0,0 +1,120 @@ +OS = $(shell uname) +AXTLS_VERSION = 1.2.1 +AXTLS_DIR = axTLS +AXTLS_FILE = $(AXTLS_DIR)-$(AXTLS_VERSION).tar.gz +#NIXIO_TLS ?= openssl +NIXIO_SHADOW ?= $(shell echo 'int main(void){ return !getspnam("root"); }' | $(CC) $(CFLAGS) -include shadow.h -xc -o/dev/null - 2>/dev/null && echo yes) +NIXIO_SO = nixio.so +NIXIO_LDFLAGS = -llua -lm -ldl +CFLAGS += -std=gnu99 + +ifeq (,$(findstring Darwin,$(OS))) + NIXIO_LDFLAGS += -lcrypt -shared +else + NIXIO_LDFLAGS += -bundle -undefined dynamic_lookup + EXTRA_CFLAGS += -D__DARWIN__ +endif + +NIXIO_OBJ = nixio.o socket.o sockopt.o bind.o address.o \ + protoent.o poll.o io.o file.o splice.o process.o \ + syslog.o bit.o binary.o fs.o user.o \ + $(if $(NIXIO_TLS),tls-crypto.o tls-context.o tls-socket.o,) + +ifeq ($(NIXIO_TLS),axtls) + TLS_CFLAGS = -IaxTLS/ssl -IaxTLS/crypto -IaxTLS/config -include axtls-compat.h + TLS_DEPENDS = axtls-compat.o + NIXIO_OBJ += axtls-compat.o libaxtls.a +endif + +ifeq ($(NIXIO_TLS),openssl) + NIXIO_LDFLAGS += -lssl -lcrypto +endif + +ifeq ($(NIXIO_TLS),cyassl) + NIXIO_LDFLAGS += -lcyassl + TLS_DEPENDS = cyassl-compat.o + TLS_CFLAGS = -include cyassl-compat.h + NIXIO_OBJ += cyassl-compat.o +endif + +ifeq ($(NIXIO_TLS),) + NIXIO_CFLAGS += -DNO_TLS +endif + +ifneq ($(NIXIO_SHADOW),yes) + NIXIO_CFLAGS += -DNO_SHADOW +endif + + +ifeq ($(OS),SunOS) + NIXIO_LDFLAGS += -lsocket -lnsl -lsendfile +endif + +ifneq (,$(findstring MINGW,$(OS))$(findstring mingw,$(OS))$(findstring Windows,$(OS))) + NIXIO_CROSS_CC:=$(shell which i586-mingw32msvc-cc) +ifneq (,$(NIXIO_CROSS_CC)) + CC:=$(NIXIO_CROSS_CC) +endif + NIXIO_OBJ += mingw-compat.o + NIXIO_LDFLAGS_POST:=-llua -lssl -lcrypto -lws2_32 -lgdi32 + FPIC:= + EXTRA_CFLAGS += -D_WIN32_WINNT=0x0501 + LUA_CFLAGS:= + NIXIO_SO:=nixio.dll + NIXIO_LDFLAGS:= +endif + + +%.o: %.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(NIXIO_CFLAGS) $(LUA_CFLAGS) $(FPIC) -c -o $@ $< + +ifneq ($(NIXIO_TLS),) +tls-crypto.o: $(TLS_DEPENDS) tls-crypto.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(NIXIO_CFLAGS) $(LUA_CFLAGS) $(FPIC) $(TLS_CFLAGS) -c -o $@ tls-crypto.c + +tls-context.o: $(TLS_DEPENDS) tls-context.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(NIXIO_CFLAGS) $(LUA_CFLAGS) $(FPIC) $(TLS_CFLAGS) -c -o $@ tls-context.c + +tls-socket.o: $(TLS_DEPENDS) tls-socket.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(NIXIO_CFLAGS) $(LUA_CFLAGS) $(FPIC) $(TLS_CFLAGS) -c -o $@ tls-socket.c + +axtls-compat.o: libaxtls.a axtls-compat.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(NIXIO_CFLAGS) $(LUA_CFLAGS) $(FPIC) $(TLS_CFLAGS) -c -o $@ axtls-compat.c + mkdir -p dist + cp -pR axtls-root/* dist/ +endif + +compile: $(NIXIO_OBJ) + $(CC) $(LDFLAGS) $(SHLIB_FLAGS) -o $(NIXIO_SO) $(NIXIO_OBJ) $(NIXIO_LDFLAGS) $(NIXIO_LDFLAGS_POST) + mkdir -p dist/usr/lib/lua + cp $(NIXIO_SO) dist/usr/lib/lua/$(NIXIO_SO) + +$(AXTLS_DIR)/.prepared: + #rm -rf $(AXTLS_DIR) + #tar xvfz $(AXTLS_FILE) + cp axtls-config/.config axtls-config/config.h $(AXTLS_DIR)/config + touch $@ + +libaxtls.a: $(AXTLS_DIR)/.prepared + $(MAKE) -C $(AXTLS_DIR) CC="$(CC)" CFLAGS="$(CFLAGS) $(EXTRA_CFLAGS) $(FPIC) -Wall -pedantic -I../config -I../ssl -I../crypto" LDFLAGS="$(LDFLAGS)" OS="$(OS)" clean all + cp -p $(AXTLS_DIR)/_stage/libaxtls.a src + # ************************************************************************* + # + # + # + # *** WARNING *** + # The use of the axTLS cryptographical provider is discouraged! + # Please switch to either CyaSSL or OpenSSL. + # Support for axTLS might be removed in the near future. + # + # + # + #************************************************************************** + +clean: + rm -f *.o *.so *.a *.dll + rm -f $(AXTLS_DIR)/.prepared + +install: compile + mkdir -p $(DESTDIR) + cp -pR dist/* $(DESTDIR)/ diff --git a/libs/luci-lib-nixio/src/address.c b/libs/luci-lib-nixio/src/address.c new file mode 100644 index 000000000..4fd557d6a --- /dev/null +++ b/libs/luci-lib-nixio/src/address.c @@ -0,0 +1,565 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include <sys/types.h> +#include <sys/param.h> +#include <errno.h> +#include <string.h> + +#ifdef __linux__ + +#include <signal.h> +#include <setjmp.h> +#include <unistd.h> + +/* setjmp() / longjmp() stuff */ +static jmp_buf nixio__jump_alarm; +static void nixio__handle_alarm(int sig) { longjmp(nixio__jump_alarm, 1); } + +#include <linux/netdevice.h> + +/* struct net_device_stats is buggy on amd64, redefine it */ +struct nixio__nds { + uint32_t rx_packets; + uint32_t tx_packets; + uint32_t rx_bytes; + uint32_t tx_bytes; + uint32_t rx_errors; + uint32_t tx_errors; + uint32_t rx_dropped; + uint32_t tx_dropped; + uint32_t multicast; + uint32_t collisions; + + uint32_t rx_length_errors; + uint32_t rx_over_errors; + uint32_t rx_crc_errors; + uint32_t rx_frame_errors; + uint32_t rx_fifo_errors; + uint32_t rx_missed_errors; + + uint32_t tx_aborted_errors; + uint32_t tx_carrier_errors; + uint32_t tx_fifo_errors; + uint32_t tx_heartbeat_errors; + uint32_t tx_window_errors; + + uint32_t rx_compressed; + uint32_t tx_compressed; +}; +#endif + +#ifndef NI_MAXHOST +#define NI_MAXHOST 1025 +#endif + +/** + * address pushing helper + */ +int nixio__addr_parse(nixio_addr *addr, struct sockaddr *saddr) { + void *baddr; + + addr->family = saddr->sa_family; + if (saddr->sa_family == AF_INET) { + struct sockaddr_in *inetaddr = (struct sockaddr_in*)saddr; + addr->port = ntohs(inetaddr->sin_port); + baddr = &inetaddr->sin_addr; + } else if (saddr->sa_family == AF_INET6) { + struct sockaddr_in6 *inet6addr = (struct sockaddr_in6*)saddr; + addr->port = ntohs(inet6addr->sin6_port); + baddr = &inet6addr->sin6_addr; +#ifdef AF_PACKET + } else if (saddr->sa_family == AF_PACKET) { + struct sockaddr_ll *etheradddr = (struct sockaddr_ll*)saddr; + addr->prefix = etheradddr->sll_hatype; + addr->port = etheradddr->sll_ifindex; + char *c = addr->host; + for (size_t i = 0; i < etheradddr->sll_halen; i++) { + *c++ = nixio__bin2hex[(etheradddr->sll_addr[i] & 0xf0) >> 4]; + *c++ = nixio__bin2hex[(etheradddr->sll_addr[i] & 0x0f)]; + *c++ = ':'; + } + *(c-1) = 0; + return 0; +#endif + } else { + errno = EAFNOSUPPORT; + return -1; + } + + if (!inet_ntop(saddr->sa_family, baddr, addr->host, sizeof(addr->host))) { + return -1; + } + + return 0; +} + +/** + * address pulling helper + */ +int nixio__addr_write(nixio_addr *addr, struct sockaddr *saddr) { + if (addr->family == AF_UNSPEC) { + if (strchr(addr->host, ':')) { + addr->family = AF_INET6; + } else { + addr->family = AF_INET; + } + } + if (addr->family == AF_INET) { + struct sockaddr_in *inetaddr = (struct sockaddr_in *)saddr; + memset(inetaddr, 0, sizeof(struct sockaddr_in)); + + if (inet_pton(AF_INET, addr->host, &inetaddr->sin_addr) < 1) { + return -1; + } + + inetaddr->sin_family = AF_INET; + inetaddr->sin_port = htons((uint16_t)addr->port); + return 0; + } else if (addr->family == AF_INET6) { + struct sockaddr_in6 *inet6addr = (struct sockaddr_in6 *)saddr; + memset(inet6addr, 0, sizeof(struct sockaddr_in6)); + + if (inet_pton(AF_INET6, addr->host, &inet6addr->sin6_addr) < 1) { + return -1; + } + + inet6addr->sin6_family = AF_INET6; + inet6addr->sin6_port = htons((uint16_t)addr->port); + return 0; + } else { + errno = EAFNOSUPPORT; + return -1; + } +} + +/** + * netmask to prefix helper + */ +int nixio__addr_prefix(struct sockaddr *saddr) { + int prefix = 0; + size_t len; + uint8_t *addr; + + if (saddr->sa_family == AF_INET) { + addr = (uint8_t*)(&((struct sockaddr_in*)saddr)->sin_addr); + len = 4; + } else if (saddr->sa_family == AF_INET6) { + addr = (uint8_t*)(&((struct sockaddr_in6*)saddr)->sin6_addr); + len = 16; + } else { + errno = EAFNOSUPPORT; + return -1; + } + + for (size_t i = 0; i < len; i++) { + if (addr[i] == 0xff) { + prefix += 8; + } else if (addr[i] == 0x00) { + break; + } else { + for (uint8_t c = addr[i]; c; c <<= 1) { + prefix++; + } + } + } + + return prefix; +} + +/** + * getaddrinfo(host, family, port) + */ +static int nixio_getaddrinfo(lua_State *L) { + const char *host = NULL; + if (!lua_isnoneornil(L, 1)) { + host = luaL_checklstring(L, 1, NULL); + } + const char *family = luaL_optlstring(L, 2, "any", NULL); + const char *port = lua_tolstring(L, 3, NULL); + + struct addrinfo hints, *result, *rp; + memset(&hints, 0, sizeof(hints)); + + if (!strcmp(family, "any")) { + hints.ai_family = AF_UNSPEC; + } else if (!strcmp(family, "inet")) { + hints.ai_family = AF_INET; + } else if (!strcmp(family, "inet6")) { + hints.ai_family = AF_INET6; + } else { + return luaL_argerror(L, 2, "supported values: any, inet, inet6"); + } + + hints.ai_socktype = 0; + hints.ai_protocol = 0; + + int aistat = getaddrinfo(host, port, &hints, &result); + if (aistat) { + lua_pushnil(L); + lua_pushinteger(L, aistat); + lua_pushstring(L, gai_strerror(aistat)); + return 3; + } + + /* create socket object */ + lua_newtable(L); + int i = 1; + + for (rp = result; rp != NULL; rp = rp->ai_next) { + /* avoid duplicate results */ +#ifndef __WINNT__ + if (!port && rp->ai_socktype != SOCK_STREAM) { + continue; + } +#endif + + if (rp->ai_family == AF_INET || rp->ai_family == AF_INET6) { + lua_createtable(L, 0, port ? 4 : 2); + if (rp->ai_family == AF_INET) { + lua_pushliteral(L, "inet"); + } else if (rp->ai_family == AF_INET6) { + lua_pushliteral(L, "inet6"); + } + lua_setfield(L, -2, "family"); + + if (port) { + switch (rp->ai_socktype) { + case SOCK_STREAM: + lua_pushliteral(L, "stream"); + break; + case SOCK_DGRAM: + lua_pushliteral(L, "dgram"); + break; + case SOCK_RAW: + lua_pushliteral(L, "raw"); + break; + default: + lua_pushnil(L); + break; + } + lua_setfield(L, -2, "socktype"); + } + + nixio_addr addr; + if (nixio__addr_parse(&addr, rp->ai_addr)) { + freeaddrinfo(result); + return nixio__perror_s(L); + } + + if (port) { + lua_pushinteger(L, addr.port); + lua_setfield(L, -2, "port"); + } + + lua_pushstring(L, addr.host); + lua_setfield(L, -2, "address"); + lua_rawseti(L, -2, i++); + } + } + + freeaddrinfo(result); + + return 1; +} + +/** + * getnameinfo(address, family[, timeout]) + */ +static int nixio_getnameinfo(lua_State *L) { + const char *ip = luaL_checkstring(L, 1); + const char *family = luaL_optstring(L, 2, NULL); + +#ifdef __linux__ + struct sigaction sa_new, sa_old; + int timeout = luaL_optnumber(L, 3, 0); + if (timeout > 0 && timeout < 1000) + { + sa_new.sa_handler = nixio__handle_alarm; + sa_new.sa_flags = 0; + sigemptyset(&sa_new.sa_mask); + sigaction(SIGALRM, &sa_new, &sa_old); + + /* user timeout exceeded */ + if (setjmp(nixio__jump_alarm)) + { + sigaction(SIGALRM, &sa_old, NULL); + + lua_pushnil(L); + lua_pushinteger(L, EAI_AGAIN); + lua_pushstring(L, gai_strerror(EAI_AGAIN)); + + return 3; + } + + ualarm(timeout * 1000, 0); + } +#endif + + char host[NI_MAXHOST]; + + struct sockaddr_storage saddr; + nixio_addr addr; + memset(&addr, 0, sizeof(addr)); + strncpy(addr.host, ip, sizeof(addr.host) - 1); + + if (!family) { + addr.family = AF_UNSPEC; + } else if (!strcmp(family, "inet")) { + addr.family = AF_INET; + } else if (!strcmp(family, "inet6")) { + addr.family = AF_INET6; + } else { + return luaL_argerror(L, 2, "supported values: inet, inet6"); + } + + nixio__addr_write(&addr, (struct sockaddr *)&saddr); + + int res = getnameinfo((struct sockaddr *)&saddr, sizeof(saddr), + host, sizeof(host), NULL, 0, NI_NAMEREQD); + +#ifdef __linux__ + if (timeout > 0 && timeout < 1000) + { + ualarm(0, 0); + sigaction(SIGALRM, &sa_old, NULL); + } +#endif + + if (res) { + lua_pushnil(L); + lua_pushinteger(L, res); + lua_pushstring(L, gai_strerror(res)); + return 3; + } else { + lua_pushstring(L, host); + return 1; + } +} + +/** + * getsockname() + */ +static int nixio_sock_getsockname(lua_State *L) { + int sockfd = nixio__checksockfd(L); + struct sockaddr_storage saddr; + socklen_t addrlen = sizeof(saddr); + nixio_addr addr; + + if (getsockname(sockfd, (struct sockaddr*)&saddr, &addrlen) || + nixio__addr_parse(&addr, (struct sockaddr*)&saddr)) { + return nixio__perror_s(L); + } + + lua_pushstring(L, addr.host); + lua_pushinteger(L, addr.port); + return 2; +} + +/** + * getpeername() + */ +static int nixio_sock_getpeername(lua_State *L) { + int sockfd = nixio__checksockfd(L); + struct sockaddr_storage saddr; + socklen_t addrlen = sizeof(saddr); + nixio_addr addr; + + if (getpeername(sockfd, (struct sockaddr*)&saddr, &addrlen) || + nixio__addr_parse(&addr, (struct sockaddr*)&saddr)) { + return nixio__perror_s(L); + } + + lua_pushstring(L, addr.host); + lua_pushinteger(L, addr.port); + return 2; +} + +#if defined(__linux__) || defined(BSD) +#ifdef BSD +#include <net/if.h> +#endif +#include <ifaddrs.h> + +static int nixio_getifaddrs(lua_State *L) { + nixio_addr addr; + struct ifaddrs *ifaddr, *c; + if (getifaddrs(&ifaddr) == -1) { + return nixio__perror(L); + } + + lua_newtable(L); + unsigned int i = 1; + + for (c = ifaddr; c; c = c->ifa_next) { + lua_newtable(L); + + lua_pushstring(L, c->ifa_name); + lua_setfield(L, -2, "name"); + + lua_createtable(L, 0, 7); + lua_pushboolean(L, c->ifa_flags & IFF_UP); + lua_setfield(L, -2, "up"); + + lua_pushboolean(L, c->ifa_flags & IFF_BROADCAST); + lua_setfield(L, -2, "broadcast"); + + lua_pushboolean(L, c->ifa_flags & IFF_LOOPBACK); + lua_setfield(L, -2, "loopback"); + + lua_pushboolean(L, c->ifa_flags & IFF_POINTOPOINT); + lua_setfield(L, -2, "pointtopoint"); + + lua_pushboolean(L, c->ifa_flags & IFF_NOARP); + lua_setfield(L, -2, "noarp"); + + lua_pushboolean(L, c->ifa_flags & IFF_PROMISC); + lua_setfield(L, -2, "promisc"); + + lua_pushboolean(L, c->ifa_flags & IFF_MULTICAST); + lua_setfield(L, -2, "multicast"); + lua_setfield(L, -2, "flags"); + + if (c->ifa_addr) { + if (!nixio__addr_parse(&addr, c->ifa_addr)) { + lua_pushstring(L, addr.host); + lua_setfield(L, -2, "addr"); + } + + if (c->ifa_addr->sa_family == AF_INET) { + lua_pushliteral(L, "inet"); + } else if (c->ifa_addr->sa_family == AF_INET6) { + lua_pushliteral(L, "inet6"); +#ifdef AF_PACKET + } else if (c->ifa_addr->sa_family == AF_PACKET) { + lua_pushliteral(L, "packet"); +#endif + } else { + lua_pushliteral(L, "unknown"); + } + lua_setfield(L, -2, "family"); + +#ifdef __linux__ + if (c->ifa_addr->sa_family == AF_PACKET) { + lua_pushinteger(L, addr.port); + lua_setfield(L, -2, "ifindex"); + + lua_pushinteger(L, addr.prefix); + lua_setfield(L, -2, "hatype"); + } +#endif + } + +#ifdef __linux__ + if (c->ifa_data && (!c->ifa_addr + || c->ifa_addr->sa_family == AF_PACKET)) { + if (!c->ifa_addr) { + lua_pushliteral(L, "packet"); + lua_setfield(L, -2, "family"); + } + + lua_createtable(L, 0, 10); + struct nixio__nds *stats = c->ifa_data; + + lua_pushnumber(L, stats->rx_packets); + lua_setfield(L, -2, "rx_packets"); + + lua_pushnumber(L, stats->tx_packets); + lua_setfield(L, -2, "tx_packets"); + + lua_pushnumber(L, stats->rx_bytes); + lua_setfield(L, -2, "rx_bytes"); + + lua_pushnumber(L, stats->tx_bytes); + lua_setfield(L, -2, "tx_bytes"); + + lua_pushnumber(L, stats->rx_errors); + lua_setfield(L, -2, "rx_errors"); + + lua_pushnumber(L, stats->tx_errors); + lua_setfield(L, -2, "tx_errors"); + + lua_pushnumber(L, stats->rx_dropped); + lua_setfield(L, -2, "rx_dropped"); + + lua_pushnumber(L, stats->tx_dropped); + lua_setfield(L, -2, "tx_dropped"); + + lua_pushnumber(L, stats->multicast); + lua_setfield(L, -2, "multicast"); + + lua_pushnumber(L, stats->collisions); + lua_setfield(L, -2, "collisions"); + } else { + lua_newtable(L); + } + lua_setfield(L, -2, "data"); +#endif + + if (c->ifa_netmask && !nixio__addr_parse(&addr, c->ifa_netmask)) { + lua_pushstring(L, addr.host); + lua_setfield(L, -2, "netmask"); + + lua_pushinteger(L, nixio__addr_prefix(c->ifa_netmask)); + lua_setfield(L, -2, "prefix"); + } + + if (c->ifa_broadaddr && !nixio__addr_parse(&addr, c->ifa_broadaddr)) { + lua_pushstring(L, addr.host); + lua_setfield(L, -2, "broadaddr"); + } + + if (c->ifa_dstaddr && !nixio__addr_parse(&addr, c->ifa_dstaddr)) { + lua_pushstring(L, addr.host); + lua_setfield(L, -2, "dstaddr"); + } + + lua_rawseti(L, -2, i++); + } + + freeifaddrs(ifaddr); + return 1; +} +#endif + + +/* module table */ +static const luaL_reg R[] = { +#if defined(__linux__) || defined(BSD) + {"getifaddrs", nixio_getifaddrs}, +#endif + {"getaddrinfo", nixio_getaddrinfo}, + {"getnameinfo", nixio_getnameinfo}, + {NULL, NULL} +}; + +/* object table */ +static const luaL_reg M[] = { + {"getsockname", nixio_sock_getsockname}, + {"getpeername", nixio_sock_getpeername}, + {NULL, NULL} +}; + +void nixio_open_address(lua_State *L) { + luaL_register(L, NULL, R); + + lua_pushvalue(L, -2); + luaL_register(L, NULL, M); + lua_pop(L, 1); +} diff --git a/libs/luci-lib-nixio/src/axtls-compat.c b/libs/luci-lib-nixio/src/axtls-compat.c new file mode 100644 index 000000000..2c5b746c2 --- /dev/null +++ b/libs/luci-lib-nixio/src/axtls-compat.c @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the axTLS project 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. + */ + +/* + * Enable a subset of openssl compatible functions. We don't aim to be 100% + * compatible - just to be able to do basic ports etc. + * + * Only really tested on mini_httpd, so I'm not too sure how extensive this + * port is. + */ + +#include "config.h" + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include "ssl.h" + +static char *key_password = NULL; + +void *SSLv23_server_method(void) { return NULL; } +void *SSLv3_server_method(void) { return NULL; } +void *TLSv1_server_method(void) { return NULL; } +void *SSLv23_client_method(void) { return NULL; } +void *SSLv3_client_method(void) { return NULL; } +void *TLSv1_client_method(void) { return NULL; } +void *SSLv23_method(void) { return NULL; } +void *TLSv1_method(void) { return NULL; } + +SSL_CTX * SSL_CTX_new(void *meth) +{ + SSL_CTX *ssl_ctx = ssl_ctx_new(SSL_SERVER_VERIFY_LATER, 5); + return ssl_ctx; +} + +void SSL_CTX_free(SSL_CTX * ssl_ctx) +{ + ssl_ctx_free(ssl_ctx); +} + +SSL * SSL_new(SSL_CTX *ssl_ctx) +{ + SSL *ssl; + + ssl = ssl_new(ssl_ctx, -1); /* fd is set later */ + + return ssl; +} + +int SSL_set_fd(SSL *s, int fd) +{ + s->client_fd = fd; + return 1; /* always succeeds */ +} + +int SSL_accept(SSL *ssl) +{ + ssl->next_state = HS_CLIENT_HELLO; + while (ssl_read(ssl, NULL) == SSL_OK) + { + if (ssl->next_state == HS_CLIENT_HELLO) + return 1; /* we're done */ + } + + return -1; +} + +int SSL_connect(SSL *ssl) +{ + SET_SSL_FLAG(SSL_IS_CLIENT); + int stat = do_client_connect(ssl); + ssl_display_error(stat); + return (stat == SSL_OK) ? 1 : -1; +} + +void SSL_free(SSL *ssl) +{ + ssl_free(ssl); +} + +int SSL_read(SSL *ssl, void *buf, int num) +{ + uint8_t *read_buf; + int ret; + + while ((ret = ssl_read(ssl, &read_buf)) == SSL_OK); + + if (ret > SSL_OK) + { + memcpy(buf, read_buf, ret > num ? num : ret); + } + + return ret; +} + +int SSL_write(SSL *ssl, const void *buf, int num) +{ + return ssl_write(ssl, buf, num); +} + +int SSL_CTX_use_certificate_file(SSL_CTX *ssl_ctx, const char *file, int type) +{ + return (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, file, NULL) == SSL_OK); +} + +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ssl_ctx, const char *file, int type) +{ + return (ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, file, key_password) == SSL_OK); +} + +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ssl_ctx, int len, const uint8_t *d) +{ + return (ssl_obj_memory_load(ssl_ctx, + SSL_OBJ_X509_CERT, d, len, NULL) == SSL_OK); +} + +int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx, + unsigned int sid_ctx_len) +{ + return 1; +} + +int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) +{ + return 1; +} + +int SSL_CTX_use_certificate_chain_file(SSL_CTX *ssl_ctx, const char *file) +{ + return (ssl_obj_load(ssl_ctx, + SSL_OBJ_X509_CERT, file, NULL) == SSL_OK); +} + +int SSL_shutdown(SSL *ssl) +{ + return 1; +} + +/*** get/set session ***/ +SSL_SESSION *SSL_get1_session(SSL *ssl) +{ + return (SSL_SESSION *)ssl_get_session_id(ssl); /* note: wrong cast */ +} + +int SSL_set_session(SSL *ssl, SSL_SESSION *session) +{ + memcpy(ssl->session_id, (uint8_t *)session, SSL_SESSION_ID_SIZE); + return 1; +} + +void SSL_SESSION_free(SSL_SESSION *session) { } +/*** end get/set session ***/ + +long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) +{ + return 0; +} + +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, + int (*verify_callback)(int, void *)) { + if (mode & SSL_VERIFY_PEER) { + ctx->options &= ~SSL_SERVER_VERIFY_LATER; + ctx->options |= SSL_CLIENT_AUTHENTICATION; + } else { + ctx->options |= SSL_SERVER_VERIFY_LATER; + ctx->options &= ~SSL_CLIENT_AUTHENTICATION; + } +} + +void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth) { } + +int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, + const char *CApath) +{ + return 1; +} + +void *SSL_load_client_CA_file(const char *file) +{ + return (void *)file; +} + +void SSL_CTX_set_client_CA_list(SSL_CTX *ssl_ctx, void *file) +{ + + ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, (const char *)file, NULL); +} + +void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, void *cb) { } + +void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u) +{ + key_password = (char *)u; +} + +int SSL_peek(SSL *ssl, void *buf, int num) +{ + memcpy(buf, ssl->bm_data, num); + return num; +} + +void SSL_set_bio(SSL *ssl, void *rbio, void *wbio) { } + +long SSL_get_verify_result(const SSL *ssl) +{ + return ssl_handshake_status(ssl); +} + +int SSL_state(SSL *ssl) +{ + return 0x03; // ok state +} + +/** end of could do better list */ + +void *SSL_get_peer_certificate(const SSL *ssl) +{ + return &ssl->ssl_ctx->certs[0]; +} + +int SSL_clear(SSL *ssl) +{ + return 1; +} + + +int SSL_CTX_check_private_key(const SSL_CTX *ctx) +{ + return 1; +} + +int SSL_CTX_set_cipher_list(SSL_CTX *s, const char *str) +{ + return 1; +} + +int SSL_get_error(const SSL *ssl, int ret) +{ + ssl_display_error(ret); + return ret; /* TODO: return proper return code */ +} + +void SSL_CTX_set_options(SSL_CTX *ssl_ctx, int option) {} +int SSL_library_init(void ) { return 1; } +void SSL_load_error_strings(void ) {} +void ERR_print_errors_fp(FILE *fp) {} + +long SSL_CTX_get_timeout(const SSL_CTX *ssl_ctx) { + return CONFIG_SSL_EXPIRY_TIME*3600; } +long SSL_CTX_set_timeout(SSL_CTX *ssl_ctx, long t) { + return SSL_CTX_get_timeout(ssl_ctx); } +void BIO_printf(FILE *f, const char *format, ...) +{ + va_list(ap); + va_start(ap, format); + vfprintf(f, format, ap); + va_end(ap); +} + +void* BIO_s_null(void) { return NULL; } +FILE *BIO_new(bio_func_type_t func) +{ + if (func == BIO_s_null) + return fopen("/dev/null", "r"); + else + return NULL; +} + +FILE *BIO_new_fp(FILE *stream, int close_flag) { return stream; } +int BIO_free(FILE *a) { if (a != stdout && a != stderr) fclose(a); return 1; } diff --git a/libs/luci-lib-nixio/src/axtls-compat.h b/libs/luci-lib-nixio/src/axtls-compat.h new file mode 100644 index 000000000..aee24f56c --- /dev/null +++ b/libs/luci-lib-nixio/src/axtls-compat.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the axTLS project 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. + */ + +/* + * Enable a subset of openssl compatible functions. We don't aim to be 100% + * compatible - just to be able to do basic ports etc. + * + * Only really tested on mini_httpd, so I'm not too sure how extensive this + * port is. + */ + +#include "nixio.h" +#include "config.h" + +#define WITH_AXTLS 1 +#define WITHOUT_OPENSSL 1 +#define SSL_OP_NO_SSLv3 0x02000000L +#define SSL_OP_NO_SSLv2 0x01000000L +#define SSL_FILETYPE_PEM 1 +#define SSL_FILETYPE_ASN1 2 +#define SSL_VERIFY_NONE 0x00 +#define SSL_VERIFY_PEER 0x01 +#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02 +#define SSL_VERIFY_CLIENT_ONCE 0x03 +#define MD5_DIGEST_LENGTH 16 +#define SHA_DIGEST_LENGTH 20 + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include "ssl.h" + +typedef SHA1_CTX SHA_CTX; + +void *SSLv23_server_method(void); +void *SSLv3_server_method(void); +void *TLSv1_server_method(void); +void *SSLv23_client_method(void); +void *SSLv3_client_method(void); +void *TLSv1_client_method(void); +void *SSLv23_method(void); +void *TLSv1_method(void); + + +typedef void * (*ssl_func_type_t)(void); +typedef void * (*bio_func_type_t)(void); + +SSL_CTX * SSL_CTX_new(void *meth); +void SSL_CTX_free(SSL_CTX * ssl_ctx); +SSL * SSL_new(SSL_CTX *ssl_ctx); +int SSL_set_fd(SSL *s, int fd); +int SSL_accept(SSL *ssl); +int SSL_connect(SSL *ssl); +void SSL_free(SSL *ssl); +int SSL_read(SSL *ssl, void *buf, int num); +int SSL_write(SSL *ssl, const void *buf, int num); +int SSL_CTX_use_certificate_file(SSL_CTX *ssl_ctx, const char *file, int type); +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ssl_ctx, const char *file, int type); +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ssl_ctx, int len, const uint8_t *d); +int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx, + unsigned int sid_ctx_len); +int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); +int SSL_CTX_use_certificate_chain_file(SSL_CTX *ssl_ctx, const char *file); +int SSL_shutdown(SSL *ssl); + +/*** get/set session ***/ +SSL_SESSION *SSL_get1_session(SSL *ssl); +int SSL_set_session(SSL *ssl, SSL_SESSION *session); +void SSL_SESSION_free(SSL_SESSION *session); +/*** end get/set session ***/ + +long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg); +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, + int (*verify_callback)(int, void *)); + +void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth); + +int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, + const char *CApath); + +void *SSL_load_client_CA_file(const char *file); + +void SSL_CTX_set_client_CA_list(SSL_CTX *ssl_ctx, void *file); + +void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, void *cb); + +void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u); + +int SSL_peek(SSL *ssl, void *buf, int num); + +void SSL_set_bio(SSL *ssl, void *rbio, void *wbio); + +long SSL_get_verify_result(const SSL *ssl); + +int SSL_state(SSL *ssl); + +/** end of could do better list */ + +void *SSL_get_peer_certificate(const SSL *ssl); + +int SSL_clear(SSL *ssl); + + +int SSL_CTX_check_private_key(const SSL_CTX *ctx); + +int SSL_CTX_set_cipher_list(SSL_CTX *s, const char *str); + +int SSL_get_error(const SSL *ssl, int ret); + +void SSL_CTX_set_options(SSL_CTX *ssl_ctx, int option); +int SSL_library_init(void ); +void SSL_load_error_strings(void ); +void ERR_print_errors_fp(FILE *fp); + +long SSL_CTX_get_timeout(const SSL_CTX *ssl_ctx); +long SSL_CTX_set_timeout(SSL_CTX *ssl_ctx, long t); +void BIO_printf(FILE *f, const char *format, ...); + +void* BIO_s_null(void); +FILE *BIO_new(bio_func_type_t func); + +FILE *BIO_new_fp(FILE *stream, int close_flag); +int BIO_free(FILE *a); diff --git a/libs/luci-lib-nixio/src/binary.c b/libs/luci-lib-nixio/src/binary.c new file mode 100644 index 000000000..2c4162228 --- /dev/null +++ b/libs/luci-lib-nixio/src/binary.c @@ -0,0 +1,313 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include <stdlib.h> + +const char nixio__bin2hex[16] = { +'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' +}; + +static unsigned char nixio__b64encode_tbl[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static unsigned char nixio__b64decode_tbl[] = { + 0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33 +}; + +static const uint32_t nixio__crc32_tbl[] = { + 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U, + 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U, + 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U, + 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU, + 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U, + 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U, + 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U, + 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU, + 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U, + 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU, + 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U, + 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U, + 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U, + 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU, + 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU, + 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U, + 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU, + 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U, + 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U, + 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U, + 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU, + 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U, + 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U, + 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU, + 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U, + 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U, + 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U, + 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U, + 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U, + 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU, + 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU, + 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U, + 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U, + 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU, + 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU, + 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U, + 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU, + 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U, + 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU, + 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U, + 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU, + 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U, + 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U, + 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU, + 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U, + 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U, + 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U, + 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U, + 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U, + 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U, + 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU, + 0x2d02ef8dU +}; + +static int nixio_bin_crc32(lua_State *L) { + size_t len; + const char *buffer = luaL_checklstring(L, 1, &len); + uint32_t value = luaL_optinteger(L, 2, 0); + + value = ~value; + for (size_t i=0; i<len; i++) { + value = nixio__crc32_tbl[(value ^ buffer[i]) & 0xffU ] ^ (value >> 8); + } + + lua_pushinteger(L, (int)(value ^ 0xffffffffU)); + return 1; +} + +static int nixio_bin_hexlify(lua_State *L) { + size_t len, lenout; + luaL_checktype(L, 1, LUA_TSTRING); + const unsigned char *data = (unsigned char*)lua_tolstring(L, 1, &len); + + if (len == 0) { + lua_pushvalue(L, 1); + return 1; + } + + lenout = len * 2; + luaL_argcheck(L, lenout > len, 1, "size overflow"); + + char *out = malloc(lenout); + if (!out) { + return luaL_error(L, NIXIO_OOM); + } + + for (size_t i=0; i < len; i++) { + out[2*i] = nixio__bin2hex[(data[i] & 0xf0) >> 4]; + out[2*i+1] = nixio__bin2hex[(data[i] & 0x0f)]; + } + + lua_pushlstring(L, out, lenout); + free(out); + + return 1; +} + + +static int nixio_bin_unhexlify(lua_State *L) { + size_t len, lenout; + const char *data = luaL_checklstring(L, 1, &len); + + if (len == 0) { + lua_pushvalue(L, 1); + return 1; + } else if (len % 2) { + errno = EINVAL; + return nixio__perror(L); + } + + lenout = len / 2; + char *out = malloc(lenout); + if (!out) { + return luaL_error(L, NIXIO_OOM); + } + + for (size_t i=0; i < lenout; i++) { + char c = data[2*i]; + if (c >= '0' && c <= '9') { + out[i] = (c - '0') << 4; + } else if (c >= 'a' && c <= 'f') { + out[i] = (c - 'a' + 10) << 4; + } else if (data[2*i] >= 'A' && c <= 'F') { + out[i] = (c - 'A' + 10) << 4; + } else { + free(out); + errno = EINVAL; + return nixio__perror(L); + } + + c = data[2*i+1]; + if (c >= '0' && c <= '9') { + out[i] += c - '0'; + } else if (c >= 'a' && c <= 'f') { + out[i] += c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + out[i] += c - 'A' + 10; + } else { + free(out); + errno = EINVAL; + return nixio__perror(L); + } + } + + lua_pushlstring(L, out, lenout); + free(out); + + return 1; +} + +static int nixio_bin_b64encode(lua_State *L) { + size_t len, lenout, pad, i; + const uint8_t *data = (const uint8_t*)luaL_checklstring(L, 1, &len); + + lenout = len / 3; + lenout *= 4; + + pad = len % 3; + + if (len == 0) { + lua_pushvalue(L, 1); + return 1; + } else if (pad) { + lenout += 4; + } + + luaL_argcheck(L, lenout > len, 1, "size overflow"); + + char *out = malloc(lenout); + if (!out) { + return luaL_error(L, NIXIO_OOM); + } + + uint8_t *o = (uint8_t*)out; + for (i = 0; i < len; i += 3) { + uint32_t cv = (data[i] << 16) | (data[i+1] << 8) | data[i+2]; + *(o+3) = nixio__b64encode_tbl[ cv & 0x3f]; + *(o+2) = nixio__b64encode_tbl[(cv >> 6) & 0x3f]; + *(o+1) = nixio__b64encode_tbl[(cv >> 12) & 0x3f]; + *o = nixio__b64encode_tbl[(cv >> 18) & 0x3f]; + o += 4; + } + + if (pad) { + uint32_t cv = data[len-pad] << 16; + *(o-1) = '='; + *(o-2) = '='; + if (pad == 2) { + cv |= data[len-pad+1] << 8; + *(o-2) = nixio__b64encode_tbl[(cv >> 6) & 0x3f]; + } + *(o-3) = nixio__b64encode_tbl[(cv >> 12) & 0x3f]; + *(o-4) = nixio__b64encode_tbl[(cv >> 18) & 0x3f]; + } + + lua_pushlstring(L, out, lenout); + free(out); + return 1; +} + +static int nixio_bin_b64decode(lua_State *L) { + size_t len, lenout, i; + const char *dt = luaL_checklstring(L, 1, &len); + + if (len == 0) { + lua_pushvalue(L, 1); + return 1; + } else if (len % 4) { + errno = EINVAL; + return nixio__perror(L); + } + + lenout = len / 4 * 3; + + unsigned char *out = malloc(lenout); + if (!out) { + return luaL_error(L, NIXIO_OOM); + } + + unsigned char *o = out; + for (i = 0; i < len; i += 4) { + uint32_t cv = 0; + for (int j = 0; j < 4; j++) { + unsigned char c = dt[i + j] - 43; + if (c > 79 || (c = nixio__b64decode_tbl[c]) == 0xff) { + free(out); + errno = EINVAL; + return nixio__perror(L); + } + + cv |= c; + if (j != 3) { + cv <<= 6; + } + } + + *(o+2) = (unsigned char)(cv & 0xff); + *(o+1) = (unsigned char)((cv >> 8) & 0xff); + *o = (unsigned char)((cv >> 16) & 0xff); + o += 3; + } + + if (dt[len-1] == '=') { + lenout--; + } + + if (dt[len-2] == '=') { + lenout--; + } + + lua_pushlstring(L, (char*)out, lenout); + free(out); + return 1; +} + +/* module table */ +static const luaL_reg R[] = { + {"hexlify", nixio_bin_hexlify}, + {"unhexlify", nixio_bin_unhexlify}, + {"crc32", nixio_bin_crc32}, + {"b64encode", nixio_bin_b64encode}, + {"b64decode", nixio_bin_b64decode}, + {NULL, NULL} +}; + + +void nixio_open_bin(lua_State *L) { + lua_newtable(L); + luaL_register(L, NULL, R); + lua_setfield(L, -2, "bin"); +} diff --git a/libs/luci-lib-nixio/src/bind.c b/libs/luci-lib-nixio/src/bind.c new file mode 100644 index 000000000..68e1df8a8 --- /dev/null +++ b/libs/luci-lib-nixio/src/bind.c @@ -0,0 +1,293 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include <sys/types.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + + +/** + * connect()/bind() shortcut + */ +static int nixio__bind_connect(lua_State *L, int do_bind) { + const char *host = NULL; + if (!lua_isnoneornil(L, 1)) { + host = luaL_checklstring(L, 1, NULL); + } + const char *port = luaL_checklstring(L, 2, NULL); + const char *family = luaL_optlstring(L, 3, "any", NULL); + const char *socktype = luaL_optlstring(L, 4, "stream", NULL); + + struct addrinfo hints, *result, *rp; + memset(&hints, 0, sizeof(hints)); + + if (!strcmp(family, "any")) { + hints.ai_family = AF_UNSPEC; + } else if (!strcmp(family, "inet")) { + hints.ai_family = AF_INET; + } else if (!strcmp(family, "inet6")) { + hints.ai_family = AF_INET6; + } else { + return luaL_argerror(L, 3, "supported values: any, inet, inet6"); + } + + if (!strcmp(socktype, "any")) { + hints.ai_socktype = 0; + } else if (!strcmp(socktype, "stream")) { + hints.ai_socktype = SOCK_STREAM; + } else if (!strcmp(socktype, "dgram")) { + hints.ai_socktype = SOCK_DGRAM; + } else { + return luaL_argerror(L, 4, "supported values: any, stream, dgram"); + } + + if (do_bind) { + hints.ai_flags |= AI_PASSIVE; + } + + hints.ai_protocol = 0; + + int aistat = getaddrinfo(host, port, &hints, &result); + if (aistat) { + lua_pushnil(L); + lua_pushinteger(L, aistat); + lua_pushstring(L, gai_strerror(aistat)); + return 3; + } + + /* create socket object */ + nixio_sock *sock = lua_newuserdata(L, sizeof(nixio_sock)); + int status = -1, clstat; + + for (rp = result; rp != NULL; rp = rp->ai_next) { + sock->fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sock->fd == -1) { + continue; + } + + if (do_bind) { + int one = 1; + setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, + (char*)&one, sizeof(one)); + status = bind(sock->fd, rp->ai_addr, rp->ai_addrlen); + } else { + do { + status = connect(sock->fd, rp->ai_addr, rp->ai_addrlen); + } while (status == -1 && errno == EINTR); + } + + /* on success */ + if (!status) { + sock->domain = rp->ai_family; + sock->type = rp->ai_socktype; + sock->protocol = rp->ai_protocol; + break; + } + + do { +#ifndef __WINNT__ + clstat = close(sock->fd); +#else + clstat = closesocket(sock->fd); +#endif + } while (clstat == -1 && errno == EINTR); + } + + freeaddrinfo(result); + + /* on failure */ + if (status) { + return nixio__perror_s(L); + } + + luaL_getmetatable(L, NIXIO_META); + lua_setmetatable(L, -2); + + return 1; +} + +/** + * bind(host, port, [family=any], [type=any]) shortcut + */ +static int nixio_bind(lua_State *L) { + return nixio__bind_connect(L, 1); +} + +/** + * connect(host, port, [family=any], [type=any]) shortcut + */ +static int nixio_connect(lua_State *L) { + return nixio__bind_connect(L, 0); +} + +/** + * bind()/connect() helper + */ +static int nixio_sock__bind_connect(lua_State *L, int do_bind) { + nixio_sock *sock = nixio__checksock(L); + int status = -1; + + if (sock->domain == AF_INET || sock->domain == AF_INET6) { + const char *host = NULL; + if (!lua_isnoneornil(L, 2)) { + host = luaL_checklstring(L, 2, NULL); + } + const char *port = luaL_checklstring(L, 3, NULL); + + struct addrinfo hints, *result, *rp; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = sock->domain; + hints.ai_socktype = sock->type; + hints.ai_protocol = sock->protocol; + + if (do_bind) { + hints.ai_flags |= AI_PASSIVE; + } + + int aistat = getaddrinfo(host, port, &hints, &result); + if (aistat) { + lua_pushnil(L); + lua_pushinteger(L, aistat); + lua_pushstring(L, gai_strerror(aistat)); + return 3; + } + + for (rp = result; rp != NULL; rp = rp->ai_next) { + if (do_bind) { + status = bind(sock->fd, rp->ai_addr, rp->ai_addrlen); + } else { + do { + status = connect(sock->fd, rp->ai_addr, rp->ai_addrlen); + } while (status == -1 && errno == EINTR); + } + + /* on success */ + if (!status || errno == EINPROGRESS) { + break; + } + } + + freeaddrinfo(result); +#ifndef __WINNT__ + } else if (sock->domain == AF_UNIX) { + size_t pathlen; + const char *path = luaL_checklstring(L, 2, &pathlen); + + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + luaL_argcheck(L, pathlen <= sizeof(addr.sun_path), 2, "out of range"); + memcpy(addr.sun_path, path, pathlen); + socklen_t alen = sizeof(sa_family_t) + pathlen; + + if (do_bind) { + status = bind(sock->fd, (struct sockaddr*)&addr, alen); + } else { + do { + status = connect(sock->fd, (struct sockaddr*)&addr, alen); + } while (status == -1 && errno == EINTR); + } +#endif + } else { + return luaL_error(L, "not supported"); + } + return nixio__pstatus_s(L, !status); +} + +/** + * bind() + */ +static int nixio_sock_bind(lua_State *L) { + return nixio_sock__bind_connect(L, 1); +} + +/** + * connect() + */ +static int nixio_sock_connect(lua_State *L) { + return nixio_sock__bind_connect(L, 0); +} + +/** + * listen() + */ +static int nixio_sock_listen(lua_State *L) { + int sockfd = nixio__checksockfd(L); + int backlog = luaL_checkinteger(L, 2); + return nixio__pstatus_s(L, !listen(sockfd, backlog)); +} + +/** + * accept() + */ +static int nixio_sock_accept(lua_State *L) { + nixio_sock *sock = nixio__checksock(L); + struct sockaddr_storage saddr; + nixio_addr addr; + socklen_t saddrlen = sizeof(saddr); + int newfd; + + do { + newfd = accept(sock->fd, (struct sockaddr *)&saddr, &saddrlen); + } while (newfd == -1 && errno == EINTR); + if (newfd < 0) { + return nixio__perror_s(L); + } + + /* create userdata */ + nixio_sock *clsock = lua_newuserdata(L, sizeof(nixio_sock)); + luaL_getmetatable(L, NIXIO_META); + lua_setmetatable(L, -2); + + memcpy(clsock, sock, sizeof(clsock)); + clsock->fd = newfd; + + if (!nixio__addr_parse(&addr, (struct sockaddr *)&saddr)) { + lua_pushstring(L, addr.host); + lua_pushinteger(L, addr.port); + return 3; + } else { + return 1; + } +} + +/* module table */ +static const luaL_reg R[] = { + {"bind", nixio_bind}, + {"connect", nixio_connect}, + {NULL, NULL} +}; + +/* object table */ +static const luaL_reg M[] = { + {"bind", nixio_sock_bind}, + {"connect", nixio_sock_connect}, + {"listen", nixio_sock_listen}, + {"accept", nixio_sock_accept}, + {NULL, NULL} +}; + +void nixio_open_bind(lua_State *L) { + luaL_register(L, NULL, R); + + lua_pushvalue(L, -2); + luaL_register(L, NULL, M); + lua_pop(L, 1); +} diff --git a/libs/luci-lib-nixio/src/bit.c b/libs/luci-lib-nixio/src/bit.c new file mode 100644 index 000000000..1b352c51c --- /dev/null +++ b/libs/luci-lib-nixio/src/bit.c @@ -0,0 +1,149 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include <stdint.h> +#include <stdlib.h> + +/* 52 bit maximum precision */ +#ifdef NIXIO_DOUBLE +#define NIXIO_BIT_BMAX 52 +#define NIXIO_BIT_NMAX 0xfffffffffffff +#else +#define NIXIO_BIT_BMAX 32 +#define NIXIO_BIT_NMAX 0xffffffff +#endif + +#define NIXIO_BIT_XOP(BIT_XOP) \ + uint64_t oper = nixio__checknumber(L, 1); \ + const int args = lua_gettop(L); \ + \ + for (int i = 2; i <= args; i++) { \ + uint64_t oper2 = nixio__checknumber(L, i); \ + oper BIT_XOP oper2; \ + } \ + \ + nixio__pushnumber(L, oper); \ + return 1; \ + + +static int nixio_bit_or(lua_State *L) { + NIXIO_BIT_XOP(|=); +} + +static int nixio_bit_and(lua_State *L) { + NIXIO_BIT_XOP(&=); +} + +static int nixio_bit_xor(lua_State *L) { + NIXIO_BIT_XOP(^=); +} + +static int nixio_bit_unset(lua_State *L) { + NIXIO_BIT_XOP(&= ~); +} + +static int nixio_bit_not(lua_State *L) { + nixio__pushnumber(L, + (~((uint64_t)nixio__checknumber(L, 1))) & NIXIO_BIT_NMAX); + return 1; +} + +static int nixio_bit_shl(lua_State *L) { + uint64_t oper = nixio__checknumber(L, 1); + oper <<= luaL_checkinteger(L, 2); + if (oper > NIXIO_BIT_NMAX) { + return luaL_error(L, "arithmetic overflow"); + } else { + nixio__pushnumber(L, oper); + return 1; + } +} + +static int nixio_bit_ashr(lua_State *L) { + int64_t oper = nixio__checknumber(L, 1); + nixio__pushnumber(L, oper >> luaL_checkinteger(L, 2)); + return 1; +} + +static int nixio_bit_shr(lua_State *L) { + uint64_t oper = nixio__checknumber(L, 1); + nixio__pushnumber(L, oper >> luaL_checkinteger(L, 2)); + return 1; +} + +static int nixio_bit_div(lua_State *L) { + uint64_t oper = luaL_checknumber(L, 1); + const int args = lua_gettop(L); + + for (int i = 2; i <= args; i++) { + uint64_t oper2 = nixio__checknumber(L, i); + oper /= oper2; + } + + nixio__pushnumber(L, oper); + return 1; +} + +static int nixio_bit_check(lua_State *L) { + uint64_t oper = nixio__checknumber(L, 1); + uint64_t oper2 = nixio__checknumber(L, 2); + lua_pushboolean(L, (oper & oper2) == oper2); + return 1; +} + +static int nixio_bit_cast(lua_State *L) { + nixio__pushnumber(L, ((uint64_t)nixio__checknumber(L, 1)) & NIXIO_BIT_NMAX); + return 1; +} + +static int nixio_bit_swap(lua_State *L) { + uint64_t op = nixio__checknumber(L, 1); + op = (op >> 24) | ((op >> 8) & 0xff00) | ((op & 0xff00) << 8) | (op << 24); + nixio__pushnumber(L, op); + return 1; +} + +/* module table */ +static const luaL_reg R[] = { + {"bor", nixio_bit_or}, + {"set", nixio_bit_or}, + {"band", nixio_bit_and}, + {"bxor", nixio_bit_xor}, + {"unset", nixio_bit_unset}, + {"bnot", nixio_bit_not}, + {"rshift", nixio_bit_shr}, + {"arshift", nixio_bit_ashr}, + {"lshift", nixio_bit_shl}, + {"div", nixio_bit_div}, + {"check", nixio_bit_check}, + {"cast", nixio_bit_cast}, + {"tobit", nixio_bit_cast}, + {"bswap", nixio_bit_swap}, + {NULL, NULL} +}; + +void nixio_open_bit(lua_State *L) { + lua_newtable(L); + luaL_register(L, NULL, R); + nixio__pushnumber(L, NIXIO_BIT_BMAX); + lua_setfield(L, -2, "bits"); + nixio__pushnumber(L, NIXIO_BIT_NMAX); + lua_setfield(L, -2, "max"); + lua_setfield(L, -2, "bit"); +} diff --git a/libs/luci-lib-nixio/src/cyassl-compat.c b/libs/luci-lib-nixio/src/cyassl-compat.c new file mode 100644 index 000000000..a483119ac --- /dev/null +++ b/libs/luci-lib-nixio/src/cyassl-compat.c @@ -0,0 +1,31 @@ +#include "cyassl-compat.h" + +int MD5_Init(MD5_CTX *md5) { + InitMd5(md5); + return 1; +} + +int MD5_Update(MD5_CTX *md5, void *input, unsigned long sz) { + Md5Update(md5, input, (word32)sz); + return 1; +} + +int MD5_Final(void *input, MD5_CTX *md5) { + Md5Final(md5, input); + return 1; +} + +int SHA1_Init(SHA_CTX *sha) { + InitSha(sha); + return 1; +} + +int SHA1_Update(SHA_CTX *sha, void *input, unsigned long sz) { + ShaUpdate(sha, input, (word32)sz); + return 1; +} + +int SHA1_Final(void *input, SHA_CTX *sha) { + ShaFinal(sha, input); + return 1; +} diff --git a/libs/luci-lib-nixio/src/cyassl-compat.h b/libs/luci-lib-nixio/src/cyassl-compat.h new file mode 100644 index 000000000..b2cdc9233 --- /dev/null +++ b/libs/luci-lib-nixio/src/cyassl-compat.h @@ -0,0 +1,32 @@ +#define WITH_CYASSL +#define WITHOUT_OPENSSL +#include <openssl/ssl.h> + +typedef unsigned int word32; + + +#define MD5_DIGEST_LENGTH 16 +typedef struct MD5_CTX { + int dummy[24]; +} MD5_CTX; + +void InitMd5(MD5_CTX*); +void Md5Update(MD5_CTX*, void*, word32); +void Md5Final(MD5_CTX*, void*); + + +#define SHA_DIGEST_LENGTH 20 +typedef struct SHA_CTX { + int dummy[24]; +} SHA_CTX; + +void InitSha(SHA_CTX*); +void ShaUpdate(SHA_CTX*, void*, word32); +void ShaFinal(SHA_CTX*, void*); + +int MD5_Init(MD5_CTX *md5); +int MD5_Update(MD5_CTX *md5, void *input, unsigned long sz); +int MD5_Final(void *input, MD5_CTX *md5); +int SHA1_Init(SHA_CTX *md5); +int SHA1_Update(SHA_CTX *sha, void *input, unsigned long sz); +int SHA1_Final(void *input, SHA_CTX *sha); diff --git a/libs/luci-lib-nixio/src/file.c b/libs/luci-lib-nixio/src/file.c new file mode 100644 index 000000000..b86e040e1 --- /dev/null +++ b/libs/luci-lib-nixio/src/file.c @@ -0,0 +1,402 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> + + +static int nixio_open(lua_State *L) { + const char *filename = luaL_checklstring(L, 1, NULL); + int flags; + + if (lua_isnoneornil(L, 2)) { + flags = O_RDONLY; + } else if (lua_isnumber(L, 2)) { + flags = lua_tointeger(L, 2); + } else if (lua_isstring(L, 2)) { + const char *str = lua_tostring(L, 2); + if (!strcmp(str, "r")) { + flags = O_RDONLY; + } else if (!strcmp(str, "r+")) { + flags = O_RDWR; + } else if (!strcmp(str, "w")) { + flags = O_WRONLY | O_CREAT | O_TRUNC; + } else if (!strcmp(str, "w+")) { + flags = O_RDWR | O_CREAT | O_TRUNC; + } else if (!strcmp(str, "a")) { + flags = O_WRONLY | O_CREAT | O_APPEND; + } else if (!strcmp(str, "a+")) { + flags = O_RDWR | O_CREAT | O_APPEND; + } else { + return luaL_argerror(L, 2, "supported values: r, r+, w, w+, a, a+"); + } + } else { + return luaL_argerror(L, 2, "open flags or string expected"); + } + + int fd; + + do { + fd = open(filename, flags, nixio__check_mode(L, 3, 0666)); + } while (fd == -1 && errno == EINTR); + if (fd == -1) { + return nixio__perror(L); + } + + int *udata = lua_newuserdata(L, sizeof(int)); + if (!udata) { + return luaL_error(L, "out of memory"); + } + + *udata = fd; + + luaL_getmetatable(L, NIXIO_FILE_META); + lua_setmetatable(L, -2); + + return 1; +} + +static int nixio_open_flags(lua_State *L) { + int mode = 0; + const int j = lua_gettop(L); + for (int i=1; i<=j; i++) { + const char *flag = luaL_checkstring(L, i); + if (!strcmp(flag, "append")) { + mode |= O_APPEND; + } else if (!strcmp(flag, "creat")) { + mode |= O_CREAT; + } else if (!strcmp(flag, "excl")) { + mode |= O_EXCL; + } else if (!strcmp(flag, "nonblock") || !strcmp(flag, "ndelay")) { +#ifndef __WINNT__ + mode |= O_NONBLOCK; +#endif + } else if (!strcmp(flag, "sync")) { +#ifndef __WINNT__ + mode |= O_SYNC; +#endif + } else if (!strcmp(flag, "trunc")) { + mode |= O_TRUNC; + } else if (!strcmp(flag, "rdonly")) { + mode |= O_RDONLY; + } else if (!strcmp(flag, "wronly")) { + mode |= O_WRONLY; + } else if (!strcmp(flag, "rdwr")) { + mode |= O_RDWR; + } else { + return luaL_argerror(L, i, "supported values: append, creat, " + "excl, nonblock, ndelay, sync, trunc"); + } + } + lua_pushinteger(L, mode); + return 1; +} + +static int nixio_dup(lua_State *L) { + int oldfd = nixio__checkfd(L, 1); + int newfd = (lua_gettop(L) > 1) ? nixio__checkfd(L, 2) : -1; + int stat = (newfd == -1) ? dup(oldfd) : dup2(oldfd, newfd); + + if (stat == -1) { + return nixio__perror(L); + } else { + if (newfd == -1) { + int *udata = lua_newuserdata(L, sizeof(int)); + if (!udata) { + return luaL_error(L, "out of memory"); + } + + *udata = stat; + luaL_getmetatable(L, NIXIO_FILE_META); + lua_setmetatable(L, -2); + } else { + lua_pushvalue(L, 2); + } + return 1; + } +} + +static int nixio_pipe(lua_State *L) { + int pipefd[2], *udata; + if (pipe(pipefd)) { + return nixio__perror(L); + } + + luaL_getmetatable(L, NIXIO_FILE_META); + udata = lua_newuserdata(L, sizeof(int)); + if (!udata) { + return luaL_error(L, "out of memory"); + } + + *udata = pipefd[0]; + lua_pushvalue(L, -2); + lua_setmetatable(L, -2); + + + udata = lua_newuserdata(L, sizeof(int)); + if (!udata) { + return luaL_error(L, "out of memory"); + } + + *udata = pipefd[1]; + lua_pushvalue(L, -3); + lua_setmetatable(L, -2); + + return 2; +} + +static int nixio_file_write(lua_State *L) { + int fd = nixio__checkfd(L, 1); + size_t len; + ssize_t sent; + const char *data = luaL_checklstring(L, 2, &len); + + if (lua_gettop(L) > 2) { + int offset = luaL_optint(L, 3, 0); + if (offset) { + if (offset < len) { + data += offset; + len -= offset; + } else { + len = 0; + } + } + + unsigned int wlen = luaL_optint(L, 4, len); + if (wlen < len) { + len = wlen; + } + } + + do { + sent = write(fd, data, len); + } while(sent == -1 && errno == EINTR); + if (sent >= 0) { + lua_pushinteger(L, sent); + return 1; + } else { + return nixio__perror(L); + } +} + +static int nixio_file_read(lua_State *L) { + int fd = nixio__checkfd(L, 1); + char buffer[NIXIO_BUFFERSIZE]; + uint req = luaL_checkinteger(L, 2); + int readc; + + /* We limit the readsize to NIXIO_BUFFERSIZE */ + req = (req > NIXIO_BUFFERSIZE) ? NIXIO_BUFFERSIZE : req; + + do { + readc = read(fd, buffer, req); + } while (readc == -1 && errno == EINTR); + + if (readc < 0) { + return nixio__perror(L); + } else { + lua_pushlstring(L, buffer, readc); + return 1; + } +} + + +static int nixio_file_seek(lua_State *L) { + int fd = nixio__checkfd(L, 1); + off_t len = (off_t)nixio__checknumber(L, 2); + int whence; + const char *whstr = luaL_optlstring(L, 3, "set", NULL); + if (!strcmp(whstr, "set")) { + whence = SEEK_SET; + } else if (!strcmp(whstr, "cur")) { + whence = SEEK_CUR; + } else if (!strcmp(whstr, "end")) { + whence = SEEK_END; + } else { + return luaL_argerror(L, 3, "supported values: set, cur, end"); + } + len = lseek(fd, len, whence); + if (len == -1) { + return nixio__perror(L); + } else { + nixio__pushnumber(L, len); + return 1; + } +} + +static int nixio_file_tell(lua_State *L) { + int fd = nixio__checkfd(L, 1); + off_t pos = lseek(fd, 0, SEEK_CUR); + if (pos < 0) { + return nixio__perror(L); + } else { + nixio__pushnumber(L, pos); + return 1; + } +} + +static int nixio_file_stat(lua_State *L) { + nixio_stat_t buf; + if (fstat(nixio__checkfd(L, 1), &buf)) { + return nixio__perror(L); + } else { + nixio__push_stat(L, &buf); + if (lua_isstring(L, 2)) { + lua_getfield(L, -1, lua_tostring(L, 2)); + } + return 1; + } +} + +static int nixio_file_sync(lua_State *L) { + int fd = nixio__checkfd(L, 1); + int stat; +#if (!defined BSD && !defined __WINNT__) + int dataonly = lua_toboolean(L, 2); + do { + stat = (dataonly) ? fdatasync(fd) : fsync(fd); + } while (stat == -1 && errno == EINTR); + return nixio__pstatus(L, !stat); +#else + do { + stat = fsync(fd); + } while (stat == -1 && errno == EINTR); + return nixio__pstatus(L, !stat); +#endif +} + +static int nixio_file_lock(lua_State *L) { + int fd = nixio__checkfd(L, 1); + const char *flag = luaL_checkstring(L, 2); + off_t len = (off_t)nixio__optnumber(L, 3, 0); + int stat; + + int cmd = 0; + if (!strcmp(flag, "lock")) { + cmd = F_LOCK; + } else if (!strcmp(flag, "tlock")) { + cmd = F_TLOCK; + } else if (!strcmp(flag, "ulock")) { + cmd = F_ULOCK; + } else if (!strcmp(flag, "test")) { + cmd = F_TEST; + } else { + return luaL_argerror(L, 2, + "supported values: lock, tlock, ulock, test"); + } + + do { + stat = lockf(fd, cmd, len); + } while (stat == -1 && errno == EINTR); + + return nixio__pstatus(L, !stat); +} + +static int nixio_file_close(lua_State *L) { + int *fdp = luaL_checkudata(L, 1, NIXIO_FILE_META); + luaL_argcheck(L, *fdp != -1, 1, "invalid file object"); + int res; + do { + res = close(*fdp); + } while (res == -1 && errno == EINTR); + *fdp = -1; + return nixio__pstatus(L, !res); +} + +static int nixio_file__gc(lua_State *L) { + int *fdp = luaL_checkudata(L, 1, NIXIO_FILE_META); + int res; + if (*fdp > 2) { + do { + res = close(*fdp); + } while (res == -1 && errno == EINTR); + *fdp = -1; + } + return 0; +} + +/** + * string representation + */ +static int nixio_file__tostring(lua_State *L) { + lua_pushfstring(L, "nixio file %d", nixio__tofd(L, 1)); + return 1; +} + +/* method table */ +static const luaL_reg M[] = { + {"write", nixio_file_write}, + {"read", nixio_file_read}, + {"tell", nixio_file_tell}, + {"seek", nixio_file_seek}, + {"stat", nixio_file_stat}, + {"sync", nixio_file_sync}, + {"lock", nixio_file_lock}, + {"close", nixio_file_close}, + {"__gc", nixio_file__gc}, + {"__tostring", nixio_file__tostring}, + {NULL, NULL} +}; + +/* module table */ +static const luaL_reg R[] = { + {"dup", nixio_dup}, + {"open", nixio_open}, + {"open_flags", nixio_open_flags}, + {"pipe", nixio_pipe}, + {NULL, NULL} +}; + +void nixio_open_file(lua_State *L) { + luaL_register(L, NULL, R); + + luaL_newmetatable(L, NIXIO_FILE_META); + luaL_register(L, NULL, M); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + + int *uin = lua_newuserdata(L, sizeof(int)); + int *uout = lua_newuserdata(L, sizeof(int)); + int *uerr = lua_newuserdata(L, sizeof(int)); + + if (!uin || !uout || !uerr) { + luaL_error(L, "out of memory"); + } + + *uin = STDIN_FILENO; + *uout = STDOUT_FILENO; + *uerr = STDERR_FILENO; + + for (int i = -4; i < -1; i++) { + lua_pushvalue(L, -4); + lua_setmetatable(L, i); + } + + lua_setfield(L, -5, "stderr"); + lua_setfield(L, -4, "stdout"); + lua_setfield(L, -3, "stdin"); + lua_setfield(L, -2, "meta_file"); +} diff --git a/libs/luci-lib-nixio/src/fs.c b/libs/luci-lib-nixio/src/fs.c new file mode 100644 index 000000000..12ca111ac --- /dev/null +++ b/libs/luci-lib-nixio/src/fs.c @@ -0,0 +1,566 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include <libgen.h> +#include <string.h> +#include <unistd.h> +#include <limits.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/time.h> +#include <dirent.h> + +/* Reads argument from given index and transforms it into a mode bitfield */ +int nixio__check_mode(lua_State *L, int idx, int def) { + if (lua_isnoneornil(L, idx) && def > 0) { + return def; + } else if (lua_isstring(L, idx) && lua_objlen(L, idx) == 9) { + int mode = 0; + const char *modestr = lua_tostring(L, idx); + int i; + for (i=0; i<9; i++) { + if (i % 3 == 0) { /* read flags */ + if (modestr[i] == 'r') { + mode |= 1 << (8 - i); + } else if (modestr[i] != '-') { + break; + } + } else if (i % 3 == 1) { /* write flags */ + if (modestr[i] == 'w') { + mode |= 1 << (8 - i); + } else if (modestr[i] != '-') { + break; + } + } else if (i == 2) { + if (modestr[i] == 'x') { + mode |= 00100; + } else if (modestr[i] == 's') { + mode |= 04100; + } else if (modestr[i] == 'S') { + mode |= 04000; + } else if (modestr[i] != '-') { + break; + } + } else if (i == 5) { + if (modestr[i] == 'x') { + mode |= 00010; + } else if (modestr[i] == 's') { + mode |= 02010; + } else if (modestr[i] == 'S') { + mode |= 02000; + } else if (modestr[i] != '-') { + break; + } + } else if (i == 8) { + if (modestr[i] == 'x') { + mode |= 00001; + } else if (modestr[i] == 't') { + mode |= 01001; + } else if (modestr[i] == 'T') { + mode |= 01000; + } else if (modestr[i] != '-') { + break; + } + } + } + if (i == 9) { /* successfully parsed */ + return mode; + } + } else if (lua_isnumber(L, idx)) { + int decmode = lua_tointeger(L, idx); + int s = (decmode % 10000) / 1000; + int u = (decmode % 1000) / 100; + int g = (decmode % 100) / 10; + int o = (decmode % 10); + + if (s>=0 && s<=7 && u>=0 && u<=7 && g>=0 && g<=7 && o>=0 && o<=7) { + return (s << 9) + (u << 6) + (g << 3) + o; + } + } + + return luaL_argerror(L, idx, "supported values: [0-7]?[0-7][0-7][0-7], " + "[-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xtT]"); +} + +/* Transforms a mode into the modestring */ +int nixio__mode_write(int mode, char *modestr) { + if (modestr) { + modestr[0] = (mode & 00400) ? 'r' : '-'; + modestr[1] = (mode & 00200) ? 'w' : '-'; + modestr[2] = ((mode & 04100) == 04100) ? 's' : + (mode & 04000) ? 'S' : (mode & 00100) ? 'x' : '-'; + modestr[3] = (mode & 00040) ? 'r' : '-'; + modestr[4] = (mode & 00020) ? 'w' : '-'; + modestr[5] = ((mode & 02010) == 02010) ? 's' : + (mode & 02000) ? 'S' : (mode & 00010) ? 'x' : '-'; + modestr[6] = (mode & 00004) ? 'r' : '-'; + modestr[7] = (mode & 00002) ? 'w' : '-'; + modestr[8] = ((mode & 01001) == 01001) ? 't' : + (mode & 01000) ? 'T' : (mode & 00001) ? 'x' : '-'; + } + + return (mode & 00007) + ((mode & 00070) >> 3) * 10 + + ((mode & 00700) >> 6) * 100 + ((mode & 07000) >> 9) * 1000; +} + +static int nixio_access(lua_State *L) { + const char *path = luaL_checkstring(L, 1); + int mode = F_OK; + + for (const char *s = luaL_optstring(L, 2, "f"); *s; s++) { + if (*s == 'r') { + mode |= R_OK; + } else if (*s == 'w') { + mode |= W_OK; + } else if (*s == 'x') { + mode |= X_OK; + } else if (*s != 'f') { + return luaL_argerror(L, 2, "supported values: [frwx]"); + } + } + + return nixio__pstatus(L, !access(path, mode)); +} + +static int nixio_basename(lua_State *L) { + const char *path = luaL_checkstring(L, 1); + char base[PATH_MAX]; + base[PATH_MAX-1] = 0; + + strncpy(base, path, PATH_MAX-1); + lua_pushstring(L, basename(base)); + return 1; +} + +static int nixio_dirname(lua_State *L) { + const char *path = luaL_checkstring(L, 1); + char base[PATH_MAX]; + base[PATH_MAX-1] = 0; + + strncpy(base, path, PATH_MAX-1); + lua_pushstring(L, dirname(base)); + return 1; +} + +static int nixio_realpath(lua_State *L) { + const char *path = luaL_checkstring(L, 1); + char real[PATH_MAX]; + + if (!realpath(path, real)) { + return nixio__perror(L); + } else { + lua_pushstring(L, real); + return 1; + } +} + +static int nixio_remove(lua_State *L) { + return nixio__pstatus(L, !remove(luaL_checkstring(L, 1))); +} + +static int nixio_unlink(lua_State *L) { + return nixio__pstatus(L, !unlink(luaL_checkstring(L, 1))); +} + +static int nixio_rename(lua_State *L) { + return nixio__pstatus(L, + !rename(luaL_checkstring(L, 1), luaL_checkstring(L, 2))); +} + +static int nixio_rmdir(lua_State *L) { + return nixio__pstatus(L, !rmdir(luaL_checkstring(L, 1))); +} + +static int nixio_mkdir(lua_State *L) { + return nixio__pstatus(L, + !mkdir(luaL_checkstring(L, 1), nixio__check_mode(L, 2, 0777))); +} + +static int nixio_chmod(lua_State *L) { + return nixio__pstatus(L, + !chmod(luaL_checkstring(L, 1), nixio__check_mode(L, 2, -1))); +} + +static int nixio_dir__gc(lua_State *L) { + DIR **dirp = lua_touserdata(L, 1); + if (dirp && *dirp) { + closedir(*dirp); + *dirp = NULL; + } + return 0; +} + +static int nixio_dir__iter(lua_State *L) { + DIR **dirp = lua_touserdata(L, lua_upvalueindex(1)); + struct dirent *entry; + const char *n = NULL; + + if (*dirp) { + do { + entry = readdir(*dirp); + n = (entry) ? entry->d_name : NULL; + } while(n && n[0] == '.' && (n[1] == 0 || (n[1] == '.' && n[2] == 0))); + } + + if (n) { + lua_pushstring(L, n); + } else { + if (*dirp) { + closedir(*dirp); + *dirp = NULL; + } + lua_pushnil(L); + } + + return 1; +} + +static int nixio_dir(lua_State *L) { + const char *path = luaL_optstring(L, 1, "."); + DIR **dirp = lua_newuserdata(L, sizeof(DIR *)); + + *dirp = opendir(path); + if (!*dirp) { + return nixio__perror(L); + } else { + luaL_getmetatable(L, NIXIO_DIR_META); + lua_setmetatable(L, -2); + lua_pushcclosure(L, nixio_dir__iter, 1); + return 1; + } +} + +static int nixio_link(lua_State *L) { + return nixio__pstatus(L, + !link(luaL_checkstring(L, 1), luaL_checkstring(L, 2))); +} + +static int nixio_utimes(lua_State *L) { + const char *path = luaL_checkstring(L, 1); + if (lua_gettop(L) < 2 || (lua_isnoneornil(L, 2) && lua_isnoneornil(L, 3))) { + return nixio__pstatus(L, !utimes(path, NULL)); + } else { + double atime = nixio__checknumber(L, 2); + double mtime = nixio__optnumber(L, 3, atime); + struct timeval times[2]; + + times[0].tv_sec = atime; + times[0].tv_usec = 0; + times[1].tv_sec = mtime; + times[1].tv_usec = 0; + + return nixio__pstatus(L, !utimes(path, times)); + } +} + +int nixio__push_stat(lua_State *L, nixio_stat_t *buf) { + lua_createtable(L, 0, 15); + + lua_pushinteger(L, buf->st_dev); + lua_setfield(L, -2, "dev"); + + lua_pushinteger(L, buf->st_ino); + lua_setfield(L, -2, "ino"); + + if (S_ISREG(buf->st_mode)) { + lua_pushliteral(L, "reg"); + } else if (S_ISDIR(buf->st_mode)) { + lua_pushliteral(L, "dir"); + } else if (S_ISCHR(buf->st_mode)) { + lua_pushliteral(L, "chr"); + } else if (S_ISBLK(buf->st_mode)) { + lua_pushliteral(L, "blk"); + } else if (S_ISFIFO(buf->st_mode)) { + lua_pushliteral(L, "fifo"); + } else if (S_ISLNK(buf->st_mode)) { + lua_pushliteral(L, "lnk"); + } else if (S_ISSOCK(buf->st_mode)) { + lua_pushliteral(L, "sock"); + } else { + lua_pushliteral(L, "unknown"); + } + lua_setfield(L, -2, "type"); + + char modestr[9]; + lua_pushinteger(L, nixio__mode_write(buf->st_mode, modestr)); + lua_setfield(L, -2, "modedec"); + + lua_pushlstring(L, modestr, 9); + lua_setfield(L, -2, "modestr"); + + lua_pushinteger(L, buf->st_nlink); + lua_setfield(L, -2, "nlink"); + + lua_pushinteger(L, buf->st_uid); + lua_setfield(L, -2, "uid"); + + lua_pushinteger(L, buf->st_gid); + lua_setfield(L, -2, "gid"); + + lua_pushinteger(L, buf->st_rdev); + lua_setfield(L, -2, "rdev"); + + nixio__pushnumber(L, buf->st_size); + lua_setfield(L, -2, "size"); + + lua_pushinteger(L, buf->st_atime); + lua_setfield(L, -2, "atime"); + + lua_pushinteger(L, buf->st_mtime); + lua_setfield(L, -2, "mtime"); + + lua_pushinteger(L, buf->st_ctime); + lua_setfield(L, -2, "ctime"); + +#ifndef __WINNT__ + lua_pushinteger(L, buf->st_blksize); + lua_setfield(L, -2, "blksize"); + + lua_pushinteger(L, buf->st_blocks); + lua_setfield(L, -2, "blocks"); +#endif + + return 1; +} + +static int nixio_stat(lua_State *L) { + nixio_stat_t buf; + if (stat(luaL_checkstring(L, 1), &buf)) { + return nixio__perror(L); + } else { + nixio__push_stat(L, &buf); + if (lua_isstring(L, 2)) { + lua_getfield(L, -1, lua_tostring(L, 2)); + } + return 1; + } +} + +static int nixio_lstat(lua_State *L) { + nixio_stat_t buf; + if (stat(luaL_checkstring(L, 1), &buf)) { + return nixio__perror(L); + } else { + nixio__push_stat(L, &buf); + if (lua_isstring(L, 2)) { + lua_getfield(L, -1, lua_tostring(L, 2)); + } + return 1; + } +} + +#ifndef __WINNT__ + +static int nixio_chown(lua_State *L) { + return nixio__pstatus(L, + !chown( + luaL_checkstring(L, 1), + lua_isnoneornil(L, 2) ? -1 : nixio__check_user(L, 2), + lua_isnoneornil(L, 3) ? -1 : nixio__check_group(L, 3) + ) + ); +} + +static int nixio_lchown(lua_State *L) { + return nixio__pstatus(L, + !lchown( + luaL_checkstring(L, 1), + lua_isnoneornil(L, 2) ? -1 : nixio__check_user(L, 2), + lua_isnoneornil(L, 3) ? -1 : nixio__check_group(L, 3) + ) + ); +} + +static int nixio_mkfifo(lua_State *L) { + return nixio__pstatus(L, + !mkfifo(luaL_checkstring(L, 1), nixio__check_mode(L, 2, -1))); +} + +static int nixio_symlink(lua_State *L) { + return nixio__pstatus(L, + !symlink(luaL_checkstring(L, 1), luaL_checkstring(L, 2))); +} + +static int nixio_readlink(lua_State *L) { + char dest[PATH_MAX]; + ssize_t res = readlink(luaL_checkstring(L, 1), dest, sizeof(dest)); + if (res < 0) { + return nixio__perror(L); + } else { + lua_pushlstring(L, dest, res); + return 1; + } +} + +#include <glob.h> + +typedef struct { + glob_t gl; + size_t pos; + int freed; +} nixio_glob_t; + +static int nixio_glob__iter(lua_State *L) { + nixio_glob_t *globres = lua_touserdata(L, lua_upvalueindex(1)); + if (!globres->freed && globres->pos < globres->gl.gl_pathc) { + lua_pushstring(L, globres->gl.gl_pathv[(globres->pos)++]); + } else { + if (!globres->freed) { + globfree(&globres->gl); + globres->freed = 1; + } + lua_pushnil(L); + } + return 1; +} + +static int nixio_glob__gc(lua_State *L) { + nixio_glob_t *globres = lua_touserdata(L, 1); + if (globres && !globres->freed) { + globres->freed = 1; + globfree(&globres->gl); + } + return 0; +} + +static int nixio_glob(lua_State *L) { + const char *pattern = luaL_optstring(L, 1, "*"); + nixio_glob_t *globres = lua_newuserdata(L, sizeof(nixio_glob_t)); + if (!globres) { + return luaL_error(L, NIXIO_OOM); + } + globres->pos = 0; + globres->freed = 0; + + int globstat = glob(pattern, 0, NULL, &globres->gl); + if (globstat == GLOB_NOMATCH) { + lua_pushcfunction(L, nixio__nulliter); + lua_pushinteger(L, 0); + } else if (globstat) { + return nixio__perror(L); + } else { + luaL_getmetatable(L, NIXIO_GLOB_META); + lua_setmetatable(L, -2); + lua_pushcclosure(L, nixio_glob__iter, 1); + lua_pushinteger(L, globres->gl.gl_pathc); + } + return 2; +} + +#include <sys/statvfs.h> + +static int nixio__push_statvfs(lua_State *L, struct statvfs *buf) { + lua_createtable(L, 0, 12); + + nixio__pushnumber(L, buf->f_bavail); + lua_setfield(L, -2, "bavail"); + + nixio__pushnumber(L, buf->f_bfree); + lua_setfield(L, -2, "bfree"); + + nixio__pushnumber(L, buf->f_blocks); + lua_setfield(L, -2, "blocks"); + + nixio__pushnumber(L, buf->f_bsize); + lua_setfield(L, -2, "bsize"); + + nixio__pushnumber(L, buf->f_frsize); + lua_setfield(L, -2, "frsize"); + + nixio__pushnumber(L, buf->f_favail); + lua_setfield(L, -2, "favail"); + + nixio__pushnumber(L, buf->f_ffree); + lua_setfield(L, -2, "ffree"); + + nixio__pushnumber(L, buf->f_files); + lua_setfield(L, -2, "files"); + + nixio__pushnumber(L, buf->f_flag); + lua_setfield(L, -2, "flag"); + + nixio__pushnumber(L, buf->f_fsid); + lua_setfield(L, -2, "fsid"); + + nixio__pushnumber(L, buf->f_namemax); + lua_setfield(L, -2, "namemax"); + + return 1; +} + +static int nixio_statvfs(lua_State *L) { + struct statvfs buf; + if (statvfs(luaL_optstring(L, 1, "."), &buf)) { + return nixio__perror(L); + } else { + return nixio__push_statvfs(L, &buf); + } +} + +#endif /* !__WINNT__ */ + + + +/* module table */ +static const luaL_reg R[] = { +#ifndef __WINNT__ + {"glob", nixio_glob}, + {"mkfifo", nixio_mkfifo}, + {"symlink", nixio_symlink}, + {"readlink", nixio_readlink}, + {"chown", nixio_chown}, + {"lchown", nixio_lchown}, + {"statvfs", nixio_statvfs}, +#endif + {"chmod", nixio_chmod}, + {"access", nixio_access}, + {"basename", nixio_basename}, + {"dir", nixio_dir}, + {"dirname", nixio_dirname}, + {"realpath", nixio_realpath}, + {"mkdir", nixio_mkdir}, + {"rmdir", nixio_rmdir}, + {"link", nixio_link}, + {"unlink", nixio_unlink}, + {"utimes", nixio_utimes}, + {"rename", nixio_rename}, + {"remove", nixio_remove}, + {"stat", nixio_stat}, + {"lstat", nixio_lstat}, + {NULL, NULL} +}; + +void nixio_open_fs(lua_State *L) { + lua_newtable(L); + luaL_register(L, NULL, R); + lua_setfield(L, -2, "fs"); + + luaL_newmetatable(L, NIXIO_DIR_META); + lua_pushcfunction(L, nixio_dir__gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); + +#ifndef __WINNT__ + luaL_newmetatable(L, NIXIO_GLOB_META); + lua_pushcfunction(L, nixio_glob__gc); + lua_setfield(L, -2, "__gc"); + lua_pop(L, 1); +#endif +} diff --git a/libs/luci-lib-nixio/src/io.c b/libs/luci-lib-nixio/src/io.c new file mode 100644 index 000000000..12d5c7df4 --- /dev/null +++ b/libs/luci-lib-nixio/src/io.c @@ -0,0 +1,225 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> + + +/** + * send() / sendto() helper + */ +static int nixio_sock__sendto(lua_State *L, int to) { + nixio_sock *sock = nixio__checksock(L); + struct sockaddr_storage addr_in; +#ifndef __WINNT__ + struct sockaddr_un addr_un; +#endif + struct sockaddr *addr = NULL; + socklen_t alen = 0; + int argoff = 2; + + if (to) { + argoff += 2; + if (sock->domain == AF_INET || sock->domain == AF_INET6) { + const char *address = luaL_checkstring(L, 3); + addr = (struct sockaddr*)&addr_in; + alen = sizeof(addr_in); + + nixio_addr naddr; + memset(&naddr, 0, sizeof(naddr)); + strncpy(naddr.host, address, sizeof(naddr.host) - 1); + naddr.port = (uint16_t)luaL_checkinteger(L, 4); + naddr.family = sock->domain; + + if (nixio__addr_write(&naddr, addr)) { + return nixio__perror_s(L); + } + } + +#ifndef __WINNT__ + else if (sock->domain == AF_UNIX) { + size_t pathlen; + const char *path = luaL_checklstring(L, 3, &pathlen); + + addr_un.sun_family = AF_UNIX; + luaL_argcheck(L, pathlen <= sizeof(addr_un.sun_path), 3, "out of range"); + memcpy(addr_un.sun_path, path, pathlen); + + addr = (struct sockaddr*)&addr_un; + alen = sizeof(sa_family_t) + pathlen; + } +#endif + } + + size_t len; + ssize_t sent; + const char *data = luaL_checklstring(L, 2, &len); + + if (lua_gettop(L) > argoff) { + int offset = luaL_optint(L, argoff + 1, 0); + if (offset) { + if (offset < len) { + data += offset; + len -= offset; + } else { + len = 0; + } + } + + unsigned int wlen = luaL_optint(L, argoff + 2, len); + if (wlen < len) { + len = wlen; + } + } + + do { + sent = sendto(sock->fd, data, len, 0, addr, alen); + } while(sent == -1 && errno == EINTR); + if (sent >= 0) { + lua_pushinteger(L, sent); + return 1; + } else { + return nixio__perror_s(L); + } +} + +/** + * send(data) + */ +static int nixio_sock_send(lua_State *L) { + return nixio_sock__sendto(L, 0); +} + +/** + * sendto(data, address, port) + */ +static int nixio_sock_sendto(lua_State *L) { + return nixio_sock__sendto(L, 1); +} + + +/** + * recv() / recvfrom() helper + */ +static int nixio_sock__recvfrom(lua_State *L, int from) { + nixio_sock *sock = nixio__checksock(L); + char buffer[NIXIO_BUFFERSIZE]; + struct sockaddr_storage addr_in; +#ifndef __WINNT__ + struct sockaddr_un addr_un; +#endif + struct sockaddr *addr = NULL; + socklen_t alen = 0; + uint req = luaL_checkinteger(L, 2); + int readc; + + if (sock->domain == AF_INET || sock->domain == AF_INET6) { + addr = (from) ? (struct sockaddr*)&addr_in : NULL; + alen = (from) ? sizeof(addr_in) : 0; + } +#ifndef __WINNT__ + else if (sock->domain == AF_UNIX) { + addr = (from) ? (struct sockaddr*)&addr_un : NULL; + alen = (from) ? sizeof(addr_un) : 0; + } +#endif + + /* We limit the readsize to NIXIO_BUFFERSIZE */ + req = (req > NIXIO_BUFFERSIZE) ? NIXIO_BUFFERSIZE : req; + + do { + readc = recvfrom(sock->fd, buffer, req, 0, addr, &alen); + } while (readc == -1 && errno == EINTR); + +#ifdef __WINNT__ + if (readc < 0) { + int e = WSAGetLastError(); + if (e == WSAECONNRESET || e == WSAECONNABORTED || e == WSAESHUTDOWN) { + readc = 0; + } + } +#endif + + if (readc < 0) { + return nixio__perror_s(L); + } else { + lua_pushlstring(L, buffer, readc); + + if (!from) { + return 1; + } + /* push address. */ + if (sock->domain == AF_INET || sock->domain == AF_INET6) { + nixio_addr naddr; + if (!nixio__addr_parse(&naddr, (struct sockaddr *)&addr_in)) { + lua_pushstring(L, naddr.host); + lua_pushinteger(L, naddr.port); + return 3; + } else { + return 1; + } + } +#ifndef __WINNT__ + else if (sock->domain == AF_UNIX && alen > sizeof(sa_family_t)) { + /* if first char is non-null then the path is not in the + abstract namespace and alen includes the trailing null */ + if (addr_un.sun_path[0]) + --alen; + lua_pushlstring(L, addr_un.sun_path, alen - sizeof(sa_family_t)); + return 2; + } +#endif + } + return 1; +} + +/** + * recv(count) + */ +static int nixio_sock_recv(lua_State *L) { + return nixio_sock__recvfrom(L, 0); +} + +/** + * recvfrom(count) + */ +static int nixio_sock_recvfrom(lua_State *L) { + return nixio_sock__recvfrom(L, 1); +} + + +/* module table */ +static const luaL_reg M[] = { + {"send", nixio_sock_send}, + {"sendto", nixio_sock_sendto}, + {"recv", nixio_sock_recv}, + {"recvfrom",nixio_sock_recvfrom}, + {"write", nixio_sock_send}, + {"read", nixio_sock_recv}, + {NULL, NULL} +}; + +void nixio_open_io(lua_State *L) { + lua_pushvalue(L, -2); + luaL_register(L, NULL, M); + lua_pop(L, 1); +} diff --git a/libs/luci-lib-nixio/src/mingw-compat.c b/libs/luci-lib-nixio/src/mingw-compat.c new file mode 100644 index 000000000..02be504a1 --- /dev/null +++ b/libs/luci-lib-nixio/src/mingw-compat.c @@ -0,0 +1,220 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/locking.h> +#include <sys/time.h> +#include <sys/utime.h> + +void nixio_open__mingw(lua_State *L) { + _fmode = _O_BINARY; + + WSADATA wsa; + + if (WSAStartup(MAKEWORD(2, 2), &wsa)) { + luaL_error(L, "Unable to initialize Winsock"); + } + + lua_newtable(L); + + NIXIO_WSA_CONSTANT(WSAEACCES); + NIXIO_WSA_CONSTANT(WSAEINTR); + NIXIO_WSA_CONSTANT(WSAEINVAL); + NIXIO_WSA_CONSTANT(WSAEBADF); + NIXIO_WSA_CONSTANT(WSAEFAULT); + NIXIO_WSA_CONSTANT(WSAEMFILE); + NIXIO_WSA_CONSTANT(WSAENAMETOOLONG); + NIXIO_WSA_CONSTANT(WSAELOOP); + NIXIO_WSA_CONSTANT(WSAEAFNOSUPPORT); + NIXIO_WSA_CONSTANT(WSAENOBUFS); + NIXIO_WSA_CONSTANT(WSAEPROTONOSUPPORT); + NIXIO_WSA_CONSTANT(WSAENOPROTOOPT); + NIXIO_WSA_CONSTANT(WSAEADDRINUSE); + NIXIO_WSA_CONSTANT(WSAENETDOWN); + NIXIO_WSA_CONSTANT(WSAENETUNREACH); + NIXIO_WSA_CONSTANT(WSAECONNABORTED); + NIXIO_WSA_CONSTANT(WSAECONNRESET); + + lua_setfield(L, -2, "const_sock"); +} + +const char* nixio__mgw_inet_ntop +(int af, const void *src, char *dst, socklen_t size) { + struct sockaddr_storage saddr; + memset(&saddr, 0, sizeof(saddr)); + + DWORD hostlen = size, sl; + if (af == AF_INET) { + struct sockaddr_in *saddr4 = (struct sockaddr_in *)&saddr; + memcpy(&saddr4->sin_addr, src, sizeof(saddr4->sin_addr)); + saddr4->sin_family = AF_INET; + saddr4->sin_port = 0; + sl = sizeof(struct sockaddr_in); + } else if (af == AF_INET6) { + struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&saddr; + memcpy(&saddr6->sin6_addr, src, sizeof(saddr6->sin6_addr)); + saddr6->sin6_family = AF_INET6; + saddr6->sin6_port = 0; + sl = sizeof(struct sockaddr_in6); + } else { + return NULL; + } + if (WSAAddressToString((struct sockaddr*)&saddr, sl, NULL, dst, &hostlen)) { + return NULL; + } + return dst; +} + +int nixio__mgw_inet_pton (int af, const char *src, void *dst) { + struct sockaddr_storage sa; + int sl = sizeof(sa); + + if (!WSAStringToAddress((char*)src, af, NULL, (struct sockaddr*)&sa, &sl)) { + if (af == AF_INET) { + struct in_addr ina = ((struct sockaddr_in *)&sa)->sin_addr; + memcpy(dst, &ina, sizeof(ina)); + return 1; + } else if (af == AF_INET6) { + struct in_addr6 ina6 = ((struct sockaddr_in6 *)&sa)->sin6_addr; + memcpy(dst, &ina6, sizeof(ina6)); + return 1; + } else { + WSASetLastError(WSAEAFNOSUPPORT); + return -1; + } + } else { + return -1; + } +} + +int nixio__mgw_nanosleep(const struct timespec *req, struct timespec *rem) { + if (rem) { + rem->tv_sec = 0; + rem->tv_nsec = 0; + } + Sleep(req->tv_sec * 1000 + req->tv_nsec * 1000000); + return 0; +} + +int nixio__mgw_poll(struct pollfd *fds, int nfds, int timeout) { + if (!fds || !nfds) { + Sleep(timeout); + return 0; + } + + struct timeval tv; + int high = 0, rf = 0, wf = 0, ef = 0; + fd_set rfds, wfds, efds; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&efds); + + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + for (int i = 0; i < nfds; i++) { + if (fds->events & POLLIN) { + FD_SET(fds->fd, &rfds); + rf++; + } + if (fds->events & POLLOUT) { + FD_SET(fds->fd, &wfds); + wf++; + } + if (fds->events & POLLERR) { + FD_SET(fds->fd, &efds); + ef++; + } + if (fds->fd > high) { + high = fds->fd; + } + } + + int stat = select(high + 1, (rf) ? &rfds : NULL, + (wf) ? &wfds : NULL, (ef) ? &efds : NULL, &tv); + if (stat < 1) { + errno = WSAGetLastError(); + return stat; + } + + high = 0; + + for (int i = 0; i < nfds; i++) { + fds->revents = 0; + if ((fds->events & POLLIN) && FD_ISSET(fds->fd, &rfds)) { + fds->revents |= POLLIN; + } + if ((fds->events & POLLOUT) && FD_ISSET(fds->fd, &wfds)) { + fds->revents |= POLLOUT; + } + if ((fds->events & POLLERR) && FD_ISSET(fds->fd, &efds)) { + fds->revents |= POLLERR; + } + if (fds->revents) { + high++; + } + } + + return high; +} + +int nixio__mgw_lockf(int fd, int cmd, off_t len) { + int stat; + if (cmd == F_LOCK) { + do { + stat = _locking(fd, _LK_LOCK, len); + } while (stat == -1 && errno == EDEADLOCK); + } else if (cmd == F_TLOCK) { + stat = _locking(fd, _LK_NBLCK, len); + } else if (cmd == F_ULOCK) { + stat = _locking(fd, _LK_UNLCK, len); + } else { + stat = -1; + errno = EINVAL; + } + return stat; +} + +char* nixio__mgw_realpath(const char *path, char *resolved) { + if (GetFullPathName(path, PATH_MAX, resolved, NULL)) { + return resolved; + } else { + errno = GetLastError(); + return NULL; + } +} + +int nixio__mgw_link(const char *oldpath, const char *newpath) { + if (!CreateHardLink(newpath, oldpath, NULL)) { + errno = GetLastError(); + return -1; + } else { + return 0; + } +} + +int nixio__mgw_utimes(const char *filename, const struct timeval times[2]) { + struct _utimbuf timebuffer; + timebuffer.actime = times[0].tv_sec; + timebuffer.modtime = times[1].tv_sec; + + return _utime(filename, &timebuffer); +} diff --git a/libs/luci-lib-nixio/src/mingw-compat.h b/libs/luci-lib-nixio/src/mingw-compat.h new file mode 100644 index 000000000..a26a4beec --- /dev/null +++ b/libs/luci-lib-nixio/src/mingw-compat.h @@ -0,0 +1,112 @@ +#ifndef NIXIO_MINGW_COMPAT_H_ +#define NIXIO_MINGW_COMPAT_H_ + +#include <winsock2.h> +#include <ws2tcpip.h> +#include <io.h> +#include <process.h> +#include <stdint.h> +#include <sys/stat.h> +#include <errno.h> + +typedef unsigned int uint; +typedef unsigned long ulong; + +#define S_ISLNK(m) 0 +#define S_ISSOCK(m) 0 + +#define EWOULDBLOCK WSAEWOULDBLOCK +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define ENOPROTOOPT WSAENOPROTOOPT + +#define SHUT_RD SD_RECEIVE +#define SHUT_WR SD_SEND +#define SHUT_RDWR SD_BOTH + +#define pipe(fds) _pipe(fds, 65536, 0) +#define fsync _commit +#define lseek lseek64 +#define stat _stati64 +#define lstat _stati64 +#define fstat _fstati64 + + +#define F_LOCK 1 +#define F_ULOCK 0 +#define F_TLOCK 2 +#define F_TEST 3 +int nixio__mgw_lockf(int fd, int cmd, off_t len); +#define lockf nixio__mgw_lockf + +const char* nixio__mgw_inet_ntop +(int af, const void *src, char *dst, socklen_t size); +#define inet_ntop nixio__mgw_inet_ntop + +int nixio__mgw_inet_pton (int af, const char *src, void *dst); +#define inet_pton nixio__mgw_inet_pton + + +#ifndef POLLIN +#define POLLIN 0x001 +#define POLLOUT 0x004 +#define POLLERR 0x008 +struct pollfd { + int fd; + short events; + short revents; +}; +#endif + +typedef int nfds_t; +int nixio__mgw_poll(struct pollfd *fds, nfds_t nfds, int timeout); +#define poll nixio__mgw_poll + + +struct timespec { + time_t tv_sec; + long tv_nsec; +}; + +int nixio__mgw_nanosleep(const struct timespec *req, struct timespec *rem); +#define nanosleep nixio__mgw_nanosleep + + +char* nixio__mgw_realpath(const char *path, char *resolved); +#define realpath nixio__mgw_realpath + + +int nixio__mgw_link(const char *oldpath, const char *newpath); +#define link nixio__mgw_link + + +int nixio__mgw_utimes(const char *filename, const struct timeval times[2]); +#define utimes nixio__mgw_utimes + + +#define setenv(k, v, o) !SetEnvironmentVariable(k, v) +#define unsetenv(k) !SetEnvironmentVariable(k, NULL) + +#define execv(p, a) execv(p, (const char* const*)a) +#define execvp(p, a) execvp(p, (const char* const*)a) +#define execve(p, a, e) execve(p, (const char* const*)a, (const char* const*)e) + +#define mkdir(p, m) mkdir(p) + + +#define nixio__perror_s(L) \ + errno = WSAGetLastError(); \ + return nixio__perror(L); + +#define nixio__pstatus_s(L, c) \ + errno = WSAGetLastError(); \ + return nixio__pstatus(L, c); + + + +#define NIXIO_WSA_CONSTANT(x) \ + lua_pushinteger(L, x); \ + lua_setfield(L, -2, #x+3); + +void nixio_open__mingw(lua_State *L); + +#endif /* NIXIO_MINGW_COMPAT_H_ */ diff --git a/libs/luci-lib-nixio/src/nixio-tls.h b/libs/luci-lib-nixio/src/nixio-tls.h new file mode 100644 index 000000000..0fac5a980 --- /dev/null +++ b/libs/luci-lib-nixio/src/nixio-tls.h @@ -0,0 +1,53 @@ +#ifndef NIXIO_TLS_H_ +#define NIXIO_TLS_H_ + +#include "nixio.h" +#include <sys/types.h> + +#ifndef WITHOUT_OPENSSL +#include <openssl/ssl.h> +#include <openssl/md5.h> +#include <openssl/sha.h> +#endif + +#define NIXIO_TLS_CTX_META "nixio.tls.ctx" +#define NIXIO_TLS_SOCK_META "nixio.tls.sock" + +typedef struct nixio_tls_socket { + SSL *socket; +#ifdef WITH_AXTLS + char connected; + size_t pbufsiz; + char *pbufpos; + char *pbuffer; +#endif +} nixio_tls_sock; + +#define NIXIO_CRYPTO_HASH_META "nixio.crypto.hash" +#define NIXIO_DIGEST_SIZE 64 +#define NIXIO_CRYPTO_BLOCK_SIZE 64 + +#define NIXIO_HASH_NONE 0 +#define NIXIO_HASH_MD5 0x01 +#define NIXIO_HASH_SHA1 0x02 + +#define NIXIO_HMAC_BIT 0x40 + +typedef int(*nixio_hash_initcb)(void *); +typedef int(*nixio_hash_updatecb)(void *, const void *, unsigned long); +typedef int(*nixio_hash_finalcb)(unsigned char *, void *); + +typedef struct nixio_hash_obj { + uint type; + unsigned char digest[NIXIO_DIGEST_SIZE]; + size_t digest_size; + unsigned char key[NIXIO_CRYPTO_BLOCK_SIZE]; + size_t key_size; + size_t block_size; + void *ctx; + nixio_hash_initcb init; + nixio_hash_updatecb update; + nixio_hash_finalcb final; +} nixio_hash; + +#endif /* NIXIO_TLS_H_ */ diff --git a/libs/luci-lib-nixio/src/nixio.c b/libs/luci-lib-nixio/src/nixio.c new file mode 100644 index 000000000..ae81c6f96 --- /dev/null +++ b/libs/luci-lib-nixio/src/nixio.c @@ -0,0 +1,240 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <signal.h> + +#define VERSION 0.4 + + +/* pushes nil, error number and errstring on the stack */ +int nixio__perror(lua_State *L) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + lua_pushboolean(L, 0); + } else { + lua_pushnil(L); + } + lua_pushinteger(L, errno); + lua_pushstring(L, strerror(errno)); + return 3; +} + +/* pushes true, if operation succeeded, otherwise call nixio__perror */ +int nixio__pstatus(lua_State *L, int condition) { + if (condition) { + lua_pushboolean(L, 1); + return 1; + } else { + return nixio__perror(L); + } +} + +/* checks whether the first argument is a socket and returns it */ +nixio_sock* nixio__checksock(lua_State *L) { + nixio_sock *sock = (nixio_sock*)luaL_checkudata(L, 1, NIXIO_META); + luaL_argcheck(L, sock->fd != -1, 1, "invalid socket object"); + return sock; +} + +/* read fd from nixio_sock object */ +int nixio__checksockfd(lua_State *L) { + return nixio__checksock(L)->fd; +} + +/* return any possible fd, otherwise error out */ +int nixio__checkfd(lua_State *L, int ud) { + int fd = nixio__tofd(L, ud); + return (fd != -1) ? fd : luaL_argerror(L, ud, "invalid file descriptor"); +} + +/* return any possible fd */ +int nixio__tofd(lua_State *L, int ud) { + void *udata = lua_touserdata(L, ud); + int fd = -1; + if (lua_getmetatable(L, ud)) { + luaL_getmetatable(L, NIXIO_META); + luaL_getmetatable(L, NIXIO_FILE_META); + luaL_getmetatable(L, LUA_FILEHANDLE); + if (lua_rawequal(L, -3, -4)) { + fd = ((nixio_sock*)udata)->fd; + } else if (lua_rawequal(L, -2, -4)) { + fd = *((int*)udata); + } else if (lua_rawequal(L, -1, -4)) { + fd = (*((FILE **)udata)) ? fileno(*((FILE **)udata)) : -1; + } + lua_pop(L, 4); + } + return fd; +} + +/* An empty iterator */ +int nixio__nulliter(lua_State *L) { + lua_pushnil(L); + return 1; +} + +static int nixio_errno(lua_State *L) { + lua_pushinteger(L, errno); + return 1; +} + +static int nixio_strerror(lua_State *L) { + lua_pushstring(L, strerror(luaL_checkinteger(L, 1))); + return 1; +} + +/* object table */ +static const luaL_reg R[] = { + {"errno", nixio_errno}, + {"strerror", nixio_strerror}, + {NULL, NULL} +}; + +/* entry point */ +NIXIO_API int luaopen_nixio(lua_State *L) { + /* create metatable */ + luaL_newmetatable(L, NIXIO_META); + + /* metatable.__index = metatable */ + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + + /* register module */ + luaL_register(L, "nixio", R); + + /* register metatable as socket_meta */ + lua_pushvalue(L, -2); + lua_setfield(L, -2, "meta_socket"); + + /* register methods */ +#ifdef __WINNT__ + nixio_open__mingw(L); +#endif + nixio_open_file(L); + nixio_open_socket(L); + nixio_open_sockopt(L); + nixio_open_bind(L); + nixio_open_address(L); + nixio_open_protoent(L); + nixio_open_poll(L); + nixio_open_io(L); + nixio_open_splice(L); + nixio_open_process(L); + nixio_open_syslog(L); + nixio_open_bit(L); + nixio_open_bin(L); + nixio_open_fs(L); + nixio_open_user(L); + +#ifndef NO_TLS + nixio_open_tls_crypto(L); + nixio_open_tls_context(L); + nixio_open_tls_socket(L); +#endif + + /* module version */ + lua_pushinteger(L, VERSION); + lua_setfield(L, -2, "version"); + + /* some constants */ + lua_newtable(L); + + lua_pushliteral(L, NIXIO_SEP); + lua_setfield(L, -2, "sep"); + + lua_pushliteral(L, NIXIO_PATHSEP); + lua_setfield(L, -2, "pathsep"); + + lua_pushinteger(L, NIXIO_BUFFERSIZE); + lua_setfield(L, -2, "buffersize"); + + NIXIO_PUSH_CONSTANT(EACCES); + NIXIO_PUSH_CONSTANT(EINTR); + NIXIO_PUSH_CONSTANT(ENOSYS); + NIXIO_PUSH_CONSTANT(EINVAL); + NIXIO_PUSH_CONSTANT(EAGAIN); + NIXIO_PUSH_CONSTANT(ENOMEM); + NIXIO_PUSH_CONSTANT(ENOENT); + NIXIO_PUSH_CONSTANT(ECHILD); + NIXIO_PUSH_CONSTANT(EIO); + NIXIO_PUSH_CONSTANT(EBADF); + NIXIO_PUSH_CONSTANT(EFAULT); + NIXIO_PUSH_CONSTANT(EFBIG); + NIXIO_PUSH_CONSTANT(ENOSPC); + NIXIO_PUSH_CONSTANT(EPIPE); + NIXIO_PUSH_CONSTANT(ESPIPE); + NIXIO_PUSH_CONSTANT(EISDIR); + NIXIO_PUSH_CONSTANT(EPERM); + NIXIO_PUSH_CONSTANT(EEXIST); + NIXIO_PUSH_CONSTANT(EMFILE); + NIXIO_PUSH_CONSTANT(ENAMETOOLONG); + NIXIO_PUSH_CONSTANT(ENFILE); + NIXIO_PUSH_CONSTANT(ENODEV); + NIXIO_PUSH_CONSTANT(EXDEV); + NIXIO_PUSH_CONSTANT(ENOTDIR); + NIXIO_PUSH_CONSTANT(ENXIO); + NIXIO_PUSH_CONSTANT(EROFS); + NIXIO_PUSH_CONSTANT(EBUSY); + NIXIO_PUSH_CONSTANT(ESRCH); + NIXIO_PUSH_CONSTANT(SIGINT); + NIXIO_PUSH_CONSTANT(SIGTERM); + NIXIO_PUSH_CONSTANT(SIGSEGV); + +#ifndef __WINNT__ + NIXIO_PUSH_CONSTANT(EALREADY); + NIXIO_PUSH_CONSTANT(EINPROGRESS); + NIXIO_PUSH_CONSTANT(EWOULDBLOCK); + NIXIO_PUSH_CONSTANT(ELOOP); + NIXIO_PUSH_CONSTANT(EOVERFLOW); + NIXIO_PUSH_CONSTANT(ETXTBSY); + NIXIO_PUSH_CONSTANT(EAFNOSUPPORT); + NIXIO_PUSH_CONSTANT(ENOBUFS); + NIXIO_PUSH_CONSTANT(EPROTONOSUPPORT); + NIXIO_PUSH_CONSTANT(ENOPROTOOPT); + NIXIO_PUSH_CONSTANT(EADDRINUSE); + NIXIO_PUSH_CONSTANT(ENETDOWN); + NIXIO_PUSH_CONSTANT(ENETUNREACH); + + NIXIO_PUSH_CONSTANT(SIGALRM); + NIXIO_PUSH_CONSTANT(SIGKILL); + NIXIO_PUSH_CONSTANT(SIGHUP); + NIXIO_PUSH_CONSTANT(SIGSTOP); + NIXIO_PUSH_CONSTANT(SIGCONT); + NIXIO_PUSH_CONSTANT(SIGCHLD); + NIXIO_PUSH_CONSTANT(SIGQUIT); + NIXIO_PUSH_CONSTANT(SIGUSR1); + NIXIO_PUSH_CONSTANT(SIGUSR2); + NIXIO_PUSH_CONSTANT(SIGIO); + NIXIO_PUSH_CONSTANT(SIGURG); + NIXIO_PUSH_CONSTANT(SIGPIPE); + + lua_pushvalue(L, -1); + lua_setfield(L, -3, "const_sock"); + + signal(SIGPIPE, SIG_IGN); +#endif /* !__WINNT__ */ + lua_setfield(L, -2, "const"); + + /* remove meta table */ + lua_remove(L, -2); + + return 1; +} diff --git a/libs/luci-lib-nixio/src/nixio.h b/libs/luci-lib-nixio/src/nixio.h new file mode 100644 index 000000000..8802e9204 --- /dev/null +++ b/libs/luci-lib-nixio/src/nixio.h @@ -0,0 +1,133 @@ +#ifndef NIXIO_H_ +#define NIXIO_H_ + +#define NIXIO_OOM "out of memory" + +#define NIXIO_META "nixio.socket" +#define NIXIO_FILE_META "nixio.file" +#define NIXIO_GLOB_META "nixio.glob" +#define NIXIO_DIR_META "nixio.dir" +#define _FILE_OFFSET_BITS 64 + +#define NIXIO_PUSH_CONSTANT(x) \ + lua_pushinteger(L, x); \ + lua_setfield(L, -2, #x); + +/* uClibc: broken as always */ +#define _LARGEFILE_SOURCE + +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> +#include <luaconf.h> + +#define NIXIO_BUFFERSIZE 8192 + +typedef struct nixio_socket { + int fd; + int domain; + int type; + int protocol; +} nixio_sock; + +typedef struct nixio_address { + int family; + char host[128]; + int port; + int prefix; +} nixio_addr; + +int nixio__perror(lua_State *L); +int nixio__pstatus(lua_State *L, int condition); + +#if defined(LUA_NUMBER_DOUBLE) || defined(LNUM_DOUBLE) || defined(LNUM_LDOUBLE) +#define NIXIO_DOUBLE 1 +#define nixio__checknumber luaL_checknumber +#define nixio__pushnumber lua_pushnumber +#define nixio__optnumber luaL_optnumber +#else +#define nixio__checknumber luaL_checkinteger +#define nixio__pushnumber lua_pushinteger +#define nixio__optnumber luaL_optinteger +#endif + + +#ifndef __WINNT__ + +#define NIXIO_API extern + +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <sys/un.h> +#include <netdb.h> +#include <poll.h> +#include <sys/stat.h> +#include <errno.h> + +#define NIXIO_SEP "/" +#define NIXIO_PATHSEP ":" + +#define nixio__perror_s nixio__perror +#define nixio__pstatus_s nixio__pstatus + +int nixio__check_group(lua_State *L, int idx); +int nixio__check_user(lua_State *L, int idx); + +typedef struct stat nixio_stat_t; + +#else /* __WINNT__ */ + +#define NIXIO_API extern __declspec(dllexport) +#define NIXIO_SEP "\\" +#define NIXIO_PATHSEP ";" +#include "mingw-compat.h" + +typedef struct _stati64 nixio_stat_t; + +#endif + +nixio_sock* nixio__checksock(lua_State *L); +int nixio__checksockfd(lua_State *L); +int nixio__checkfd(lua_State *L, int ud); +int nixio__tofd(lua_State *L, int ud); +int nixio__nulliter(lua_State *L); + +int nixio__addr_parse(nixio_addr *addr, struct sockaddr *saddr); +int nixio__addr_write(nixio_addr *addr, struct sockaddr *saddr); + +int nixio__check_mode(lua_State *L, int idx, int def); +int nixio__mode_write(int mode, char *modestr); + +int nixio__push_stat(lua_State *L, nixio_stat_t *buf); + +const char nixio__bin2hex[16]; + +/* Module functions */ +void nixio_open_file(lua_State *L); +void nixio_open_socket(lua_State *L); +void nixio_open_sockopt(lua_State *L); +void nixio_open_bind(lua_State *L); +void nixio_open_address(lua_State *L); +void nixio_open_protoent(lua_State *L); +void nixio_open_poll(lua_State *L); +void nixio_open_io(lua_State *L); +void nixio_open_splice(lua_State *L); +void nixio_open_process(lua_State *L); +void nixio_open_syslog(lua_State *L); +void nixio_open_bit(lua_State *L); +void nixio_open_bin(lua_State *L); +void nixio_open_fs(lua_State *L); +void nixio_open_user(lua_State *L); + +#ifndef NO_TLS +void nixio_open_tls_crypto(lua_State *L); +void nixio_open_tls_context(lua_State *L); +void nixio_open_tls_socket(lua_State *L); +#endif + +/* Method functions */ + +#endif /* NIXIO_H_ */ diff --git a/libs/luci-lib-nixio/src/poll.c b/libs/luci-lib-nixio/src/poll.c new file mode 100644 index 000000000..1211bc72a --- /dev/null +++ b/libs/luci-lib-nixio/src/poll.c @@ -0,0 +1,210 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include <time.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <sys/time.h> + + +static int nixio_gettimeofday(lua_State *L) { + struct timeval tv; + gettimeofday(&tv, NULL); + nixio__pushnumber(L, tv.tv_sec); + nixio__pushnumber(L, tv.tv_usec); + return 2; +} + + +/** + * nanosleep() + */ +static int nixio_nanosleep(lua_State *L) { + struct timespec req, rem; + req.tv_sec = luaL_optint(L, 1, 0); + req.tv_nsec = luaL_optint(L, 2, 0); + + int status = nanosleep(&req, &rem); + if (!status) { + lua_pushboolean(L, 1); + return 1; + } else { + if (errno == EINTR) { + lua_pushboolean(L, 0); + lua_pushinteger(L, rem.tv_sec); + lua_pushinteger(L, rem.tv_nsec); + return 3; + } else { + return nixio__perror(L); + } + } +} + +/** + * Checks whether a flag is set in the bitmap and sets the matching table value + */ +static void nixio_poll_flags__r(lua_State *L, int *map, int f, const char *t) { + lua_pushstring(L, t); + if (*map & f) { + lua_pushboolean(L, 1); + } else { + lua_pushnil(L); + } + lua_rawset(L, -3); +} + +/** + * Translate integer to poll flags and vice versa + */ +static int nixio_poll_flags(lua_State *L) { + int flags; + if (lua_isnumber(L, 1)) { + flags = luaL_checkinteger(L, 1); + lua_newtable(L); + nixio_poll_flags__r(L, &flags, POLLIN, "in"); + nixio_poll_flags__r(L, &flags, POLLOUT, "out"); + nixio_poll_flags__r(L, &flags, POLLERR, "err"); +#ifndef __WINNT__ + nixio_poll_flags__r(L, &flags, POLLPRI, "pri"); + nixio_poll_flags__r(L, &flags, POLLHUP, "hup"); + nixio_poll_flags__r(L, &flags, POLLNVAL, "nval"); +#endif + } else { + flags = 0; + const int j = lua_gettop(L); + for (int i=1; i<=j; i++) { + const char *flag = luaL_checkstring(L, i); + if (!strcmp(flag, "in")) { + flags |= POLLIN; + } else if (!strcmp(flag, "out")) { + flags |= POLLOUT; + } else if (!strcmp(flag, "err")) { + flags |= POLLERR; + } else if (!strcmp(flag, "pri")) { +#ifndef __WINNT__ + flags |= POLLPRI; +#endif + } else if (!strcmp(flag, "hup")) { +#ifndef __WINNT__ + flags |= POLLHUP; +#endif + } else if (!strcmp(flag, "nval")) { +#ifndef __WINNT__ + flags |= POLLNVAL; +#endif + } else { + return luaL_argerror(L, i, + "supported values: in, pri, out, err, hup, nval"); + } + } + lua_pushinteger(L, flags); + } + return 1; +} + +/** + * poll({{fd = socket, events = FLAGS}, ...}, timeout) + */ +static int nixio_poll(lua_State *L) { + int len = lua_objlen(L, 1); + int i, fd; + int timeout = luaL_optint(L, 2, 0); + int status = -1; + + /* we are being abused as sleep() replacement... */ + if (lua_isnoneornil(L, 1) || len < 1) { + if (!poll(NULL, 0, timeout)) { + lua_pushinteger(L, 0); + return 1; + } else { + return nixio__perror(L); + } + } + + luaL_checktype(L, 1, LUA_TTABLE); + struct pollfd *fds = calloc(len, sizeof(struct pollfd)); + if (!fds) { + return luaL_error(L, NIXIO_OOM); + } + + for (i = 0; i < len; i++) { + lua_rawgeti(L, 1, i+1); + if (!lua_istable(L, -1)) { + free(fds); + return luaL_argerror(L, 1, "invalid datastructure"); + } + + lua_pushliteral(L, "fd"); + lua_rawget(L, -2); + fd = nixio__tofd(L, -1); + if (fd == -1) { + free(fds); + return luaL_argerror(L, 1, "invalid fd in datastructure"); + } + fds[i].fd = fd; + + lua_pushliteral(L, "events"); + lua_rawget(L, -3); + fds[i].events = (short)lua_tointeger(L, -1); + + lua_pop(L, 3); + } + + status = poll(fds, (nfds_t)len, timeout); + + if (status == 0) { + free(fds); + lua_pushboolean(L, 0); + return 1; + } else if (status < 0) { + free(fds); + return nixio__perror(L); + } + + for (i = 0; i < len; i++) { + lua_rawgeti(L, 1, i+1); + + lua_pushliteral(L, "revents"); + lua_pushinteger(L, fds[i].revents); + lua_rawset(L, -3); + + lua_pop(L, 1); + } + + free(fds); + + lua_pushinteger(L, status); + lua_pushvalue(L, 1); + + return 2; +} + +/* module table */ +static const luaL_reg R[] = { + {"gettimeofday", nixio_gettimeofday}, + {"nanosleep", nixio_nanosleep}, + {"poll", nixio_poll}, + {"poll_flags", nixio_poll_flags}, + {NULL, NULL} +}; + +void nixio_open_poll(lua_State *L) { + luaL_register(L, NULL, R); +} diff --git a/libs/luci-lib-nixio/src/process.c b/libs/luci-lib-nixio/src/process.c new file mode 100644 index 000000000..5ae9b829e --- /dev/null +++ b/libs/luci-lib-nixio/src/process.c @@ -0,0 +1,450 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <signal.h> + +#define NIXIO_EXECVE 0x01 +#define NIXIO_EXECV 0x02 +#define NIXIO_EXECVP 0x03 + +int nixio__exec(lua_State *L, int m) { + const char *path = luaL_checkstring(L, 1); + const char *arg; + int argn, i; + + if (m == NIXIO_EXECVE) { + luaL_checktype(L, 2, LUA_TTABLE); + argn = lua_objlen(L, 2) + 1; + } else { + argn = lua_gettop(L); + } + + char **args = lua_newuserdata(L, sizeof(char*) * (argn + 1)); + args[argn] = NULL; + args[0] = (char *)path; + + if (m == NIXIO_EXECVE) { + for (i = 1; i < argn; i++) { + lua_rawgeti(L, 2, i); + arg = lua_tostring(L, -1); + luaL_argcheck(L, arg, 2, "invalid argument"); + args[i] = (char *)arg; + } + + if (lua_isnoneornil(L, 3)) { + execv(path, args); + } else { + luaL_checktype(L, 3, LUA_TTABLE); + argn = 0; + lua_pushnil(L); + while (lua_next(L, 3)) { + if (!lua_checkstack(L, 1)) { + lua_settop(L, 0); + return luaL_error(L, "stack overflow"); + } + + if (lua_type(L, -2) != LUA_TSTRING || !lua_isstring(L, -1)) { + return luaL_argerror(L, 3, "invalid environment"); + } + + lua_pushfstring(L, "%s=%s", + lua_tostring(L, -2), lua_tostring(L, -1)); + + lua_insert(L, 5); + lua_pop(L, 1); + argn++; + } + + char **env = lua_newuserdata(L, sizeof(char*) * (argn + 1)); + env[argn] = NULL; + + for (i = 1; i <= argn; i++) { + env[i-1] = (char *)lua_tostring(L, -(i+1)); + } + + execve(path, args, env); + } + } else { + for (i = 2; i <= argn; i++) { + arg = luaL_checkstring(L, i); + args[i-1] = (char *)arg; + } + + if (m == NIXIO_EXECV) { + execv(path, args); + } else { + execvp(path, args); + } + } + + return nixio__perror(L); +} + +#ifndef __WINNT__ +#include <sys/utsname.h> +#include <sys/times.h> +#include <sys/wait.h> +#include <pwd.h> +#include <grp.h> + +static int nixio_fork(lua_State *L) { + pid_t pid = fork(); + if (pid == -1) { + return nixio__perror(L); + } else { + lua_pushinteger(L, pid); + return 1; + } +} + +static int nixio_kill(lua_State *L) { + return nixio__pstatus(L, !kill(luaL_checkint(L, 1), luaL_checkint(L, 2))); +} + +static int nixio_getppid(lua_State *L) { + lua_pushinteger(L, getppid()); + return 1; +} + +static int nixio_getuid(lua_State *L) { + lua_pushinteger(L, getuid()); + return 1; +} + +static int nixio_getgid(lua_State *L) { + lua_pushinteger(L, getgid()); + return 1; +} + +static int nixio_setgid(lua_State *L) { + return nixio__pstatus(L, !setgid(nixio__check_group(L, 1))); +} + +static int nixio_setuid(lua_State *L) { + return nixio__pstatus(L, !setuid(nixio__check_user(L, 1))); +} + +static int nixio_nice(lua_State *L) { + int nval = luaL_checkint(L, 1); + + errno = 0; + nval = nice(nval); + + if (nval == -1 && errno) { + return nixio__perror(L); + } else { + lua_pushinteger(L, nval); + return 1; + } +} + +static int nixio_setsid(lua_State *L) { + pid_t pid = setsid(); + + if (pid == -1) { + return nixio__perror(L); + } else { + lua_pushinteger(L, pid); + return 1; + } +} + +static int nixio_wait(lua_State *L) { + pid_t pidin = luaL_optinteger(L, 1, -1), pidout; + int options = 0, status; + + const int j = lua_gettop(L); + for (int i=2; i<=j; i++) { + const char *flag = luaL_checkstring(L, i); + if (!strcmp(flag, "nohang")) { + options |= WNOHANG; + } else if (!strcmp(flag, "untraced")) { + options |= WUNTRACED; + } else if (!strcmp(flag, "continued")) { + options |= WCONTINUED; + } else { + return luaL_argerror(L, i, + "supported values: nohang, untraced, continued"); + } + } + + do { + pidout = waitpid(pidin, &status, options); + } while (pidout == -1 && errno == EINTR); + + if (pidout == 0) { + lua_pushboolean(L, 0); + return 1; + } else if (pidout == -1) { + return nixio__perror(L); + } else { + lua_pushinteger(L, pidout); + } + + if (WIFEXITED(status)) { + lua_pushliteral(L, "exited"); + lua_pushinteger(L, WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + lua_pushliteral(L, "signaled"); + lua_pushinteger(L, WTERMSIG(status)); + } else if (WIFSTOPPED(status)) { + lua_pushliteral(L, "stopped"); + lua_pushinteger(L, WSTOPSIG(status)); + } else { + return 1; + } + + return 3; +} + +static int nixio_times(lua_State *L) { + struct tms buf; + if (times(&buf) == -1) { + return nixio__perror(L); + } else { + lua_createtable(L, 0, 4); + nixio__pushnumber(L, buf.tms_cstime); + lua_setfield(L, -2, "cstime"); + + nixio__pushnumber(L, buf.tms_cutime); + lua_setfield(L, -2, "cutime"); + + nixio__pushnumber(L, buf.tms_stime); + lua_setfield(L, -2, "stime"); + + nixio__pushnumber(L, buf.tms_utime); + lua_setfield(L, -2, "utime"); + + return 1; + } +} + +static int nixio_uname(lua_State *L) { + struct utsname buf; + if (uname(&buf)) { + return nixio__perror(L); + } + + lua_createtable(L, 0, 5); + + lua_pushstring(L, buf.machine); + lua_setfield(L, -2, "machine"); + + lua_pushstring(L, buf.version); + lua_setfield(L, -2, "version"); + + lua_pushstring(L, buf.release); + lua_setfield(L, -2, "release"); + + lua_pushstring(L, buf.nodename); + lua_setfield(L, -2, "nodename"); + + lua_pushstring(L, buf.sysname); + lua_setfield(L, -2, "sysname"); + + return 1; +} + +#endif /* !__WINNT__ */ + +static int nixio_chdir(lua_State *L) { + return nixio__pstatus(L, !chdir(luaL_checkstring(L, 1))); +} + +static int nixio_signal(lua_State *L) { + int sig = luaL_checkinteger(L, 1); + const char *val = luaL_checkstring(L, 2); + + if (!strcmp(val, "ign") || !strcmp(val, "ignore")) { + return nixio__pstatus(L, signal(sig, SIG_IGN) != SIG_ERR); + } else if (!strcmp(val, "dfl") || !strcmp(val, "default")) { + return nixio__pstatus(L, signal(sig, SIG_DFL) != SIG_ERR); + } else { + return luaL_argerror(L, 2, "supported values: ign, dfl"); + } +} + +static int nixio_getpid(lua_State *L) { + lua_pushinteger(L, getpid()); + return 1; +} + +static int nixio_getenv(lua_State *L) { + const char *key = luaL_optstring(L, 1, NULL); + if (key) { + const char *val = getenv(key); + if (val) { + lua_pushstring(L, val); + } else { + lua_pushnil(L); + } + } else { + lua_newtable(L); + extern char **environ; + for (char **c = environ; *c; c++) { + const char *delim = strchr(*c, '='); + if (!delim) { + return luaL_error(L, "invalid environment"); + } + lua_pushlstring(L, *c, delim-*c); + lua_pushstring(L, delim + 1); + lua_rawset(L, -3); + } + } + return 1; +} + +static int nixio_setenv(lua_State *L) { + const char *key = luaL_checkstring(L, 1); + const char *val = luaL_optstring(L, 2, NULL); + return nixio__pstatus(L, (val) ? !setenv(key, val, 1) : !unsetenv(key)); +} + +static int nixio_exec(lua_State *L) { + return nixio__exec(L, NIXIO_EXECV); +} + +static int nixio_execp(lua_State *L) { + return nixio__exec(L, NIXIO_EXECVP); +} + +static int nixio_exece(lua_State *L) { + return nixio__exec(L, NIXIO_EXECVE); +} + +static int nixio_getcwd(lua_State *L) { + char path[PATH_MAX]; + + if (getcwd(path, sizeof(path))) { + lua_pushstring(L, path); + return 1; + } else { + return nixio__perror(L); + } +} + +static int nixio_umask(lua_State *L) { + char mask[9]; + lua_pushinteger(L, + nixio__mode_write(umask(nixio__check_mode(L, 1, -1)), mask)); + lua_pushlstring(L, mask, 9); + return 2; +} + +#ifdef __linux__ + +#include <sys/sysinfo.h> + +static int nixio_sysinfo(lua_State *L) { + struct sysinfo info; + if (sysinfo(&info)) { + return nixio__perror(L); + } + + lua_createtable(L, 0, 12); + + nixio__pushnumber(L, info.bufferram); + lua_setfield(L, -2, "bufferram"); + + nixio__pushnumber(L, info.freehigh); + lua_setfield(L, -2, "freehigh"); + + nixio__pushnumber(L, info.freeram); + lua_setfield(L, -2, "freeram"); + + nixio__pushnumber(L, info.freeswap); + lua_setfield(L, -2, "freeswap"); + + lua_createtable(L, 0, 3); + for (int i=0; i<3; i++) { + lua_pushnumber(L, info.loads[i] / 65536.); + lua_rawseti(L, -2, i+1); + } + lua_setfield(L, -2, "loads"); + + lua_pushinteger(L, info.mem_unit); + lua_setfield(L, -2, "mem_unit"); + + lua_pushinteger(L, info.procs); + lua_setfield(L, -2, "procs"); + + nixio__pushnumber(L, info.sharedram); + lua_setfield(L, -2, "sharedram"); + + nixio__pushnumber(L, info.totalhigh); + lua_setfield(L, -2, "totalhigh"); + + nixio__pushnumber(L, info.totalram); + lua_setfield(L, -2, "totalram"); + + nixio__pushnumber(L, info.totalswap); + lua_setfield(L, -2, "totalswap"); + + lua_pushinteger(L, info.uptime); + lua_setfield(L, -2, "uptime"); + + return 1; +} + +#endif + + +/* module table */ +static const luaL_reg R[] = { +#ifdef __linux__ + {"sysinfo", nixio_sysinfo}, +#endif +#ifndef __WINNT__ + {"fork", nixio_fork}, + {"kill", nixio_kill}, + {"nice", nixio_nice}, + {"getppid", nixio_getppid}, + {"getuid", nixio_getuid}, + {"getgid", nixio_getgid}, + {"setuid", nixio_setuid}, + {"setgid", nixio_setgid}, + {"setsid", nixio_setsid}, + {"wait", nixio_wait}, + {"waitpid", nixio_wait}, + {"times", nixio_times}, + {"uname", nixio_uname}, +#endif + {"chdir", nixio_chdir}, + {"signal", nixio_signal}, + {"getpid", nixio_getpid}, + {"getenv", nixio_getenv}, + {"setenv", nixio_setenv}, + {"putenv", nixio_setenv}, + {"exec", nixio_exec}, + {"execp", nixio_execp}, + {"exece", nixio_exece}, + {"getcwd", nixio_getcwd}, + {"umask", nixio_umask}, + {NULL, NULL} +}; + +void nixio_open_process(lua_State *L) { + luaL_register(L, NULL, R); +} diff --git a/libs/luci-lib-nixio/src/protoent.c b/libs/luci-lib-nixio/src/protoent.c new file mode 100644 index 000000000..bda68a584 --- /dev/null +++ b/libs/luci-lib-nixio/src/protoent.c @@ -0,0 +1,103 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2011 Jo-Philipp Wich <jow@openwrt.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" + +#ifndef __WINNT__ +#include <netdb.h> +#endif + +/** + * protoent conversion helper + */ +static int nixio__pushprotoent(lua_State *L, struct protoent *e) { + int i; + if (e) { + lua_newtable(L); + + lua_pushstring(L, e->p_name); + lua_setfield(L, -2, "name"); + + lua_pushnumber(L, e->p_proto); + lua_setfield(L, -2, "proto"); + + lua_newtable(L); + for (i = 0; e->p_aliases[i]; i++) { + lua_pushstring(L, e->p_aliases[i]); + lua_rawseti(L, -2, i+1); + } + lua_setfield(L, -2, "aliases"); + return 1; + } else { + return 0; + } +} + +/** + * getprotobyname(name) + */ +static int nixio_getprotobyname(lua_State *L) { + const char *name = luaL_checkstring(L, 1); + struct protoent *res = getprotobyname(name); + return nixio__pushprotoent(L, res); +} + +/** + * getprotobynumber(proto) + */ +static int nixio_getprotobynumber(lua_State *L) { + int proto = luaL_checkinteger(L, 1); + struct protoent *res = getprotobynumber(proto); + return nixio__pushprotoent(L, res); +} + +/** + * getproto(name_or_proto) + */ +static int nixio_getproto(lua_State *L) { + int i = 1; + struct protoent *res; + if (lua_isnumber(L, 1)) { + return nixio_getprotobynumber(L); + } else if (lua_isstring(L, 1)) { + return nixio_getprotobyname(L); + } else if (lua_isnoneornil(L, 1)) { + setprotoent(1); + lua_newtable(L); + while ((res = getprotoent()) != NULL) { + nixio__pushprotoent(L, res); + lua_rawseti(L, -2, i++); + } + endprotoent(); + return 1; + } else { + return luaL_argerror(L, 1, "supported values: <protoname>, <protonumber>"); + } +} + +/* module table */ +static const luaL_reg R[] = { + {"getprotobyname", nixio_getprotobyname}, + {"getprotobynumber", nixio_getprotobynumber}, + {"getproto", nixio_getproto}, + {NULL, NULL} +}; + +void nixio_open_protoent(lua_State *L) { + luaL_register(L, NULL, R); +} diff --git a/libs/luci-lib-nixio/src/socket.c b/libs/luci-lib-nixio/src/socket.c new file mode 100644 index 000000000..17c6afc79 --- /dev/null +++ b/libs/luci-lib-nixio/src/socket.c @@ -0,0 +1,173 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include <unistd.h> +#include <string.h> +#include <errno.h> + + +/** + * create new socket + */ +static int nixio_socket(lua_State *L) { + const char *domain = luaL_optlstring(L, 1, "", NULL); + const char *type = luaL_optlstring(L, 2, "", NULL); + const char *proto = lua_tolstring(L, 3, NULL); + + nixio_sock *sock = lua_newuserdata(L, sizeof(nixio_sock)); + if (!sock) { + return luaL_error(L, "out of memory"); + } + + if (!strcmp(domain, "inet")) { + sock->domain = AF_INET; + } else if (!strcmp(domain, "inet6")) { + sock->domain = AF_INET6; + } else if (!strcmp(domain, "unix")) { + sock->domain = AF_UNIX; + /*} else if (!strcmp(domain, "packet")) { + sock->domain = AF_PACKET;*/ + } else { + return luaL_argerror(L, 1, + "supported values: inet, inet6, unix, packet" + ); + } + + if (!strcmp(type, "stream")) { + sock->type = SOCK_STREAM; + } else if (!strcmp(type, "dgram")) { + sock->type = SOCK_DGRAM; + } else if (!strcmp(type, "raw")) { + sock->type = SOCK_RAW; + } else { + return luaL_argerror(L, 2, "supported values: stream, dgram, raw"); + } + + if (!proto) { + sock->protocol = 0; + } else if (!strcmp(proto, "icmp")) { + sock->protocol = IPPROTO_ICMP; + } else if (!strcmp(proto, "icmpv6")) { + sock->protocol = IPPROTO_ICMPV6; + } else { + return luaL_argerror(L, 3, "supported values: [empty], icmp, icmpv6"); + } + + /* create userdata */ + luaL_getmetatable(L, NIXIO_META); + lua_setmetatable(L, -2); + + sock->fd = socket(sock->domain, sock->type, sock->protocol); + + if (sock->fd < 0) { + return nixio__perror_s(L); + } + + return 1; +} + +/** + * close a socket + */ +static int nixio_sock_close(lua_State *L) { + nixio_sock *sock = nixio__checksock(L); + int sockfd = sock->fd; + int res; + sock->fd = -1; + + do { +#ifndef __WINNT__ + res = close(sockfd); +#else + res = closesocket(sockfd); +#endif + } while (res == -1 && errno == EINTR); + + return nixio__pstatus_s(L, !res); +} + +/** + * garbage collector + */ +static int nixio_sock__gc(lua_State *L) { + nixio_sock *sock = (nixio_sock*)luaL_checkudata(L, 1, NIXIO_META); + int res; + if (sock && sock->fd != -1) { + do { +#ifndef __WINNT__ + res = close(sock->fd); +#else + res = closesocket(sock->fd); +#endif + } while (res == -1 && errno == EINTR); + } + return 0; +} + +/** + * string representation + */ +static int nixio_sock__tostring(lua_State *L) { + lua_pushfstring(L, "nixio socket %d", nixio__checksockfd(L)); + return 1; +} + +/** + * shutdown a socket + */ +static int nixio_sock_shutdown(lua_State *L) { + int sockfd = nixio__checksockfd(L); + const char *what = luaL_optlstring(L, 2, "rdwr", NULL); + int how; + + if (!strcmp(what, "rdwr") || !strcmp(what, "both")) { + how = SHUT_RDWR; + } else if (!strcmp(what, "rd") || !strcmp(what, "read")) { + how = SHUT_RD; + } else if (!strcmp(what, "wr") || !strcmp(what, "write")) { + how = SHUT_WR; + } else { + return luaL_argerror(L, 2, "supported values: both, read, write"); + } + + return nixio__pstatus_s(L, !shutdown(sockfd, how)); +} + +/* module table */ +static const luaL_reg R[] = { + {"socket", nixio_socket}, + {NULL, NULL} +}; + +/* object table */ +static const luaL_reg M[] = { + {"close", nixio_sock_close}, + {"shutdown", nixio_sock_shutdown}, + {"__gc", nixio_sock__gc}, + {"__tostring", nixio_sock__tostring}, + {NULL, NULL} +}; + +void nixio_open_socket(lua_State *L) { + luaL_register(L, NULL, R); + + lua_pushvalue(L, -2); + luaL_register(L, NULL, M); + lua_pop(L, 1); +} diff --git a/libs/luci-lib-nixio/src/sockopt.c b/libs/luci-lib-nixio/src/sockopt.c new file mode 100644 index 000000000..cede884ce --- /dev/null +++ b/libs/luci-lib-nixio/src/sockopt.c @@ -0,0 +1,390 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" + +#ifndef __WINNT__ +#include <net/if.h> +#endif + +#include <sys/types.h> +#include <sys/time.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#ifndef IPV6_ADD_MEMBERSHIP +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#endif + +#ifndef IPV6_DROP_MEMBERSHIP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +#endif + +static int nixio_sock_fileno(lua_State *L) { + lua_pushinteger(L, nixio__checkfd(L, 1)); + return 1; +} + +/** + * setblocking() + */ +static int nixio_sock_setblocking(lua_State *L) { + int fd = nixio__checkfd(L, 1); + luaL_checkany(L, 2); + int set = lua_toboolean(L, 2); + +#ifndef __WINNT__ + + int flags = fcntl(fd, F_GETFL); + + if (flags == -1) { + return nixio__perror(L); + } + + if (!set) { + flags |= O_NONBLOCK; + } else { + flags &= ~O_NONBLOCK; + } + + return nixio__pstatus(L, !fcntl(fd, F_SETFL, flags)); + +#else /* __WINNT__ */ + + lua_getmetatable(L, 1); + luaL_getmetatable(L, NIXIO_META); + if (lua_equal(L, -1, -2)) { /* Socket */ + unsigned long val = !set; + return nixio__pstatus_s(L, !ioctlsocket(fd, FIONBIO, &val)); + } else { /* File */ + WSASetLastError(WSAENOTSOCK); + return nixio__perror_s(L); + } + +#endif /* __WINNT__ */ +} + +static int nixio__gso_int(lua_State *L, int fd, int level, int opt, int set) { + int value; + socklen_t optlen = sizeof(value); + if (!set) { + if (!getsockopt(fd, level, opt, (char *)&value, &optlen)) { + lua_pushinteger(L, value); + return 1; + } + } else { + value = luaL_checkinteger(L, set); + if (!setsockopt(fd, level, opt, (char *)&value, optlen)) { + lua_pushboolean(L, 1); + return 1; + } + } + return nixio__perror_s(L); +} + +static int nixio__gso_ling(lua_State *L, int fd, int level, int opt, int set) { + struct linger value; + socklen_t optlen = sizeof(value); + if (!set) { + if (!getsockopt(fd, level, opt, (char *)&value, &optlen)) { + lua_pushinteger(L, value.l_onoff ? value.l_linger : 0); + return 1; + } + } else { + value.l_linger = luaL_checkinteger(L, set); + value.l_onoff = value.l_linger ? 1 : 0; + if (!setsockopt(fd, level, opt, (char *)&value, optlen)) { + lua_pushboolean(L, 1); + return 1; + } + } + return nixio__perror_s(L); +} + +static int nixio__gso_timev(lua_State *L, int fd, int level, int opt, int set) { + struct timeval value; + socklen_t optlen = sizeof(value); + if (!set) { + if (!getsockopt(fd, level, opt, (char *)&value, &optlen)) { + lua_pushinteger(L, value.tv_sec); + lua_pushinteger(L, value.tv_usec); + return 2; + } + } else { + value.tv_sec = luaL_checkinteger(L, set); + value.tv_usec = luaL_optinteger(L, set + 1, 0); + if (!setsockopt(fd, level, opt, (char *)&value, optlen)) { + lua_pushboolean(L, 1); + return 1; + } + } + return nixio__perror_s(L); +} + +#ifdef SO_BINDTODEVICE + +static int nixio__gso_b(lua_State *L, int fd, int level, int opt, int set) { + if (!set) { + socklen_t optlen = IFNAMSIZ; + char ifname[IFNAMSIZ]; + if (!getsockopt(fd, level, opt, (char *)ifname, &optlen)) { + lua_pushlstring(L, ifname, optlen); + return 1; + } + } else { + size_t valuelen; + const char *value = luaL_checklstring(L, set, &valuelen); + luaL_argcheck(L, valuelen <= IFNAMSIZ, set, "invalid interface name"); + if (!setsockopt(fd, level, opt, (char *)value, valuelen)) { + lua_pushboolean(L, 1); + return 1; + } + } + return nixio__perror_s(L); +} + +#endif /* SO_BINDTODEVICE */ + +static int nixio__gso_mreq4(lua_State *L, int fd, int level, int opt, int set) { + struct ip_mreq value; + socklen_t optlen = sizeof(value); + if (!set) { + char buf[INET_ADDRSTRLEN]; + if (!getsockopt(fd, level, opt, (char *)&value, &optlen)) { + if (!inet_ntop(AF_INET, &value.imr_multiaddr, buf, sizeof(buf))) { + return nixio__perror_s(L); + } + lua_pushstring(L, buf); + if (!inet_ntop(AF_INET, &value.imr_interface, buf, sizeof(buf))) { + return nixio__perror_s(L); + } + lua_pushstring(L, buf); + return 2; + } + } else { + const char *maddr = luaL_checkstring(L, set); + const char *iface = luaL_optstring(L, set + 1, "0.0.0.0"); + if (inet_pton(AF_INET, maddr, &value.imr_multiaddr) < 1) { + return nixio__perror_s(L); + } + if (inet_pton(AF_INET, iface, &value.imr_interface) < 1) { + return nixio__perror_s(L); + } + if (!setsockopt(fd, level, opt, (char *)&value, optlen)) { + lua_pushboolean(L, 1); + return 1; + } + } + return nixio__perror_s(L); +} + +static int nixio__gso_mreq6(lua_State *L, int fd, int level, int opt, int set) { + struct ipv6_mreq val; + socklen_t optlen = sizeof(val); + if (!set) { + char buf[INET_ADDRSTRLEN]; + if (!getsockopt(fd, level, opt, (char *)&val, &optlen)) { + if (!inet_ntop(AF_INET6, &val.ipv6mr_multiaddr, buf, sizeof(buf))) { + return nixio__perror_s(L); + } + lua_pushstring(L, buf); + lua_pushinteger(L, val.ipv6mr_interface); + return 2; + } + } else { + const char *maddr = luaL_checkstring(L, set); + if (inet_pton(AF_INET6, maddr, &val.ipv6mr_multiaddr) < 1) { + return nixio__perror_s(L); + } + val.ipv6mr_interface = luaL_optlong(L, set + 1, 0); + if (!setsockopt(fd, level, opt, (char *)&val, optlen)) { + lua_pushboolean(L, 1); + return 1; + } + } + return nixio__perror_s(L); +} + +/** + * get/setsockopt() helper + */ +static int nixio__getsetsockopt(lua_State *L, int set) { + nixio_sock *sock = nixio__checksock(L); + const char *level = luaL_optlstring(L, 2, "", NULL); + const char *option = luaL_optlstring(L, 3, "", NULL); + set = (set) ? 4 : 0; + + if (!strcmp(level, "socket")) { + if (!strcmp(option, "keepalive")) { + return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_KEEPALIVE, set); + } else if (!strcmp(option, "reuseaddr")) { + return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_REUSEADDR, set); + } else if (!strcmp(option, "rcvbuf")) { + return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_RCVBUF, set); + } else if (!strcmp(option, "sndbuf")) { + return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_SNDBUF, set); + } else if (!strcmp(option, "priority")) { +#ifdef SO_PRIORITY + return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_PRIORITY, set); +#else + return nixio__pstatus(L, !(errno = ENOPROTOOPT)); +#endif + } else if (!strcmp(option, "broadcast")) { + return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_BROADCAST, set); + } else if (!strcmp(option, "dontroute")) { + return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_DONTROUTE, set); + } else if (!strcmp(option, "error")) { + return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_ERROR, set); + } else if (!strcmp(option, "oobinline")) { + return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_OOBINLINE, set); + } else if (!strcmp(option, "linger")) { + return nixio__gso_ling(L, sock->fd, SOL_SOCKET, SO_LINGER, set); + } else if (!strcmp(option, "sndtimeo")) { + return nixio__gso_timev(L, sock->fd, SOL_SOCKET, SO_SNDTIMEO, set); + } else if (!strcmp(option, "rcvtimeo")) { + return nixio__gso_timev(L, sock->fd, SOL_SOCKET, SO_RCVTIMEO, set); + } else if (!strcmp(option, "bindtodevice")) { +#ifdef SO_BINDTODEVICE + return nixio__gso_b(L, sock->fd, SOL_SOCKET, SO_BINDTODEVICE, set); +#else + return nixio__pstatus(L, !(errno = ENOPROTOOPT)); +#endif + } else { + return luaL_argerror(L, 3, "supported values: keepalive, reuseaddr," + " sndbuf, rcvbuf, priority, broadcast, linger, sndtimeo, rcvtimeo," + " dontroute, bindtodevice, error, oobinline" + ); + } + } else if (!strcmp(level, "tcp")) { + if (!strcmp(option, "cork")) { +#ifdef TCP_CORK + return nixio__gso_int(L, sock->fd, IPPROTO_TCP, TCP_CORK, set); +#else + return nixio__pstatus(L, !(errno = ENOPROTOOPT)); +#endif + } else if (!strcmp(option, "nodelay")) { + return nixio__gso_int(L, sock->fd, IPPROTO_TCP, TCP_NODELAY, set); + } else { + return luaL_argerror(L, 3, "supported values: cork, nodelay"); + } + } else if (!strcmp(level, "ip")) { + if (!strcmp(option, "mtu")) { +#ifdef IP_MTU + return nixio__gso_int(L, sock->fd, IPPROTO_IP, IP_MTU, set); +#else + return nixio__pstatus(L, !(errno = ENOPROTOOPT)); +#endif + } else if (!strcmp(option, "hdrincl")) { + return nixio__gso_int(L, sock->fd, IPPROTO_IP, IP_HDRINCL, + set); + } else if (!strcmp(option, "multicast_loop")) { + return nixio__gso_int(L, sock->fd, IPPROTO_IP, IP_MULTICAST_LOOP, + set); + } else if (!strcmp(option, "multicast_ttl")) { + return nixio__gso_int(L, sock->fd, IPPROTO_IP, IP_MULTICAST_TTL, + set); + } else if (!strcmp(option, "multicast_if")) { + return nixio__gso_mreq4(L, sock->fd, IPPROTO_IP, IP_MULTICAST_IF, + set); + } else if (!strcmp(option, "add_membership")) { + return nixio__gso_mreq4(L, sock->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + set); + } else if (!strcmp(option, "drop_membership")) { + return nixio__gso_mreq4(L, sock->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, + set); + } else { + return luaL_argerror(L, 3, + "supported values: hdrincl, mtu, multicast_loop, " + "multicast_ttl, multicast_if, add_membership, drop_membership"); + } + } else if (!strcmp(level, "ipv6")) { + if (!strcmp(option, "mtu")) { +#ifdef IPV6_MTU + return nixio__gso_int(L, sock->fd, IPPROTO_IPV6, IPV6_MTU, set); +#else + return nixio__pstatus(L, !(errno = ENOPROTOOPT)); +#endif + } else if (!strcmp(option, "v6only")) { +#ifdef IPV6_V6ONLY + return nixio__gso_int(L, sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, set); +#else + return nixio__pstatus(L, !(errno = ENOPROTOOPT)); +#endif + } else if (!strcmp(option, "multicast_loop")) { + return nixio__gso_int(L, sock->fd, IPPROTO_IPV6, + IPV6_MULTICAST_LOOP, set); + } else if (!strcmp(option, "multicast_hops")) { + return nixio__gso_int(L, sock->fd, IPPROTO_IPV6, + IPV6_MULTICAST_HOPS, set); + } else if (!strcmp(option, "multicast_if")) { + return nixio__gso_mreq6(L, sock->fd, IPPROTO_IPV6, + IPV6_MULTICAST_IF, set); + } else if (!strcmp(option, "add_membership")) { + return nixio__gso_mreq6(L, sock->fd, IPPROTO_IPV6, + IPV6_ADD_MEMBERSHIP, set); + } else if (!strcmp(option, "drop_membership")) { + return nixio__gso_mreq6(L, sock->fd, IPPROTO_IPV6, + IPV6_DROP_MEMBERSHIP, set); + } else { + return luaL_argerror(L, 3, + "supported values: v6only, mtu, multicast_loop, multicast_hops," + " multicast_if, add_membership, drop_membership"); + } + } else { + return luaL_argerror(L, 2, "supported values: socket, tcp, ip, ipv6"); + } +} + +/** + * getsockopt() + */ +static int nixio_sock_getsockopt(lua_State *L) { + return nixio__getsetsockopt(L, 0); +} + +/** + * setsockopt() + */ +static int nixio_sock_setsockopt(lua_State *L) { + return nixio__getsetsockopt(L, 1); +} + +/* module table */ +static const luaL_reg M[] = { + {"setblocking", nixio_sock_setblocking}, + {"getsockopt", nixio_sock_getsockopt}, + {"setsockopt", nixio_sock_setsockopt}, + {"getopt", nixio_sock_getsockopt}, + {"setopt", nixio_sock_setsockopt}, + {"fileno", nixio_sock_fileno}, + {NULL, NULL} +}; + +void nixio_open_sockopt(lua_State *L) { + lua_pushvalue(L, -2); + luaL_register(L, NULL, M); + lua_pop(L, 1); + + luaL_getmetatable(L, NIXIO_FILE_META); + lua_pushcfunction(L, nixio_sock_setblocking); + lua_setfield(L, -2, "setblocking"); + lua_pushcfunction(L, nixio_sock_fileno); + lua_setfield(L, -2, "fileno"); + lua_pop(L, 1); +} diff --git a/libs/luci-lib-nixio/src/splice.c b/libs/luci-lib-nixio/src/splice.c new file mode 100644 index 000000000..db63ea9a8 --- /dev/null +++ b/libs/luci-lib-nixio/src/splice.c @@ -0,0 +1,185 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef __linux__ +#define _GNU_SOURCE +#endif + +#include "nixio.h" +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <sys/param.h> + + +#ifndef __WINNT__ + +#ifndef BSD +#include <sys/sendfile.h> +#else +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> +#endif + +#ifdef _GNU_SOURCE +#ifdef SPLICE_F_MOVE + +/* guess what sucks... */ +#ifdef __UCLIBC__ +#include <unistd.h> +#include <sys/syscall.h> + +ssize_t splice(int __fdin, __off64_t *__offin, int __fdout, + __off64_t *__offout, size_t __len, unsigned int __flags) { +#ifdef __NR_splice + return syscall(__NR_splice, __fdin, __offin, __fdout, __offout, __len, __flags); +#else + (void)__fdin; + (void)__offin; + (void)__fdout; + (void)__offout; + (void)__len; + (void)__flags; + errno = ENOSYS; + return -1; +#endif +} + +#undef SPLICE_F_MOVE +#undef SPLICE_F_NONBLOCK +#undef SPLICE_F_MORE + +#define SPLICE_F_MOVE 1 +#define SPLICE_F_NONBLOCK 2 +#define SPLICE_F_MORE 4 + +#endif /* __UCLIBC__ */ + +/** + * splice(fd_in, fd_out, length, flags) + */ +static int nixio_splice(lua_State *L) { + int fd_in = nixio__checkfd(L, 1); + int fd_out = nixio__checkfd(L, 2); + size_t len = luaL_checkinteger(L, 3); + int flags = luaL_optinteger(L, 4, 0); + long spliced; + + do { + spliced = splice(fd_in, NULL, fd_out, NULL, len, flags); + } while (spliced == -1 && errno == EINTR); + + if (spliced < 0) { + return nixio__perror(L); + } + + lua_pushinteger(L, spliced); + return 1; +} + +/** + * Translate splice flags to integer + */ +static int nixio_splice_flags(lua_State *L) { + const int j = lua_gettop(L); + int flags = 0; + for (int i=1; i<=j; i++) { + const char *flag = luaL_checkstring(L, i); + if (!strcmp(flag, "move")) { + flags |= SPLICE_F_MOVE; + } else if (!strcmp(flag, "nonblock")) { + flags |= SPLICE_F_NONBLOCK; + } else if (!strcmp(flag, "more")) { + flags |= SPLICE_F_MORE; + } else { + return luaL_argerror(L, i, "supported values: " + "move, nonblock, more"); + } + } + lua_pushinteger(L, flags); + + return 1; +} + +#endif /* SPLICE_F_MOVE */ +#endif /* _GNU_SOURCE */ + +/** + * sendfile(outfd, infd, length) + */ +static int nixio_sendfile(lua_State *L) { + int sock = nixio__checksockfd(L); + int infd = nixio__checkfd(L, 2); + size_t len = luaL_checkinteger(L, 3); + off_t spliced; + +#ifndef BSD + do { + spliced = sendfile(sock, infd, NULL, len); + } while (spliced == -1 && errno == EINTR); + + if (spliced == -1) { + return nixio__perror(L); + } +#else + int r; + const off_t offset = lseek(infd, 0, SEEK_CUR); + + do { +#ifdef __DARWIN__ + r = sendfile(infd, sock, offset, (off_t *)&len, NULL, 0); + spliced = r; +#else + r = sendfile(infd, sock, offset, len, NULL, &spliced, 0); +#endif + } while (r == -1 && errno == EINTR); + + if (r == -1) { + return nixio__perror(L); + } +#endif + + lua_pushinteger(L, spliced); + return 1; +} + +/* module table */ +static const luaL_reg R[] = { +#ifdef _GNU_SOURCE +#ifdef SPLICE_F_MOVE + {"splice", nixio_splice}, + {"splice_flags", nixio_splice_flags}, +#endif +#endif + {"sendfile", nixio_sendfile}, + {NULL, NULL} +}; + + +void nixio_open_splice(lua_State *L) { + luaL_register(L, NULL, R); +} + +#else /* __WINNT__ */ + +void nixio_open_splice(lua_State *L) { +} + +#endif /* !__WINNT__ */ diff --git a/libs/luci-lib-nixio/src/syslog.c b/libs/luci-lib-nixio/src/syslog.c new file mode 100644 index 000000000..89f1b1dda --- /dev/null +++ b/libs/luci-lib-nixio/src/syslog.c @@ -0,0 +1,122 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include <string.h> + +#ifndef __WINNT__ +#include <syslog.h> + + +static int nixio_openlog(lua_State *L) { + int option = 0, facility = LOG_USER; + + const char *ident = luaL_optstring(L, 1, "nixio"); + const int j = lua_gettop(L); + for (int i=2; i<=j; i++) { + const char *flag = luaL_checkstring(L, i); + if (!strcmp(flag, "cons")) { + option |= LOG_CONS; + } else if (!strcmp(flag, "nowait")) { + option |= LOG_NOWAIT; + } else if (!strcmp(flag, "pid")) { + option |= LOG_PID; + } else if (!strcmp(flag, "perror")) { +#ifdef LOG_PERROR + option |= LOG_PERROR; +#endif + } else if (!strcmp(flag, "ndelay")) { + option |= LOG_NDELAY; + } else if (!strcmp(flag, "odelay")) { + option |= LOG_ODELAY; + } else { + return luaL_argerror(L, i, + "supported values: cons, nowait, pid, perror, ndelay, odelay"); + } + } + + openlog(ident, option, facility); + return 0; +} + +static int nixio_closelog(lua_State *L) { + closelog(); + return 0; +} + +static int nixio__syslogmask(lua_State *L, int dolog) { + int priority; + + const char *flag = luaL_checkstring(L, 1); + if (!strcmp(flag, "emerg")) { + priority = LOG_EMERG; + } else if (!strcmp(flag, "alert")) { + priority = LOG_ALERT; + } else if (!strcmp(flag, "crit")) { + priority = LOG_CRIT; + } else if (!strcmp(flag, "err")) { + priority = LOG_ERR; + } else if (!strcmp(flag, "warning")) { + priority = LOG_WARNING; + } else if (!strcmp(flag, "notice")) { + priority = LOG_NOTICE; + } else if (!strcmp(flag, "info")) { + priority = LOG_INFO; + } else if (!strcmp(flag, "debug")) { + priority = LOG_DEBUG; + } else { + return luaL_argerror(L, 1, "supported values: emerg, alert, crit, err, " + "warning, notice, info, debug"); + } + + if (dolog) { + const char *msg = luaL_checkstring(L, 2); + syslog(priority, "%s", msg); + } else { + setlogmask(LOG_UPTO(priority)); + } + return 0; +} + +static int nixio_setlogmask(lua_State *L) { + return nixio__syslogmask(L, 0); +} + +static int nixio_syslog(lua_State *L) { + return nixio__syslogmask(L, 1); +} + +/* module table */ +static const luaL_reg R[] = { + {"openlog", nixio_openlog}, + {"syslog", nixio_syslog}, + {"setlogmask", nixio_setlogmask}, + {"closelog", nixio_closelog}, + {NULL, NULL} +}; + +void nixio_open_syslog(lua_State *L) { + luaL_register(L, NULL, R); +} + +#else /* __WINNT__ */ + +void nixio_open_syslog(lua_State *L) { +} + +#endif /* __WINNT__ */ diff --git a/libs/luci-lib-nixio/src/tls-context.c b/libs/luci-lib-nixio/src/tls-context.c new file mode 100644 index 000000000..e9a833f59 --- /dev/null +++ b/libs/luci-lib-nixio/src/tls-context.c @@ -0,0 +1,248 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio-tls.h" +#include <string.h> + +static SSL_CTX* nixio__checktlsctx(lua_State *L) { + SSL_CTX **ctx = (SSL_CTX **)luaL_checkudata(L, 1, NIXIO_TLS_CTX_META); + luaL_argcheck(L, *ctx, 1, "invalid context"); + return *ctx; +} + +static int nixio__tls_perror(lua_State *L, int code) { + lua_pushnil(L); + lua_pushinteger(L, code); + return 2; +} + +static int nixio__tls_pstatus(lua_State *L, int code) { + if (code == 1) { + lua_pushboolean(L, 1); + return 1; + } else { + return nixio__tls_perror(L, code); + } +} + +static int nixio_tls_ctx(lua_State * L) { + const char *method = luaL_optlstring(L, 1, "client", NULL); + + luaL_getmetatable(L, NIXIO_TLS_CTX_META); + SSL_CTX **ctx = lua_newuserdata(L, sizeof(SSL_CTX *)); + if (!ctx) { + return luaL_error(L, "out of memory"); + } + + /* create userdata */ + lua_pushvalue(L, -2); + lua_setmetatable(L, -2); + + if (!strcmp(method, "client")) { + *ctx = SSL_CTX_new(TLSv1_client_method()); + } else if (!strcmp(method, "server")) { + *ctx = SSL_CTX_new(TLSv1_server_method()); + } else { + return luaL_argerror(L, 1, "supported values: client, server"); + } + + if (!(*ctx)) { + return luaL_error(L, "unable to create TLS context"); + } + +#ifdef WITH_CYASSL + SSL_CTX_set_verify(*ctx, SSL_VERIFY_NONE, NULL); +#endif + + return 1; +} + +static int nixio_tls_ctx_create(lua_State *L) { + SSL_CTX *ctx = nixio__checktlsctx(L); + int fd = nixio__checkfd(L, 2); + + lua_createtable(L, 0, 3); + nixio_tls_sock *sock = lua_newuserdata(L, sizeof(nixio_tls_sock)); + if (!sock) { + return luaL_error(L, "out of memory"); + } + memset(sock, 0, sizeof(nixio_tls_sock)); + + /* create userdata */ + luaL_getmetatable(L, NIXIO_TLS_SOCK_META); + lua_pushvalue(L, -1); + lua_setmetatable(L, -3); + + sock->socket = SSL_new(ctx); + if (!sock->socket) { + return nixio__tls_perror(L, 0); + } + + if (SSL_set_fd(sock->socket, fd) != 1) { + return nixio__tls_perror(L, 0); + } + + /* save context and socket to prevent GC from collecting them */ + lua_setmetatable(L, -3); + lua_setfield(L, -2, "connection"); + + lua_pushvalue(L, 1); + lua_setfield(L, -2, "context"); + + lua_pushvalue(L, 2); + lua_setfield(L, -2, "socket"); + + return 1; +} + +static int nixio_tls_ctx_set_cert(lua_State *L) { + SSL_CTX *ctx = nixio__checktlsctx(L); + const char *cert = luaL_checkstring(L, 2); + const char *type = luaL_optstring(L, 3, "chain"); + int ktype; + + if (!strcmp(type, "chain")) { + return nixio__tls_pstatus(L, + SSL_CTX_use_certificate_chain_file(ctx, cert)); + } else if (!strcmp(type, "pem")) { + ktype = SSL_FILETYPE_PEM; + } else if (!strcmp(type, "asn1")) { + ktype = SSL_FILETYPE_ASN1; + } else { + return luaL_argerror(L, 3, "supported values: chain, pem, asn1"); + } + + return nixio__tls_pstatus(L, + SSL_CTX_use_certificate_file(ctx, cert, ktype)); +} + +static int nixio_tls_ctx_set_verify_locations(lua_State *L) { + SSL_CTX *ctx = nixio__checktlsctx(L); + const char *CAfile = luaL_optstring(L, 2, NULL); + const char *CApath = luaL_optstring(L, 3, NULL); + return nixio__tls_pstatus(L, SSL_CTX_load_verify_locations(ctx, + CAfile, CApath)); +} + +static int nixio_tls_ctx_set_key(lua_State *L) { + SSL_CTX *ctx = nixio__checktlsctx(L); + const char *cert = luaL_checkstring(L, 2); + const char *type = luaL_optstring(L, 3, "pem"); + int ktype; + + if (!strcmp(type, "pem")) { + ktype = SSL_FILETYPE_PEM; + } else if (!strcmp(type, "asn1")) { + ktype = SSL_FILETYPE_ASN1; + } else { + return luaL_argerror(L, 3, "supported values: pem, asn1"); + } + + return nixio__tls_pstatus(L, SSL_CTX_use_PrivateKey_file(ctx, cert, ktype)); +} + +static int nixio_tls_ctx_set_ciphers(lua_State *L) { + SSL_CTX *ctx = nixio__checktlsctx(L); + size_t len; + const char *ciphers = luaL_checklstring(L, 2, &len); + luaL_argcheck(L, len < 255, 2, "cipher string too long"); + return nixio__tls_pstatus(L, SSL_CTX_set_cipher_list(ctx, ciphers)); +} + +static int nixio_tls_ctx_set_verify(lua_State *L) { + SSL_CTX *ctx = nixio__checktlsctx(L); + const int j = lua_gettop(L); + int flags = 0; + for (int i=2; i<=j; i++) { + const char *flag = luaL_checkstring(L, i); + if (!strcmp(flag, "none")) { + flags |= SSL_VERIFY_NONE; + } else if (!strcmp(flag, "peer")) { + flags |= SSL_VERIFY_PEER; + } else if (!strcmp(flag, "verify_fail_if_no_peer_cert")) { + flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + } else if (!strcmp(flag, "client_once")) { + flags |= SSL_VERIFY_CLIENT_ONCE; + } else { + return luaL_argerror(L, i, "supported values: none, peer, " + "verify_fail_if_no_peer_cert, client_once"); + } + } + SSL_CTX_set_verify(ctx, flags, NULL); + return 0; +} + +static int nixio_tls_ctx__gc(lua_State *L) { + SSL_CTX **ctx = (SSL_CTX **)luaL_checkudata(L, 1, NIXIO_TLS_CTX_META); + if (*ctx) { + SSL_CTX_free(*ctx); + *ctx = NULL; + } + return 0; +} + +static int nixio_tls_ctx__tostring(lua_State *L) { + SSL_CTX *ctx = nixio__checktlsctx(L); + lua_pushfstring(L, "nixio TLS context: %p", ctx); + return 1; +} + +/* module table */ +static const luaL_reg R[] = { + {"tls", nixio_tls_ctx}, + {NULL, NULL} +}; + +/* ctx function table */ +static const luaL_reg CTX_M[] = { + {"set_cert", nixio_tls_ctx_set_cert}, + {"set_verify_locations", nixio_tls_ctx_set_verify_locations}, + {"set_key", nixio_tls_ctx_set_key}, + {"set_ciphers", nixio_tls_ctx_set_ciphers}, + {"set_verify", nixio_tls_ctx_set_verify}, + {"create", nixio_tls_ctx_create}, + {"__gc", nixio_tls_ctx__gc}, + {"__tostring", nixio_tls_ctx__tostring}, + {NULL, NULL} +}; + + +void nixio_open_tls_context(lua_State *L) { + /* initialize tls library */ + SSL_load_error_strings(); + SSL_library_init(); + + /* register module functions */ + luaL_register(L, NULL, R); + +#if defined (WITH_AXTLS) + lua_pushliteral(L, "axtls"); +#elif defined (WITH_CYASSL) + lua_pushliteral(L, "cyassl"); +#else + lua_pushliteral(L, "openssl"); +#endif + lua_setfield(L, -2, "tls_provider"); + + /* create context metatable */ + luaL_newmetatable(L, NIXIO_TLS_CTX_META); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_register(L, NULL, CTX_M); + lua_setfield(L, -2, "meta_tls_context"); +} diff --git a/libs/luci-lib-nixio/src/tls-crypto.c b/libs/luci-lib-nixio/src/tls-crypto.c new file mode 100644 index 000000000..714ec4e60 --- /dev/null +++ b/libs/luci-lib-nixio/src/tls-crypto.c @@ -0,0 +1,185 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio-tls.h" +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +static int nixio_crypto_hash__init(lua_State *L, int hmac) { + const char *type = luaL_checkstring(L, 1); + nixio_hash *hash = lua_newuserdata(L, sizeof(nixio_hash)); + + if (!strcmp(type, "md5")) { + hash->type = NIXIO_HASH_MD5; + hash->digest_size = MD5_DIGEST_LENGTH; + hash->block_size = 64; + hash->ctx = malloc(sizeof(MD5_CTX)); + if (!hash->ctx) { + return luaL_error(L, NIXIO_OOM); + } + MD5_Init((MD5_CTX*)hash->ctx); + hash->init = (nixio_hash_initcb)MD5_Init; + hash->update = (nixio_hash_updatecb)MD5_Update; + hash->final = (nixio_hash_finalcb)MD5_Final; + } else if (!strcmp(type, "sha1")) { + hash->type = NIXIO_HASH_SHA1; + hash->digest_size = SHA_DIGEST_LENGTH; + hash->block_size = 64; + hash->ctx = malloc(sizeof(SHA_CTX)); + if (!hash->ctx) { + return luaL_error(L, NIXIO_OOM); + } + SHA1_Init((SHA_CTX*)hash->ctx); + hash->init = (nixio_hash_initcb)SHA1_Init; + hash->update = (nixio_hash_updatecb)SHA1_Update; + hash->final = (nixio_hash_finalcb)SHA1_Final; + } else { + luaL_argerror(L, 1, "supported values: md5, sha1"); + } + + luaL_getmetatable(L, NIXIO_CRYPTO_HASH_META); + lua_setmetatable(L, -2); + + if (hmac) { + const char *key = luaL_checklstring(L, 2, &hash->key_size); + if (hash->key_size > hash->block_size) { + hash->update(hash->ctx, key, hash->key_size); + hash->final(hash->digest, hash->ctx); + hash->init(hash->ctx); + hash->key_size = hash->digest_size; + memcpy(hash->key, hash->digest, hash->key_size); + } else { + memcpy(hash->key, key, hash->key_size); + } + + unsigned char pad[NIXIO_CRYPTO_BLOCK_SIZE]; + for (uint i = 0; i < hash->block_size; i++) { + pad[i] = (i < hash->key_size) ? (0x36 ^ hash->key[i]) : 0x36; + } + hash->update(hash->ctx, pad, hash->block_size); + hash->type |= NIXIO_HMAC_BIT; + } + + return 1; +} + +static int nixio_crypto_hash(lua_State *L) { + return nixio_crypto_hash__init(L, 0); +} + +static int nixio_crypto_hmac(lua_State *L) { + return nixio_crypto_hash__init(L, 1); +} + +static int nixio_crypto_hash_update(lua_State *L) { + nixio_hash *hash = luaL_checkudata(L, 1, NIXIO_CRYPTO_HASH_META); + if (hash->type) { + size_t len; + const char *chunk = luaL_checklstring(L, 2, &len); + hash->update(hash->ctx, chunk, len); + lua_pushvalue(L, 1); + return 1; + } else { + return luaL_error(L, "Tried to update finalized hash object."); + } +} + +static int nixio_crypto_hash_final(lua_State *L) { + nixio_hash *hash = luaL_checkudata(L, 1, NIXIO_CRYPTO_HASH_META); + if (hash->type & NIXIO_HMAC_BIT) { + hash->final(hash->digest, hash->ctx); + hash->init(hash->ctx); + + unsigned char pad[NIXIO_CRYPTO_BLOCK_SIZE]; + for (uint i = 0; i < hash->block_size; i++) { + pad[i] = (i < hash->key_size) ? (0x5c ^ hash->key[i]) : 0x5c; + } + + hash->update(hash->ctx, pad, hash->block_size); + hash->update(hash->ctx, hash->digest, hash->digest_size); + } + + if (hash->type) { + hash->type = NIXIO_HASH_NONE; + hash->final(hash->digest, hash->ctx); + free(hash->ctx); + } + + char hashdigest[NIXIO_DIGEST_SIZE*2]; + for (uint i=0; i < hash->digest_size; i++) { + hashdigest[2*i] = nixio__bin2hex[(hash->digest[i] & 0xf0) >> 4]; + hashdigest[2*i+1] = nixio__bin2hex[(hash->digest[i] & 0x0f)]; + } + + lua_pushlstring(L, hashdigest, hash->digest_size * 2); + memcpy(hashdigest, hash->digest, hash->digest_size); + lua_pushlstring(L, hashdigest, hash->digest_size); + + return 2; +} + +static int nixio_crypto_hash__gc(lua_State *L) { + nixio_hash *hash = luaL_checkudata(L, 1, NIXIO_CRYPTO_HASH_META); + if (hash->type) { + hash->final(hash->digest, hash->ctx); + free(hash->ctx); + hash->type = NIXIO_HASH_NONE; + } + return 0; +} + +static int nixio_crypto_hash__tostring(lua_State *L) { + nixio_hash *hash = luaL_checkudata(L, 1, NIXIO_CRYPTO_HASH_META); + lua_pushfstring(L, "nixio hash object: %p", hash); + return 1; +} + + +/* module table */ +static const luaL_reg R[] = { + {"hash", nixio_crypto_hash}, + {"hmac", nixio_crypto_hmac}, + {NULL, NULL} +}; + +/* hash table */ +static const luaL_reg M[] = { + {"update", nixio_crypto_hash_update}, + {"final", nixio_crypto_hash_final}, + {"__gc", nixio_crypto_hash__gc}, + {"__tostring", nixio_crypto_hash__tostring}, + {NULL, NULL} +}; + + + +void nixio_open_tls_crypto(lua_State *L) { + luaL_newmetatable(L, NIXIO_CRYPTO_HASH_META); + luaL_register(L, NULL, M); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + lua_pop(L, 1); + + lua_newtable(L); + luaL_register(L, NULL, R); + + lua_setfield(L, -2, "crypto"); +} diff --git a/libs/luci-lib-nixio/src/tls-socket.c b/libs/luci-lib-nixio/src/tls-socket.c new file mode 100644 index 000000000..fe4cb6075 --- /dev/null +++ b/libs/luci-lib-nixio/src/tls-socket.c @@ -0,0 +1,263 @@ + /* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio-tls.h" +#include <string.h> +#include <stdlib.h> + +static int nixio__tls_sock_perror(lua_State *L, SSL *sock, int code) { + lua_pushnil(L); + lua_pushinteger(L, SSL_get_error(sock, code)); + return 2; +} + +static int nixio__tls_sock_pstatus(lua_State *L, SSL *sock, int code) { + if (code > 0) { + lua_pushboolean(L, 1); + return 1; + } else { + return nixio__tls_sock_perror(L, sock, code); + } +} + +static SSL* nixio__checktlssock(lua_State *L) { + if (lua_istable(L, 1)) { + lua_getfield(L, 1, "connection"); + lua_replace(L, 1); + } + nixio_tls_sock *sock = luaL_checkudata(L, 1, NIXIO_TLS_SOCK_META); + luaL_argcheck(L, sock->socket, 1, "invalid context"); + return sock->socket; +} + +#ifndef WITH_AXTLS +#define nixio_tls__check_connected(L) ; + +#define nixio_tls__set_connected(L, val) ; +#else +#define nixio_tls__check_connected(L) \ + nixio_tls_sock *ctsock = luaL_checkudata(L, 1, NIXIO_TLS_SOCK_META); \ + if (!ctsock->connected) { \ + lua_pushnil(L); \ + lua_pushinteger(L, 1); \ + return 2; \ + } + +#define nixio_tls__set_connected(L, val) \ +((nixio_tls_sock*)luaL_checkudata(L, 1, NIXIO_TLS_SOCK_META))->connected = val; +#endif /* WITH_AXTLS */ + +static int nixio_tls_sock_recv(lua_State *L) { + SSL *sock = nixio__checktlssock(L); + nixio_tls__check_connected(L); + uint req = luaL_checkinteger(L, 2); + + luaL_argcheck(L, req >= 0, 2, "out of range"); + + /* We limit the readsize to NIXIO_BUFFERSIZE */ + req = (req > NIXIO_BUFFERSIZE) ? NIXIO_BUFFERSIZE : req; + +#ifndef WITH_AXTLS + + char buffer[NIXIO_BUFFERSIZE]; + int readc = SSL_read(sock, buffer, req); + + if (readc < 0) { + return nixio__tls_sock_pstatus(L, sock, readc); + } else { + lua_pushlstring(L, buffer, readc); + return 1; + } + +#else + + if (!req) { + lua_pushliteral(L, ""); + return 1; + } + + nixio_tls_sock *t = lua_touserdata(L, 1); + + /* AXTLS doesn't handle buffering for us, so we have to hack around*/ + if (req < t->pbufsiz) { + lua_pushlstring(L, t->pbufpos, req); + t->pbufpos += req; + t->pbufsiz -= req; + return 1; + } else { + uint8_t *axbuf; + int axread; + + /* while handshake pending */ + while ((axread = ssl_read(sock, &axbuf)) == SSL_OK); + + if (t->pbufsiz) { + lua_pushlstring(L, t->pbufpos, t->pbufsiz); + } + + if (axread < 0) { + /* There is an error */ + free(t->pbuffer); + t->pbuffer = t->pbufpos = NULL; + + if (axread != SSL_ERROR_CONN_LOST) { + t->pbufsiz = 0; + return nixio__tls_sock_perror(L, sock, axread); + } else { + if (!t->pbufsiz) { + lua_pushliteral(L, ""); + } else { + t->pbufsiz = 0; + } + } + } else { + int stillwant = req - t->pbufsiz; + if (stillwant < axread) { + /* we got more data than we need */ + lua_pushlstring(L, (char *)axbuf, stillwant); + if(t->pbufsiz) { + lua_concat(L, 2); + } + + /* remaining data goes into the buffer */ + t->pbufpos = t->pbuffer; + t->pbufsiz = axread - stillwant; + t->pbuffer = realloc(t->pbuffer, t->pbufsiz); + if (!t->pbuffer) { + free(t->pbufpos); + t->pbufpos = NULL; + t->pbufsiz = 0; + return luaL_error(L, "out of memory"); + } + + t->pbufpos = t->pbuffer; + memcpy(t->pbufpos, axbuf + stillwant, t->pbufsiz); + } else { + lua_pushlstring(L, (char *)axbuf, axread); + if(t->pbufsiz) { + lua_concat(L, 2); + } + + /* free buffer */ + free(t->pbuffer); + t->pbuffer = t->pbufpos = NULL; + t->pbufsiz = 0; + } + } + return 1; + } + +#endif /* WITH_AXTLS */ + +} + +static int nixio_tls_sock_send(lua_State *L) { + SSL *sock = nixio__checktlssock(L); + nixio_tls__check_connected(L); + size_t len; + ssize_t sent; + const char *data = luaL_checklstring(L, 2, &len); + + if (lua_gettop(L) > 2) { + int offset = luaL_optint(L, 3, 0); + if (offset) { + if (offset < len) { + data += offset; + len -= offset; + } else { + len = 0; + } + } + + unsigned int wlen = luaL_optint(L, 4, len); + if (wlen < len) { + len = wlen; + } + } + + sent = SSL_write(sock, data, len); + if (sent > 0) { + lua_pushinteger(L, sent); + return 1; + } else { + return nixio__tls_sock_pstatus(L, sock, sent); + } +} + +static int nixio_tls_sock_accept(lua_State *L) { + SSL *sock = nixio__checktlssock(L); + const int stat = SSL_accept(sock); + nixio_tls__set_connected(L, stat == 1); + return nixio__tls_sock_pstatus(L, sock, stat); +} + +static int nixio_tls_sock_connect(lua_State *L) { + SSL *sock = nixio__checktlssock(L); + const int stat = SSL_connect(sock); + nixio_tls__set_connected(L, stat == 1); + return nixio__tls_sock_pstatus(L, sock, stat); +} + +static int nixio_tls_sock_shutdown(lua_State *L) { + SSL *sock = nixio__checktlssock(L); + nixio_tls__set_connected(L, 0); + return nixio__tls_sock_pstatus(L, sock, SSL_shutdown(sock)); +} + +static int nixio_tls_sock__gc(lua_State *L) { + nixio_tls_sock *sock = luaL_checkudata(L, 1, NIXIO_TLS_SOCK_META); + if (sock->socket) { + SSL_free(sock->socket); + sock->socket = NULL; +#ifdef WITH_AXTLS + free(sock->pbuffer); +#endif + } + return 0; +} + +static int nixio_tls_sock__tostring(lua_State *L) { + SSL *sock = nixio__checktlssock(L); + lua_pushfstring(L, "nixio TLS connection: %p", sock); + return 1; +} + + +/* ctx function table */ +static const luaL_reg M[] = { + {"recv", nixio_tls_sock_recv}, + {"send", nixio_tls_sock_send}, + {"read", nixio_tls_sock_recv}, + {"write", nixio_tls_sock_send}, + {"accept", nixio_tls_sock_accept}, + {"connect", nixio_tls_sock_connect}, + {"shutdown", nixio_tls_sock_shutdown}, + {"__gc", nixio_tls_sock__gc}, + {"__tostring", nixio_tls_sock__tostring}, + {NULL, NULL} +}; + + +void nixio_open_tls_socket(lua_State *L) { + /* create socket metatable */ + luaL_newmetatable(L, NIXIO_TLS_SOCK_META); + luaL_register(L, NULL, M); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + lua_setfield(L, -2, "meta_tls_socket"); +} diff --git a/libs/luci-lib-nixio/src/user.c b/libs/luci-lib-nixio/src/user.c new file mode 100644 index 000000000..b701bac95 --- /dev/null +++ b/libs/luci-lib-nixio/src/user.c @@ -0,0 +1,263 @@ +/* + * nixio - Linux I/O library for lua + * + * Copyright (C) 2009 Steven Barth <steven@midlink.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nixio.h" +#include <sys/types.h> +#include <errno.h> +#include <unistd.h> +#include <sys/param.h> + +#ifndef __WINNT__ + +#include <grp.h> +#include <pwd.h> + +#ifndef BSD +#ifndef NO_SHADOW +#include <shadow.h> +#endif +#include <crypt.h> +#endif + +int nixio__check_group(lua_State *L, int idx) { + if (lua_isnumber(L, idx)) { + return lua_tointeger(L, idx); + } else if (lua_isstring(L, idx)) { + struct group *g = getgrnam(lua_tostring(L, idx)); + return (!g) ? -1 : g->gr_gid; + } else { + return luaL_argerror(L, idx, "supported values: <groupname>, <gid>"); + } +} + +int nixio__check_user(lua_State *L, int idx) { + if (lua_isnumber(L, idx)) { + return lua_tointeger(L, idx); + } else if (lua_isstring(L, idx)) { + struct passwd *p = getpwnam(lua_tostring(L, idx)); + return (!p) ? -1 : p->pw_uid; + } else { + return luaL_argerror(L, idx, "supported values: <username>, <uid>"); + } +} + + +static int nixio__push_group(lua_State *L, struct group *gr) { + lua_createtable(L, 0, 4); + lua_pushstring(L, gr->gr_name); + lua_setfield(L, -2, "name"); + lua_pushstring(L, gr->gr_passwd); + lua_setfield(L, -2, "passwd"); + lua_pushinteger(L, gr->gr_gid); + lua_setfield(L, -2, "gid"); + lua_newtable(L); + + for (int i=0; gr->gr_mem[i]; i++) { + lua_pushstring(L, gr->gr_mem[i]); + lua_rawseti(L, -2, i+1); + } + + lua_setfield(L, -2, "mem"); + return 1; +} + +static int nixio_getgr(lua_State *L) { + struct group *gr; + errno = 0; + if (lua_isnumber(L, 1)) { + gr = getgrgid(lua_tointeger(L, 1)); + } else if (lua_isstring(L, 1)) { + gr = getgrnam(lua_tostring(L, 1)); + } else if (lua_isnoneornil(L, 1)) { + lua_newtable(L); + int i = 0; + + setgrent(); + while ((gr = getgrent())) { + nixio__push_group(L, gr); + lua_rawseti(L, -2, ++i); + } + + if (errno) { + return nixio__perror(L); + } + + endgrent(); + return 1; + } else { + return luaL_argerror(L, 1, "supported values: <groupname>, <gid>"); + } + + if (!gr) { + return nixio__perror(L); + } else { + return nixio__push_group(L, gr); + } +} + +static int nixio__push_passwd(lua_State *L, struct passwd *pw) { + lua_createtable(L, 0, 7); + lua_pushstring(L, pw->pw_name); + lua_setfield(L, -2, "name"); + lua_pushstring(L, pw->pw_passwd); + lua_setfield(L, -2, "passwd"); + lua_pushinteger(L, pw->pw_gid); + lua_setfield(L, -2, "gid"); + lua_pushinteger(L, pw->pw_uid); + lua_setfield(L, -2, "uid"); + lua_pushstring(L, pw->pw_dir); + lua_setfield(L, -2, "dir"); + lua_pushstring(L, pw->pw_gecos); + lua_setfield(L, -2, "gecos"); + lua_pushstring(L, pw->pw_shell); + lua_setfield(L, -2, "shell"); + return 1; +} + +static int nixio_getpw(lua_State *L) { + struct passwd *pw; + errno = 0; + if (lua_isnumber(L, 1)) { + pw = getpwuid(lua_tointeger(L, 1)); + } else if (lua_isstring(L, 1)) { + pw = getpwnam(lua_tostring(L, 1)); + } else if (lua_isnoneornil(L, 1)) { + lua_newtable(L); + int i = 0; + + setpwent(); + while ((pw = getpwent())) { + nixio__push_passwd(L, pw); + lua_rawseti(L, -2, ++i); + } + + if (errno) { + return nixio__perror(L); + } + + endpwent(); + return 1; + } else { + return luaL_argerror(L, 1, "supported values: <username>, <uid>"); + } + + if (!pw) { + return nixio__perror(L); + } else { + return nixio__push_passwd(L, pw); + } +} + +#ifndef BSD +#ifndef NO_SHADOW +static int nixio__push_spwd(lua_State *L, struct spwd *sp) { + lua_createtable(L, 0, 9); + lua_pushstring(L, sp->sp_namp); + lua_setfield(L, -2, "namp"); + lua_pushinteger(L, sp->sp_expire); + lua_setfield(L, -2, "expire"); + lua_pushinteger(L, sp->sp_flag); + lua_setfield(L, -2, "flag"); + lua_pushinteger(L, sp->sp_inact); + lua_setfield(L, -2, "inact"); + lua_pushinteger(L, sp->sp_lstchg); + lua_setfield(L, -2, "lstchg"); + lua_pushinteger(L, sp->sp_max); + lua_setfield(L, -2, "max"); + lua_pushinteger(L, sp->sp_min); + lua_setfield(L, -2, "min"); + lua_pushinteger(L, sp->sp_warn); + lua_setfield(L, -2, "warn"); + lua_pushstring(L, sp->sp_pwdp); + lua_setfield(L, -2, "pwdp"); + return 1; +} + +static int nixio_getsp(lua_State *L) { + struct spwd *sp; + errno = 0; + if (lua_isstring(L, 1)) { + sp = getspnam(lua_tostring(L, 1)); + } else if (lua_isnoneornil(L, 1)) { + lua_newtable(L); + int i = 0; + + setspent(); + while ((sp = getspent())) { + nixio__push_spwd(L, sp); + lua_rawseti(L, -2, ++i); + } + + if (errno) { + return nixio__perror(L); + } + + endspent(); + return 1; + } else { + return luaL_argerror(L, 1, "supported values: <username>"); + } + + if (!sp) { + return nixio__perror(L); + } else { + return nixio__push_spwd(L, sp); + } +} +#endif /* !NO_SHADOW */ +#endif /* !BSD */ + +static int nixio_crypt(lua_State *L) { + const char *key = luaL_checkstring(L, 1); + const char *salt = luaL_checkstring(L, 2); + const char *hash = crypt(key, salt); + + if (hash) { + lua_pushstring(L, hash); + } else { + lua_pushnil(L); + } + + return 1; +} + + +/* module table */ +static const luaL_reg R[] = { + {"crypt", nixio_crypt}, + {"getgr", nixio_getgr}, + {"getpw", nixio_getpw}, +#ifndef BSD +#ifndef NO_SHADOW + {"getsp", nixio_getsp}, +#endif +#endif + {NULL, NULL} +}; + +#else /* __WINNT__ */ + +static const luaL_reg R[] = { + {NULL, NULL} +}; + +#endif + +void nixio_open_user(lua_State *L) { + luaL_register(L, NULL, R); +} |