1997-12-13 17:16:07 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1997-12-13 17:16:07 +03:00
NBT netbios routines and daemon - version 2
1998-01-22 16:27:43 +03:00
Copyright ( C ) Andrew Tridgell 1994 - 1998
Copyright ( C ) Luke Kenneth Casson Leighton 1994 - 1998
Copyright ( C ) Jeremy Allison 1994 - 1998
1997-12-13 17:16:07 +03:00
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-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1997-12-13 17:16:07 +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 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1997-12-13 17:16:07 +03:00
*/
# include "includes.h"
1997-12-16 12:20:34 +03:00
extern BOOL found_lm_clients ;
1997-12-13 17:16:07 +03:00
#if 0
/* XXXX note: This function is currently unsuitable for use, as it
does not properly check that a server is in a fit state to become
a backup browser before asking it to be one .
The code is left here to be worked on at a later date .
*/
/****************************************************************************
Tell a server to become a backup browser
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void tell_become_backup ( void )
{
struct subnet_record * subrec ;
for ( subrec = FIRST_SUBNET ; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST ( subrec ) )
{
struct work_record * work ;
for ( work = subrec - > workgrouplist ; work ; work = work - > next )
{
struct server_record * servrec ;
int num_servers = 0 ;
int num_backups = 0 ;
for ( servrec = work - > serverlist ; servrec ; servrec = servrec - > next )
{
num_servers + + ;
if ( is_myname ( servrec - > serv . name ) )
continue ;
if ( servrec - > serv . type & SV_TYPE_BACKUP_BROWSER )
{
num_backups + + ;
continue ;
}
if ( servrec - > serv . type & SV_TYPE_MASTER_BROWSER )
continue ;
if ( ! ( servrec - > serv . type & SV_TYPE_POTENTIAL_BROWSER ) )
continue ;
DEBUG ( 3 , ( " num servers: %d num backups: %d \n " ,
num_servers , num_backups ) ) ;
/* make first server a backup server. thereafter make every
tenth server a backup server */
if ( num_backups ! = 0 & & ( num_servers + 9 ) / num_backups > 10 )
continue ;
DEBUG ( 2 , ( " sending become backup to %s %s for %s \n " ,
servrec - > serv . name , inet_ntoa ( subrec - > bcast_ip ) ,
work - > work_group ) ) ;
/* type 11 request from MYNAME(20) to WG(1e) for SERVER */
do_announce_request ( servrec - > serv . name , work - > work_group ,
ANN_BecomeBackup , 0x20 , 0x1e , subrec - > bcast_ip ) ;
}
}
}
}
# endif
/*******************************************************************
Process an incoming host announcement packet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void process_host_announce ( struct subnet_record * subrec , struct packet_struct * p , char * buf )
{
2003-08-23 05:59:14 +04:00
struct dgram_packet * dgram = & p - > packet . dgram ;
int ttl = IVAL ( buf , 1 ) / 1000 ;
2004-03-16 00:45:45 +03:00
unstring announce_name ;
2003-08-23 05:59:14 +04:00
uint32 servertype = IVAL ( buf , 23 ) ;
fstring comment ;
struct work_record * work ;
struct server_record * servrec ;
2004-03-16 00:45:45 +03:00
unstring work_name ;
unstring source_name ;
2003-08-23 05:59:14 +04:00
START_PROFILE ( host_announce ) ;
pull_ascii_fstring ( comment , buf + 31 ) ;
1997-12-13 17:16:07 +03:00
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( announce_name , sizeof ( announce_name ) , buf + 5 ) ;
pull_ascii_nstring ( source_name , sizeof ( source_name ) , dgram - > source_name . name ) ;
2003-08-23 05:59:14 +04:00
DEBUG ( 3 , ( " process_host_announce: from %s<%02x> IP %s to \
1997-12-13 17:16:07 +03:00
% s for server % s . \ n " , source_name, source_name[15], inet_ntoa(p->ip),
2003-08-23 05:59:14 +04:00
nmb_namestr ( & dgram - > dest_name ) , announce_name ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
DEBUG ( 5 , ( " process_host_announce: ttl=%d server type=%08x comment=%s \n " ,
ttl , servertype , comment ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
/* Filter servertype to remove impossible bits. */
servertype & = ~ ( SV_TYPE_LOCAL_LIST_ONLY | SV_TYPE_DOMAIN_ENUM ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
/* A host announcement must be sent to the name WORKGROUP<1d>. */
if ( dgram - > dest_name . name_type ! = 0x1d ) {
DEBUG ( 2 , ( " process_host_announce: incorrect name type for destination from IP %s \
1997-12-13 17:16:07 +03:00
( was % 02 x ) should be 0x1d . Allowing packet anyway . \ n " ,
2003-08-23 05:59:14 +04:00
inet_ntoa ( p - > ip ) , dgram - > dest_name . name_type ) ) ;
/* Change it so it was. */
dgram - > dest_name . name_type = 0x1d ;
}
/* For a host announce the workgroup name is the destination name. */
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( work_name , sizeof ( work_name ) , dgram - > dest_name . name ) ;
2003-08-23 05:59:14 +04:00
/*
* Syntax servers version 5.1 send HostAnnounce packets to
* * THE WRONG NAME * . They send to LOCAL_MASTER_BROWSER_NAME < 00 >
* instead of WORKGROUP < 1 d > name . So to fix this we check if
* the workgroup name is our own name , and if so change it
* to be our primary workgroup name .
*/
if ( strequal ( work_name , global_myname ( ) ) )
2004-03-16 00:45:45 +03:00
unstrcpy ( work_name , lp_workgroup ( ) ) ;
2003-08-23 05:59:14 +04:00
/*
* We are being very agressive here in adding a workgroup
* name on the basis of a host announcing itself as being
* in that workgroup . Maybe we should wait for the workgroup
* announce instead ? JRA .
*/
work = find_workgroup_on_subnet ( subrec , work_name ) ;
if ( servertype ! = 0 ) {
if ( work = = NULL ) {
/* We have no record of this workgroup. Add it. */
if ( ( work = create_workgroup_on_subnet ( subrec , work_name , ttl ) ) = = NULL )
goto done ;
}
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
if ( ( servrec = find_server_in_workgroup ( work , announce_name ) ) = = NULL ) {
/* If this server is not already in the workgroup, add it. */
create_server_on_workgroup ( work , announce_name ,
servertype | SV_TYPE_LOCAL_LIST_ONLY ,
ttl , comment ) ;
} else {
/* Update the record. */
servrec - > serv . type = servertype | SV_TYPE_LOCAL_LIST_ONLY ;
update_server_ttl ( servrec , ttl ) ;
fstrcpy ( servrec - > serv . comment , comment ) ;
}
} else {
/*
* This server is announcing it is going down . Remove it from the
* workgroup .
*/
if ( ! is_myname ( announce_name ) & & ( work ! = NULL ) & &
( ( servrec = find_server_in_workgroup ( work , announce_name ) ) ! = NULL ) ) {
remove_server_from_workgroup ( work , servrec ) ;
}
}
subrec - > work_changed = True ;
2001-09-05 22:43:55 +04:00
done :
2003-08-23 05:59:14 +04:00
END_PROFILE ( host_announce ) ;
1997-12-13 17:16:07 +03:00
}
/*******************************************************************
Process an incoming WORKGROUP announcement packet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void process_workgroup_announce ( struct subnet_record * subrec , struct packet_struct * p , char * buf )
{
2003-08-23 05:59:14 +04:00
struct dgram_packet * dgram = & p - > packet . dgram ;
int ttl = IVAL ( buf , 1 ) / 1000 ;
2004-03-16 00:45:45 +03:00
unstring workgroup_announce_name ;
unstring master_name ;
2003-08-23 05:59:14 +04:00
uint32 servertype = IVAL ( buf , 23 ) ;
struct work_record * work ;
2004-03-16 00:45:45 +03:00
unstring source_name ;
unstring dest_name ;
2003-08-23 05:59:14 +04:00
START_PROFILE ( workgroup_announce ) ;
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( workgroup_announce_name , sizeof ( workgroup_announce_name ) , buf + 5 ) ;
pull_ascii_nstring ( master_name , sizeof ( master_name ) , buf + 31 ) ;
pull_ascii_nstring ( source_name , sizeof ( source_name ) , dgram - > source_name . name ) ;
pull_ascii_nstring ( dest_name , sizeof ( dest_name ) , dgram - > dest_name . name ) ;
2003-08-23 05:59:14 +04:00
DEBUG ( 3 , ( " process_workgroup_announce: from %s<%02x> IP %s to \
1997-12-13 17:16:07 +03:00
% s for workgroup % s . \ n " , source_name, source_name[15], inet_ntoa(p->ip),
2003-08-23 05:59:14 +04:00
nmb_namestr ( & dgram - > dest_name ) , workgroup_announce_name ) ) ;
DEBUG ( 5 , ( " process_workgroup_announce: ttl=%d server type=%08x master browser=%s \n " ,
ttl , servertype , master_name ) ) ;
/* Workgroup announcements must only go to the MSBROWSE name. */
if ( ! strequal ( dest_name , MSBROWSE ) | | ( dgram - > dest_name . name_type ! = 0x1 ) ) {
DEBUG ( 0 , ( " process_workgroup_announce: from IP %s should be to __MSBROWSE__<0x01> not %s \n " ,
inet_ntoa ( p - > ip ) , nmb_namestr ( & dgram - > dest_name ) ) ) ;
goto done ;
}
if ( ( work = find_workgroup_on_subnet ( subrec , workgroup_announce_name ) ) = = NULL ) {
/* We have no record of this workgroup. Add it. */
if ( ( work = create_workgroup_on_subnet ( subrec , workgroup_announce_name , ttl ) ) = = NULL )
goto done ;
} else {
/* Update the workgroup death_time. */
update_workgroup_ttl ( work , ttl ) ;
}
if ( * work - > local_master_browser_name = = ' \0 ' ) {
/* Set the master browser name. */
set_workgroup_local_master_browser_name ( work , master_name ) ;
}
subrec - > work_changed = True ;
1997-12-13 17:16:07 +03:00
2001-09-05 22:43:55 +04:00
done :
2003-08-23 05:59:14 +04:00
END_PROFILE ( workgroup_announce ) ;
1997-12-13 17:16:07 +03:00
}
/*******************************************************************
Process an incoming local master browser announcement packet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void process_local_master_announce ( struct subnet_record * subrec , struct packet_struct * p , char * buf )
{
2003-08-23 05:59:14 +04:00
struct dgram_packet * dgram = & p - > packet . dgram ;
int ttl = IVAL ( buf , 1 ) / 1000 ;
2004-03-16 00:45:45 +03:00
unstring server_name ;
2003-08-23 05:59:14 +04:00
uint32 servertype = IVAL ( buf , 23 ) ;
fstring comment ;
2004-03-16 00:45:45 +03:00
unstring work_name ;
2003-08-23 05:59:14 +04:00
struct work_record * work ;
struct server_record * servrec ;
2004-03-16 00:45:45 +03:00
unstring source_name ;
2003-08-23 05:59:14 +04:00
START_PROFILE ( local_master_announce ) ;
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( server_name , sizeof ( server_name ) , buf + 5 ) ;
2003-08-23 05:59:14 +04:00
pull_ascii_fstring ( comment , buf + 31 ) ;
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( source_name , sizeof ( source_name ) , dgram - > source_name . name ) ;
pull_ascii_nstring ( work_name , sizeof ( work_name ) , dgram - > dest_name . name ) ;
2003-08-23 05:59:14 +04:00
DEBUG ( 3 , ( " process_local_master_announce: from %s<%02x> IP %s to \
1997-12-13 17:16:07 +03:00
% s for server % s . \ n " , source_name, source_name[15], inet_ntoa(p->ip),
2003-08-23 05:59:14 +04:00
nmb_namestr ( & dgram - > dest_name ) , server_name ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
DEBUG ( 5 , ( " process_local_master_announce: ttl=%d server type=%08x comment=%s \n " ,
ttl , servertype , comment ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
/* A local master announcement must be sent to the name WORKGROUP<1e>. */
if ( dgram - > dest_name . name_type ! = 0x1e ) {
DEBUG ( 0 , ( " process_local_master_announce: incorrect name type for destination from IP %s \
1997-12-13 17:16:07 +03:00
( was % 02 x ) should be 0x1e . Ignoring packet . \ n " ,
2003-08-23 05:59:14 +04:00
inet_ntoa ( p - > ip ) , dgram - > dest_name . name_type ) ) ;
goto done ;
}
/* Filter servertype to remove impossible bits. */
servertype & = ~ ( SV_TYPE_LOCAL_LIST_ONLY | SV_TYPE_DOMAIN_ENUM ) ;
/* For a local master announce the workgroup name is the destination name. */
if ( ( work = find_workgroup_on_subnet ( subrec , work_name ) ) = = NULL ) {
/* Don't bother adding if it's a local master release announce. */
if ( servertype = = 0 )
goto done ;
/* We have no record of this workgroup. Add it. */
if ( ( work = create_workgroup_on_subnet ( subrec , work_name , ttl ) ) = = NULL )
goto done ;
}
/* If we think we're the local master browser for this workgroup,
we should never have got this packet . We don ' t see our own
packets .
*/
if ( AM_LOCAL_MASTER_BROWSER ( work ) ) {
DEBUG ( 0 , ( " process_local_master_announce: Server %s at IP %s is announcing itself as \
1997-12-13 17:16:07 +03:00
a local master browser for workgroup % s and we think we are master . Forcing election . \ n " ,
2003-08-23 05:59:14 +04:00
server_name , inet_ntoa ( p - > ip ) , work_name ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
/* Samba nmbd versions 1.9.17 to 1.9.17p4 have a bug in that when
they have become a local master browser once , they will never
stop sending local master announcements . To fix this we send
them a reset browser packet , with level 0x2 on the __SAMBA__
name that only they should be listening to . */
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
send_browser_reset ( 0x2 , " __SAMBA__ " , 0x20 , p - > ip ) ;
/* We should demote ourself and force an election. */
unbecome_local_master_browser ( subrec , work , True ) ;
/* The actual election requests are handled in nmbd_election.c */
goto done ;
}
/* Find the server record on this workgroup. If it doesn't exist, add it. */
if ( servertype ! = 0 ) {
if ( ( servrec = find_server_in_workgroup ( work , server_name ) ) = = NULL ) {
/* If this server is not already in the workgroup, add it. */
create_server_on_workgroup ( work , server_name ,
servertype | SV_TYPE_LOCAL_LIST_ONLY ,
ttl , comment ) ;
} else {
/* Update the record. */
servrec - > serv . type = servertype | SV_TYPE_LOCAL_LIST_ONLY ;
update_server_ttl ( servrec , ttl ) ;
fstrcpy ( servrec - > serv . comment , comment ) ;
}
set_workgroup_local_master_browser_name ( work , server_name ) ;
} else {
/*
* This server is announcing it is going down . Remove it from the
* workgroup .
*/
if ( ! is_myname ( server_name ) & & ( work ! = NULL ) & &
( ( servrec = find_server_in_workgroup ( work , server_name ) ) ! = NULL ) ) {
remove_server_from_workgroup ( work , servrec ) ;
}
}
subrec - > work_changed = True ;
2001-09-05 22:43:55 +04:00
done :
2003-08-23 05:59:14 +04:00
END_PROFILE ( local_master_announce ) ;
1997-12-13 17:16:07 +03:00
}
/*******************************************************************
Process a domain master announcement frame .
Domain master browsers receive these from local masters . The Domain
master should then issue a sync with the local master , asking for
that machines local server list .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void process_master_browser_announce ( struct subnet_record * subrec ,
struct packet_struct * p , char * buf )
{
2004-03-16 00:45:45 +03:00
unstring local_master_name ;
2003-08-23 05:59:14 +04:00
struct work_record * work ;
struct browse_cache_record * browrec ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
START_PROFILE ( master_browser_announce ) ;
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( local_master_name , sizeof ( local_master_name ) , buf ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
DEBUG ( 3 , ( " process_master_browser_announce: Local master announce from %s IP %s. \n " ,
local_master_name , inet_ntoa ( p - > ip ) ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
if ( ! lp_domain_master ( ) ) {
DEBUG ( 0 , ( " process_master_browser_announce: Not configured as domain \
1997-12-13 17:16:07 +03:00
master - ignoring master announce . \ n " ));
2003-08-23 05:59:14 +04:00
goto done ;
}
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
if ( ( work = find_workgroup_on_subnet ( subrec , lp_workgroup ( ) ) ) = = NULL ) {
DEBUG ( 0 , ( " process_master_browser_announce: Cannot find workgroup %s on subnet %s \n " ,
lp_workgroup ( ) , subrec - > subnet_name ) ) ;
goto done ;
}
if ( ! AM_DOMAIN_MASTER_BROWSER ( work ) ) {
DEBUG ( 0 , ( " process_master_browser_announce: Local master announce made to us from \
1997-12-13 17:16:07 +03:00
% s IP % s and we are not a domain master browser . \ n " , local_master_name, inet_ntoa(p->ip)));
2003-08-23 05:59:14 +04:00
goto done ;
}
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
/* Add this host as a local master browser entry on the browse lists.
This causes a sync request to be made to it at a later date .
*/
if ( ( browrec = find_browser_in_lmb_cache ( local_master_name ) ) = = NULL ) {
/* Add it. */
create_browser_in_lmb_cache ( work - > work_group , local_master_name , p - > ip ) ;
} else {
update_browser_death_time ( browrec ) ;
}
1997-12-13 17:16:07 +03:00
2001-09-05 22:43:55 +04:00
done :
2003-08-23 05:59:14 +04:00
END_PROFILE ( master_browser_announce ) ;
1997-12-13 17:16:07 +03:00
}
1997-12-16 12:20:34 +03:00
/*******************************************************************
Process an incoming LanMan host announcement packet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-03-31 02:25:08 +04:00
void process_lm_host_announce ( struct subnet_record * subrec , struct packet_struct * p , char * buf , int len )
1997-12-16 12:20:34 +03:00
{
2003-08-23 05:59:14 +04:00
struct dgram_packet * dgram = & p - > packet . dgram ;
uint32 servertype = IVAL ( buf , 1 ) ;
int osmajor = CVAL ( buf , 5 ) ; /* major version of node software */
int osminor = CVAL ( buf , 6 ) ; /* minor version of node software */
int ttl = SVAL ( buf , 7 ) ;
2004-03-16 00:45:45 +03:00
unstring announce_name ;
2003-08-23 05:59:14 +04:00
struct work_record * work ;
struct server_record * servrec ;
2004-03-16 00:45:45 +03:00
unstring work_name ;
unstring source_name ;
2003-08-23 05:59:14 +04:00
fstring comment ;
r22042: Try and clean up my own mess using the API Volker
suggested. I now use :
BOOL is_offset_safe(const char *buf_base, size_t buf_len, char *ptr, size_t off)
char *get_safe_ptr(const char *buf_base, size_t buf_len, char *ptr, size_t off)
char *get_safe_str_ptr(const char *buf_base, size_t buf_len, char *ptr, size_t off)
int get_safe_SVAL(const char *buf_base, size_t buf_len, char *ptr, size_t off, int failval)
int get_safe_IVAL(const char *buf_base, size_t buf_len, char *ptr, size_t off, int failval)
Volker, please criticize and comment. Thanks,
Jeremy.
(This used to be commit d47af7c9263f519e7307859b6a696d854c5dfca3)
2007-04-02 23:04:57 +04:00
char * s = get_safe_str_ptr ( buf , len , buf , 9 ) ;
2003-08-23 05:59:14 +04:00
2007-03-31 07:11:02 +04:00
START_PROFILE ( lm_host_announce ) ;
2007-03-31 02:25:08 +04:00
if ( ! s ) {
2007-03-31 07:11:02 +04:00
goto done ;
2007-03-31 02:25:08 +04:00
}
2007-04-03 00:10:21 +04:00
s = skip_string ( buf , len , s ) ;
2007-03-31 02:25:08 +04:00
if ( ! s ) {
2007-03-31 07:11:02 +04:00
goto done ;
2007-03-31 02:25:08 +04:00
}
2003-08-23 05:59:14 +04:00
pull_ascii ( comment , s , sizeof ( fstring ) , 43 , STR_TERMINATE ) ;
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( announce_name , sizeof ( announce_name ) , buf + 9 ) ;
pull_ascii_nstring ( source_name , sizeof ( source_name ) , dgram - > source_name . name ) ;
2003-08-23 05:59:14 +04:00
/* For a LanMan host announce the workgroup name is the destination name. */
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( work_name , sizeof ( work_name ) , dgram - > dest_name . name ) ;
2003-08-23 05:59:14 +04:00
DEBUG ( 3 , ( " process_lm_host_announce: LM Announcement from %s IP %s to \
% s for server % s . \ n " , nmb_namestr(&dgram->source_name), inet_ntoa(p->ip),
nmb_namestr ( & dgram - > dest_name ) , announce_name ) ) ;
DEBUG ( 5 , ( " process_lm_host_announce: os=(%d,%d) ttl=%d server type=%08x comment=%s \n " ,
osmajor , osminor , ttl , servertype , comment ) ) ;
if ( ( osmajor < 36 ) | | ( osmajor > 38 ) | | ( osminor ! = 0 ) ) {
DEBUG ( 5 , ( " process_lm_host_announce: LM Announcement packet does not \
1998-02-24 20:59:34 +03:00
originate from OS / 2 Warp client . Ignoring packet . \ n " ));
2003-08-23 05:59:14 +04:00
/* Could have been from a Windows machine (with its LM Announce enabled),
or a Samba server . Then don ' t disrupt the current browse list . */
goto done ;
}
1997-12-16 12:20:34 +03:00
2003-08-23 05:59:14 +04:00
/* Filter servertype to remove impossible bits. */
servertype & = ~ ( SV_TYPE_LOCAL_LIST_ONLY | SV_TYPE_DOMAIN_ENUM ) ;
1997-12-16 12:20:34 +03:00
2003-08-23 05:59:14 +04:00
/* A LanMan host announcement must be sent to the name WORKGROUP<00>. */
if ( dgram - > dest_name . name_type ! = 0x00 ) {
DEBUG ( 2 , ( " process_lm_host_announce: incorrect name type for destination from IP %s \
1997-12-16 12:20:34 +03:00
( was % 02 x ) should be 0x00 . Allowing packet anyway . \ n " ,
2003-08-23 05:59:14 +04:00
inet_ntoa ( p - > ip ) , dgram - > dest_name . name_type ) ) ;
/* Change it so it was. */
dgram - > dest_name . name_type = 0x00 ;
}
/*
* Syntax servers version 5.1 send HostAnnounce packets to
* * THE WRONG NAME * . They send to LOCAL_MASTER_BROWSER_NAME < 00 >
* instead of WORKGROUP < 1 d > name . So to fix this we check if
* the workgroup name is our own name , and if so change it
* to be our primary workgroup name . This code is probably
* not needed in the LanMan announce code , but it won ' t hurt .
*/
if ( strequal ( work_name , global_myname ( ) ) )
2004-03-16 00:45:45 +03:00
unstrcpy ( work_name , lp_workgroup ( ) ) ;
2003-08-23 05:59:14 +04:00
/*
* We are being very agressive here in adding a workgroup
* name on the basis of a host announcing itself as being
* in that workgroup . Maybe we should wait for the workgroup
* announce instead ? JRA .
*/
work = find_workgroup_on_subnet ( subrec , work_name ) ;
if ( servertype ! = 0 ) {
if ( work = = NULL ) {
/* We have no record of this workgroup. Add it. */
if ( ( work = create_workgroup_on_subnet ( subrec , work_name , ttl ) ) = = NULL )
goto done ;
}
if ( ( servrec = find_server_in_workgroup ( work , announce_name ) ) = = NULL ) {
/* If this server is not already in the workgroup, add it. */
create_server_on_workgroup ( work , announce_name ,
servertype | SV_TYPE_LOCAL_LIST_ONLY ,
ttl , comment ) ;
} else {
/* Update the record. */
servrec - > serv . type = servertype | SV_TYPE_LOCAL_LIST_ONLY ;
update_server_ttl ( servrec , ttl ) ;
fstrcpy ( servrec - > serv . comment , comment ) ;
}
} else {
/*
* This server is announcing it is going down . Remove it from the
* workgroup .
*/
if ( ! is_myname ( announce_name ) & & ( work ! = NULL ) & &
( ( servrec = find_server_in_workgroup ( work , announce_name ) ) ! = NULL ) ) {
remove_server_from_workgroup ( work , servrec ) ;
}
}
subrec - > work_changed = True ;
found_lm_clients = True ;
1997-12-16 12:20:34 +03:00
2001-09-05 22:43:55 +04:00
done :
2003-08-23 05:59:14 +04:00
END_PROFILE ( lm_host_announce ) ;
1997-12-16 12:20:34 +03:00
}
1997-12-13 17:16:07 +03:00
/****************************************************************************
Send a backup list response .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-23 05:59:14 +04:00
1997-12-13 17:16:07 +03:00
static void send_backup_list_response ( struct subnet_record * subrec ,
1998-08-30 21:04:24 +04:00
struct work_record * work ,
struct nmb_name * send_to_name ,
unsigned char max_number_requested ,
uint32 token , struct in_addr sendto_ip ,
int port )
1997-12-13 17:16:07 +03:00
{
2003-08-23 05:59:14 +04:00
char outbuf [ 1024 ] ;
char * p , * countptr ;
unsigned int count = 0 ;
2004-03-16 00:45:45 +03:00
unstring send_to_namestr ;
1999-12-13 16:27:58 +03:00
#if 0
1997-12-13 17:16:07 +03:00
struct server_record * servrec ;
1999-12-13 16:27:58 +03:00
# endif
2004-03-16 00:45:45 +03:00
unstring myname ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
memset ( outbuf , ' \0 ' , sizeof ( outbuf ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
DEBUG ( 3 , ( " send_backup_list_response: sending backup list for workgroup %s to %s IP %s \n " ,
work - > work_group , nmb_namestr ( send_to_name ) , inet_ntoa ( sendto_ip ) ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
p = outbuf ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
SCVAL ( p , 0 , ANN_GetBackupListResp ) ; /* Backup list response opcode. */
p + + ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
countptr = p ;
p + + ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
SIVAL ( p , 0 , token ) ; /* The sender's unique info. */
p + = 4 ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
/* We always return at least one name - our own. */
count = 1 ;
2004-03-16 00:45:45 +03:00
unstrcpy ( myname , global_myname ( ) ) ;
2003-08-23 05:59:14 +04:00
strupper_m ( myname ) ;
myname [ 15 ] = ' \0 ' ;
push_pstring_base ( p , myname , outbuf ) ;
2003-04-23 17:27:35 +04:00
2007-04-03 00:10:21 +04:00
p = skip_string ( outbuf , sizeof ( outbuf ) , p ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
/* Look for backup browsers in this workgroup. */
1999-12-13 16:27:58 +03:00
#if 0
/* we don't currently send become_backup requests so we should never
send any other servers names out as backups for our
workgroup . That ' s why this is commented out ( tridge ) */
/*
* NB . Note that the struct work_record here is not neccessarily
* attached to the subnet * subrec .
*/
1997-12-13 17:16:07 +03:00
for ( servrec = work - > serverlist ; servrec ; servrec = servrec - > next )
{
1999-12-13 16:27:58 +03:00
int len = PTR_DIFF ( p , outbuf ) ;
1997-12-13 17:16:07 +03:00
if ( ( sizeof ( outbuf ) - len ) < 16 )
break ;
1998-01-09 08:33:27 +03:00
if ( count > = ( unsigned int ) max_number_requested )
1997-12-13 17:16:07 +03:00
break ;
2002-11-13 02:20:50 +03:00
if ( strnequal ( servrec - > serv . name , global_myname ( ) , 15 ) )
1997-12-13 17:16:07 +03:00
continue ;
if ( ! ( servrec - > serv . type & SV_TYPE_BACKUP_BROWSER ) )
continue ;
StrnCpy ( p , servrec - > serv . name , 15 ) ;
2003-07-03 23:11:31 +04:00
strupper_m ( p ) ;
1997-12-13 17:16:07 +03:00
count + + ;
DEBUG ( 5 , ( " send_backup_list_response: Adding server %s number %d \n " ,
p , count ) ) ;
2007-04-03 00:10:21 +04:00
p = skip_string ( outbuf , sizeof ( outbuf ) , p ) ;
1997-12-13 17:16:07 +03:00
}
1999-12-13 16:27:58 +03:00
# endif
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
SCVAL ( countptr , 0 , count ) ;
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( send_to_namestr , sizeof ( send_to_namestr ) , send_to_name - > name ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
DEBUG ( 4 , ( " send_backup_list_response: sending response to %s<00> IP %s with %d servers. \n " ,
send_to_namestr , inet_ntoa ( sendto_ip ) , count ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
send_mailslot ( True , BROWSE_MAILSLOT ,
outbuf , PTR_DIFF ( p , outbuf ) ,
global_myname ( ) , 0 ,
send_to_namestr , 0 ,
sendto_ip , subrec - > myip , port ) ;
1997-12-13 17:16:07 +03:00
}
/*******************************************************************
Process a send backup list request packet .
A client sends a backup list request to ask for a list of servers on
the net that maintain server lists for a domain . A server is then
chosen from this list to send NetServerEnum commands to to list
available servers .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void process_get_backup_list_request ( struct subnet_record * subrec ,
struct packet_struct * p , char * buf )
{
2003-08-23 05:59:14 +04:00
struct dgram_packet * dgram = & p - > packet . dgram ;
struct work_record * work ;
unsigned char max_number_requested = CVAL ( buf , 0 ) ;
uint32 token = IVAL ( buf , 1 ) ; /* Sender's key index for the workgroup. */
int name_type = dgram - > dest_name . name_type ;
2004-03-16 00:45:45 +03:00
unstring workgroup_name ;
2003-08-23 05:59:14 +04:00
struct subnet_record * search_subrec = subrec ;
START_PROFILE ( get_backup_list ) ;
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( workgroup_name , sizeof ( workgroup_name ) , dgram - > dest_name . name ) ;
2003-08-23 05:59:14 +04:00
DEBUG ( 3 , ( " process_get_backup_list_request: request from %s IP %s to %s. \n " ,
nmb_namestr ( & dgram - > source_name ) , inet_ntoa ( p - > ip ) ,
nmb_namestr ( & dgram - > dest_name ) ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
/* We have to be a master browser, or a domain master browser
for the requested workgroup . That means it must be our
workgroup . */
if ( strequal ( workgroup_name , lp_workgroup ( ) ) = = False ) {
DEBUG ( 7 , ( " process_get_backup_list_request: Ignoring announce request for workgroup %s. \n " ,
workgroup_name ) ) ;
goto done ;
}
if ( ( work = find_workgroup_on_subnet ( search_subrec , workgroup_name ) ) = = NULL ) {
DEBUG ( 0 , ( " process_get_backup_list_request: Cannot find workgroup %s on \
1999-12-13 16:27:58 +03:00
subnet % s . \ n " , workgroup_name, search_subrec->subnet_name));
2003-08-23 05:59:14 +04:00
goto done ;
}
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
/*
* If the packet was sent to WORKGROUP < 1 b > instead
* of WORKGROUP < 1 d > then it was unicast to us a domain master
* browser . Change search subrec to unicast .
*/
1999-12-13 16:27:58 +03:00
2003-08-23 05:59:14 +04:00
if ( name_type = = 0x1b ) {
/* We must be a domain master browser in order to
process this packet . */
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
if ( ! AM_DOMAIN_MASTER_BROWSER ( work ) ) {
DEBUG ( 0 , ( " process_get_backup_list_request: domain list requested for workgroup %s \
1997-12-13 17:16:07 +03:00
and I am not a domain master browser . \ n " , workgroup_name));
2003-08-23 05:59:14 +04:00
goto done ;
}
1999-12-13 16:27:58 +03:00
2003-08-23 05:59:14 +04:00
search_subrec = unicast_subnet ;
} else if ( name_type = = 0x1d ) {
/* We must be a local master browser in order to process this packet. */
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
if ( ! AM_LOCAL_MASTER_BROWSER ( work ) ) {
DEBUG ( 0 , ( " process_get_backup_list_request: domain list requested for workgroup %s \
1997-12-13 17:16:07 +03:00
and I am not a local master browser . \ n " , workgroup_name));
2003-08-23 05:59:14 +04:00
goto done ;
}
} else {
DEBUG ( 0 , ( " process_get_backup_list_request: Invalid name type %x - should be 0x1b or 0x1d. \n " ,
name_type ) ) ;
goto done ;
}
send_backup_list_response ( subrec , work , & dgram - > source_name ,
max_number_requested , token , p - > ip , p - > port ) ;
1997-12-13 17:16:07 +03:00
2001-09-05 22:43:55 +04:00
done :
2003-08-23 05:59:14 +04:00
END_PROFILE ( get_backup_list ) ;
1997-12-13 17:16:07 +03:00
}
/*******************************************************************
Process a reset browser state packet .
Diagnostic packet :
0x1 - Stop being a master browser and become a backup browser .
0x2 - Discard browse lists , stop being a master browser , try again .
0x4 - Stop being a master browser forever .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void process_reset_browser ( struct subnet_record * subrec ,
struct packet_struct * p , char * buf )
{
2003-08-23 05:59:14 +04:00
struct dgram_packet * dgram = & p - > packet . dgram ;
int state = CVAL ( buf , 0 ) ;
struct subnet_record * sr ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
START_PROFILE ( reset_browser ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
DEBUG ( 1 , ( " process_reset_browser: received diagnostic browser reset \
request from % s IP % s state = 0 x % X \ n " ,
nmb_namestr ( & dgram - > source_name ) , inet_ntoa ( p - > ip ) , state ) ) ;
/* Stop being a local master browser on all our broadcast subnets. */
if ( state & 0x1 ) {
for ( sr = FIRST_SUBNET ; sr ; sr = NEXT_SUBNET_EXCLUDING_UNICAST ( sr ) ) {
struct work_record * work ;
for ( work = sr - > workgrouplist ; work ; work = work - > next ) {
if ( AM_LOCAL_MASTER_BROWSER ( work ) )
unbecome_local_master_browser ( sr , work , True ) ;
}
}
}
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
/* Discard our browse lists. */
if ( state & 0x2 ) {
/*
* Calling expire_workgroups_and_servers with a - 1
* time causes all servers not marked with a PERMANENT_TTL
* on the workgroup lists to be discarded , and all
* workgroups with empty server lists to be discarded .
* This means we keep our own server names and workgroup
* as these have a PERMANENT_TTL .
*/
expire_workgroups_and_servers ( - 1 ) ;
}
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
/* Request to stop browsing altogether. */
if ( state & 0x4 )
DEBUG ( 1 , ( " process_reset_browser: ignoring request to stop being a browser. \n " ) ) ;
2001-09-07 02:08:19 +04:00
2003-08-23 05:59:14 +04:00
END_PROFILE ( reset_browser ) ;
1997-12-13 17:16:07 +03:00
}
/*******************************************************************
1997-12-16 12:20:34 +03:00
Process an announcement request packet .
1997-12-13 17:16:07 +03:00
We don ' t respond immediately , we just check it ' s a request for
1997-12-16 12:20:34 +03:00
our workgroup and then set the flag telling the announce code
1997-12-13 17:16:07 +03:00
in nmbd_sendannounce . c : announce_my_server_names that an
announcement is needed soon .
1997-12-16 12:20:34 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-12-13 17:16:07 +03:00
void process_announce_request ( struct subnet_record * subrec , struct packet_struct * p , char * buf )
{
2003-08-23 05:59:14 +04:00
struct dgram_packet * dgram = & p - > packet . dgram ;
struct work_record * work ;
2004-03-16 00:45:45 +03:00
unstring workgroup_name ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
START_PROFILE ( announce_request ) ;
1997-12-13 17:16:07 +03:00
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( workgroup_name , sizeof ( workgroup_name ) , dgram - > dest_name . name ) ;
2003-08-23 05:59:14 +04:00
DEBUG ( 3 , ( " process_announce_request: Announce request from %s IP %s to %s. \n " ,
nmb_namestr ( & dgram - > source_name ) , inet_ntoa ( p - > ip ) ,
nmb_namestr ( & dgram - > dest_name ) ) ) ;
/* We only send announcement requests on our workgroup. */
if ( strequal ( workgroup_name , lp_workgroup ( ) ) = = False ) {
DEBUG ( 7 , ( " process_announce_request: Ignoring announce request for workgroup %s. \n " ,
workgroup_name ) ) ;
goto done ;
}
if ( ( work = find_workgroup_on_subnet ( subrec , workgroup_name ) ) = = NULL ) {
DEBUG ( 0 , ( " process_announce_request: Unable to find workgroup %s on subnet ! \n " ,
workgroup_name ) ) ;
goto done ;
}
work - > needannounce = True ;
2001-09-05 22:43:55 +04:00
done :
2003-08-23 05:59:14 +04:00
2006-05-05 11:15:45 +04:00
END_PROFILE ( announce_request ) ;
1997-12-13 17:16:07 +03:00
}
1997-12-16 12:20:34 +03:00
/*******************************************************************
Process a LanMan announcement request packet .
We don ' t respond immediately , we just check it ' s a request for
our workgroup and then set the flag telling that we have found
a LanMan client ( DOS or OS / 2 ) and that we will have to start
sending LanMan announcements ( unless specifically disabled
1997-12-24 10:10:04 +03:00
through the " lm announce " parameter in smb . conf )
1997-12-16 12:20:34 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-03-31 02:25:08 +04:00
void process_lm_announce_request ( struct subnet_record * subrec , struct packet_struct * p , char * buf , int len )
1997-12-16 12:20:34 +03:00
{
2003-08-23 05:59:14 +04:00
struct dgram_packet * dgram = & p - > packet . dgram ;
2004-03-16 00:45:45 +03:00
unstring workgroup_name ;
1997-12-16 12:20:34 +03:00
2003-08-23 05:59:14 +04:00
START_PROFILE ( lm_announce_request ) ;
1997-12-16 12:20:34 +03:00
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( workgroup_name , sizeof ( workgroup_name ) , dgram - > dest_name . name ) ;
2003-08-23 05:59:14 +04:00
DEBUG ( 3 , ( " process_lm_announce_request: Announce request from %s IP %s to %s. \n " ,
nmb_namestr ( & dgram - > source_name ) , inet_ntoa ( p - > ip ) ,
nmb_namestr ( & dgram - > dest_name ) ) ) ;
1997-12-16 12:20:34 +03:00
2003-08-23 05:59:14 +04:00
/* We only send announcement requests on our workgroup. */
if ( strequal ( workgroup_name , lp_workgroup ( ) ) = = False ) {
DEBUG ( 7 , ( " process_lm_announce_request: Ignoring announce request for workgroup %s. \n " ,
workgroup_name ) ) ;
goto done ;
}
if ( find_workgroup_on_subnet ( subrec , workgroup_name ) = = NULL ) {
DEBUG ( 0 , ( " process_announce_request: Unable to find workgroup %s on subnet ! \n " ,
workgroup_name ) ) ;
goto done ;
}
found_lm_clients = True ;
1997-12-16 12:20:34 +03:00
2001-09-05 22:43:55 +04:00
done :
2003-08-23 05:59:14 +04:00
2006-05-05 11:15:45 +04:00
END_PROFILE ( lm_announce_request ) ;
1997-12-16 12:20:34 +03:00
}