2 Unix SMB/CIFS implementation.
4 Python DNS server wrapper
6 Copyright (C) 2015 Andrew Bartlett
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "python/py3compat.h"
25 #include "python/modules.h"
28 #include "dns_server/dnsserver_common.h"
29 #include "dsdb/samdb/samdb.h"
30 #include "dsdb/common/util.h"
31 #include "librpc/gen_ndr/ndr_dnsp.h"
32 #include "librpc/rpc/pyrpc_util.h"
34 /* FIXME: These should be in a header file somewhere */
35 #define PyErr_LDB_OR_RAISE(py_ldb, ldb) \
36 if (!py_check_dcerpc_type(py_ldb, "ldb", "Ldb")) { \
37 PyErr_SetString(PyExc_TypeError, "Ldb connection object required"); \
40 ldb = pyldb_Ldb_AsLdbContext(py_ldb);
42 #define PyErr_LDB_DN_OR_RAISE(py_ldb_dn, dn) \
43 if (!py_check_dcerpc_type(py_ldb_dn, "ldb", "Dn")) { \
44 PyErr_SetString(PyExc_TypeError, "ldb Dn object required"); \
47 dn = pyldb_Dn_AS_DN(py_ldb_dn);
49 static PyObject *py_dnsp_DnssrvRpcRecord_get_list(struct dnsp_DnssrvRpcRecord *records,
52 PyObject *py_dns_list;
54 py_dns_list = PyList_New(num_records);
55 if (py_dns_list == NULL) {
58 for (i = 0; i < num_records; i++) {
59 PyObject *py_dns_record;
60 py_dns_record = py_return_ndr_struct("samba.dcerpc.dnsp", "DnssrvRpcRecord", records, &records[i]);
61 PyList_SetItem(py_dns_list, i, py_dns_record);
66 static int py_dnsp_DnssrvRpcRecord_get_array(PyObject *value,
68 struct dnsp_DnssrvRpcRecord **records,
69 uint16_t *num_records)
72 struct dnsp_DnssrvRpcRecord *recs;
73 PY_CHECK_TYPE(&PyList_Type, value, return -1;);
74 recs = talloc_array(mem_ctx, struct dnsp_DnssrvRpcRecord,
75 PyList_GET_SIZE(value));
80 for (i = 0; i < PyList_GET_SIZE(value); i++) {
82 PyObject *item = PyList_GET_ITEM(value, i);
83 type_correct = py_check_dcerpc_type(item, "samba.dcerpc.dnsp", "DnssrvRpcRecord");
84 if (type_correct == false) {
87 if (talloc_reference(mem_ctx, pytalloc_get_mem_ctx(item)) == NULL) {
91 recs[i] = *(struct dnsp_DnssrvRpcRecord *)pytalloc_get_ptr(item);
94 *num_records = PyList_GET_SIZE(value);
98 static PyObject *py_dsdb_dns_lookup(PyObject *self,
99 PyObject *args, PyObject *kwargs)
101 struct ldb_context *samdb;
102 PyObject *py_ldb, *ret, *pydn;
103 PyObject *py_dns_partition = NULL;
104 PyObject *result = NULL;
109 struct dns_server_zone *zones_list;
110 struct ldb_dn *dn, *dns_partition = NULL;
111 struct dnsp_DnssrvRpcRecord *records;
112 uint16_t num_records;
113 const char * const kwnames[] = { "ldb", "dns_name",
114 "dns_partition", NULL };
116 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Os|O",
117 discard_const_p(char *, kwnames),
119 &py_dns_partition)) {
122 PyErr_LDB_OR_RAISE(py_ldb, samdb);
124 if (py_dns_partition) {
125 PyErr_LDB_DN_OR_RAISE(py_dns_partition,
129 frame = talloc_stackframe();
131 status = dns_common_zones(samdb, frame, dns_partition,
133 if (!NT_STATUS_IS_OK(status)) {
135 PyErr_SetNTSTATUS(status);
139 werr = dns_common_name2dn(samdb, zones_list, frame, dns_name, &dn);
140 if (!W_ERROR_IS_OK(werr)) {
142 PyErr_SetWERROR(werr);
146 werr = dns_common_lookup(samdb,
152 if (!W_ERROR_IS_OK(werr)) {
154 PyErr_SetWERROR(werr);
158 ret = py_dnsp_DnssrvRpcRecord_get_list(records, num_records);
159 pydn = pyldb_Dn_FromDn(dn);
161 result = Py_BuildValue("(OO)", pydn, ret);
167 static PyObject *py_dsdb_dns_extract(PyObject *self, PyObject *args)
169 struct ldb_context *samdb;
170 PyObject *py_dns_el, *ret;
171 PyObject *py_ldb = NULL;
174 struct ldb_message_element *dns_el;
175 struct dnsp_DnssrvRpcRecord *records;
176 uint16_t num_records;
178 if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_dns_el)) {
182 PyErr_LDB_OR_RAISE(py_ldb, samdb);
184 if (!py_check_dcerpc_type(py_dns_el, "ldb", "MessageElement")) {
185 PyErr_SetString(PyExc_TypeError,
186 "ldb MessageElement object required");
189 dns_el = pyldb_MessageElement_AsMessageElement(py_dns_el);
191 frame = talloc_stackframe();
193 werr = dns_common_extract(samdb, dns_el,
197 if (!W_ERROR_IS_OK(werr)) {
199 PyErr_SetWERROR(werr);
203 ret = py_dnsp_DnssrvRpcRecord_get_list(records, num_records);
208 static PyObject *py_dsdb_dns_replace(PyObject *self, PyObject *args)
210 struct ldb_context *samdb;
211 PyObject *py_ldb, *py_dns_records;
217 struct dns_server_zone *zones_list;
219 struct dnsp_DnssrvRpcRecord *records;
220 uint16_t num_records;
223 * TODO: This is a shocking abuse, but matches what the
224 * internal DNS server does, it should be pushed into
225 * dns_common_replace()
227 static const int serial = 110;
229 if (!PyArg_ParseTuple(args, "OsO", &py_ldb, &dns_name, &py_dns_records)) {
232 PyErr_LDB_OR_RAISE(py_ldb, samdb);
234 frame = talloc_stackframe();
236 status = dns_common_zones(samdb, frame, NULL, &zones_list);
237 if (!NT_STATUS_IS_OK(status)) {
238 PyErr_SetNTSTATUS(status);
243 werr = dns_common_name2dn(samdb, zones_list, frame, dns_name, &dn);
244 if (!W_ERROR_IS_OK(werr)) {
245 PyErr_SetWERROR(werr);
250 ret = py_dnsp_DnssrvRpcRecord_get_array(py_dns_records,
252 &records, &num_records);
258 werr = dns_common_replace(samdb,
261 false, /* Not adding a record */
265 if (!W_ERROR_IS_OK(werr)) {
266 PyErr_SetWERROR(werr);
275 static PyObject *py_dsdb_dns_replace_by_dn(PyObject *self, PyObject *args)
277 struct ldb_context *samdb;
278 PyObject *py_ldb, *py_dn, *py_dns_records;
283 struct dnsp_DnssrvRpcRecord *records;
284 uint16_t num_records;
287 * TODO: This is a shocking abuse, but matches what the
288 * internal DNS server does, it should be pushed into
289 * dns_common_replace()
291 static const int serial = 110;
293 if (!PyArg_ParseTuple(args, "OOO", &py_ldb, &py_dn, &py_dns_records)) {
296 PyErr_LDB_OR_RAISE(py_ldb, samdb);
298 PyErr_LDB_DN_OR_RAISE(py_dn, dn);
300 frame = talloc_stackframe();
302 ret = py_dnsp_DnssrvRpcRecord_get_array(py_dns_records,
304 &records, &num_records);
310 werr = dns_common_replace(samdb,
313 false, /* Not adding a record */
317 if (!W_ERROR_IS_OK(werr)) {
318 PyErr_SetWERROR(werr);
328 static PyMethodDef py_dsdb_dns_methods[] = {
330 { "lookup", PY_DISCARD_FUNC_SIG(PyCFunction, py_dsdb_dns_lookup),
331 METH_VARARGS|METH_KEYWORDS,
332 "Get the DNS database entries for a DNS name"},
333 { "replace", (PyCFunction)py_dsdb_dns_replace,
334 METH_VARARGS, "Replace the DNS database entries for a DNS name"},
335 { "replace_by_dn", (PyCFunction)py_dsdb_dns_replace_by_dn,
336 METH_VARARGS, "Replace the DNS database entries for a LDB DN"},
337 { "extract", (PyCFunction)py_dsdb_dns_extract,
338 METH_VARARGS, "Return the DNS database entry as a python structure from an Ldb.MessageElement of type dnsRecord"},
342 static struct PyModuleDef moduledef = {
343 PyModuleDef_HEAD_INIT,
344 .m_name = "dsdb_dns",
345 .m_doc = "Python bindings for the DNS objects in the directory service databases.",
347 .m_methods = py_dsdb_dns_methods,
350 MODULE_INIT_FUNC(dsdb_dns)
354 m = PyModule_Create(&moduledef);