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 "source3/lib/smbconf/smbconf_reg.h"
27 : #include "source3/lib/smbconf/smbconf_init.h"
28 : #include "lib/smbconf/pysmbconf.h"
29 :
30 : /*
31 : * The name of the other, general, smbconf module that implements
32 : * the common type. We import this module by name to access
33 : * its methods by the python API.
34 : */
35 : #define SMBCONF_MOD "samba.smbconf"
36 :
37 : /*
38 : * Return a new but uninitialized SMBConf python object via
39 : * the python API of the (other) smbconf module.
40 : */
41 13 : static PyObject *py_new_SMBConf(PyObject * smbconf_mod)
42 : {
43 13 : PyObject *obj = NULL;
44 13 : PyObject *method = PyObject_GetAttrString(smbconf_mod, "SMBConf");
45 13 : if (method == NULL) {
46 : return NULL;
47 : }
48 :
49 13 : obj = PyObject_CallObject(method, NULL);
50 13 : Py_CLEAR(method);
51 : return obj;
52 : }
53 :
54 : /*
55 : * Raise a new SMBConfError python exception given a error code.
56 : * This uses the python API of the (other) smbconf module.
57 : */
58 0 : static PyObject *py_raise_SMBConfError(PyObject * smbconf_mod, sbcErr err)
59 : {
60 0 : PyObject *obj = NULL;
61 0 : PyObject *method =
62 0 : PyObject_GetAttrString(smbconf_mod, "_smbconf_error");
63 0 : if (method == NULL) {
64 : return NULL;
65 : }
66 :
67 0 : obj = PyObject_CallFunction(method, "i", err);
68 0 : Py_CLEAR(method);
69 : return obj;
70 : }
71 :
72 11 : static PyObject *py_init_reg(PyObject * module, PyObject * args)
73 : {
74 11 : PyObject *obj = NULL;
75 11 : PyObject *smbconf_mod = NULL;
76 11 : char *path = NULL;
77 11 : struct smbconf_ctx *conf_ctx = NULL;
78 11 : TALLOC_CTX *mem_ctx = NULL;
79 11 : sbcErr err;
80 :
81 : /*
82 : * The path here is _NOT_ the path to a file in the file
83 : * system. It's a special HK registry thingy. But passing
84 : * a null string to smbconf_init_reg populates it with
85 : * a functional default value. So we allow the python
86 : * caller to pass None and convert to NULL.
87 : */
88 11 : if (!PyArg_ParseTuple(args, "z", &path)) {
89 : return NULL;
90 : }
91 :
92 11 : smbconf_mod = PyImport_ImportModule(SMBCONF_MOD);
93 11 : if (smbconf_mod == NULL) {
94 : return NULL;
95 : }
96 :
97 11 : obj = py_new_SMBConf(smbconf_mod);
98 11 : if (obj == NULL) {
99 0 : Py_CLEAR(smbconf_mod);
100 0 : return NULL;
101 : }
102 :
103 11 : mem_ctx = ((py_SMBConf_Object *) obj)->mem_ctx;
104 11 : err = smbconf_init_reg(mem_ctx, &conf_ctx, path);
105 11 : if (err != SBC_ERR_OK) {
106 0 : py_raise_SMBConfError(smbconf_mod, err);
107 0 : Py_CLEAR(obj);
108 0 : Py_CLEAR(smbconf_mod);
109 0 : return NULL;
110 : }
111 11 : ((py_SMBConf_Object *) obj)->conf_ctx = conf_ctx;
112 :
113 11 : Py_DECREF(smbconf_mod);
114 : return obj;
115 : }
116 :
117 2 : static PyObject *py_init_str(PyObject * module, PyObject * args)
118 : {
119 2 : PyObject *obj = NULL;
120 2 : PyObject *smbconf_mod = NULL;
121 2 : char *path = NULL;
122 2 : struct smbconf_ctx *conf_ctx = NULL;
123 2 : TALLOC_CTX *mem_ctx = NULL;
124 2 : sbcErr err;
125 :
126 2 : if (!PyArg_ParseTuple(args, "s", &path)) {
127 : return NULL;
128 : }
129 :
130 2 : smbconf_mod = PyImport_ImportModule(SMBCONF_MOD);
131 2 : if (smbconf_mod == NULL) {
132 : return NULL;
133 : }
134 :
135 2 : obj = py_new_SMBConf(smbconf_mod);
136 2 : if (obj == NULL) {
137 0 : Py_CLEAR(smbconf_mod);
138 0 : return NULL;
139 : }
140 :
141 2 : mem_ctx = ((py_SMBConf_Object *) obj)->mem_ctx;
142 2 : err = smbconf_init(mem_ctx, &conf_ctx, path);
143 2 : if (err != SBC_ERR_OK) {
144 0 : py_raise_SMBConfError(smbconf_mod, err);
145 0 : Py_CLEAR(obj);
146 0 : Py_CLEAR(smbconf_mod);
147 0 : return NULL;
148 : }
149 2 : ((py_SMBConf_Object *) obj)->conf_ctx = conf_ctx;
150 :
151 2 : Py_DECREF(smbconf_mod);
152 : return obj;
153 : }
154 :
155 : PyDoc_STRVAR(py_init_reg_doc,
156 : "Return an SMBConf object using the registry based configuration.\n"
157 : "The path argument provided must either be None to use the\n"
158 : "default path or a path within the registry. It must start with\n"
159 : "the characters 'HK' if provided. It is *not* a path to a\n"
160 : "file or database in the file system.\n");
161 :
162 : PyDoc_STRVAR(py_init_str_doc,
163 : "Return an SMBConf object opened using one of the backends\n"
164 : "supported by Samba.\n"
165 : "The provided string argument must be in the form \"backend:path\".\n"
166 : "The backend portion is to be the name of a supported backend\n"
167 : "such as 'file', or 'registry'. The path following the colon is\n"
168 : "backend specific. In the case of the file backend this is the path\n"
169 : "to a configuration file.\n"
170 : "Examples:\n"
171 : " c1 = samba.samba3.smbconfig.init(\"file:/tmp/smb.conf\")\n"
172 : " c2 = samba.samba3.smbconfig.init(\"registry:\")\n");
173 : /*
174 : * The major advantage of having this `init` function in the
175 : * python wrapper is that if a backend is added without
176 : * explicit changes to the python wrapper libs, it should still
177 : * be able to access that backend through the general init
178 : * function. The value add is not huge but more like insurance.
179 : */
180 :
181 : static PyMethodDef pys3smbconf_methods[] = {
182 : { "init_reg", (PyCFunction) py_init_reg, METH_VARARGS,
183 : py_init_reg_doc },
184 : { "init", (PyCFunction) py_init_str, METH_VARARGS,
185 : py_init_str_doc },
186 : { 0 },
187 : };
188 :
189 : PyDoc_STRVAR(py_s3smbconf_doc,
190 : "The s3smbconf module is a wrapper for Samba's 'source3' smbconf library.\n"
191 : "This library provides functions to use configuration backends that are\n"
192 : "specific to the file server suite of components within Samba.\n"
193 : "This includes functions to access the registry backend of the\n"
194 : "smbconf subsystem. This backend is read-write.\n");
195 :
196 : static struct PyModuleDef moduledef = {
197 : PyModuleDef_HEAD_INIT,
198 : .m_name = "smbconf",
199 : .m_doc = py_s3smbconf_doc,
200 : .m_size = -1,
201 : .m_methods = pys3smbconf_methods,
202 : };
203 :
204 1 : MODULE_INIT_FUNC(smbconf)
205 : {
206 1 : PyObject *m = PyModule_Create(&moduledef);
207 1 : if (m == NULL) {
208 0 : return NULL;
209 : }
210 :
211 : return m;
212 : }
|