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/>.
22 #include "lib/replace/system/python.h"
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 static PyObject
*py_dnsp_DnssrvRpcRecord_get_list(struct dnsp_DnssrvRpcRecord
*records
,
37 PyObject
*py_dns_list
;
39 py_dns_list
= PyList_New(num_records
);
40 if (py_dns_list
== NULL
) {
43 for (i
= 0; i
< num_records
; i
++) {
44 PyObject
*py_dns_record
;
45 py_dns_record
= py_return_ndr_struct("samba.dcerpc.dnsp", "DnssrvRpcRecord", records
, &records
[i
]);
46 PyList_SetItem(py_dns_list
, i
, py_dns_record
);
52 static int py_dnsp_DnssrvRpcRecord_get_array(PyObject
*value
,
54 struct dnsp_DnssrvRpcRecord
**records
,
55 uint16_t *num_records
)
58 struct dnsp_DnssrvRpcRecord
*recs
;
59 PY_CHECK_TYPE(&PyList_Type
, value
, return -1;);
60 recs
= talloc_array(mem_ctx
, struct dnsp_DnssrvRpcRecord
,
61 PyList_GET_SIZE(value
));
66 for (i
= 0; i
< PyList_GET_SIZE(value
); i
++) {
68 PyObject
*item
= PyList_GET_ITEM(value
, i
);
69 type_correct
= py_check_dcerpc_type(item
, "samba.dcerpc.dnsp", "DnssrvRpcRecord");
70 if (type_correct
== false) {
73 if (talloc_reference(mem_ctx
, pytalloc_get_mem_ctx(item
)) == NULL
) {
77 recs
[i
] = *(struct dnsp_DnssrvRpcRecord
*)pytalloc_get_ptr(item
);
80 *num_records
= PyList_GET_SIZE(value
);
84 static PyObject
*py_dsdb_dns_lookup(PyObject
*self
,
85 PyObject
*args
, PyObject
*kwargs
)
87 struct ldb_context
*samdb
;
88 PyObject
*py_ldb
, *ret
, *pydn
;
89 PyObject
*py_dns_partition
= NULL
;
90 PyObject
*result
= NULL
;
95 struct dns_server_zone
*zones_list
;
96 struct ldb_dn
*dn
, *dns_partition
= NULL
;
97 struct dnsp_DnssrvRpcRecord
*records
;
99 const char * const kwnames
[] = { "ldb", "dns_name",
100 "dns_partition", NULL
};
102 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "Os|O",
103 discard_const_p(char *, kwnames
),
105 &py_dns_partition
)) {
108 PyErr_LDB_OR_RAISE(py_ldb
, samdb
);
110 if (py_dns_partition
) {
111 PyErr_LDB_DN_OR_RAISE(py_dns_partition
,
115 frame
= talloc_stackframe();
117 status
= dns_common_zones(samdb
, frame
, dns_partition
,
119 if (!NT_STATUS_IS_OK(status
)) {
121 PyErr_SetNTSTATUS(status
);
125 werr
= dns_common_name2dn(samdb
, zones_list
, frame
, dns_name
, &dn
);
126 if (!W_ERROR_IS_OK(werr
)) {
128 PyErr_SetWERROR(werr
);
132 werr
= dns_common_lookup(samdb
,
138 if (!W_ERROR_IS_OK(werr
)) {
140 PyErr_SetWERROR(werr
);
144 ret
= py_dnsp_DnssrvRpcRecord_get_list(records
, num_records
);
145 pydn
= pyldb_Dn_FromDn(dn
, (PyLdbObject
*)py_ldb
);
147 result
= Py_BuildValue("(OO)", pydn
, ret
);
153 static PyObject
*py_dsdb_dns_extract(PyObject
*self
, PyObject
*args
)
155 struct ldb_context
*samdb
;
156 PyObject
*py_dns_el
, *ret
;
157 PyObject
*py_ldb
= NULL
;
160 struct ldb_message_element
*dns_el
;
161 struct dnsp_DnssrvRpcRecord
*records
;
162 uint16_t num_records
;
164 if (!PyArg_ParseTuple(args
, "OO", &py_ldb
, &py_dns_el
)) {
168 PyErr_LDB_OR_RAISE(py_ldb
, samdb
);
170 if (!py_check_dcerpc_type(py_dns_el
, "ldb", "MessageElement")) {
171 PyErr_SetString(PyExc_TypeError
,
172 "ldb MessageElement object required");
175 dns_el
= pyldb_MessageElement_AsMessageElement(py_dns_el
);
177 frame
= talloc_stackframe();
179 werr
= dns_common_extract(samdb
, dns_el
,
183 if (!W_ERROR_IS_OK(werr
)) {
185 PyErr_SetWERROR(werr
);
189 ret
= py_dnsp_DnssrvRpcRecord_get_list(records
, num_records
);
194 static PyObject
*py_dsdb_dns_replace(PyObject
*self
, PyObject
*args
)
196 struct ldb_context
*samdb
;
197 PyObject
*py_ldb
, *py_dns_records
;
203 struct dns_server_zone
*zones_list
;
205 struct dnsp_DnssrvRpcRecord
*records
;
206 uint16_t num_records
;
209 * TODO: This is a shocking abuse, but matches what the
210 * internal DNS server does, it should be pushed into
211 * dns_common_replace()
213 static const int serial
= 110;
215 if (!PyArg_ParseTuple(args
, "OsO", &py_ldb
, &dns_name
, &py_dns_records
)) {
218 PyErr_LDB_OR_RAISE(py_ldb
, samdb
);
220 frame
= talloc_stackframe();
222 status
= dns_common_zones(samdb
, frame
, NULL
, &zones_list
);
223 if (!NT_STATUS_IS_OK(status
)) {
224 PyErr_SetNTSTATUS(status
);
229 werr
= dns_common_name2dn(samdb
, zones_list
, frame
, dns_name
, &dn
);
230 if (!W_ERROR_IS_OK(werr
)) {
231 PyErr_SetWERROR(werr
);
236 ret
= py_dnsp_DnssrvRpcRecord_get_array(py_dns_records
,
238 &records
, &num_records
);
244 werr
= dns_common_replace(samdb
,
247 false, /* Not adding a record */
251 if (!W_ERROR_IS_OK(werr
)) {
252 PyErr_SetWERROR(werr
);
261 static PyObject
*py_dsdb_dns_replace_by_dn(PyObject
*self
, PyObject
*args
)
263 struct ldb_context
*samdb
;
264 PyObject
*py_ldb
, *py_dn
, *py_dns_records
;
269 struct dnsp_DnssrvRpcRecord
*records
;
270 uint16_t num_records
;
273 * TODO: This is a shocking abuse, but matches what the
274 * internal DNS server does, it should be pushed into
275 * dns_common_replace()
277 static const int serial
= 110;
279 if (!PyArg_ParseTuple(args
, "OOO", &py_ldb
, &py_dn
, &py_dns_records
)) {
282 PyErr_LDB_OR_RAISE(py_ldb
, samdb
);
284 PyErr_LDB_DN_OR_RAISE(py_dn
, dn
);
286 frame
= talloc_stackframe();
288 ret
= py_dnsp_DnssrvRpcRecord_get_array(py_dns_records
,
290 &records
, &num_records
);
296 werr
= dns_common_replace(samdb
,
299 false, /* Not adding a node */
303 if (!W_ERROR_IS_OK(werr
)) {
304 PyErr_SetWERROR(werr
);
315 static PyObject
*py_dsdb_dns_records_match(PyObject
*self
, PyObject
*args
)
317 PyObject
*py_recs
[2];
318 struct dnsp_DnssrvRpcRecord
*rec1
;
319 struct dnsp_DnssrvRpcRecord
*rec2
;
324 if (!PyArg_ParseTuple(args
, "OO", &py_recs
[0], &py_recs
[1])) {
328 for (i
= 0; i
< 2; i
++) {
329 type_correct
= py_check_dcerpc_type(py_recs
[i
],
332 if (! type_correct
) {
333 PyErr_SetString(PyExc_ValueError
,
334 "DnssrvRpcRecord expected");
339 rec1
= (struct dnsp_DnssrvRpcRecord
*)pytalloc_get_ptr(py_recs
[0]);
340 rec2
= (struct dnsp_DnssrvRpcRecord
*)pytalloc_get_ptr(py_recs
[1]);
342 match
= dns_record_match(rec1
, rec2
);
343 return PyBool_FromLong(match
);
347 static PyObject
*py_dsdb_dns_unix_to_dns_timestamp(PyObject
*self
, PyObject
*args
)
353 if (!PyArg_ParseTuple(args
, "L", <
)) {
359 /* time_t is presumably 32 bit here */
360 PyErr_SetString(PyExc_ValueError
, "Time out of range");
363 timestamp
= unix_to_dns_timestamp(t
);
364 return Py_BuildValue("k", (unsigned long) timestamp
);
367 static PyObject
*py_dsdb_dns_timestamp_to_nt_time(PyObject
*self
, PyObject
*args
)
369 unsigned long long timestamp
;
372 if (!PyArg_ParseTuple(args
, "K", ×tamp
)) {
376 if (timestamp
> UINT32_MAX
) {
377 PyErr_SetString(PyExc_ValueError
, "Time out of range");
380 status
= dns_timestamp_to_nt_time(&nt
, (uint32_t)timestamp
);
381 if (!NT_STATUS_IS_OK(status
)) {
382 PyErr_SetString(PyExc_ValueError
, "Time out of range");
385 return Py_BuildValue("L", (long long) nt
);
389 static PyMethodDef py_dsdb_dns_methods
[] = {
391 { "lookup", PY_DISCARD_FUNC_SIG(PyCFunction
, py_dsdb_dns_lookup
),
392 METH_VARARGS
|METH_KEYWORDS
,
393 "Get the DNS database entries for a DNS name"},
394 { "replace", (PyCFunction
)py_dsdb_dns_replace
,
395 METH_VARARGS
, "Replace the DNS database entries for a DNS name"},
396 { "replace_by_dn", (PyCFunction
)py_dsdb_dns_replace_by_dn
,
397 METH_VARARGS
, "Replace the DNS database entries for a LDB DN"},
398 { "records_match", (PyCFunction
)py_dsdb_dns_records_match
,
399 METH_VARARGS
|METH_KEYWORDS
,
400 "Decide whether two records match, according to dns update rules"},
401 { "extract", (PyCFunction
)py_dsdb_dns_extract
,
402 METH_VARARGS
, "Return the DNS database entry as a python structure from an Ldb.MessageElement of type dnsRecord"},
403 { "unix_to_dns_timestamp", (PyCFunction
)py_dsdb_dns_unix_to_dns_timestamp
,
405 "Convert a time.time() value to a dns timestamp (hours since 1601)"},
406 { "dns_timestamp_to_nt_time", (PyCFunction
)py_dsdb_dns_timestamp_to_nt_time
,
408 "Convert a dns timestamp to an NTTIME value"},
412 static struct PyModuleDef moduledef
= {
413 PyModuleDef_HEAD_INIT
,
414 .m_name
= "dsdb_dns",
415 .m_doc
= "Python bindings for the DNS objects in the directory service databases.",
417 .m_methods
= py_dsdb_dns_methods
,
420 MODULE_INIT_FUNC(dsdb_dns
)
424 m
= PyModule_Create(&moduledef
);