From: Douglas Bagnall Date: Sat, 27 Mar 2021 09:09:56 +0000 (+0000) Subject: pydns: expose dns timestamp utils to python, and test X-Git-Tag: tevent-0.11.0~1361 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=146c23fb7d98515c4dd0349d0406b7f459d3b696;p=thirdparty%2Fsamba.git pydns: expose dns timestamp utils to python, and test Signed-off-by: Douglas Bagnall Reviewed-by: Jeremy Allison --- diff --git a/python/samba/tests/dsdb_dns.py b/python/samba/tests/dsdb_dns.py new file mode 100644 index 00000000000..8c7fc343278 --- /dev/null +++ b/python/samba/tests/dsdb_dns.py @@ -0,0 +1,86 @@ +# Unix SMB/CIFS implementation. Tests for dsdb_dns module +# Copyright © Catalyst IT 2021 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +from samba.tests import TestCase +from samba import dsdb_dns +import time + + +def unix2nttime(t): + # here we reimplement unix_to_nt_time from lib/util/time.c + if t == -1: + return t + if t == (1 << 63) - 1: + return (1 << 63) - 1 + if t == 0: + return 0 + t += 11644473600 + t *= 1e7 + return int(t) + + +def unix2dns_timestamp(t): + nt = unix2nttime(t) + if nt < 0: + # because NTTIME is a uint64_t. + nt += 1 << 64 + return nt // int(3.6e10) + + +def timestamp2nttime(ts): + nt = ts * int(3.6e10) + if nt >= 1 << 63: + raise OverflowError("nt time won't fit this") + return nt + + +class DsdbDnsTestCase(TestCase): + def test_unix_to_dns_timestamp(self): + unixtimes = [1616829393, + 1, + 0, + -1, + 1 << 31 - 1] + + for t in unixtimes: + expected = unix2dns_timestamp(t) + result = dsdb_dns.unix_to_dns_timestamp(t) + self.assertEqual(result, expected) + + def test_dns_timestamp_to_nt_time(self): + timestamps = [16168393, + 1, + 0, + (1 << 32) - 1, + (1 << 63) - 1, + int((1 << 63) / 3.6e10), + int((1 << 63) / 3.6e10) + 1, # overflows + ] + + for t in timestamps: + overflows = False + try: + expected = timestamp2nttime(t) + except OverflowError: + overflows = True + try: + result = dsdb_dns.dns_timestamp_to_nt_time(t) + except ValueError: + self.assertTrue(overflows, f"timestamp {t} should not overflow") + continue + self.assertFalse(overflows, f"timestamp {t} should overflow") + + self.assertEqual(result, expected) diff --git a/source4/dns_server/pydns.c b/source4/dns_server/pydns.c index 1e6a1cb6105..ad5a96bf763 100644 --- a/source4/dns_server/pydns.c +++ b/source4/dns_server/pydns.c @@ -325,6 +325,48 @@ static PyObject *py_dsdb_dns_replace_by_dn(PyObject *self, PyObject *args) Py_RETURN_NONE; } +static PyObject *py_dsdb_dns_unix_to_dns_timestamp(PyObject *self, PyObject *args) +{ + uint32_t timestamp; + time_t t; + long long lt; + + if (!PyArg_ParseTuple(args, "L", <)) { + return NULL; + } + + t = lt; + if (t != lt) { + /* time_t is presumably 32 bit here */ + PyErr_SetString(PyExc_ValueError, "Time out of range"); + return NULL; + } + timestamp = unix_to_dns_timestamp(t); + return Py_BuildValue("k", (unsigned long) timestamp); +} + +static PyObject *py_dsdb_dns_timestamp_to_nt_time(PyObject *self, PyObject *args) +{ + unsigned long long timestamp; + NTSTATUS status; + NTTIME nt; + if (!PyArg_ParseTuple(args, "K", ×tamp)) { + return NULL; + } + + if (timestamp > UINT32_MAX || timestamp < 0) { + PyErr_SetString(PyExc_ValueError, "Time out of range"); + return NULL; + } + status = dns_timestamp_to_nt_time(&nt, (uint32_t)timestamp); + if (!NT_STATUS_IS_OK(status)) { + PyErr_SetString(PyExc_ValueError, "Time out of range"); + return NULL; + } + return Py_BuildValue("L", (long long) nt); +} + + static PyMethodDef py_dsdb_dns_methods[] = { { "lookup", PY_DISCARD_FUNC_SIG(PyCFunction, py_dsdb_dns_lookup), @@ -336,6 +378,12 @@ static PyMethodDef py_dsdb_dns_methods[] = { METH_VARARGS, "Replace the DNS database entries for a LDB DN"}, { "extract", (PyCFunction)py_dsdb_dns_extract, METH_VARARGS, "Return the DNS database entry as a python structure from an Ldb.MessageElement of type dnsRecord"}, + { "unix_to_dns_timestamp", (PyCFunction)py_dsdb_dns_unix_to_dns_timestamp, + METH_VARARGS, + "Convert a time.time() value to a dns timestamp (hours since 1601)"}, + { "dns_timestamp_to_nt_time", (PyCFunction)py_dsdb_dns_timestamp_to_nt_time, + METH_VARARGS, + "Convert a dns timestamp to an NTTIME value"}, {0} }; diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index 051f483c5e3..cd5730e672f 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -823,6 +823,8 @@ planoldpythontestsuite("ad_dc_default:local", "samba.tests.krb5.s4u_tests", 'SERVICE_PASSWORD':'$PASSWORD', 'FOR_USER':'$USERNAME'}) +planoldpythontestsuite("ad_dc_default", "samba.tests.dsdb_dns") + planoldpythontestsuite("fl2008r2dc:local", "samba.tests.krb5.xrealm_tests") for env in ["ad_dc", smbv1_disabled_testenv]: