summaryrefslogtreecommitdiffstats
path: root/source3/lib/smbconf/pys3smbconf.c
blob: 09d4881a9b0b9f59951b62c7d86194dc099a9d8b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/*
 *  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 "lib/replace/system/python.h"
#include "includes.h"
#include "python/py3compat.h"

#include "lib/smbconf/smbconf.h"
#include "source3/lib/smbconf/smbconf_reg.h"
#include "source3/lib/smbconf/smbconf_init.h"
#include "lib/smbconf/pysmbconf.h"

/*
 * The name of the other, general, smbconf module that implements
 * the common type. We import this module by name to access
 * its methods by the python API.
 */
#define SMBCONF_MOD "samba.smbconf"

/*
 * Return a new but uninitialized SMBConf python object via
 * the python API of the (other) smbconf module.
 */
static PyObject *py_new_SMBConf(PyObject * smbconf_mod)
{
	PyObject *obj = NULL;
	PyObject *method = PyObject_GetAttrString(smbconf_mod, "SMBConf");
	if (method == NULL) {
		return NULL;
	}

	obj = PyObject_CallObject(method, NULL);
	Py_CLEAR(method);
	return obj;
}

/*
 * Raise a new SMBConfError python exception given a error code.
 * This uses the python API of the (other) smbconf module.
 */
static PyObject *py_raise_SMBConfError(PyObject * smbconf_mod, sbcErr err)
{
	PyObject *obj = NULL;
	PyObject *method =
	    PyObject_GetAttrString(smbconf_mod, "_smbconf_error");
	if (method == NULL) {
		return NULL;
	}

	obj = PyObject_CallFunction(method, "i", err);
	Py_CLEAR(method);
	return obj;
}

static PyObject *py_init_reg(PyObject * module, PyObject * args)
{
	PyObject *obj = NULL;
	PyObject *smbconf_mod = NULL;
	char *path = NULL;
	struct smbconf_ctx *conf_ctx = NULL;
	TALLOC_CTX *mem_ctx = NULL;
	sbcErr err;

	/*
	 * The path here is _NOT_ the path to a file in the file
	 * system. It's a special HK registry thingy. But passing
	 * a null string to smbconf_init_reg populates it with
	 * a functional default value. So we allow the python
	 * caller to pass None and convert to NULL.
	 */
	if (!PyArg_ParseTuple(args, "z", &path)) {
		return NULL;
	}

	smbconf_mod = PyImport_ImportModule(SMBCONF_MOD);
	if (smbconf_mod == NULL) {
		return NULL;
	}

	obj = py_new_SMBConf(smbconf_mod);
	if (obj == NULL) {
		Py_CLEAR(smbconf_mod);
		return NULL;
	}

	mem_ctx = ((py_SMBConf_Object *) obj)->mem_ctx;
	err = smbconf_init_reg(mem_ctx, &conf_ctx, path);
	if (err != SBC_ERR_OK) {
		py_raise_SMBConfError(smbconf_mod, err);
		Py_CLEAR(obj);
		Py_CLEAR(smbconf_mod);
		return NULL;
	}
	((py_SMBConf_Object *) obj)->conf_ctx = conf_ctx;

	Py_DECREF(smbconf_mod);
	return obj;
}

static PyObject *py_init_str(PyObject * module, PyObject * args)
{
	PyObject *obj = NULL;
	PyObject *smbconf_mod = NULL;
	char *path = NULL;
	struct smbconf_ctx *conf_ctx = NULL;
	TALLOC_CTX *mem_ctx = NULL;
	sbcErr err;

	if (!PyArg_ParseTuple(args, "s", &path)) {
		return NULL;
	}

	smbconf_mod = PyImport_ImportModule(SMBCONF_MOD);
	if (smbconf_mod == NULL) {
		return NULL;
	}

	obj = py_new_SMBConf(smbconf_mod);
	if (obj == NULL) {
		Py_CLEAR(smbconf_mod);
		return NULL;
	}

	mem_ctx = ((py_SMBConf_Object *) obj)->mem_ctx;
	err = smbconf_init(mem_ctx, &conf_ctx, path);
	if (err != SBC_ERR_OK) {
		py_raise_SMBConfError(smbconf_mod, err);
		Py_CLEAR(obj);
		Py_CLEAR(smbconf_mod);
		return NULL;
	}
	((py_SMBConf_Object *) obj)->conf_ctx = conf_ctx;

	Py_DECREF(smbconf_mod);
	return obj;
}

PyDoc_STRVAR(py_init_reg_doc,
"Return an SMBConf object using the registry based configuration.\n"
"The path argument provided must either be None to use the\n"
"default path or a path within the registry. It must start with\n"
"the characters 'HK' if provided. It is *not* a path to a\n"
"file or database in the file system.\n");

PyDoc_STRVAR(py_init_str_doc,
"Return an SMBConf object opened using one of the backends\n"
"supported by Samba.\n"
"The provided string argument must be in the form \"backend:path\".\n"
"The backend portion is to be the name of a supported backend\n"
"such as 'file', or 'registry'. The path following the colon is\n"
"backend specific. In the case of the file backend this is the path\n"
"to a configuration file.\n"
"Examples:\n"
"    c1 = samba.samba3.smbconfig.init(\"file:/tmp/smb.conf\")\n"
"    c2 = samba.samba3.smbconfig.init(\"registry:\")\n");
/*
 * The major advantage of having this `init` function in the
 * python wrapper is that if a backend is added without
 * explicit changes to the python wrapper libs, it should still
 * be able to access that backend through the general init
 * function. The value add is not huge but more like insurance.
 */

static PyMethodDef pys3smbconf_methods[] = {
	{ "init_reg", (PyCFunction) py_init_reg, METH_VARARGS,
	 py_init_reg_doc },
	{ "init", (PyCFunction) py_init_str, METH_VARARGS,
	 py_init_str_doc },
	{ 0 },
};

PyDoc_STRVAR(py_s3smbconf_doc,
"The s3smbconf module is a wrapper for Samba's 'source3' smbconf library.\n"
"This library provides functions to use configuration backends that are\n"
"specific to the file server suite of components within Samba.\n"
"This includes functions to access the registry backend of the\n"
"smbconf subsystem. This backend is read-write.\n");

static struct PyModuleDef moduledef = {
	PyModuleDef_HEAD_INIT,
	.m_name = "smbconf",
	.m_doc = py_s3smbconf_doc,
	.m_size = -1,
	.m_methods = pys3smbconf_methods,
};

MODULE_INIT_FUNC(smbconf)
{
	PyObject *m = PyModule_Create(&moduledef);
	if (m == NULL) {
		return NULL;
	}

	return m;
}