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
,
97 PyObject
*args
, PyObject
*kwargs
)
99 struct ldb_context
*samdb
;
100 PyObject
*py_ldb
, *ret
, *pydn
;
101 PyObject
*py_dns_partition
= NULL
;
106 struct dns_server_zone
*zones_list
;
107 struct ldb_dn
*dn
, *dns_partition
= NULL
;
108 struct dnsp_DnssrvRpcRecord
*records
;
109 uint16_t num_records
;
110 const char * const kwnames
[] = { "ldb", "dns_name",
111 "dns_partition", NULL
};
113 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "Os|O",
114 discard_const_p(char *, kwnames
),
116 &py_dns_partition
)) {
119 PyErr_LDB_OR_RAISE(py_ldb
, samdb
);
121 if (py_dns_partition
) {
122 PyErr_LDB_DN_OR_RAISE(py_dns_partition
,
126 frame
= talloc_stackframe();
128 status
= dns_common_zones(samdb
, frame
, dns_partition
,
130 if (!NT_STATUS_IS_OK(status
)) {
132 PyErr_SetNTSTATUS(status
);
136 werr
= dns_common_name2dn(samdb
, zones_list
, frame
, dns_name
, &dn
);
137 if (!W_ERROR_IS_OK(werr
)) {
139 PyErr_SetWERROR(werr
);
143 werr
= dns_common_lookup(samdb
,
149 if (!W_ERROR_IS_OK(werr
)) {
151 PyErr_SetWERROR(werr
);
155 ret
= py_dnsp_DnssrvRpcRecord_get_list(records
, num_records
);
156 pydn
= pyldb_Dn_FromDn(dn
);
158 return Py_BuildValue("(OO)", pydn
, ret
);
161 static PyObject
*py_dsdb_dns_extract(PyObject
*self
, PyObject
*args
)
163 struct ldb_context
*samdb
;
164 PyObject
*py_dns_el
, *ret
;
165 PyObject
*py_ldb
= NULL
;
168 struct ldb_message_element
*dns_el
;
169 struct dnsp_DnssrvRpcRecord
*records
;
170 uint16_t num_records
;
172 if (!PyArg_ParseTuple(args
, "OO", &py_ldb
, &py_dns_el
)) {
176 PyErr_LDB_OR_RAISE(py_ldb
, samdb
);
178 if (!py_check_dcerpc_type(py_dns_el
, "ldb", "MessageElement")) {
179 PyErr_SetString(PyExc_TypeError
,
180 "ldb MessageElement object required");
183 dns_el
= pyldb_MessageElement_AsMessageElement(py_dns_el
);
185 frame
= talloc_stackframe();
187 werr
= dns_common_extract(samdb
, dns_el
,
191 if (!W_ERROR_IS_OK(werr
)) {
193 PyErr_SetWERROR(werr
);
197 ret
= py_dnsp_DnssrvRpcRecord_get_list(records
, num_records
);
202 static PyObject
*py_dsdb_dns_replace(PyObject
*self
, PyObject
*args
)
204 struct ldb_context
*samdb
;
205 PyObject
*py_ldb
, *py_dns_records
;
211 struct dns_server_zone
*zones_list
;
213 struct dnsp_DnssrvRpcRecord
*records
;
214 uint16_t num_records
;
217 * TODO: This is a shocking abuse, but matches what the
218 * internal DNS server does, it should be pushed into
219 * dns_common_replace()
221 static const int serial
= 110;
223 if (!PyArg_ParseTuple(args
, "OsO", &py_ldb
, &dns_name
, &py_dns_records
)) {
226 PyErr_LDB_OR_RAISE(py_ldb
, samdb
);
228 frame
= talloc_stackframe();
230 status
= dns_common_zones(samdb
, frame
, NULL
, &zones_list
);
231 if (!NT_STATUS_IS_OK(status
)) {
232 PyErr_SetNTSTATUS(status
);
237 werr
= dns_common_name2dn(samdb
, zones_list
, frame
, dns_name
, &dn
);
238 if (!W_ERROR_IS_OK(werr
)) {
239 PyErr_SetWERROR(werr
);
244 ret
= py_dnsp_DnssrvRpcRecord_get_array(py_dns_records
,
246 &records
, &num_records
);
252 werr
= dns_common_replace(samdb
,
255 false, /* Not adding a record */
259 if (!W_ERROR_IS_OK(werr
)) {
260 PyErr_SetWERROR(werr
);
269 static PyObject
*py_dsdb_dns_replace_by_dn(PyObject
*self
, PyObject
*args
)
271 struct ldb_context
*samdb
;
272 PyObject
*py_ldb
, *py_dn
, *py_dns_records
;
277 struct dnsp_DnssrvRpcRecord
*records
;
278 uint16_t num_records
;
281 * TODO: This is a shocking abuse, but matches what the
282 * internal DNS server does, it should be pushed into
283 * dns_common_replace()
285 static const int serial
= 110;
287 if (!PyArg_ParseTuple(args
, "OOO", &py_ldb
, &py_dn
, &py_dns_records
)) {
290 PyErr_LDB_OR_RAISE(py_ldb
, samdb
);
292 PyErr_LDB_DN_OR_RAISE(py_dn
, dn
);
294 frame
= talloc_stackframe();
296 ret
= py_dnsp_DnssrvRpcRecord_get_array(py_dns_records
,
298 &records
, &num_records
);
304 werr
= dns_common_replace(samdb
,
307 false, /* Not adding a record */
311 if (!W_ERROR_IS_OK(werr
)) {
312 PyErr_SetWERROR(werr
);
322 static PyMethodDef py_dsdb_dns_methods
[] = {
324 { "lookup", (PyCFunction
)py_dsdb_dns_lookup
,
325 METH_VARARGS
|METH_KEYWORDS
,
326 "Get the DNS database entries for a DNS name"},
327 { "replace", (PyCFunction
)py_dsdb_dns_replace
,
328 METH_VARARGS
, "Replace the DNS database entries for a DNS name"},
329 { "replace_by_dn", (PyCFunction
)py_dsdb_dns_replace_by_dn
,
330 METH_VARARGS
, "Replace the DNS database entries for a LDB DN"},
331 { "extract", (PyCFunction
)py_dsdb_dns_extract
,
332 METH_VARARGS
, "Return the DNS database entry as a python structure from an Ldb.MessageElement of type dnsRecord"},
336 void initdsdb_dns(void);
338 void initdsdb_dns(void)
342 m
= Py_InitModule3("dsdb_dns", py_dsdb_dns_methods
,
343 "Python bindings for the DNS objects in the directory service databases.");