diff options
Diffstat (limited to 'util-src')
-rw-r--r-- | util-src/Makefile | 35 | ||||
-rw-r--r-- | util-src/Makefile.win | 25 | ||||
-rw-r--r-- | util-src/encodings.c | 191 | ||||
-rw-r--r-- | util-src/hashes.c | 172 | ||||
-rw-r--r-- | util-src/pposix.c | 380 | ||||
-rw-r--r-- | util-src/signal.c (renamed from util-src/lsignal.c) | 77 | ||||
-rw-r--r-- | util-src/windows.c | 89 |
7 files changed, 821 insertions, 148 deletions
diff --git a/util-src/Makefile b/util-src/Makefile index 3b7ca7bc..90d65e51 100644 --- a/util-src/Makefile +++ b/util-src/Makefile @@ -7,38 +7,35 @@ LUA_LIB?=lua$(LUA_SUFFIX) IDN_LIB?=idn OPENSSL_LIB?=crypto CC?=gcc +CXX?=g++ LD?=gcc +CFLAGS+=-ggdb +.PHONY: all install clean +.SUFFIXES: .c .o .so all: encodings.so hashes.so pposix.so signal.so install: encodings.so hashes.so pposix.so signal.so install *.so ../util/ - clean: rm -f *.o rm -f *.so rm -f ../util/*.so -encodings.o: encodings.c - $(CC) $(CFLAGS) -I$(LUA_INCDIR) -c -o encodings.o encodings.c encodings.so: encodings.o - export MACOSX_DEPLOYMENT_TARGET="10.3"; $(LD) $(LFLAGS) -o encodings.so encodings.o -L$(LUA_LIBDIR) -llua$(LUA_SUFFIX) -lidn - + MACOSX_DEPLOYMENT_TARGET="10.3"; export MACOSX_DEPLOYMENT_TARGET; + $(CC) -o $@ $< $(LDFLAGS) $(IDNA_LIBS) -hashes.o: hashes.c - $(CC) $(CFLAGS) -I$(LUA_INCDIR) -c -o hashes.o hashes.c hashes.so: hashes.o - export MACOSX_DEPLOYMENT_TARGET="10.3"; $(LD) $(LFLAGS) -o hashes.so hashes.o -L$(LUA_LIBDIR) -llua$(LUA_SUFFIX) -lcrypto - -pposix.o: pposix.c - $(CC) $(CFLAGS) -I$(LUA_INCDIR) -c -o pposix.o pposix.c -pposix.so: pposix.o - export MACOSX_DEPLOYMENT_TARGET="10.3"; $(LD) $(LFLAGS) -o pposix.so pposix.o -L$(LUA_LIBDIR) -llua$(LUA_SUFFIX) - -lsignal.o: lsignal.c - $(CC) $(CFLAGS) -I$(LUA_INCDIR) -c -o lsignal.o lsignal.c -signal.so: lsignal.o - export MACOSX_DEPLOYMENT_TARGET="10.3"; $(LD) $(LFLAGS) -o signal.so lsignal.o - + MACOSX_DEPLOYMENT_TARGET="10.3"; export MACOSX_DEPLOYMENT_TARGET; + $(CC) -o $@ $< $(LDFLAGS) -l$(OPENSSL_LIB) + +.c.o: + $(CC) $(CFLAGS) -I$(LUA_INCDIR) -c -o $@ $< + +.o.so: + MACOSX_DEPLOYMENT_TARGET="10.3"; export MACOSX_DEPLOYMENT_TARGET; + $(LD) -o $@ $< $(LDFLAGS) + diff --git a/util-src/Makefile.win b/util-src/Makefile.win index d76aaccb..7b141097 100644 --- a/util-src/Makefile.win +++ b/util-src/Makefile.win @@ -1,7 +1,7 @@ LUA_PATH=$(LUA_DEV) -IDN_PATH=.\libidn-1.9 -OPENSSL_PATH=.\openssl-0.9.8i +IDN_PATH=..\..\libidn-1.15 +OPENSSL_PATH=..\..\openssl-0.9.8k LUA_INCLUDE=$(LUA_PATH)\include LUA_LIB=$(LUA_PATH)\lib\lua5.1.lib @@ -12,18 +12,27 @@ IDN_INCLUDE2=$(IDN_PATH)\win32\include OPENSSL_LIB=$(OPENSSL_PATH)\out32dll\libeay32.lib OPENSSL_INCLUDE=$(OPENSSL_PATH)\include -all: encodings.dll hashes.dll +CL=cl /LD /MD /nologo -install: encodings.dll hashes.dll +all: encodings.dll hashes.dll windows.dll + +install: encodings.dll hashes.dll windows.dll copy /Y *.dll ..\util\ clean: - del encodings.dll encodings.exp encodings.lib encodings.obj - del hashes.dll hashes.exp hashes.lib hashes.obj + del encodings.dll encodings.exp encodings.lib encodings.obj encodings.dll.manifest + del hashes.dll hashes.exp hashes.lib hashes.obj hashes.dll.manifest + del windows.dll windows.exp windows.lib windows.obj windows.dll.manifest encodings.dll: encodings.c - cl /LD /nologo encodings.c /I"$(LUA_INCLUDE)" /I"$(IDN_INCLUDE1)" /I"$(IDN_INCLUDE2)" /link "$(LUA_LIB)" "$(IDN_LIB)" /export:luaopen_util_encodings + $(CL) encodings.c /I"$(LUA_INCLUDE)" /I"$(IDN_INCLUDE1)" /I"$(IDN_INCLUDE2)" /link "$(LUA_LIB)" "$(IDN_LIB)" /export:luaopen_util_encodings + del encodings.exp encodings.lib encodings.obj encodings.dll.manifest hashes.dll: hashes.c - cl /LD /nologo hashes.c /I"$(LUA_INCLUDE)" /I"$(OPENSSL_INCLUDE)" /link "$(LUA_LIB)" "$(OPENSSL_LIB)" /export:luaopen_util_hashes + $(CL) hashes.c /I"$(LUA_INCLUDE)" /I"$(OPENSSL_INCLUDE)" /link "$(LUA_LIB)" "$(OPENSSL_LIB)" /export:luaopen_util_hashes + del hashes.exp hashes.lib hashes.obj hashes.dll.manifest + +windows.dll: windows.c + $(CL) windows.c /I"$(LUA_INCLUDE)" /link "$(LUA_LIB)" dnsapi.lib /export:luaopen_util_windows + del windows.exp windows.lib windows.obj windows.dll.manifest diff --git a/util-src/encodings.c b/util-src/encodings.c index d7aabc14..b9b6160a 100644 --- a/util-src/encodings.c +++ b/util-src/encodings.c @@ -1,6 +1,6 @@ -/* Prosody IM v0.4 --- Copyright (C) 2008-2009 Matthew Wild --- Copyright (C) 2008-2009 Waqas Hussain +/* Prosody IM +-- Copyright (C) 2008-2010 Matthew Wild +-- Copyright (C) 2008-2010 Waqas Hussain -- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. @@ -12,12 +12,11 @@ * Lua library for base64, stringprep and idna encodings */ -// Newer MSVC compilers deprecate strcpy as unsafe, but we use it in a safe way +/* Newer MSVC compilers deprecate strcpy as unsafe, but we use it in a safe way */ #define _CRT_SECURE_NO_DEPRECATE #include <string.h> #include <stdlib.h> - #include "lua.h" #include "lauxlib.h" @@ -108,7 +107,6 @@ static int Lbase64_decode(lua_State *L) /** decode(s) */ break; } } - return 0; } static const luaL_Reg Reg_base64[] = @@ -119,27 +117,114 @@ static const luaL_Reg Reg_base64[] = }; /***************** STRINGPREP *****************/ +#ifdef USE_STRINGPREP_ICU + +#include <unicode/usprep.h> +#include <unicode/ustring.h> +#include <unicode/utrace.h> + +static int icu_stringprep_prep(lua_State *L, const UStringPrepProfile *profile) +{ + size_t input_len; + int32_t unprepped_len, prepped_len, output_len; + const char *input; + char output[1024]; + + UChar unprepped[1024]; /* Temporary unicode buffer (1024 characters) */ + UChar prepped[1024]; + + UErrorCode err = U_ZERO_ERROR; + + if(!lua_isstring(L, 1)) { + lua_pushnil(L); + return 1; + } + input = lua_tolstring(L, 1, &input_len); + if (input_len >= 1024) { + lua_pushnil(L); + return 1; + } + u_strFromUTF8(unprepped, 1024, &unprepped_len, input, input_len, &err); + if (U_FAILURE(err)) { + lua_pushnil(L); + return 1; + } + prepped_len = usprep_prepare(profile, unprepped, unprepped_len, prepped, 1024, 0, NULL, &err); + if (U_FAILURE(err)) { + lua_pushnil(L); + return 1; + } else { + u_strToUTF8(output, 1024, &output_len, prepped, prepped_len, &err); + if (U_SUCCESS(err) && output_len < 1024) + lua_pushlstring(L, output, output_len); + else + lua_pushnil(L); + return 1; + } +} + +UStringPrepProfile *icu_nameprep; +UStringPrepProfile *icu_nodeprep; +UStringPrepProfile *icu_resourceprep; +UStringPrepProfile *icu_saslprep; + +/* initialize global ICU stringprep profiles */ +void init_icu() +{ + UErrorCode err = U_ZERO_ERROR; + utrace_setLevel(UTRACE_VERBOSE); + icu_nameprep = usprep_openByType(USPREP_RFC3491_NAMEPREP, &err); + icu_nodeprep = usprep_openByType(USPREP_RFC3920_NODEPREP, &err); + icu_resourceprep = usprep_openByType(USPREP_RFC3920_RESOURCEPREP, &err); + icu_saslprep = usprep_openByType(USPREP_RFC4013_SASLPREP, &err); + if (U_FAILURE(err)) fprintf(stderr, "[c] util.encodings: error: %s\n", u_errorName((UErrorCode)err)); +} + +#define MAKE_PREP_FUNC(myFunc, prep) \ +static int myFunc(lua_State *L) { return icu_stringprep_prep(L, prep); } + +MAKE_PREP_FUNC(Lstringprep_nameprep, icu_nameprep) /** stringprep.nameprep(s) */ +MAKE_PREP_FUNC(Lstringprep_nodeprep, icu_nodeprep) /** stringprep.nodeprep(s) */ +MAKE_PREP_FUNC(Lstringprep_resourceprep, icu_resourceprep) /** stringprep.resourceprep(s) */ +MAKE_PREP_FUNC(Lstringprep_saslprep, icu_saslprep) /** stringprep.saslprep(s) */ + +static const luaL_Reg Reg_stringprep[] = +{ + { "nameprep", Lstringprep_nameprep }, + { "nodeprep", Lstringprep_nodeprep }, + { "resourceprep", Lstringprep_resourceprep }, + { "saslprep", Lstringprep_saslprep }, + { NULL, NULL } +}; +#else /* USE_STRINGPREP_ICU */ + +/****************** libidn ********************/ #include <stringprep.h> static int stringprep_prep(lua_State *L, const Stringprep_profile *profile) { size_t len; - const char *s = luaL_checklstring(L, 1, &len); + const char *s; char string[1024]; int ret; + if(!lua_isstring(L, 1)) { + lua_pushnil(L); + return 1; + } + s = lua_tolstring(L, 1, &len); if (len >= 1024) { lua_pushnil(L); - return 1; // TODO return error message + return 1; /* TODO return error message */ } strcpy(string, s); - ret = stringprep(string, 1024, 0, profile); + ret = stringprep(string, 1024, (Stringprep_profile_flags)0, profile); if (ret == STRINGPREP_OK) { lua_pushstring(L, string); return 1; } else { lua_pushnil(L); - return 1; // TODO return error message + return 1; /* TODO return error message */ } } @@ -159,25 +244,93 @@ static const luaL_Reg Reg_stringprep[] = { "saslprep", Lstringprep_saslprep }, { NULL, NULL } }; +#endif /***************** IDNA *****************/ +#ifdef USE_STRINGPREP_ICU +#include <unicode/ustdio.h> +#include <unicode/uidna.h> +/* IDNA2003 or IDNA2008 ? ? ? */ +static int Lidna_to_ascii(lua_State *L) /** idna.to_ascii(s) */ +{ + size_t len; + int32_t ulen, dest_len, output_len; + const char *s = luaL_checklstring(L, 1, &len); + UChar ustr[1024]; + UErrorCode err = U_ZERO_ERROR; + UChar dest[1024]; + char output[1024]; + + u_strFromUTF8(ustr, 1024, &ulen, s, len, &err); + if (U_FAILURE(err)) { + lua_pushnil(L); + return 1; + } + + dest_len = uidna_IDNToASCII(ustr, ulen, dest, 1024, UIDNA_USE_STD3_RULES, NULL, &err); + if (U_FAILURE(err)) { + lua_pushnil(L); + return 1; + } else { + u_strToUTF8(output, 1024, &output_len, dest, dest_len, &err); + if (U_SUCCESS(err) && output_len < 1024) + lua_pushlstring(L, output, output_len); + else + lua_pushnil(L); + return 1; + } +} + +static int Lidna_to_unicode(lua_State *L) /** idna.to_unicode(s) */ +{ + size_t len; + int32_t ulen, dest_len, output_len; + const char *s = luaL_checklstring(L, 1, &len); + UChar ustr[1024]; + UErrorCode err = U_ZERO_ERROR; + UChar dest[1024]; + char output[1024]; + + u_strFromUTF8(ustr, 1024, &ulen, s, len, &err); + if (U_FAILURE(err)) { + lua_pushnil(L); + return 1; + } + + dest_len = uidna_IDNToUnicode(ustr, ulen, dest, 1024, UIDNA_USE_STD3_RULES, NULL, &err); + if (U_FAILURE(err)) { + lua_pushnil(L); + return 1; + } else { + u_strToUTF8(output, 1024, &output_len, dest, dest_len, &err); + if (U_SUCCESS(err) && output_len < 1024) + lua_pushlstring(L, output, output_len); + else + lua_pushnil(L); + return 1; + } +} + +#else /* USE_STRINGPREP_ICU */ +/****************** libidn ********************/ #include <idna.h> +#include <idn-free.h> static int Lidna_to_ascii(lua_State *L) /** idna.to_ascii(s) */ { size_t len; const char *s = luaL_checklstring(L, 1, &len); char* output = NULL; - int ret = idna_to_ascii_8z(s, &output, 0); + int ret = idna_to_ascii_8z(s, &output, IDNA_USE_STD3_ASCII_RULES); if (ret == IDNA_SUCCESS) { lua_pushstring(L, output); - if (output) free(output); + idn_free(output); return 1; } else { lua_pushnil(L); - if (output) free(output); - return 1; // TODO return error message + idn_free(output); + return 1; /* TODO return error message */ } } @@ -189,14 +342,15 @@ static int Lidna_to_unicode(lua_State *L) /** idna.to_unicode(s) */ int ret = idna_to_unicode_8z8z(s, &output, 0); if (ret == IDNA_SUCCESS) { lua_pushstring(L, output); - if (output) free(output); + idn_free(output); return 1; } else { lua_pushnil(L); - if (output) free(output); - return 1; // TODO return error message + idn_free(output); + return 1; /* TODO return error message */ } } +#endif static const luaL_Reg Reg_idna[] = { @@ -214,6 +368,9 @@ static const luaL_Reg Reg[] = LUALIB_API int luaopen_util_encodings(lua_State *L) { +#ifdef USE_STRINGPREP_ICU + init_icu(); +#endif luaL_register(L, "encodings", Reg); lua_pushliteral(L, "base64"); diff --git a/util-src/hashes.c b/util-src/hashes.c index 907167e2..8f7d7140 100644 --- a/util-src/hashes.c +++ b/util-src/hashes.c @@ -1,6 +1,6 @@ -/* Prosody IM v0.4 --- Copyright (C) 2008 Matthew Wild --- Copyright (C) 2008 Waqas Hussain +/* Prosody IM +-- Copyright (C) 2009-2010 Matthew Wild +-- Copyright (C) 2009-2010 Waqas Hussain -- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. @@ -14,14 +14,19 @@ */ #include <string.h> +#include <stdlib.h> +#include <inttypes.h> #include "lua.h" #include "lauxlib.h" #include <openssl/sha.h> #include <openssl/md5.h> -const char* hex_tab = "0123456789abcdef"; -void toHex(const char* in, int length, char* out) { +#define HMAC_IPAD 0x36363636 +#define HMAC_OPAD 0x5c5c5c5c + +const char *hex_tab = "0123456789abcdef"; +void toHex(const unsigned char *in, int length, unsigned char *out) { int i; for (i = 0; i < length; i++) { out[i*2] = hex_tab[(in[i] >> 4) & 0xF]; @@ -34,28 +39,161 @@ static int myFunc(lua_State *L) { \ size_t len; \ const char *s = luaL_checklstring(L, 1, &len); \ int hex_out = lua_toboolean(L, 2); \ - char hash[size]; \ - char result[size*2]; \ - func((const unsigned char*)s, len, (unsigned char*)hash); \ + unsigned char hash[size], result[size*2]; \ + func((const unsigned char*)s, len, hash); \ if (hex_out) { \ toHex(hash, size, result); \ - lua_pushlstring(L, result, size*2); \ + lua_pushlstring(L, (char*)result, size*2); \ } else { \ - lua_pushlstring(L, hash, size);\ + lua_pushlstring(L, (char*)hash, size);\ } \ return 1; \ } -MAKE_HASH_FUNCTION(Lsha1, SHA1, 20) -MAKE_HASH_FUNCTION(Lsha256, SHA256, 32) -MAKE_HASH_FUNCTION(Lmd5, MD5, 16) +MAKE_HASH_FUNCTION(Lsha1, SHA1, SHA_DIGEST_LENGTH) +MAKE_HASH_FUNCTION(Lsha224, SHA224, SHA224_DIGEST_LENGTH) +MAKE_HASH_FUNCTION(Lsha256, SHA256, SHA256_DIGEST_LENGTH) +MAKE_HASH_FUNCTION(Lsha384, SHA384, SHA384_DIGEST_LENGTH) +MAKE_HASH_FUNCTION(Lsha512, SHA512, SHA512_DIGEST_LENGTH) +MAKE_HASH_FUNCTION(Lmd5, MD5, MD5_DIGEST_LENGTH) + +struct hash_desc { + int (*Init)(void*); + int (*Update)(void*, const void *, size_t); + int (*Final)(unsigned char*, void*); + size_t digestLength; + void *ctx, *ctxo; +}; + +static void hmac(struct hash_desc *desc, const char *key, size_t key_len, + const char *msg, size_t msg_len, unsigned char *result) +{ + union xory { + unsigned char bytes[64]; + uint32_t quadbytes[16]; + }; + + int i; + char hashedKey[64]; /* Maximum used digest length */ + union xory k_ipad, k_opad; + + if (key_len > 64) { + desc->Init(desc->ctx); + desc->Update(desc->ctx, key, key_len); + desc->Final(desc->ctx, hashedKey); + key = (const char*)hashedKey; + key_len = desc->digestLength; + } + + memcpy(k_ipad.bytes, key, key_len); + memset(k_ipad.bytes + key_len, 0, 64 - key_len); + memcpy(k_opad.bytes, k_ipad.bytes, 64); + + for (i = 0; i < 16; i++) { + k_ipad.quadbytes[i] ^= HMAC_IPAD; + k_opad.quadbytes[i] ^= HMAC_OPAD; + } + + desc->Init(desc->ctx); + desc->Update(desc->ctx, k_ipad.bytes, 64); + desc->Init(desc->ctxo); + desc->Update(desc->ctxo, k_opad.bytes, 64); + desc->Update(desc->ctx, msg, msg_len); + desc->Final(result, desc->ctx); + desc->Update(desc->ctxo, result, desc->digestLength); + desc->Final(result, desc->ctxo); +} + +#define MAKE_HMAC_FUNCTION(myFunc, func, size, type) \ +static int myFunc(lua_State *L) { \ + type ctx, ctxo; \ + unsigned char hash[size], result[2*size]; \ + size_t key_len, msg_len; \ + const char *key = luaL_checklstring(L, 1, &key_len); \ + const char *msg = luaL_checklstring(L, 2, &msg_len); \ + const int hex_out = lua_toboolean(L, 3); \ + struct hash_desc desc; \ + desc.Init = (int (*)(void*))func##_Init; \ + desc.Update = (int (*)(void*, const void *, size_t))func##_Update; \ + desc.Final = (int (*)(unsigned char*, void*))func##_Final; \ + desc.digestLength = size; \ + desc.ctx = &ctx; \ + desc.ctxo = &ctxo; \ + hmac(&desc, key, key_len, msg, msg_len, hash); \ + if (hex_out) { \ + toHex(hash, size, result); \ + lua_pushlstring(L, (char*)result, size*2); \ + } else { \ + lua_pushlstring(L, (char*)hash, size); \ + } \ + return 1; \ +} + +MAKE_HMAC_FUNCTION(Lhmac_sha1, SHA1, SHA_DIGEST_LENGTH, SHA_CTX) +MAKE_HMAC_FUNCTION(Lhmac_sha256, SHA256, SHA256_DIGEST_LENGTH, SHA256_CTX) +MAKE_HMAC_FUNCTION(Lhmac_sha512, SHA512, SHA512_DIGEST_LENGTH, SHA512_CTX) +MAKE_HMAC_FUNCTION(Lhmac_md5, MD5, MD5_DIGEST_LENGTH, MD5_CTX) + +static int LscramHi(lua_State *L) { + union xory { + unsigned char bytes[SHA_DIGEST_LENGTH]; + uint32_t quadbytes[SHA_DIGEST_LENGTH/4]; + }; + int i; + SHA_CTX ctx, ctxo; + unsigned char Ust[SHA_DIGEST_LENGTH]; + union xory Und; + union xory res; + size_t str_len, salt_len; + struct hash_desc desc; + const char *str = luaL_checklstring(L, 1, &str_len); + const char *salt = luaL_checklstring(L, 2, &salt_len); + char *salt2; + const int iter = luaL_checkinteger(L, 3); + + desc.Init = (int (*)(void*))SHA1_Init; + desc.Update = (int (*)(void*, const void *, size_t))SHA1_Update; + desc.Final = (int (*)(unsigned char*, void*))SHA1_Final; + desc.digestLength = SHA_DIGEST_LENGTH; + desc.ctx = &ctx; + desc.ctxo = &ctxo; + + salt2 = malloc(salt_len + 4); + if (salt2 == NULL) + luaL_error(L, "Out of memory in scramHi"); + memcpy(salt2, salt, salt_len); + memcpy(salt2 + salt_len, "\0\0\0\1", 4); + hmac(&desc, str, str_len, salt2, salt_len + 4, Ust); + free(salt2); + + memcpy(res.bytes, Ust, sizeof(res)); + for (i = 1; i < iter; i++) { + int j; + hmac(&desc, str, str_len, (char*)Ust, sizeof(Ust), Und.bytes); + for (j = 0; j < SHA_DIGEST_LENGTH/4; j++) + res.quadbytes[j] ^= Und.quadbytes[j]; + memcpy(Ust, Und.bytes, sizeof(Ust)); + } + + lua_pushlstring(L, (char*)res.bytes, SHA_DIGEST_LENGTH); + + return 1; +} static const luaL_Reg Reg[] = { - { "sha1", Lsha1 }, - { "sha256", Lsha256 }, - { "md5", Lmd5 }, - { NULL, NULL } + { "sha1", Lsha1 }, + { "sha224", Lsha224 }, + { "sha256", Lsha256 }, + { "sha384", Lsha384 }, + { "sha512", Lsha512 }, + { "md5", Lmd5 }, + { "hmac_sha1", Lhmac_sha1 }, + { "hmac_sha256", Lhmac_sha256 }, + { "hmac_sha512", Lhmac_sha512 }, + { "hmac_md5", Lhmac_md5 }, + { "scram_Hi_sha1", LscramHi }, + { NULL, NULL } }; LUALIB_API int luaopen_util_hashes(lua_State *L) diff --git a/util-src/pposix.c b/util-src/pposix.c index d27a84b1..f5cc8270 100644 --- a/util-src/pposix.c +++ b/util-src/pposix.c @@ -1,8 +1,8 @@ -/* Prosody IM v0.4 --- Copyright (C) 2008-2009 Matthew Wild --- Copyright (C) 2008-2009 Waqas Hussain +/* Prosody IM +-- Copyright (C) 2008-2010 Matthew Wild +-- Copyright (C) 2008-2010 Waqas Hussain -- Copyright (C) 2009 Tobias Markmann --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -13,14 +13,16 @@ * POSIX support functions for Lua */ -#define MODULE_VERSION "0.3.1" +#define MODULE_VERSION "0.3.6" #include <stdlib.h> +#include <math.h> #include <unistd.h> #include <libgen.h> #include <sys/resource.h> #include <sys/types.h> #include <sys/stat.h> +#include <sys/utsname.h> #include <fcntl.h> #include <syslog.h> @@ -30,22 +32,33 @@ #include <string.h> #include <errno.h> #include "lua.h" +#include "lualib.h" #include "lauxlib.h" +#include <fcntl.h> +#if defined(_GNU_SOURCE) +#include <linux/falloc.h> +#endif + +#if (defined(_SVID_SOURCE) && !defined(WITHOUT_MALLINFO)) + #include <malloc.h> + #define WITH_MALLINFO +#endif + /* Daemonization support */ static int lc_daemonize(lua_State *L) { pid_t pid; - + if ( getppid() == 1 ) { lua_pushboolean(L, 0); lua_pushstring(L, "already-daemonized"); return 2; } - + /* Attempt initial fork */ if((pid = fork()) < 0) { @@ -61,7 +74,7 @@ static int lc_daemonize(lua_State *L) lua_pushnumber(L, pid); return 2; } - + /* and we are the child process */ if(setsid() == -1) { @@ -76,6 +89,10 @@ static int lc_daemonize(lua_State *L) close(0); close(1); close(2); + /* Make sure accidental use of FDs 0, 1, 2 don't cause weirdness */ + open("/dev/null", O_RDONLY); + open("/dev/null", O_WRONLY); + open("/dev/null", O_WRONLY); /* Final fork, use it wisely */ if(fork()) @@ -91,10 +108,14 @@ static int lc_daemonize(lua_State *L) const char * const facility_strings[] = { "auth", +#if !(defined(sun) || defined(__sun)) "authpriv", +#endif "cron", "daemon", +#if !(defined(sun) || defined(__sun)) "ftp", +#endif "kern", "local0", "local1", @@ -113,10 +134,14 @@ const char * const facility_strings[] = { }; int facility_constants[] = { LOG_AUTH, +#if !(defined(sun) || defined(__sun)) LOG_AUTHPRIV, +#endif LOG_CRON, LOG_DAEMON, +#if !(defined(sun) || defined(__sun)) LOG_FTP, +#endif LOG_KERN, LOG_LOCAL0, LOG_LOCAL1, @@ -142,7 +167,7 @@ int facility_constants[] = { exist, the results are undefined. Most portable is to use a string constant. " -- syslog manpage -*/ +*/ char* syslog_ident = NULL; int lc_syslog_open(lua_State* L) @@ -151,12 +176,12 @@ int lc_syslog_open(lua_State* L) facility = facility_constants[facility]; luaL_checkstring(L, 1); - + if(syslog_ident) free(syslog_ident); - + syslog_ident = strdup(lua_tostring(L, 1)); - + openlog(syslog_ident, LOG_PID, facility); return 0; } @@ -179,12 +204,13 @@ int level_constants[] = { }; int lc_syslog_log(lua_State* L) { - int level = luaL_checkoption(L, 1, "notice", level_strings); - level = level_constants[level]; + int level = level_constants[luaL_checkoption(L, 1, "notice", level_strings)]; - luaL_checkstring(L, 2); + if(lua_gettop(L) == 3) + syslog(level, "%s: %s", luaL_checkstring(L, 2), luaL_checkstring(L, 3)); + else + syslog(level, "%s", lua_tostring(L, 2)); - syslog(level, "%s", lua_tostring(L, 2)); return 0; } @@ -256,7 +282,7 @@ int lc_setuid(lua_State* L) { uid = lua_tonumber(L, 1); } - + if(uid>-1) { /* Ok, attempt setuid */ @@ -285,7 +311,7 @@ int lc_setuid(lua_State* L) return 1; } } - + /* Seems we couldn't find a valid UID to switch to */ lua_pushboolean(L, 0); lua_pushstring(L, "invalid-uid"); @@ -314,7 +340,7 @@ int lc_setgid(lua_State* L) { gid = lua_tonumber(L, 1); } - + if(gid>-1) { /* Ok, attempt setgid */ @@ -343,20 +369,107 @@ int lc_setgid(lua_State* L) return 1; } } - + /* Seems we couldn't find a valid GID to switch to */ lua_pushboolean(L, 0); lua_pushstring(L, "invalid-gid"); return 2; } +int lc_initgroups(lua_State* L) +{ + int ret; + gid_t gid; + struct passwd *p; + + if(!lua_isstring(L, 1)) + { + lua_pushnil(L); + lua_pushstring(L, "invalid-username"); + return 2; + } + p = getpwnam(lua_tostring(L, 1)); + if(!p) + { + lua_pushnil(L); + lua_pushstring(L, "no-such-user"); + return 2; + } + if(lua_gettop(L) < 2) + lua_pushnil(L); + switch(lua_type(L, 2)) + { + case LUA_TNIL: + gid = p->pw_gid; + break; + case LUA_TNUMBER: + gid = lua_tointeger(L, 2); + break; + default: + lua_pushnil(L); + lua_pushstring(L, "invalid-gid"); + return 2; + } + ret = initgroups(lua_tostring(L, 1), gid); + if(ret) + { + switch(errno) + { + case ENOMEM: + lua_pushnil(L); + lua_pushstring(L, "no-memory"); + break; + case EPERM: + lua_pushnil(L); + lua_pushstring(L, "permission-denied"); + break; + default: + lua_pushnil(L); + lua_pushstring(L, "unknown-error"); + } + } + else + { + lua_pushboolean(L, 1); + lua_pushnil(L); + } + return 2; +} + +int lc_umask(lua_State* L) +{ + char old_mode_string[7]; + mode_t old_mode = umask(strtoul(luaL_checkstring(L, 1), NULL, 8)); + + snprintf(old_mode_string, sizeof(old_mode_string), "%03o", old_mode); + old_mode_string[sizeof(old_mode_string)-1] = 0; + lua_pushstring(L, old_mode_string); + + return 1; +} + +int lc_mkdir(lua_State* L) +{ + int ret = mkdir(luaL_checkstring(L, 1), S_IRUSR | S_IWUSR | S_IXUSR + | S_IRGRP | S_IWGRP | S_IXGRP + | S_IROTH | S_IXOTH); /* mode 775 */ + + lua_pushboolean(L, ret==0); + if(ret) + { + lua_pushstring(L, strerror(errno)); + return 2; + } + return 1; +} + /* Like POSIX's setrlimit()/getrlimit() API functions. - * + * * Syntax: * pposix.setrlimit( resource, soft limit, hard limit) - * + * * Any negative limit will be replace with the current limit by an additional call of getrlimit(). - * + * * Example usage: * pposix.setrlimit("NOFILE", 1000, 2000) */ @@ -365,11 +478,16 @@ int string2resource(const char *s) { if (!strcmp(s, "CPU")) return RLIMIT_CPU; if (!strcmp(s, "DATA")) return RLIMIT_DATA; if (!strcmp(s, "FSIZE")) return RLIMIT_FSIZE; - if (!strcmp(s, "MEMLOCK")) return RLIMIT_MEMLOCK; if (!strcmp(s, "NOFILE")) return RLIMIT_NOFILE; + if (!strcmp(s, "STACK")) return RLIMIT_STACK; +#if !(defined(sun) || defined(__sun)) + if (!strcmp(s, "MEMLOCK")) return RLIMIT_MEMLOCK; if (!strcmp(s, "NPROC")) return RLIMIT_NPROC; if (!strcmp(s, "RSS")) return RLIMIT_RSS; - if (!strcmp(s, "STACK")) return RLIMIT_STACK; +#endif +#ifdef RLIMIT_NICE + if (!strcmp(s, "NICE")) return RLIMIT_NICE; +#endif return -1; } @@ -383,16 +501,16 @@ int lc_setrlimit(lua_State *L) { lua_pushboolean(L, 0); lua_pushstring(L, "incorrect-arguments"); } - + resource = luaL_checkstring(L, 1); softlimit = luaL_checkinteger(L, 2); hardlimit = luaL_checkinteger(L, 3); - + rid = string2resource(resource); if (rid != -1) { struct rlimit lim; struct rlimit lim_current; - + if (softlimit < 0 || hardlimit < 0) { if (getrlimit(rid, &lim_current)) { lua_pushboolean(L, 0); @@ -400,12 +518,12 @@ int lc_setrlimit(lua_State *L) { return 2; } } - + if (softlimit < 0) lim.rlim_cur = lim_current.rlim_cur; else lim.rlim_cur = softlimit; if (hardlimit < 0) lim.rlim_max = lim_current.rlim_max; else lim.rlim_max = hardlimit; - + if (setrlimit(rid, &lim)) { lua_pushboolean(L, 0); lua_pushstring(L, "setrlimit-failed"); @@ -426,13 +544,13 @@ int lc_getrlimit(lua_State *L) { const char *resource = NULL; int rid = -1; struct rlimit lim; - + if (arguments != 1) { lua_pushboolean(L, 0); lua_pushstring(L, "invalid-arguments"); return 2; } - + resource = luaL_checkstring(L, 1); rid = string2resource(resource); if (rid != -1) { @@ -453,51 +571,191 @@ int lc_getrlimit(lua_State *L) { return 3; } +int lc_abort(lua_State* L) +{ + abort(); + return 0; +} + +int lc_uname(lua_State* L) +{ + struct utsname uname_info; + if(uname(&uname_info) != 0) + { + lua_pushnil(L); + lua_pushstring(L, strerror(errno)); + return 2; + } + lua_newtable(L); + lua_pushstring(L, uname_info.sysname); + lua_setfield(L, -2, "sysname"); + lua_pushstring(L, uname_info.nodename); + lua_setfield(L, -2, "nodename"); + lua_pushstring(L, uname_info.release); + lua_setfield(L, -2, "release"); + lua_pushstring(L, uname_info.version); + lua_setfield(L, -2, "version"); + lua_pushstring(L, uname_info.machine); + lua_setfield(L, -2, "machine"); + return 1; +} + +int lc_setenv(lua_State* L) +{ + const char *var = luaL_checkstring(L, 1); + const char *value; + + /* If the second argument is nil or nothing, unset the var */ + if(lua_isnoneornil(L, 2)) + { + if(unsetenv(var) != 0) + { + lua_pushnil(L); + lua_pushstring(L, strerror(errno)); + return 2; + } + lua_pushboolean(L, 1); + return 1; + } + + value = luaL_checkstring(L, 2); + + if(setenv(var, value, 1) != 0) + { + lua_pushnil(L); + lua_pushstring(L, strerror(errno)); + return 2; + } + + lua_pushboolean(L, 1); + return 1; +} + +#ifdef WITH_MALLINFO +int lc_meminfo(lua_State* L) +{ + struct mallinfo info = mallinfo(); + lua_newtable(L); + /* This is the total size of memory allocated with sbrk by malloc, in bytes. */ + lua_pushinteger(L, info.arena); + lua_setfield(L, -2, "allocated"); + /* This is the total size of memory allocated with mmap, in bytes. */ + lua_pushinteger(L, info.hblkhd); + lua_setfield(L, -2, "allocated_mmap"); + /* This is the total size of memory occupied by chunks handed out by malloc. */ + lua_pushinteger(L, info.uordblks); + lua_setfield(L, -2, "used"); + /* This is the total size of memory occupied by free (not in use) chunks. */ + lua_pushinteger(L, info.fordblks); + lua_setfield(L, -2, "unused"); + /* This is the size of the top-most releasable chunk that normally borders the + end of the heap (i.e., the high end of the virtual address space's data segment). */ + lua_pushinteger(L, info.keepcost); + lua_setfield(L, -2, "returnable"); + return 1; +} +#endif + +/* File handle extraction blatantly stolen from + * https://github.com/rrthomas/luaposix/blob/master/lposix.c#L631 + * */ + +#if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE) +int lc_fallocate(lua_State* L) +{ + off_t offset, len; + FILE *f = *(FILE**) luaL_checkudata(L, 1, LUA_FILEHANDLE); + + offset = luaL_checkinteger(L, 2); + len = luaL_checkinteger(L, 3); + +#if defined(_GNU_SOURCE) + if(fallocate(fileno(f), FALLOC_FL_KEEP_SIZE, offset, len) == 0) + { + lua_pushboolean(L, 1); + return 1; + } + + if(errno != ENOSYS && errno != EOPNOTSUPP) + { + lua_pushnil(L); + lua_pushstring(L, strerror(errno)); + return 2; + } +#else +#warning Only using posix_fallocate() fallback. +#warning Linux fallocate() is strongly recommended if available: recompile with -D_GNU_SOURCE +#warning Note that posix_fallocate() will still be used on filesystems that dont support fallocate() +#endif + + if(posix_fallocate(fileno(f), offset, len) == 0) + { + lua_pushboolean(L, 1); + return 1; + } + else + { + lua_pushnil(L); + lua_pushstring(L, strerror(errno)); + /* posix_fallocate() can leave a bunch of NULs at the end, so we cut that + * this assumes that offset == length of the file */ + ftruncate(fileno(f), offset); + return 2; + } +} +#endif + /* Register functions */ int luaopen_util_pposix(lua_State *L) { - lua_newtable(L); + luaL_Reg exports[] = { + { "abort", lc_abort }, - lua_pushcfunction(L, lc_daemonize); - lua_setfield(L, -2, "daemonize"); + { "daemonize", lc_daemonize }, - lua_pushcfunction(L, lc_syslog_open); - lua_setfield(L, -2, "syslog_open"); + { "syslog_open", lc_syslog_open }, + { "syslog_close", lc_syslog_close }, + { "syslog_log", lc_syslog_log }, + { "syslog_setminlevel", lc_syslog_setmask }, - lua_pushcfunction(L, lc_syslog_close); - lua_setfield(L, -2, "syslog_close"); + { "getpid", lc_getpid }, + { "getuid", lc_getuid }, + { "getgid", lc_getgid }, - lua_pushcfunction(L, lc_syslog_log); - lua_setfield(L, -2, "syslog_log"); + { "setuid", lc_setuid }, + { "setgid", lc_setgid }, + { "initgroups", lc_initgroups }, - lua_pushcfunction(L, lc_syslog_setmask); - lua_setfield(L, -2, "syslog_setminlevel"); + { "umask", lc_umask }, - lua_pushcfunction(L, lc_getpid); - lua_setfield(L, -2, "getpid"); + { "mkdir", lc_mkdir }, - lua_pushcfunction(L, lc_getuid); - lua_setfield(L, -2, "getuid"); - lua_pushcfunction(L, lc_getgid); - lua_setfield(L, -2, "getgid"); + { "setrlimit", lc_setrlimit }, + { "getrlimit", lc_getrlimit }, - lua_pushcfunction(L, lc_setuid); - lua_setfield(L, -2, "setuid"); - lua_pushcfunction(L, lc_setgid); - lua_setfield(L, -2, "setgid"); - - lua_pushcfunction(L, lc_setrlimit); - lua_setfield(L, -2, "setrlimit"); - - lua_pushcfunction(L, lc_getrlimit); - lua_setfield(L, -2, "getrlimit"); + { "uname", lc_uname }, + + { "setenv", lc_setenv }, + +#ifdef WITH_MALLINFO + { "meminfo", lc_meminfo }, +#endif + +#if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE) + { "fallocate", lc_fallocate }, +#endif + + { NULL, NULL } + }; + + luaL_register(L, "pposix", exports); lua_pushliteral(L, "pposix"); lua_setfield(L, -2, "_NAME"); lua_pushliteral(L, MODULE_VERSION); lua_setfield(L, -2, "_VERSION"); - + return 1; -}; +} diff --git a/util-src/lsignal.c b/util-src/signal.c index 158efcd6..961d2d3e 100644 --- a/util-src/lsignal.c +++ b/util-src/signal.c @@ -1,9 +1,9 @@ /* - * lsignal.h -- Signal Handler Library for Lua + * signal.c -- Signal Handler Library for Lua * - * Version: 1.000 + * Version: 1.000+changes * - * Copyright (C) 2007 Patrick J. Donnelly (batrick@unm.edu) + * Copyright (C) 2007 Patrick J. Donnelly (batrick@batbytes.com) * * This software is distributed under the same license as Lua 5.0: * @@ -27,6 +27,7 @@ */ #include <signal.h> +#include <stdlib.h> #include "lua.h" #include "lauxlib.h" @@ -149,43 +150,67 @@ static const struct lua_signal lua_signals[] = { {NULL, 0} }; -static int Nsig = 0; static lua_State *Lsig = NULL; static lua_Hook Hsig = NULL; static int Hmask = 0; static int Hcount = 0; +static struct signal_event +{ + int Nsig; + struct signal_event *next_event; +} *signal_queue = NULL; + +static struct signal_event *last_event = NULL; + static void sighook(lua_State *L, lua_Debug *ar) { + struct signal_event *event; + /* restore the old hook */ + lua_sethook(L, Hsig, Hmask, Hcount); + lua_pushstring(L, LUA_SIGNAL); lua_gettable(L, LUA_REGISTRYINDEX); - lua_pushnumber(L, Nsig); - lua_gettable(L, -2); - lua_call(L, 0, 0); + while((event = signal_queue)) + { + lua_pushnumber(L, event->Nsig); + lua_gettable(L, -2); + lua_call(L, 0, 0); + signal_queue = event->next_event; + free(event); + }; + + lua_pop(L, 1); /* pop lua_signal table */ - /* set the old hook */ - lua_sethook(L, Hsig, Hmask, Hcount); } static void handle(int sig) { - Hsig = lua_gethook(Lsig); - Hmask = lua_gethookmask(Lsig); - Hcount = lua_gethookcount(Lsig); - Nsig = sig; - - lua_sethook(Lsig, sighook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); - /* - switch (sig) + if(!signal_queue) { - case SIGABRT: ; - case SIGFPE: ; - case SIGILL: ; - case SIGINT: ; - case SIGSEGV: ; - case SIGTERM: ; - } */ + /* Store the existing debug hook (if any) and its parameters */ + Hsig = lua_gethook(Lsig); + Hmask = lua_gethookmask(Lsig); + Hcount = lua_gethookcount(Lsig); + + signal_queue = malloc(sizeof(struct signal_event)); + signal_queue->Nsig = sig; + signal_queue->next_event = NULL; + + last_event = signal_queue; + + /* Set our new debug hook */ + lua_sethook(Lsig, sighook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); + } + else + { + last_event->next_event = malloc(sizeof(struct signal_event)); + last_event->next_event->Nsig = sig; + last_event->next_event->next_event = NULL; + + last_event = last_event->next_event; + } } /* @@ -301,7 +326,7 @@ static int l_raise(lua_State *L) return 1; } -#ifdef _POSIX_SOURCE +#if defined(__unix__) || defined(__APPLE__) /* define some posix only functions */ @@ -348,7 +373,7 @@ static int l_kill(lua_State *L) static const struct luaL_Reg lsignal_lib[] = { {"signal", l_signal}, {"raise", l_raise}, -#ifdef _POSIX_SOURCE +#if defined(__unix__) || defined(__APPLE__) {"kill", l_kill}, #endif {NULL, NULL} diff --git a/util-src/windows.c b/util-src/windows.c new file mode 100644 index 00000000..121cc471 --- /dev/null +++ b/util-src/windows.c @@ -0,0 +1,89 @@ +/* Prosody IM +-- Copyright (C) 2008-2010 Matthew Wild +-- Copyright (C) 2008-2010 Waqas Hussain +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- +*/ + +/* +* windows.c +* Windows support functions for Lua +*/ + +#include <stdio.h> +#include <windows.h> +#include <windns.h> + +#include "lua.h" +#include "lauxlib.h" + +static int Lget_nameservers(lua_State *L) { + char stack_buffer[1024]; // stack allocated buffer + IP4_ARRAY* ips = (IP4_ARRAY*) stack_buffer; + DWORD len = sizeof(stack_buffer); + DNS_STATUS status; + + status = DnsQueryConfig(DnsConfigDnsServerList, FALSE, NULL, NULL, ips, &len); + if (status == 0) { + DWORD i; + lua_createtable(L, ips->AddrCount, 0); + for (i = 0; i < ips->AddrCount; i++) { + DWORD ip = ips->AddrArray[i]; + char ip_str[16] = ""; + sprintf_s(ip_str, sizeof(ip_str), "%d.%d.%d.%d", (ip >> 0) & 255, (ip >> 8) & 255, (ip >> 16) & 255, (ip >> 24) & 255); + lua_pushstring(L, ip_str); + lua_rawseti(L, -2, i+1); + } + return 1; + } else { + lua_pushnil(L); + lua_pushfstring(L, "DnsQueryConfig returned %d", status); + return 2; + } +} + +static int lerror(lua_State *L, char* string) { + lua_pushnil(L); + lua_pushfstring(L, "%s: %d", string, GetLastError()); + return 2; +} + +static int Lget_consolecolor(lua_State *L) { + HWND console = GetStdHandle(STD_OUTPUT_HANDLE); + WORD color; DWORD read_len; + + CONSOLE_SCREEN_BUFFER_INFO info; + + if (console == INVALID_HANDLE_VALUE) return lerror(L, "GetStdHandle"); + if (!GetConsoleScreenBufferInfo(console, &info)) return lerror(L, "GetConsoleScreenBufferInfo"); + if (!ReadConsoleOutputAttribute(console, &color, sizeof(WORD), info.dwCursorPosition, &read_len)) return lerror(L, "ReadConsoleOutputAttribute"); + + lua_pushnumber(L, color); + return 1; +} +static int Lset_consolecolor(lua_State *L) { + int color = luaL_checkint(L, 1); + HWND console = GetStdHandle(STD_OUTPUT_HANDLE); + if (console == INVALID_HANDLE_VALUE) return lerror(L, "GetStdHandle"); + if (!SetConsoleTextAttribute(console, color)) return lerror(L, "SetConsoleTextAttribute"); + lua_pushboolean(L, 1); + return 1; +} + +static const luaL_Reg Reg[] = +{ + { "get_nameservers", Lget_nameservers }, + { "get_consolecolor", Lget_consolecolor }, + { "set_consolecolor", Lset_consolecolor }, + { NULL, NULL } +}; + +LUALIB_API int luaopen_util_windows(lua_State *L) { + luaL_register(L, "windows", Reg); + lua_pushliteral(L, "version"); /** version */ + lua_pushliteral(L, "-3.14"); + lua_settable(L,-3); + return 1; +} |