s3:utils: let connections_forall_read() report if the session was authenticated
[samba4-gss.git] / lib / smbconf / pysmbconf.c
blob2538127b1baf7a91f33ae64998ebf965068b8a54
1 /*
2 * Unix SMB/CIFS implementation.
3 * libsmbconf - Samba configuration library - Python bindings
5 * Copyright (C) John Mulligan <phlogistonjohn@asynchrono.us> 2022
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "lib/replace/system/python.h"
22 #include "includes.h"
23 #include "python/py3compat.h"
25 #include "lib/smbconf/smbconf.h"
26 #include "lib/smbconf/smbconf_txt.h"
27 #include "lib/smbconf/pysmbconf.h"
29 static PyObject *PyExc_SMBConfError;
31 static void py_raise_SMBConfError(sbcErr err)
33 PyObject *v = NULL;
34 PyObject *args = NULL;
37 * TODO: have the exception type accept arguments in new/init
39 args = Py_BuildValue("(is)", err, sbcErrorString(err));
40 if (args == NULL) {
41 PyErr_Format(PyExc_SMBConfError, "[%d]: %s", err,
42 sbcErrorString(err));
43 return;
45 v = PyObject_Call(PyExc_SMBConfError, args, NULL);
46 if (v == NULL) {
47 Py_CLEAR(args);
48 return;
51 * It's clearer to set an explicit error_code attribute for use in calling
52 * code to check what kind of SMBConfError was raised.
54 if (PyObject_SetAttrString(v, "error_code", PyTuple_GetItem(args, 0)) == -1) {
55 Py_CLEAR(v);
56 Py_CLEAR(args);
57 return;
59 Py_CLEAR(args);
60 PyErr_SetObject((PyObject *) Py_TYPE(v), v);
61 Py_DECREF(v);
65 * py_from_smbconf_service returns a python tuple that is basically equivalent
66 * to the struct smbconf_service type content-wise.
68 static PyObject *py_from_smbconf_service(struct smbconf_service *svc)
70 uint32_t count;
71 PyObject *plist = PyList_New(svc->num_params);
72 if (plist == NULL) {
73 return NULL;
76 for (count = 0; count < svc->num_params; count++) {
77 PyObject *pt = Py_BuildValue("(ss)",
78 svc->param_names[count],
79 svc->param_values[count]);
80 if (pt == NULL) {
81 Py_CLEAR(plist);
82 return NULL;
84 if (PyList_SetItem(plist, count, pt) < 0) {
85 Py_CLEAR(pt);
86 Py_CLEAR(plist);
87 return NULL;
90 return Py_BuildValue("(sO)", svc->name, plist);
93 static PyObject *obj_new(PyTypeObject * type, PyObject * args, PyObject * kwds)
95 py_SMBConf_Object *self = (py_SMBConf_Object *) type->tp_alloc(type, 0);
96 if (self == NULL) {
97 return NULL;
100 self->mem_ctx = talloc_new(NULL);
101 if (self->mem_ctx == NULL) {
102 Py_DECREF(self);
103 return NULL;
106 return (PyObject *) self;
109 static void obj_dealloc(py_SMBConf_Object * self)
111 if (self->conf_ctx != NULL) {
112 smbconf_shutdown(self->conf_ctx);
114 talloc_free(self->mem_ctx);
115 Py_TYPE(self)->tp_free((PyObject *) self);
118 static bool obj_ready(py_SMBConf_Object * self)
120 if (self->conf_ctx == NULL) {
121 PyErr_Format(PyExc_RuntimeError,
122 "attempt to use an uninitialized SMBConf object");
123 return false;
125 return true;
128 static PyObject *obj_requires_messaging(py_SMBConf_Object * self,
129 PyObject * Py_UNUSED(ignored))
131 if (!obj_ready(self)) {
132 return NULL;
134 if (smbconf_backend_requires_messaging(self->conf_ctx)) {
135 Py_RETURN_TRUE;
137 Py_RETURN_FALSE;
140 static PyObject *obj_is_writable(py_SMBConf_Object * self,
141 PyObject * Py_UNUSED(ignored))
143 if (!obj_ready(self)) {
144 return NULL;
146 if (smbconf_is_writeable(self->conf_ctx)) {
147 Py_RETURN_TRUE;
149 Py_RETURN_FALSE;
152 static PyObject *obj_share_names(py_SMBConf_Object * self,
153 PyObject * Py_UNUSED(ignored))
155 sbcErr err;
156 uint32_t count;
157 uint32_t num_shares;
158 char **share_names = NULL;
159 PyObject *slist = NULL;
160 TALLOC_CTX *mem_ctx = NULL;
162 if (!obj_ready(self)) {
163 return NULL;
166 mem_ctx = talloc_new(self->mem_ctx);
167 if (mem_ctx == NULL) {
168 PyErr_NoMemory();
169 return NULL;
172 err =
173 smbconf_get_share_names(self->conf_ctx, mem_ctx, &num_shares,
174 &share_names);
175 if (err != SBC_ERR_OK) {
176 talloc_free(mem_ctx);
177 py_raise_SMBConfError(err);
178 return NULL;
181 slist = PyList_New(num_shares);
182 if (slist == NULL) {
183 talloc_free(mem_ctx);
184 return NULL;
186 for (count = 0; count < num_shares; count++) {
187 PyObject *ustr = PyUnicode_FromString(share_names[count]);
188 if (ustr == NULL) {
189 Py_CLEAR(slist);
190 talloc_free(mem_ctx);
191 return NULL;
193 if (PyList_SetItem(slist, count, ustr) < 0) {
194 Py_CLEAR(ustr);
195 Py_CLEAR(slist);
196 talloc_free(mem_ctx);
197 return NULL;
200 talloc_free(mem_ctx);
201 return slist;
204 static PyObject *obj_get_share(py_SMBConf_Object * self, PyObject * args)
206 sbcErr err;
207 char *servicename = NULL;
208 struct smbconf_service *svc = NULL;
209 PyObject *plist = NULL;
210 TALLOC_CTX *mem_ctx = NULL;
212 if (!PyArg_ParseTuple(args, "s", &servicename)) {
213 return NULL;
216 if (!obj_ready(self)) {
217 return NULL;
220 mem_ctx = talloc_new(self->mem_ctx);
221 if (mem_ctx == NULL) {
222 PyErr_NoMemory();
223 return NULL;
226 err = smbconf_get_share(self->conf_ctx, mem_ctx, servicename, &svc);
227 if (err != SBC_ERR_OK) {
228 talloc_free(mem_ctx);
229 py_raise_SMBConfError(err);
230 return NULL;
233 * if py_from_smbconf_service returns NULL, then an exception should
234 * already be set. No special error handling needed.
236 plist = py_from_smbconf_service(svc);
237 talloc_free(mem_ctx);
238 return plist;
241 static PyObject *obj_get_config(py_SMBConf_Object * self,
242 PyObject * Py_UNUSED(ignored))
244 sbcErr err;
245 PyObject *svclist = NULL;
246 TALLOC_CTX *mem_ctx = NULL;
247 uint32_t count;
248 uint32_t num_shares;
249 struct smbconf_service **svcs = NULL;
251 if (!obj_ready(self)) {
252 return NULL;
255 mem_ctx = talloc_new(self->mem_ctx);
256 if (mem_ctx == NULL) {
257 PyErr_NoMemory();
258 return NULL;
261 err = smbconf_get_config(self->conf_ctx, mem_ctx, &num_shares, &svcs);
262 if (err != SBC_ERR_OK) {
263 talloc_free(mem_ctx);
264 py_raise_SMBConfError(err);
265 return NULL;
268 svclist = PyList_New(num_shares);
269 if (svclist == NULL) {
270 talloc_free(mem_ctx);
271 return NULL;
273 for (count = 0; count < num_shares; count++) {
274 PyObject *svcobj = py_from_smbconf_service(svcs[count]);
275 if (svcobj == NULL) {
276 Py_CLEAR(svclist);
277 talloc_free(mem_ctx);
278 return NULL;
280 if (PyList_SetItem(svclist, count, svcobj) < 0) {
281 Py_CLEAR(svcobj);
282 Py_CLEAR(svclist);
283 talloc_free(mem_ctx);
284 return NULL;
288 talloc_free(mem_ctx);
289 return svclist;
292 static PyObject *obj_create_share(py_SMBConf_Object * self, PyObject * args)
294 sbcErr err;
295 char *servicename = NULL;
297 if (!PyArg_ParseTuple(args, "s", &servicename)) {
298 return NULL;
301 err = smbconf_create_share(self->conf_ctx, servicename);
302 if (err != SBC_ERR_OK) {
303 py_raise_SMBConfError(err);
304 return NULL;
306 Py_RETURN_NONE;
309 static PyObject *obj_drop(py_SMBConf_Object * self,
310 PyObject * Py_UNUSED(ignored))
312 sbcErr err;
314 err = smbconf_drop(self->conf_ctx);
315 if (err != SBC_ERR_OK) {
316 py_raise_SMBConfError(err);
317 return NULL;
319 Py_RETURN_NONE;
322 static PyObject *obj_set_parameter(py_SMBConf_Object * self, PyObject * args)
324 sbcErr err;
325 char *servicename = NULL;
326 char *param = NULL;
327 char *val = NULL;
329 if (!PyArg_ParseTuple(args, "sss", &servicename, &param, &val)) {
330 return NULL;
333 err = smbconf_set_parameter(self->conf_ctx, servicename, param, val);
334 if (err != SBC_ERR_OK) {
335 py_raise_SMBConfError(err);
336 return NULL;
338 Py_RETURN_NONE;
341 static PyObject *obj_set_global_parameter(py_SMBConf_Object * self,
342 PyObject * args)
344 sbcErr err;
345 char *param = NULL;
346 char *val = NULL;
348 if (!PyArg_ParseTuple(args, "ss", &param, &val)) {
349 return NULL;
352 err = smbconf_set_global_parameter(self->conf_ctx, param, val);
353 if (err != SBC_ERR_OK) {
354 py_raise_SMBConfError(err);
355 return NULL;
357 Py_RETURN_NONE;
360 static PyObject *obj_delete_share(py_SMBConf_Object * self, PyObject * args)
362 sbcErr err;
363 char *servicename = NULL;
365 if (!PyArg_ParseTuple(args, "s", &servicename)) {
366 return NULL;
369 err = smbconf_delete_share(self->conf_ctx, servicename);
370 if (err != SBC_ERR_OK) {
371 py_raise_SMBConfError(err);
372 return NULL;
374 Py_RETURN_NONE;
377 static char *py_get_kv_str(TALLOC_CTX * mem_ctx, PyObject * obj, Py_ssize_t idx)
379 char *ss = NULL;
380 PyObject *pystr = PySequence_GetItem(obj, idx);
381 if (pystr == NULL) {
382 return NULL;
384 if (!PyUnicode_Check(pystr)) {
385 PyErr_SetString(PyExc_TypeError, "keys/values expect a str");
386 Py_CLEAR(pystr);
387 return NULL;
389 ss = talloc_strdup(mem_ctx, PyUnicode_AsUTF8(pystr));
390 Py_CLEAR(pystr);
391 return ss;
394 static PyObject *obj_create_set_share(py_SMBConf_Object * self, PyObject * args)
396 sbcErr err;
397 char *servicename = NULL;
398 PyObject *kvs = NULL;
399 Py_ssize_t size, idx;
400 struct smbconf_service *tmp_service = NULL;
401 TALLOC_CTX *tmp_ctx = talloc_new(self->mem_ctx);
403 if (!PyArg_ParseTuple(args, "sO", &servicename, &kvs)) {
404 talloc_free(tmp_ctx);
405 return NULL;
408 if (PySequence_Check(kvs) == 0) {
409 PyErr_SetString(PyExc_TypeError,
410 "a sequence object is required");
411 talloc_free(tmp_ctx);
412 return NULL;
415 size = PySequence_Size(kvs);
416 if (size == -1) {
417 PyErr_SetString(PyExc_ValueError, "failed to get size");
418 talloc_free(tmp_ctx);
419 return NULL;
422 tmp_service = talloc_zero(tmp_ctx, struct smbconf_service);
423 if (tmp_service == NULL) {
424 PyErr_NoMemory();
425 talloc_free(tmp_ctx);
426 return NULL;
429 tmp_service->name = talloc_strdup(tmp_service, servicename);
430 if (tmp_service->name == NULL) {
431 PyErr_NoMemory();
432 talloc_free(tmp_ctx);
433 return NULL;
435 tmp_service->num_params = (uint32_t) size;
436 tmp_service->param_names = talloc_array(tmp_ctx, char *, size);
437 if (tmp_service->param_names == NULL) {
438 PyErr_NoMemory();
439 talloc_free(tmp_ctx);
440 return NULL;
442 tmp_service->param_values = talloc_array(tmp_ctx, char *, size);
443 if (tmp_service->param_values == NULL) {
444 PyErr_NoMemory();
445 talloc_free(tmp_ctx);
446 return NULL;
449 for (idx = 0; idx < size; idx++) {
450 char *tmp_str = NULL;
451 PyObject *tmp_pair = PySequence_GetItem(kvs, idx);
452 if (tmp_pair == NULL) {
453 talloc_free(tmp_ctx);
454 return NULL;
456 if (PySequence_Size(tmp_pair) != 2) {
457 PyErr_SetString(PyExc_ValueError,
458 "expecting two-item tuples");
459 Py_CLEAR(tmp_pair);
460 talloc_free(tmp_ctx);
461 return NULL;
464 /* fetch key */
465 tmp_str = py_get_kv_str(tmp_ctx, tmp_pair, 0);
466 if (tmp_str == NULL) {
467 Py_CLEAR(tmp_pair);
468 talloc_free(tmp_ctx);
469 return NULL;
471 tmp_service->param_names[idx] = tmp_str;
473 /* fetch value */
474 tmp_str = py_get_kv_str(tmp_ctx, tmp_pair, 1);
475 if (tmp_str == NULL) {
476 Py_CLEAR(tmp_pair);
477 talloc_free(tmp_ctx);
478 return NULL;
480 tmp_service->param_values[idx] = tmp_str;
482 Py_CLEAR(tmp_pair);
485 err = smbconf_create_set_share(self->conf_ctx, tmp_service);
486 if (err != SBC_ERR_OK) {
487 py_raise_SMBConfError(err);
488 talloc_free(tmp_ctx);
489 return NULL;
491 talloc_free(tmp_ctx);
492 Py_RETURN_NONE;
495 static PyObject *obj_delete_parameter(py_SMBConf_Object * self, PyObject * args)
497 sbcErr err;
498 char *servicename = NULL;
499 char *param_name = NULL;
501 if (!PyArg_ParseTuple(args, "ss", &servicename, &param_name)) {
502 return NULL;
505 err = smbconf_delete_parameter(self->conf_ctx, servicename, param_name);
506 if (err != SBC_ERR_OK) {
507 py_raise_SMBConfError(err);
508 return NULL;
510 Py_RETURN_NONE;
513 static PyObject *obj_delete_global_parameter(py_SMBConf_Object * self,
514 PyObject * args)
516 sbcErr err;
517 char *param_name = NULL;
519 if (!PyArg_ParseTuple(args, "s", &param_name)) {
520 return NULL;
523 err = smbconf_delete_global_parameter(self->conf_ctx, param_name);
524 if (err != SBC_ERR_OK) {
525 py_raise_SMBConfError(err);
526 return NULL;
528 Py_RETURN_NONE;
531 static PyObject *obj_transaction_start(py_SMBConf_Object * self,
532 PyObject * Py_UNUSED(ignored))
534 sbcErr err = smbconf_transaction_start(self->conf_ctx);
535 if (err != SBC_ERR_OK) {
536 py_raise_SMBConfError(err);
537 return NULL;
539 Py_RETURN_NONE;
542 static PyObject *obj_transaction_commit(py_SMBConf_Object * self,
543 PyObject * Py_UNUSED(ignored))
545 sbcErr err = smbconf_transaction_commit(self->conf_ctx);
546 if (err != SBC_ERR_OK) {
547 py_raise_SMBConfError(err);
548 return NULL;
550 Py_RETURN_NONE;
553 static PyObject *obj_transaction_cancel(py_SMBConf_Object * self,
554 PyObject * Py_UNUSED(ignored))
556 sbcErr err = smbconf_transaction_cancel(self->conf_ctx);
557 if (err != SBC_ERR_OK) {
558 py_raise_SMBConfError(err);
559 return NULL;
561 Py_RETURN_NONE;
564 PyDoc_STRVAR(obj_requires_messaging_doc,
565 "requires_messaging() -> bool\n"
566 "\n"
567 "Returns true if the backend requires interprocess messaging.\n");
569 PyDoc_STRVAR(obj_is_writable_doc,
570 "is_writeable() -> bool\n"
571 "\n"
572 "Returns true if the SMBConf object's backend is writable.\n");
574 PyDoc_STRVAR(obj_share_names_doc,
575 "share_names() -> list[str]\n"
576 "\n"
577 "Return a list of the share names currently configured.\n"
578 "Includes the global section as a share name.\n");
580 PyDoc_STRVAR(obj_get_share_doc,
581 "get_share() -> (str, list[(str, str)])\n"
582 "\n"
583 "Given the name of a share, return a tuple of \n"
584 "(share_name, share_parms) where share_params is a list of\n"
585 "(param_name, param_value) tuples.\n"
586 "The term global can be specified to get global section parameters.\n");
588 PyDoc_STRVAR(obj_get_config_doc,
589 "get_config() -> list[(str, list[(str, str)])]\n"
590 "Return a list of tuples for every section/share of the current\n"
591 "configuration. Each tuple in the list is the same as described\n"
592 "for get_share().\n");
594 PyDoc_STRVAR(obj_create_share_doc,
595 "create_share(name: str) -> None\n"
596 "Create a new empty share in the configuration. The share\n"
597 "name must not exist or an error will be raised.\n");
599 PyDoc_STRVAR(obj_drop_doc,
600 "drop() -> None\n"
601 "Drop the entire configuration, resetting it to an empty state.\n");
603 PyDoc_STRVAR(obj_set_parameter_doc,
604 "set_parameter(str, str, str) -> None\n"
605 "Set a configuration parameter. Specify service name, parameter name,\n"
606 "and parameter value.\n");
608 PyDoc_STRVAR(obj_set_global_parameter_doc,
609 "set_global_parameter(str, str) -> None\n"
610 "Set a global configuration parameter. Specify the parameter name\n"
611 "and parameter value.\n");
613 PyDoc_STRVAR(obj_delete_share_doc,
614 "delete_share(str) -> None\n"
615 "Delete a service from the configuration.\n");
617 PyDoc_STRVAR(obj_create_set_share_doc,
618 "create_set_share(str, [(str, str)...]) -> None\n"
619 "Create and set the definition of a service.\n");
621 PyDoc_STRVAR(obj_delete_parameter_doc,
622 "delete_parameter(str, str) -> None\n"
623 "Delete a single configuration parameter.\n");
625 PyDoc_STRVAR(obj_delete_global_parameter_doc,
626 "delete_parameter(str, str) -> None\n"
627 "Delete a single global configuration parameter.\n");
629 PyDoc_STRVAR(obj_transaction_start_doc,
630 "transaction_start() -> None\n"
631 "Start a transaction.\n"
632 "Transactions allow making compound sets of changes atomically.\n");
634 PyDoc_STRVAR(obj_transaction_commit_doc,
635 "transaction_commit() -> None\n"
636 "Commit the transaction.\n");
638 PyDoc_STRVAR(obj_transaction_cancel_doc,
639 "transaction_cancel() -> None\n"
640 "Cancel the transaction.\n");
642 static PyMethodDef py_smbconf_obj_methods[] = {
643 { "requires_messaging", (PyCFunction) obj_requires_messaging,
644 METH_NOARGS, obj_requires_messaging_doc },
645 { "is_writeable", (PyCFunction) obj_is_writable, METH_NOARGS,
646 obj_is_writable_doc },
647 { "share_names", (PyCFunction) obj_share_names, METH_NOARGS,
648 obj_share_names_doc },
649 { "get_share", (PyCFunction) obj_get_share, METH_VARARGS,
650 obj_get_share_doc },
651 { "get_config", (PyCFunction) obj_get_config, METH_NOARGS,
652 obj_get_config_doc },
653 { "create_share", (PyCFunction) obj_create_share, METH_VARARGS,
654 obj_create_share_doc },
655 { "create_set_share", (PyCFunction) obj_create_set_share, METH_VARARGS,
656 obj_create_set_share_doc },
657 { "drop", (PyCFunction) obj_drop, METH_NOARGS,
658 obj_drop_doc },
659 { "set_parameter", (PyCFunction) obj_set_parameter, METH_VARARGS,
660 obj_set_parameter_doc },
661 { "set_global_parameter", (PyCFunction) obj_set_global_parameter,
662 METH_VARARGS, obj_set_global_parameter_doc },
663 { "delete_share", (PyCFunction) obj_delete_share, METH_VARARGS,
664 obj_delete_share_doc },
665 { "delete_parameter", (PyCFunction) obj_delete_parameter, METH_VARARGS,
666 obj_delete_parameter_doc },
667 { "delete_global_parameter", (PyCFunction) obj_delete_global_parameter,
668 METH_VARARGS, obj_delete_global_parameter_doc },
669 { "transaction_start", (PyCFunction) obj_transaction_start, METH_NOARGS,
670 obj_transaction_start_doc },
671 { "transaction_commit", (PyCFunction) obj_transaction_commit,
672 METH_NOARGS, obj_transaction_commit_doc },
673 { "transaction_cancel", (PyCFunction) obj_transaction_cancel,
674 METH_NOARGS, obj_transaction_cancel_doc },
675 { 0 },
678 PyDoc_STRVAR(py_SMBConf_type_doc,
679 "SMBConf objects provide uniform access to Samba configuration backends.\n"
680 "\n"
681 "The SMBConf type should not be instantiated directly. Rather, use a\n"
682 "backend specific init function like init_txt.\n");
684 static PyTypeObject py_SMBConf_Type = {
685 PyVarObject_HEAD_INIT(NULL, 0)
686 .tp_name = "smbconf.SMBConf",
687 .tp_doc = py_SMBConf_type_doc,
688 .tp_basicsize = sizeof(py_SMBConf_Object),
689 .tp_methods = py_smbconf_obj_methods,
690 .tp_new = obj_new,
691 .tp_dealloc = (destructor) obj_dealloc,
694 static PyObject *py_init_txt(PyObject * module, PyObject * args)
696 py_SMBConf_Object *obj;
697 sbcErr err;
698 char *path = NULL;
699 struct smbconf_ctx *conf_ctx = NULL;
701 if (!PyArg_ParseTuple(args, "s", &path)) {
702 return NULL;
705 obj = (py_SMBConf_Object *) obj_new(&py_SMBConf_Type, NULL, NULL);
706 if (obj == NULL) {
707 return NULL;
710 err = smbconf_init_txt(obj->mem_ctx, &conf_ctx, path);
711 if (err != SBC_ERR_OK) {
712 Py_DECREF(obj);
713 py_raise_SMBConfError(err);
714 return NULL;
716 obj->conf_ctx = conf_ctx;
717 return (PyObject *) obj;
720 static PyObject *py_smbconf_error(PyObject * module, PyObject * args)
722 sbcErr errcode;
724 if (!PyArg_ParseTuple(args, "i", &errcode)) {
725 return NULL;
728 /* this always raises an exception. it doesn't return the exception. */
729 py_raise_SMBConfError(errcode);
730 return NULL;
733 static PyMethodDef pysmbconf_methods[] = {
734 { "init_txt", (PyCFunction) py_init_txt, METH_VARARGS,
735 "Return an SMBConf object for the given text config file." },
736 { "_smbconf_error", (PyCFunction) py_smbconf_error, METH_VARARGS,
737 "Raise an SMBConfError based on the given error code." },
738 { 0 },
741 PyDoc_STRVAR(py_smbconf_doc,
742 "The smbconf module is a wrapper for Samba's smbconf library.\n"
743 "This library supports common functions to access the contents\n"
744 "of a configuration backend, such as the text-based smb.conf file\n"
745 "or the read-write registry backend.\n"
746 "The read-only functions on the SMBConf type function on both backend\n"
747 "types. Future, write based functions need a writable backend (registry).\n"
748 "\n"
749 "Note that the registry backend will be provided by a different\n"
750 "library module from the source3 tree (implementation TBD).\n");
752 static struct PyModuleDef moduledef = {
753 PyModuleDef_HEAD_INIT,
754 .m_name = "smbconf",
755 .m_doc = py_smbconf_doc,
756 .m_size = -1,
757 .m_methods = pysmbconf_methods,
760 MODULE_INIT_FUNC(smbconf)
762 PyObject *m = PyModule_Create(&moduledef);
763 if (m == NULL) {
764 return NULL;
767 if (PyType_Ready(&py_SMBConf_Type) < 0) {
768 Py_DECREF(m);
769 return NULL;
771 Py_INCREF(&py_SMBConf_Type);
772 if (PyModule_AddObject(m, "SMBConf", (PyObject *) & py_SMBConf_Type) <
773 0) {
774 Py_DECREF(&py_SMBConf_Type);
775 Py_DECREF(m);
776 return NULL;
779 PyExc_SMBConfError =
780 PyErr_NewException(discard_const_p(char, "smbconf.SMBConfError"),
781 NULL, NULL);
782 if (PyExc_SMBConfError == NULL) {
783 Py_DECREF(m);
784 return NULL;
786 Py_INCREF(PyExc_SMBConfError);
787 if (PyModule_AddObject(m, "SMBConfError", PyExc_SMBConfError) < 0) {
788 Py_DECREF(PyExc_SMBConfError);
789 Py_DECREF(m);
790 return NULL;
794 * ADD_FLAGS macro borrowed from source3/libsmb/pylibsmb.c
796 #define ADD_FLAGS(val) PyModule_AddObject(m, #val, PyLong_FromLong(val))
798 ADD_FLAGS(SBC_ERR_OK);
799 ADD_FLAGS(SBC_ERR_NOT_IMPLEMENTED);
800 ADD_FLAGS(SBC_ERR_NOT_SUPPORTED);
801 ADD_FLAGS(SBC_ERR_UNKNOWN_FAILURE);
802 ADD_FLAGS(SBC_ERR_NOMEM);
803 ADD_FLAGS(SBC_ERR_INVALID_PARAM);
804 ADD_FLAGS(SBC_ERR_BADFILE);
805 ADD_FLAGS(SBC_ERR_NO_SUCH_SERVICE);
806 ADD_FLAGS(SBC_ERR_IO_FAILURE);
807 ADD_FLAGS(SBC_ERR_CAN_NOT_COMPLETE);
808 ADD_FLAGS(SBC_ERR_NO_MORE_ITEMS);
809 ADD_FLAGS(SBC_ERR_FILE_EXISTS);
810 ADD_FLAGS(SBC_ERR_ACCESS_DENIED);
812 return m;