Merged UDF Linux and Windows development environments

This commit is contained in:
Bernardo Damele 2010-01-14 01:51:20 +00:00
parent 746cbdba96
commit d4d26b59eb
16 changed files with 777 additions and 278 deletions

View File

@ -1,278 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" type="text/css" href="../mysqludf.css"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>lib_mysqludf_sys - A library of MySQL UDFs for working with the environment in which MySQL runs</title>
</head>
<body>
<div>
<a href="../index.html">Top</a>
| <a href="../mysql_udf_repository_libraries.html">Up</a>
</div>
<h1>lib_mysqludf_sys</h1>
<div>
<a href="lib_mysqludf_sys.html">Documentation</a>
| <a href="lib_mysqludf_sys.so">Binary</a>
| <a href="lib_mysqludf_sys.sql">Installation</a>
| <a href="lib_mysqludf_sys.c">Source</a>
| <a href="lib_mysqludf_sys_0.0.2.tar.gz">tar.gz</a>
</div>
<p>
This library <code>lib_mysqludf_sys</code> contains a number of functions that allows one to interact with the operating system.
</p>
<ol>
<li><a href="#sys_eval"><code>sys_eval</code></a> - executes an arbitrary command, and returns it's output.</li>
<li><a href="#sys_exec"><code>sys_exec</code></a> - executes an arbitrary command, and returns it's exit code.</li>
<li><a href="#sys_get"><code>sys_get</code></a> - gets the value of an environment variable.</li>
<li><a href="#sys_set"><code>sys_set</code></a> - create an environment variable, or update the value of an existing environment variable.</li>
</ol>
<p>
Use <a href="#lib_mysqludf_sys_info"><code>lib_mysqludf_sys_info()</code></a> to obtain information about the currently installed version of <code>lib_mysqludf_sys</code>.
</p>
<a name="sys_eval"></a><h2>sys_eval</h2>
<p>
<code>sys_eval</code> takes one command string argument and executes it, returning its output.
</p>
<h3>Syntax</h3>
<pre>sys_eval(<b>arg1</b>)</pre>
<h3>Parameters and Return Values</h3>
<dl>
<dt><code><b>arg1</b></code></dt>
<dd>
A command string valid for the current operating system or execution environment.
</dd>
<dt>returns</dt>
<dd>
Whatever output the command pushed to the standard output stream.
</dd>
</dl>
<h3>Installation</h3>
<p>
Place the shared library binary in an appropriate location.
Log in to mysql as root or as another user with sufficient privileges, and select any database.
Then, create the function using the following DDL statement:
</p>
<pre>
CREATE FUNCTION sys_eval RETURNS STRING SONAME 'lib_mysqludf_sys.so';
</pre>
<p>
The function will be globally available in all databases.
</p>
<p>
The deinstall the function, run the following statement:
</p>
<pre>
DROP FUNCTION sys_eval;
</pre>
<h3>Examples</h3>
<p>
None yet
</p>
<h3>A Note of Caution</h3>
<p>
Be very careful in deciding whether you need this function.
UDFs are available to all database users - you cannot grant EXECUTE privileges for them.
As the commandstring passed to <code>sys_exec</code> can do pretty much everything,
exposing the function poses a very real security hazard.
</p>
<p>
Even for a benign user, it is possible to accidentally do a lot of damage with it.
The call will be executed with the privileges of the os user that runs MySQL,
so it is entirely feasible to delete MySQL's data directory, or worse.
</p>
<p>
The function is intended for specialized MySQL applications where one needs extended
control over the operating system.
Currently, we do not have UDF's for ftp, email and http,
and this function can be used to implement such functionality in case it is really necessary
(datawarehouse staging areas could be a case in example).
</p>
<p>
You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this.
</p>
<p>
If you do decide to use this library in a production environment, make sure that only specific commands can be run and file access is limited by using <a href="http://www.novell.com/documentation/apparmor/index.html">AppArmor</a>.
</p>
<a name="sys_exec"></a><h2>sys_exec</h2>
<p>
<code>sys_exec</code> takes one command string argument and executes it.
</p>
<h3>Syntax</h3>
<pre>sys_exec(<b>arg1</b>)</pre>
<h3>Parameters and Return Values</h3>
<dl>
<dt><code><b>arg1</b></code></dt>
<dd>
A command string valid for the current operating system or execution environment.
</dd>
<dt>returns</dt>
<dd>
An (integer) exit code returned by the executed process.
</dd>
</dl>
<h3>Installation</h3>
<p>
Place the shared library binary in an appropriate location.
Log in to mysql as root or as another user with sufficient privileges, and select any database.
Then, create the function using the following DDL statement:
</p>
<pre>
CREATE FUNCTION sys_exec RETURNS INT SONAME 'lib_mysqludf_sys.so';
</pre>
<p>
The function will be globally available in all databases.
</p>
<p>
The deinstall the function, run the following statement:
</p>
<pre>
DROP FUNCTION sys_exec;
</pre>
<h3>Examples</h3>
<p>
None yet
</p>
<h3>A Note of Caution</h3>
<p>
Be very careful in deciding whether you need this function.
UDFs are available to all database users - you cannot grant EXECUTE privileges for them.
As the commandstring passed to <code>sys_exec</code> can do pretty much everything,
exposing the function poses a very real security hazard.
</p>
<p>
Even for a benign user, it is possible to accidentally do a lot of damage with it.
The call will be executed with the privileges of the os user that runs MySQL,
so it is entirely feasible to delete MySQL's data directory, or worse.
</p>
<p>
The function is intended for specialized MySQL applications where one needs extended
control over the operating system.
Currently, we do not have UDF's for ftp, email and http,
and this function can be used to implement such functionality in case it is really necessary
(datawarehouse staging areas could be a case in example).
</p>
<p>
You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this.
</p>
<p>
If you do decide to use this library in a production environment, make sure that only specific commands can be run and file access is limited by using <a href="http://www.novell.com/documentation/apparmor/index.html">AppArmor</a>.
</p>
<a name="sys_get"></a><h2>sys_get</h2>
<p>
<code>sys_get</code> takes the name of an environment variable and returns the value of the variable.
</p>
<h3>Syntax</h3>
<pre>sys_get([<b>arg1</b>)</pre>
<h3>Parameters and Return Values</h3>
<dl>
<dt><code><b>arg1</b></code></dt>
<dd>
A string that denotes the name of an environment value.
</dd>
<dt>returns</dt>
<dd>
If the variable exists, a string containing the value of the environment variable.
If the variable does not exist, the function return NULL.
</dd>
</dl>
<h3>Installation</h3>
<p>
Place the shared library binary in an appropriate location.
Log in to mysql as root or as another user with sufficient privileges, and select any database.
Then, create the function using the following DDL statement:
</p>
<pre>
CREATE FUNCTION sys_get RETURNS STRING SONAME 'lib_mysqludf_sys.so';
</pre>
<p>
The function will be globally available in all databases.
</p>
<p>
The deinstall the function, run the following statement:
</p>
<pre>
DROP FUNCTION sys_get;
</pre>
<h3>Examples</h3>
<p>
None yet
</p>
<h3>A Note of Caution</h3>
<p>
Be very careful in deciding whether you need this function.
UDFs are available to all database users - you cannot grant EXECUTE privileges for them.
The variables known in the environment where mysql runs are freely accessible using this function.
Any user can get access to potentially secret information, such as
the user that is running mysqld, the path of the user's home directory etc.
</p>
<p>
The function is intended for specialized MySQL applications where one needs extended
control over the operating system.
</p>
<p>
You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this.
</p>
<a name="sys_set"></a><h2>sys_set</h2>
<p>
<code>sys_get</code> takes the name of an environment variable and returns the value of the variable.
</p>
<h3>Syntax</h3>
<pre>sys_set([<b>arg1, arg2</b>)</pre>
<h3>Parameters and Return Values</h3>
<dl>
<dt><code><b>arg1</b></code></dt>
<dd>
A string that denotes the name of an environment value.
</dd>
<dt><code><b>arg2</b></code></dt>
<dd>
An expression that contains the value that is to be assigned to the environment variable.
</dd>
<dt>returns</dt>
<dd>
0 if the assignment or creation succeed.
non-zero otherwise.
</dd>
</dl>
<h3>Installation</h3>
<p>
Place the shared library binary in an appropriate location.
Log in to mysql as root or as another user with sufficient privileges, and select any database.
Then, create the function using the following DDL statement:
</p>
<pre>
CREATE FUNCTION sys_set RETURNS STRING SONAME 'lib_mysqludf_sys.so';
</pre>
<p>
The function will be globally available in all databases.
</p>
<p>
The deinstall the function, run the following statement:
</p>
<pre>
DROP FUNCTION sys_set;
</pre>
<h3>Examples</h3>
<p>
None yet
</p>
<h3>A Note of Caution</h3>
<p>
Be very careful in deciding whether you need this function.
UDFs are available to all database users - you cannot grant EXECUTE privileges for them.
This function will overwrite existing environment variables.
</p>
<p>
The function is intended for specialized MySQL applications where one needs extended
control over the operating system.
</p>
<p>
You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this.
</p>
</body>
</html

View File

@ -0,0 +1,19 @@
1. Before compiling, certain enviroment variables have to be set, depending on the project used. for project lib_mysqludf_sys variables PLATFORM_SDK_DIR and MYSQL_SERVER_DIR have to be set, while for lib_postgresqludf_sys PLATFORM_SDK_DIR and POSTGRESQL_SERVER_DIR.
--------------------------------------------------------------------------
Variable name Variable description
--------------------------------------------------------------------------
PLATFORM_SDK_DIR directory where the Platform SDK is installed
MYSQL_SERVER_DIR directory where the MySQL is installed
POSTGRESQL_SERVER_DIR directory where the PostgreSQL is installed
2. Procedure for setting environment variables:
My Computer -> Properties -> Advanced -> Environment Variables
User variables -> New
3. Sample values:
--------------------------------------------------------------------------
Variable name Variable value
--------------------------------------------------------------------------
PLATFORM_SDK_DIR C:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2
MYSQL_SERVER_DIR C:\Program Files\MySQL\MySQL Server 5.1
POSTGRESQL_SERVER_DIR C:\Program Files\PostgreSQL\8.3

Binary file not shown.

View File

@ -0,0 +1,551 @@
/*
lib_mysqludf_sys - a library with miscellaneous (operating) system level functions
Copyright (C) 2007 Roland Bouman
Copyright (C) 2008-2009 Roland Bouman and Bernardo Damele A. G.
web: http://www.mysqludf.org/
email: mysqludfs@gmail.com, bernardo.damele@gmail.com
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
#define DLLEXP __declspec(dllexport)
#else
#define DLLEXP
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
#ifdef STANDARD
#include <string.h>
#include <stdlib.h>
#include <time.h>
#ifdef __WIN__
typedef unsigned __int64 ulonglong;
typedef __int64 longlong;
#else
typedef unsigned long long ulonglong;
typedef long long longlong;
#endif /*__WIN__*/
#else
#include <my_global.h>
#include <my_sys.h>
#endif
#include <mysql.h>
#include <m_ctype.h>
#include <m_string.h>
#include <stdlib.h>
#include <ctype.h>
#ifdef HAVE_DLOPEN
#ifdef __cplusplus
extern "C" {
#endif
#define LIBVERSION "lib_mysqludf_sys version 0.0.3"
#ifdef __WIN__
#define SETENV(name,value) SetEnvironmentVariable(name,value);
#else
#define SETENV(name,value) setenv(name,value,1);
#endif
DLLEXP
my_bool lib_mysqludf_sys_info_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
);
DLLEXP
void lib_mysqludf_sys_info_deinit(
UDF_INIT *initid
);
DLLEXP
char* lib_mysqludf_sys_info(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
);
/**
* sys_get
*
* Gets the value of the specified environment variable.
*/
DLLEXP
my_bool sys_get_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
);
DLLEXP
void sys_get_deinit(
UDF_INIT *initid
);
DLLEXP
char* sys_get(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
);
/**
* sys_set
*
* Sets the value of the environment variables.
* This function accepts a set of name/value pairs
* which are then set as environment variables.
* Use sys_get to retrieve the value of such a variable
*/
DLLEXP
my_bool sys_set_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
);
DLLEXP
void sys_set_deinit(
UDF_INIT *initid
);
DLLEXP
long long sys_set(
UDF_INIT *initid
, UDF_ARGS *args
, char *is_null
, char *error
);
/**
* sys_exec
*
* executes the argument commandstring and returns its exit status.
* Beware that this can be a security hazard.
*/
DLLEXP
my_bool sys_exec_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
);
DLLEXP
void sys_exec_deinit(
UDF_INIT *initid
);
DLLEXP
my_ulonglong sys_exec(
UDF_INIT *initid
, UDF_ARGS *args
, char *is_null
, char *error
);
/**
* sys_eval
*
* executes the argument commandstring and returns its standard output.
* Beware that this can be a security hazard.
*/
DLLEXP
my_bool sys_eval_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
);
DLLEXP
void sys_eval_deinit(
UDF_INIT *initid
);
DLLEXP
char* sys_eval(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
);
/**
* sys_bineval
*
* executes bynary opcodes.
* Beware that this can be a security hazard.
*/
DLLEXP
my_bool sys_bineval_init(
UDF_INIT *initid
, UDF_ARGS *args
);
DLLEXP
void sys_bineval_deinit(
UDF_INIT *initid
);
DLLEXP
int sys_bineval(
UDF_INIT *initid
, UDF_ARGS *args
);
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter);
#endif
#ifdef __cplusplus
}
#endif
/**
* lib_mysqludf_sys_info
*/
my_bool lib_mysqludf_sys_info_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
){
my_bool status;
if(args->arg_count!=0){
strcpy(
message
, "No arguments allowed (udf: lib_mysqludf_sys_info)"
);
status = 1;
} else {
status = 0;
}
return status;
}
void lib_mysqludf_sys_info_deinit(
UDF_INIT *initid
){
}
char* lib_mysqludf_sys_info(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
){
strcpy(result,LIBVERSION);
*length = strlen(LIBVERSION);
return result;
}
my_bool sys_get_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
){
if(args->arg_count==1
&& args->arg_type[0]==STRING_RESULT){
initid->maybe_null = 1;
return 0;
} else {
strcpy(
message
, "Expected exactly one string type parameter"
);
return 1;
}
}
void sys_get_deinit(
UDF_INIT *initid
){
}
char* sys_get(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
){
char* value = getenv(args->args[0]);
if(value == NULL){
*is_null = 1;
} else {
*length = strlen(value);
}
return value;
}
my_bool sys_set_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
){
if(args->arg_count!=2){
strcpy(
message
, "Expected exactly two arguments"
);
return 1;
}
if(args->arg_type[0]!=STRING_RESULT){
strcpy(
message
, "Expected string type for name parameter"
);
return 1;
}
args->arg_type[1]=STRING_RESULT;
if((initid->ptr=malloc(
args->lengths[0]
+ 1
+ args->lengths[1]
+ 1
))==NULL){
strcpy(
message
, "Could not allocate memory"
);
return 1;
}
return 0;
}
void sys_set_deinit(
UDF_INIT *initid
){
if (initid->ptr!=NULL){
free(initid->ptr);
}
}
long long sys_set(
UDF_INIT *initid
, UDF_ARGS *args
, char *is_null
, char *error
){
char *name = initid->ptr;
char *value = name + args->lengths[0] + 1;
memcpy(
name
, args->args[0]
, args->lengths[0]
);
*(name + args->lengths[0]) = '\0';
memcpy(
value
, args->args[1]
, args->lengths[1]
);
*(value + args->lengths[1]) = '\0';
return SETENV(name,value);
}
my_bool sys_exec_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
){
unsigned int i=0;
if(args->arg_count == 1
&& args->arg_type[i]==STRING_RESULT){
return 0;
} else {
strcpy(
message
, "Expected exactly one string type parameter"
);
return 1;
}
}
void sys_exec_deinit(
UDF_INIT *initid
){
}
my_ulonglong sys_exec(
UDF_INIT *initid
, UDF_ARGS *args
, char *is_null
, char *error
){
return system(args->args[0]);
}
my_bool sys_eval_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
){
unsigned int i=0;
if(args->arg_count == 1
&& args->arg_type[i]==STRING_RESULT){
return 0;
} else {
strcpy(
message
, "Expected exactly one string type parameter"
);
return 1;
}
}
void sys_eval_deinit(
UDF_INIT *initid
){
}
char* sys_eval(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
){
FILE *pipe;
char line[1024];
unsigned long outlen, linelen;
result = malloc(1);
outlen = 0;
pipe = popen(args->args[0], "r");
while (fgets(line, sizeof(line), pipe) != NULL) {
linelen = strlen(line);
result = realloc(result, outlen + linelen);
strncpy(result + outlen, line, linelen);
outlen = outlen + linelen;
}
pclose(pipe);
if (!(*result) || result == NULL) {
*is_null = 1;
} else {
result[outlen-1] = 0x00;
*length = strlen(result);
}
return result;
}
my_bool sys_bineval_init(
UDF_INIT *initid
, UDF_ARGS *args
){
return 0;
}
void sys_bineval_deinit(
UDF_INIT *initid
){
}
int sys_bineval(
UDF_INIT *initid
, UDF_ARGS *args
){
int32 argv0_size;
size_t len;
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
int pID;
char *code;
#else
int *addr;
size_t page_size;
pid_t pID;
#endif
argv0_size = strlen(args->args[0]);
len = (size_t)argv0_size;
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
// allocate a +rwx memory page
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
strncpy(code, args->args[0], len);
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
#else
pID = fork();
if(pID<0)
return 1;
if(pID==0)
{
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
page_size = (len+page_size) & ~(page_size); // align to page boundary
// mmap an rwx memory page
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
if (addr == MAP_FAILED)
return 1;
strncpy((char *)addr, args->args[0], len);
((void (*)(void))addr)();
}
if(pID>0)
waitpid(pID, 0, WNOHANG);
#endif
return 0;
}
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter)
{
__try
{
__asm
{
mov eax, [lpParameter]
call eax
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return 0;
}
#endif
#endif /* HAVE_DLOPEN */

View File

@ -0,0 +1,207 @@
/*
lib_postgresqludf_sys - a library with miscellaneous (operating) system level functions
Copyright (C) 2009 Bernardo Damele A. G.
web: http://bernardodamele.blogspot.com/
email: bernardo.damele@gmail.com
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
#define _USE_32BIT_TIME_T
#define DLLEXP __declspec(dllexport)
#define BUILDING_DLL 1
#else
#define DLLEXP
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
#include <postgres.h>
#include <fmgr.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter);
#endif
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(sys_exec);
#ifdef PGDLLIMPORT
extern PGDLLIMPORT Datum sys_exec(PG_FUNCTION_ARGS) {
#else
extern DLLIMPORT Datum sys_exec(PG_FUNCTION_ARGS) {
#endif
text *argv0 = PG_GETARG_TEXT_P(0);
int32 argv0_size;
int32 result = 0;
char *command;
argv0_size = VARSIZE(argv0) - VARHDRSZ;
command = (char *)malloc(argv0_size + 1);
memcpy(command, VARDATA(argv0), argv0_size);
command[argv0_size] = '\0';
/*
Only if you want to log
elog(NOTICE, "Command execution: %s", command);
*/
result = system(command);
free(command);
PG_FREE_IF_COPY(argv0, 0);
PG_RETURN_INT32(result);
}
PG_FUNCTION_INFO_V1(sys_eval);
#ifdef PGDLLIMPORT
extern PGDLLIMPORT Datum sys_eval(PG_FUNCTION_ARGS) {
#else
extern DLLIMPORT Datum sys_eval(PG_FUNCTION_ARGS) {
#endif
text *argv0 = PG_GETARG_TEXT_P(0);
text *result_text;
int32 argv0_size;
char *command;
char *result;
FILE *pipe;
char line[1024];
int32 outlen, linelen;
argv0_size = VARSIZE(argv0) - VARHDRSZ;
command = (char *)malloc(argv0_size + 1);
memcpy(command, VARDATA(argv0), argv0_size);
command[argv0_size] = '\0';
/*
Only if you want to log
elog(NOTICE, "Command evaluated: %s", command);
*/
result = (char *)malloc(1);
outlen = 0;
pipe = popen(command, "r");
while (fgets(line, sizeof(line), pipe) != NULL) {
linelen = strlen(line);
result = (char *)realloc(result, outlen + linelen);
strncpy(result + outlen, line, linelen);
outlen = outlen + linelen;
}
pclose(pipe);
if (*result) {
result[outlen-1] = 0x00;
}
result_text = (text *)malloc(VARHDRSZ + strlen(result));
#ifdef SET_VARSIZE
SET_VARSIZE(result_text, VARHDRSZ + strlen(result));
#else
VARATT_SIZEP(result_text) = strlen(result) + VARHDRSZ;
#endif
memcpy(VARDATA(result_text), result, strlen(result));
PG_RETURN_POINTER(result_text);
}
PG_FUNCTION_INFO_V1(sys_bineval);
#ifdef PGDLLIMPORT
extern PGDLLIMPORT Datum sys_bineval(PG_FUNCTION_ARGS) {
#else
extern DLLIMPORT Datum sys_bineval(PG_FUNCTION_ARGS) {
#endif
text *argv0 = PG_GETARG_TEXT_P(0);
int32 argv0_size;
size_t len;
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
int pID;
char *code;
#else
int *addr;
size_t page_size;
pid_t pID;
#endif
argv0_size = VARSIZE(argv0) - VARHDRSZ;
len = (size_t)argv0_size;
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
// allocate a +rwx memory page
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
strncpy(code, VARDATA(argv0), len);
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
#else
pID = fork();
if(pID<0)
PG_RETURN_INT32(1);
if(pID==0)
{
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
page_size = (len+page_size) & ~(page_size); // align to page boundary
// mmap an rwx memory page
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
if (addr == MAP_FAILED)
PG_RETURN_INT32(1);
strncpy((char *)addr, VARDATA(argv0), len);
((void (*)(void))addr)();
}
if(pID>0)
waitpid(pID, 0, WNOHANG);
#endif
PG_RETURN_INT32(0);
}
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter)
{
__try
{
__asm
{
mov eax, [lpParameter]
call eax
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return 0;
}
#endif