LCOV - code coverage report
Current view: top level - source4/dns_server - pydns.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 103 157 65.6 %
Date: 2021-08-25 13:27:56 Functions: 9 10 90.0 %

          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 <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             : /* FIXME: These should be in a header file somewhere */
      35             : #define PyErr_LDB_OR_RAISE(py_ldb, ldb) \
      36             :         if (!py_check_dcerpc_type(py_ldb, "ldb", "Ldb")) { \
      37             :                 PyErr_SetString(PyExc_TypeError, "Ldb connection object required"); \
      38             :                 return NULL; \
      39             :         } \
      40             :         ldb = pyldb_Ldb_AsLdbContext(py_ldb);
      41             : 
      42             : #define PyErr_LDB_DN_OR_RAISE(py_ldb_dn, dn) \
      43             :         if (!py_check_dcerpc_type(py_ldb_dn, "ldb", "Dn")) { \
      44             :                 PyErr_SetString(PyExc_TypeError, "ldb Dn object required"); \
      45             :                 return NULL; \
      46             :         } \
      47             :         dn = pyldb_Dn_AS_DN(py_ldb_dn);
      48             : 
      49         439 : static PyObject *py_dnsp_DnssrvRpcRecord_get_list(struct dnsp_DnssrvRpcRecord *records,
      50             :                                                   uint16_t num_records)
      51             : {
      52             :         PyObject *py_dns_list;
      53             :         int i;
      54         439 :         py_dns_list = PyList_New(num_records);
      55         439 :         if (py_dns_list == NULL) {
      56           0 :                 return NULL;
      57             :         }
      58        1823 :         for (i = 0; i < num_records; i++) {
      59             :                 PyObject *py_dns_record;
      60        1388 :                 py_dns_record = py_return_ndr_struct("samba.dcerpc.dnsp", "DnssrvRpcRecord", records, &records[i]);
      61        1388 :                 PyList_SetItem(py_dns_list, i, py_dns_record);
      62             :         }
      63         435 :         return py_dns_list;
      64             : }
      65             : 
      66             : 
      67        1064 : static int py_dnsp_DnssrvRpcRecord_get_array(PyObject *value,
      68             :                                              TALLOC_CTX *mem_ctx,
      69             :                                              struct dnsp_DnssrvRpcRecord **records,
      70             :                                              uint16_t *num_records)
      71             : {
      72             :         int i;
      73             :         struct dnsp_DnssrvRpcRecord *recs;
      74        1064 :         PY_CHECK_TYPE(&PyList_Type, value, return -1;);
      75        1064 :         recs = talloc_array(mem_ctx, struct dnsp_DnssrvRpcRecord,
      76             :                             PyList_GET_SIZE(value));
      77        1064 :         if (recs == NULL) {
      78           0 :                 PyErr_NoMemory();
      79           0 :                 return -1;
      80             :         }
      81        1478 :         for (i = 0; i < PyList_GET_SIZE(value); i++) {
      82             :                 bool type_correct;
      83         443 :                 PyObject *item = PyList_GET_ITEM(value, i);
      84         443 :                 type_correct = py_check_dcerpc_type(item, "samba.dcerpc.dnsp", "DnssrvRpcRecord");
      85         443 :                 if (type_correct == false) {
      86           0 :                         return -1;
      87             :                 }
      88         443 :                 if (talloc_reference(mem_ctx, pytalloc_get_mem_ctx(item)) == NULL) {
      89           0 :                         PyErr_NoMemory();
      90           0 :                         return -1;
      91             :                 }
      92         443 :                 recs[i] = *(struct dnsp_DnssrvRpcRecord *)pytalloc_get_ptr(item);
      93             :         }
      94        1064 :         *records = recs;
      95        1064 :         *num_records = PyList_GET_SIZE(value);
      96        1064 :         return 0;
      97             : }
      98             : 
      99         461 : static PyObject *py_dsdb_dns_lookup(PyObject *self,
     100             :                                     PyObject *args, PyObject *kwargs)
     101             : {
     102             :         struct ldb_context *samdb;
     103             :         PyObject *py_ldb, *ret, *pydn;
     104         461 :         PyObject *py_dns_partition = NULL;
     105         461 :         PyObject *result = NULL;
     106             :         char *dns_name;
     107             :         TALLOC_CTX *frame;
     108             :         NTSTATUS status;
     109             :         WERROR werr;
     110             :         struct dns_server_zone *zones_list;
     111         461 :         struct ldb_dn *dn, *dns_partition = NULL;
     112             :         struct dnsp_DnssrvRpcRecord *records;
     113             :         uint16_t num_records;
     114         461 :         const char * const kwnames[] = { "ldb", "dns_name",
     115             :                                          "dns_partition", NULL };
     116             : 
     117         461 :         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Os|O",
     118             :                                          discard_const_p(char *, kwnames),
     119             :                                          &py_ldb, &dns_name,
     120             :                                          &py_dns_partition)) {
     121           0 :                 return NULL;
     122             :         }
     123         461 :         PyErr_LDB_OR_RAISE(py_ldb, samdb);
     124             : 
     125         461 :         if (py_dns_partition) {
     126          89 :                 PyErr_LDB_DN_OR_RAISE(py_dns_partition,
     127             :                                       dns_partition);
     128             :         }
     129             : 
     130         461 :         frame = talloc_stackframe();
     131             : 
     132         461 :         status = dns_common_zones(samdb, frame, dns_partition,
     133             :                                   &zones_list);
     134         461 :         if (!NT_STATUS_IS_OK(status)) {
     135           0 :                 talloc_free(frame);
     136           0 :                 PyErr_SetNTSTATUS(status);
     137           0 :                 return NULL;
     138             :         }
     139             : 
     140         461 :         werr = dns_common_name2dn(samdb, zones_list, frame, dns_name, &dn);
     141         461 :         if (!W_ERROR_IS_OK(werr)) {
     142          12 :                 talloc_free(frame);
     143          12 :                 PyErr_SetWERROR(werr);
     144          12 :                 return NULL;
     145             :         }
     146             : 
     147         449 :         werr = dns_common_lookup(samdb,
     148             :                                  frame,
     149             :                                  dn,
     150             :                                  &records,
     151             :                                  &num_records,
     152             :                                  NULL);
     153         449 :         if (!W_ERROR_IS_OK(werr)) {
     154          10 :                 talloc_free(frame);
     155          10 :                 PyErr_SetWERROR(werr);
     156          10 :                 return NULL;
     157             :         }
     158             : 
     159         439 :         ret = py_dnsp_DnssrvRpcRecord_get_list(records, num_records);
     160         439 :         pydn = pyldb_Dn_FromDn(dn);
     161         439 :         talloc_free(frame);
     162         439 :         result = Py_BuildValue("(OO)", pydn, ret);
     163         439 :         Py_CLEAR(ret);
     164         439 :         Py_CLEAR(pydn);
     165         435 :         return result;
     166             : }
     167             : 
     168           0 : static PyObject *py_dsdb_dns_extract(PyObject *self, PyObject *args)
     169             : {
     170             :         struct ldb_context *samdb;
     171             :         PyObject *py_dns_el, *ret;
     172           0 :         PyObject *py_ldb = NULL;
     173             :         TALLOC_CTX *frame;
     174             :         WERROR werr;
     175             :         struct ldb_message_element *dns_el;
     176             :         struct dnsp_DnssrvRpcRecord *records;
     177             :         uint16_t num_records;
     178             : 
     179           0 :         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_dns_el)) {
     180           0 :                 return NULL;
     181             :         }
     182             : 
     183           0 :         PyErr_LDB_OR_RAISE(py_ldb, samdb);
     184             : 
     185           0 :         if (!py_check_dcerpc_type(py_dns_el, "ldb", "MessageElement")) {
     186           0 :                 PyErr_SetString(PyExc_TypeError,
     187             :                                 "ldb MessageElement object required");
     188           0 :                 return NULL;
     189             :         }
     190           0 :         dns_el = pyldb_MessageElement_AsMessageElement(py_dns_el);
     191             : 
     192           0 :         frame = talloc_stackframe();
     193             : 
     194           0 :         werr = dns_common_extract(samdb, dns_el,
     195             :                                   frame,
     196             :                                   &records,
     197             :                                   &num_records);
     198           0 :         if (!W_ERROR_IS_OK(werr)) {
     199           0 :                 talloc_free(frame);
     200           0 :                 PyErr_SetWERROR(werr);
     201           0 :                 return NULL;
     202             :         }
     203             : 
     204           0 :         ret = py_dnsp_DnssrvRpcRecord_get_list(records, num_records);
     205           0 :         talloc_free(frame);
     206           0 :         return ret;
     207             : }
     208             : 
     209         206 : static PyObject *py_dsdb_dns_replace(PyObject *self, PyObject *args)
     210             : {
     211             :         struct ldb_context *samdb;
     212             :         PyObject *py_ldb, *py_dns_records;
     213             :         char *dns_name;
     214             :         TALLOC_CTX *frame;
     215             :         NTSTATUS status;
     216             :         WERROR werr;
     217             :         int ret;
     218             :         struct dns_server_zone *zones_list;
     219             :         struct ldb_dn *dn;
     220             :         struct dnsp_DnssrvRpcRecord *records;
     221             :         uint16_t num_records;
     222             : 
     223             :         /*
     224             :          * TODO: This is a shocking abuse, but matches what the
     225             :          * internal DNS server does, it should be pushed into
     226             :          * dns_common_replace()
     227             :          */
     228             :         static const int serial = 110;
     229             : 
     230         206 :         if (!PyArg_ParseTuple(args, "OsO", &py_ldb, &dns_name, &py_dns_records)) {
     231           0 :                 return NULL;
     232             :         }
     233         206 :         PyErr_LDB_OR_RAISE(py_ldb, samdb);
     234             : 
     235         206 :         frame = talloc_stackframe();
     236             : 
     237         206 :         status = dns_common_zones(samdb, frame, NULL, &zones_list);
     238         206 :         if (!NT_STATUS_IS_OK(status)) {
     239           0 :                 PyErr_SetNTSTATUS(status);
     240           0 :                 talloc_free(frame);
     241           0 :                 return NULL;
     242             :         }
     243             : 
     244         206 :         werr = dns_common_name2dn(samdb, zones_list, frame, dns_name, &dn);
     245         206 :         if (!W_ERROR_IS_OK(werr)) {
     246           0 :                 PyErr_SetWERROR(werr);
     247           0 :                 talloc_free(frame);
     248           0 :                 return NULL;
     249             :         }
     250             : 
     251         206 :         ret = py_dnsp_DnssrvRpcRecord_get_array(py_dns_records,
     252             :                                                 frame,
     253             :                                                 &records, &num_records);
     254         206 :         if (ret != 0) {
     255           0 :                 talloc_free(frame);
     256           0 :                 return NULL;
     257             :         }
     258             : 
     259         206 :         werr = dns_common_replace(samdb,
     260             :                                   frame,
     261             :                                   dn,
     262             :                                   false, /* Not adding a record */
     263             :                                   serial,
     264             :                                   records,
     265             :                                   num_records);
     266         206 :         if (!W_ERROR_IS_OK(werr)) {
     267           0 :                 PyErr_SetWERROR(werr);
     268           0 :                 talloc_free(frame);
     269           0 :                 return NULL;
     270             :         }
     271             : 
     272         206 :         talloc_free(frame);
     273         206 :         Py_RETURN_NONE;
     274             : }
     275             : 
     276         858 : static PyObject *py_dsdb_dns_replace_by_dn(PyObject *self, PyObject *args)
     277             : {
     278             :         struct ldb_context *samdb;
     279             :         PyObject *py_ldb, *py_dn, *py_dns_records;
     280             :         TALLOC_CTX *frame;
     281             :         WERROR werr;
     282             :         int ret;
     283             :         struct ldb_dn *dn;
     284             :         struct dnsp_DnssrvRpcRecord *records;
     285             :         uint16_t num_records;
     286             : 
     287             :         /*
     288             :          * TODO: This is a shocking abuse, but matches what the
     289             :          * internal DNS server does, it should be pushed into
     290             :          * dns_common_replace()
     291             :          */
     292             :         static const int serial = 110;
     293             : 
     294         858 :         if (!PyArg_ParseTuple(args, "OOO", &py_ldb, &py_dn, &py_dns_records)) {
     295           0 :                 return NULL;
     296             :         }
     297         858 :         PyErr_LDB_OR_RAISE(py_ldb, samdb);
     298             : 
     299         858 :         PyErr_LDB_DN_OR_RAISE(py_dn, dn);
     300             : 
     301         858 :         frame = talloc_stackframe();
     302             : 
     303         858 :         ret = py_dnsp_DnssrvRpcRecord_get_array(py_dns_records,
     304             :                                                 frame,
     305             :                                                 &records, &num_records);
     306         858 :         if (ret != 0) {
     307           0 :                 talloc_free(frame);
     308           0 :                 return NULL;
     309             :         }
     310             : 
     311         858 :         werr = dns_common_replace(samdb,
     312             :                                   frame,
     313             :                                   dn,
     314             :                                   false, /* Not adding a node */
     315             :                                   serial,
     316             :                                   records,
     317             :                                   num_records);
     318         858 :         if (!W_ERROR_IS_OK(werr)) {
     319           0 :                 PyErr_SetWERROR(werr);
     320           0 :                 talloc_free(frame);
     321           0 :                 return NULL;
     322             :         }
     323             : 
     324         858 :         talloc_free(frame);
     325             : 
     326         858 :         Py_RETURN_NONE;
     327             : }
     328             : 
     329             : 
     330        2187 : static PyObject *py_dsdb_dns_records_match(PyObject *self, PyObject *args)
     331             : {
     332             :         PyObject *py_recs[2];
     333             :         struct dnsp_DnssrvRpcRecord *rec1;
     334             :         struct dnsp_DnssrvRpcRecord *rec2;
     335             :         size_t i;
     336             :         bool type_correct;
     337             :         bool match;
     338             : 
     339        2187 :         if (!PyArg_ParseTuple(args, "OO", &py_recs[0], &py_recs[1])) {
     340           0 :                 return NULL;
     341             :         }
     342             : 
     343        6561 :         for (i = 0; i < 2; i++) {
     344        4374 :                 type_correct = py_check_dcerpc_type(py_recs[i],
     345             :                                                     "samba.dcerpc.dnsp",
     346             :                                                     "DnssrvRpcRecord");
     347        4374 :                 if (! type_correct) {
     348           0 :                         PyErr_SetString(PyExc_ValueError,
     349             :                                         "DnssrvRpcRecord expected");
     350           0 :                         return NULL;
     351             :                 }
     352             :         }
     353             : 
     354        2187 :         rec1 = (struct dnsp_DnssrvRpcRecord *)pytalloc_get_ptr(py_recs[0]);
     355        2187 :         rec2 = (struct dnsp_DnssrvRpcRecord *)pytalloc_get_ptr(py_recs[1]);
     356             : 
     357        2187 :         match = dns_record_match(rec1, rec2);
     358        2187 :         return PyBool_FromLong(match);
     359             : }
     360             : 
     361             : 
     362         293 : static PyObject *py_dsdb_dns_unix_to_dns_timestamp(PyObject *self, PyObject *args)
     363             : {
     364             :         uint32_t timestamp;
     365             :         time_t t;
     366             :         long long lt;
     367             : 
     368         293 :         if (!PyArg_ParseTuple(args, "L", &lt)) {
     369           0 :                 return NULL;
     370             :         }
     371             : 
     372         293 :         t = lt;
     373         293 :         if (t != lt) {
     374             :                 /* time_t is presumably 32 bit here */
     375           0 :                 PyErr_SetString(PyExc_ValueError, "Time out of range");
     376           0 :                 return NULL;
     377             :         }
     378         293 :         timestamp = unix_to_dns_timestamp(t);
     379         293 :         return Py_BuildValue("k", (unsigned long) timestamp);
     380             : }
     381             : 
     382          13 : static PyObject *py_dsdb_dns_timestamp_to_nt_time(PyObject *self, PyObject *args)
     383             : {
     384             :         unsigned long long timestamp;
     385             :         NTSTATUS status;
     386             :         NTTIME nt;
     387          13 :         if (!PyArg_ParseTuple(args, "K", &timestamp)) {
     388           0 :                 return NULL;
     389             :         }
     390             : 
     391          13 :         if (timestamp > UINT32_MAX || timestamp < 0) {
     392           1 :                 PyErr_SetString(PyExc_ValueError, "Time out of range");
     393           1 :                 return NULL;
     394             :         }
     395          12 :         status = dns_timestamp_to_nt_time(&nt, (uint32_t)timestamp);
     396          12 :         if (!NT_STATUS_IS_OK(status)) {
     397           2 :                 PyErr_SetString(PyExc_ValueError, "Time out of range");
     398           2 :                 return NULL;
     399             :         }
     400          10 :         return Py_BuildValue("L", (long long) nt);
     401             : }
     402             : 
     403             : 
     404             : static PyMethodDef py_dsdb_dns_methods[] = {
     405             : 
     406             :         { "lookup", PY_DISCARD_FUNC_SIG(PyCFunction, py_dsdb_dns_lookup),
     407             :                 METH_VARARGS|METH_KEYWORDS,
     408             :                 "Get the DNS database entries for a DNS name"},
     409             :         { "replace", (PyCFunction)py_dsdb_dns_replace,
     410             :                 METH_VARARGS, "Replace the DNS database entries for a DNS name"},
     411             :         { "replace_by_dn", (PyCFunction)py_dsdb_dns_replace_by_dn,
     412             :                 METH_VARARGS, "Replace the DNS database entries for a LDB DN"},
     413             :         { "records_match", (PyCFunction)py_dsdb_dns_records_match,
     414             :           METH_VARARGS|METH_KEYWORDS,
     415             :           "Decide whether two records match, according to dns update rules"},
     416             :         { "extract", (PyCFunction)py_dsdb_dns_extract,
     417             :                 METH_VARARGS, "Return the DNS database entry as a python structure from an Ldb.MessageElement of type dnsRecord"},
     418             :         { "unix_to_dns_timestamp", (PyCFunction)py_dsdb_dns_unix_to_dns_timestamp,
     419             :           METH_VARARGS,
     420             :           "Convert a time.time() value to a dns timestamp (hours since 1601)"},
     421             :         { "dns_timestamp_to_nt_time", (PyCFunction)py_dsdb_dns_timestamp_to_nt_time,
     422             :           METH_VARARGS,
     423             :           "Convert a dns timestamp to an NTTIME value"},
     424             :         {0}
     425             : };
     426             : 
     427             : static struct PyModuleDef moduledef = {
     428             :     PyModuleDef_HEAD_INIT,
     429             :     .m_name = "dsdb_dns",
     430             :     .m_doc = "Python bindings for the DNS objects in the directory service databases.",
     431             :     .m_size = -1,
     432             :     .m_methods = py_dsdb_dns_methods,
     433             : };
     434             : 
     435        4830 : MODULE_INIT_FUNC(dsdb_dns)
     436             : {
     437             :         PyObject *m;
     438             : 
     439        4830 :         m = PyModule_Create(&moduledef);
     440             : 
     441        4830 :         if (m == NULL)
     442           0 :                 return NULL;
     443             : 
     444        4830 :         return m;
     445             : }

Generated by: LCOV version 1.13