2005-01-31 04:57:58 +03:00
/*
Unix SMB / CIFS implementation .
packet utility functions
Copyright ( C ) Andrew Tridgell 2005
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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2005-01-31 04:57:58 +03:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-01-31 04:57:58 +03:00
*/
# include "includes.h"
# include "nbt_server/nbt_server.h"
2020-11-20 17:27:17 +03:00
# include "samba/service_task.h"
2006-01-10 01:12:53 +03:00
# include "lib/socket/socket.h"
2006-03-16 03:23:11 +03:00
# include "librpc/gen_ndr/ndr_nbt.h"
2007-09-08 16:42:09 +04:00
# include "param/param.h"
2005-01-31 04:57:58 +03:00
/*
we received a badly formed packet - log it
*/
2005-02-04 04:39:10 +03:00
void nbtd_bad_packet ( struct nbt_name_packet * packet ,
2006-01-10 01:12:53 +03:00
const struct socket_address * src , const char * reason )
2005-01-31 04:57:58 +03:00
{
2005-10-14 16:22:15 +04:00
DEBUG ( 2 , ( " nbtd: bad packet '%s' from %s:%d \n " , reason , src - > addr , src - > port ) ) ;
2005-01-31 04:57:58 +03:00
if ( DEBUGLVL ( 5 ) ) {
NDR_PRINT_DEBUG ( nbt_name_packet , packet ) ;
}
}
2005-02-04 05:05:27 +03:00
/*
2005-02-04 08:13:46 +03:00
see if an incoming packet is a broadcast packet from one of our own
interfaces
2005-02-04 05:05:27 +03:00
*/
2007-10-07 01:33:16 +04:00
bool nbtd_self_packet_and_bcast ( struct nbt_name_socket * nbtsock ,
2006-01-18 19:36:53 +03:00
struct nbt_name_packet * packet ,
const struct socket_address * src )
2005-02-04 05:05:27 +03:00
{
2008-09-23 11:02:16 +04:00
struct nbtd_interface * iface = talloc_get_type ( nbtsock - > incoming . private_data ,
2005-02-06 11:25:53 +03:00
struct nbtd_interface ) ;
2006-01-18 19:36:53 +03:00
2005-02-04 08:13:46 +03:00
/* if its not a broadcast then its not considered a self packet */
if ( ! ( packet - > operation & NBT_FLAG_BROADCAST ) ) {
2007-10-07 01:33:16 +04:00
return false ;
2005-02-04 08:13:46 +03:00
}
2006-01-18 19:36:53 +03:00
/*
* this uses the fact that iface - > nbtsock is the unicast listen address
* if the interface isn ' t the global bcast interface
*
* so if the request was directed to the unicast address it isn ' t a broadcast
* message
*/
if ( iface - > nbtsock = = nbtsock & &
iface ! = iface - > nbtsrv - > bcast_interface ) {
2007-10-07 01:33:16 +04:00
return false ;
2005-02-04 05:05:27 +03:00
}
2006-01-18 19:36:53 +03:00
return nbtd_self_packet ( nbtsock , packet , src ) ;
}
2007-10-07 01:33:16 +04:00
bool nbtd_self_packet ( struct nbt_name_socket * nbtsock ,
2006-01-18 19:36:53 +03:00
struct nbt_name_packet * packet ,
const struct socket_address * src )
{
2008-09-23 11:02:16 +04:00
struct nbtd_interface * iface = talloc_get_type ( nbtsock - > incoming . private_data ,
2006-01-18 19:36:53 +03:00
struct nbtd_interface ) ;
struct nbtd_server * nbtsrv = iface - > nbtsrv ;
/* if its not from the nbt port, then it wasn't a broadcast from us */
2010-07-16 08:32:42 +04:00
if ( src - > port ! = lpcfg_nbt_port ( iface - > nbtsrv - > task - > lp_ctx ) ) {
2007-10-07 01:33:16 +04:00
return false ;
2005-02-04 08:13:46 +03:00
}
/* we have to loop over our interface list, seeing if its from
one of our own interfaces */
2005-02-04 05:05:27 +03:00
for ( iface = nbtsrv - > interfaces ; iface ; iface = iface - > next ) {
2005-10-14 16:22:15 +04:00
if ( strcmp ( src - > addr , iface - > ip_address ) = = 0 ) {
2007-10-07 01:33:16 +04:00
return true ;
2005-02-04 05:05:27 +03:00
}
}
2007-10-07 01:33:16 +04:00
return false ;
2005-02-04 05:05:27 +03:00
}
2005-02-12 02:54:37 +03:00
2018-02-02 15:30:44 +03:00
struct nbt_name_packet * nbtd_name_query_reply_packet (
TALLOC_CTX * mem_ctx ,
uint16_t trn_id ,
uint32_t ttl ,
uint16_t nb_flags ,
const struct nbt_name * name ,
const char * * addresses ,
size_t num_addresses )
2005-02-12 02:54:37 +03:00
{
struct nbt_name_packet * packet ;
2018-02-02 15:30:44 +03:00
size_t i ;
struct nbt_res_rec * answer ;
struct nbt_rdata_netbios * rdata ;
NTSTATUS status ;
2005-02-12 02:54:37 +03:00
if ( num_addresses = = 0 ) {
2018-02-02 15:30:44 +03:00
return NULL ;
2005-02-12 02:54:37 +03:00
}
2018-02-02 15:30:44 +03:00
packet = talloc_zero ( mem_ctx , struct nbt_name_packet ) ;
if ( packet = = NULL ) {
return NULL ;
}
2005-02-12 02:54:37 +03:00
2018-02-02 15:30:44 +03:00
packet - > name_trn_id = trn_id ;
2005-02-12 02:54:37 +03:00
packet - > ancount = 1 ;
2010-09-30 04:22:09 +04:00
packet - > operation =
NBT_FLAG_REPLY |
NBT_OPCODE_QUERY |
NBT_FLAG_AUTHORITATIVE |
2005-02-12 02:54:37 +03:00
NBT_FLAG_RECURSION_DESIRED |
NBT_FLAG_RECURSION_AVAIL ;
packet - > answers = talloc_array ( packet , struct nbt_res_rec , 1 ) ;
2018-02-02 15:30:44 +03:00
if ( packet - > answers = = NULL ) {
goto failed ;
}
answer = packet - > answers ;
status = nbt_name_dup ( packet - > answers , name , & answer - > name ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto failed ;
}
answer - > rr_type = NBT_QTYPE_NETBIOS ;
answer - > rr_class = NBT_QCLASS_IP ;
answer - > ttl = ttl ;
rdata = & answer - > rdata . netbios ;
rdata - > length = num_addresses * 6 ;
rdata - > addresses = talloc_array (
packet - > answers ,
struct nbt_rdata_address ,
num_addresses ) ;
if ( rdata - > addresses = = NULL ) {
goto failed ;
}
for ( i = 0 ; i < num_addresses ; i + + ) {
struct nbt_rdata_address * addr = & rdata - > addresses [ i ] ;
2005-02-12 02:54:37 +03:00
addr - > nb_flags = nb_flags ;
addr - > ipaddr = talloc_strdup ( packet - > answers , addresses [ i ] ) ;
2018-02-02 15:30:44 +03:00
if ( addr - > ipaddr = = NULL ) {
goto failed ;
}
}
return packet ;
failed :
TALLOC_FREE ( packet ) ;
return NULL ;
}
/*
send a name query reply
*/
void nbtd_name_query_reply ( struct nbt_name_socket * nbtsock ,
struct nbt_name_packet * request_packet ,
struct socket_address * src ,
struct nbt_name * name , uint32_t ttl ,
uint16_t nb_flags , const char * * addresses )
{
struct nbt_name_packet * packet ;
struct nbtd_interface * iface = talloc_get_type ( nbtsock - > incoming . private_data ,
struct nbtd_interface ) ;
struct nbtd_server * nbtsrv = iface - > nbtsrv ;
packet = nbtd_name_query_reply_packet (
nbtsock ,
request_packet - > name_trn_id ,
ttl ,
nb_flags ,
name ,
addresses ,
str_list_length ( addresses ) ) ;
if ( packet = = NULL ) {
return ;
2005-02-12 02:54:37 +03:00
}
2005-02-12 04:00:15 +03:00
DEBUG ( 7 , ( " Sending name query reply for %s at %s to %s:%d \n " ,
2005-10-14 16:22:15 +04:00
nbt_name_string ( packet , name ) , addresses [ 0 ] , src - > addr , src - > port ) ) ;
2005-02-12 02:54:37 +03:00
2005-07-10 12:41:02 +04:00
nbtsrv - > stats . total_sent + + ;
2005-10-14 16:22:15 +04:00
nbt_name_reply_send ( nbtsock , src , packet ) ;
2005-02-12 02:54:37 +03:00
talloc_free ( packet ) ;
}
/*
send a negative name query reply
*/
void nbtd_negative_name_query_reply ( struct nbt_name_socket * nbtsock ,
struct nbt_name_packet * request_packet ,
2006-01-10 01:12:53 +03:00
struct socket_address * src )
2005-02-12 02:54:37 +03:00
{
struct nbt_name_packet * packet ;
struct nbt_name * name = & request_packet - > questions [ 0 ] . name ;
2008-09-23 11:02:16 +04:00
struct nbtd_interface * iface = talloc_get_type ( nbtsock - > incoming . private_data ,
2005-07-10 12:41:02 +04:00
struct nbtd_interface ) ;
struct nbtd_server * nbtsrv = iface - > nbtsrv ;
2005-02-12 02:54:37 +03:00
packet = talloc_zero ( nbtsock , struct nbt_name_packet ) ;
if ( packet = = NULL ) return ;
packet - > name_trn_id = request_packet - > name_trn_id ;
packet - > ancount = 1 ;
2010-09-30 04:22:09 +04:00
packet - > operation =
NBT_FLAG_REPLY |
NBT_OPCODE_QUERY |
NBT_FLAG_AUTHORITATIVE |
2005-02-12 02:54:37 +03:00
NBT_RCODE_NAM ;
packet - > answers = talloc_array ( packet , struct nbt_res_rec , 1 ) ;
if ( packet - > answers = = NULL ) goto failed ;
packet - > answers [ 0 ] . name = * name ;
packet - > answers [ 0 ] . rr_type = NBT_QTYPE_NULL ;
packet - > answers [ 0 ] . rr_class = NBT_QCLASS_IP ;
packet - > answers [ 0 ] . ttl = 0 ;
ZERO_STRUCT ( packet - > answers [ 0 ] . rdata ) ;
2005-02-12 04:00:15 +03:00
DEBUG ( 7 , ( " Sending negative name query reply for %s to %s:%d \n " ,
2005-10-14 16:22:15 +04:00
nbt_name_string ( packet , name ) , src - > addr , src - > port ) ) ;
2005-02-12 02:54:37 +03:00
2005-07-10 12:41:02 +04:00
nbtsrv - > stats . total_sent + + ;
2005-10-14 16:22:15 +04:00
nbt_name_reply_send ( nbtsock , src , packet ) ;
2005-02-12 02:54:37 +03:00
failed :
talloc_free ( packet ) ;
}
/*
2005-02-12 14:33:42 +03:00
send a name registration reply
2005-02-12 02:54:37 +03:00
*/
2005-02-12 14:33:42 +03:00
void nbtd_name_registration_reply ( struct nbt_name_socket * nbtsock ,
struct nbt_name_packet * request_packet ,
2006-01-10 01:12:53 +03:00
struct socket_address * src ,
2005-02-12 14:33:42 +03:00
uint8_t rcode )
2005-02-12 02:54:37 +03:00
{
struct nbt_name_packet * packet ;
struct nbt_name * name = & request_packet - > questions [ 0 ] . name ;
2008-09-23 11:02:16 +04:00
struct nbtd_interface * iface = talloc_get_type ( nbtsock - > incoming . private_data ,
2005-07-10 12:41:02 +04:00
struct nbtd_interface ) ;
struct nbtd_server * nbtsrv = iface - > nbtsrv ;
2005-02-12 02:54:37 +03:00
packet = talloc_zero ( nbtsock , struct nbt_name_packet ) ;
if ( packet = = NULL ) return ;
packet - > name_trn_id = request_packet - > name_trn_id ;
packet - > ancount = 1 ;
2010-09-30 04:22:09 +04:00
packet - > operation =
NBT_FLAG_REPLY |
2005-02-12 02:54:37 +03:00
NBT_OPCODE_REGISTER |
2010-09-30 04:22:09 +04:00
NBT_FLAG_AUTHORITATIVE |
2005-02-12 02:54:37 +03:00
NBT_FLAG_RECURSION_DESIRED |
NBT_FLAG_RECURSION_AVAIL |
2005-02-12 14:33:42 +03:00
rcode ;
2005-02-12 02:54:37 +03:00
packet - > answers = talloc_array ( packet , struct nbt_res_rec , 1 ) ;
if ( packet - > answers = = NULL ) goto failed ;
packet - > answers [ 0 ] . name = * name ;
packet - > answers [ 0 ] . rr_type = NBT_QTYPE_NETBIOS ;
packet - > answers [ 0 ] . rr_class = NBT_QCLASS_IP ;
2005-02-12 14:33:42 +03:00
packet - > answers [ 0 ] . ttl = request_packet - > additional [ 0 ] . ttl ;
2005-02-12 02:54:37 +03:00
packet - > answers [ 0 ] . rdata = request_packet - > additional [ 0 ] . rdata ;
2005-02-12 14:33:42 +03:00
DEBUG ( 7 , ( " Sending %s name registration reply for %s to %s:%d \n " ,
rcode = = 0 ? " positive " : " negative " ,
2005-10-14 16:22:15 +04:00
nbt_name_string ( packet , name ) , src - > addr , src - > port ) ) ;
2005-02-12 14:33:42 +03:00
2005-07-10 12:41:02 +04:00
nbtsrv - > stats . total_sent + + ;
2005-10-14 16:22:15 +04:00
nbt_name_reply_send ( nbtsock , src , packet ) ;
2005-02-12 14:33:42 +03:00
failed :
talloc_free ( packet ) ;
}
/*
send a name release reply
*/
void nbtd_name_release_reply ( struct nbt_name_socket * nbtsock ,
struct nbt_name_packet * request_packet ,
2006-01-10 01:12:53 +03:00
struct socket_address * src ,
2005-02-12 14:33:42 +03:00
uint8_t rcode )
{
struct nbt_name_packet * packet ;
struct nbt_name * name = & request_packet - > questions [ 0 ] . name ;
2008-09-23 11:02:16 +04:00
struct nbtd_interface * iface = talloc_get_type ( nbtsock - > incoming . private_data ,
2005-07-10 12:41:02 +04:00
struct nbtd_interface ) ;
struct nbtd_server * nbtsrv = iface - > nbtsrv ;
2005-02-12 14:33:42 +03:00
packet = talloc_zero ( nbtsock , struct nbt_name_packet ) ;
if ( packet = = NULL ) return ;
packet - > name_trn_id = request_packet - > name_trn_id ;
packet - > ancount = 1 ;
2010-09-30 04:22:09 +04:00
packet - > operation =
NBT_FLAG_REPLY |
2005-02-12 14:33:42 +03:00
NBT_OPCODE_RELEASE |
2010-09-30 04:22:09 +04:00
NBT_FLAG_AUTHORITATIVE |
2005-02-12 14:33:42 +03:00
rcode ;
packet - > answers = talloc_array ( packet , struct nbt_res_rec , 1 ) ;
if ( packet - > answers = = NULL ) goto failed ;
packet - > answers [ 0 ] . name = * name ;
packet - > answers [ 0 ] . rr_type = NBT_QTYPE_NETBIOS ;
packet - > answers [ 0 ] . rr_class = NBT_QCLASS_IP ;
packet - > answers [ 0 ] . ttl = request_packet - > additional [ 0 ] . ttl ;
packet - > answers [ 0 ] . rdata = request_packet - > additional [ 0 ] . rdata ;
DEBUG ( 7 , ( " Sending %s name release reply for %s to %s:%d \n " ,
rcode = = 0 ? " positive " : " negative " ,
2005-10-14 16:22:15 +04:00
nbt_name_string ( packet , name ) , src - > addr , src - > port ) ) ;
2005-02-12 02:54:37 +03:00
2005-07-10 12:41:02 +04:00
nbtsrv - > stats . total_sent + + ;
2005-10-14 16:22:15 +04:00
nbt_name_reply_send ( nbtsock , src , packet ) ;
2005-02-12 02:54:37 +03:00
failed :
talloc_free ( packet ) ;
}
2005-02-14 12:15:24 +03:00
/*
send a WACK reply
*/
void nbtd_wack_reply ( struct nbt_name_socket * nbtsock ,
struct nbt_name_packet * request_packet ,
2006-01-10 01:12:53 +03:00
struct socket_address * src ,
2005-02-14 12:15:24 +03:00
uint32_t ttl )
{
struct nbt_name_packet * packet ;
struct nbt_name * name = & request_packet - > questions [ 0 ] . name ;
2008-09-23 11:02:16 +04:00
struct nbtd_interface * iface = talloc_get_type ( nbtsock - > incoming . private_data ,
2005-07-10 12:41:02 +04:00
struct nbtd_interface ) ;
struct nbtd_server * nbtsrv = iface - > nbtsrv ;
2005-02-14 12:15:24 +03:00
packet = talloc_zero ( nbtsock , struct nbt_name_packet ) ;
if ( packet = = NULL ) return ;
packet - > name_trn_id = request_packet - > name_trn_id ;
packet - > ancount = 1 ;
2010-09-30 04:22:09 +04:00
packet - > operation =
NBT_FLAG_REPLY |
2005-02-14 12:15:24 +03:00
NBT_OPCODE_WACK |
2010-09-30 04:22:09 +04:00
NBT_FLAG_AUTHORITATIVE ;
2005-02-14 12:15:24 +03:00
packet - > answers = talloc_array ( packet , struct nbt_res_rec , 1 ) ;
if ( packet - > answers = = NULL ) goto failed ;
packet - > answers [ 0 ] . name = * name ;
librpc/nbt: Avoid reading invalid member of union
WACK packets use the ‘data’ member of the ‘nbt_rdata’ union, but they
claim to be a different type — NBT_QTYPE_NETBIOS — than would normally
be used with that union member. This means that if rr_type is equal to
NBT_QTYPE_NETBIOS, ndr_push_nbt_res_rec() has to guess which type the
structure really is by examining the data member. However, if the
structure is actually of a different type, that union member will not be
valid and accessing it will invoke undefined behaviour.
To fix this, eliminate all the guesswork and introduce a new type,
NBT_QTYPE_WACK, which can never appear on the wire, and which indicates
that although the ‘data’ union member should be used, the wire type is
actually NBT_QTYPE_NETBIOS.
This means that as far as NDR is concerned, the ‘netbios’ member of the
‘nbt_rdata’ union will consistently be used for all NBT_QTYPE_NETBIOS
structures; we shall no longer access the wrong member of the union.
Credit to OSS-Fuzz.
REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=38480
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15019
Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Autobuild-User(master): Douglas Bagnall <dbagnall@samba.org>
Autobuild-Date(master): Fri Jul 7 01:14:06 UTC 2023 on atb-devel-224
2023-07-06 01:57:59 +03:00
packet - > answers [ 0 ] . rr_type = NBT_QTYPE_WACK ;
2005-02-14 12:15:24 +03:00
packet - > answers [ 0 ] . rr_class = NBT_QCLASS_IP ;
packet - > answers [ 0 ] . ttl = ttl ;
packet - > answers [ 0 ] . rdata . data . length = 2 ;
2007-09-08 20:46:30 +04:00
packet - > answers [ 0 ] . rdata . data . data = talloc_array ( packet , uint8_t , 2 ) ;
2005-02-14 12:15:24 +03:00
if ( packet - > answers [ 0 ] . rdata . data . data = = NULL ) goto failed ;
RSSVAL ( packet - > answers [ 0 ] . rdata . data . data , 0 , request_packet - > operation ) ;
DEBUG ( 7 , ( " Sending WACK reply for %s to %s:%d \n " ,
2005-10-14 16:22:15 +04:00
nbt_name_string ( packet , name ) , src - > addr , src - > port ) ) ;
2005-02-14 12:15:24 +03:00
2005-07-10 12:41:02 +04:00
nbtsrv - > stats . total_sent + + ;
2005-10-14 16:22:15 +04:00
nbt_name_reply_send ( nbtsock , src , packet ) ;
2005-02-14 12:15:24 +03:00
failed :
talloc_free ( packet ) ;
}