2012-09-05 10:24:52 +04:00
/*
Unix SMB / CIFS implementation .
DNS server handler for signed packets
Copyright ( C ) 2012 Kai Blin < kai @ samba . org >
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 "includes.h"
# include "system/network.h"
# include "librpc/ndr/libndr.h"
# include "librpc/gen_ndr/ndr_dns.h"
# include "dns_server/dns_server.h"
# include "libcli/util/ntstatus.h"
# include "auth/auth.h"
# include "auth/gensec/gensec.h"
2024-05-30 15:39:28 +03:00
# include "lib/util/bytearray.h"
2012-09-05 10:24:52 +04:00
2013-01-14 04:14:29 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_DNS
2012-09-05 10:34:49 +04:00
static WERROR dns_copy_tsig ( TALLOC_CTX * mem_ctx ,
struct dns_res_rec * old ,
struct dns_res_rec * new_rec )
{
new_rec - > name = talloc_strdup ( mem_ctx , old - > name ) ;
W_ERROR_HAVE_NO_MEMORY ( new_rec - > name ) ;
new_rec - > rr_type = old - > rr_type ;
new_rec - > rr_class = old - > rr_class ;
new_rec - > ttl = old - > ttl ;
new_rec - > length = old - > length ;
new_rec - > rdata . tsig_record . algorithm_name = talloc_strdup ( mem_ctx ,
old - > rdata . tsig_record . algorithm_name ) ;
W_ERROR_HAVE_NO_MEMORY ( new_rec - > rdata . tsig_record . algorithm_name ) ;
new_rec - > rdata . tsig_record . time_prefix = old - > rdata . tsig_record . time_prefix ;
new_rec - > rdata . tsig_record . time = old - > rdata . tsig_record . time ;
new_rec - > rdata . tsig_record . fudge = old - > rdata . tsig_record . fudge ;
new_rec - > rdata . tsig_record . mac_size = old - > rdata . tsig_record . mac_size ;
new_rec - > rdata . tsig_record . mac = talloc_memdup ( mem_ctx ,
old - > rdata . tsig_record . mac ,
old - > rdata . tsig_record . mac_size ) ;
W_ERROR_HAVE_NO_MEMORY ( new_rec - > rdata . tsig_record . mac ) ;
new_rec - > rdata . tsig_record . original_id = old - > rdata . tsig_record . original_id ;
new_rec - > rdata . tsig_record . error = old - > rdata . tsig_record . error ;
new_rec - > rdata . tsig_record . other_size = old - > rdata . tsig_record . other_size ;
new_rec - > rdata . tsig_record . other_data = talloc_memdup ( mem_ctx ,
old - > rdata . tsig_record . other_data ,
old - > rdata . tsig_record . other_size ) ;
W_ERROR_HAVE_NO_MEMORY ( new_rec - > rdata . tsig_record . other_data ) ;
return WERR_OK ;
}
2012-09-05 10:24:52 +04:00
struct dns_server_tkey * dns_find_tkey ( struct dns_server_tkey_store * store ,
const char * name )
{
struct dns_server_tkey * tkey = NULL ;
uint16_t i = 0 ;
do {
struct dns_server_tkey * tmp_key = store - > tkeys [ i ] ;
i + + ;
i % = TKEY_BUFFER_SIZE ;
if ( tmp_key = = NULL ) {
continue ;
}
s4:dnsserver: Rename dns_name_equal() to samba_dns_name_equal()
This function already exists in bind9 but takes different arguments, so when
the DLZ is loaded and this function is called bind crashes:
named[1523]: samba_dlz: allowing update of signer=DESKTOP-8BUKMBK\$\@AFOREST.AD name=118.101.168.192.in-addr.arpa tcpaddr=192.168.101.118 type=PTR key=1264-ms-7.1-2ac9.9ef238e1-9747-11ed-9f95-525400dc6981/159/0
named[1523]: samba_dlz: allowing update of signer=DESKTOP-8BUKMBK\$\@AFOREST.AD name=118.101.168.192.in-addr.arpa tcpaddr=192.168.101.118 type=PTR key=1264-ms-7.1-2ac9.9ef238e1-9747-11ed-9f95-525400dc6981/159/0
named[1523]: client @0x7f26caa90f68 192.168.101.118#58223/key DESKTOP-8BUKMBK\$\@AFOREST.AD: updating zone '101.168.192.in-addr.arpa/NONE': deleting rrset at '118.101.168.192.in-addr.ar
named[1523]: name.c:664: REQUIRE(((name1) != ((void *)0) && ((const isc__magic_t *)(name1))->magic == ((('D') << 24 | ('N') << 16 | ('S') << 8 | ('n'))))) failed, back trace
Backtrace:
#0 0x00007f2716c957ec in __pthread_kill_implementation () from /lib64/libc.so.6
#1 0x00007f2716c42816 in raise () from /lib64/libc.so.6
#2 0x00007f2716c2b81c in abort () from /lib64/libc.so.6
#3 0x000055d4de847995 in assertion_failed (file=<optimized out>, line=<optimized out>,
type=<optimized out>, cond=<optimized out>) at /usr/src/debug/bind-9.18.10/bin/named/main.c:237
#4 0x00007f27176388fc in isc_assertion_failed (file=file@entry=0x7f27173b0df6 "name.c",
line=line@entry=664, type=type@entry=isc_assertiontype_require,
cond=cond@entry=0x7f27173b0268 "((name1) != ((void *)0) && ((const isc__magic_t *)(name1))->magic == ((('D') << 24 | ('N') << 16 | ('S') << 8 | ('n'))))")
at /usr/src/debug/bind-9.18.10/lib/isc/assertions.c:48
#5 0x00007f27172946f9 in dns_name_equal (name1=<optimized out>, name2=<optimized out>)
at /usr/src/debug/bind-9.18.10/lib/dns/name.c:664
**** Here bind's dns_name_equal() is called instead of samba's dns_name_equal() ****
#6 0x00007f27077ad6f2 in dns_record_match (rec1=0x7f26f8042d70, rec2=0x7f26f8044d10)
at ../../source4/dns_server/dnsserver_common.c:1346
#7 0x00007f271404732c in b9_record_match (rec1=0x7f26f8042d70, rec2=0x7f26f8044d10)
at ../../source4/dns_server/dlz_bind9.c:1830
#8 0x00007f2714047daa in dlz_subrdataset (name=0x7f2706ff82f0 "118.101.168.192.in-addr.arpa",
rdatastr=0x7f26c9c10000 "118.101.168.192.in-addr.arpa.\t1200\tIN\tPTR\tDESKTOP-8BUKMBK.aforest.ad.",
dbdata=0x7f271003d300, version=0x7f26f8044b20) at ../../source4/dns_server/dlz_bind9.c:2077
#9 0x000055d4de84afb4 in dlopen_dlz_subrdataset (name=0x7f2706ff82f0 "118.101.168.192.in-addr.arpa",
rdatastr=<optimized out>, driverarg=<optimized out>, dbdata=0x7f270430f680, version=<optimized out>)
at /usr/src/debug/bind-9.18.10/bin/named/dlz_dlopen_driver.c:483
#10 0x00007f271738e734 in modrdataset.constprop.0 (db=0x7f2704291740, node=0x7f26c9c006e0,
version=0x7f26f8044b20, rdataset=0x7f2706ff8830,
mod_function=0x55d4de84af80 <dlopen_dlz_subrdataset>, options=<optimized out>)
at /usr/src/debug/bind-9.18.10/lib/dns/sdlz.c:1107
#11 0x00007f2717251855 in diff_apply (diff=diff@entry=0x7f2706ff8df0, db=db@entry=0x7f2704291740,
ver=ver@entry=0x7f26f8044b20, warn=warn@entry=true) at /usr/src/debug/bind-9.18.10/lib/dns/diff.c:370
#12 0x00007f2717251c8a in dns_diff_apply (diff=diff@entry=0x7f2706ff8df0, db=db@entry=0x7f2704291740,
ver=ver@entry=0x7f26f8044b20) at /usr/src/debug/bind-9.18.10/lib/dns/diff.c:465
#13 0x00007f2717d105aa in do_one_tuple (tuple=tuple@entry=0x7f2706ff8e50, db=db@entry=0x7f2704291740,
ver=ver@entry=0x7f26f8044b20, diff=diff@entry=0x7f2706ff9400)
at /usr/src/debug/bind-9.18.10/lib/ns/update.c:454
#14 0x00007f2717d10fff in update_one_rr (rdata=0x7f2706ff8ee8, ttl=<optimized out>,
name=<optimized out>, op=DNS_DIFFOP_DEL, diff=0x7f2706ff9400, ver=0x7f26f8044b20, db=0x7f2704291740)
at /usr/src/debug/bind-9.18.10/lib/ns/update.c:505
#15 delete_if_action (data=<optimized out>, rr=0x7f2706ff8ee0)
at /usr/src/debug/bind-9.18.10/lib/ns/update.c:1427
#16 0x00007f2717d10ccd in foreach_rr (db=0x7f2704291740, ver=<optimized out>, name=0x7f26caa61d00,
type=<optimized out>, covers=<optimized out>,
rr_action=rr_action@entry=0x7f2717d10f60 <delete_if_action>, rr_action_data=0x7f2706ff9280)
at /usr/src/debug/bind-9.18.10/lib/ns/update.c:736
#17 0x00007f2717d10e76 in delete_if (predicate=predicate@entry=0x7f2717d0fb10 <true_p>,
db=<optimized out>, ver=<optimized out>, name=<optimized out>, type=<optimized out>,
covers=<optimized out>, update_rr=0x7f2706ff94b0, diff=0x7f2706ff9400)
at /usr/src/debug/bind-9.18.10/lib/ns/update.c:1454
#18 0x00007f2717d1bccd in update_action (task=<optimized out>, event=<optimized out>)
at /usr/src/debug/bind-9.18.10/lib/ns/update.c:3299
#19 0x00007f271765eb4c in task_run (task=0x7f27155ccf00)
at /usr/src/debug/bind-9.18.10/lib/isc/task.c:823
#20 isc_task_run (task=0x7f27155ccf00) at /usr/src/debug/bind-9.18.10/lib/isc/task.c:904
#21 0x00007f271762cb12 in isc__nm_async_task (worker=0x7f2716236560, ev0=0x7f26caa07000)
at netmgr/netmgr.c:840
#22 process_netievent (worker=worker@entry=0x7f2716236560, ievent=0x7f26caa07000) at netmgr/netmgr.c:918
#23 0x00007f271762d197 in process_queue (worker=worker@entry=0x7f2716236560,
type=type@entry=NETIEVENT_TASK) at netmgr/netmgr.c:1011
#24 0x00007f271762d3b3 in process_all_queues (worker=0x7f2716236560) at netmgr/netmgr.c:765
#25 async_cb (handle=0x7f27162368c0) at netmgr/netmgr.c:794
#26 0x00007f2717c4cb0d in uv__async_io (loop=0x7f2716236570, w=<optimized out>, events=<optimized out>)
at src/unix/async.c:163
#27 0x00007f2717c6825d in uv__io_poll (loop=0x7f2716236570, timeout=<optimized out>)
at src/unix/epoll.c:374
#28 0x00007f2717c5247a in uv__io_poll (timeout=<optimized out>, loop=0x7f2716236570)
at src/unix/udp.c:122
#29 uv_run (loop=loop@entry=0x7f2716236570, mode=mode@entry=UV_RUN_DEFAULT) at src/unix/core.c:406
#30 0x00007f271762d834 in nm_thread (worker0=0x7f2716236560) at netmgr/netmgr.c:696
#31 0x00007f27176627f5 in isc__trampoline_run (arg=0x55d4dfe3ad70)
at /usr/src/debug/bind-9.18.10/lib/isc/trampoline.c:189
#32 0x00007f2716c9398d in start_thread () from /lib64/libc.so.6
#33 0x00007f2716d19344 in clone () from /lib64/libc.so.6
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14030
Signed-off-by: Samuel Cabrero <scabrero@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Autobuild-User(master): Samuel Cabrero <scabrero@samba.org>
Autobuild-Date(master): Thu Jan 19 10:20:27 UTC 2023 on atb-devel-224
2023-01-18 19:25:29 +03:00
if ( samba_dns_name_equal ( name , tmp_key - > name ) ) {
2012-09-05 10:24:52 +04:00
tkey = tmp_key ;
break ;
}
} while ( i ! = 0 ) ;
return tkey ;
}
2012-09-05 10:34:04 +04:00
2012-09-05 10:34:49 +04:00
WERROR dns_verify_tsig ( struct dns_server * dns ,
TALLOC_CTX * mem_ctx ,
struct dns_request_state * state ,
struct dns_name_packet * packet ,
DATA_BLOB * in )
{
WERROR werror ;
NTSTATUS status ;
enum ndr_err_code ndr_err ;
uint16_t i , arcount = 0 ;
DATA_BLOB tsig_blob , fake_tsig_blob , sig ;
uint8_t * buffer = NULL ;
size_t buffer_len = 0 , packet_len = 0 ;
struct dns_server_tkey * tkey = NULL ;
struct dns_fake_tsig_rec * check_rec = talloc_zero ( mem_ctx ,
struct dns_fake_tsig_rec ) ;
2024-05-31 09:38:24 +03:00
const char * algorithm = NULL ;
2012-09-05 10:34:49 +04:00
/* Find the first TSIG record in the additional records */
for ( i = 0 ; i < packet - > arcount ; i + + ) {
if ( packet - > additional [ i ] . rr_type = = DNS_QTYPE_TSIG ) {
break ;
}
}
2018-05-31 21:57:36 +03:00
if ( i = = packet - > arcount ) {
/* no TSIG around */
2012-09-05 10:34:49 +04:00
return WERR_OK ;
}
/* The TSIG record needs to be the last additional record */
2018-05-31 21:56:31 +03:00
if ( i + 1 ! = packet - > arcount ) {
2012-09-07 00:53:32 +04:00
DEBUG ( 1 , ( " TSIG record not the last additional record! \n " ) ) ;
2012-09-05 10:34:49 +04:00
return DNS_ERR ( FORMAT_ERROR ) ;
}
/* We got a TSIG, so we need to sign our reply */
state - > sign = true ;
2022-07-14 13:00:51 +03:00
DBG_DEBUG ( " Got TSIG \n " ) ;
2012-09-05 10:34:49 +04:00
2014-10-14 11:34:29 +04:00
state - > tsig = talloc_zero ( state - > mem_ctx , struct dns_res_rec ) ;
2012-09-05 10:34:49 +04:00
if ( state - > tsig = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-09-05 10:34:49 +04:00
}
werror = dns_copy_tsig ( state - > tsig , & packet - > additional [ i ] ,
state - > tsig ) ;
if ( ! W_ERROR_IS_OK ( werror ) ) {
return werror ;
}
packet - > arcount - - ;
tkey = dns_find_tkey ( dns - > tkeys , state - > tsig - > name ) ;
if ( tkey = = NULL ) {
2024-05-30 15:42:53 +03:00
DBG_DEBUG ( " dns_find_tkey() => REFUSED / DNS_RCODE_BADKEY \n " ) ;
2016-05-30 17:37:32 +03:00
/*
* We must save the name for use in the TSIG error
* response and have no choice here but to save the
* keyname from the TSIG request .
*/
state - > key_name = talloc_strdup ( state - > mem_ctx ,
state - > tsig - > name ) ;
2016-06-16 07:25:59 +03:00
if ( state - > key_name = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2016-06-16 07:25:59 +03:00
}
2012-09-05 10:34:49 +04:00
state - > tsig_error = DNS_RCODE_BADKEY ;
2024-05-30 15:42:53 +03:00
return DNS_ERR ( REFUSED ) ;
2012-09-05 10:34:49 +04:00
}
2022-07-14 13:00:51 +03:00
DBG_DEBUG ( " dns_find_tkey() => found \n " ) ;
2012-09-05 10:34:49 +04:00
2024-05-31 09:38:24 +03:00
algorithm = state - > tsig - > rdata . tsig_record . algorithm_name ;
if ( strcmp ( algorithm , " gss-tsig " ) = = 0 ) {
/* ok */
} else if ( strcmp ( algorithm , " gss.microsoft.com " ) = = 0 ) {
/* ok */
} else {
state - > tsig_error = DNS_RCODE_BADKEY ;
return DNS_ERR ( REFUSED ) ;
}
2016-05-30 17:37:32 +03:00
/*
* Remember the keyname that found an existing tkey , used
* later to fetch the key with dns_find_tkey ( ) when signing
* and adding a TSIG record with MAC .
*/
state - > key_name = talloc_strdup ( state - > mem_ctx , tkey - > name ) ;
if ( state - > key_name = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2016-05-30 17:37:32 +03:00
}
2012-09-05 10:34:49 +04:00
/* FIXME: check TSIG here */
if ( check_rec = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-09-05 10:34:49 +04:00
}
/* first build and verify check packet */
check_rec - > name = talloc_strdup ( check_rec , tkey - > name ) ;
if ( check_rec - > name = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-09-05 10:34:49 +04:00
}
check_rec - > rr_class = DNS_QCLASS_ANY ;
check_rec - > ttl = 0 ;
2024-05-31 09:38:24 +03:00
check_rec - > algorithm_name = talloc_strdup ( check_rec , algorithm ) ;
2012-09-05 10:34:49 +04:00
if ( check_rec - > algorithm_name = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-09-05 10:34:49 +04:00
}
check_rec - > time_prefix = 0 ;
check_rec - > time = state - > tsig - > rdata . tsig_record . time ;
check_rec - > fudge = state - > tsig - > rdata . tsig_record . fudge ;
check_rec - > error = 0 ;
check_rec - > other_size = 0 ;
check_rec - > other_data = NULL ;
ndr_err = ndr_push_struct_blob ( & tsig_blob , mem_ctx , state - > tsig ,
( ndr_push_flags_fn_t ) ndr_push_dns_res_rec ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 1 , ( " Failed to push packet: %s! \n " ,
ndr_errstr ( ndr_err ) ) ) ;
return DNS_ERR ( SERVER_FAILURE ) ;
}
ndr_err = ndr_push_struct_blob ( & fake_tsig_blob , mem_ctx , check_rec ,
( ndr_push_flags_fn_t ) ndr_push_dns_fake_tsig_rec ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 1 , ( " Failed to push packet: %s! \n " ,
ndr_errstr ( ndr_err ) ) ) ;
return DNS_ERR ( SERVER_FAILURE ) ;
}
/* we need to work some magic here. we need to keep the input packet
* exactly like we got it , but we need to cut off the tsig record */
packet_len = in - > length - tsig_blob . length ;
buffer_len = packet_len + fake_tsig_blob . length ;
buffer = talloc_zero_array ( mem_ctx , uint8_t , buffer_len ) ;
if ( buffer = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-09-05 10:34:49 +04:00
}
memcpy ( buffer , in - > data , packet_len ) ;
memcpy ( buffer + packet_len , fake_tsig_blob . data , fake_tsig_blob . length ) ;
sig . length = state - > tsig - > rdata . tsig_record . mac_size ;
sig . data = talloc_memdup ( mem_ctx , state - > tsig - > rdata . tsig_record . mac , sig . length ) ;
if ( sig . data = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-09-05 10:34:49 +04:00
}
/* Now we also need to count down the additional record counter */
arcount = RSVAL ( buffer , 10 ) ;
RSSVAL ( buffer , 10 , arcount - 1 ) ;
status = gensec_check_packet ( tkey - > gensec , buffer , buffer_len ,
buffer , buffer_len , & sig ) ;
if ( NT_STATUS_EQUAL ( NT_STATUS_ACCESS_DENIED , status ) ) {
2022-07-14 13:00:51 +03:00
dump_data_dbgc ( DBGC_DNS , 8 , sig . data , sig . length ) ;
dump_data_dbgc ( DBGC_DNS , 8 , buffer , buffer_len ) ;
DBG_NOTICE ( " Verifying tsig failed: %s \n " , nt_errstr ( status ) ) ;
2016-05-30 17:40:45 +03:00
state - > tsig_error = DNS_RCODE_BADSIG ;
2024-05-30 15:42:53 +03:00
return DNS_ERR ( REFUSED ) ;
2012-09-05 10:34:49 +04:00
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
2022-07-14 13:00:51 +03:00
dump_data_dbgc ( DBGC_DNS , 8 , sig . data , sig . length ) ;
dump_data_dbgc ( DBGC_DNS , 8 , buffer , buffer_len ) ;
2012-09-07 00:53:32 +04:00
DEBUG ( 1 , ( " Verifying tsig failed: %s \n " , nt_errstr ( status ) ) ) ;
2012-09-05 10:34:49 +04:00
return ntstatus_to_werror ( status ) ;
}
state - > authenticated = true ;
2022-07-14 13:00:51 +03:00
DBG_DEBUG ( " AUTHENTICATED \n " ) ;
2012-09-05 10:34:49 +04:00
return WERR_OK ;
}
2016-05-30 17:03:33 +03:00
static WERROR dns_tsig_compute_mac ( TALLOC_CTX * mem_ctx ,
struct dns_request_state * state ,
struct dns_name_packet * packet ,
struct dns_server_tkey * tkey ,
time_t current_time ,
DATA_BLOB * _psig )
2012-09-05 10:34:04 +04:00
{
NTSTATUS status ;
enum ndr_err_code ndr_err ;
DATA_BLOB packet_blob , tsig_blob , sig ;
uint8_t * buffer = NULL ;
2016-05-23 20:09:05 +03:00
uint8_t * p = NULL ;
2012-09-05 10:34:04 +04:00
size_t buffer_len = 0 ;
struct dns_fake_tsig_rec * check_rec = talloc_zero ( mem_ctx ,
struct dns_fake_tsig_rec ) ;
2016-05-23 20:09:05 +03:00
size_t mac_size = 0 ;
2024-05-30 15:39:28 +03:00
bool gss_tsig ;
2012-09-05 10:34:04 +04:00
if ( check_rec = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-09-05 10:34:04 +04:00
}
2024-05-30 15:39:28 +03:00
if ( strcmp ( tkey - > algorithm , " gss-tsig " ) = = 0 ) {
gss_tsig = true ;
} else {
/* gss.microsoft.com */
gss_tsig = false ;
}
2012-09-05 10:34:04 +04:00
/* first build and verify check packet */
check_rec - > name = talloc_strdup ( check_rec , tkey - > name ) ;
if ( check_rec - > name = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-09-05 10:34:04 +04:00
}
check_rec - > rr_class = DNS_QCLASS_ANY ;
check_rec - > ttl = 0 ;
check_rec - > algorithm_name = talloc_strdup ( check_rec , tkey - > algorithm ) ;
if ( check_rec - > algorithm_name = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-09-05 10:34:04 +04:00
}
check_rec - > time_prefix = 0 ;
check_rec - > time = current_time ;
check_rec - > fudge = 300 ;
check_rec - > error = state - > tsig_error ;
check_rec - > other_size = 0 ;
check_rec - > other_data = NULL ;
ndr_err = ndr_push_struct_blob ( & packet_blob , mem_ctx , packet ,
( ndr_push_flags_fn_t ) ndr_push_dns_name_packet ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 1 , ( " Failed to push packet: %s! \n " ,
ndr_errstr ( ndr_err ) ) ) ;
return DNS_ERR ( SERVER_FAILURE ) ;
}
ndr_err = ndr_push_struct_blob ( & tsig_blob , mem_ctx , check_rec ,
( ndr_push_flags_fn_t ) ndr_push_dns_fake_tsig_rec ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 1 , ( " Failed to push packet: %s! \n " ,
ndr_errstr ( ndr_err ) ) ) ;
return DNS_ERR ( SERVER_FAILURE ) ;
}
2016-05-23 20:09:05 +03:00
if ( state - > tsig ! = NULL ) {
mac_size = state - > tsig - > rdata . tsig_record . mac_size ;
}
buffer_len = mac_size ;
2024-05-30 15:39:28 +03:00
if ( gss_tsig & & mac_size > 0 ) {
buffer_len + = 2 ;
}
2016-05-23 20:09:05 +03:00
buffer_len + = packet_blob . length ;
if ( buffer_len < packet_blob . length ) {
2015-12-03 17:24:26 +03:00
return WERR_INVALID_PARAMETER ;
2016-05-23 20:09:05 +03:00
}
buffer_len + = tsig_blob . length ;
if ( buffer_len < tsig_blob . length ) {
2015-12-03 17:24:26 +03:00
return WERR_INVALID_PARAMETER ;
2016-05-23 20:09:05 +03:00
}
2012-09-05 10:34:04 +04:00
buffer = talloc_zero_array ( mem_ctx , uint8_t , buffer_len ) ;
if ( buffer = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-09-05 10:34:04 +04:00
}
2016-05-23 20:09:05 +03:00
p = buffer ;
/*
* RFC 2845 " 4.2 TSIG on Answers " , how to lay out the buffer
* that we ' re going to sign :
2024-05-30 15:39:28 +03:00
* 1. if MAC of request is present
* - 16 bit big endian length of MAC of request
* - MAC of request
2016-05-23 20:09:05 +03:00
* 2. Outgoing packet
* 3. TSIG record
*/
if ( mac_size > 0 ) {
2024-05-30 15:39:28 +03:00
if ( gss_tsig ) {
/*
* only gss - tsig not with
* gss . microsoft . com
*/
PUSH_BE_U16 ( p , 0 , mac_size ) ;
p + = 2 ;
}
2016-05-23 20:09:05 +03:00
memcpy ( p , state - > tsig - > rdata . tsig_record . mac , mac_size ) ;
p + = mac_size ;
}
memcpy ( p , packet_blob . data , packet_blob . length ) ;
p + = packet_blob . length ;
2012-09-05 10:34:04 +04:00
2016-05-23 20:09:05 +03:00
memcpy ( p , tsig_blob . data , tsig_blob . length ) ;
2012-09-05 10:34:04 +04:00
status = gensec_sign_packet ( tkey - > gensec , mem_ctx , buffer , buffer_len ,
buffer , buffer_len , & sig ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return ntstatus_to_werror ( status ) ;
}
2016-05-30 17:03:33 +03:00
* _psig = sig ;
return WERR_OK ;
}
WERROR dns_sign_tsig ( struct dns_server * dns ,
TALLOC_CTX * mem_ctx ,
struct dns_request_state * state ,
struct dns_name_packet * packet ,
uint16_t error )
{
WERROR werror ;
time_t current_time = time ( NULL ) ;
struct dns_res_rec * tsig = NULL ;
DATA_BLOB sig = ( DATA_BLOB ) {
. data = NULL ,
. length = 0
} ;
2024-05-31 09:38:24 +03:00
const char * algorithm = " gss-tsig " ;
2016-05-30 17:03:33 +03:00
tsig = talloc_zero ( mem_ctx , struct dns_res_rec ) ;
if ( tsig = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2016-05-30 17:03:33 +03:00
}
2016-05-30 18:25:56 +03:00
if ( state - > tsig_error = = DNS_RCODE_OK ) {
struct dns_server_tkey * tkey = dns_find_tkey (
dns - > tkeys , state - > key_name ) ;
if ( tkey = = NULL ) {
2022-07-14 13:00:51 +03:00
DBG_WARNING ( " dns_find_tkey() => NULL) \n " ) ;
2016-05-30 18:25:56 +03:00
return DNS_ERR ( SERVER_FAILURE ) ;
}
2016-05-30 17:03:33 +03:00
2016-05-30 18:25:56 +03:00
werror = dns_tsig_compute_mac ( mem_ctx , state , packet ,
tkey , current_time , & sig ) ;
2022-07-14 13:00:51 +03:00
DBG_DEBUG ( " dns_tsig_compute_mac() => %s \n " , win_errstr ( werror ) ) ;
2016-05-30 18:25:56 +03:00
if ( ! W_ERROR_IS_OK ( werror ) ) {
return werror ;
}
2024-05-31 09:38:24 +03:00
algorithm = tkey - > algorithm ;
2016-05-30 17:03:33 +03:00
}
tsig - > name = talloc_strdup ( tsig , state - > key_name ) ;
2012-09-05 10:34:04 +04:00
if ( tsig - > name = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-09-05 10:34:04 +04:00
}
2016-05-30 17:03:33 +03:00
tsig - > rr_class = DNS_QCLASS_ANY ;
2012-09-05 10:34:04 +04:00
tsig - > rr_type = DNS_QTYPE_TSIG ;
tsig - > ttl = 0 ;
tsig - > length = UINT16_MAX ;
2024-05-31 09:38:24 +03:00
tsig - > rdata . tsig_record . algorithm_name = talloc_strdup ( tsig , algorithm ) ;
2018-06-06 19:00:22 +03:00
if ( tsig - > rdata . tsig_record . algorithm_name = = NULL ) {
return WERR_NOT_ENOUGH_MEMORY ;
}
2016-05-30 17:03:33 +03:00
tsig - > rdata . tsig_record . time_prefix = 0 ;
tsig - > rdata . tsig_record . time = current_time ;
tsig - > rdata . tsig_record . fudge = 300 ;
2012-09-05 10:34:04 +04:00
tsig - > rdata . tsig_record . error = state - > tsig_error ;
tsig - > rdata . tsig_record . original_id = packet - > id ;
tsig - > rdata . tsig_record . other_size = 0 ;
tsig - > rdata . tsig_record . other_data = NULL ;
2016-05-30 18:25:56 +03:00
if ( sig . length > 0 ) {
tsig - > rdata . tsig_record . mac_size = sig . length ;
tsig - > rdata . tsig_record . mac = talloc_memdup ( tsig , sig . data , sig . length ) ;
2018-06-06 19:00:22 +03:00
if ( tsig - > rdata . tsig_record . mac = = NULL ) {
return WERR_NOT_ENOUGH_MEMORY ;
}
2016-05-30 18:25:56 +03:00
}
2012-09-05 10:34:04 +04:00
2022-07-14 13:00:51 +03:00
DBG_DEBUG ( " sig.length=%zu \n " , sig . length ) ;
2012-09-05 10:34:04 +04:00
if ( packet - > arcount = = 0 ) {
packet - > additional = talloc_zero ( mem_ctx , struct dns_res_rec ) ;
if ( packet - > additional = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-09-05 10:34:04 +04:00
}
}
packet - > additional = talloc_realloc ( mem_ctx , packet - > additional ,
struct dns_res_rec ,
packet - > arcount + 1 ) ;
if ( packet - > additional = = NULL ) {
2015-12-03 17:24:18 +03:00
return WERR_NOT_ENOUGH_MEMORY ;
2012-09-05 10:34:04 +04:00
}
werror = dns_copy_tsig ( mem_ctx , tsig ,
& packet - > additional [ packet - > arcount ] ) ;
2022-07-14 13:00:51 +03:00
DBG_DEBUG ( " dns_copy_tsig() => %s \n " , win_errstr ( werror ) ) ;
2012-09-05 10:34:04 +04:00
if ( ! W_ERROR_IS_OK ( werror ) ) {
return werror ;
}
packet - > arcount + + ;
return WERR_OK ;
}