diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c index 47f85852781..3bc5d73b330 100644 --- a/src/pl/plpython/plpython.c +++ b/src/pl/plpython/plpython.c @@ -29,7 +29,7 @@ * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.33 2003/06/11 18:33:39 tgl Exp $ + * $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.34 2003/06/25 01:18:58 momjian Exp $ * ********************************************************************* */ @@ -61,6 +61,8 @@ #include "utils/syscache.h" #include +#include +#include #include "plpython.h" /* convert Postgresql Datum or tuple into a PyObject. @@ -135,8 +137,6 @@ typedef struct PLyProcedure * tuple type */ PLyTypeInfo args[FUNC_MAX_ARGS]; int nargs; - PyObject *interp; /* restricted interpreter instance */ - PyObject *reval; /* interpreter return */ PyObject *code; /* compiled procedure code */ PyObject *statics; /* data saved across calls, local scope */ PyObject *globals; /* data saved across calls, global score */ @@ -186,13 +186,8 @@ PG_FUNCTION_INFO_V1(plpython_call_handler); */ static void PLy_init_all(void); static void PLy_init_interp(void); -static void PLy_init_safe_interp(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, * and appends it to the error and sends it to elog */ @@ -249,10 +244,6 @@ static void PLy_input_datum_func2(PLyDatumToOb *, Oid, Form_pg_type); static void PLy_output_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 */ static PyObject *PLyDict_FromTuple(PLyTypeInfo *, HeapTuple, TupleDesc); @@ -280,58 +271,9 @@ static PLyProcedure *PLy_last_procedure = NULL; static volatile int PLy_restart_in_progress = 0; static PyObject *PLy_interp_globals = NULL; -static PyObject *PLy_interp_safe = NULL; static PyObject *PLy_interp_safe_globals = 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 char *PLy_importable_modules_list[] = { - "array", - "bisect", - "binascii", - "calendar", - "cmath", - "codecs", - "errno", - "marshal", - "math", - "md5", - "mpz", - "operator", - "pcre", - "pickle", - "random", - "re", - "regex", - "sre", - "sha", - "string", - "StringIO", - "struct", - "time", - "whrandom", - "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 */ static PyObject *PLy_exc_error = NULL; @@ -904,7 +846,7 @@ PLy_procedure_call(PLyProcedure * proc, char *kargs, PyObject * vargs) current = PLy_last_procedure; PLy_last_procedure = proc; PyDict_SetItemString(proc->globals, kargs, vargs); - rv = PyObject_CallFunction(proc->reval, "O", proc->code); + rv = PyEval_EvalCode( (PyCodeObject*)proc->code, proc->globals, proc->globals); PLy_last_procedure = current; if ((rv == NULL) || (PyErr_Occurred())) @@ -1084,7 +1026,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, bool is_trigger, for (i = 0; i < FUNC_MAX_ARGS; i++) PLy_typeinfo_init(&proc->args[i]); proc->nargs = 0; - proc->code = proc->interp = proc->reval = proc->statics = NULL; + proc->code = proc->statics = NULL; proc->globals = proc->me = NULL; SAVE_EXC(); @@ -1189,45 +1131,12 @@ PLy_procedure_create(FunctionCallInfo fcinfo, bool is_trigger, void PLy_procedure_compile(PLyProcedure * proc, const char *src) { - PyObject *module, - *crv = NULL; + PyObject *crv = NULL; char *msrc; enter(); - /* - * get an instance of rexec.RExec for the function - */ - proc->interp = PyObject_CallMethod(PLy_interp_safe, "RExec", NULL); - if ((proc->interp == NULL) || (PyErr_Occurred())) - PLy_elog(ERROR, "Unable to create rexec.RExec instance"); - - proc->reval = PyObject_GetAttrString(proc->interp, "r_eval"); - if ((proc->reval == NULL) || (PyErr_Occurred())) - PLy_elog(ERROR, "Unable to get method `r_eval' from rexec.RExec"); - - /* - * add a __main__ module to the function's interpreter - */ - module = PyObject_CallMethod(proc->interp, "add_module", "s", "__main__"); - if ((module == NULL) || (PyErr_Occurred())) - PLy_elog(ERROR, "Unable to get module `__main__' from rexec.RExec"); - - /* - * add plpy module to the interpreters main dictionary - */ - proc->globals = PyModule_GetDict(module); - if ((proc->globals == NULL) || (PyErr_Occurred())) - PLy_elog(ERROR, "Unable to get `__main__.__dict__' from rexec.RExec"); - - /* - * why the hell won't r_import or r_exec('import plpy') work? - */ - module = PyDict_GetItemString(PLy_interp_globals, "plpy"); - if ((module == NULL) || (PyErr_Occurred())) - PLy_elog(ERROR, "Unable to get `plpy'"); - Py_INCREF(module); - PyDict_SetItemString(proc->globals, "plpy", module); + proc->globals = PyDict_Copy(PLy_interp_globals); /* * SD is private preserved data between calls GD is global data shared @@ -1235,13 +1144,12 @@ PLy_procedure_compile(PLyProcedure * proc, const char *src) */ proc->statics = PyDict_New(); PyDict_SetItemString(proc->globals, "SD", proc->statics); - PyDict_SetItemString(proc->globals, "GD", PLy_interp_safe_globals); /* * insert the function code into the interpreter */ msrc = PLy_procedure_munge_source(proc->pyname, src); - crv = PyObject_CallMethod(proc->interp, "r_exec", "s", msrc); + crv = PyRun_String(msrc, Py_file_input, proc->globals, NULL); free(msrc); if ((crv != NULL) && (!PyErr_Occurred())) @@ -1319,8 +1227,6 @@ PLy_procedure_delete(PLyProcedure * proc) enter(); Py_XDECREF(proc->code); - Py_XDECREF(proc->interp); - Py_XDECREF(proc->reval); Py_XDECREF(proc->statics); Py_XDECREF(proc->globals); Py_XDECREF(proc->me); @@ -2418,7 +2324,6 @@ PLy_init_all(void) Py_Initialize(); PLy_init_interp(); PLy_init_plpy(); - PLy_init_safe_interp(); if (PyErr_Occurred()) PLy_elog(FATAL, "Untrapped error in initialization."); PLy_procedure_cache = PyDict_New(); @@ -2442,6 +2347,8 @@ PLy_init_interp(void) PLy_elog(ERROR, "Unable to import '__main__' module."); Py_INCREF(mainmod); PLy_interp_globals = PyModule_GetDict(mainmod); + PLy_interp_safe_globals = PyDict_New(); + PyDict_SetItemString(PLy_interp_globals, "GD", PLy_interp_safe_globals); Py_DECREF(mainmod); if ((PLy_interp_globals == NULL) || (PyErr_Occurred())) PLy_elog(ERROR, "Unable to initialize globals."); @@ -2485,139 +2392,6 @@ PLy_init_plpy(void) 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 -PLy_init_safe_interp(void) -{ - PyObject *rmod, - *rexec, - *rexec_dict; - char *rname = "rexec"; - int len; - - enter(); - - rmod = PyImport_ImportModuleEx(rname, PLy_interp_globals, - PLy_interp_globals, Py_None); - if ((rmod == NULL) || (PyErr_Occurred())) - PLy_elog(ERROR, "Unable to import %s.", rname); - PyDict_SetItemString(PLy_interp_globals, rname, rmod); - PLy_interp_safe = rmod; - - len = sizeof(PLy_importable_modules_list) / sizeof(char *); - PLy_importable_modules = build_tuple(PLy_importable_modules_list, len); - - 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(); - if (PLy_interp_safe_globals == NULL) - 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; -} - - /* the python interface to the elog function * don't confuse these with PLy_elog */ diff --git a/src/pl/plpython/plpython_error.sql b/src/pl/plpython/plpython_error.sql index 0cde4df9967..f1939eb8ffb 100644 --- a/src/pl/plpython/plpython_error.sql +++ b/src/pl/plpython/plpython_error.sql @@ -9,9 +9,5 @@ SELECT invalid_type_reraised('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(); +SELECT write_file('/tmp/plpython','Only trusted users should be able to do this!'); +SELECT read_file('/tmp/plpython'); diff --git a/src/pl/plpython/plpython_function.sql b/src/pl/plpython/plpython_function.sql index 2769e9de36f..82a3c0c9598 100644 --- a/src/pl/plpython/plpython_function.sql +++ b/src/pl/plpython/plpython_function.sql @@ -34,7 +34,7 @@ return SD["call"] CREATE FUNCTION import_fail() returns text AS 'try: - import socket + import foosocket except Exception, ex: plpy.notice("import socket failed -- %s" % str(ex)) return "failed as expected" @@ -304,30 +304,5 @@ CREATE OR REPLACE FUNCTION read_file(text) RETURNS text AS ' CREATE OR REPLACE FUNCTION write_file(text,text) RETURNS text AS ' open(args[0],"w").write(args[1]) + return "Wrote to file: %s" % args[0] ' 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'; -