ctdb-recoverd: Call an election when the recovery lock is lost
[samba.git] / source4 / dns_server / pydns.c
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 "python/py3compat.h"
24 #include "includes.h"
25 #include <pyldb.h>
26 #include <pytalloc.h>
27 #include "dns_server/dnsserver_common.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "dsdb/common/util.h"
30 #include "librpc/gen_ndr/ndr_dnsp.h"
31 #include "librpc/rpc/pyrpc_util.h"
32
33 /* FIXME: These should be in a header file somewhere */
34 #define PyErr_LDB_OR_RAISE(py_ldb, ldb) \
35         if (!py_check_dcerpc_type(py_ldb, "ldb", "Ldb")) { \
36                 PyErr_SetString(PyExc_TypeError, "Ldb connection object required"); \
37                 return NULL; \
38         } \
39         ldb = pyldb_Ldb_AsLdbContext(py_ldb);
40
41 #define PyErr_LDB_DN_OR_RAISE(py_ldb_dn, dn) \
42         if (!py_check_dcerpc_type(py_ldb_dn, "ldb", "Dn")) { \
43                 PyErr_SetString(PyExc_TypeError, "ldb Dn object required"); \
44                 return NULL; \
45         } \
46         dn = pyldb_Dn_AsDn(py_ldb_dn);
47
48 static PyObject *py_dnsp_DnssrvRpcRecord_get_list(struct dnsp_DnssrvRpcRecord *records,
49                                                   uint16_t num_records)
50 {
51         PyObject *py_dns_list;
52         int i;
53         py_dns_list = PyList_New(num_records);
54         if (py_dns_list == NULL) {
55                 return NULL;
56         }
57         for (i = 0; i < num_records; i++) {
58                 PyObject *py_dns_record;
59                 py_dns_record = py_return_ndr_struct("samba.dcerpc.dnsp", "DnssrvRpcRecord", records, &records[i]);
60                 PyList_SetItem(py_dns_list, i, py_dns_record);
61         }
62         return py_dns_list;
63 }
64
65 static int py_dnsp_DnssrvRpcRecord_get_array(PyObject *value,
66                                              TALLOC_CTX *mem_ctx,
67                                              struct dnsp_DnssrvRpcRecord **records,
68                                              uint16_t *num_records)
69 {
70         int i;
71         struct dnsp_DnssrvRpcRecord *recs;
72         PY_CHECK_TYPE(&PyList_Type, value, return -1;);
73         recs = talloc_array(mem_ctx, struct dnsp_DnssrvRpcRecord,
74                             PyList_GET_SIZE(value));
75         if (recs == NULL) {
76                 PyErr_NoMemory();
77                 return -1;
78         }
79         for (i = 0; i < PyList_GET_SIZE(value); i++) {
80                 bool type_correct;
81                 PyObject *item = PyList_GET_ITEM(value, i);
82                 type_correct = py_check_dcerpc_type(item, "samba.dcerpc.dnsp", "DnssrvRpcRecord");
83                 if (type_correct == false) {
84                         return -1;
85                 }
86                 if (talloc_reference(mem_ctx, pytalloc_get_mem_ctx(item)) == NULL) {
87                         PyErr_NoMemory();
88                         return -1;
89                 }
90                 recs[i] = *(struct dnsp_DnssrvRpcRecord *)pytalloc_get_ptr(item);
91         }
92         *records = recs;
93         *num_records = PyList_GET_SIZE(value);
94         return 0;
95 }
96
97 static PyObject *py_dsdb_dns_lookup(PyObject *self,
98                                     PyObject *args, PyObject *kwargs)
99 {
100         struct ldb_context *samdb;
101         PyObject *py_ldb, *ret, *pydn;
102         PyObject *py_dns_partition = NULL;
103         char *dns_name;
104         TALLOC_CTX *frame;
105         NTSTATUS status;
106         WERROR werr;
107         struct dns_server_zone *zones_list;
108         struct ldb_dn *dn, *dns_partition = NULL;
109         struct dnsp_DnssrvRpcRecord *records;
110         uint16_t num_records;
111         const char * const kwnames[] = { "ldb", "dns_name",
112                                          "dns_partition", NULL };
113
114         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Os|O",
115                                          discard_const_p(char *, kwnames),
116                                          &py_ldb, &dns_name,
117                                          &py_dns_partition)) {
118                 return NULL;
119         }
120         PyErr_LDB_OR_RAISE(py_ldb, samdb);
121
122         if (py_dns_partition) {
123                 PyErr_LDB_DN_OR_RAISE(py_dns_partition,
124                                       dns_partition);
125         }
126
127         frame = talloc_stackframe();
128
129         status = dns_common_zones(samdb, frame, dns_partition,
130                                   &zones_list);
131         if (!NT_STATUS_IS_OK(status)) {
132                 talloc_free(frame);
133                 PyErr_SetNTSTATUS(status);
134                 return NULL;
135         }
136
137         werr = dns_common_name2dn(samdb, zones_list, frame, dns_name, &dn);
138         if (!W_ERROR_IS_OK(werr)) {
139                 talloc_free(frame);
140                 PyErr_SetWERROR(werr);
141                 return NULL;
142         }
143
144         werr = dns_common_lookup(samdb,
145                                  frame,
146                                  dn,
147                                  &records,
148                                  &num_records,
149                                  NULL);
150         if (!W_ERROR_IS_OK(werr)) {
151                 talloc_free(frame);
152                 PyErr_SetWERROR(werr);
153                 return NULL;
154         }
155
156         ret = py_dnsp_DnssrvRpcRecord_get_list(records, num_records);
157         pydn = pyldb_Dn_FromDn(dn);
158         talloc_free(frame);
159         return Py_BuildValue("(OO)", pydn, ret);
160 }
161
162 static PyObject *py_dsdb_dns_extract(PyObject *self, PyObject *args)
163 {
164         struct ldb_context *samdb;
165         PyObject *py_dns_el, *ret;
166         PyObject *py_ldb = NULL;
167         TALLOC_CTX *frame;
168         WERROR werr;
169         struct ldb_message_element *dns_el;
170         struct dnsp_DnssrvRpcRecord *records;
171         uint16_t num_records;
172
173         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_dns_el)) {
174                 return NULL;
175         }
176
177         PyErr_LDB_OR_RAISE(py_ldb, samdb);
178
179         if (!py_check_dcerpc_type(py_dns_el, "ldb", "MessageElement")) {
180                 PyErr_SetString(PyExc_TypeError,
181                                 "ldb MessageElement object required");
182                 return NULL;
183         }
184         dns_el = pyldb_MessageElement_AsMessageElement(py_dns_el);
185
186         frame = talloc_stackframe();
187
188         werr = dns_common_extract(samdb, dns_el,
189                                   frame,
190                                   &records,
191                                   &num_records);
192         if (!W_ERROR_IS_OK(werr)) {
193                 talloc_free(frame);
194                 PyErr_SetWERROR(werr);
195                 return NULL;
196         }
197
198         ret = py_dnsp_DnssrvRpcRecord_get_list(records, num_records);
199         talloc_free(frame);
200         return ret;
201 }
202
203 static PyObject *py_dsdb_dns_replace(PyObject *self, PyObject *args)
204 {
205         struct ldb_context *samdb;
206         PyObject *py_ldb, *py_dns_records;
207         char *dns_name;
208         TALLOC_CTX *frame;
209         NTSTATUS status;
210         WERROR werr;
211         int ret;
212         struct dns_server_zone *zones_list;
213         struct ldb_dn *dn;
214         struct dnsp_DnssrvRpcRecord *records;
215         uint16_t num_records;
216
217         /*
218          * TODO: This is a shocking abuse, but matches what the
219          * internal DNS server does, it should be pushed into
220          * dns_common_replace()
221          */
222         static const int serial = 110;
223
224         if (!PyArg_ParseTuple(args, "OsO", &py_ldb, &dns_name, &py_dns_records)) {
225                 return NULL;
226         }
227         PyErr_LDB_OR_RAISE(py_ldb, samdb);
228
229         frame = talloc_stackframe();
230
231         status = dns_common_zones(samdb, frame, NULL, &zones_list);
232         if (!NT_STATUS_IS_OK(status)) {
233                 PyErr_SetNTSTATUS(status);
234                 talloc_free(frame);
235                 return NULL;
236         }
237
238         werr = dns_common_name2dn(samdb, zones_list, frame, dns_name, &dn);
239         if (!W_ERROR_IS_OK(werr)) {
240                 PyErr_SetWERROR(werr);
241                 talloc_free(frame);
242                 return NULL;
243         }
244
245         ret = py_dnsp_DnssrvRpcRecord_get_array(py_dns_records,
246                                                 frame,
247                                                 &records, &num_records);
248         if (ret != 0) {
249                 talloc_free(frame);
250                 return NULL;
251         }
252
253         werr = dns_common_replace(samdb,
254                                   frame,
255                                   dn,
256                                   false, /* Not adding a record */
257                                   serial,
258                                   records,
259                                   num_records);
260         if (!W_ERROR_IS_OK(werr)) {
261                 PyErr_SetWERROR(werr);
262                 talloc_free(frame);
263                 return NULL;
264         }
265
266         talloc_free(frame);
267         Py_RETURN_NONE;
268 }
269
270 static PyObject *py_dsdb_dns_replace_by_dn(PyObject *self, PyObject *args)
271 {
272         struct ldb_context *samdb;
273         PyObject *py_ldb, *py_dn, *py_dns_records;
274         TALLOC_CTX *frame;
275         WERROR werr;
276         int ret;
277         struct ldb_dn *dn;
278         struct dnsp_DnssrvRpcRecord *records;
279         uint16_t num_records;
280
281         /*
282          * TODO: This is a shocking abuse, but matches what the
283          * internal DNS server does, it should be pushed into
284          * dns_common_replace()
285          */
286         static const int serial = 110;
287
288         if (!PyArg_ParseTuple(args, "OOO", &py_ldb, &py_dn, &py_dns_records)) {
289                 return NULL;
290         }
291         PyErr_LDB_OR_RAISE(py_ldb, samdb);
292
293         PyErr_LDB_DN_OR_RAISE(py_dn, dn);
294
295         frame = talloc_stackframe();
296
297         ret = py_dnsp_DnssrvRpcRecord_get_array(py_dns_records,
298                                                 frame,
299                                                 &records, &num_records);
300         if (ret != 0) {
301                 talloc_free(frame);
302                 return NULL;
303         }
304
305         werr = dns_common_replace(samdb,
306                                   frame,
307                                   dn,
308                                   false, /* Not adding a record */
309                                   serial,
310                                   records,
311                                   num_records);
312         if (!W_ERROR_IS_OK(werr)) {
313                 PyErr_SetWERROR(werr);
314                 talloc_free(frame);
315                 return NULL;
316         }
317
318         talloc_free(frame);
319
320         Py_RETURN_NONE;
321 }
322
323 static PyMethodDef py_dsdb_dns_methods[] = {
324
325         { "lookup", (PyCFunction)py_dsdb_dns_lookup,
326                 METH_VARARGS|METH_KEYWORDS,
327                 "Get the DNS database entries for a DNS name"},
328         { "replace", (PyCFunction)py_dsdb_dns_replace,
329                 METH_VARARGS, "Replace the DNS database entries for a DNS name"},
330         { "replace_by_dn", (PyCFunction)py_dsdb_dns_replace_by_dn,
331                 METH_VARARGS, "Replace the DNS database entries for a LDB DN"},
332         { "extract", (PyCFunction)py_dsdb_dns_extract,
333                 METH_VARARGS, "Return the DNS database entry as a python structure from an Ldb.MessageElement of type dnsRecord"},
334         { NULL }
335 };
336
337 static struct PyModuleDef moduledef = {
338     PyModuleDef_HEAD_INIT,
339     .m_name = "dsdb_dns",
340     .m_doc = "Python bindings for the DNS objects in the directory service databases.",
341     .m_size = -1,
342     .m_methods = py_dsdb_dns_methods,
343 };
344
345 MODULE_INIT_FUNC(dsdb_dns)
346 {
347         PyObject *m;
348
349         m = PyModule_Create(&moduledef);
350
351         if (m == NULL)
352                 return NULL;
353
354         return m;
355 }