2015-09-22 03:11:04 +03:00
/*
Unix SMB / CIFS implementation .
Python DNS server wrapper
Copyright ( C ) 2015 Andrew Bartlett
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 < http : //www.gnu.org/licenses/>.
*/
# include <Python.h>
2018-01-30 20:47:32 +03:00
# include "python/py3compat.h"
2015-09-22 03:11:04 +03:00
# include "includes.h"
2019-05-02 21:45:14 +03:00
# include "python/modules.h"
2015-09-22 03:11:04 +03:00
# include <pyldb.h>
# include <pytalloc.h>
# include "dns_server/dnsserver_common.h"
# include "dsdb/samdb/samdb.h"
# include "dsdb/common/util.h"
# include "librpc/gen_ndr/ndr_dnsp.h"
# include "librpc/rpc/pyrpc_util.h"
/* FIXME: These should be in a header file somewhere */
# define PyErr_LDB_OR_RAISE(py_ldb, ldb) \
if ( ! py_check_dcerpc_type ( py_ldb , " ldb " , " Ldb " ) ) { \
2017-04-10 07:06:13 +03:00
PyErr_SetString ( PyExc_TypeError , " Ldb connection object required " ) ; \
2015-09-22 03:11:04 +03:00
return NULL ; \
} \
ldb = pyldb_Ldb_AsLdbContext ( py_ldb ) ;
2015-10-14 06:56:41 +03:00
# define PyErr_LDB_DN_OR_RAISE(py_ldb_dn, dn) \
if ( ! py_check_dcerpc_type ( py_ldb_dn , " ldb " , " Dn " ) ) { \
2017-04-10 07:06:13 +03:00
PyErr_SetString ( PyExc_TypeError , " ldb Dn object required " ) ; \
2015-10-14 06:56:41 +03:00
return NULL ; \
} \
2018-04-27 04:15:01 +03:00
dn = pyldb_Dn_AS_DN ( py_ldb_dn ) ;
2015-10-14 06:56:41 +03:00
2015-09-22 03:11:04 +03:00
static PyObject * py_dnsp_DnssrvRpcRecord_get_list ( struct dnsp_DnssrvRpcRecord * records ,
uint16_t num_records )
{
PyObject * py_dns_list ;
int i ;
py_dns_list = PyList_New ( num_records ) ;
if ( py_dns_list = = NULL ) {
return NULL ;
}
for ( i = 0 ; i < num_records ; i + + ) {
PyObject * py_dns_record ;
py_dns_record = py_return_ndr_struct ( " samba.dcerpc.dnsp " , " DnssrvRpcRecord " , records , & records [ i ] ) ;
PyList_SetItem ( py_dns_list , i , py_dns_record ) ;
}
return py_dns_list ;
}
2021-05-28 09:08:56 +03:00
2015-09-22 03:11:04 +03:00
static int py_dnsp_DnssrvRpcRecord_get_array ( PyObject * value ,
TALLOC_CTX * mem_ctx ,
struct dnsp_DnssrvRpcRecord * * records ,
uint16_t * num_records )
{
int i ;
struct dnsp_DnssrvRpcRecord * recs ;
PY_CHECK_TYPE ( & PyList_Type , value , return - 1 ; ) ;
recs = talloc_array ( mem_ctx , struct dnsp_DnssrvRpcRecord ,
PyList_GET_SIZE ( value ) ) ;
if ( recs = = NULL ) {
PyErr_NoMemory ( ) ;
return - 1 ;
}
for ( i = 0 ; i < PyList_GET_SIZE ( value ) ; i + + ) {
bool type_correct ;
PyObject * item = PyList_GET_ITEM ( value , i ) ;
type_correct = py_check_dcerpc_type ( item , " samba.dcerpc.dnsp " , " DnssrvRpcRecord " ) ;
if ( type_correct = = false ) {
return - 1 ;
}
if ( talloc_reference ( mem_ctx , pytalloc_get_mem_ctx ( item ) ) = = NULL ) {
PyErr_NoMemory ( ) ;
return - 1 ;
}
recs [ i ] = * ( struct dnsp_DnssrvRpcRecord * ) pytalloc_get_ptr ( item ) ;
}
* records = recs ;
* num_records = PyList_GET_SIZE ( value ) ;
return 0 ;
}
2017-06-09 07:05:31 +03:00
static PyObject * py_dsdb_dns_lookup ( PyObject * self ,
PyObject * args , PyObject * kwargs )
2015-09-22 03:11:04 +03:00
{
struct ldb_context * samdb ;
2017-02-27 07:09:56 +03:00
PyObject * py_ldb , * ret , * pydn ;
2017-06-09 07:05:31 +03:00
PyObject * py_dns_partition = NULL ;
2019-01-22 21:26:23 +03:00
PyObject * result = NULL ;
2015-09-22 03:11:04 +03:00
char * dns_name ;
TALLOC_CTX * frame ;
NTSTATUS status ;
WERROR werr ;
struct dns_server_zone * zones_list ;
2017-06-09 07:05:31 +03:00
struct ldb_dn * dn , * dns_partition = NULL ;
2015-09-22 03:11:04 +03:00
struct dnsp_DnssrvRpcRecord * records ;
uint16_t num_records ;
2017-06-09 07:05:31 +03:00
const char * const kwnames [ ] = { " ldb " , " dns_name " ,
" dns_partition " , NULL } ;
2015-09-22 03:11:04 +03:00
2017-06-09 07:05:31 +03:00
if ( ! PyArg_ParseTupleAndKeywords ( args , kwargs , " Os|O " ,
discard_const_p ( char * , kwnames ) ,
& py_ldb , & dns_name ,
& py_dns_partition ) ) {
2015-09-22 03:11:04 +03:00
return NULL ;
}
PyErr_LDB_OR_RAISE ( py_ldb , samdb ) ;
2017-06-09 07:05:31 +03:00
if ( py_dns_partition ) {
PyErr_LDB_DN_OR_RAISE ( py_dns_partition ,
dns_partition ) ;
}
2015-09-22 03:11:04 +03:00
frame = talloc_stackframe ( ) ;
2017-06-09 07:05:31 +03:00
status = dns_common_zones ( samdb , frame , dns_partition ,
& zones_list ) ;
2015-09-22 03:11:04 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2017-02-27 06:51:45 +03:00
talloc_free ( frame ) ;
2015-09-22 03:11:04 +03:00
PyErr_SetNTSTATUS ( status ) ;
return NULL ;
}
werr = dns_common_name2dn ( samdb , zones_list , frame , dns_name , & dn ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2017-02-27 06:51:45 +03:00
talloc_free ( frame ) ;
2015-09-22 03:11:04 +03:00
PyErr_SetWERROR ( werr ) ;
return NULL ;
}
werr = dns_common_lookup ( samdb ,
frame ,
dn ,
& records ,
& num_records ,
NULL ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2017-02-27 06:51:45 +03:00
talloc_free ( frame ) ;
2015-09-22 03:11:04 +03:00
PyErr_SetWERROR ( werr ) ;
return NULL ;
}
2017-02-27 06:51:45 +03:00
ret = py_dnsp_DnssrvRpcRecord_get_list ( records , num_records ) ;
2017-02-27 07:09:56 +03:00
pydn = pyldb_Dn_FromDn ( dn ) ;
2017-02-27 06:51:45 +03:00
talloc_free ( frame ) ;
2019-01-22 21:26:23 +03:00
result = Py_BuildValue ( " (OO) " , pydn , ret ) ;
Py_CLEAR ( ret ) ;
Py_CLEAR ( pydn ) ;
return result ;
2015-09-22 03:11:04 +03:00
}
2015-09-22 06:32:57 +03:00
static PyObject * py_dsdb_dns_extract ( PyObject * self , PyObject * args )
{
2017-04-11 03:43:22 +03:00
struct ldb_context * samdb ;
2017-02-27 06:51:45 +03:00
PyObject * py_dns_el , * ret ;
2017-04-11 03:43:22 +03:00
PyObject * py_ldb = NULL ;
2015-09-22 06:32:57 +03:00
TALLOC_CTX * frame ;
WERROR werr ;
struct ldb_message_element * dns_el ;
struct dnsp_DnssrvRpcRecord * records ;
uint16_t num_records ;
2017-04-11 03:43:22 +03:00
if ( ! PyArg_ParseTuple ( args , " OO " , & py_ldb , & py_dns_el ) ) {
2015-09-22 06:32:57 +03:00
return NULL ;
}
2017-04-11 03:43:22 +03:00
PyErr_LDB_OR_RAISE ( py_ldb , samdb ) ;
2015-09-22 06:32:57 +03:00
if ( ! py_check_dcerpc_type ( py_dns_el , " ldb " , " MessageElement " ) ) {
2017-04-10 07:06:13 +03:00
PyErr_SetString ( PyExc_TypeError ,
2015-09-22 06:32:57 +03:00
" ldb MessageElement object required " ) ;
return NULL ;
}
dns_el = pyldb_MessageElement_AsMessageElement ( py_dns_el ) ;
frame = talloc_stackframe ( ) ;
2017-04-11 03:43:22 +03:00
werr = dns_common_extract ( samdb , dns_el ,
2015-09-22 06:32:57 +03:00
frame ,
& records ,
& num_records ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2017-02-27 06:51:45 +03:00
talloc_free ( frame ) ;
2015-09-22 06:32:57 +03:00
PyErr_SetWERROR ( werr ) ;
return NULL ;
}
2017-02-27 06:51:45 +03:00
ret = py_dnsp_DnssrvRpcRecord_get_list ( records , num_records ) ;
talloc_free ( frame ) ;
return ret ;
2015-09-22 06:32:57 +03:00
}
2015-09-22 03:11:04 +03:00
static PyObject * py_dsdb_dns_replace ( PyObject * self , PyObject * args )
{
struct ldb_context * samdb ;
PyObject * py_ldb , * py_dns_records ;
char * dns_name ;
TALLOC_CTX * frame ;
NTSTATUS status ;
WERROR werr ;
int ret ;
struct dns_server_zone * zones_list ;
struct ldb_dn * dn ;
struct dnsp_DnssrvRpcRecord * records ;
uint16_t num_records ;
/*
* TODO : This is a shocking abuse , but matches what the
* internal DNS server does , it should be pushed into
* dns_common_replace ( )
*/
static const int serial = 110 ;
if ( ! PyArg_ParseTuple ( args , " OsO " , & py_ldb , & dns_name , & py_dns_records ) ) {
return NULL ;
}
PyErr_LDB_OR_RAISE ( py_ldb , samdb ) ;
frame = talloc_stackframe ( ) ;
2017-06-09 07:05:31 +03:00
status = dns_common_zones ( samdb , frame , NULL , & zones_list ) ;
2015-09-22 03:11:04 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
PyErr_SetNTSTATUS ( status ) ;
2017-02-27 06:51:45 +03:00
talloc_free ( frame ) ;
2015-09-22 03:11:04 +03:00
return NULL ;
}
werr = dns_common_name2dn ( samdb , zones_list , frame , dns_name , & dn ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
PyErr_SetWERROR ( werr ) ;
2017-02-27 06:51:45 +03:00
talloc_free ( frame ) ;
2015-09-22 03:11:04 +03:00
return NULL ;
}
ret = py_dnsp_DnssrvRpcRecord_get_array ( py_dns_records ,
frame ,
& records , & num_records ) ;
if ( ret ! = 0 ) {
2017-02-27 06:51:45 +03:00
talloc_free ( frame ) ;
2015-09-22 03:11:04 +03:00
return NULL ;
}
werr = dns_common_replace ( samdb ,
frame ,
dn ,
false , /* Not adding a record */
serial ,
records ,
num_records ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
PyErr_SetWERROR ( werr ) ;
2017-02-27 06:51:45 +03:00
talloc_free ( frame ) ;
2015-09-22 03:11:04 +03:00
return NULL ;
}
2017-02-27 06:51:45 +03:00
talloc_free ( frame ) ;
2015-09-22 03:11:04 +03:00
Py_RETURN_NONE ;
}
2015-10-14 06:56:41 +03:00
static PyObject * py_dsdb_dns_replace_by_dn ( PyObject * self , PyObject * args )
{
struct ldb_context * samdb ;
PyObject * py_ldb , * py_dn , * py_dns_records ;
TALLOC_CTX * frame ;
WERROR werr ;
int ret ;
struct ldb_dn * dn ;
struct dnsp_DnssrvRpcRecord * records ;
uint16_t num_records ;
/*
* TODO : This is a shocking abuse , but matches what the
* internal DNS server does , it should be pushed into
* dns_common_replace ( )
*/
static const int serial = 110 ;
if ( ! PyArg_ParseTuple ( args , " OOO " , & py_ldb , & py_dn , & py_dns_records ) ) {
return NULL ;
}
PyErr_LDB_OR_RAISE ( py_ldb , samdb ) ;
PyErr_LDB_DN_OR_RAISE ( py_dn , dn ) ;
frame = talloc_stackframe ( ) ;
ret = py_dnsp_DnssrvRpcRecord_get_array ( py_dns_records ,
frame ,
& records , & num_records ) ;
if ( ret ! = 0 ) {
2017-02-27 06:51:45 +03:00
talloc_free ( frame ) ;
2015-10-14 06:56:41 +03:00
return NULL ;
}
werr = dns_common_replace ( samdb ,
frame ,
dn ,
2021-06-20 13:03:35 +03:00
false , /* Not adding a node */
2015-10-14 06:56:41 +03:00
serial ,
records ,
num_records ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
PyErr_SetWERROR ( werr ) ;
2017-02-27 06:51:45 +03:00
talloc_free ( frame ) ;
2015-10-14 06:56:41 +03:00
return NULL ;
}
2017-02-27 06:51:45 +03:00
talloc_free ( frame ) ;
2015-10-14 06:56:41 +03:00
Py_RETURN_NONE ;
}
2021-05-28 09:08:56 +03:00
static PyObject * py_dsdb_dns_records_match ( PyObject * self , PyObject * args )
{
PyObject * py_recs [ 2 ] ;
struct dnsp_DnssrvRpcRecord * rec1 ;
struct dnsp_DnssrvRpcRecord * rec2 ;
size_t i ;
bool type_correct ;
bool match ;
if ( ! PyArg_ParseTuple ( args , " OO " , & py_recs [ 0 ] , & py_recs [ 1 ] ) ) {
return NULL ;
}
for ( i = 0 ; i < 2 ; i + + ) {
type_correct = py_check_dcerpc_type ( py_recs [ i ] ,
" samba.dcerpc.dnsp " ,
" DnssrvRpcRecord " ) ;
if ( ! type_correct ) {
PyErr_SetString ( PyExc_ValueError ,
" DnssrvRpcRecord expected " ) ;
return NULL ;
}
}
rec1 = ( struct dnsp_DnssrvRpcRecord * ) pytalloc_get_ptr ( py_recs [ 0 ] ) ;
rec2 = ( struct dnsp_DnssrvRpcRecord * ) pytalloc_get_ptr ( py_recs [ 1 ] ) ;
match = dns_record_match ( rec1 , rec2 ) ;
return PyBool_FromLong ( match ) ;
}
2021-03-27 12:09:56 +03:00
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 " , & lt ) ) {
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 " , & timestamp ) ) {
return NULL ;
}
2021-12-14 17:42:06 +03:00
if ( timestamp > UINT32_MAX ) {
2021-03-27 12:09:56 +03:00
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 ) ;
}
2015-09-22 03:11:04 +03:00
static PyMethodDef py_dsdb_dns_methods [ ] = {
2019-05-02 21:45:14 +03:00
{ " lookup " , PY_DISCARD_FUNC_SIG ( PyCFunction , py_dsdb_dns_lookup ) ,
2017-06-09 07:05:31 +03:00
METH_VARARGS | METH_KEYWORDS ,
" Get the DNS database entries for a DNS name " } ,
2015-09-22 03:11:04 +03:00
{ " replace " , ( PyCFunction ) py_dsdb_dns_replace ,
METH_VARARGS , " Replace the DNS database entries for a DNS name " } ,
2015-10-14 06:56:41 +03:00
{ " replace_by_dn " , ( PyCFunction ) py_dsdb_dns_replace_by_dn ,
METH_VARARGS , " Replace the DNS database entries for a LDB DN " } ,
2021-05-28 09:08:56 +03:00
{ " records_match " , ( PyCFunction ) py_dsdb_dns_records_match ,
METH_VARARGS | METH_KEYWORDS ,
" Decide whether two records match, according to dns update rules " } ,
2015-09-22 06:32:57 +03:00
{ " extract " , ( PyCFunction ) py_dsdb_dns_extract ,
METH_VARARGS , " Return the DNS database entry as a python structure from an Ldb.MessageElement of type dnsRecord " } ,
2021-03-27 12:09:56 +03:00
{ " 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 " } ,
2020-05-05 04:47:39 +03:00
{ 0 }
2015-09-22 03:11:04 +03:00
} ;
2018-01-30 20:47:32 +03:00
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT ,
. m_name = " dsdb_dns " ,
. m_doc = " Python bindings for the DNS objects in the directory service databases. " ,
. m_size = - 1 ,
. m_methods = py_dsdb_dns_methods ,
} ;
2015-09-22 03:11:04 +03:00
2018-01-30 20:47:32 +03:00
MODULE_INIT_FUNC ( dsdb_dns )
2015-09-22 03:11:04 +03:00
{
PyObject * m ;
2018-01-30 20:47:32 +03:00
m = PyModule_Create ( & moduledef ) ;
2015-09-22 03:11:04 +03:00
if ( m = = NULL )
2018-01-30 20:47:32 +03:00
return NULL ;
return m ;
2015-09-22 03:11:04 +03:00
}