Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Python DNS server wrapper
5 :
6 : Copyright (C) 2015 Andrew Bartlett
7 :
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.
12 :
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.
17 :
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/>.
20 : */
21 :
22 : #include "lib/replace/system/python.h"
23 : #include "python/py3compat.h"
24 : #include "includes.h"
25 : #include "python/modules.h"
26 : #include <pyldb.h>
27 : #include <pytalloc.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"
33 :
34 430 : static PyObject *py_dnsp_DnssrvRpcRecord_get_list(struct dnsp_DnssrvRpcRecord *records,
35 : uint16_t num_records)
36 : {
37 4 : PyObject *py_dns_list;
38 4 : int i;
39 430 : py_dns_list = PyList_New(num_records);
40 430 : if (py_dns_list == NULL) {
41 0 : return NULL;
42 : }
43 1701 : for (i = 0; i < num_records; i++) {
44 6 : PyObject *py_dns_record;
45 1271 : py_dns_record = py_return_ndr_struct("samba.dcerpc.dnsp", "DnssrvRpcRecord", records, &records[i]);
46 1271 : PyList_SetItem(py_dns_list, i, py_dns_record);
47 : }
48 426 : return py_dns_list;
49 : }
50 :
51 :
52 842 : static int py_dnsp_DnssrvRpcRecord_get_array(PyObject *value,
53 : TALLOC_CTX *mem_ctx,
54 : struct dnsp_DnssrvRpcRecord **records,
55 : uint16_t *num_records)
56 : {
57 29 : int i;
58 29 : struct dnsp_DnssrvRpcRecord *recs;
59 842 : PY_CHECK_TYPE(&PyList_Type, value, return -1;);
60 842 : recs = talloc_array(mem_ctx, struct dnsp_DnssrvRpcRecord,
61 : PyList_GET_SIZE(value));
62 842 : if (recs == NULL) {
63 0 : PyErr_NoMemory();
64 0 : return -1;
65 : }
66 959 : for (i = 0; i < PyList_GET_SIZE(value); i++) {
67 4 : bool type_correct;
68 117 : PyObject *item = PyList_GET_ITEM(value, i);
69 117 : type_correct = py_check_dcerpc_type(item, "samba.dcerpc.dnsp", "DnssrvRpcRecord");
70 117 : if (type_correct == false) {
71 0 : return -1;
72 : }
73 117 : if (talloc_reference(mem_ctx, pytalloc_get_mem_ctx(item)) == NULL) {
74 0 : PyErr_NoMemory();
75 0 : return -1;
76 : }
77 117 : recs[i] = *(struct dnsp_DnssrvRpcRecord *)pytalloc_get_ptr(item);
78 : }
79 842 : *records = recs;
80 842 : *num_records = PyList_GET_SIZE(value);
81 842 : return 0;
82 : }
83 :
84 450 : static PyObject *py_dsdb_dns_lookup(PyObject *self,
85 : PyObject *args, PyObject *kwargs)
86 : {
87 6 : struct ldb_context *samdb;
88 6 : PyObject *py_ldb, *ret, *pydn;
89 450 : PyObject *py_dns_partition = NULL;
90 450 : PyObject *result = NULL;
91 6 : char *dns_name;
92 6 : TALLOC_CTX *frame;
93 6 : NTSTATUS status;
94 6 : WERROR werr;
95 6 : struct dns_server_zone *zones_list;
96 450 : struct ldb_dn *dn, *dns_partition = NULL;
97 6 : struct dnsp_DnssrvRpcRecord *records;
98 6 : uint16_t num_records;
99 450 : const char * const kwnames[] = { "ldb", "dns_name",
100 : "dns_partition", NULL };
101 :
102 450 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Os|O",
103 : discard_const_p(char *, kwnames),
104 : &py_ldb, &dns_name,
105 : &py_dns_partition)) {
106 0 : return NULL;
107 : }
108 450 : PyErr_LDB_OR_RAISE(py_ldb, samdb);
109 :
110 450 : if (py_dns_partition) {
111 93 : PyErr_LDB_DN_OR_RAISE(py_dns_partition,
112 : dns_partition);
113 : }
114 :
115 450 : frame = talloc_stackframe();
116 :
117 450 : status = dns_common_zones(samdb, frame, dns_partition,
118 : &zones_list);
119 450 : if (!NT_STATUS_IS_OK(status)) {
120 0 : talloc_free(frame);
121 0 : PyErr_SetNTSTATUS(status);
122 0 : return NULL;
123 : }
124 :
125 450 : werr = dns_common_name2dn(samdb, zones_list, frame, dns_name, &dn);
126 450 : if (!W_ERROR_IS_OK(werr)) {
127 12 : talloc_free(frame);
128 12 : PyErr_SetWERROR(werr);
129 12 : return NULL;
130 : }
131 :
132 438 : werr = dns_common_lookup(samdb,
133 : frame,
134 : dn,
135 : &records,
136 : &num_records,
137 : NULL);
138 438 : if (!W_ERROR_IS_OK(werr)) {
139 8 : talloc_free(frame);
140 8 : PyErr_SetWERROR(werr);
141 8 : return NULL;
142 : }
143 :
144 430 : ret = py_dnsp_DnssrvRpcRecord_get_list(records, num_records);
145 430 : pydn = pyldb_Dn_FromDn(dn, (PyLdbObject *)py_ldb);
146 430 : talloc_free(frame);
147 430 : result = Py_BuildValue("(OO)", pydn, ret);
148 430 : Py_CLEAR(ret);
149 430 : Py_CLEAR(pydn);
150 426 : return result;
151 : }
152 :
153 0 : static PyObject *py_dsdb_dns_extract(PyObject *self, PyObject *args)
154 : {
155 0 : struct ldb_context *samdb;
156 0 : PyObject *py_dns_el, *ret;
157 0 : PyObject *py_ldb = NULL;
158 0 : TALLOC_CTX *frame;
159 0 : WERROR werr;
160 0 : struct ldb_message_element *dns_el;
161 0 : struct dnsp_DnssrvRpcRecord *records;
162 0 : uint16_t num_records;
163 :
164 0 : if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_dns_el)) {
165 0 : return NULL;
166 : }
167 :
168 0 : PyErr_LDB_OR_RAISE(py_ldb, samdb);
169 :
170 0 : if (!py_check_dcerpc_type(py_dns_el, "ldb", "MessageElement")) {
171 0 : PyErr_SetString(PyExc_TypeError,
172 : "ldb MessageElement object required");
173 0 : return NULL;
174 : }
175 0 : dns_el = pyldb_MessageElement_AsMessageElement(py_dns_el);
176 :
177 0 : frame = talloc_stackframe();
178 :
179 0 : werr = dns_common_extract(samdb, dns_el,
180 : frame,
181 : &records,
182 : &num_records);
183 0 : if (!W_ERROR_IS_OK(werr)) {
184 0 : talloc_free(frame);
185 0 : PyErr_SetWERROR(werr);
186 0 : return NULL;
187 : }
188 :
189 0 : ret = py_dnsp_DnssrvRpcRecord_get_list(records, num_records);
190 0 : talloc_free(frame);
191 0 : return ret;
192 : }
193 :
194 166 : static PyObject *py_dsdb_dns_replace(PyObject *self, PyObject *args)
195 : {
196 4 : struct ldb_context *samdb;
197 4 : PyObject *py_ldb, *py_dns_records;
198 4 : char *dns_name;
199 4 : TALLOC_CTX *frame;
200 4 : NTSTATUS status;
201 4 : WERROR werr;
202 4 : int ret;
203 4 : struct dns_server_zone *zones_list;
204 4 : struct ldb_dn *dn;
205 4 : struct dnsp_DnssrvRpcRecord *records;
206 4 : uint16_t num_records;
207 :
208 : /*
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()
212 : */
213 4 : static const int serial = 110;
214 :
215 166 : if (!PyArg_ParseTuple(args, "OsO", &py_ldb, &dns_name, &py_dns_records)) {
216 0 : return NULL;
217 : }
218 166 : PyErr_LDB_OR_RAISE(py_ldb, samdb);
219 :
220 166 : frame = talloc_stackframe();
221 :
222 166 : status = dns_common_zones(samdb, frame, NULL, &zones_list);
223 166 : if (!NT_STATUS_IS_OK(status)) {
224 0 : PyErr_SetNTSTATUS(status);
225 0 : talloc_free(frame);
226 0 : return NULL;
227 : }
228 :
229 166 : werr = dns_common_name2dn(samdb, zones_list, frame, dns_name, &dn);
230 166 : if (!W_ERROR_IS_OK(werr)) {
231 0 : PyErr_SetWERROR(werr);
232 0 : talloc_free(frame);
233 0 : return NULL;
234 : }
235 :
236 166 : ret = py_dnsp_DnssrvRpcRecord_get_array(py_dns_records,
237 : frame,
238 : &records, &num_records);
239 166 : if (ret != 0) {
240 0 : talloc_free(frame);
241 0 : return NULL;
242 : }
243 :
244 166 : werr = dns_common_replace(samdb,
245 : frame,
246 : dn,
247 : false, /* Not adding a record */
248 : serial,
249 : records,
250 : num_records);
251 166 : if (!W_ERROR_IS_OK(werr)) {
252 0 : PyErr_SetWERROR(werr);
253 0 : talloc_free(frame);
254 0 : return NULL;
255 : }
256 :
257 166 : talloc_free(frame);
258 166 : Py_RETURN_NONE;
259 : }
260 :
261 676 : static PyObject *py_dsdb_dns_replace_by_dn(PyObject *self, PyObject *args)
262 : {
263 25 : struct ldb_context *samdb;
264 25 : PyObject *py_ldb, *py_dn, *py_dns_records;
265 25 : TALLOC_CTX *frame;
266 25 : WERROR werr;
267 25 : int ret;
268 25 : struct ldb_dn *dn;
269 25 : struct dnsp_DnssrvRpcRecord *records;
270 25 : uint16_t num_records;
271 :
272 : /*
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()
276 : */
277 25 : static const int serial = 110;
278 :
279 676 : if (!PyArg_ParseTuple(args, "OOO", &py_ldb, &py_dn, &py_dns_records)) {
280 0 : return NULL;
281 : }
282 676 : PyErr_LDB_OR_RAISE(py_ldb, samdb);
283 :
284 676 : PyErr_LDB_DN_OR_RAISE(py_dn, dn);
285 :
286 676 : frame = talloc_stackframe();
287 :
288 676 : ret = py_dnsp_DnssrvRpcRecord_get_array(py_dns_records,
289 : frame,
290 : &records, &num_records);
291 676 : if (ret != 0) {
292 0 : talloc_free(frame);
293 0 : return NULL;
294 : }
295 :
296 676 : werr = dns_common_replace(samdb,
297 : frame,
298 : dn,
299 : false, /* Not adding a node */
300 : serial,
301 : records,
302 : num_records);
303 676 : if (!W_ERROR_IS_OK(werr)) {
304 0 : PyErr_SetWERROR(werr);
305 0 : talloc_free(frame);
306 0 : return NULL;
307 : }
308 :
309 676 : talloc_free(frame);
310 :
311 676 : Py_RETURN_NONE;
312 : }
313 :
314 :
315 1458 : static PyObject *py_dsdb_dns_records_match(PyObject *self, PyObject *args)
316 : {
317 0 : PyObject *py_recs[2];
318 0 : struct dnsp_DnssrvRpcRecord *rec1;
319 0 : struct dnsp_DnssrvRpcRecord *rec2;
320 0 : size_t i;
321 0 : bool type_correct;
322 0 : bool match;
323 :
324 1458 : if (!PyArg_ParseTuple(args, "OO", &py_recs[0], &py_recs[1])) {
325 0 : return NULL;
326 : }
327 :
328 4374 : for (i = 0; i < 2; i++) {
329 2916 : type_correct = py_check_dcerpc_type(py_recs[i],
330 : "samba.dcerpc.dnsp",
331 : "DnssrvRpcRecord");
332 2916 : if (! type_correct) {
333 0 : PyErr_SetString(PyExc_ValueError,
334 : "DnssrvRpcRecord expected");
335 0 : return NULL;
336 : }
337 : }
338 :
339 1458 : rec1 = (struct dnsp_DnssrvRpcRecord *)pytalloc_get_ptr(py_recs[0]);
340 1458 : rec2 = (struct dnsp_DnssrvRpcRecord *)pytalloc_get_ptr(py_recs[1]);
341 :
342 1458 : match = dns_record_match(rec1, rec2);
343 1458 : return PyBool_FromLong(match);
344 : }
345 :
346 :
347 207 : static PyObject *py_dsdb_dns_unix_to_dns_timestamp(PyObject *self, PyObject *args)
348 : {
349 0 : uint32_t timestamp;
350 0 : time_t t;
351 0 : long long lt;
352 :
353 207 : if (!PyArg_ParseTuple(args, "L", <)) {
354 0 : return NULL;
355 : }
356 :
357 207 : t = lt;
358 207 : if (t != lt) {
359 : /* time_t is presumably 32 bit here */
360 0 : PyErr_SetString(PyExc_ValueError, "Time out of range");
361 0 : return NULL;
362 : }
363 207 : timestamp = unix_to_dns_timestamp(t);
364 207 : return Py_BuildValue("k", (unsigned long) timestamp);
365 : }
366 :
367 11 : static PyObject *py_dsdb_dns_timestamp_to_nt_time(PyObject *self, PyObject *args)
368 : {
369 0 : unsigned long long timestamp;
370 0 : NTSTATUS status;
371 0 : NTTIME nt;
372 11 : if (!PyArg_ParseTuple(args, "K", ×tamp)) {
373 0 : return NULL;
374 : }
375 :
376 11 : if (timestamp > UINT32_MAX) {
377 1 : PyErr_SetString(PyExc_ValueError, "Time out of range");
378 1 : return NULL;
379 : }
380 10 : status = dns_timestamp_to_nt_time(&nt, (uint32_t)timestamp);
381 10 : if (!NT_STATUS_IS_OK(status)) {
382 2 : PyErr_SetString(PyExc_ValueError, "Time out of range");
383 2 : return NULL;
384 : }
385 8 : return Py_BuildValue("L", (long long) nt);
386 : }
387 :
388 :
389 : static PyMethodDef py_dsdb_dns_methods[] = {
390 :
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,
404 : METH_VARARGS,
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,
407 : METH_VARARGS,
408 : "Convert a dns timestamp to an NTTIME value"},
409 : {0}
410 : };
411 :
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.",
416 : .m_size = -1,
417 : .m_methods = py_dsdb_dns_methods,
418 : };
419 :
420 7630 : MODULE_INIT_FUNC(dsdb_dns)
421 : {
422 192 : PyObject *m;
423 :
424 7630 : m = PyModule_Create(&moduledef);
425 :
426 7630 : if (m == NULL)
427 0 : return NULL;
428 :
429 7438 : return m;
430 : }
|