diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
commit | 4f5791ebd03eaec1c7da0865a383175b05102712 (patch) | |
tree | 8ce7b00f7a76baa386372422adebbe64510812d4 /source4/param | |
parent | Initial commit. (diff) | |
download | samba-upstream.tar.xz samba-upstream.zip |
Adding upstream version 2:4.17.12+dfsg.upstream/2%4.17.12+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | source4/param/loadparm.c | 77 | ||||
-rw-r--r-- | source4/param/provision.c | 559 | ||||
-rw-r--r-- | source4/param/provision.h | 72 | ||||
-rw-r--r-- | source4/param/pyparam.c | 746 | ||||
-rw-r--r-- | source4/param/pyparam.h | 28 | ||||
-rw-r--r-- | source4/param/pyparam_util.c | 81 | ||||
-rw-r--r-- | source4/param/secrets.c | 152 | ||||
-rw-r--r-- | source4/param/secrets.h | 51 | ||||
-rw-r--r-- | source4/param/share.c | 156 | ||||
-rw-r--r-- | source4/param/share.h | 149 | ||||
-rw-r--r-- | source4/param/share_classic.c | 385 | ||||
-rw-r--r-- | source4/param/tests/loadparm.c | 271 | ||||
-rw-r--r-- | source4/param/tests/share.c | 207 | ||||
-rw-r--r-- | source4/param/wscript_build | 62 |
14 files changed, 2996 insertions, 0 deletions
diff --git a/source4/param/loadparm.c b/source4/param/loadparm.c new file mode 100644 index 0000000..7d3891d --- /dev/null +++ b/source4/param/loadparm.c @@ -0,0 +1,77 @@ +/* + Unix SMB/CIFS implementation. + Parameter loading functions + Copyright (C) Karl Auer 1993-1998 + + Largely re-written by Andrew Tridgell, September 1994 + + Copyright (C) Simo Sorce 2001 + Copyright (C) Alexander Bokovoy 2002 + Copyright (C) Stefan (metze) Metzmacher 2002 + Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003. + Copyright (C) James Myers 2003 <myersjj@samba.org> + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/param/param.h" +#include "libcli/raw/libcliraw.h" +#include "librpc/ndr/libndr.h" +#include "libcli/smb/smb2_negotiate_context.h" + +void lpcfg_smbcli_options(struct loadparm_context *lp_ctx, + struct smbcli_options *options) +{ + struct GUID client_guid; + const char *str = NULL; + + str = lpcfg_parm_string(lp_ctx, NULL, "libsmb", "client_guid"); + if (str != NULL) { + GUID_from_string(str, &client_guid); + } else { + client_guid = GUID_random(); + } + *options = (struct smbcli_options) { + .max_xmit = lpcfg_max_xmit(lp_ctx), + .max_mux = lpcfg_max_mux(lp_ctx), + .use_spnego = lpcfg_nt_status_support(lp_ctx) && lpcfg_client_use_spnego(lp_ctx), + .signing = lpcfg_client_signing(lp_ctx), + .request_timeout = SMB_REQUEST_TIMEOUT, + .ntstatus_support = lpcfg_nt_status_support(lp_ctx), + .min_protocol = lpcfg_client_min_protocol(lp_ctx), + .max_protocol = lpcfg__client_max_protocol(lp_ctx), + .unicode = lpcfg_unicode(lp_ctx), + .use_oplocks = true, + .use_level2_oplocks = true, + .smb2_capabilities = SMB2_CAP_ALL, + .client_guid = client_guid, + .max_credits = WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK, + .smb3_capabilities = smb311_capabilities_parse("client", + lpcfg_client_smb3_signing_algorithms(lp_ctx), + lpcfg_client_smb3_encryption_algorithms(lp_ctx)), + }; +} + +void lpcfg_smbcli_session_options(struct loadparm_context *lp_ctx, + struct smbcli_session_options *options) +{ + *options = (struct smbcli_session_options) { + .lanman_auth = lpcfg_client_lanman_auth(lp_ctx), + .ntlmv2_auth = lpcfg_client_ntlmv2_auth(lp_ctx), + .plaintext_auth = lpcfg_client_plaintext_auth(lp_ctx), + }; +} + diff --git a/source4/param/provision.c b/source4/param/provision.c new file mode 100644 index 0000000..e0b7c69 --- /dev/null +++ b/source4/param/provision.c @@ -0,0 +1,559 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008-2009 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <Python.h> +#include "python/py3compat.h" +#include <ldb.h> +#include <pyldb.h> +#include "includes.h" +#include "librpc/ndr/libndr.h" +#include "param/provision.h" +#include "param/secrets.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 (value == NULL) { + return false; + } + if (PyDict_SetItemString(dict, key, value) == -1) { + Py_XDECREF(value); + return false; + } + Py_XDECREF(value); + return true; +} + +static PyObject *provision_module(void) +{ + PyObject *name = PyUnicode_FromString("samba.provision"); + PyObject *mod = NULL; + if (name == NULL) + return NULL; + mod = PyImport_Import(name); + Py_CLEAR(name); + return mod; +} + +static PyObject *schema_module(void) +{ + PyObject *name = PyUnicode_FromString("samba.schema"); + PyObject *mod = NULL; + if (name == NULL) + return NULL; + mod = PyImport_Import(name); + Py_CLEAR(name); + return mod; +} + +static PyObject *ldb_module(void) +{ + PyObject *name = PyUnicode_FromString("ldb"); + PyObject *mod = NULL; + if (name == NULL) + return NULL; + mod = PyImport_Import(name); + Py_CLEAR(name); + return mod; +} + +static PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx) +{ + PyLdbObject *ret; + PyObject *ldb_mod = ldb_module(); + PyTypeObject *ldb_ctx_type; + if (ldb_mod == NULL) + return NULL; + + ldb_ctx_type = (PyTypeObject *)PyObject_GetAttrString(ldb_mod, "Ldb"); + + 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; +} + +NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, + struct provision_settings *settings, + struct provision_result *result) +{ + const char *configfile; + 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(); /* Put the samba path at the start of sys.path */ + + provision_mod = provision_module(); + + if (provision_mod == NULL) { + PyErr_Print(); + DEBUG(0, ("Unable to import provision Python module.\n")); + return NT_STATUS_UNSUCCESSFUL; + } + + provision_dict = PyModule_GetDict(provision_mod); + + if (provision_dict == NULL) { + DEBUG(0, ("Unable to get dictionary for provision module\n")); + return NT_STATUS_UNSUCCESSFUL; + } + + provision_fn = PyDict_GetItemString(provision_dict, "provision_become_dc"); + if (provision_fn == NULL) { + PyErr_Print(); + DEBUG(0, ("Unable to get provision_become_dc function\n")); + return NT_STATUS_UNSUCCESSFUL; + } + + DEBUG(0,("New Server in Site[%s]\n", + settings->site_name)); + + DEBUG(0,("DSA Instance [%s]\n" + "\tinvocationId[%s]\n", + settings->ntds_dn_str, + settings->invocation_id == NULL?"None":GUID_string(mem_ctx, settings->invocation_id))); + + DEBUG(0,("Paths under targetdir[%s]\n", + settings->targetdir)); + parameters = PyDict_New(); + + configfile = lpcfg_configfile(lp_ctx); + if (configfile != NULL) { + if (!dict_insert(parameters, "smbconf", + PyUnicode_FromString(configfile))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + } + + if (!dict_insert(parameters, + "rootdn", + PyUnicode_FromString(settings->root_dn_str))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + if (settings->targetdir != NULL) { + if (!dict_insert(parameters, + "targetdir", + PyUnicode_FromString(settings->targetdir))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + } + if (!dict_insert(parameters, + "hostname", + PyUnicode_FromString(settings->netbios_name))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + if (!dict_insert(parameters, + "domain", + PyUnicode_FromString(settings->domain))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + if (!dict_insert(parameters, + "realm", + PyUnicode_FromString(settings->realm))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + if (settings->root_dn_str) { + if (!dict_insert(parameters, + "rootdn", + PyUnicode_FromString(settings->root_dn_str))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + } + + if (settings->domain_dn_str) { + if (!dict_insert(parameters, + "domaindn", + PyUnicode_FromString(settings->domain_dn_str))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + } + + if (settings->schema_dn_str) { + if (!dict_insert(parameters, + "schemadn", + PyUnicode_FromString(settings->schema_dn_str))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + } + if (settings->config_dn_str) { + if (!dict_insert(parameters, + "configdn", + PyUnicode_FromString(settings->config_dn_str))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + } + if (settings->server_dn_str) { + if (!dict_insert(parameters, + "serverdn", + PyUnicode_FromString(settings->server_dn_str))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + } + if (settings->site_name) { + if (!dict_insert(parameters, + "sitename", + PyUnicode_FromString(settings->site_name))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + } + + if (!dict_insert(parameters, + "machinepass", + PyUnicode_FromString(settings->machine_password))){ + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + + if (!dict_insert(parameters, + "debuglevel", + PyLong_FromLong(DEBUGLEVEL))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + + if (!dict_insert(parameters, + "use_ntvfs", + PyLong_FromLong(settings->use_ntvfs))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + + py_result = PyEval_CallObjectWithKeywords(provision_fn, NULL, parameters); + + if (py_result == NULL) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + + py_domaindn = PyObject_GetAttrString(py_result, "domaindn"); + result->domaindn = talloc_strdup(mem_ctx, PyUnicode_AsUTF8(py_domaindn)); + + /* FIXME paths */ + 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); + + 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 = NULL, *dom_sid_Type = NULL, *result = NULL; + + mod_security = PyImport_ImportModule("samba.dcerpc.security"); + if (mod_security == NULL) { + return NULL; + } + + dom_sid_Type = PyObject_GetAttrString(mod_security, "dom_sid"); + if (dom_sid_Type == NULL) { + Py_DECREF(mod_security); + return NULL; + } + + 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, + struct tevent_context *event_ctx, + struct provision_store_self_join_settings *settings, + const char **error_string) +{ + int ret; + PyObject *provision_mod = NULL, *provision_dict = NULL; + PyObject *provision_fn = NULL, *py_result = NULL; + PyObject *parameters = 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) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + + /* Create/Open the secrets database */ + ldb = secrets_db_create(tmp_mem, lp_ctx); + if (!ldb) { + *error_string + = talloc_asprintf(mem_ctx, + "Could not open secrets database"); + status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + goto out; + } + + ret = ldb_transaction_start(ldb); + + if (ret != LDB_SUCCESS) { + *error_string + = talloc_asprintf(mem_ctx, + "Could not start transaction on secrets database: %s", ldb_errstring(ldb)); + status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + goto out; + } + + Py_Initialize(); + py_update_path(); /* Put the samba path at the start of sys.path */ + provision_mod = provision_module(); + + if (provision_mod == NULL) { + *error_string + = talloc_asprintf(mem_ctx, "Unable to import provision Python module."); + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + + provision_dict = PyModule_GetDict(provision_mod); + + if (provision_dict == NULL) { + *error_string + = talloc_asprintf(mem_ctx, "Unable to get dictionary for provision module"); + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + + provision_fn = PyDict_GetItemString(provision_dict, "secretsdb_self_join"); + if (provision_fn == NULL) { + *error_string + = talloc_asprintf(mem_ctx, "Unable to get provision_become_dc function"); + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + + parameters = PyDict_New(); + + if(!dict_insert(parameters, + "secretsdb", + PyLdb_FromLdbContext(ldb))){ + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + if (!dict_insert(parameters, + "domain", + PyUnicode_FromString(settings->domain_name))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + if (settings->realm != NULL) { + if (!dict_insert(parameters, + "realm", + PyUnicode_FromString(settings->realm))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + } + if (!dict_insert(parameters, + "machinepass", + PyUnicode_FromString(settings->machine_password))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + if (!dict_insert(parameters, + "netbiosname", + PyUnicode_FromString(settings->netbios_name))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + + + if (!dict_insert(parameters, + "domainsid", + py_dom_sid_FromSid(settings->domain_sid))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + + if (!dict_insert(parameters, + "secure_channel_type", + PyLong_FromLong(settings->secure_channel_type))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + + if (!dict_insert(parameters, + "key_version_number", + PyLong_FromLong(settings->key_version_number))) { + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + + py_result = PyEval_CallObjectWithKeywords(provision_fn, NULL, parameters); + + if (py_result == NULL) { + ldb_transaction_cancel(ldb); + status = NT_STATUS_UNSUCCESSFUL; + goto out; + } + + ret = ldb_transaction_commit(ldb); + if (ret != LDB_SUCCESS) { + *error_string + = talloc_asprintf(mem_ctx, + "Could not commit transaction on secrets database: %s", ldb_errstring(ldb)); + status = NT_STATUS_INTERNAL_DB_ERROR; + goto out; + } + + status = NT_STATUS_OK; +out: + talloc_free(tmp_mem); + Py_CLEAR(parameters); + Py_CLEAR(provision_mod); + Py_CLEAR(provision_dict); + Py_CLEAR(py_result); + 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, + const char *schema_dn, + DATA_BLOB *override_prefixmap) +{ + PyObject *schema_mod, *schema_dict, *schema_fn, *py_result, *parameters; + PyObject *py_ldb = NULL; + struct ldb_context *ldb_result = NULL; + Py_Initialize(); + py_update_path(); /* Put the samba path at the start of sys.path */ + + schema_mod = schema_module(); + + if (schema_mod == NULL) { + PyErr_Print(); + DEBUG(0, ("Unable to import schema Python module.\n")); + return NULL; + } + + schema_dict = PyModule_GetDict(schema_mod); + + if (schema_dict == NULL) { + DEBUG(0, ("Unable to get dictionary for schema module\n")); + return NULL; + } + + schema_fn = PyDict_GetItemString(schema_dict, "ldb_with_schema"); + if (schema_fn == NULL) { + PyErr_Print(); + DEBUG(0, ("Unable to get schema_get_ldb function\n")); + return NULL; + } + + parameters = PyDict_New(); + + if (schema_dn) { + if (!dict_insert(parameters, + "schemadn", + PyUnicode_FromString(schema_dn))) { + return NULL; + } + } + + if (override_prefixmap) { + 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); + + Py_DECREF(parameters); + + if (py_result == NULL) { + PyErr_Print(); + PyErr_Clear(); + return NULL; + } + + 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; +} diff --git a/source4/param/provision.h b/source4/param/provision.h new file mode 100644 index 0000000..2f6f582 --- /dev/null +++ b/source4/param/provision.h @@ -0,0 +1,72 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _PROVISION_H_ +#define _PROVISION_H_ + +struct provision_settings { + const char *site_name; + const char *root_dn_str; + const char *domain_dn_str; + const char *config_dn_str; + const char *schema_dn_str; + const char *server_dn_str; + const struct GUID *invocation_id; + const char *netbios_name; + const char *host_ip; + const char *realm; + const char *domain; + const char *ntds_dn_str; + const char *machine_password; + const char *targetdir; + bool use_ntvfs; +}; + +/* FIXME: Rename this to hostconfig ? */ +struct provision_result { + const char *domaindn; + struct ldb_context *samdb; + struct loadparm_context *lp_ctx; +}; + +struct provision_store_self_join_settings { + const char *domain_name; + const char *realm; + const char *netbios_name; + enum netr_SchannelType secure_channel_type; + const char *machine_password; + int key_version_number; + struct dom_sid *domain_sid; +}; + +NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, + struct provision_settings *settings, + struct provision_result *result); + +NTSTATUS provision_store_self_join(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, + struct tevent_context *ev_ctx, + struct provision_store_self_join_settings *settings, + const char **error_string); + +struct ldb_context *provision_get_schema(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + const char *schema_dn, + DATA_BLOB *override_prefixmap); + +#endif /* _PROVISION_H_ */ diff --git a/source4/param/pyparam.c b/source4/param/pyparam.c new file mode 100644 index 0000000..8f28083 --- /dev/null +++ b/source4/param/pyparam.c @@ -0,0 +1,746 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <Python.h> +#include "python/py3compat.h" +#include "includes.h" +#include "param/param.h" +#include "param/loadparm.h" +#include <pytalloc.h> +#include "dynconfig/dynconfig.h" + +#define PyLoadparmContext_AsLoadparmContext(obj) pytalloc_get_type(obj, struct loadparm_context) +#define PyLoadparmService_AsLoadparmService(obj) pytalloc_get_type(obj, struct loadparm_service) + +extern PyTypeObject PyLoadparmContext; +extern PyTypeObject PyLoadparmService; + +static PyObject *PyLoadparmService_FromService(struct loadparm_service *service) +{ + return pytalloc_reference(&PyLoadparmService, service); +} + +static PyObject *py_lp_ctx_get_helper(struct loadparm_context *lp_ctx, const char *service_name, const char *param_name) +{ + struct parm_struct *parm = NULL; + void *parm_ptr = NULL; + int i; + + if (service_name != NULL && strwicmp(service_name, GLOBAL_NAME) && + strwicmp(service_name, GLOBAL_NAME2)) { + struct loadparm_service *service; + /* its a share parameter */ + service = lpcfg_service(lp_ctx, service_name); + if (service == NULL) { + return NULL; + } + if (strchr(param_name, ':')) { + /* its a parametric option on a share */ + const char *type = talloc_strndup(lp_ctx, param_name, + strcspn(param_name, ":")); + const char *option = strchr(param_name, ':') + 1; + const char *value; + if (type == NULL || option == NULL) { + return NULL; + } + value = lpcfg_get_parametric(lp_ctx, service, type, option); + if (value == NULL) { + return NULL; + } + return PyUnicode_FromString(value); + } + + parm = lpcfg_parm_struct(lp_ctx, param_name); + if (parm == NULL || parm->p_class == P_GLOBAL) { + return NULL; + } + parm_ptr = lpcfg_parm_ptr(lp_ctx, service, parm); + } else if (strchr(param_name, ':')) { + /* its a global parametric option */ + const char *type = talloc_strndup(lp_ctx, + param_name, strcspn(param_name, ":")); + const char *option = strchr(param_name, ':') + 1; + const char *value; + if (type == NULL || option == NULL) { + return NULL; + } + value = lpcfg_get_parametric(lp_ctx, NULL, type, option); + if (value == NULL) + return NULL; + return PyUnicode_FromString(value); + } else { + /* its a global parameter */ + parm = lpcfg_parm_struct(lp_ctx, param_name); + if (parm == NULL) { + return NULL; + } + parm_ptr = lpcfg_parm_ptr(lp_ctx, NULL, parm); + } + + if (parm == NULL || parm_ptr == NULL) { + return NULL; + } + + /* construct and return the right type of python object */ + switch (parm->type) { + case P_CHAR: + return PyUnicode_FromFormat("%c", *(char *)parm_ptr); + case P_STRING: + case P_USTRING: + return PyUnicode_FromString(*(char **)parm_ptr); + case P_BOOL: + return PyBool_FromLong(*(bool *)parm_ptr); + case P_BOOLREV: + return PyBool_FromLong(!(*(bool *)parm_ptr)); + case P_INTEGER: + case P_OCTAL: + case P_BYTES: + return PyLong_FromLong(*(int *)parm_ptr); + case P_ENUM: + for (i=0; parm->enum_list[i].name; i++) { + if (*(int *)parm_ptr == parm->enum_list[i].value) { + return PyUnicode_FromString(parm->enum_list[i].name); + } + } + return NULL; + case P_CMDLIST: + case P_LIST: + { + int j; + const char **strlist = *(const char ***)parm_ptr; + PyObject *pylist; + + if(strlist == NULL) { + return PyList_New(0); + } + + pylist = PyList_New(str_list_length(strlist)); + for (j = 0; strlist[j]; j++) + PyList_SetItem(pylist, j, + PyUnicode_FromString(strlist[j])); + return pylist; + } + } + return NULL; + +} + +static PyObject *py_lp_ctx_load(PyObject *self, PyObject *args) +{ + char *filename; + bool ret; + if (!PyArg_ParseTuple(args, "s", &filename)) + return NULL; + + ret = lpcfg_load(PyLoadparmContext_AsLoadparmContext(self), filename); + + if (!ret) { + PyErr_Format(PyExc_RuntimeError, "Unable to load file %s", filename); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject *py_lp_ctx_load_default(PyObject *self, PyObject *unused) +{ + bool ret; + ret = lpcfg_load_default(PyLoadparmContext_AsLoadparmContext(self)); + + if (!ret) { + PyErr_SetString(PyExc_RuntimeError, "Unable to load default file"); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject *py_lp_ctx_get(PyObject *self, PyObject *args) +{ + char *param_name; + char *section_name = NULL; + PyObject *ret; + if (!PyArg_ParseTuple(args, "s|z", ¶m_name, §ion_name)) + return NULL; + + ret = py_lp_ctx_get_helper(PyLoadparmContext_AsLoadparmContext(self), section_name, param_name); + if (ret == NULL) + Py_RETURN_NONE; + return ret; +} + +static PyObject *py_lp_ctx_is_myname(PyObject *self, PyObject *args) +{ + char *name; + if (!PyArg_ParseTuple(args, "s", &name)) + return NULL; + + return PyBool_FromLong(lpcfg_is_myname(PyLoadparmContext_AsLoadparmContext(self), name)); +} + +static PyObject *py_lp_ctx_is_mydomain(PyObject *self, PyObject *args) +{ + char *name; + if (!PyArg_ParseTuple(args, "s", &name)) + return NULL; + + return PyBool_FromLong(lpcfg_is_mydomain(PyLoadparmContext_AsLoadparmContext(self), name)); +} + +static PyObject *py_lp_ctx_set(PyObject *self, PyObject *args) +{ + char *name, *value; + bool ret; + if (!PyArg_ParseTuple(args, "ss", &name, &value)) + return NULL; + + ret = lpcfg_set_cmdline(PyLoadparmContext_AsLoadparmContext(self), name, value); + if (!ret) { + PyErr_SetString(PyExc_RuntimeError, "Unable to set parameter"); + return NULL; + } + + Py_RETURN_NONE; +} + +static PyObject *py_lp_ctx_private_path(PyObject *self, PyObject *args) +{ + char *name, *path; + PyObject *ret; + if (!PyArg_ParseTuple(args, "s", &name)) + return NULL; + + path = lpcfg_private_path(NULL, PyLoadparmContext_AsLoadparmContext(self), name); + ret = PyUnicode_FromString(path); + talloc_free(path); + + return ret; +} + +static PyObject *py_lp_ctx_services(PyObject *self, PyObject *unused) +{ + struct loadparm_context *lp_ctx = PyLoadparmContext_AsLoadparmContext(self); + PyObject *ret; + int i; + ret = PyList_New(lpcfg_numservices(lp_ctx)); + for (i = 0; i < lpcfg_numservices(lp_ctx); i++) { + struct loadparm_service *service = lpcfg_servicebynum(lp_ctx, i); + if (service != NULL) { + PyList_SetItem(ret, i, PyUnicode_FromString(lpcfg_servicename(service))); + } + } + return ret; +} + +static PyObject *py_lp_ctx_server_role(PyObject *self, PyObject *unused) +{ + struct loadparm_context *lp_ctx = PyLoadparmContext_AsLoadparmContext(self); + uint32_t role; + const char *role_str; + + role = lpcfg_server_role(lp_ctx); + role_str = server_role_str(role); + + return PyUnicode_FromString(role_str); +} + +static PyObject *py_lp_dump(PyObject *self, PyObject *args) +{ + bool show_defaults = false; + const char *file_name = ""; + const char *mode = "w"; + FILE *f; + struct loadparm_context *lp_ctx = PyLoadparmContext_AsLoadparmContext(self); + + if (!PyArg_ParseTuple(args, "|bss", &show_defaults, &file_name, &mode)) + return NULL; + + if (file_name[0] == '\0') { + f = stdout; + } else { + f = fopen(file_name, mode); + } + + if (f == NULL) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + + lpcfg_dump(lp_ctx, f, show_defaults, lpcfg_numservices(lp_ctx)); + + if (f != stdout) { + fclose(f); + } + + Py_RETURN_NONE; +} + +static PyObject *py_lp_dump_globals(PyObject *self, PyObject *args) +{ + bool show_defaults = false; + const char *file_name = ""; + const char *mode = "w"; + FILE *f; + struct loadparm_context *lp_ctx = PyLoadparmContext_AsLoadparmContext(self); + + if (!PyArg_ParseTuple(args, "|bss", &show_defaults, &file_name, &mode)) + return NULL; + + if (file_name[0] == '\0') { + f = stdout; + } else { + f = fopen(file_name, mode); + } + + if (f == NULL) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + + lpcfg_dump_globals(lp_ctx, f, show_defaults); + + if (f != stdout) { + fclose(f); + } + + Py_RETURN_NONE; +} + +static PyObject *py_lp_dump_a_parameter(PyObject *self, PyObject *args) +{ + char *param_name; + const char *section_name = NULL; + const char *file_name = ""; + const char *mode = "w"; + FILE *f; + struct loadparm_context *lp_ctx = PyLoadparmContext_AsLoadparmContext(self); + struct loadparm_service *service; + bool ret; + + if (!PyArg_ParseTuple(args, "s|zss", ¶m_name, §ion_name, &file_name, &mode)) + return NULL; + + if (file_name[0] == '\0') { + f = stdout; + } else { + f = fopen(file_name, mode); + } + + if (f == NULL) { + return NULL; + } + + if (section_name != NULL && strwicmp(section_name, GLOBAL_NAME) && + strwicmp(section_name, GLOBAL_NAME2)) { + /* it's a share parameter */ + service = lpcfg_service(lp_ctx, section_name); + if (service == NULL) { + PyErr_Format(PyExc_RuntimeError, "Unknown section %s", section_name); + return NULL; + } + } else { + /* it's global */ + service = NULL; + section_name = "global"; + } + + ret = lpcfg_dump_a_parameter(lp_ctx, service, param_name, f); + + if (!ret) { + PyErr_Format(PyExc_RuntimeError, "Parameter %s unknown for section %s", param_name, section_name); + if (f != stdout) { + fclose(f); + } + return NULL; + } + + if (f != stdout) { + fclose(f); + } + + Py_RETURN_NONE; + +} + +static PyObject *py_lp_log_level(PyObject *self, PyObject *unused) +{ + int ret = debuglevel_get(); + return PyLong_FromLong(ret); +} + + +static PyObject *py_samdb_url(PyObject *self, PyObject *unused) +{ + struct loadparm_context *lp_ctx = PyLoadparmContext_AsLoadparmContext(self); + return PyUnicode_FromFormat("tdb://%s/sam.ldb", lpcfg_private_dir(lp_ctx)); +} + +static PyObject *py_cache_path(PyObject *self, PyObject *args) +{ + struct loadparm_context *lp_ctx = PyLoadparmContext_AsLoadparmContext(self); + char *name = NULL; + char *path = NULL; + PyObject *ret = NULL; + + if (!PyArg_ParseTuple(args, "s", &name)) { + return NULL; + } + + path = lpcfg_cache_path(NULL, lp_ctx, name); + if (!path) { + PyErr_Format(PyExc_RuntimeError, + "Unable to access cache %s", name); + return NULL; + } + ret = PyUnicode_FromString(path); + talloc_free(path); + + return ret; +} + +static PyObject *py_state_path(PyObject *self, PyObject *args) +{ + struct loadparm_context *lp_ctx = + PyLoadparmContext_AsLoadparmContext(self); + char *name = NULL; + char *path = NULL; + PyObject *ret = NULL; + + if (!PyArg_ParseTuple(args, "s", &name)) { + return NULL; + } + + path = lpcfg_state_path(NULL, lp_ctx, name); + if (!path) { + PyErr_Format(PyExc_RuntimeError, + "Unable to access cache %s", name); + return NULL; + } + ret = PyUnicode_FromString(path); + talloc_free(path); + + return ret; +} + +static PyMethodDef py_lp_ctx_methods[] = { + { "load", py_lp_ctx_load, METH_VARARGS, + "S.load(filename) -> None\n" + "Load specified file." }, + { "load_default", py_lp_ctx_load_default, METH_NOARGS, + "S.load_default() -> None\n" + "Load default smb.conf file." }, + { "is_myname", py_lp_ctx_is_myname, METH_VARARGS, + "S.is_myname(name) -> bool\n" + "Check whether the specified name matches one of our netbios names." }, + { "is_mydomain", py_lp_ctx_is_mydomain, METH_VARARGS, + "S.is_mydomain(name) -> bool\n" + "Check whether the specified name matches our domain name." }, + { "get", py_lp_ctx_get, METH_VARARGS, + "S.get(name, service_name) -> value\n" + "Find specified parameter." }, + { "set", py_lp_ctx_set, METH_VARARGS, + "S.set(name, value) -> bool\n" + "Change a parameter." }, + { "private_path", py_lp_ctx_private_path, METH_VARARGS, + "S.private_path(name) -> path\n" }, + { "services", py_lp_ctx_services, METH_NOARGS, + "S.services() -> list" }, + { "server_role", py_lp_ctx_server_role, METH_NOARGS, + "S.server_role() -> value\n" + "Get the server role." }, + { "dump", py_lp_dump, METH_VARARGS, + "S.dump(show_defaults=False, file_name='', mode='w')" }, + { "dump_globals", py_lp_dump_globals, METH_VARARGS, + "S.dump_globals(show_defaults=False, file_name='', mode='w')" }, + { "dump_a_parameter", py_lp_dump_a_parameter, METH_VARARGS, + "S.dump_a_parameter(name, service_name, file_name='', mode='w')" }, + { "log_level", py_lp_log_level, METH_NOARGS, + "S.log_level() -> int\n Get the active log level" }, + { "samdb_url", py_samdb_url, METH_NOARGS, + "S.samdb_url() -> string\n" + "Returns the current URL for sam.ldb." }, + { "cache_path", py_cache_path, METH_VARARGS, + "S.cache_path(name) -> string\n" + "Returns a path in the Samba cache directory." }, + { "state_path", py_state_path, METH_VARARGS, + "S.state_path(name) -> string\n" + "Returns a path in the Samba state directory." }, + {0} +}; + +static PyObject *py_lp_ctx_default_service(PyObject *self, void *closure) +{ + return PyLoadparmService_FromService(lpcfg_default_service(PyLoadparmContext_AsLoadparmContext(self))); +} + +static PyObject *py_lp_ctx_config_file(PyObject *self, void *closure) +{ + const char *configfile = lpcfg_configfile(PyLoadparmContext_AsLoadparmContext(self)); + if (configfile == NULL) + Py_RETURN_NONE; + else + return PyUnicode_FromString(configfile); +} + +static PyObject *py_lp_ctx_weak_crypto(PyObject *self, void *closure) +{ + enum samba_weak_crypto weak_crypto = + lpcfg_weak_crypto(PyLoadparmContext_AsLoadparmContext(self)); + + switch(weak_crypto) { + case SAMBA_WEAK_CRYPTO_UNKNOWN: + Py_RETURN_NONE; + case SAMBA_WEAK_CRYPTO_ALLOWED: + return PyUnicode_FromString("allowed"); + case SAMBA_WEAK_CRYPTO_DISALLOWED: + return PyUnicode_FromString("disallowed"); + } + + Py_RETURN_NONE; +} + +static PyGetSetDef py_lp_ctx_getset[] = { + { + .name = discard_const_p(char, "default_service"), + .get = (getter)py_lp_ctx_default_service, + }, + { + .name = discard_const_p(char, "configfile"), + .get = (getter)py_lp_ctx_config_file, + .doc = discard_const_p(char, "Name of last config file that was loaded.") + }, + { + .name = discard_const_p(char, "weak_crypto"), + .get = (getter)py_lp_ctx_weak_crypto, + .doc = discard_const_p(char, "If weak crypto is allowed.") + }, + { .name = NULL } +}; + +static PyObject *py_lp_ctx_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + const char *kwnames[] = {"filename_for_non_global_lp", NULL}; + PyObject *lp_ctx; + const char *non_global_conf = NULL; + struct loadparm_context *ctx; + + if (!PyArg_ParseTupleAndKeywords(args, + kwargs, + "|s", + discard_const_p(char *, + kwnames), + &non_global_conf)) { + return NULL; + } + + /* + * by default, any LoadParm python objects map to a single global + * underlying object. The filename_for_non_global_lp arg overrides this + * default behaviour and creates a separate underlying LoadParm object. + */ + if (non_global_conf != NULL) { + bool ok; + ctx = loadparm_init(NULL); + if (ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } + + lp_ctx = pytalloc_reference(type, ctx); + if (lp_ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } + + ok = lpcfg_load_no_global( + PyLoadparmContext_AsLoadparmContext(lp_ctx), + non_global_conf); + if (!ok) { + PyErr_Format(PyExc_ValueError, + "Could not load non-global conf %s", + non_global_conf); + return NULL; + } + return lp_ctx; + } else{ + return pytalloc_reference(type, loadparm_init_global(false)); + } +} + +static Py_ssize_t py_lp_ctx_len(PyObject *self) +{ + return lpcfg_numservices(PyLoadparmContext_AsLoadparmContext(self)); +} + +static PyObject *py_lp_ctx_getitem(PyObject *self, PyObject *name) +{ + struct loadparm_service *service; + if (!PyUnicode_Check(name)) { + PyErr_SetString(PyExc_TypeError, "Only string subscripts are supported"); + return NULL; + } + service = lpcfg_service(PyLoadparmContext_AsLoadparmContext(self), PyUnicode_AsUTF8(name)); + if (service == NULL) { + PyErr_SetString(PyExc_KeyError, "No such section"); + return NULL; + } + return PyLoadparmService_FromService(service); +} + +static PyMappingMethods py_lp_ctx_mapping = { + .mp_length = (lenfunc)py_lp_ctx_len, + .mp_subscript = (binaryfunc)py_lp_ctx_getitem, +}; + +PyTypeObject PyLoadparmContext = { + .tp_name = "param.LoadParm", + .tp_getset = py_lp_ctx_getset, + .tp_methods = py_lp_ctx_methods, + .tp_new = py_lp_ctx_new, + .tp_as_mapping = &py_lp_ctx_mapping, + .tp_flags = Py_TPFLAGS_DEFAULT, +}; + +static PyObject *py_lp_service_dump(PyObject *self, PyObject *args) +{ + bool show_defaults = false; + FILE *f; + const char *file_name = ""; + const char *mode = "w"; + struct loadparm_service *service = PyLoadparmService_AsLoadparmService(self); + struct loadparm_service *default_service; + PyObject *py_default_service; + + if (!PyArg_ParseTuple(args, "O|bss", &py_default_service, &show_defaults, &file_name, &mode)) + return NULL; + + if (file_name[0] == '\0') { + f = stdout; + } else { + f = fopen(file_name, mode); + } + + if (f == NULL) { + return NULL; + } + + if (!PyObject_TypeCheck(py_default_service, &PyLoadparmService)) { + PyErr_SetNone(PyExc_TypeError); + if (f != stdout) { + fclose(f); + } + return NULL; + } + + default_service = PyLoadparmService_AsLoadparmService(py_default_service); + + lpcfg_dump_one(f, show_defaults, service, default_service); + + if (f != stdout) { + fclose(f); + } + + Py_RETURN_NONE; +} + +static PyMethodDef py_lp_service_methods[] = { + { "dump", (PyCFunction)py_lp_service_dump, METH_VARARGS, + "S.dump(default_service, show_defaults=False, file_name='', mode='w')" }, + {0} +}; + +PyTypeObject PyLoadparmService = { + .tp_name = "param.LoadparmService", + .tp_methods = py_lp_service_methods, + .tp_flags = Py_TPFLAGS_DEFAULT, +}; + +static PyObject *py_data_dir(PyObject *self) +{ + return PyUnicode_FromString(dyn_DATADIR); +} + +static PyObject *py_default_path(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return PyUnicode_FromString(lp_default_path()); +} + +static PyObject *py_setup_dir(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return PyUnicode_FromString(dyn_SETUPDIR); +} + +static PyObject *py_modules_dir(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return PyUnicode_FromString(dyn_MODULESDIR); +} + +static PyObject *py_bin_dir(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return PyUnicode_FromString(dyn_BINDIR); +} + +static PyObject *py_sbin_dir(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return PyUnicode_FromString(dyn_SBINDIR); +} + +static PyMethodDef pyparam_methods[] = { + { "data_dir", (PyCFunction)py_data_dir, METH_NOARGS, + "Returns the compiled in location of data directory." }, + { "default_path", (PyCFunction)py_default_path, METH_NOARGS, + "Returns the default smb.conf path." }, + { "setup_dir", (PyCFunction)py_setup_dir, METH_NOARGS, + "Returns the compiled in location of provision templates." }, + { "modules_dir", (PyCFunction)py_modules_dir, METH_NOARGS, + "Returns the compiled in location of modules." }, + { "bin_dir", (PyCFunction)py_bin_dir, METH_NOARGS, + "Returns the compiled in BINDIR." }, + { "sbin_dir", (PyCFunction)py_sbin_dir, METH_NOARGS, + "Returns the compiled in SBINDIR." }, + {0} +}; + +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + .m_name = "param", + .m_doc = "Parsing and writing Samba configuration files.", + .m_size = -1, + .m_methods = pyparam_methods, +}; + +MODULE_INIT_FUNC(param) +{ + PyObject *m; + PyTypeObject *talloc_type = pytalloc_GetObjectType(); + if (talloc_type == NULL) + return NULL; + + if (pytalloc_BaseObject_PyType_Ready(&PyLoadparmContext) < 0) + return NULL; + + if (pytalloc_BaseObject_PyType_Ready(&PyLoadparmService) < 0) + return NULL; + + m = PyModule_Create(&moduledef); + if (m == NULL) + return NULL; + + Py_INCREF(&PyLoadparmContext); + PyModule_AddObject(m, "LoadParm", (PyObject *)&PyLoadparmContext); + return m; +} diff --git a/source4/param/pyparam.h b/source4/param/pyparam.h new file mode 100644 index 0000000..e8944f5 --- /dev/null +++ b/source4/param/pyparam.h @@ -0,0 +1,28 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _PYPARAM_H_ +#define _PYPARAM_H_ + +#include "param/param.h" + +_PUBLIC_ struct loadparm_context *lpcfg_from_py_object(TALLOC_CTX *mem_ctx, PyObject *py_obj); +_PUBLIC_ struct loadparm_context *py_default_loadparm_context(TALLOC_CTX *mem_ctx); + +#endif /* _PYPARAM_H_ */ diff --git a/source4/param/pyparam_util.c b/source4/param/pyparam_util.c new file mode 100644 index 0000000..9b9dcd2 --- /dev/null +++ b/source4/param/pyparam_util.c @@ -0,0 +1,81 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <Python.h> +#include "py3compat.h" +#include "includes.h" +#include "param/param.h" +#include "param/pyparam.h" +#include "param/loadparm.h" +#include <pytalloc.h> + +#define PyLoadparmContext_AsLoadparmContext(obj) pytalloc_get_type(obj, struct loadparm_context) + +_PUBLIC_ struct loadparm_context *lpcfg_from_py_object(TALLOC_CTX *mem_ctx, PyObject *py_obj) +{ + struct loadparm_context *lp_ctx; + PyObject *param_mod; + PyTypeObject *lp_type; + bool is_lpobj; + + if (PyUnicode_Check(py_obj)) { + lp_ctx = loadparm_init_global(false); + if (lp_ctx == NULL) { + return NULL; + } + if (!lpcfg_load(lp_ctx, PyUnicode_AsUTF8(py_obj))) { + PyErr_Format(PyExc_RuntimeError, "Unable to load %s", + PyUnicode_AsUTF8(py_obj)); + return NULL; + } + return lp_ctx; + } + + if (py_obj == Py_None) { + return loadparm_init_global(true); + } + + param_mod = PyImport_ImportModule("samba.param"); + if (param_mod == NULL) { + return NULL; + } + + lp_type = (PyTypeObject *)PyObject_GetAttrString(param_mod, "LoadParm"); + Py_DECREF(param_mod); + if (lp_type == NULL) { + PyErr_SetString(PyExc_RuntimeError, "Unable to import LoadParm"); + return NULL; + } + + is_lpobj = PyObject_TypeCheck(py_obj, lp_type); + Py_DECREF(lp_type); + if (is_lpobj) { + return talloc_reference(mem_ctx, PyLoadparmContext_AsLoadparmContext(py_obj)); + } + + PyErr_SetNone(PyExc_TypeError); + return NULL; +} + +struct loadparm_context *py_default_loadparm_context(TALLOC_CTX *mem_ctx) +{ + return loadparm_init_global(true); +} + + diff --git a/source4/param/secrets.c b/source4/param/secrets.c new file mode 100644 index 0000000..1df8620 --- /dev/null +++ b/source4/param/secrets.c @@ -0,0 +1,152 @@ +/* + Unix SMB/CIFS implementation. + Copyright (C) Andrew Tridgell 1992-2001 + Copyright (C) Andrew Bartlett 2002 + Copyright (C) Rafal Szczesniak 2002 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* the Samba secrets database stores any generated, private information + such as the local SID and machine trust password */ + +#include "includes.h" +#include "secrets.h" +#include "param/param.h" +#include "system/filesys.h" +#include "lib/tdb_wrap/tdb_wrap.h" +#include "lib/ldb-samba/ldb_wrap.h" +#include <ldb.h> +#include "../lib/util/util_tdb.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "dsdb/samdb/samdb.h" + +/** + create or connect to the secrets ldb +*/ +struct ldb_context *secrets_db_create(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx) +{ + return ldb_wrap_connect(mem_ctx, NULL, lp_ctx, "secrets.ldb", + NULL, NULL, 0); +} + +/** + connect to the secrets ldb +*/ +struct ldb_context *secrets_db_connect(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx) +{ + return ldb_wrap_connect(mem_ctx, NULL, lp_ctx, "secrets.ldb", + NULL, NULL, LDB_FLG_DONT_CREATE_DB); +} + +/** + * Retrieve the domain SID from the secrets database. + * @return pointer to a SID object if the SID could be obtained, NULL otherwise + */ +struct dom_sid *secrets_get_domain_sid(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + const char *domain, + enum netr_SchannelType *sec_channel_type, + char **errstring) +{ + struct ldb_context *ldb; + struct ldb_message *msg; + int ldb_ret; + const char *attrs[] = { "objectSid", "secureChannelType", NULL }; + struct dom_sid *result = NULL; + const struct ldb_val *v; + enum ndr_err_code ndr_err; + + *errstring = NULL; + + ldb = secrets_db_connect(mem_ctx, lp_ctx); + if (ldb == NULL) { + DEBUG(5, ("secrets_db_connect failed\n")); + return NULL; + } + + ldb_ret = dsdb_search_one(ldb, ldb, &msg, + ldb_dn_new(mem_ctx, ldb, SECRETS_PRIMARY_DOMAIN_DN), + LDB_SCOPE_ONELEVEL, + attrs, 0, SECRETS_PRIMARY_DOMAIN_FILTER, domain); + + if (ldb_ret != LDB_SUCCESS) { + *errstring = talloc_asprintf(mem_ctx, "Failed to find record for %s in %s: %s: %s", + domain, (char *) ldb_get_opaque(ldb, "ldb_url"), + ldb_strerror(ldb_ret), ldb_errstring(ldb)); + return NULL; + } + v = ldb_msg_find_ldb_val(msg, "objectSid"); + if (v == NULL) { + *errstring = talloc_asprintf(mem_ctx, "Failed to find a SID on record for %s in %s", + domain, (char *) ldb_get_opaque(ldb, "ldb_url")); + return NULL; + } + + if (sec_channel_type) { + int t; + t = ldb_msg_find_attr_as_int(msg, "secureChannelType", -1); + if (t == -1) { + *errstring = talloc_asprintf(mem_ctx, "Failed to find secureChannelType for %s in %s", + domain, (char *) ldb_get_opaque(ldb, "ldb_url")); + return NULL; + } + *sec_channel_type = t; + } + + result = talloc(mem_ctx, struct dom_sid); + if (result == NULL) { + talloc_free(ldb); + return NULL; + } + + ndr_err = ndr_pull_struct_blob(v, result, result, + (ndr_pull_flags_fn_t)ndr_pull_dom_sid); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + *errstring = talloc_asprintf(mem_ctx, "Failed to parse SID on record for %s in %s", + domain, (char *) ldb_get_opaque(ldb, "ldb_url")); + talloc_free(result); + talloc_free(ldb); + return NULL; + } + + return result; +} + +char *keytab_name_from_msg(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct ldb_message *msg) +{ + const char *krb5keytab = ldb_msg_find_attr_as_string(msg, "krb5Keytab", NULL); + if (krb5keytab) { + return talloc_strdup(mem_ctx, krb5keytab); + } else { + char *file_keytab; + char *relative_path; + const char *privateKeytab = ldb_msg_find_attr_as_string(msg, "privateKeytab", NULL); + if (!privateKeytab) { + return NULL; + } + + relative_path = ldb_relative_path(ldb, mem_ctx, privateKeytab); + if (!relative_path) { + return NULL; + } + file_keytab = talloc_asprintf(mem_ctx, "FILE:%s", relative_path); + talloc_free(relative_path); + return file_keytab; + } + return NULL; +} + diff --git a/source4/param/secrets.h b/source4/param/secrets.h new file mode 100644 index 0000000..1d2dc2b --- /dev/null +++ b/source4/param/secrets.h @@ -0,0 +1,51 @@ +/* + * Unix SMB/CIFS implementation. + * secrets.tdb file format info + * Copyright (C) Andrew Tridgell 2000 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program 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 General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _SOURCE4_PARAM_SECRETS_H +#define _SOURCE4_PARAM_SECRETS_H + +#define SECRETS_PRIMARY_DOMAIN_DN "cn=Primary Domains" +#define SECRETS_PRINCIPALS_DN "cn=Principals" +#define SECRETS_PRIMARY_DOMAIN_FILTER "(&(flatname=%s)(objectclass=primaryDomain))" +#define SECRETS_PRIMARY_REALM_FILTER "(&(realm=%s)(objectclass=primaryDomain))" +#define SECRETS_KRBTGT_SEARCH "(&((|(realm=%s)(flatname=%s))(samAccountName=krbtgt)))" +#define SECRETS_PRINCIPAL_SEARCH "(&(|(realm=%s)(flatname=%s))(servicePrincipalName=%s))" +#define SECRETS_LDAP_FILTER "(&(objectclass=ldapSecret)(cn=SAMDB Credentials))" + +struct loadparm_context; +struct tevent_context; +struct ldb_message; +struct ldb_context; + +#include "librpc/gen_ndr/misc.h" + +bool randseed_init(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx); + +struct ldb_context *secrets_db_create(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx); +struct ldb_context *secrets_db_connect(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx); +struct dom_sid *secrets_get_domain_sid(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + const char *domain, + enum netr_SchannelType *sec_channel_type, + char **errstring); +char *keytab_name_from_msg(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct ldb_message *msg); + + +#endif /* _SOURCE4_PARAM_SECRETS_H */ diff --git a/source4/param/share.c b/source4/param/share.c new file mode 100644 index 0000000..aa477c7 --- /dev/null +++ b/source4/param/share.c @@ -0,0 +1,156 @@ +/* + Unix SMB/CIFS implementation. + + Modular shares configuration system + + Copyright (C) Simo Sorce 2006 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "param/share.h" +#include "param/param.h" +#include "lib/util/samba_modules.h" + +char *share_string_option(TALLOC_CTX *mem_ctx, struct share_config *scfg, const char *opt_name, const char *defval) +{ + return scfg->ctx->ops->string_option(mem_ctx, scfg, opt_name, defval); +} + +int share_int_option(struct share_config *scfg, const char *opt_name, int defval) +{ + return scfg->ctx->ops->int_option(scfg, opt_name, defval); +} + +bool share_bool_option(struct share_config *scfg, const char *opt_name, bool defval) +{ + return scfg->ctx->ops->bool_option(scfg, opt_name, defval); +} + +const char **share_string_list_option(TALLOC_CTX *mem_ctx, struct share_config *scfg, const char *opt_name) +{ + return scfg->ctx->ops->string_list_option(mem_ctx, scfg, opt_name); +} + +NTSTATUS share_list_all(TALLOC_CTX *mem_ctx, struct share_context *sctx, int *count, const char ***names) +{ + return sctx->ops->list_all(mem_ctx, sctx, count, names); +} + +NTSTATUS share_get_config(TALLOC_CTX *mem_ctx, struct share_context *sctx, const char *name, struct share_config **scfg) +{ + return sctx->ops->get_config(mem_ctx, sctx, name, scfg); +} + +NTSTATUS share_create(struct share_context *sctx, const char *name, struct share_info *info, int count) +{ + if (sctx->ops->create) { + return sctx->ops->create(sctx, name, info, count); + } + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS share_set(struct share_context *sctx, const char *name, struct share_info *info, int count) +{ + if (sctx->ops->set) { + return sctx->ops->set(sctx, name, info, count); + } + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS share_remove(struct share_context *sctx, const char *name) +{ + if (sctx->ops->remove) { + return sctx->ops->remove(sctx, name); + } + return NT_STATUS_NOT_IMPLEMENTED; +} + +/* List of currently available share backends */ +static struct share_ops **backends = NULL; + +static const struct share_ops *share_backend_by_name(const char *name) +{ + int i; + + for (i = 0; backends && backends[i]; i++) { + if (strcmp(backends[i]->name, name) == 0) { + return backends[i]; + } + } + + return NULL; +} + +/* + Register the share backend +*/ +NTSTATUS share_register(const struct share_ops *ops) +{ + int i; + + if (share_backend_by_name(ops->name) != NULL) { + DEBUG(0,("SHARE backend [%s] already registered\n", ops->name)); + return NT_STATUS_OBJECT_NAME_COLLISION; + } + + i = 0; + while (backends && backends[i]) { + i++; + } + + backends = realloc_p(backends, struct share_ops *, i + 2); + if (!backends) { + smb_panic("out of memory in share_register"); + } + + backends[i] = (struct share_ops *)smb_xmemdup(ops, sizeof(*ops)); + backends[i]->name = smb_xstrdup(ops->name); + + backends[i + 1] = NULL; + + DEBUG(3, ("SHARE backend [%s] registered.\n", ops->name)); + + return NT_STATUS_OK; +} + +NTSTATUS share_get_context(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + struct share_context **ctx) +{ + const struct share_ops *ops; + + ops = share_backend_by_name("classic"); + if (!ops) { + DEBUG(0, ("share_init_connection: share backend [classic] not found!\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + return ops->init(mem_ctx, ops, lp_ctx, ctx); +} + +/* + initialise the SHARE subsystem +*/ +NTSTATUS share_init(void) +{ +#define _MODULE_PROTO(init) extern NTSTATUS init(TALLOC_CTX *); + STATIC_share_MODULES_PROTO; + init_module_fn static_init[] = { STATIC_share_MODULES }; + + run_init_functions(NULL, static_init); + + return NT_STATUS_OK; +} diff --git a/source4/param/share.h b/source4/param/share.h new file mode 100644 index 0000000..087697a --- /dev/null +++ b/source4/param/share.h @@ -0,0 +1,149 @@ +/* + Unix SMB/CIFS implementation. + + Modular services configuration + + Copyright (C) Simo Sorce 2006 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _SHARE_H +#define _SHARE_H + +struct share_ops; + +struct share_context { + const struct share_ops *ops; + void *priv_data; +}; + +struct share_config { + const char *name; + struct share_context *ctx; + void *opaque; +}; + +enum share_info_type { + SHARE_INFO_STRING, + SHARE_INFO_INT, + SHARE_INFO_BLOB +}; + +struct share_info { + enum share_info_type type; + const char *name; + void *value; +}; + +struct tevent_context; + +struct share_ops { + const char *name; + NTSTATUS (*init)(TALLOC_CTX *, const struct share_ops*, + struct loadparm_context *lp_ctx, + struct share_context **); + char *(*string_option)(TALLOC_CTX *, struct share_config *, const char *, const char *); + int (*int_option)(struct share_config *, const char *, int); + bool (*bool_option)(struct share_config *, const char *, bool); + const char **(*string_list_option)(TALLOC_CTX *, struct share_config *, const char *); + NTSTATUS (*list_all)(TALLOC_CTX *, struct share_context *, int *, const char ***); + NTSTATUS (*get_config)(TALLOC_CTX *, struct share_context *, const char *, struct share_config **); + NTSTATUS (*create)(struct share_context *, const char *, struct share_info *, int); + NTSTATUS (*set)(struct share_context *, const char *, struct share_info *, int); + NTSTATUS (*remove)(struct share_context *, const char *); +}; + +struct loadparm_context; + +char *share_string_option(TALLOC_CTX *mem_ctx, struct share_config *scfg, const char *opt_name, const char *defval); +int share_int_option(struct share_config *scfg, const char *opt_name, int defval); +bool share_bool_option(struct share_config *scfg, const char *opt_name, bool defval); +const char **share_string_list_option(TALLOC_CTX *mem_ctx, struct share_config *scfg, const char *opt_name); +NTSTATUS share_list_all(TALLOC_CTX *mem_ctx, struct share_context *sctx, int *count, const char ***names); +NTSTATUS share_get_config(TALLOC_CTX *mem_ctx, struct share_context *sctx, const char *name, struct share_config **scfg); +NTSTATUS share_create(struct share_context *sctx, const char *name, struct share_info *info, int count); +NTSTATUS share_set(struct share_context *sctx, const char *name, struct share_info *info, int count); +NTSTATUS share_remove(struct share_context *sctx, const char *name); +NTSTATUS share_register(const struct share_ops *ops); +NTSTATUS share_get_context(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + struct share_context **ctx); +NTSTATUS share_init(void); + +/* list of shares options */ + +#define SHARE_NAME "name" +#define SHARE_PATH "path" +#define SHARE_COMMENT "comment" +#define SHARE_PASSWORD "password" +#define SHARE_HOSTS_ALLOW "hosts-allow" +#define SHARE_HOSTS_DENY "hosts-deny" +#define SHARE_NTVFS_HANDLER "ntvfs-handler" +#define SHARE_TYPE "type" +#define SHARE_CSC_POLICY "csc-policy" +#define SHARE_AVAILABLE "available" +#define SHARE_BROWSEABLE "browseable" +#define SHARE_MAX_CONNECTIONS "max-connections" + +/* I'd like to see the following options go away + * and always use EAs and SECDESCs */ +#define SHARE_READONLY "readonly" +#define SHARE_MAP_SYSTEM "map-system" +#define SHARE_MAP_HIDDEN "map-hidden" +#define SHARE_MAP_ARCHIVE "map-archive" + +#define SHARE_STRICT_LOCKING "strict-locking" +#define SHARE_OPLOCKS "oplocks" +#define SHARE_STRICT_SYNC "strict-sync" +#define SHARE_MSDFS_ROOT "msdfs-root" +#define SHARE_CI_FILESYSTEM "ci-filesystem" + +#define SHARE_DIR_MASK "directory mask" +#define SHARE_CREATE_MASK "create mask" +#define SHARE_FORCE_CREATE_MODE "force create mode" +#define SHARE_FORCE_DIR_MODE "force directory mode" + +/* defaults */ + +#define SHARE_HOST_ALLOW_DEFAULT NULL +#define SHARE_HOST_DENY_DEFAULT NULL +#define SHARE_VOLUME_DEFAULT NULL +#define SHARE_TYPE_DEFAULT "DISK" +#define SHARE_CSC_POLICY_DEFAULT 0 +#define SHARE_AVAILABLE_DEFAULT true +#define SHARE_BROWSEABLE_DEFAULT true +#define SHARE_MAX_CONNECTIONS_DEFAULT 0 + +#define SHARE_DIR_MASK_DEFAULT 0755 +#define SHARE_CREATE_MASK_DEFAULT 0744 +#define SHARE_FORCE_CREATE_MODE_DEFAULT 0000 +#define SHARE_FORCE_DIR_MODE_DEFAULT 0000 + + + +/* I'd like to see the following options go away + * and always use EAs and SECDESCs */ +#define SHARE_READONLY_DEFAULT true +#define SHARE_MAP_SYSTEM_DEFAULT false +#define SHARE_MAP_HIDDEN_DEFAULT false +#define SHARE_MAP_ARCHIVE_DEFAULT true + +#define SHARE_STRICT_LOCKING_DEFAULT true +#define SHARE_OPLOCKS_DEFAULT true +#define SHARE_STRICT_SYNC_DEFAULT false +#define SHARE_MSDFS_ROOT_DEFAULT false +#define SHARE_CI_FILESYSTEM_DEFAULT false + +#endif /* _SHARE_H */ diff --git a/source4/param/share_classic.c b/source4/param/share_classic.c new file mode 100644 index 0000000..d03558d --- /dev/null +++ b/source4/param/share_classic.c @@ -0,0 +1,385 @@ +/* + Unix SMB/CIFS implementation. + + Classic file based shares configuration + + Copyright (C) Simo Sorce 2006 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "param/share.h" +#include "param/param.h" + +NTSTATUS share_classic_init(TALLOC_CTX *); + +static NTSTATUS sclassic_init(TALLOC_CTX *mem_ctx, + const struct share_ops *ops, + struct loadparm_context *lp_ctx, + struct share_context **ctx) +{ + *ctx = talloc(mem_ctx, struct share_context); + if (!*ctx) { + DEBUG(0, ("ERROR: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + (*ctx)->ops = ops; + (*ctx)->priv_data = lp_ctx; + + return NT_STATUS_OK; +} + +static char *sclassic_string_option(TALLOC_CTX *mem_ctx, + struct share_config *scfg, + const char *opt_name, + const char *defval) +{ + struct loadparm_service *s = talloc_get_type(scfg->opaque, + struct loadparm_service); + struct loadparm_context *lp_ctx = talloc_get_type(scfg->ctx->priv_data, + struct loadparm_context); + char *parm, *val; + const char *ret; + + if (strchr(opt_name, ':')) { + parm = talloc_strdup(scfg, opt_name); + if (!parm) { + return NULL; + } + val = strchr(parm, ':'); + *val = '\0'; + val++; + + ret = lpcfg_parm_string(lp_ctx, s, parm, val); + if (!ret) { + ret = defval; + } + talloc_free(parm); + return talloc_strdup(mem_ctx, ret); + } + + if (strcmp(opt_name, SHARE_NAME) == 0) { + return talloc_strdup(mem_ctx, scfg->name); + } + + if (strcmp(opt_name, SHARE_PATH) == 0) { + return lpcfg_path(s, lpcfg_default_service(lp_ctx), mem_ctx); + } + + if (strcmp(opt_name, SHARE_COMMENT) == 0) { + return lpcfg_comment(s, lpcfg_default_service(lp_ctx), mem_ctx); + } + + if (strcmp(opt_name, SHARE_TYPE) == 0) { + if (lpcfg_printable(s, lpcfg_default_service(lp_ctx))) { + return talloc_strdup(mem_ctx, "PRINTER"); + } + if (strcmp("NTFS", lpcfg_fstype(s, lpcfg_default_service(lp_ctx))) == 0) { + return talloc_strdup(mem_ctx, "DISK"); + } + return talloc_strdup(mem_ctx, lpcfg_fstype(s, lpcfg_default_service(lp_ctx))); + } + + if (strcmp(opt_name, SHARE_PASSWORD) == 0) { + return talloc_strdup(mem_ctx, defval); + } + + DEBUG(0,("request for unknown share string option '%s'\n", + opt_name)); + + return talloc_strdup(mem_ctx, defval); +} + +static int sclassic_int_option(struct share_config *scfg, const char *opt_name, int defval) +{ + struct loadparm_service *s = talloc_get_type(scfg->opaque, + struct loadparm_service); + struct loadparm_context *lp_ctx = talloc_get_type(scfg->ctx->priv_data, + struct loadparm_context); + char *parm, *val; + int ret; + + if (strchr(opt_name, ':')) { + parm = talloc_strdup(scfg, opt_name); + if (!parm) { + return -1; + } + val = strchr(parm, ':'); + *val = '\0'; + val++; + + ret = lpcfg_parm_int(lp_ctx, s, parm, val, defval); + if (!ret) { + ret = defval; + } + talloc_free(parm); + return ret; + } + + if (strcmp(opt_name, SHARE_CSC_POLICY) == 0) { + return lpcfg_csc_policy(s, lpcfg_default_service(lp_ctx)); + } + + if (strcmp(opt_name, SHARE_MAX_CONNECTIONS) == 0) { + return lpcfg_max_connections(s, lpcfg_default_service(lp_ctx)); + } + + if (strcmp(opt_name, SHARE_CREATE_MASK) == 0) { + return lpcfg_create_mask(s, lpcfg_default_service(lp_ctx)); + } + + if (strcmp(opt_name, SHARE_DIR_MASK) == 0) { + return lpcfg_directory_mask(s, lpcfg_default_service(lp_ctx)); + } + + if (strcmp(opt_name, SHARE_FORCE_DIR_MODE) == 0) { + return lpcfg_force_directory_mode(s, lpcfg_default_service(lp_ctx)); + } + + if (strcmp(opt_name, SHARE_FORCE_CREATE_MODE) == 0) { + return lpcfg_force_create_mode(s, lpcfg_default_service(lp_ctx)); + } + + + DEBUG(0,("request for unknown share int option '%s'\n", + opt_name)); + + return defval; +} + +static bool sclassic_bool_option(struct share_config *scfg, const char *opt_name, + bool defval) +{ + struct loadparm_service *s = talloc_get_type(scfg->opaque, + struct loadparm_service); + struct loadparm_context *lp_ctx = talloc_get_type(scfg->ctx->priv_data, + struct loadparm_context); + char *parm, *val; + bool ret; + + if (strchr(opt_name, ':')) { + parm = talloc_strdup(scfg, opt_name); + if(!parm) { + return false; + } + val = strchr(parm, ':'); + *val = '\0'; + val++; + + ret = lpcfg_parm_bool(lp_ctx, s, parm, val, defval); + talloc_free(parm); + return ret; + } + + if (strcmp(opt_name, SHARE_AVAILABLE) == 0) { + return s != NULL; + } + + if (strcmp(opt_name, SHARE_BROWSEABLE) == 0) { + return lpcfg_browseable(s, lpcfg_default_service(lp_ctx)); + } + + if (strcmp(opt_name, SHARE_READONLY) == 0) { + return lpcfg_read_only(s, lpcfg_default_service(lp_ctx)); + } + + if (strcmp(opt_name, SHARE_MAP_SYSTEM) == 0) { + return lpcfg_map_system(s, lpcfg_default_service(lp_ctx)); + } + + if (strcmp(opt_name, SHARE_MAP_HIDDEN) == 0) { + return lpcfg_map_hidden(s, lpcfg_default_service(lp_ctx)); + } + + if (strcmp(opt_name, SHARE_MAP_ARCHIVE) == 0) { + return lpcfg_map_archive(s, lpcfg_default_service(lp_ctx)); + } + + if (strcmp(opt_name, SHARE_STRICT_LOCKING) == 0) { + return lpcfg_strict_locking(s, lpcfg_default_service(lp_ctx)); + } + + if (strcmp(opt_name, SHARE_OPLOCKS) == 0) { + return lpcfg_oplocks(s, lpcfg_default_service(lp_ctx)); + } + + if (strcmp(opt_name, SHARE_STRICT_SYNC) == 0) { + return lpcfg_strict_sync(s, lpcfg_default_service(lp_ctx)); + } + + if (strcmp(opt_name, SHARE_MSDFS_ROOT) == 0) { + return lpcfg_msdfs_root(s, lpcfg_default_service(lp_ctx)); + } + + if (strcmp(opt_name, SHARE_CI_FILESYSTEM) == 0) { + int case_sensitive = lpcfg_case_sensitive(s, lpcfg_default_service(lp_ctx)); + /* + * Yes, this confusingly named option means Samba acts + * case sensitive, so that the filesystem can act case + * insensitive. + * + */ + if (case_sensitive == Auto) { + /* Auto is for unix extensions and unix + * clients, which we don't support here. + * Samba needs to do the case changing, + * because the filesystem is case + * sensitive */ + return false; + } else if (case_sensitive) { + /* True means that Samba won't do anything to + * change the case of incoming requests. + * Essentially this means we trust the file + * system to be case insensitive */ + return true; + } else { + /* False means that Smaba needs to do the case + * changing, because the filesystem is case + * sensitive */ + return false; + } + } + + DEBUG(0,("request for unknown share bool option '%s'\n", + opt_name)); + + return defval; +} + +static const char **sclassic_string_list_option(TALLOC_CTX *mem_ctx, struct share_config *scfg, const char *opt_name) +{ + struct loadparm_service *s = talloc_get_type(scfg->opaque, + struct loadparm_service); + struct loadparm_context *lp_ctx = talloc_get_type(scfg->ctx->priv_data, + struct loadparm_context); + char *parm, *val; + const char **ret; + + if (strchr(opt_name, ':')) { + parm = talloc_strdup(scfg, opt_name); + if (!parm) { + return NULL; + } + val = strchr(parm, ':'); + *val = '\0'; + val++; + + ret = lpcfg_parm_string_list(mem_ctx, lp_ctx, s, parm, val, ",;"); + talloc_free(parm); + return ret; + } + + if (strcmp(opt_name, SHARE_HOSTS_ALLOW) == 0) { + return lpcfg_hosts_allow(s, lpcfg_default_service(lp_ctx)); + } + + if (strcmp(opt_name, SHARE_HOSTS_DENY) == 0) { + return lpcfg_hosts_deny(s, lpcfg_default_service(lp_ctx)); + } + + if (strcmp(opt_name, SHARE_NTVFS_HANDLER) == 0) { + return lpcfg_ntvfs_handler(s, lpcfg_default_service(lp_ctx)); + } + + DEBUG(0,("request for unknown share list option '%s'\n", + opt_name)); + + return NULL; +} + +static NTSTATUS sclassic_list_all(TALLOC_CTX *mem_ctx, + struct share_context *ctx, + int *count, + const char ***names) +{ + int i; + int num_services; + const char **n; + + num_services = lpcfg_numservices((struct loadparm_context *)ctx->priv_data); + + n = talloc_array(mem_ctx, const char *, num_services); + if (!n) { + DEBUG(0,("ERROR: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + for (i = 0; i < num_services; i++) { + n[i] = talloc_strdup(n, lpcfg_servicename(lpcfg_servicebynum((struct loadparm_context *)ctx->priv_data, i))); + if (!n[i]) { + DEBUG(0,("ERROR: Out of memory!\n")); + talloc_free(n); + return NT_STATUS_NO_MEMORY; + } + } + + *names = n; + *count = num_services; + + return NT_STATUS_OK; +} + +static NTSTATUS sclassic_get_config(TALLOC_CTX *mem_ctx, + struct share_context *ctx, + const char *name, + struct share_config **scfg) +{ + struct share_config *s; + struct loadparm_service *service; + + service = lpcfg_service((struct loadparm_context *)ctx->priv_data, name); + + if (service == NULL) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + s = talloc(mem_ctx, struct share_config); + if (!s) { + DEBUG(0,("ERROR: Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + s->name = talloc_strdup(s, lpcfg_servicename(service)); + if (!s->name) { + DEBUG(0,("ERROR: Out of memory!\n")); + talloc_free(s); + return NT_STATUS_NO_MEMORY; + } + + s->opaque = (void *)service; + s->ctx = ctx; + + *scfg = s; + + return NT_STATUS_OK; +} + +static const struct share_ops ops = { + .name = "classic", + .init = sclassic_init, + .string_option = sclassic_string_option, + .int_option = sclassic_int_option, + .bool_option = sclassic_bool_option, + .string_list_option = sclassic_string_list_option, + .list_all = sclassic_list_all, + .get_config = sclassic_get_config +}; + +NTSTATUS share_classic_init(TALLOC_CTX *ctx) +{ + return share_register(&ops); +} + diff --git a/source4/param/tests/loadparm.c b/source4/param/tests/loadparm.c new file mode 100644 index 0000000..6a6e33e --- /dev/null +++ b/source4/param/tests/loadparm.c @@ -0,0 +1,271 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "param/share.h" +#include "param/param.h" +#include "torture/torture.h" +#include "torture/local/proto.h" +#include "libds/common/roles.h" + +static bool test_create(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lp_ctx != NULL, "lp_ctx"); + return true; +} + +static bool test_set_option(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "workgroup=werkgroep"), "lpcfg_set_option failed"); + torture_assert_str_equal(tctx, "WERKGROEP", lpcfg_workgroup(lp_ctx), "workgroup"); + return true; +} + +static bool test_set_cmdline(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_set_cmdline(lp_ctx, "workgroup", "werkgroep"), "lpcfg_set_cmdline failed"); + torture_assert(tctx, lpcfg_do_global_parameter(lp_ctx, "workgroup", "barbla"), "lpcfg_set_option failed"); + torture_assert_str_equal(tctx, "WERKGROEP", lpcfg_workgroup(lp_ctx), "workgroup"); + return true; +} + +static bool test_do_global_parameter(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_do_global_parameter(lp_ctx, "workgroup", "werkgroep42"), + "lpcfg_set_cmdline failed"); + torture_assert_str_equal(tctx, lpcfg_workgroup(lp_ctx), "WERKGROEP42", "workgroup"); + return true; +} + + +static bool test_do_global_parameter_var(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_do_global_parameter_var(lp_ctx, "workgroup", "werk%s%d", "groep", 42), + "lpcfg_set_cmdline failed"); + torture_assert_str_equal(tctx, lpcfg_workgroup(lp_ctx), "WERKGROEP42", "workgroup"); + return true; +} + + +static bool test_set_option_invalid(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, !lpcfg_set_option(lp_ctx, "workgroup"), "lpcfg_set_option succeeded"); + return true; +} + +static bool test_set_option_parametric(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "some:thing=blaat"), "lpcfg_set_option failed"); + torture_assert_str_equal(tctx, lpcfg_parm_string(lp_ctx, NULL, "some", "thing"), "blaat", + "invalid parametric option"); + return true; +} + +static bool test_lp_parm_double(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "some:thing=3.4"), "lpcfg_set_option failed"); + torture_assert(tctx, lpcfg_parm_double(lp_ctx, NULL, "some", "thing", 2.0) == 3.4, + "invalid parametric option"); + torture_assert(tctx, lpcfg_parm_double(lp_ctx, NULL, "some", "bla", 2.0) == 2.0, + "invalid parametric option"); + return true; +} + +static bool test_lp_parm_bool(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "some:thing=true"), "lpcfg_set_option failed"); + torture_assert(tctx, lpcfg_parm_bool(lp_ctx, NULL, "some", "thing", false) == true, + "invalid parametric option"); + torture_assert(tctx, lpcfg_parm_bool(lp_ctx, NULL, "some", "bla", true) == true, + "invalid parametric option"); + return true; +} + +static bool test_lp_parm_int(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "some:thing=34"), "lpcfg_set_option failed"); + torture_assert_int_equal(tctx, lpcfg_parm_int(lp_ctx, NULL, "some", "thing", 20), 34, + "invalid parametric option"); + torture_assert_int_equal(tctx, lpcfg_parm_int(lp_ctx, NULL, "some", "bla", 42), 42, + "invalid parametric option"); + return true; +} + +static bool test_lp_parm_bytes(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "some:thing=16K"), "lpcfg_set_option failed"); + torture_assert_int_equal(tctx, lpcfg_parm_bytes(lp_ctx, NULL, "some", "thing", 20), 16 * 1024, + "invalid parametric option"); + torture_assert_int_equal(tctx, lpcfg_parm_bytes(lp_ctx, NULL, "some", "bla", 42), 42, + "invalid parametric option"); + return true; +} + +static bool test_lp_do_service_parameter(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + struct loadparm_service *service = lpcfg_add_service(lp_ctx, lpcfg_default_service(lp_ctx), "foo"); + torture_assert(tctx, lpcfg_do_service_parameter(lp_ctx, service, + "some:thing", "foo"), "lpcfg_set_option failed"); + torture_assert_str_equal(tctx, lpcfg_parm_string(lp_ctx, service, "some", "thing"), "foo", + "invalid parametric option"); + return true; +} + +static bool test_lp_service(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + struct loadparm_service *service = lpcfg_add_service(lp_ctx, lpcfg_default_service(lp_ctx), "foo"); + torture_assert(tctx, service == lpcfg_service(lp_ctx, "foo"), "invalid service"); + return true; +} + +static bool test_server_role_default(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert_int_equal(tctx, lpcfg_server_role(lp_ctx), ROLE_STANDALONE, "ROLE should be standalone by default"); + torture_assert_int_equal(tctx, lpcfg_security(lp_ctx), SEC_USER, "security should be user"); + return true; +} + +static bool test_server_role_dc_specified(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "server role=domain controller"), "lpcfg_set_option failed"); + torture_assert_int_equal(tctx, lpcfg_server_role(lp_ctx), ROLE_ACTIVE_DIRECTORY_DC, "ROLE should be DC"); + torture_assert_int_equal(tctx, lpcfg_security(lp_ctx), SEC_USER, "security should be USER"); + return true; +} + +static bool test_server_role_member_specified(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "server role=member"), "lpcfg_set_option failed"); + torture_assert_int_equal(tctx, lpcfg_server_role(lp_ctx), ROLE_DOMAIN_MEMBER, "ROLE should be member"); + torture_assert_int_equal(tctx, lpcfg_security(lp_ctx), SEC_ADS, "security should be ADS"); + return true; +} + +static bool test_server_role_member_specified2(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "server role=member"), "lpcfg_set_option failed"); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "security=domain"), "lpcfg_set_option failed"); + torture_assert_int_equal(tctx, lpcfg_server_role(lp_ctx), ROLE_DOMAIN_MEMBER, "ROLE should be member"); + torture_assert_int_equal(tctx, lpcfg_security(lp_ctx), SEC_DOMAIN, "security should be domain"); + return true; +} + +static bool test_server_role_member_specified3(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "server role=member"), "lpcfg_set_option failed"); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "security=ads"), "lpcfg_set_option failed"); + torture_assert_int_equal(tctx, lpcfg_server_role(lp_ctx), ROLE_DOMAIN_MEMBER, "ROLE should be member"); + torture_assert_int_equal(tctx, lpcfg_security(lp_ctx), SEC_ADS, "security should be ads"); + return true; +} + +static bool test_server_role_standalone_specified(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "server role=standalone"), "lpcfg_set_option failed"); + torture_assert_int_equal(tctx, lpcfg_server_role(lp_ctx), ROLE_STANDALONE, "ROLE should be standalone"); + torture_assert_int_equal(tctx, lpcfg_security(lp_ctx), SEC_USER, "security should be USER"); + return true; +} + +static bool test_server_role_dc_domain_logons(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "domain logons=true"), "lpcfg_set_option failed"); + torture_assert_int_equal(tctx, lpcfg_server_role(lp_ctx), ROLE_DOMAIN_PDC, "ROLE should be PDC"); + torture_assert_int_equal(tctx, lpcfg_security(lp_ctx), SEC_USER, "security should be user"); + return true; +} + +static bool test_server_role_dc_domain_logons_and_not_master(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "domain logons=true"), "lpcfg_set_option failed"); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "domain master=false"), "lpcfg_set_option failed"); + torture_assert_int_equal(tctx, lpcfg_server_role(lp_ctx), ROLE_DOMAIN_BDC, "ROLE should be BDC"); + torture_assert_int_equal(tctx, lpcfg_security(lp_ctx), SEC_USER, "security should be user"); + return true; +} + +static bool test_server_role_security_ads(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "security=ads"), "lpcfg_set_option failed"); + torture_assert_int_equal(tctx, lpcfg_server_role(lp_ctx), ROLE_DOMAIN_MEMBER, "ROLE should be MEMBER"); + torture_assert_int_equal(tctx, lpcfg_security(lp_ctx), SEC_ADS, "security should be ads"); + return true; +} + +static bool test_server_role_security_domain(struct torture_context *tctx) +{ + struct loadparm_context *lp_ctx = loadparm_init(tctx); + torture_assert(tctx, lpcfg_set_option(lp_ctx, "security=domain"), "lpcfg_set_option failed"); + torture_assert_int_equal(tctx, lpcfg_server_role(lp_ctx), ROLE_DOMAIN_MEMBER, "ROLE should be MEMBER"); + torture_assert_int_equal(tctx, lpcfg_security(lp_ctx), SEC_DOMAIN, "security should be domain"); + return true; +} + +struct torture_suite *torture_local_loadparm(TALLOC_CTX *mem_ctx) +{ + struct torture_suite *suite = torture_suite_create(mem_ctx, "loadparm"); + + torture_suite_add_simple_test(suite, "create", test_create); + torture_suite_add_simple_test(suite, "set_option", test_set_option); + torture_suite_add_simple_test(suite, "set_cmdline", test_set_cmdline); + torture_suite_add_simple_test(suite, "set_option_invalid", test_set_option_invalid); + torture_suite_add_simple_test(suite, "set_option_parametric", test_set_option_parametric); + torture_suite_add_simple_test(suite, "set_lp_parm_double", test_lp_parm_double); + torture_suite_add_simple_test(suite, "set_lp_parm_bool", test_lp_parm_bool); + torture_suite_add_simple_test(suite, "set_lp_parm_int", test_lp_parm_int); + torture_suite_add_simple_test(suite, "set_lp_parm_bytes", test_lp_parm_bytes); + torture_suite_add_simple_test(suite, "service_parameter", test_lp_do_service_parameter); + torture_suite_add_simple_test(suite, "lpcfg_service", test_lp_service); + torture_suite_add_simple_test(suite, "do_global_parameter_var", test_do_global_parameter_var); + torture_suite_add_simple_test(suite, "do_global_parameter", test_do_global_parameter); + torture_suite_add_simple_test(suite, "test_server_role_default", test_server_role_default); + torture_suite_add_simple_test(suite, "test_server_role_dc_specified", test_server_role_dc_specified); + torture_suite_add_simple_test(suite, "test_server_role_member_specified", test_server_role_member_specified); + torture_suite_add_simple_test(suite, "test_server_role_member_specified2", test_server_role_member_specified2); + torture_suite_add_simple_test(suite, "test_server_role_member_specified3", test_server_role_member_specified3); + torture_suite_add_simple_test(suite, "test_server_role_standalone_specified", test_server_role_standalone_specified); + torture_suite_add_simple_test(suite, "test_server_role_dc_domain_logons", test_server_role_dc_domain_logons); + torture_suite_add_simple_test(suite, "test_server_role_dc_domain_logons_and_not_master", test_server_role_dc_domain_logons_and_not_master); + torture_suite_add_simple_test(suite, "test_server_role_security_ads", test_server_role_security_ads); + torture_suite_add_simple_test(suite, "test_server_role_security_domain", test_server_role_security_domain); + + return suite; +} diff --git a/source4/param/tests/share.c b/source4/param/tests/share.c new file mode 100644 index 0000000..9ac43ba --- /dev/null +++ b/source4/param/tests/share.c @@ -0,0 +1,207 @@ +/* + Unix SMB/CIFS implementation. + + local testing of share code + + Copyright (C) Jelmer Vernooij 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "param/share.h" +#include "param/param.h" +#include "torture/torture.h" +#include "torture/local/proto.h" + +static bool test_list_empty(struct torture_context *tctx, + const void *tcase_data, + const void *test_data) +{ + struct share_context *ctx = (struct share_context *)discard_const(tcase_data); + int count; + const char **names; + + torture_assert_ntstatus_ok(tctx, share_list_all(tctx, ctx, &count, &names), + "share_list_all failed"); + + return true; +} + +static bool test_create(struct torture_context *tctx, + const void *tcase_data, + const void *test_data) +{ + struct share_context *ctx = (struct share_context *)discard_const(tcase_data); + int count; + const char **names; + int i; + bool found = false; + struct share_info inf[] = { + { SHARE_INFO_STRING, SHARE_TYPE, discard_const_p(void *, "IPC$") }, + { SHARE_INFO_STRING, SHARE_PATH, discard_const_p(void *, "/tmp/bla") } + }; + NTSTATUS status; + + status = share_create(ctx, "bloe", inf, 2); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) + torture_skip(tctx, "Not supported by backend"); + + torture_assert_ntstatus_ok(tctx, status, "create_share failed"); + + torture_assert_ntstatus_ok(tctx, share_list_all(tctx, ctx, &count, &names), + "share_list_all failed"); + + torture_assert(tctx, count >= 1, "creating share failed"); + + + for (i = 0; i < count; i++) { + found |= strcmp(names[i], "bloe") == 0; + } + + torture_assert(tctx, found, "created share found"); + + return true; +} + + +static bool test_create_invalid(struct torture_context *tctx, + const void *tcase_data, + const void *test_data) +{ + struct share_context *ctx = (struct share_context *)discard_const(tcase_data); + NTSTATUS status; + + status = share_create(ctx, "bla", NULL, 0); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) + torture_skip(tctx, "Not supported by backend"); + + torture_assert_ntstatus_equal(tctx, NT_STATUS_INVALID_PARAMETER, + status, + "create_share failed"); + + torture_assert_ntstatus_equal(tctx, NT_STATUS_INVALID_PARAMETER, + share_create(ctx, NULL, NULL, 0), + "create_share failed"); + + return true; +} + +static bool test_share_remove_invalid(struct torture_context *tctx, + const void *tcase_data, + const void *test_data) +{ + struct share_context *ctx = (struct share_context *)discard_const(tcase_data); + NTSTATUS status; + + status = share_remove(ctx, "nonexistent"); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) + torture_skip(tctx, "Not supported by backend"); + + torture_assert_ntstatus_equal(tctx, status, NT_STATUS_UNSUCCESSFUL, "remove fails"); + + return true; +} + + + +static bool test_share_remove(struct torture_context *tctx, + const void *tcase_data, + const void *test_data) +{ + struct share_context *ctx = (struct share_context *)discard_const(tcase_data); + struct share_info inf[] = { + { SHARE_INFO_STRING, SHARE_TYPE, discard_const_p(void *, "IPC$") }, + { SHARE_INFO_STRING, SHARE_PATH, discard_const_p(void *, "/tmp/bla") } + }; + NTSTATUS status; + + status = share_create(ctx, "blie", inf, 2); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) + torture_skip(tctx, "Not supported by backend"); + + torture_assert_ntstatus_ok(tctx, status, "create_share failed"); + + torture_assert_ntstatus_ok(tctx, share_remove(ctx, "blie"), "remove failed"); + + return true; +} + +static bool test_double_create(struct torture_context *tctx, + const void *tcase_data, + const void *test_data) +{ + struct share_context *ctx = (struct share_context *)discard_const(tcase_data); + struct share_info inf[] = { + { SHARE_INFO_STRING, SHARE_TYPE, discard_const_p(void *, "IPC$") }, + { SHARE_INFO_STRING, SHARE_PATH, discard_const_p(void *, "/tmp/bla") } + }; + NTSTATUS status; + + status = share_create(ctx, "bla", inf, 2); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) + torture_skip(tctx, "Not supported by backend"); + + torture_assert_ntstatus_ok(tctx, status, "create_share failed"); + + torture_assert_ntstatus_equal(tctx, NT_STATUS_OBJECT_NAME_COLLISION, + share_create(ctx, "bla", inf, 2), + "create_share failed"); + + return true; +} + +static void tcase_add_share_tests(struct torture_tcase *tcase) +{ + torture_tcase_add_test_const(tcase, "list_empty", test_list_empty,NULL); + torture_tcase_add_test_const(tcase, "share_create", test_create, NULL); + torture_tcase_add_test_const(tcase, "share_remove", test_share_remove, + NULL); + torture_tcase_add_test_const(tcase, "share_remove_invalid", + test_share_remove_invalid, NULL); + torture_tcase_add_test_const(tcase, "share_create_invalid", + test_create_invalid, NULL); + torture_tcase_add_test_const(tcase, "share_double_create", + test_double_create, NULL); +} + +static bool setup_classic(struct torture_context *tctx, void **data) +{ + return NT_STATUS_IS_OK(share_get_context(tctx, tctx->lp_ctx, (struct share_context **)data)); +} + +static bool teardown(struct torture_context *tctx, void *data) +{ + talloc_free(data); + return true; +} + +struct torture_suite *torture_local_share(TALLOC_CTX *mem_ctx) +{ + struct torture_suite *suite = torture_suite_create(mem_ctx, "share"); + struct torture_tcase *tcase; + + share_init(); + + tcase = torture_suite_add_tcase(suite, "classic"); + torture_tcase_set_fixture(tcase, setup_classic, teardown); + tcase_add_share_tests(tcase); + + return suite; +} diff --git a/source4/param/wscript_build b/source4/param/wscript_build new file mode 100644 index 0000000..d1b852c --- /dev/null +++ b/source4/param/wscript_build @@ -0,0 +1,62 @@ +#!/usr/bin/env python +name = bld.pyembed_libname('PROVISION') +pytalloc_util = bld.pyembed_libname('pytalloc-util') +pyparam_util = bld.pyembed_libname('pyparam_util') +libpython = bld.pyembed_libname('LIBPYTHON') + +pyldb_util = bld.pyembed_libname('pyldb-util') +bld.SAMBA_SUBSYSTEM(name, + source='provision.c pyparam.c', + deps='%s %s ldb %s %s' % (libpython, pyparam_util, pytalloc_util, pyldb_util), + pyext=True, + enabled=bld.PYTHON_BUILD_IS_ENABLED(), +) + + +bld.SAMBA_SUBSYSTEM('share', + source='share.c', + public_headers='share.h', + deps='samba-util samba-modules' + ) + + +bld.SAMBA_MODULE('share_classic', + source='share_classic.c', + subsystem='share', + init_function='share_classic_init', + deps='samba-util samba-hostconfig' + ) + + +bld.SAMBA_SUBSYSTEM('SECRETS', + source='secrets.c', + deps='ldb tdb-wrap util_tdb NDR_SECURITY tevent ldbwrap' + ) + +pytalloc_util = bld.pyembed_libname('pytalloc-util') +pyparam_util = bld.pyembed_libname('pyparam_util') +libpython = bld.pyembed_libname('LIBPYTHON') + +bld.SAMBA_PYTHON('pyparam', + source='pyparam.c', + deps='samba-hostconfig %s' % pytalloc_util, + realname='samba/param.so' + ) + +bld.SAMBA_SUBSYSTEM(pyparam_util, + source='pyparam_util.c', + deps='%s samba-hostconfig %s' % (libpython, pytalloc_util), + pyext=True, + enabled=bld.PYTHON_BUILD_IS_ENABLED() + ) + +bld.SAMBA_SUBSYSTEM('param_options', + source='loadparm.c', + deps='samba-hostconfig') + + +bld.SAMBA_LIBRARY('shares', + source=[], + deps='share', + grouping_library=True, + private_library=True) |