s4/param: Fix provision_get_schema leaking python object
[bbaumbach/samba-autobuild/.git] / source4 / param / provision.c
index 81c4fb16a50f6a0035b371df4ba0ea35d53ae1fc..85671f80b87586fd60cd0cecc0e844b54c8749e8 100644 (file)
 */
 
 #include <Python.h>
+#include "python/py3compat.h"
+#include <ldb.h>
+#include <pyldb.h>
 #include "includes.h"
-#include "auth/auth.h"
-#include "lib/ldb_wrap.h"
-#include "ldb/include/ldb.h"
-#include "ldb_errors.h"
-#include "libcli/raw/libcliraw.h"
 #include "librpc/ndr/libndr.h"
-
-#include "param/param.h"
 #include "param/provision.h"
 #include "param/secrets.h"
-#include "lib/talloc/pytalloc.h"
-#include "librpc/rpc/pyrpc.h"
-#include "scripting/python/modules.h"
-#include "lib/ldb/pyldb.h"
+#include <pytalloc.h>
+#include "python/modules.h"
 #include "param/pyparam.h"
 #include "dynconfig/dynconfig.h"
 
+static bool dict_insert(PyObject* dict,
+                       const char* key,
+                       PyObject* value)
+{
+       if (PyDict_SetItemString(dict, key, value) == -1) {
+               Py_XDECREF(value);
+               return false;
+       }
+       Py_XDECREF(value);
+       return true;
+}
+
 static PyObject *provision_module(void)
 {
-       PyObject *name = PyString_FromString("samba.provision");
+       PyObject *name = PyStr_FromString("samba.provision");
+       PyObject *mod = NULL;
        if (name == NULL)
                return NULL;
-       return PyImport_Import(name);
+       mod = PyImport_Import(name);
+       Py_CLEAR(name);
+       return mod;
 }
 
 static PyObject *schema_module(void)
 {
-       PyObject *name = PyString_FromString("samba.schema");
+       PyObject *name = PyStr_FromString("samba.schema");
+       PyObject *mod = NULL;
        if (name == NULL)
                return NULL;
-       return PyImport_Import(name);
+       mod = PyImport_Import(name);
+       Py_CLEAR(name);
+       return mod;
 }
 
 static PyObject *ldb_module(void)
 {
-       PyObject *name = PyString_FromString("ldb");
+       PyObject *name = PyStr_FromString("ldb");
+       PyObject *mod = NULL;
        if (name == NULL)
                return NULL;
-       return PyImport_Import(name);
+       mod = PyImport_Import(name);
+       Py_CLEAR(name);
+       return mod;
 }
 
 static PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx)
@@ -74,10 +89,12 @@ static PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx)
        ret = (PyLdbObject *)ldb_ctx_type->tp_alloc(ldb_ctx_type, 0);
        if (ret == NULL) {
                PyErr_NoMemory();
+               Py_XDECREF(ldb_ctx_type);
                return NULL;
        }
        ret->mem_ctx = talloc_new(NULL);
        ret->ldb_ctx = talloc_reference(ret->mem_ctx, ldb_ctx);
+       Py_XDECREF(ldb_ctx_type);
        return (PyObject *)ret;
 }
 
@@ -86,12 +103,17 @@ NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
                        struct provision_result *result)
 {
        const char *configfile;
-       PyObject *provision_mod, *provision_dict, *provision_fn, *py_result, *parameters;
+       PyObject *provision_mod = NULL, *provision_dict = NULL;
+       PyObject *provision_fn = NULL, *py_result = NULL;
+       PyObject *parameters = NULL, *py_lp_ctx = NULL, *py_domaindn = NULL;
+
+       struct ldb_context *samdb;
+       NTSTATUS status = NT_STATUS_OK;
        
        DEBUG(0,("Provision for Become-DC test using python\n"));
 
        Py_Initialize();
-       py_update_path("bin"); /* FIXME: Can't assume this is always the case */
+       py_update_path(); /* Put the samba path at the start of sys.path */
 
        provision_mod = provision_module();
 
@@ -127,92 +149,180 @@ NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
                 settings->targetdir));
        parameters = PyDict_New();
 
-       configfile = lp_configfile(lp_ctx);
+       configfile = lpcfg_configfile(lp_ctx);
        if (configfile != NULL) {
-               PyDict_SetItemString(parameters, "smbconf", 
-                                    PyString_FromString(configfile));
-       }
-
-       PyDict_SetItemString(parameters, "rootdn", 
-                                                PyString_FromString(settings->root_dn_str));
-       if (settings->targetdir != NULL)
-               PyDict_SetItemString(parameters, "targetdir", 
-                                                        PyString_FromString(settings->targetdir));
-       if (file_exist("setup/provision.smb.conf.dc")) {
-               PyDict_SetItemString(parameters, "setup_dir",
-                                    PyString_FromString("setup"));
-       } else {
-               PyDict_SetItemString(parameters, "setup_dir",
-                                    PyString_FromString(dyn_SETUPDIR));
-       }
-       PyDict_SetItemString(parameters, "hostname", 
-                                                PyString_FromString(settings->netbios_name));
-       PyDict_SetItemString(parameters, "domain", 
-                                                PyString_FromString(settings->domain));
-       PyDict_SetItemString(parameters, "realm", 
-                                                PyString_FromString(settings->realm));
-       if (settings->root_dn_str)
-               PyDict_SetItemString(parameters, "rootdn", 
-                                    PyString_FromString(settings->root_dn_str));
-
-       if (settings->domain_dn_str) 
-               PyDict_SetItemString(parameters, "domaindn", 
-                                    PyString_FromString(settings->domain_dn_str));
-
-       if (settings->schema_dn_str) 
-               PyDict_SetItemString(parameters, "schemadn", 
-                                    PyString_FromString(settings->schema_dn_str));
-       
-       if (settings->config_dn_str) 
-               PyDict_SetItemString(parameters, "configdn", 
-                                    PyString_FromString(settings->config_dn_str));
-       
-       if (settings->server_dn_str) 
-               PyDict_SetItemString(parameters, "serverdn", 
-                                    PyString_FromString(settings->server_dn_str));
-       
-       if (settings->site_name) 
-               PyDict_SetItemString(parameters, "sitename", 
-                                    PyString_FromString(settings->site_name));
+               if (!dict_insert(parameters, "smbconf",
+                                PyStr_FromString(configfile))) {
+                       status = NT_STATUS_UNSUCCESSFUL;
+                       goto out;
+               }
+       }
 
-       PyDict_SetItemString(parameters, "machinepass", 
-                            PyString_FromString(settings->machine_password));
+       if (!dict_insert(parameters,
+                        "rootdn",
+                        PyStr_FromString(settings->root_dn_str))) {
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
+       if (settings->targetdir != NULL) {
+               if (!dict_insert(parameters,
+                                "targetdir",
+                                PyStr_FromString(settings->targetdir))) {
+                       status = NT_STATUS_UNSUCCESSFUL;
+                       goto out;
+               }
+       }
+       if (!dict_insert(parameters,
+                        "hostname",
+                        PyStr_FromString(settings->netbios_name))) {
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
+       if (!dict_insert(parameters,
+                        "domain",
+                        PyStr_FromString(settings->domain))) {
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
+       if (!dict_insert(parameters,
+                        "realm",
+                        PyStr_FromString(settings->realm))) {
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
+       if (settings->root_dn_str) {
+               if (!dict_insert(parameters,
+                                "rootdn",
+                                PyStr_FromString(settings->root_dn_str))) {
+                       status = NT_STATUS_UNSUCCESSFUL;
+                       goto out;
+               }
+       }
 
-       
-       PyDict_SetItemString(parameters, "debuglevel", PyInt_FromLong(DEBUGLEVEL));
+       if (settings->domain_dn_str) {
+               if (!dict_insert(parameters,
+                                "domaindn",
+                                PyStr_FromString(settings->domain_dn_str))) {
+                       status = NT_STATUS_UNSUCCESSFUL;
+                       goto out;
+               }
+       }
 
-       py_result = PyEval_CallObjectWithKeywords(provision_fn, NULL, parameters);
+       if (settings->schema_dn_str) {
+               if (!dict_insert(parameters,
+                                "schemadn",
+                                PyStr_FromString(settings->schema_dn_str))) {
+                       status = NT_STATUS_UNSUCCESSFUL;
+                       goto out;
+               }
+       }
+       if (settings->config_dn_str) {
+               if (!dict_insert(parameters,
+                                "configdn",
+                                PyStr_FromString(settings->config_dn_str))) {
+                       status = NT_STATUS_UNSUCCESSFUL;
+                       goto out;
+               }
+       }
+       if (settings->server_dn_str) {
+               if (!dict_insert(parameters,
+                                "serverdn",
+                                PyStr_FromString(settings->server_dn_str))) {
+                       status = NT_STATUS_UNSUCCESSFUL;
+                       goto out;
+               }
+       }
+       if (settings->site_name) {
+               if (!dict_insert(parameters,
+                                "sitename",
+                                 PyStr_FromString(settings->site_name))) {
+                       status = NT_STATUS_UNSUCCESSFUL;
+                       goto out;
+               }
+       }
 
-       Py_DECREF(parameters);
+       if (!dict_insert(parameters,
+                        "machinepass",
+                        PyStr_FromString(settings->machine_password))){
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
+
+       if (!dict_insert(parameters,
+                        "debuglevel",
+                        PyInt_FromLong(DEBUGLEVEL))) {
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
+
+       if (!dict_insert(parameters,
+                        "use_ntvfs",
+                        PyInt_FromLong(settings->use_ntvfs))) {
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
+
+       py_result = PyEval_CallObjectWithKeywords(provision_fn, NULL, parameters);
 
        if (py_result == NULL) {
-               PyErr_Print();
-               PyErr_Clear();
-               return NT_STATUS_UNSUCCESSFUL;
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
        }
 
-       result->domaindn = talloc_strdup(mem_ctx, PyString_AsString(PyObject_GetAttrString(py_result, "domaindn")));
+       py_domaindn = PyObject_GetAttrString(py_result, "domaindn");
+       result->domaindn = talloc_strdup(mem_ctx, PyStr_AsString(py_domaindn));
 
        /* FIXME paths */
-       result->lp_ctx = lp_from_py_object(result, PyObject_GetAttrString(py_result, "lp"));
-       result->samdb = PyLdb_AsLdbContext(PyObject_GetAttrString(py_result, "samdb"));
+       py_lp_ctx = PyObject_GetAttrString(py_result, "lp");
+       if (py_lp_ctx == NULL) {
+               DEBUG(0, ("Missing 'lp' attribute"));
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
+       result->lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx);
 
-       return NT_STATUS_OK;
+       samdb = pyldb_Ldb_AsLdbContext(PyObject_GetAttrString(py_result, "samdb"));
+       if (samdb == NULL) {
+               DEBUG(0, ("Missing 'samdb' attribute"));
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
+       result->samdb = samdb;
+       status = NT_STATUS_OK;
+out:
+       Py_CLEAR(parameters);
+       Py_CLEAR(provision_mod);
+       Py_CLEAR(provision_fn);
+       Py_CLEAR(provision_dict);
+       Py_CLEAR(py_result);
+       Py_CLEAR(py_lp_ctx);
+       Py_CLEAR(py_domaindn);
+       if (!NT_STATUS_IS_OK(status)) {
+               PyErr_Print();
+               PyErr_Clear();
+       }
+       return status;
 }
 
 static PyObject *py_dom_sid_FromSid(struct dom_sid *sid)
 {
-       PyObject *mod_security, *dom_sid_Type;
+       PyObject *mod_security = NULL, *dom_sid_Type = NULL, *result = NULL;
 
        mod_security = PyImport_ImportModule("samba.dcerpc.security");
-       if (mod_security == NULL)
+       if (mod_security == NULL) {
                return NULL;
+       }
 
        dom_sid_Type = PyObject_GetAttrString(mod_security, "dom_sid");
-       if (dom_sid_Type == NULL)
+       if (dom_sid_Type == NULL) {
+               Py_DECREF(mod_security);
                return NULL;
+       }
 
-       return py_talloc_reference((PyTypeObject *)dom_sid_Type, sid);
+       result = pytalloc_reference((PyTypeObject *)dom_sid_Type, sid);
+       Py_DECREF(mod_security);
+       Py_DECREF(dom_sid_Type);
+       return result;
 }
 
 NTSTATUS provision_store_self_join(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
@@ -221,21 +331,28 @@ NTSTATUS provision_store_self_join(TALLOC_CTX *mem_ctx, struct loadparm_context
                                   const char **error_string)
 {
        int ret;
-       PyObject *provision_mod, *provision_dict, *provision_fn, *py_result, *parameters, *py_sid;
-       struct ldb_context *ldb;
+       PyObject *provision_mod = NULL, *provision_dict = NULL;
+       PyObject *provision_fn = NULL, *py_result = NULL;
+       PyObject *parameters = NULL, *py_sid = NULL;
+       struct ldb_context *ldb = NULL;
        TALLOC_CTX *tmp_mem = talloc_new(mem_ctx);
+
+       NTSTATUS status = NT_STATUS_OK;
+       *error_string = NULL;
+
        if (!tmp_mem) {
-               return NT_STATUS_NO_MEMORY;
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
        }
 
        /* Open the secrets database */
-       ldb = secrets_db_connect(tmp_mem, event_ctx, lp_ctx);
+       ldb = secrets_db_connect(tmp_mem, lp_ctx);
        if (!ldb) {
                *error_string
                        = talloc_asprintf(mem_ctx, 
                                          "Could not open secrets database");
-               talloc_free(tmp_mem);
-               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+               status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+               goto out;
        }
 
        ret = ldb_transaction_start(ldb);
@@ -244,20 +361,19 @@ NTSTATUS provision_store_self_join(TALLOC_CTX *mem_ctx, struct loadparm_context
                *error_string
                        = talloc_asprintf(mem_ctx, 
                                          "Could not start transaction on secrets database: %s", ldb_errstring(ldb));
-               talloc_free(tmp_mem);
-               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+               status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+               goto out;
        }
 
        Py_Initialize();
-       py_update_path("bin"); /* FIXME: Can't assume this is always the case */
+       py_update_path(); /* Put the samba path at the start of sys.path */
        provision_mod = provision_module();
 
        if (provision_mod == NULL) {
-               PyErr_Print();
                *error_string
                        = talloc_asprintf(mem_ctx, "Unable to import provision Python module.");
-               talloc_free(tmp_mem);
-               return NT_STATUS_UNSUCCESSFUL;
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
        }
 
        provision_dict = PyModule_GetDict(provision_mod);
@@ -265,55 +381,86 @@ NTSTATUS provision_store_self_join(TALLOC_CTX *mem_ctx, struct loadparm_context
        if (provision_dict == NULL) {
                *error_string
                        = talloc_asprintf(mem_ctx, "Unable to get dictionary for provision module");
-               talloc_free(tmp_mem);
-               return NT_STATUS_UNSUCCESSFUL;
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
        }
 
        provision_fn = PyDict_GetItemString(provision_dict, "secretsdb_self_join");
        if (provision_fn == NULL) {
-               PyErr_Print();
                *error_string
                        = talloc_asprintf(mem_ctx, "Unable to get provision_become_dc function");
-               talloc_free(tmp_mem);
-               return NT_STATUS_UNSUCCESSFUL;
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
        }
-       
+
        parameters = PyDict_New();
 
-       PyDict_SetItemString(parameters, "secretsdb", 
-                            PyLdb_FromLdbContext(ldb));
-       PyDict_SetItemString(parameters, "domain", 
-                            PyString_FromString(settings->domain_name));
+       if(!dict_insert(parameters,
+                       "secretsdb",
+                       PyLdb_FromLdbContext(ldb))){
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
+       if (!dict_insert(parameters,
+                        "domain",
+                        PyStr_FromString(settings->domain_name))) {
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
        if (settings->realm != NULL) {
-               PyDict_SetItemString(parameters, "realm",
-                                    PyString_FromString(settings->realm));
+               if (!dict_insert(parameters,
+                                "realm",
+                                PyStr_FromString(settings->realm))) {
+                       status = NT_STATUS_UNSUCCESSFUL;
+                       goto out;
+               }
+       }
+       if (!dict_insert(parameters,
+                        "machinepass",
+                        PyStr_FromString(settings->machine_password))) {
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
+       if (!dict_insert(parameters,
+                        "netbiosname",
+                        PyStr_FromString(settings->netbios_name))) {
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
        }
-       PyDict_SetItemString(parameters, "machinepass", 
-                            PyString_FromString(settings->machine_password));
-       PyDict_SetItemString(parameters, "netbiosname", 
-                            PyString_FromString(settings->netbios_name));
 
        py_sid = py_dom_sid_FromSid(settings->domain_sid);
        if (py_sid == NULL) {
-               Py_DECREF(parameters);
-               goto failure;
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
        }
 
-       PyDict_SetItemString(parameters, "domainsid", 
-                            py_sid);
+       if (!dict_insert(parameters,
+                        "domainsid",
+                        py_sid)) {
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
 
-       PyDict_SetItemString(parameters, "secure_channel_type", 
-                      PyInt_FromLong(settings->secure_channel_type));
+       if (!dict_insert(parameters,
+                        "secure_channel_type",
+                        PyInt_FromLong(settings->secure_channel_type))) {
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
 
-       PyDict_SetItemString(parameters, "key_version_number", 
-                      PyInt_FromLong(settings->key_version_number));
+       if (!dict_insert(parameters,
+                        "key_version_number",
+                        PyInt_FromLong(settings->key_version_number))) {
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
+       }
 
        py_result = PyEval_CallObjectWithKeywords(provision_fn, NULL, parameters);
 
-       Py_DECREF(parameters);
-
        if (py_result == NULL) {
-               goto failure;
+               ldb_transaction_cancel(ldb);
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto out;
        }
 
        ret = ldb_transaction_commit(ldb);
@@ -321,34 +468,37 @@ NTSTATUS provision_store_self_join(TALLOC_CTX *mem_ctx, struct loadparm_context
                *error_string
                        = talloc_asprintf(mem_ctx, 
                                          "Could not commit transaction on secrets database: %s", ldb_errstring(ldb));
-               talloc_free(tmp_mem);
-               return NT_STATUS_INTERNAL_DB_ERROR;
+               status = NT_STATUS_INTERNAL_DB_ERROR;
+               goto out;
        }
 
+       status = NT_STATUS_OK;
+out:
        talloc_free(tmp_mem);
-
-       return NT_STATUS_OK;
-
-failure:
-       ldb_transaction_cancel(ldb);
-       talloc_free(tmp_mem);
-
-       PyErr_Print();
-       PyErr_Clear();
-       return NT_STATUS_UNSUCCESSFUL;
+       Py_CLEAR(parameters);
+       Py_CLEAR(provision_mod);
+       Py_CLEAR(provision_fn);
+       Py_CLEAR(provision_dict);
+       Py_CLEAR(py_result);
+       Py_CLEAR(py_sid);
+       if (!NT_STATUS_IS_OK(status)) {
+               PyErr_Print();
+               PyErr_Clear();
+       }
+       return status;
 }
 
 
-struct ldb_context *provision_get_schema(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
+struct ldb_context *provision_get_schema(TALLOC_CTX *mem_ctx,
+                                        struct loadparm_context *lp_ctx,
+                                        const char *schema_dn,
                                         DATA_BLOB *override_prefixmap)
 {
-       const char *setupdir;
        PyObject *schema_mod, *schema_dict, *schema_fn, *py_result, *parameters;
-       
-       DEBUG(0,("Schema for DRS tests using python\n"));
-
+       PyObject *py_ldb = NULL;
+       struct ldb_context *ldb_result = NULL;
        Py_Initialize();
-       py_update_path("bin"); /* FIXME: Can't assume this is always the case */
+       py_update_path(); /* Put the samba path at the start of sys.path */
 
        schema_mod = schema_module();
 
@@ -374,13 +524,22 @@ struct ldb_context *provision_get_schema(TALLOC_CTX *mem_ctx, struct loadparm_co
        
        parameters = PyDict_New();
 
-       setupdir = lp_setupdir(lp_ctx);
-       PyDict_SetItemString(parameters, "setup_dir", 
-                            PyString_FromString(setupdir));
+       if (schema_dn) {
+               if (!dict_insert(parameters,
+                                "schemadn",
+                                PyStr_FromString(schema_dn))) {
+                       return NULL;
+               }
+       }
+
        if (override_prefixmap) {
-               PyDict_SetItemString(parameters, "override_prefixmap",
-                                    PyString_FromStringAndSize((const char *)override_prefixmap->data,
-                                                               override_prefixmap->length));
+               if (!dict_insert(parameters,
+                                "override_prefixmap",
+                                PyBytes_FromStringAndSize(
+                                       (const char *)override_prefixmap->data,
+                                       override_prefixmap->length))) {
+                       return NULL;
+               }
        }
 
        py_result = PyEval_CallObjectWithKeywords(schema_fn, NULL, parameters);
@@ -393,5 +552,12 @@ struct ldb_context *provision_get_schema(TALLOC_CTX *mem_ctx, struct loadparm_co
                return NULL;
        }
 
-       return PyLdb_AsLdbContext(PyObject_GetAttrString(py_result, "ldb"));
+       py_ldb = PyObject_GetAttrString(py_result, "ldb");
+       Py_DECREF(py_result);
+       ldb_result = pyldb_Ldb_AsLdbContext(py_ldb);
+       if (talloc_reference(mem_ctx, ldb_result) == NULL) {
+               ldb_result = NULL;
+       }
+       Py_DECREF(py_ldb);
+       return ldb_result;
 }