diff options
Diffstat (limited to 'lib/smbconf/pysmbconf.c')
-rw-r--r-- | lib/smbconf/pysmbconf.c | 813 |
1 files changed, 813 insertions, 0 deletions
diff --git a/lib/smbconf/pysmbconf.c b/lib/smbconf/pysmbconf.c new file mode 100644 index 0000000..1b3c101 --- /dev/null +++ b/lib/smbconf/pysmbconf.c @@ -0,0 +1,813 @@ +/* + * Unix SMB/CIFS implementation. + * libsmbconf - Samba configuration library - Python bindings + * + * Copyright (C) John Mulligan <phlogistonjohn@asynchrono.us> 2022 + * + * 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 "includes.h" +#include "python/py3compat.h" + +#include "lib/smbconf/smbconf.h" +#include "lib/smbconf/smbconf_txt.h" +#include "lib/smbconf/pysmbconf.h" + +static PyObject *PyExc_SMBConfError; + +static void py_raise_SMBConfError(sbcErr err) +{ + PyObject *v = NULL; + PyObject *args = NULL; + + /* + * TODO: have the exception type accept arguments in new/init + */ + args = Py_BuildValue("(is)", err, sbcErrorString(err)); + if (args == NULL) { + PyErr_Format(PyExc_SMBConfError, "[%d]: %s", err, + sbcErrorString(err)); + return; + } + v = PyObject_Call(PyExc_SMBConfError, args, NULL); + if (v == NULL) { + Py_CLEAR(args); + return; + } + /* + * It's clearer to set an explicit error_code attribute for use in calling + * code to check what kind of SMBConfError was raised. + */ + if (PyObject_SetAttrString(v, "error_code", PyTuple_GetItem(args, 0)) == -1) { + Py_CLEAR(v); + Py_CLEAR(args); + return; + } + Py_CLEAR(args); + PyErr_SetObject((PyObject *) Py_TYPE(v), v); + Py_DECREF(v); +} + +/* + * py_from_smbconf_service returns a python tuple that is basically equivalent + * to the struct smbconf_service type content-wise. + */ +static PyObject *py_from_smbconf_service(struct smbconf_service *svc) +{ + uint32_t count; + PyObject *plist = PyList_New(svc->num_params); + if (plist == NULL) { + return NULL; + } + + for (count = 0; count < svc->num_params; count++) { + PyObject *pt = Py_BuildValue("(ss)", + svc->param_names[count], + svc->param_values[count]); + if (pt == NULL) { + Py_CLEAR(plist); + return NULL; + } + if (PyList_SetItem(plist, count, pt) < 0) { + Py_CLEAR(pt); + Py_CLEAR(plist); + return NULL; + } + } + return Py_BuildValue("(sO)", svc->name, plist); +} + +static PyObject *obj_new(PyTypeObject * type, PyObject * args, PyObject * kwds) +{ + py_SMBConf_Object *self = (py_SMBConf_Object *) type->tp_alloc(type, 0); + if (self == NULL) { + return NULL; + } + + self->mem_ctx = talloc_new(NULL); + if (self->mem_ctx == NULL) { + Py_DECREF(self); + return NULL; + } + + return (PyObject *) self; +} + +static void obj_dealloc(py_SMBConf_Object * self) +{ + if (self->conf_ctx != NULL) { + smbconf_shutdown(self->conf_ctx); + } + talloc_free(self->mem_ctx); + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static bool obj_ready(py_SMBConf_Object * self) +{ + if (self->conf_ctx == NULL) { + PyErr_Format(PyExc_RuntimeError, + "attempt to use an uninitialized SMBConf object"); + return false; + } + return true; +} + +static PyObject *obj_requires_messaging(py_SMBConf_Object * self, + PyObject * Py_UNUSED(ignored)) +{ + if (!obj_ready(self)) { + return NULL; + } + if (smbconf_backend_requires_messaging(self->conf_ctx)) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + +static PyObject *obj_is_writable(py_SMBConf_Object * self, + PyObject * Py_UNUSED(ignored)) +{ + if (!obj_ready(self)) { + return NULL; + } + if (smbconf_is_writeable(self->conf_ctx)) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + +static PyObject *obj_share_names(py_SMBConf_Object * self, + PyObject * Py_UNUSED(ignored)) +{ + sbcErr err; + uint32_t count; + uint32_t num_shares; + char **share_names = NULL; + PyObject *slist = NULL; + TALLOC_CTX *mem_ctx = NULL; + + if (!obj_ready(self)) { + return NULL; + } + + mem_ctx = talloc_new(self->mem_ctx); + if (mem_ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } + + err = + smbconf_get_share_names(self->conf_ctx, mem_ctx, &num_shares, + &share_names); + if (err != SBC_ERR_OK) { + talloc_free(mem_ctx); + py_raise_SMBConfError(err); + return NULL; + } + + slist = PyList_New(num_shares); + if (slist == NULL) { + talloc_free(mem_ctx); + return NULL; + } + for (count = 0; count < num_shares; count++) { + PyObject *ustr = PyUnicode_FromString(share_names[count]); + if (ustr == NULL) { + Py_CLEAR(slist); + talloc_free(mem_ctx); + return NULL; + } + if (PyList_SetItem(slist, count, ustr) < 0) { + Py_CLEAR(ustr); + Py_CLEAR(slist); + talloc_free(mem_ctx); + return NULL; + } + } + talloc_free(mem_ctx); + return slist; +} + +static PyObject *obj_get_share(py_SMBConf_Object * self, PyObject * args) +{ + sbcErr err; + char *servicename = NULL; + struct smbconf_service *svc = NULL; + PyObject *plist = NULL; + TALLOC_CTX *mem_ctx = NULL; + + if (!PyArg_ParseTuple(args, "s", &servicename)) { + return NULL; + } + + if (!obj_ready(self)) { + return NULL; + } + + mem_ctx = talloc_new(self->mem_ctx); + if (mem_ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } + + err = smbconf_get_share(self->conf_ctx, mem_ctx, servicename, &svc); + if (err != SBC_ERR_OK) { + talloc_free(mem_ctx); + py_raise_SMBConfError(err); + return NULL; + } + /* + * if py_from_smbconf_service returns NULL, then an exception should + * already be set. No special error handling needed. + */ + plist = py_from_smbconf_service(svc); + talloc_free(mem_ctx); + return plist; +} + +static PyObject *obj_get_config(py_SMBConf_Object * self, + PyObject * Py_UNUSED(ignored)) +{ + sbcErr err; + PyObject *svclist = NULL; + TALLOC_CTX *mem_ctx = NULL; + uint32_t count; + uint32_t num_shares; + struct smbconf_service **svcs = NULL; + + if (!obj_ready(self)) { + return NULL; + } + + mem_ctx = talloc_new(self->mem_ctx); + if (mem_ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } + + err = smbconf_get_config(self->conf_ctx, mem_ctx, &num_shares, &svcs); + if (err != SBC_ERR_OK) { + talloc_free(mem_ctx); + py_raise_SMBConfError(err); + return NULL; + } + + svclist = PyList_New(num_shares); + if (svclist == NULL) { + talloc_free(mem_ctx); + return NULL; + } + for (count = 0; count < num_shares; count++) { + PyObject *svcobj = py_from_smbconf_service(svcs[count]); + if (svcobj == NULL) { + Py_CLEAR(svclist); + talloc_free(mem_ctx); + return NULL; + } + if (PyList_SetItem(svclist, count, svcobj) < 0) { + Py_CLEAR(svcobj); + Py_CLEAR(svclist); + talloc_free(mem_ctx); + return NULL; + } + } + + talloc_free(mem_ctx); + return svclist; +} + +static PyObject *obj_create_share(py_SMBConf_Object * self, PyObject * args) +{ + sbcErr err; + char *servicename = NULL; + + if (!PyArg_ParseTuple(args, "s", &servicename)) { + return NULL; + } + + err = smbconf_create_share(self->conf_ctx, servicename); + if (err != SBC_ERR_OK) { + py_raise_SMBConfError(err); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject *obj_drop(py_SMBConf_Object * self, + PyObject * Py_UNUSED(ignored)) +{ + sbcErr err; + + err = smbconf_drop(self->conf_ctx); + if (err != SBC_ERR_OK) { + py_raise_SMBConfError(err); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject *obj_set_parameter(py_SMBConf_Object * self, PyObject * args) +{ + sbcErr err; + char *servicename = NULL; + char *param = NULL; + char *val = NULL; + + if (!PyArg_ParseTuple(args, "sss", &servicename, ¶m, &val)) { + return NULL; + } + + err = smbconf_set_parameter(self->conf_ctx, servicename, param, val); + if (err != SBC_ERR_OK) { + py_raise_SMBConfError(err); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject *obj_set_global_parameter(py_SMBConf_Object * self, + PyObject * args) +{ + sbcErr err; + char *param = NULL; + char *val = NULL; + + if (!PyArg_ParseTuple(args, "ss", ¶m, &val)) { + return NULL; + } + + err = smbconf_set_global_parameter(self->conf_ctx, param, val); + if (err != SBC_ERR_OK) { + py_raise_SMBConfError(err); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject *obj_delete_share(py_SMBConf_Object * self, PyObject * args) +{ + sbcErr err; + char *servicename = NULL; + + if (!PyArg_ParseTuple(args, "s", &servicename)) { + return NULL; + } + + err = smbconf_delete_share(self->conf_ctx, servicename); + if (err != SBC_ERR_OK) { + py_raise_SMBConfError(err); + return NULL; + } + Py_RETURN_NONE; +} + +static char *py_get_kv_str(TALLOC_CTX * mem_ctx, PyObject * obj, Py_ssize_t idx) +{ + char *ss = NULL; + PyObject *pystr = PySequence_GetItem(obj, idx); + if (pystr == NULL) { + return NULL; + } + if (!PyUnicode_Check(pystr)) { + PyErr_SetString(PyExc_TypeError, "keys/values expect a str"); + Py_CLEAR(pystr); + return NULL; + } + ss = talloc_strdup(mem_ctx, PyUnicode_AsUTF8(pystr)); + Py_CLEAR(pystr); + return ss; +} + +static PyObject *obj_create_set_share(py_SMBConf_Object * self, PyObject * args) +{ + sbcErr err; + char *servicename = NULL; + PyObject *kvs = NULL; + Py_ssize_t size, idx; + struct smbconf_service *tmp_service = NULL; + TALLOC_CTX *tmp_ctx = talloc_new(self->mem_ctx); + + if (!PyArg_ParseTuple(args, "sO", &servicename, &kvs)) { + talloc_free(tmp_ctx); + return NULL; + } + + if (PySequence_Check(kvs) == 0) { + PyErr_SetString(PyExc_TypeError, + "a sequence object is required"); + talloc_free(tmp_ctx); + return NULL; + } + + size = PySequence_Size(kvs); + if (size == -1) { + PyErr_SetString(PyExc_ValueError, "failed to get size"); + talloc_free(tmp_ctx); + return NULL; + } + + tmp_service = talloc_zero(tmp_ctx, struct smbconf_service); + if (tmp_service == NULL) { + PyErr_NoMemory(); + talloc_free(tmp_ctx); + return NULL; + } + + tmp_service->name = talloc_strdup(tmp_service, servicename); + if (tmp_service->name == NULL) { + PyErr_NoMemory(); + talloc_free(tmp_ctx); + return NULL; + } + tmp_service->num_params = (uint32_t) size; + tmp_service->param_names = talloc_array(tmp_ctx, char *, size); + if (tmp_service->param_names == NULL) { + PyErr_NoMemory(); + talloc_free(tmp_ctx); + return NULL; + } + tmp_service->param_values = talloc_array(tmp_ctx, char *, size); + if (tmp_service->param_values == NULL) { + PyErr_NoMemory(); + talloc_free(tmp_ctx); + return NULL; + } + + for (idx = 0; idx < size; idx++) { + char *tmp_str = NULL; + PyObject *tmp_pair = PySequence_GetItem(kvs, idx); + if (tmp_pair == NULL) { + talloc_free(tmp_ctx); + return NULL; + } + if (PySequence_Size(tmp_pair) != 2) { + PyErr_SetString(PyExc_ValueError, + "expecting two-item tuples"); + Py_CLEAR(tmp_pair); + talloc_free(tmp_ctx); + return NULL; + } + + /* fetch key */ + tmp_str = py_get_kv_str(tmp_ctx, tmp_pair, 0); + if (tmp_str == NULL) { + Py_CLEAR(tmp_pair); + talloc_free(tmp_ctx); + return NULL; + } + tmp_service->param_names[idx] = tmp_str; + + /* fetch value */ + tmp_str = py_get_kv_str(tmp_ctx, tmp_pair, 1); + if (tmp_str == NULL) { + Py_CLEAR(tmp_pair); + talloc_free(tmp_ctx); + return NULL; + } + tmp_service->param_values[idx] = tmp_str; + + Py_CLEAR(tmp_pair); + } + + err = smbconf_create_set_share(self->conf_ctx, tmp_service); + if (err != SBC_ERR_OK) { + py_raise_SMBConfError(err); + talloc_free(tmp_ctx); + return NULL; + } + talloc_free(tmp_ctx); + Py_RETURN_NONE; +} + +static PyObject *obj_delete_parameter(py_SMBConf_Object * self, PyObject * args) +{ + sbcErr err; + char *servicename = NULL; + char *param_name = NULL; + + if (!PyArg_ParseTuple(args, "ss", &servicename, ¶m_name)) { + return NULL; + } + + err = smbconf_delete_parameter(self->conf_ctx, servicename, param_name); + if (err != SBC_ERR_OK) { + py_raise_SMBConfError(err); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject *obj_delete_global_parameter(py_SMBConf_Object * self, + PyObject * args) +{ + sbcErr err; + char *param_name = NULL; + + if (!PyArg_ParseTuple(args, "s", ¶m_name)) { + return NULL; + } + + err = smbconf_delete_global_parameter(self->conf_ctx, param_name); + if (err != SBC_ERR_OK) { + py_raise_SMBConfError(err); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject *obj_transaction_start(py_SMBConf_Object * self, + PyObject * Py_UNUSED(ignored)) +{ + sbcErr err = smbconf_transaction_start(self->conf_ctx); + if (err != SBC_ERR_OK) { + py_raise_SMBConfError(err); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject *obj_transaction_commit(py_SMBConf_Object * self, + PyObject * Py_UNUSED(ignored)) +{ + sbcErr err = smbconf_transaction_commit(self->conf_ctx); + if (err != SBC_ERR_OK) { + py_raise_SMBConfError(err); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject *obj_transaction_cancel(py_SMBConf_Object * self, + PyObject * Py_UNUSED(ignored)) +{ + sbcErr err = smbconf_transaction_cancel(self->conf_ctx); + if (err != SBC_ERR_OK) { + py_raise_SMBConfError(err); + return NULL; + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(obj_requires_messaging_doc, +"requires_messaging() -> bool\n" +"\n" +"Returns true if the backend requires interprocess messaging.\n"); + +PyDoc_STRVAR(obj_is_writable_doc, +"is_writeable() -> bool\n" +"\n" +"Returns true if the SMBConf object's backend is writable.\n"); + +PyDoc_STRVAR(obj_share_names_doc, +"share_names() -> list[str]\n" +"\n" +"Return a list of the share names currently configured.\n" +"Includes the global section as a share name.\n"); + +PyDoc_STRVAR(obj_get_share_doc, +"get_share() -> (str, list[(str, str)])\n" +"\n" +"Given the name of a share, return a tuple of \n" +"(share_name, share_parms) where share_params is a list of\n" +"(param_name, param_value) tuples.\n" +"The term global can be specified to get global section parameters.\n"); + +PyDoc_STRVAR(obj_get_config_doc, +"get_config() -> list[(str, list[(str, str)])]\n" +"Return a list of tuples for every section/share of the current\n" +"configuration. Each tuple in the list is the same as described\n" +"for get_share().\n"); + +PyDoc_STRVAR(obj_create_share_doc, +"create_share(name: str) -> None\n" +"Create a new empty share in the configuration. The share\n" +"name must not exist or an error will be raised.\n"); + +PyDoc_STRVAR(obj_drop_doc, +"drop() -> None\n" +"Drop the entire configuration, resetting it to an empty state.\n"); + +PyDoc_STRVAR(obj_set_parameter_doc, +"set_parameter(str, str, str) -> None\n" +"Set a configuration parmeter. Specify service name, parameter name,\n" +"and parameter value.\n"); + +PyDoc_STRVAR(obj_set_global_parameter_doc, +"set_global_parameter(str, str) -> None\n" +"Set a global configuration parmeter. Specify the parameter name\n" +"and parameter value.\n"); + +PyDoc_STRVAR(obj_delete_share_doc, +"delete_share(str) -> None\n" +"Delete a service from the configuration.\n"); + +PyDoc_STRVAR(obj_create_set_share_doc, +"create_set_share(str, [(str, str)...]) -> None\n" +"Create and set the definition of a service.\n"); + +PyDoc_STRVAR(obj_delete_parameter_doc, +"delete_parameter(str, str) -> None\n" +"Delete a single configuration parameter.\n"); + +PyDoc_STRVAR(obj_delete_global_parameter_doc, +"delete_parameter(str, str) -> None\n" +"Delete a single global configuration parameter.\n"); + +PyDoc_STRVAR(obj_transaction_start_doc, +"transaction_start() -> None\n" +"Start a transaction.\n" +"Transactions allow making compound sets of changes atomically.\n"); + +PyDoc_STRVAR(obj_transaction_commit_doc, +"transaction_commit() -> None\n" +"Commit the transaction.\n"); + +PyDoc_STRVAR(obj_transaction_cancel_doc, +"transaction_cancel() -> None\n" +"Cancel the transaction.\n"); + +static PyMethodDef py_smbconf_obj_methods[] = { + { "requires_messaging", (PyCFunction) obj_requires_messaging, + METH_NOARGS, obj_requires_messaging_doc }, + { "is_writeable", (PyCFunction) obj_is_writable, METH_NOARGS, + obj_is_writable_doc }, + { "share_names", (PyCFunction) obj_share_names, METH_NOARGS, + obj_share_names_doc }, + { "get_share", (PyCFunction) obj_get_share, METH_VARARGS, + obj_get_share_doc }, + { "get_config", (PyCFunction) obj_get_config, METH_NOARGS, + obj_get_config_doc }, + { "create_share", (PyCFunction) obj_create_share, METH_VARARGS, + obj_create_share_doc }, + { "create_set_share", (PyCFunction) obj_create_set_share, METH_VARARGS, + obj_create_set_share_doc }, + { "drop", (PyCFunction) obj_drop, METH_NOARGS, + obj_drop_doc }, + { "set_parameter", (PyCFunction) obj_set_parameter, METH_VARARGS, + obj_set_parameter_doc }, + { "set_global_parameter", (PyCFunction) obj_set_global_parameter, + METH_VARARGS, obj_set_global_parameter_doc }, + { "delete_share", (PyCFunction) obj_delete_share, METH_VARARGS, + obj_delete_share_doc }, + { "delete_parameter", (PyCFunction) obj_delete_parameter, METH_VARARGS, + obj_delete_parameter_doc }, + { "delete_global_parameter", (PyCFunction) obj_delete_global_parameter, + METH_VARARGS, obj_delete_global_parameter_doc }, + { "transaction_start", (PyCFunction) obj_transaction_start, METH_NOARGS, + obj_transaction_start_doc }, + { "transaction_commit", (PyCFunction) obj_transaction_commit, + METH_NOARGS, obj_transaction_commit_doc }, + { "transaction_cancel", (PyCFunction) obj_transaction_cancel, + METH_NOARGS, obj_transaction_cancel_doc }, + { 0 }, +}; + +PyDoc_STRVAR(py_SMBConf_type_doc, +"SMBConf objects provide uniform access to Samba configuration backends.\n" +"\n" +"The SMBConf type should not be instantiated directly. Rather, use a\n" +"backend specific init function like init_txt.\n"); + +static PyTypeObject py_SMBConf_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "smbconf.SMBConf", + .tp_doc = py_SMBConf_type_doc, + .tp_basicsize = sizeof(py_SMBConf_Object), + .tp_methods = py_smbconf_obj_methods, + .tp_new = obj_new, + .tp_dealloc = (destructor) obj_dealloc, +}; + +static PyObject *py_init_txt(PyObject * module, PyObject * args) +{ + py_SMBConf_Object *obj; + sbcErr err; + char *path = NULL; + struct smbconf_ctx *conf_ctx = NULL; + + if (!PyArg_ParseTuple(args, "s", &path)) { + return NULL; + } + + obj = (py_SMBConf_Object *) obj_new(&py_SMBConf_Type, NULL, NULL); + if (obj == NULL) { + return NULL; + } + + err = smbconf_init_txt(obj->mem_ctx, &conf_ctx, path); + if (err != SBC_ERR_OK) { + Py_DECREF(obj); + py_raise_SMBConfError(err); + return NULL; + } + obj->conf_ctx = conf_ctx; + return (PyObject *) obj; +} + +static PyObject *py_smbconf_error(PyObject * module, PyObject * args) +{ + sbcErr errcode; + + if (!PyArg_ParseTuple(args, "i", &errcode)) { + return NULL; + } + + /* this always raises an exception. it doesn't return the exception. */ + py_raise_SMBConfError(errcode); + return NULL; +} + +static PyMethodDef pysmbconf_methods[] = { + { "init_txt", (PyCFunction) py_init_txt, METH_VARARGS, + "Return an SMBConf object for the given text config file." }, + { "_smbconf_error", (PyCFunction) py_smbconf_error, METH_VARARGS, + "Raise an SMBConfError based on the given error code." }, + { 0 }, +}; + +PyDoc_STRVAR(py_smbconf_doc, +"The smbconf module is a wrapper for Samba's smbconf library.\n" +"This library supports common functions to access the contents\n" +"of a configuration backend, such as the text-based smb.conf file\n" +"or the read-write registry backend.\n" +"The read-only functions on the SMBConf type function on both backend\n" +"types. Future, write based functions need a writable backend (registry).\n" +"\n" +"Note that the registry backend will be provided by a different\n" +"library module from the source3 tree (implemenation TBD).\n"); + +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + .m_name = "smbconf", + .m_doc = py_smbconf_doc, + .m_size = -1, + .m_methods = pysmbconf_methods, +}; + +MODULE_INIT_FUNC(smbconf) +{ + PyObject *m = PyModule_Create(&moduledef); + if (m == NULL) { + return NULL; + } + + if (PyType_Ready(&py_SMBConf_Type) < 0) { + Py_DECREF(m); + return NULL; + } + Py_INCREF(&py_SMBConf_Type); + if (PyModule_AddObject(m, "SMBConf", (PyObject *) & py_SMBConf_Type) < + 0) { + Py_DECREF(&py_SMBConf_Type); + Py_DECREF(m); + return NULL; + } + + PyExc_SMBConfError = + PyErr_NewException(discard_const_p(char, "smbconf.SMBConfError"), + NULL, NULL); + if (PyExc_SMBConfError == NULL) { + Py_DECREF(m); + return NULL; + } + Py_INCREF(PyExc_SMBConfError); + if (PyModule_AddObject(m, "SMBConfError", PyExc_SMBConfError) < 0) { + Py_DECREF(PyExc_SMBConfError); + Py_DECREF(m); + return NULL; + } + +/* + * ADD_FLAGS macro borrowed from source3/libsmb/pylibsmb.c + */ +#define ADD_FLAGS(val) PyModule_AddObject(m, #val, PyLong_FromLong(val)) + + ADD_FLAGS(SBC_ERR_OK); + ADD_FLAGS(SBC_ERR_NOT_IMPLEMENTED); + ADD_FLAGS(SBC_ERR_NOT_SUPPORTED); + ADD_FLAGS(SBC_ERR_UNKNOWN_FAILURE); + ADD_FLAGS(SBC_ERR_NOMEM); + ADD_FLAGS(SBC_ERR_INVALID_PARAM); + ADD_FLAGS(SBC_ERR_BADFILE); + ADD_FLAGS(SBC_ERR_NO_SUCH_SERVICE); + ADD_FLAGS(SBC_ERR_IO_FAILURE); + ADD_FLAGS(SBC_ERR_CAN_NOT_COMPLETE); + ADD_FLAGS(SBC_ERR_NO_MORE_ITEMS); + ADD_FLAGS(SBC_ERR_FILE_EXISTS); + ADD_FLAGS(SBC_ERR_ACCESS_DENIED); + + return m; +} |