Commit 1ca717f3 authored by Tom Lane's avatar Tom Lane

plpython security and error handling fixes, from

Kevin Jacobs and Brad McLean.
parent b0df7a60
SELECT invalid_type_uncaught('rick'); SELECT invalid_type_uncaught('rick');
ERROR: plpython: Call of function `__plpython_procedure_invalid_type_uncaught_1175341' failed. NOTICE: plpython: in function __plpython_procedure_invalid_type_uncaught_49801:
plpy.SPIError: Cache lookup for type `test' failed. plpy.SPIError: Cache lookup for type `test' failed.
SELECT invalid_type_caught('rick'); SELECT invalid_type_caught('rick');
NOTICE: ("Cache lookup for type `test' failed.",) NOTICE: plpython: in function __plpython_procedure_invalid_type_caught_49802:
invalid_type_caught plpy.SPIError: Cache lookup for type `test' failed.
---------------------
(1 row)
SELECT invalid_type_reraised('rick'); SELECT invalid_type_reraised('rick');
ERROR: plpython: Call of function `__plpython_procedure_invalid_type_reraised_1175343' failed. NOTICE: plpython: in function __plpython_procedure_invalid_type_reraised_49803:
plpy.Error: ("Cache lookup for type `test' failed.",) plpy.SPIError: Cache lookup for type `test' failed.
SELECT valid_type('rick'); SELECT valid_type('rick');
valid_type valid_type
------------ ------------
(1 row) (1 row)
SELECT read_file('/etc/passwd');
ERROR: plpython: Call of function `__plpython_procedure_read_file_49809' failed.
exceptions.IOError: can't open files in restricted mode
SELECT write_file('/tmp/plpython','This is very bad');
ERROR: plpython: Call of function `__plpython_procedure_write_file_49810' failed.
exceptions.IOError: can't open files in restricted mode
SELECT getpid();
ERROR: plpython: Call of function `__plpython_procedure_getpid_49811' failed.
exceptions.AttributeError: getpid
SELECT uname();
ERROR: plpython: Call of function `__plpython_procedure_uname_49812' failed.
exceptions.AttributeError: uname
SELECT sys_exit();
ERROR: plpython: Call of function `__plpython_procedure_sys_exit_49813' failed.
exceptions.AttributeError: exit
SELECT sys_argv();
sys_argv
----------------
['RESTRICTED']
(1 row)
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.12 2001/11/05 17:46:39 momjian Exp $ * $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.13 2001/11/16 18:04:31 tgl Exp $
* *
********************************************************************* *********************************************************************
*/ */
...@@ -188,6 +188,10 @@ static void PLy_init_interp(void); ...@@ -188,6 +188,10 @@ static void PLy_init_interp(void);
static void PLy_init_safe_interp(void); static void PLy_init_safe_interp(void);
static void PLy_init_plpy(void); static void PLy_init_plpy(void);
/* Helper functions used during initialization */
static int populate_methods(PyObject *klass, PyMethodDef *methods);
static PyObject *build_tuple(char* string_list[], int len);
/* error handler. collects the current Python exception, if any, /* error handler. collects the current Python exception, if any,
* and appends it to the error and sends it to elog * and appends it to the error and sends it to elog
*/ */
...@@ -199,6 +203,10 @@ static void ...@@ -199,6 +203,10 @@ static void
PLy_exception_set(PyObject *, const char *,...) PLy_exception_set(PyObject *, const char *,...)
__attribute__((format(printf, 2, 3))); __attribute__((format(printf, 2, 3)));
/* Get the innermost python procedure called from the backend.
*/
static char *PLy_procedure_name(PLyProcedure *);
/* some utility functions /* some utility functions
*/ */
static void *PLy_malloc(size_t); static void *PLy_malloc(size_t);
...@@ -240,6 +248,10 @@ static void PLy_input_datum_func2(PLyDatumToOb *, Form_pg_type); ...@@ -240,6 +248,10 @@ static void PLy_input_datum_func2(PLyDatumToOb *, Form_pg_type);
static void PLy_output_tuple_funcs(PLyTypeInfo *, TupleDesc); static void PLy_output_tuple_funcs(PLyTypeInfo *, TupleDesc);
static void PLy_input_tuple_funcs(PLyTypeInfo *, TupleDesc); static void PLy_input_tuple_funcs(PLyTypeInfo *, TupleDesc);
/* RExec methods
*/
static PyObject *PLy_r_open(PyObject *self, PyObject* args);
/* conversion functions /* conversion functions
*/ */
static PyObject *PLyDict_FromTuple(PLyTypeInfo *, HeapTuple, TupleDesc); static PyObject *PLyDict_FromTuple(PLyTypeInfo *, HeapTuple, TupleDesc);
...@@ -255,6 +267,11 @@ static PyObject *PLyString_FromString(const char *); ...@@ -255,6 +267,11 @@ static PyObject *PLyString_FromString(const char *);
static int PLy_first_call = 1; static int PLy_first_call = 1;
static volatile int PLy_call_level = 0; static volatile int PLy_call_level = 0;
/*
* Last function called by postgres backend
*/
static PLyProcedure *PLy_last_procedure = NULL;
/* this gets modified in plpython_call_handler and PLy_elog. /* this gets modified in plpython_call_handler and PLy_elog.
* test it any old where, but do NOT modify it anywhere except * test it any old where, but do NOT modify it anywhere except
* those two functions * those two functions
...@@ -265,35 +282,60 @@ static PyObject *PLy_interp_globals = NULL; ...@@ -265,35 +282,60 @@ static PyObject *PLy_interp_globals = NULL;
static PyObject *PLy_interp_safe = NULL; static PyObject *PLy_interp_safe = NULL;
static PyObject *PLy_interp_safe_globals = NULL; static PyObject *PLy_interp_safe_globals = NULL;
static PyObject *PLy_importable_modules = NULL; static PyObject *PLy_importable_modules = NULL;
static PyObject *PLy_ok_posix_names = NULL;
static PyObject *PLy_ok_sys_names = NULL;
static PyObject *PLy_procedure_cache = NULL; static PyObject *PLy_procedure_cache = NULL;
char *PLy_importable_modules_list[] = { static char *PLy_importable_modules_list[] = {
"array", "array",
"bisect", "bisect",
"binascii",
"calendar", "calendar",
"cmath", "cmath",
"codecs",
"errno", "errno",
"marshal", "marshal",
"math", "math",
"md5", "md5",
"mpz", "mpz",
"operator", "operator",
"pcre",
"pickle", "pickle",
"random", "random",
"re", "re",
"regex",
"sre",
"sha", "sha",
"string", "string",
"StringIO", "StringIO",
"struct",
"time", "time",
"whrandom", "whrandom",
"zlib" "zlib"
}; };
static char *PLy_ok_posix_names_list[] = {
/* None for now */
};
static char *PLy_ok_sys_names_list[] = {
"byteeorder",
"copyright",
"getdefaultencoding",
"getrefcount",
"hexrevision",
"maxint",
"maxunicode",
"platform",
"version",
"version_info"
};
/* Python exceptions /* Python exceptions
*/ */
PyObject *PLy_exc_error = NULL; static PyObject *PLy_exc_error = NULL;
PyObject *PLy_exc_fatal = NULL; static PyObject *PLy_exc_fatal = NULL;
PyObject *PLy_exc_spi_error = NULL; static PyObject *PLy_exc_spi_error = NULL;
/* some globals for the python module /* some globals for the python module
*/ */
...@@ -334,7 +376,6 @@ perm_fmgr_info(Oid functionId, FmgrInfo *finfo) ...@@ -334,7 +376,6 @@ perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
fmgr_info_cxt(functionId, finfo, TopMemoryContext); fmgr_info_cxt(functionId, finfo, TopMemoryContext);
} }
Datum Datum
plpython_call_handler(PG_FUNCTION_ARGS) plpython_call_handler(PG_FUNCTION_ARGS)
{ {
...@@ -366,8 +407,10 @@ plpython_call_handler(PG_FUNCTION_ARGS) ...@@ -366,8 +407,10 @@ plpython_call_handler(PG_FUNCTION_ARGS)
} }
else else
PLy_restart_in_progress += 1; PLy_restart_in_progress += 1;
if (proc) if (proc)
{
Py_DECREF(proc->me); Py_DECREF(proc->me);
}
RERAISE_EXC(); RERAISE_EXC();
} }
...@@ -805,7 +848,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc) ...@@ -805,7 +848,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
if (plrv == NULL) if (plrv == NULL)
{ {
elog(FATAL, "Aiieee, PLy_procedure_call returned NULL"); elog(FATAL, "Aiieee, PLy_procedure_call returned NULL");
#if 0 #ifdef NOT_USED
if (!PLy_restart_in_progress) if (!PLy_restart_in_progress)
PLy_elog(ERROR, "plpython: Function \"%s\" failed.", proc->proname); PLy_elog(ERROR, "plpython: Function \"%s\" failed.", proc->proname);
...@@ -853,11 +896,15 @@ PyObject * ...@@ -853,11 +896,15 @@ PyObject *
PLy_procedure_call(PLyProcedure * proc, char *kargs, PyObject * vargs) PLy_procedure_call(PLyProcedure * proc, char *kargs, PyObject * vargs)
{ {
PyObject *rv; PyObject *rv;
PLyProcedure *current;
enter(); enter();
current = PLy_last_procedure;
PLy_last_procedure = proc;
PyDict_SetItemString(proc->globals, kargs, vargs); PyDict_SetItemString(proc->globals, kargs, vargs);
rv = PyObject_CallFunction(proc->reval, "O", proc->code); rv = PyObject_CallFunction(proc->reval, "O", proc->code);
PLy_last_procedure = current;
if ((rv == NULL) || (PyErr_Occurred())) if ((rv == NULL) || (PyErr_Occurred()))
{ {
...@@ -1150,12 +1197,6 @@ PLy_procedure_compile(PLyProcedure * proc, const char *src) ...@@ -1150,12 +1197,6 @@ PLy_procedure_compile(PLyProcedure * proc, const char *src)
if ((proc->interp == NULL) || (PyErr_Occurred())) if ((proc->interp == NULL) || (PyErr_Occurred()))
PLy_elog(ERROR, "Unable to create rexec.RExec instance"); PLy_elog(ERROR, "Unable to create rexec.RExec instance");
/*
* tweak the list of permitted modules
*/
PyObject_SetAttrString(proc->interp, "ok_builtin_modules",
PLy_importable_modules);
proc->reval = PyObject_GetAttrString(proc->interp, "r_eval"); proc->reval = PyObject_GetAttrString(proc->interp, "r_eval");
if ((proc->reval == NULL) || (PyErr_Occurred())) if ((proc->reval == NULL) || (PyErr_Occurred()))
PLy_elog(ERROR, "Unable to get method `r_eval' from rexec.RExec"); PLy_elog(ERROR, "Unable to get method `r_eval' from rexec.RExec");
...@@ -1632,9 +1673,12 @@ static PyObject *PLy_plan_status(PyObject *, PyObject *); ...@@ -1632,9 +1673,12 @@ static PyObject *PLy_plan_status(PyObject *, PyObject *);
static PyObject *PLy_result_new(void); static PyObject *PLy_result_new(void);
static void PLy_result_dealloc(PyObject *); static void PLy_result_dealloc(PyObject *);
static PyObject *PLy_result_getattr(PyObject *, char *); static PyObject *PLy_result_getattr(PyObject *, char *);
#ifdef NOT_USED
/* Appear to be unused */
static PyObject *PLy_result_fetch(PyObject *, PyObject *); static PyObject *PLy_result_fetch(PyObject *, PyObject *);
static PyObject *PLy_result_nrows(PyObject *, PyObject *); static PyObject *PLy_result_nrows(PyObject *, PyObject *);
static PyObject *PLy_result_status(PyObject *, PyObject *); static PyObject *PLy_result_status(PyObject *, PyObject *);
#endif
static int PLy_result_length(PyObject *); static int PLy_result_length(PyObject *);
static PyObject *PLy_result_item(PyObject *, int); static PyObject *PLy_result_item(PyObject *, int);
static PyObject *PLy_result_slice(PyObject *, int, int); static PyObject *PLy_result_slice(PyObject *, int, int);
...@@ -1650,7 +1694,7 @@ static PyObject *PLy_spi_execute_plan(PyObject *, PyObject *, int); ...@@ -1650,7 +1694,7 @@ static PyObject *PLy_spi_execute_plan(PyObject *, PyObject *, int);
static PyObject *PLy_spi_execute_fetch_result(SPITupleTable *, int, int); static PyObject *PLy_spi_execute_fetch_result(SPITupleTable *, int, int);
PyTypeObject PLy_PlanType = { static PyTypeObject PLy_PlanType = {
PyObject_HEAD_INIT(NULL) PyObject_HEAD_INIT(NULL)
0, /* ob_size */ 0, /* ob_size */
"PLyPlan", /* tp_name */ "PLyPlan", /* tp_name */
...@@ -1679,13 +1723,13 @@ PyTypeObject PLy_PlanType = { ...@@ -1679,13 +1723,13 @@ PyTypeObject PLy_PlanType = {
PLy_plan_doc, /* tp_doc */ PLy_plan_doc, /* tp_doc */
}; };
PyMethodDef PLy_plan_methods[] = { static PyMethodDef PLy_plan_methods[] = {
{"status", (PyCFunction) PLy_plan_status, METH_VARARGS, NULL}, {"status", (PyCFunction) PLy_plan_status, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };
PySequenceMethods PLy_result_as_sequence = { static PySequenceMethods PLy_result_as_sequence = {
(inquiry) PLy_result_length, /* sq_length */ (inquiry) PLy_result_length, /* sq_length */
(binaryfunc) 0, /* sq_concat */ (binaryfunc) 0, /* sq_concat */
(intargfunc) 0, /* sq_repeat */ (intargfunc) 0, /* sq_repeat */
...@@ -1695,7 +1739,7 @@ PySequenceMethods PLy_result_as_sequence = { ...@@ -1695,7 +1739,7 @@ PySequenceMethods PLy_result_as_sequence = {
(intintobjargproc) PLy_result_ass_slice, /* sq_ass_slice */ (intintobjargproc) PLy_result_ass_slice, /* sq_ass_slice */
}; };
PyTypeObject PLy_ResultType = { static PyTypeObject PLy_ResultType = {
PyObject_HEAD_INIT(NULL) PyObject_HEAD_INIT(NULL)
0, /* ob_size */ 0, /* ob_size */
"PLyResult", /* tp_name */ "PLyResult", /* tp_name */
...@@ -1723,14 +1767,15 @@ PyTypeObject PLy_ResultType = { ...@@ -1723,14 +1767,15 @@ PyTypeObject PLy_ResultType = {
0, /* tp_xxx4 */ 0, /* tp_xxx4 */
PLy_result_doc, /* tp_doc */ PLy_result_doc, /* tp_doc */
}; };
#ifdef NOT_USED
PyMethodDef PLy_result_methods[] = { /* Appear to be unused */
static PyMethodDef PLy_result_methods[] = {
{"fetch", (PyCFunction) PLy_result_fetch, METH_VARARGS, NULL,}, {"fetch", (PyCFunction) PLy_result_fetch, METH_VARARGS, NULL,},
{"nrows", (PyCFunction) PLy_result_nrows, METH_VARARGS, NULL}, {"nrows", (PyCFunction) PLy_result_nrows, METH_VARARGS, NULL},
{"status", (PyCFunction) PLy_result_status, METH_VARARGS, NULL}, {"status", (PyCFunction) PLy_result_status, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };
#endif
static PyMethodDef PLy_methods[] = { static PyMethodDef PLy_methods[] = {
/* /*
...@@ -1833,7 +1878,7 @@ PLy_plan_status(PyObject * self, PyObject * args) ...@@ -1833,7 +1878,7 @@ PLy_plan_status(PyObject * self, PyObject * args)
/* result object methods /* result object methods
*/ */
static PyObject * PyObject *
PLy_result_new(void) PLy_result_new(void)
{ {
PLyResultObject *ob; PLyResultObject *ob;
...@@ -1853,7 +1898,7 @@ PLy_result_new(void) ...@@ -1853,7 +1898,7 @@ PLy_result_new(void)
return (PyObject *) ob; return (PyObject *) ob;
} }
static void void
PLy_result_dealloc(PyObject * arg) PLy_result_dealloc(PyObject * arg)
{ {
PLyResultObject *ob = (PLyResultObject *) arg; PLyResultObject *ob = (PLyResultObject *) arg;
...@@ -1867,19 +1912,20 @@ PLy_result_dealloc(PyObject * arg) ...@@ -1867,19 +1912,20 @@ PLy_result_dealloc(PyObject * arg)
PyMem_DEL(ob); PyMem_DEL(ob);
} }
static PyObject * PyObject *
PLy_result_getattr(PyObject * self, char *attr) PLy_result_getattr(PyObject * self, char *attr)
{ {
return NULL; return NULL;
} }
#ifdef NOT_USED
static PyObject * /* Appear to be unused */
PyObject *
PLy_result_fetch(PyObject * self, PyObject * args) PLy_result_fetch(PyObject * self, PyObject * args)
{ {
return NULL; return NULL;
} }
static PyObject * PyObject *
PLy_result_nrows(PyObject * self, PyObject * args) PLy_result_nrows(PyObject * self, PyObject * args)
{ {
PLyResultObject *ob = (PLyResultObject *) self; PLyResultObject *ob = (PLyResultObject *) self;
...@@ -1888,7 +1934,7 @@ PLy_result_nrows(PyObject * self, PyObject * args) ...@@ -1888,7 +1934,7 @@ PLy_result_nrows(PyObject * self, PyObject * args)
return ob->nrows; return ob->nrows;
} }
static PyObject * PyObject *
PLy_result_status(PyObject * self, PyObject * args) PLy_result_status(PyObject * self, PyObject * args)
{ {
PLyResultObject *ob = (PLyResultObject *) self; PLyResultObject *ob = (PLyResultObject *) self;
...@@ -1896,7 +1942,7 @@ PLy_result_status(PyObject * self, PyObject * args) ...@@ -1896,7 +1942,7 @@ PLy_result_status(PyObject * self, PyObject * args)
Py_INCREF(ob->status); Py_INCREF(ob->status);
return ob->status; return ob->status;
} }
#endif
int int
PLy_result_length(PyObject * arg) PLy_result_length(PyObject * arg)
{ {
...@@ -1991,7 +2037,8 @@ PLy_spi_prepare(PyObject * self, PyObject * args) ...@@ -1991,7 +2037,8 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
if (!PyErr_Occurred()) if (!PyErr_Occurred())
PyErr_SetString(PLy_exc_spi_error, PyErr_SetString(PLy_exc_spi_error,
"Unknown error in PLy_spi_prepare."); "Unknown error in PLy_spi_prepare.");
return NULL; PLy_elog(NOTICE,"in function %s:",PLy_procedure_name(PLy_last_procedure));
RERAISE_EXC();
} }
if (list != NULL) if (list != NULL)
...@@ -2097,7 +2144,7 @@ PLy_spi_execute(PyObject * self, PyObject * args) ...@@ -2097,7 +2144,7 @@ PLy_spi_execute(PyObject * self, PyObject * args)
enter(); enter();
#if 0 #ifdef NOT_USED
/* /*
* there should - hahaha - be an python exception set so just return * there should - hahaha - be an python exception set so just return
...@@ -2187,7 +2234,8 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, int limit) ...@@ -2187,7 +2234,8 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, int limit)
if (!PyErr_Occurred()) if (!PyErr_Occurred())
PyErr_SetString(PLy_exc_error, PyErr_SetString(PLy_exc_error,
"Unknown error in PLy_spi_execute_plan"); "Unknown error in PLy_spi_execute_plan");
return NULL; PLy_elog(NOTICE,"in function %s:",PLy_procedure_name(PLy_last_procedure));
RERAISE_EXC();
} }
if (nargs) if (nargs)
...@@ -2249,16 +2297,15 @@ PLy_spi_execute_query(char *query, int limit) ...@@ -2249,16 +2297,15 @@ PLy_spi_execute_query(char *query, int limit)
if (TRAP_EXC()) if (TRAP_EXC())
{ {
RESTORE_EXC(); RESTORE_EXC();
if ((!PLy_restart_in_progress) && (!PyErr_Occurred())) if ((!PLy_restart_in_progress) && (!PyErr_Occurred()))
PyErr_SetString(PLy_exc_spi_error, PyErr_SetString(PLy_exc_spi_error,
"Unknown error in PLy_spi_execute_query."); "Unknown error in PLy_spi_execute_query.");
return NULL; PLy_elog(NOTICE,"in function %s:",PLy_procedure_name(PLy_last_procedure));
RERAISE_EXC();
} }
rv = SPI_exec(query, limit); rv = SPI_exec(query, limit);
RESTORE_EXC(); RESTORE_EXC();
if (rv < 0) if (rv < 0)
{ {
PLy_exception_set(PLy_exc_spi_error, PLy_exception_set(PLy_exc_spi_error,
...@@ -2311,7 +2358,7 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status) ...@@ -2311,7 +2358,7 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
"Unknown error in PLy_spi_execute_fetch_result"); "Unknown error in PLy_spi_execute_fetch_result");
Py_DECREF(result); Py_DECREF(result);
PLy_typeinfo_dealloc(&args); PLy_typeinfo_dealloc(&args);
return NULL; RERAISE_EXC();
} }
if (rows) if (rows)
...@@ -2450,13 +2497,33 @@ PLy_init_plpy(void) ...@@ -2450,13 +2497,33 @@ PLy_init_plpy(void)
elog(ERROR, "Unable to init plpy."); elog(ERROR, "Unable to init plpy.");
} }
/*
* New RExec methods
*/
PyObject*
PLy_r_open(PyObject *self, PyObject* args)
{
PyErr_SetString(PyExc_IOError, "can't open files in restricted mode");
return NULL;
}
static PyMethodDef PLy_r_exec_methods[] = {
{"r_open", (PyCFunction)PLy_r_open, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
/*
* Init new RExec
*/
void void
PLy_init_safe_interp(void) PLy_init_safe_interp(void)
{ {
PyObject *rmod; PyObject *rmod, *rexec, *rexec_dict;
char *rname = "rexec"; char *rname = "rexec";
int i, int len;
imax;
enter(); enter();
...@@ -2467,19 +2534,93 @@ PLy_init_safe_interp(void) ...@@ -2467,19 +2534,93 @@ PLy_init_safe_interp(void)
PyDict_SetItemString(PLy_interp_globals, rname, rmod); PyDict_SetItemString(PLy_interp_globals, rname, rmod);
PLy_interp_safe = rmod; PLy_interp_safe = rmod;
imax = sizeof(PLy_importable_modules_list) / sizeof(char *); len = sizeof(PLy_importable_modules_list) / sizeof(char *);
PLy_importable_modules = PyTuple_New(imax); PLy_importable_modules = build_tuple(PLy_importable_modules_list, len);
for (i = 0; i < imax; i++)
{
PyObject *m = PyString_FromString(PLy_importable_modules_list[i]);
PyTuple_SetItem(PLy_importable_modules, i, m); len = sizeof(PLy_ok_posix_names_list) / sizeof(char *);
} PLy_ok_posix_names = build_tuple(PLy_ok_posix_names_list, len);
len = sizeof(PLy_ok_sys_names_list) / sizeof(char *);
PLy_ok_sys_names = build_tuple(PLy_ok_sys_names_list, len);
PLy_interp_safe_globals = PyDict_New(); PLy_interp_safe_globals = PyDict_New();
if (PLy_interp_safe_globals == NULL) if (PLy_interp_safe_globals == NULL)
PLy_elog(ERROR, "Unable to create shared global dictionary."); PLy_elog(ERROR, "Unable to create shared global dictionary.");
/*
* get an rexec.RExec class
*/
rexec = PyDict_GetItemString(PyModule_GetDict(rmod), "RExec");
if (rexec == NULL || !PyClass_Check(rexec))
PLy_elog(ERROR, "Unable to get RExec object.");
rexec_dict = ((PyClassObject*)rexec)->cl_dict;
/*
* tweak the list of permitted modules, posix and sys functions
*/
PyDict_SetItemString(rexec_dict, "ok_builtin_modules", PLy_importable_modules);
PyDict_SetItemString(rexec_dict, "ok_posix_names", PLy_ok_posix_names);
PyDict_SetItemString(rexec_dict, "ok_sys_names", PLy_ok_sys_names);
/*
* change the r_open behavior
*/
if( populate_methods(rexec, PLy_r_exec_methods) )
PLy_elog(ERROR, "Failed to update RExec methods.");
}
/* Helper function to build tuples from string lists */
static
PyObject *build_tuple(char* string_list[], int len)
{
PyObject *tup = PyTuple_New(len);
int i;
for (i = 0; i < len; i++)
{
PyObject *m = PyString_FromString(string_list[i]);
PyTuple_SetItem(tup, i, m);
}
return tup;
}
/* Helper function for populating a class with method wrappers. */
static int
populate_methods(PyObject *klass, PyMethodDef *methods)
{
if (!klass || !methods)
return 0;
for ( ; methods->ml_name; ++methods) {
/* get a wrapper for the built-in function */
PyObject *func = PyCFunction_New(methods, NULL);
PyObject *meth;
int status;
if (!func)
return -1;
/* turn the function into an unbound method */
if (!(meth = PyMethod_New(func, NULL, klass))) {
Py_DECREF(func);
return -1;
}
/* add method to dictionary */
status = PyDict_SetItemString( ((PyClassObject*)klass)->cl_dict,
methods->ml_name, meth);
Py_DECREF(meth);
Py_DECREF(func);
/* stop now if an error occurred, otherwise do the next method */
if (status)
return status;
}
return 0;
} }
...@@ -2566,7 +2707,7 @@ PLy_log(volatile int level, PyObject * self, PyObject * args) ...@@ -2566,7 +2707,7 @@ PLy_log(volatile int level, PyObject * self, PyObject * args)
* hideously. * hideously.
*/ */
elog(FATAL, "plpython: Aiieee, elog threw an unknown exception!"); elog(FATAL, "plpython: Aiieee, elog threw an unknown exception!");
return NULL; RERAISE_EXC();
} }
elog(level, sv); elog(level, sv);
...@@ -2584,6 +2725,18 @@ PLy_log(volatile int level, PyObject * self, PyObject * args) ...@@ -2584,6 +2725,18 @@ PLy_log(volatile int level, PyObject * self, PyObject * args)
} }
/* Get the last procedure name called by the backend ( the innermost,
* If a plpython procedure call calls the backend and the backend calls
* another plpython procedure )
*/
char *PLy_procedure_name(PLyProcedure *proc)
{
if ( proc == NULL )
return "<unknown procedure>";
return proc->proname;
}
/* output a python traceback/exception via the postgresql elog /* output a python traceback/exception via the postgresql elog
* function. not pretty. * function. not pretty.
*/ */
......
...@@ -7,3 +7,11 @@ SELECT invalid_type_uncaught('rick'); ...@@ -7,3 +7,11 @@ SELECT invalid_type_uncaught('rick');
SELECT invalid_type_caught('rick'); SELECT invalid_type_caught('rick');
SELECT invalid_type_reraised('rick'); SELECT invalid_type_reraised('rick');
SELECT valid_type('rick'); SELECT valid_type('rick');
-- Security sandbox tests
SELECT read_file('/etc/passwd');
SELECT write_file('/tmp/plpython','This is very bad');
SELECT getpid();
SELECT uname();
SELECT sys_exit();
SELECT sys_argv();
...@@ -257,6 +257,12 @@ if len(rv): ...@@ -257,6 +257,12 @@ if len(rv):
return None return None
' '
LANGUAGE 'plpython'; LANGUAGE 'plpython';
/* Flat out syntax error
*/
CREATE FUNCTION sql_syntax_error() RETURNS text
AS
'plpy.execute("syntax error")'
LANGUAGE 'plpython';
/* check the handling of uncaught python exceptions /* check the handling of uncaught python exceptions
*/ */
...@@ -287,5 +293,36 @@ return seq ...@@ -287,5 +293,36 @@ return seq
' '
LANGUAGE 'plpython'; LANGUAGE 'plpython';
CREATE OR REPLACE FUNCTION read_file(text) RETURNS text AS '
return open(args[0]).read()
' LANGUAGE 'plpython';
CREATE OR REPLACE FUNCTION write_file(text,text) RETURNS text AS '
open(args[0],"w").write(args[1])
' LANGUAGE 'plpython';
CREATE OR REPLACE FUNCTION getpid() RETURNS int4 AS '
import os
return os.getpid()
' LANGUAGE 'plpython';
CREATE OR REPLACE FUNCTION uname() RETURNS int4 AS '
import os
return os.uname()
' LANGUAGE 'plpython';
CREATE OR REPLACE FUNCTION sys_exit() RETURNS text AS '
import sys
return sys.exit()
' LANGUAGE 'plpython';
CREATE OR REPLACE FUNCTION sys_argv() RETURNS text AS '
import sys
return str(sys.argv)
' LANGUAGE 'plpython';
CREATE OR REPLACE FUNCTION sys_version() RETURNS text AS '
import sys
return str(sys.version)
' LANGUAGE 'plpython';
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment