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/>.
26 #include "dns_server/dnsserver_common.h"
27 #include "dsdb/samdb/samdb.h"
28 #include "dsdb/common/util.h"
29 #include "librpc/gen_ndr/ndr_dnsp.h"
30 #include "librpc/rpc/pyrpc_util.h"
32 /* FIXME: These should be in a header file somewhere */
33 #define PyErr_LDB_OR_RAISE(py_ldb, ldb) \
34 if (!py_check_dcerpc_type(py_ldb, "ldb", "Ldb")) { \
35 PyErr_SetString(PyExc_TypeError, "Ldb connection object required"); \
38 ldb = pyldb_Ldb_AsLdbContext(py_ldb);
40 #define PyErr_LDB_DN_OR_RAISE(py_ldb_dn, dn) \
41 if (!py_check_dcerpc_type(py_ldb_dn, "ldb", "Dn")) { \
42 PyErr_SetString(PyExc_TypeError, "ldb Dn object required"); \
45 dn = pyldb_Dn_AsDn(py_ldb_dn);
47 static PyObject *py_dnsp_DnssrvRpcRecord_get_list(struct dnsp_DnssrvRpcRecord *records,
50 PyObject *py_dns_list;
52 py_dns_list = PyList_New(num_records);
53 if (py_dns_list == NULL) {
56 for (i = 0; i < num_records; i++) {
57 PyObject *py_dns_record;
58 py_dns_record = py_return_ndr_struct("samba.dcerpc.dnsp", "DnssrvRpcRecord", records, &records[i]);
59 PyList_SetItem(py_dns_list, i, py_dns_record);
64 static int py_dnsp_DnssrvRpcRecord_get_array(PyObject *value,
66 struct dnsp_DnssrvRpcRecord **records,
67 uint16_t *num_records)
70 struct dnsp_DnssrvRpcRecord *recs;
71 PY_CHECK_TYPE(&PyList_Type, value, return -1;);
72 recs = talloc_array(mem_ctx, struct dnsp_DnssrvRpcRecord,
73 PyList_GET_SIZE(value));
78 for (i = 0; i < PyList_GET_SIZE(value); i++) {
80 PyObject *item = PyList_GET_ITEM(value, i);
81 type_correct = py_check_dcerpc_type(item, "samba.dcerpc.dnsp", "DnssrvRpcRecord");
82 if (type_correct == false) {
85 if (talloc_reference(mem_ctx, pytalloc_get_mem_ctx(item)) == NULL) {
89 recs[i] = *(struct dnsp_DnssrvRpcRecord *)pytalloc_get_ptr(item);
92 *num_records = PyList_GET_SIZE(value);
96 static PyObject *py_dsdb_dns_lookup(PyObject *self, PyObject *args)
98 struct ldb_context *samdb;
99 PyObject *py_ldb, *ret, *pydn;
104 struct dns_server_zone *zones_list;
106 struct dnsp_DnssrvRpcRecord *records;
107 uint16_t num_records;
109 if (!PyArg_ParseTuple(args, "Os", &py_ldb, &dns_name)) {
112 PyErr_LDB_OR_RAISE(py_ldb, samdb);
114 frame = talloc_stackframe();
116 status = dns_common_zones(samdb, frame, &zones_list);
117 if (!NT_STATUS_IS_OK(status)) {
119 PyErr_SetNTSTATUS(status);
123 werr = dns_common_name2dn(samdb, zones_list, frame, dns_name, &dn);
124 if (!W_ERROR_IS_OK(werr)) {
126 PyErr_SetWERROR(werr);
130 werr = dns_common_lookup(samdb,
136 if (!W_ERROR_IS_OK(werr)) {
138 PyErr_SetWERROR(werr);
142 ret = py_dnsp_DnssrvRpcRecord_get_list(records, num_records);
143 pydn = pyldb_Dn_FromDn(dn);
145 return Py_BuildValue("(OO)", pydn, ret);
148 static PyObject *py_dsdb_dns_extract(PyObject *self, PyObject *args)
150 PyObject *py_dns_el, *ret;
153 struct ldb_message_element *dns_el;
154 struct dnsp_DnssrvRpcRecord *records;
155 uint16_t num_records;
157 if (!PyArg_ParseTuple(args, "O", &py_dns_el)) {
161 if (!py_check_dcerpc_type(py_dns_el, "ldb", "MessageElement")) {
162 PyErr_SetString(PyExc_TypeError,
163 "ldb MessageElement object required");
166 dns_el = pyldb_MessageElement_AsMessageElement(py_dns_el);
168 frame = talloc_stackframe();
170 werr = dns_common_extract(dns_el,
174 if (!W_ERROR_IS_OK(werr)) {
176 PyErr_SetWERROR(werr);
180 ret = py_dnsp_DnssrvRpcRecord_get_list(records, num_records);
185 static PyObject *py_dsdb_dns_replace(PyObject *self, PyObject *args)
187 struct ldb_context *samdb;
188 PyObject *py_ldb, *py_dns_records;
194 struct dns_server_zone *zones_list;
196 struct dnsp_DnssrvRpcRecord *records;
197 uint16_t num_records;
200 * TODO: This is a shocking abuse, but matches what the
201 * internal DNS server does, it should be pushed into
202 * dns_common_replace()
204 static const int serial = 110;
206 if (!PyArg_ParseTuple(args, "OsO", &py_ldb, &dns_name, &py_dns_records)) {
209 PyErr_LDB_OR_RAISE(py_ldb, samdb);
211 frame = talloc_stackframe();
213 status = dns_common_zones(samdb, frame, &zones_list);
214 if (!NT_STATUS_IS_OK(status)) {
215 PyErr_SetNTSTATUS(status);
220 werr = dns_common_name2dn(samdb, zones_list, frame, dns_name, &dn);
221 if (!W_ERROR_IS_OK(werr)) {
222 PyErr_SetWERROR(werr);
227 ret = py_dnsp_DnssrvRpcRecord_get_array(py_dns_records,
229 &records, &num_records);
235 werr = dns_common_replace(samdb,
238 false, /* Not adding a record */
242 if (!W_ERROR_IS_OK(werr)) {
243 PyErr_SetWERROR(werr);
252 static PyObject *py_dsdb_dns_replace_by_dn(PyObject *self, PyObject *args)
254 struct ldb_context *samdb;
255 PyObject *py_ldb, *py_dn, *py_dns_records;
260 struct dnsp_DnssrvRpcRecord *records;
261 uint16_t num_records;
264 * TODO: This is a shocking abuse, but matches what the
265 * internal DNS server does, it should be pushed into
266 * dns_common_replace()
268 static const int serial = 110;
270 if (!PyArg_ParseTuple(args, "OOO", &py_ldb, &py_dn, &py_dns_records)) {
273 PyErr_LDB_OR_RAISE(py_ldb, samdb);
275 PyErr_LDB_DN_OR_RAISE(py_dn, dn);
277 frame = talloc_stackframe();
279 ret = py_dnsp_DnssrvRpcRecord_get_array(py_dns_records,
281 &records, &num_records);
287 werr = dns_common_replace(samdb,
290 false, /* Not adding a record */
294 if (!W_ERROR_IS_OK(werr)) {
295 PyErr_SetWERROR(werr);
305 static PyMethodDef py_dsdb_dns_methods[] = {
307 { "lookup", (PyCFunction)py_dsdb_dns_lookup,
308 METH_VARARGS, "Get the DNS database entries for a DNS name"},
309 { "replace", (PyCFunction)py_dsdb_dns_replace,
310 METH_VARARGS, "Replace the DNS database entries for a DNS name"},
311 { "replace_by_dn", (PyCFunction)py_dsdb_dns_replace_by_dn,
312 METH_VARARGS, "Replace the DNS database entries for a LDB DN"},
313 { "extract", (PyCFunction)py_dsdb_dns_extract,
314 METH_VARARGS, "Return the DNS database entry as a python structure from an Ldb.MessageElement of type dnsRecord"},
318 void initdsdb_dns(void);
320 void initdsdb_dns(void)
324 m = Py_InitModule3("dsdb_dns", py_dsdb_dns_methods,
325 "Python bindings for the DNS objects in the directory service databases.");