pydsdb_dns: Use TypeError not LdbError for mismatched types
[metze/samba/wip.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 "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(PyExc_TypeError, "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(PyExc_TypeError, "ldb Dn object required"); \
43                 return NULL; \
44         } \
45         dn = pyldb_Dn_AsDn(py_ldb_dn);
46
47 static PyObject *py_dnsp_DnssrvRpcRecord_get_list(struct dnsp_DnssrvRpcRecord *records,
48                                                   uint16_t num_records)
49 {
50         PyObject *py_dns_list;
51         int i;
52         py_dns_list = PyList_New(num_records);
53         if (py_dns_list == NULL) {
54                 return NULL;
55         }
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);
60         }
61         return py_dns_list;
62 }
63
64 static int py_dnsp_DnssrvRpcRecord_get_array(PyObject *value,
65                                              TALLOC_CTX *mem_ctx,
66                                              struct dnsp_DnssrvRpcRecord **records,
67                                              uint16_t *num_records)
68 {
69         int i;
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));
74         if (recs == NULL) {
75                 PyErr_NoMemory();
76                 return -1;
77         }
78         for (i = 0; i < PyList_GET_SIZE(value); i++) {
79                 bool type_correct;
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) {
83                         return -1;
84                 }
85                 if (talloc_reference(mem_ctx, pytalloc_get_mem_ctx(item)) == NULL) {
86                         PyErr_NoMemory();
87                         return -1;
88                 }
89                 recs[i] = *(struct dnsp_DnssrvRpcRecord *)pytalloc_get_ptr(item);
90         }
91         *records = recs;
92         *num_records = PyList_GET_SIZE(value);
93         return 0;
94 }
95
96 static PyObject *py_dsdb_dns_lookup(PyObject *self, PyObject *args)
97 {
98         struct ldb_context *samdb;
99         PyObject *py_ldb, *ret, *pydn;
100         char *dns_name;
101         TALLOC_CTX *frame;
102         NTSTATUS status;
103         WERROR werr;
104         struct dns_server_zone *zones_list;
105         struct ldb_dn *dn;
106         struct dnsp_DnssrvRpcRecord *records;
107         uint16_t num_records;
108
109         if (!PyArg_ParseTuple(args, "Os", &py_ldb, &dns_name)) {
110                 return NULL;
111         }
112         PyErr_LDB_OR_RAISE(py_ldb, samdb);
113
114         frame = talloc_stackframe();
115
116         status = dns_common_zones(samdb, frame, &zones_list);
117         if (!NT_STATUS_IS_OK(status)) {
118                 talloc_free(frame);
119                 PyErr_SetNTSTATUS(status);
120                 return NULL;
121         }
122
123         werr = dns_common_name2dn(samdb, zones_list, frame, dns_name, &dn);
124         if (!W_ERROR_IS_OK(werr)) {
125                 talloc_free(frame);
126                 PyErr_SetWERROR(werr);
127                 return NULL;
128         }
129
130         werr = dns_common_lookup(samdb,
131                                  frame,
132                                  dn,
133                                  &records,
134                                  &num_records,
135                                  NULL);
136         if (!W_ERROR_IS_OK(werr)) {
137                 talloc_free(frame);
138                 PyErr_SetWERROR(werr);
139                 return NULL;
140         }
141
142         ret = py_dnsp_DnssrvRpcRecord_get_list(records, num_records);
143         pydn = pyldb_Dn_FromDn(dn);
144         talloc_free(frame);
145         return Py_BuildValue("(OO)", pydn, ret);
146 }
147
148 static PyObject *py_dsdb_dns_extract(PyObject *self, PyObject *args)
149 {
150         PyObject *py_dns_el, *ret;
151         TALLOC_CTX *frame;
152         WERROR werr;
153         struct ldb_message_element *dns_el;
154         struct dnsp_DnssrvRpcRecord *records;
155         uint16_t num_records;
156
157         if (!PyArg_ParseTuple(args, "O", &py_dns_el)) {
158                 return NULL;
159         }
160
161         if (!py_check_dcerpc_type(py_dns_el, "ldb", "MessageElement")) {
162                 PyErr_SetString(PyExc_TypeError,
163                                 "ldb MessageElement object required");
164                 return NULL;
165         }
166         dns_el = pyldb_MessageElement_AsMessageElement(py_dns_el);
167
168         frame = talloc_stackframe();
169
170         werr = dns_common_extract(dns_el,
171                                   frame,
172                                   &records,
173                                   &num_records);
174         if (!W_ERROR_IS_OK(werr)) {
175                 talloc_free(frame);
176                 PyErr_SetWERROR(werr);
177                 return NULL;
178         }
179
180         ret = py_dnsp_DnssrvRpcRecord_get_list(records, num_records);
181         talloc_free(frame);
182         return ret;
183 }
184
185 static 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                 talloc_free(frame);
217                 return NULL;
218         }
219
220         werr = dns_common_name2dn(samdb, zones_list, frame, dns_name, &dn);
221         if (!W_ERROR_IS_OK(werr)) {
222                 PyErr_SetWERROR(werr);
223                 talloc_free(frame);
224                 return NULL;
225         }
226
227         ret = py_dnsp_DnssrvRpcRecord_get_array(py_dns_records,
228                                                 frame,
229                                                 &records, &num_records);
230         if (ret != 0) {
231                 talloc_free(frame);
232                 return NULL;
233         }
234
235         werr = dns_common_replace(samdb,
236                                   frame,
237                                   dn,
238                                   false, /* Not adding a record */
239                                   serial,
240                                   records,
241                                   num_records);
242         if (!W_ERROR_IS_OK(werr)) {
243                 PyErr_SetWERROR(werr);
244                 talloc_free(frame);
245                 return NULL;
246         }
247
248         talloc_free(frame);
249         Py_RETURN_NONE;
250 }
251
252 static PyObject *py_dsdb_dns_replace_by_dn(PyObject *self, PyObject *args)
253 {
254         struct ldb_context *samdb;
255         PyObject *py_ldb, *py_dn, *py_dns_records;
256         TALLOC_CTX *frame;
257         WERROR werr;
258         int ret;
259         struct ldb_dn *dn;
260         struct dnsp_DnssrvRpcRecord *records;
261         uint16_t num_records;
262
263         /*
264          * TODO: This is a shocking abuse, but matches what the
265          * internal DNS server does, it should be pushed into
266          * dns_common_replace()
267          */
268         static const int serial = 110;
269
270         if (!PyArg_ParseTuple(args, "OOO", &py_ldb, &py_dn, &py_dns_records)) {
271                 return NULL;
272         }
273         PyErr_LDB_OR_RAISE(py_ldb, samdb);
274
275         PyErr_LDB_DN_OR_RAISE(py_dn, dn);
276
277         frame = talloc_stackframe();
278
279         ret = py_dnsp_DnssrvRpcRecord_get_array(py_dns_records,
280                                                 frame,
281                                                 &records, &num_records);
282         if (ret != 0) {
283                 talloc_free(frame);
284                 return NULL;
285         }
286
287         werr = dns_common_replace(samdb,
288                                   frame,
289                                   dn,
290                                   false, /* Not adding a record */
291                                   serial,
292                                   records,
293                                   num_records);
294         if (!W_ERROR_IS_OK(werr)) {
295                 PyErr_SetWERROR(werr);
296                 talloc_free(frame);
297                 return NULL;
298         }
299
300         talloc_free(frame);
301
302         Py_RETURN_NONE;
303 }
304
305 static PyMethodDef py_dsdb_dns_methods[] = {
306
307         { "lookup", (PyCFunction)py_dsdb_dns_lookup,
308                 METH_VARARGS, "Get the DNS database entries for a DNS name"},
309         { "replace", (PyCFunction)py_dsdb_dns_replace,
310                 METH_VARARGS, "Replace the DNS database entries for a DNS name"},
311         { "replace_by_dn", (PyCFunction)py_dsdb_dns_replace_by_dn,
312                 METH_VARARGS, "Replace the DNS database entries for a LDB DN"},
313         { "extract", (PyCFunction)py_dsdb_dns_extract,
314                 METH_VARARGS, "Return the DNS database entry as a python structure from an Ldb.MessageElement of type dnsRecord"},
315         { NULL }
316 };
317
318 void initdsdb_dns(void);
319
320 void initdsdb_dns(void)
321 {
322         PyObject *m;
323
324         m = Py_InitModule3("dsdb_dns", py_dsdb_dns_methods,
325                            "Python bindings for the DNS objects in the directory service databases.");
326         if (m == NULL)
327                 return;
328 }