Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * libsmbconf - Samba configuration library - Python bindings
4 : *
5 : * Copyright (C) John Mulligan <phlogistonjohn@asynchrono.us> 2022
6 : *
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.
11 : *
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.
16 : *
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/>.
19 : */
20 :
21 : #include "lib/replace/system/python.h"
22 : #include "includes.h"
23 : #include "python/py3compat.h"
24 :
25 : #include "lib/smbconf/smbconf.h"
26 : #include "lib/smbconf/smbconf_txt.h"
27 : #include "lib/smbconf/pysmbconf.h"
28 :
29 : static PyObject *PyExc_SMBConfError;
30 :
31 6 : static void py_raise_SMBConfError(sbcErr err)
32 : {
33 6 : PyObject *v = NULL;
34 6 : PyObject *args = NULL;
35 :
36 : /*
37 : * TODO: have the exception type accept arguments in new/init
38 : */
39 6 : args = Py_BuildValue("(is)", err, sbcErrorString(err));
40 6 : if (args == NULL) {
41 0 : PyErr_Format(PyExc_SMBConfError, "[%d]: %s", err,
42 : sbcErrorString(err));
43 0 : return;
44 : }
45 6 : v = PyObject_Call(PyExc_SMBConfError, args, NULL);
46 6 : if (v == NULL) {
47 0 : Py_CLEAR(args);
48 0 : return;
49 : }
50 : /*
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.
53 : */
54 6 : if (PyObject_SetAttrString(v, "error_code", PyTuple_GetItem(args, 0)) == -1) {
55 0 : Py_CLEAR(v);
56 0 : Py_CLEAR(args);
57 0 : return;
58 : }
59 6 : Py_CLEAR(args);
60 6 : PyErr_SetObject((PyObject *) Py_TYPE(v), v);
61 6 : Py_DECREF(v);
62 : }
63 :
64 : /*
65 : * py_from_smbconf_service returns a python tuple that is basically equivalent
66 : * to the struct smbconf_service type content-wise.
67 : */
68 16 : static PyObject *py_from_smbconf_service(struct smbconf_service *svc)
69 : {
70 16 : uint32_t count;
71 16 : PyObject *plist = PyList_New(svc->num_params);
72 16 : if (plist == NULL) {
73 : return NULL;
74 : }
75 :
76 55 : for (count = 0; count < svc->num_params; count++) {
77 78 : PyObject *pt = Py_BuildValue("(ss)",
78 39 : svc->param_names[count],
79 39 : svc->param_values[count]);
80 39 : if (pt == NULL) {
81 0 : Py_CLEAR(plist);
82 0 : return NULL;
83 : }
84 39 : if (PyList_SetItem(plist, count, pt) < 0) {
85 0 : Py_CLEAR(pt);
86 0 : Py_CLEAR(plist);
87 0 : return NULL;
88 : }
89 : }
90 16 : return Py_BuildValue("(sO)", svc->name, plist);
91 : }
92 :
93 22 : static PyObject *obj_new(PyTypeObject * type, PyObject * args, PyObject * kwds)
94 : {
95 22 : py_SMBConf_Object *self = (py_SMBConf_Object *) type->tp_alloc(type, 0);
96 22 : if (self == NULL) {
97 : return NULL;
98 : }
99 :
100 22 : self->mem_ctx = talloc_new(NULL);
101 22 : if (self->mem_ctx == NULL) {
102 0 : Py_DECREF(self);
103 0 : return NULL;
104 : }
105 :
106 : return (PyObject *) self;
107 : }
108 :
109 22 : static void obj_dealloc(py_SMBConf_Object * self)
110 : {
111 22 : if (self->conf_ctx != NULL) {
112 20 : smbconf_shutdown(self->conf_ctx);
113 : }
114 22 : talloc_free(self->mem_ctx);
115 22 : Py_TYPE(self)->tp_free((PyObject *) self);
116 22 : }
117 :
118 28 : static bool obj_ready(py_SMBConf_Object * self)
119 : {
120 28 : if (self->conf_ctx == NULL) {
121 4 : PyErr_Format(PyExc_RuntimeError,
122 : "attempt to use an uninitialized SMBConf object");
123 4 : return false;
124 : }
125 : return true;
126 : }
127 :
128 2 : static PyObject *obj_requires_messaging(py_SMBConf_Object * self,
129 : PyObject * Py_UNUSED(ignored))
130 : {
131 2 : if (!obj_ready(self)) {
132 1 : return NULL;
133 : }
134 1 : if (smbconf_backend_requires_messaging(self->conf_ctx)) {
135 0 : Py_RETURN_TRUE;
136 : }
137 1 : Py_RETURN_FALSE;
138 : }
139 :
140 5 : static PyObject *obj_is_writable(py_SMBConf_Object * self,
141 : PyObject * Py_UNUSED(ignored))
142 : {
143 5 : if (!obj_ready(self)) {
144 1 : return NULL;
145 : }
146 4 : if (smbconf_is_writeable(self->conf_ctx)) {
147 2 : Py_RETURN_TRUE;
148 : }
149 2 : Py_RETURN_FALSE;
150 : }
151 :
152 7 : static PyObject *obj_share_names(py_SMBConf_Object * self,
153 : PyObject * Py_UNUSED(ignored))
154 : {
155 7 : sbcErr err;
156 7 : uint32_t count;
157 7 : uint32_t num_shares;
158 7 : char **share_names = NULL;
159 7 : PyObject *slist = NULL;
160 7 : TALLOC_CTX *mem_ctx = NULL;
161 :
162 7 : if (!obj_ready(self)) {
163 1 : return NULL;
164 : }
165 :
166 6 : mem_ctx = talloc_new(self->mem_ctx);
167 6 : if (mem_ctx == NULL) {
168 0 : PyErr_NoMemory();
169 0 : return NULL;
170 : }
171 :
172 6 : err =
173 6 : smbconf_get_share_names(self->conf_ctx, mem_ctx, &num_shares,
174 : &share_names);
175 6 : if (err != SBC_ERR_OK) {
176 0 : talloc_free(mem_ctx);
177 0 : py_raise_SMBConfError(err);
178 0 : return NULL;
179 : }
180 :
181 6 : slist = PyList_New(num_shares);
182 6 : if (slist == NULL) {
183 0 : talloc_free(mem_ctx);
184 0 : return NULL;
185 : }
186 18 : for (count = 0; count < num_shares; count++) {
187 12 : PyObject *ustr = PyUnicode_FromString(share_names[count]);
188 12 : if (ustr == NULL) {
189 0 : Py_CLEAR(slist);
190 0 : talloc_free(mem_ctx);
191 0 : return NULL;
192 : }
193 12 : if (PyList_SetItem(slist, count, ustr) < 0) {
194 0 : Py_CLEAR(ustr);
195 0 : Py_CLEAR(slist);
196 0 : talloc_free(mem_ctx);
197 0 : return NULL;
198 : }
199 : }
200 6 : talloc_free(mem_ctx);
201 6 : return slist;
202 : }
203 :
204 13 : static PyObject *obj_get_share(py_SMBConf_Object * self, PyObject * args)
205 : {
206 13 : sbcErr err;
207 13 : char *servicename = NULL;
208 13 : struct smbconf_service *svc = NULL;
209 13 : PyObject *plist = NULL;
210 13 : TALLOC_CTX *mem_ctx = NULL;
211 :
212 13 : if (!PyArg_ParseTuple(args, "s", &servicename)) {
213 : return NULL;
214 : }
215 :
216 13 : if (!obj_ready(self)) {
217 1 : return NULL;
218 : }
219 :
220 12 : mem_ctx = talloc_new(self->mem_ctx);
221 12 : if (mem_ctx == NULL) {
222 0 : PyErr_NoMemory();
223 0 : return NULL;
224 : }
225 :
226 12 : err = smbconf_get_share(self->conf_ctx, mem_ctx, servicename, &svc);
227 12 : if (err != SBC_ERR_OK) {
228 1 : talloc_free(mem_ctx);
229 1 : py_raise_SMBConfError(err);
230 1 : return NULL;
231 : }
232 : /*
233 : * if py_from_smbconf_service returns NULL, then an exception should
234 : * already be set. No special error handling needed.
235 : */
236 11 : plist = py_from_smbconf_service(svc);
237 11 : talloc_free(mem_ctx);
238 11 : return plist;
239 : }
240 :
241 1 : static PyObject *obj_get_config(py_SMBConf_Object * self,
242 : PyObject * Py_UNUSED(ignored))
243 : {
244 1 : sbcErr err;
245 1 : PyObject *svclist = NULL;
246 1 : TALLOC_CTX *mem_ctx = NULL;
247 1 : uint32_t count;
248 1 : uint32_t num_shares;
249 1 : struct smbconf_service **svcs = NULL;
250 :
251 1 : if (!obj_ready(self)) {
252 0 : return NULL;
253 : }
254 :
255 1 : mem_ctx = talloc_new(self->mem_ctx);
256 1 : if (mem_ctx == NULL) {
257 0 : PyErr_NoMemory();
258 0 : return NULL;
259 : }
260 :
261 1 : err = smbconf_get_config(self->conf_ctx, mem_ctx, &num_shares, &svcs);
262 1 : if (err != SBC_ERR_OK) {
263 0 : talloc_free(mem_ctx);
264 0 : py_raise_SMBConfError(err);
265 0 : return NULL;
266 : }
267 :
268 1 : svclist = PyList_New(num_shares);
269 1 : if (svclist == NULL) {
270 0 : talloc_free(mem_ctx);
271 0 : return NULL;
272 : }
273 6 : for (count = 0; count < num_shares; count++) {
274 5 : PyObject *svcobj = py_from_smbconf_service(svcs[count]);
275 5 : if (svcobj == NULL) {
276 0 : Py_CLEAR(svclist);
277 0 : talloc_free(mem_ctx);
278 0 : return NULL;
279 : }
280 5 : if (PyList_SetItem(svclist, count, svcobj) < 0) {
281 0 : Py_CLEAR(svcobj);
282 0 : Py_CLEAR(svclist);
283 0 : talloc_free(mem_ctx);
284 0 : return NULL;
285 : }
286 : }
287 :
288 1 : talloc_free(mem_ctx);
289 1 : return svclist;
290 : }
291 :
292 7 : static PyObject *obj_create_share(py_SMBConf_Object * self, PyObject * args)
293 : {
294 7 : sbcErr err;
295 7 : char *servicename = NULL;
296 :
297 7 : if (!PyArg_ParseTuple(args, "s", &servicename)) {
298 : return NULL;
299 : }
300 :
301 7 : err = smbconf_create_share(self->conf_ctx, servicename);
302 7 : if (err != SBC_ERR_OK) {
303 1 : py_raise_SMBConfError(err);
304 1 : return NULL;
305 : }
306 6 : Py_RETURN_NONE;
307 : }
308 :
309 11 : static PyObject *obj_drop(py_SMBConf_Object * self,
310 : PyObject * Py_UNUSED(ignored))
311 : {
312 11 : sbcErr err;
313 :
314 11 : err = smbconf_drop(self->conf_ctx);
315 11 : if (err != SBC_ERR_OK) {
316 0 : py_raise_SMBConfError(err);
317 0 : return NULL;
318 : }
319 11 : Py_RETURN_NONE;
320 : }
321 :
322 2 : static PyObject *obj_set_parameter(py_SMBConf_Object * self, PyObject * args)
323 : {
324 2 : sbcErr err;
325 2 : char *servicename = NULL;
326 2 : char *param = NULL;
327 2 : char *val = NULL;
328 :
329 2 : if (!PyArg_ParseTuple(args, "sss", &servicename, ¶m, &val)) {
330 : return NULL;
331 : }
332 :
333 2 : err = smbconf_set_parameter(self->conf_ctx, servicename, param, val);
334 2 : if (err != SBC_ERR_OK) {
335 0 : py_raise_SMBConfError(err);
336 0 : return NULL;
337 : }
338 2 : Py_RETURN_NONE;
339 : }
340 :
341 11 : static PyObject *obj_set_global_parameter(py_SMBConf_Object * self,
342 : PyObject * args)
343 : {
344 11 : sbcErr err;
345 11 : char *param = NULL;
346 11 : char *val = NULL;
347 :
348 11 : if (!PyArg_ParseTuple(args, "ss", ¶m, &val)) {
349 : return NULL;
350 : }
351 :
352 11 : err = smbconf_set_global_parameter(self->conf_ctx, param, val);
353 11 : if (err != SBC_ERR_OK) {
354 1 : py_raise_SMBConfError(err);
355 1 : return NULL;
356 : }
357 10 : Py_RETURN_NONE;
358 : }
359 :
360 1 : static PyObject *obj_delete_share(py_SMBConf_Object * self, PyObject * args)
361 : {
362 1 : sbcErr err;
363 1 : char *servicename = NULL;
364 :
365 1 : if (!PyArg_ParseTuple(args, "s", &servicename)) {
366 : return NULL;
367 : }
368 :
369 1 : err = smbconf_delete_share(self->conf_ctx, servicename);
370 1 : if (err != SBC_ERR_OK) {
371 0 : py_raise_SMBConfError(err);
372 0 : return NULL;
373 : }
374 1 : Py_RETURN_NONE;
375 : }
376 :
377 28 : static char *py_get_kv_str(TALLOC_CTX * mem_ctx, PyObject * obj, Py_ssize_t idx)
378 : {
379 28 : char *ss = NULL;
380 28 : PyObject *pystr = PySequence_GetItem(obj, idx);
381 28 : if (pystr == NULL) {
382 : return NULL;
383 : }
384 28 : if (!PyUnicode_Check(pystr)) {
385 1 : PyErr_SetString(PyExc_TypeError, "keys/values expect a str");
386 1 : Py_CLEAR(pystr);
387 1 : return NULL;
388 : }
389 27 : ss = talloc_strdup(mem_ctx, PyUnicode_AsUTF8(pystr));
390 27 : Py_CLEAR(pystr);
391 : return ss;
392 : }
393 :
394 11 : static PyObject *obj_create_set_share(py_SMBConf_Object * self, PyObject * args)
395 : {
396 11 : sbcErr err;
397 11 : char *servicename = NULL;
398 11 : PyObject *kvs = NULL;
399 11 : Py_ssize_t size, idx;
400 11 : struct smbconf_service *tmp_service = NULL;
401 11 : TALLOC_CTX *tmp_ctx = talloc_new(self->mem_ctx);
402 :
403 11 : if (!PyArg_ParseTuple(args, "sO", &servicename, &kvs)) {
404 0 : talloc_free(tmp_ctx);
405 0 : return NULL;
406 : }
407 :
408 11 : if (PySequence_Check(kvs) == 0) {
409 1 : PyErr_SetString(PyExc_TypeError,
410 : "a sequence object is required");
411 1 : talloc_free(tmp_ctx);
412 1 : return NULL;
413 : }
414 :
415 10 : size = PySequence_Size(kvs);
416 10 : if (size == -1) {
417 0 : PyErr_SetString(PyExc_ValueError, "failed to get size");
418 0 : talloc_free(tmp_ctx);
419 0 : return NULL;
420 : }
421 :
422 10 : tmp_service = talloc_zero(tmp_ctx, struct smbconf_service);
423 10 : if (tmp_service == NULL) {
424 0 : PyErr_NoMemory();
425 0 : talloc_free(tmp_ctx);
426 0 : return NULL;
427 : }
428 :
429 10 : tmp_service->name = talloc_strdup(tmp_service, servicename);
430 10 : if (tmp_service->name == NULL) {
431 0 : PyErr_NoMemory();
432 0 : talloc_free(tmp_ctx);
433 0 : return NULL;
434 : }
435 10 : tmp_service->num_params = (uint32_t) size;
436 10 : tmp_service->param_names = talloc_array(tmp_ctx, char *, size);
437 10 : if (tmp_service->param_names == NULL) {
438 0 : PyErr_NoMemory();
439 0 : talloc_free(tmp_ctx);
440 0 : return NULL;
441 : }
442 10 : tmp_service->param_values = talloc_array(tmp_ctx, char *, size);
443 10 : if (tmp_service->param_values == NULL) {
444 0 : PyErr_NoMemory();
445 0 : talloc_free(tmp_ctx);
446 0 : return NULL;
447 : }
448 :
449 23 : for (idx = 0; idx < size; idx++) {
450 16 : char *tmp_str = NULL;
451 16 : PyObject *tmp_pair = PySequence_GetItem(kvs, idx);
452 16 : if (tmp_pair == NULL) {
453 0 : talloc_free(tmp_ctx);
454 0 : return NULL;
455 : }
456 16 : if (PySequence_Size(tmp_pair) != 2) {
457 2 : PyErr_SetString(PyExc_ValueError,
458 : "expecting two-item tuples");
459 2 : Py_CLEAR(tmp_pair);
460 2 : talloc_free(tmp_ctx);
461 2 : return NULL;
462 : }
463 :
464 : /* fetch key */
465 14 : tmp_str = py_get_kv_str(tmp_ctx, tmp_pair, 0);
466 14 : if (tmp_str == NULL) {
467 0 : Py_CLEAR(tmp_pair);
468 0 : talloc_free(tmp_ctx);
469 0 : return NULL;
470 : }
471 14 : tmp_service->param_names[idx] = tmp_str;
472 :
473 : /* fetch value */
474 14 : tmp_str = py_get_kv_str(tmp_ctx, tmp_pair, 1);
475 14 : if (tmp_str == NULL) {
476 1 : Py_CLEAR(tmp_pair);
477 1 : talloc_free(tmp_ctx);
478 1 : return NULL;
479 : }
480 13 : tmp_service->param_values[idx] = tmp_str;
481 :
482 13 : Py_CLEAR(tmp_pair);
483 : }
484 :
485 7 : err = smbconf_create_set_share(self->conf_ctx, tmp_service);
486 7 : if (err != SBC_ERR_OK) {
487 2 : py_raise_SMBConfError(err);
488 2 : talloc_free(tmp_ctx);
489 2 : return NULL;
490 : }
491 5 : talloc_free(tmp_ctx);
492 5 : Py_RETURN_NONE;
493 : }
494 :
495 1 : static PyObject *obj_delete_parameter(py_SMBConf_Object * self, PyObject * args)
496 : {
497 1 : sbcErr err;
498 1 : char *servicename = NULL;
499 1 : char *param_name = NULL;
500 :
501 1 : if (!PyArg_ParseTuple(args, "ss", &servicename, ¶m_name)) {
502 : return NULL;
503 : }
504 :
505 1 : err = smbconf_delete_parameter(self->conf_ctx, servicename, param_name);
506 1 : if (err != SBC_ERR_OK) {
507 0 : py_raise_SMBConfError(err);
508 0 : return NULL;
509 : }
510 1 : Py_RETURN_NONE;
511 : }
512 :
513 2 : static PyObject *obj_delete_global_parameter(py_SMBConf_Object * self,
514 : PyObject * args)
515 : {
516 2 : sbcErr err;
517 2 : char *param_name = NULL;
518 :
519 2 : if (!PyArg_ParseTuple(args, "s", ¶m_name)) {
520 : return NULL;
521 : }
522 :
523 2 : err = smbconf_delete_global_parameter(self->conf_ctx, param_name);
524 2 : if (err != SBC_ERR_OK) {
525 0 : py_raise_SMBConfError(err);
526 0 : return NULL;
527 : }
528 2 : Py_RETURN_NONE;
529 : }
530 :
531 4 : static PyObject *obj_transaction_start(py_SMBConf_Object * self,
532 : PyObject * Py_UNUSED(ignored))
533 : {
534 4 : sbcErr err = smbconf_transaction_start(self->conf_ctx);
535 4 : if (err != SBC_ERR_OK) {
536 0 : py_raise_SMBConfError(err);
537 0 : return NULL;
538 : }
539 4 : Py_RETURN_NONE;
540 : }
541 :
542 2 : static PyObject *obj_transaction_commit(py_SMBConf_Object * self,
543 : PyObject * Py_UNUSED(ignored))
544 : {
545 2 : sbcErr err = smbconf_transaction_commit(self->conf_ctx);
546 2 : if (err != SBC_ERR_OK) {
547 0 : py_raise_SMBConfError(err);
548 0 : return NULL;
549 : }
550 2 : Py_RETURN_NONE;
551 : }
552 :
553 2 : static PyObject *obj_transaction_cancel(py_SMBConf_Object * self,
554 : PyObject * Py_UNUSED(ignored))
555 : {
556 2 : sbcErr err = smbconf_transaction_cancel(self->conf_ctx);
557 2 : if (err != SBC_ERR_OK) {
558 0 : py_raise_SMBConfError(err);
559 0 : return NULL;
560 : }
561 2 : Py_RETURN_NONE;
562 : }
563 :
564 : PyDoc_STRVAR(obj_requires_messaging_doc,
565 : "requires_messaging() -> bool\n"
566 : "\n"
567 : "Returns true if the backend requires interprocess messaging.\n");
568 :
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");
573 :
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");
579 :
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");
587 :
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");
593 :
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");
598 :
599 : PyDoc_STRVAR(obj_drop_doc,
600 : "drop() -> None\n"
601 : "Drop the entire configuration, resetting it to an empty state.\n");
602 :
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");
607 :
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");
612 :
613 : PyDoc_STRVAR(obj_delete_share_doc,
614 : "delete_share(str) -> None\n"
615 : "Delete a service from the configuration.\n");
616 :
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");
620 :
621 : PyDoc_STRVAR(obj_delete_parameter_doc,
622 : "delete_parameter(str, str) -> None\n"
623 : "Delete a single configuration parameter.\n");
624 :
625 : PyDoc_STRVAR(obj_delete_global_parameter_doc,
626 : "delete_parameter(str, str) -> None\n"
627 : "Delete a single global configuration parameter.\n");
628 :
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");
633 :
634 : PyDoc_STRVAR(obj_transaction_commit_doc,
635 : "transaction_commit() -> None\n"
636 : "Commit the transaction.\n");
637 :
638 : PyDoc_STRVAR(obj_transaction_cancel_doc,
639 : "transaction_cancel() -> None\n"
640 : "Cancel the transaction.\n");
641 :
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 },
676 : };
677 :
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");
683 :
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,
692 : };
693 :
694 8 : static PyObject *py_init_txt(PyObject * module, PyObject * args)
695 : {
696 8 : py_SMBConf_Object *obj;
697 8 : sbcErr err;
698 8 : char *path = NULL;
699 8 : struct smbconf_ctx *conf_ctx = NULL;
700 :
701 8 : if (!PyArg_ParseTuple(args, "s", &path)) {
702 : return NULL;
703 : }
704 :
705 8 : obj = (py_SMBConf_Object *) obj_new(&py_SMBConf_Type, NULL, NULL);
706 8 : if (obj == NULL) {
707 : return NULL;
708 : }
709 :
710 8 : err = smbconf_init_txt(obj->mem_ctx, &conf_ctx, path);
711 8 : if (err != SBC_ERR_OK) {
712 1 : Py_DECREF(obj);
713 1 : py_raise_SMBConfError(err);
714 1 : return NULL;
715 : }
716 7 : obj->conf_ctx = conf_ctx;
717 7 : return (PyObject *) obj;
718 : }
719 :
720 0 : static PyObject *py_smbconf_error(PyObject * module, PyObject * args)
721 : {
722 0 : sbcErr errcode;
723 :
724 0 : if (!PyArg_ParseTuple(args, "i", &errcode)) {
725 : return NULL;
726 : }
727 :
728 : /* this always raises an exception. it doesn't return the exception. */
729 0 : py_raise_SMBConfError(errcode);
730 0 : return NULL;
731 : }
732 :
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 },
739 : };
740 :
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");
751 :
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,
758 : };
759 :
760 1 : MODULE_INIT_FUNC(smbconf)
761 : {
762 1 : PyObject *m = PyModule_Create(&moduledef);
763 1 : if (m == NULL) {
764 : return NULL;
765 : }
766 :
767 1 : if (PyType_Ready(&py_SMBConf_Type) < 0) {
768 0 : Py_DECREF(m);
769 0 : return NULL;
770 : }
771 1 : Py_INCREF(&py_SMBConf_Type);
772 1 : if (PyModule_AddObject(m, "SMBConf", (PyObject *) & py_SMBConf_Type) <
773 : 0) {
774 0 : Py_DECREF(&py_SMBConf_Type);
775 0 : Py_DECREF(m);
776 0 : return NULL;
777 : }
778 :
779 2 : PyExc_SMBConfError =
780 1 : PyErr_NewException(discard_const_p(char, "smbconf.SMBConfError"),
781 : NULL, NULL);
782 1 : if (PyExc_SMBConfError == NULL) {
783 0 : Py_DECREF(m);
784 0 : return NULL;
785 : }
786 1 : Py_INCREF(PyExc_SMBConfError);
787 1 : if (PyModule_AddObject(m, "SMBConfError", PyExc_SMBConfError) < 0) {
788 0 : Py_DECREF(PyExc_SMBConfError);
789 0 : Py_DECREF(m);
790 0 : return NULL;
791 : }
792 :
793 : /*
794 : * ADD_FLAGS macro borrowed from source3/libsmb/pylibsmb.c
795 : */
796 : #define ADD_FLAGS(val) PyModule_AddObject(m, #val, PyLong_FromLong(val))
797 :
798 1 : ADD_FLAGS(SBC_ERR_OK);
799 1 : ADD_FLAGS(SBC_ERR_NOT_IMPLEMENTED);
800 1 : ADD_FLAGS(SBC_ERR_NOT_SUPPORTED);
801 1 : ADD_FLAGS(SBC_ERR_UNKNOWN_FAILURE);
802 1 : ADD_FLAGS(SBC_ERR_NOMEM);
803 1 : ADD_FLAGS(SBC_ERR_INVALID_PARAM);
804 1 : ADD_FLAGS(SBC_ERR_BADFILE);
805 1 : ADD_FLAGS(SBC_ERR_NO_SUCH_SERVICE);
806 1 : ADD_FLAGS(SBC_ERR_IO_FAILURE);
807 1 : ADD_FLAGS(SBC_ERR_CAN_NOT_COMPLETE);
808 1 : ADD_FLAGS(SBC_ERR_NO_MORE_ITEMS);
809 1 : ADD_FLAGS(SBC_ERR_FILE_EXISTS);
810 1 : ADD_FLAGS(SBC_ERR_ACCESS_DENIED);
811 :
812 1 : return m;
813 : }
|