source: vendor/current/source4/dns_server/pydns.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 7.8 KB
Line 
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 <Python.h>
23#include "includes.h"
24#include <pyldb.h>
25#include <pytalloc.h>
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"
31
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(py_ldb_get_exception(), "Ldb connection object required"); \
36 return NULL; \
37 } \
38 ldb = pyldb_Ldb_AsLdbContext(py_ldb);
39
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(py_ldb_get_exception(), "ldb Dn object required"); \
43 return NULL; \
44 } \
45 dn = pyldb_Dn_AsDn(py_ldb_dn);
46
47static PyObject *py_ldb_get_exception(void)
48{
49 PyObject *mod = PyImport_ImportModule("ldb");
50 if (mod == NULL)
51 return NULL;
52
53 return PyObject_GetAttrString(mod, "LdbError");
54}
55
56static PyObject *py_dnsp_DnssrvRpcRecord_get_list(struct dnsp_DnssrvRpcRecord *records,
57 uint16_t num_records)
58{
59 PyObject *py_dns_list;
60 int i;
61 py_dns_list = PyList_New(num_records);
62 if (py_dns_list == NULL) {
63 return NULL;
64 }
65 for (i = 0; i < num_records; i++) {
66 PyObject *py_dns_record;
67 py_dns_record = py_return_ndr_struct("samba.dcerpc.dnsp", "DnssrvRpcRecord", records, &records[i]);
68 PyList_SetItem(py_dns_list, i, py_dns_record);
69 }
70 return py_dns_list;
71}
72
73static int py_dnsp_DnssrvRpcRecord_get_array(PyObject *value,
74 TALLOC_CTX *mem_ctx,
75 struct dnsp_DnssrvRpcRecord **records,
76 uint16_t *num_records)
77{
78 int i;
79 struct dnsp_DnssrvRpcRecord *recs;
80 PY_CHECK_TYPE(&PyList_Type, value, return -1;);
81 recs = talloc_array(mem_ctx, struct dnsp_DnssrvRpcRecord,
82 PyList_GET_SIZE(value));
83 if (recs == NULL) {
84 PyErr_NoMemory();
85 return -1;
86 }
87 for (i = 0; i < PyList_GET_SIZE(value); i++) {
88 bool type_correct;
89 PyObject *item = PyList_GET_ITEM(value, i);
90 type_correct = py_check_dcerpc_type(item, "samba.dcerpc.dnsp", "DnssrvRpcRecord");
91 if (type_correct == false) {
92 return -1;
93 }
94 if (talloc_reference(mem_ctx, pytalloc_get_mem_ctx(item)) == NULL) {
95 PyErr_NoMemory();
96 return -1;
97 }
98 recs[i] = *(struct dnsp_DnssrvRpcRecord *)pytalloc_get_ptr(item);
99 }
100 *records = recs;
101 *num_records = PyList_GET_SIZE(value);
102 return 0;
103}
104
105static PyObject *py_dsdb_dns_lookup(PyObject *self, PyObject *args)
106{
107 struct ldb_context *samdb;
108 PyObject *py_ldb;
109 char *dns_name;
110 TALLOC_CTX *frame;
111 NTSTATUS status;
112 WERROR werr;
113 struct dns_server_zone *zones_list;
114 struct ldb_dn *dn;
115 struct dnsp_DnssrvRpcRecord *records;
116 uint16_t num_records;
117
118 if (!PyArg_ParseTuple(args, "Os", &py_ldb, &dns_name)) {
119 return NULL;
120 }
121 PyErr_LDB_OR_RAISE(py_ldb, samdb);
122
123 frame = talloc_stackframe();
124
125 status = dns_common_zones(samdb, frame, &zones_list);
126 if (!NT_STATUS_IS_OK(status)) {
127 PyErr_SetNTSTATUS(status);
128 return NULL;
129 }
130
131 werr = dns_common_name2dn(samdb, zones_list, frame, dns_name, &dn);
132 if (!W_ERROR_IS_OK(werr)) {
133 PyErr_SetWERROR(werr);
134 return NULL;
135 }
136
137 werr = dns_common_lookup(samdb,
138 frame,
139 dn,
140 &records,
141 &num_records,
142 NULL);
143 if (!W_ERROR_IS_OK(werr)) {
144 PyErr_SetWERROR(werr);
145 return NULL;
146 }
147
148 return py_dnsp_DnssrvRpcRecord_get_list(records, num_records);
149}
150
151static PyObject *py_dsdb_dns_extract(PyObject *self, PyObject *args)
152{
153 PyObject *py_dns_el;
154 TALLOC_CTX *frame;
155 WERROR werr;
156 struct ldb_message_element *dns_el;
157 struct dnsp_DnssrvRpcRecord *records;
158 uint16_t num_records;
159
160 if (!PyArg_ParseTuple(args, "O", &py_dns_el)) {
161 return NULL;
162 }
163
164 if (!py_check_dcerpc_type(py_dns_el, "ldb", "MessageElement")) {
165 PyErr_SetString(py_ldb_get_exception(),
166 "ldb MessageElement object required");
167 return NULL;
168 }
169 dns_el = pyldb_MessageElement_AsMessageElement(py_dns_el);
170
171 frame = talloc_stackframe();
172
173 werr = dns_common_extract(dns_el,
174 frame,
175 &records,
176 &num_records);
177 if (!W_ERROR_IS_OK(werr)) {
178 PyErr_SetWERROR(werr);
179 return NULL;
180 }
181
182 return py_dnsp_DnssrvRpcRecord_get_list(records, num_records);
183}
184
185static PyObject *py_dsdb_dns_replace(PyObject *self, PyObject *args)
186{
187 struct ldb_context *samdb;
188 PyObject *py_ldb, *py_dns_records;
189 char *dns_name;
190 TALLOC_CTX *frame;
191 NTSTATUS status;
192 WERROR werr;
193 int ret;
194 struct dns_server_zone *zones_list;
195 struct ldb_dn *dn;
196 struct dnsp_DnssrvRpcRecord *records;
197 uint16_t num_records;
198
199 /*
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()
203 */
204 static const int serial = 110;
205
206 if (!PyArg_ParseTuple(args, "OsO", &py_ldb, &dns_name, &py_dns_records)) {
207 return NULL;
208 }
209 PyErr_LDB_OR_RAISE(py_ldb, samdb);
210
211 frame = talloc_stackframe();
212
213 status = dns_common_zones(samdb, frame, &zones_list);
214 if (!NT_STATUS_IS_OK(status)) {
215 PyErr_SetNTSTATUS(status);
216 return NULL;
217 }
218
219 werr = dns_common_name2dn(samdb, zones_list, frame, dns_name, &dn);
220 if (!W_ERROR_IS_OK(werr)) {
221 PyErr_SetWERROR(werr);
222 return NULL;
223 }
224
225 ret = py_dnsp_DnssrvRpcRecord_get_array(py_dns_records,
226 frame,
227 &records, &num_records);
228 if (ret != 0) {
229 return NULL;
230 }
231
232 werr = dns_common_replace(samdb,
233 frame,
234 dn,
235 false, /* Not adding a record */
236 serial,
237 records,
238 num_records);
239 if (!W_ERROR_IS_OK(werr)) {
240 PyErr_SetWERROR(werr);
241 return NULL;
242 }
243
244 Py_RETURN_NONE;
245}
246
247static PyObject *py_dsdb_dns_replace_by_dn(PyObject *self, PyObject *args)
248{
249 struct ldb_context *samdb;
250 PyObject *py_ldb, *py_dn, *py_dns_records;
251 TALLOC_CTX *frame;
252 WERROR werr;
253 int ret;
254 struct ldb_dn *dn;
255 struct dnsp_DnssrvRpcRecord *records;
256 uint16_t num_records;
257
258 /*
259 * TODO: This is a shocking abuse, but matches what the
260 * internal DNS server does, it should be pushed into
261 * dns_common_replace()
262 */
263 static const int serial = 110;
264
265 if (!PyArg_ParseTuple(args, "OOO", &py_ldb, &py_dn, &py_dns_records)) {
266 return NULL;
267 }
268 PyErr_LDB_OR_RAISE(py_ldb, samdb);
269
270 PyErr_LDB_DN_OR_RAISE(py_dn, dn);
271
272 frame = talloc_stackframe();
273
274 ret = py_dnsp_DnssrvRpcRecord_get_array(py_dns_records,
275 frame,
276 &records, &num_records);
277 if (ret != 0) {
278 return NULL;
279 }
280
281 werr = dns_common_replace(samdb,
282 frame,
283 dn,
284 false, /* Not adding a record */
285 serial,
286 records,
287 num_records);
288 if (!W_ERROR_IS_OK(werr)) {
289 PyErr_SetWERROR(werr);
290 return NULL;
291 }
292
293 Py_RETURN_NONE;
294}
295
296static PyMethodDef py_dsdb_dns_methods[] = {
297
298 { "lookup", (PyCFunction)py_dsdb_dns_lookup,
299 METH_VARARGS, "Get the DNS database entries for a DNS name"},
300 { "replace", (PyCFunction)py_dsdb_dns_replace,
301 METH_VARARGS, "Replace the DNS database entries for a DNS name"},
302 { "replace_by_dn", (PyCFunction)py_dsdb_dns_replace_by_dn,
303 METH_VARARGS, "Replace the DNS database entries for a LDB DN"},
304 { "extract", (PyCFunction)py_dsdb_dns_extract,
305 METH_VARARGS, "Return the DNS database entry as a python structure from an Ldb.MessageElement of type dnsRecord"},
306 { NULL }
307};
308
309void initdsdb_dns(void);
310
311void initdsdb_dns(void)
312{
313 PyObject *m;
314
315 m = Py_InitModule3("dsdb_dns", py_dsdb_dns_methods,
316 "Python bindings for the DNS objects in the directory service databases.");
317 if (m == NULL)
318 return;
319}
Note: See TracBrowser for help on using the repository browser.