0001-01-01 02:30:17 +02:30
/*
Unix SMB / Netbios implementation .
Version 1.9 .
NBT netbios routines and daemon - version 2
0001-01-01 02:30:17 +02:30
Copyright ( C ) Andrew Tridgell 1994 - 1998
Copyright ( C ) Luke Kenneth Casson Leighton 1994 - 1998
Copyright ( C ) Jeremy Allison 1994 - 1998
0001-01-01 02:30:17 +02:30
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 2 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
extern int DEBUGLEVEL ;
0001-01-01 02:30:17 +02:30
extern pstring global_myname ;
extern fstring global_myworkgroup ;
0001-01-01 02:30:17 +02:30
extern BOOL found_lm_clients ;
0001-01-01 02:30:17 +02:30
#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 )
{
struct dgram_packet * dgram = & p - > packet . dgram ;
int ttl = IVAL ( buf , 1 ) / 1000 ;
char * announce_name = buf + 5 ;
uint32 servertype = IVAL ( buf , 23 ) ;
char * comment = buf + 31 ;
struct work_record * work ;
struct server_record * servrec ;
char * work_name ;
char * source_name = dgram - > source_name . name ;
comment [ 43 ] = 0 ;
DEBUG ( 3 , ( " process_host_announce: from %s<%02x> IP %s to \
% s for server % s . \ n " , source_name, source_name[15], inet_ntoa(p->ip),
0001-01-01 02:30:17 +02:30
nmb_namestr ( & dgram - > dest_name ) , announce_name ) ) ;
0001-01-01 02:30:17 +02:30
DEBUG ( 5 , ( " process_host_announce: ttl=%d server type=%08x comment=%s \n " ,
ttl , servertype , comment ) ) ;
/* Filter servertype to remove impossible bits. */
servertype & = ~ ( SV_TYPE_LOCAL_LIST_ONLY | SV_TYPE_DOMAIN_ENUM ) ;
/* 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 \
( was % 02 x ) should be 0x1d . Allowing packet anyway . \ n " ,
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. */
work_name = dgram - > dest_name . name ;
0001-01-01 02:30:17 +02:30
/*
* 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 .
*/
0001-01-01 02:30:17 +02:30
if ( strequal ( work_name , global_myname ) )
work_name = global_myworkgroup ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
/*
* 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 .
*/
0001-01-01 02:30:17 +02:30
work = find_workgroup_on_subnet ( subrec , work_name ) ;
if ( servertype ! = 0 )
0001-01-01 02:30:17 +02:30
{
0001-01-01 02:30:17 +02:30
if ( work = = NULL )
{
/* We have no record of this workgroup. Add it. */
if ( ( work = create_workgroup_on_subnet ( subrec , work_name , ttl ) ) = = NULL )
return ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
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 ) ;
StrnCpy ( servrec - > serv . comment , comment , sizeof ( servrec - > serv . comment ) - 1 ) ;
}
0001-01-01 02:30:17 +02:30
}
else
{
0001-01-01 02:30:17 +02:30
/*
* 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 ) ;
}
0001-01-01 02:30:17 +02:30
}
subrec - > work_changed = True ;
}
/*******************************************************************
Process an incoming WORKGROUP announcement packet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void process_workgroup_announce ( struct subnet_record * subrec , struct packet_struct * p , char * buf )
{
struct dgram_packet * dgram = & p - > packet . dgram ;
int ttl = IVAL ( buf , 1 ) / 1000 ;
char * workgroup_announce_name = buf + 5 ;
uint32 servertype = IVAL ( buf , 23 ) ;
char * master_name = buf + 31 ;
struct work_record * work ;
char * source_name = dgram - > source_name . name ;
master_name [ 43 ] = 0 ;
DEBUG ( 3 , ( " process_workgroup_announce: from %s<%02x> IP %s to \
% s for workgroup % s . \ n " , source_name, source_name[15], inet_ntoa(p->ip),
0001-01-01 02:30:17 +02:30
nmb_namestr ( & dgram - > dest_name ) , workgroup_announce_name ) ) ;
0001-01-01 02:30:17 +02:30
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 ( dgram - > dest_name . name , MSBROWSE ) | | ( dgram - > dest_name . name_type ! = 0x1 ) )
{
DEBUG ( 0 , ( " process_workgroup_announce: from IP %s should be to __MSBROWSE__<0x01> not %s \n " ,
0001-01-01 02:30:17 +02:30
inet_ntoa ( p - > ip ) , nmb_namestr ( & dgram - > dest_name ) ) ) ;
0001-01-01 02:30:17 +02:30
return ;
}
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 )
return ;
}
else
{
/* Update the workgroup death_time. */
update_workgroup_ttl ( work , ttl ) ;
}
if ( * work - > local_master_browser_name = = ' \0 ' )
{
/* Set the master browser name. */
0001-01-01 02:30:17 +02:30
set_workgroup_local_master_browser_name ( work , master_name ) ;
0001-01-01 02:30:17 +02:30
}
subrec - > work_changed = True ;
}
/*******************************************************************
Process an incoming local master browser announcement packet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void process_local_master_announce ( struct subnet_record * subrec , struct packet_struct * p , char * buf )
{
struct dgram_packet * dgram = & p - > packet . dgram ;
int ttl = IVAL ( buf , 1 ) / 1000 ;
char * server_name = buf + 5 ;
uint32 servertype = IVAL ( buf , 23 ) ;
char * comment = buf + 31 ;
char * work_name ;
struct work_record * work ;
struct server_record * servrec ;
char * source_name = dgram - > source_name . name ;
comment [ 43 ] = 0 ;
DEBUG ( 3 , ( " process_local_master_announce: from %s<%02x> IP %s to \
% s for server % s . \ n " , source_name, source_name[15], inet_ntoa(p->ip),
0001-01-01 02:30:17 +02:30
nmb_namestr ( & dgram - > dest_name ) , server_name ) ) ;
0001-01-01 02:30:17 +02:30
DEBUG ( 5 , ( " process_local_master_announce: ttl=%d server type=%08x comment=%s \n " ,
ttl , servertype , comment ) ) ;
/* 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 \
( was % 02 x ) should be 0x1e . Ignoring packet . \ n " ,
inet_ntoa ( p - > ip ) , dgram - > dest_name . name_type ) ) ;
return ;
}
/* 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. */
work_name = dgram - > dest_name . name ;
if ( ( work = find_workgroup_on_subnet ( subrec , work_name ) ) = = NULL )
{
0001-01-01 02:30:17 +02:30
/* Don't bother adding if it's a local master release announce. */
if ( servertype = = 0 )
return ;
0001-01-01 02:30:17 +02:30
/* We have no record of this workgroup. Add it. */
if ( ( work = create_workgroup_on_subnet ( subrec , work_name , ttl ) ) = = NULL )
return ;
}
/* 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 \
a local master browser for workgroup % s and we think we are master . Forcing election . \ n " ,
server_name , inet_ntoa ( p - > ip ) , work_name ) ) ;
/* 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 . */
send_browser_reset ( 0x2 , " __SAMBA__ " , 0x20 , p - > ip ) ;
/* We should demote ourself and force an election. */
0001-01-01 02:30:17 +02:30
unbecome_local_master_browser ( subrec , work , True ) ;
0001-01-01 02:30:17 +02:30
/* The actual election requests are handled in
nmbd_election . c */
return ;
}
/* Find the server record on this workgroup. If it doesn't exist, add it. */
0001-01-01 02:30:17 +02:30
if ( servertype ! = 0 )
0001-01-01 02:30:17 +02:30
{
0001-01-01 02:30:17 +02:30
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 ) ;
StrnCpy ( servrec - > serv . comment , comment , sizeof ( servrec - > serv . comment ) - 1 ) ;
}
set_workgroup_local_master_browser_name ( work , server_name ) ;
0001-01-01 02:30:17 +02:30
}
else
{
0001-01-01 02:30:17 +02:30
/*
* 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 ) ;
}
0001-01-01 02:30:17 +02:30
}
subrec - > work_changed = True ;
}
/*******************************************************************
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 )
{
char * local_master_name = buf ;
struct work_record * work ;
struct browse_cache_record * browrec ;
local_master_name [ 15 ] = 0 ;
DEBUG ( 3 , ( " process_master_browser_announce: Local master announce from %s IP %s. \n " ,
local_master_name , inet_ntoa ( p - > ip ) ) ) ;
if ( ! lp_domain_master ( ) )
{
DEBUG ( 0 , ( " process_master_browser_announce: Not configured as domain \
master - ignoring master announce . \ n " ));
return ;
}
0001-01-01 02:30:17 +02:30
if ( ( work = find_workgroup_on_subnet ( subrec , global_myworkgroup ) ) = = NULL )
0001-01-01 02:30:17 +02:30
{
DEBUG ( 0 , ( " process_master_browser_announce: Cannot find workgroup %s on subnet %s \n " ,
0001-01-01 02:30:17 +02:30
global_myworkgroup , subrec - > subnet_name ) ) ;
0001-01-01 02:30:17 +02:30
return ;
}
if ( ! AM_DOMAIN_MASTER_BROWSER ( work ) )
{
DEBUG ( 0 , ( " process_master_browser_announce: Local master announce made to us from \
% s IP % s and we are not a domain master browser . \ n " , local_master_name, inet_ntoa(p->ip)));
return ;
}
/* 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 ) ;
}
0001-01-01 02:30:17 +02:30
/*******************************************************************
Process an incoming LanMan host announcement packet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void process_lm_host_announce ( struct subnet_record * subrec , struct packet_struct * p , char * buf )
{
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 ) ;
char * announce_name = buf + 9 ;
struct work_record * work ;
struct server_record * servrec ;
char * work_name ;
char * source_name = dgram - > source_name . name ;
pstring comment ;
char * s = buf + 9 ;
s = skip_string ( s , 1 ) ;
StrnCpy ( comment , s , 43 ) ;
DEBUG ( 3 , ( " process_lm_host_announce: LM Announcement from %s<%02x> IP %s to \
% s for server % s . \ n " , source_name, source_name[15], inet_ntoa(p->ip),
0001-01-01 02:30:17 +02:30
nmb_namestr ( & dgram - > dest_name ) , announce_name ) ) ;
0001-01-01 02:30:17 +02:30
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 ) )
{
0001-01-01 02:30:17 +02:30
DEBUG ( 5 , ( " process_lm_host_announce: LM Announcement packet does not \
originate from OS / 2 Warp client . Ignoring packet . \ n " ));
0001-01-01 02:30:17 +02:30
/* Could have been from a Windows machine (with its LM Announce enabled),
or a Samba server . Then don ' t disrupt the current browse list . */
return ;
}
/* Filter servertype to remove impossible bits. */
servertype & = ~ ( SV_TYPE_LOCAL_LIST_ONLY | SV_TYPE_DOMAIN_ENUM ) ;
/* 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 \
( was % 02 x ) should be 0x00 . Allowing packet anyway . \ n " ,
inet_ntoa ( p - > ip ) , dgram - > dest_name . name_type ) ) ;
/* Change it so it was. */
dgram - > dest_name . name_type = 0x00 ;
}
/* For a LanMan host announce the workgroup name is the destination name. */
work_name = dgram - > dest_name . name ;
/*
* 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 .
*/
0001-01-01 02:30:17 +02:30
if ( strequal ( work_name , global_myname ) )
work_name = global_myworkgroup ;
0001-01-01 02:30:17 +02:30
/*
* 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 .
*/
0001-01-01 02:30:17 +02:30
work = find_workgroup_on_subnet ( subrec , work_name ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( servertype ! = 0 )
0001-01-01 02:30:17 +02:30
{
0001-01-01 02:30:17 +02:30
if ( work = = NULL )
{
/* We have no record of this workgroup. Add it. */
if ( ( work = create_workgroup_on_subnet ( subrec , work_name , ttl ) ) = = NULL )
return ;
}
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 ) ;
StrnCpy ( servrec - > serv . comment , comment , sizeof ( servrec - > serv . comment ) - 1 ) ;
}
0001-01-01 02:30:17 +02:30
}
else
{
0001-01-01 02:30:17 +02:30
/*
* 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 ) ;
}
0001-01-01 02:30:17 +02:30
}
subrec - > work_changed = True ;
found_lm_clients = True ;
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
Send a backup list response .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void send_backup_list_response ( struct subnet_record * subrec ,
0001-01-01 02:30:17 +02:30
struct work_record * work ,
struct nmb_name * send_to_name ,
unsigned char max_number_requested ,
uint32 token , struct in_addr sendto_ip ,
int port )
0001-01-01 02:30:17 +02:30
{
char outbuf [ 1024 ] ;
0001-01-01 02:30:17 +02:30
char * p , * countptr ;
0001-01-01 02:30:17 +02:30
unsigned int count = 0 ;
0001-01-01 02:30:17 +02:30
int len ;
struct server_record * servrec ;
bzero ( outbuf , sizeof ( outbuf ) ) ;
DEBUG ( 3 , ( " send_backup_list_response: sending backup list for workgroup %s to %s IP %s \n " ,
0001-01-01 02:30:17 +02:30
work - > work_group , nmb_namestr ( send_to_name ) , inet_ntoa ( sendto_ip ) ) ) ;
0001-01-01 02:30:17 +02:30
p = outbuf ;
SCVAL ( p , 0 , ANN_GetBackupListResp ) ; /* Backup list response opcode. */
p + + ;
countptr = p ;
p + + ;
SIVAL ( p , 0 , token ) ; /* The sender's unique info. */
p + = 4 ;
/* We always return at least one name - our own. */
count = 1 ;
0001-01-01 02:30:17 +02:30
StrnCpy ( p , global_myname , 15 ) ;
0001-01-01 02:30:17 +02:30
strupper ( p ) ;
p = skip_string ( p , 1 ) ;
/* Look for backup browsers in this workgroup. */
for ( servrec = work - > serverlist ; servrec ; servrec = servrec - > next )
{
len = PTR_DIFF ( p , outbuf ) ;
if ( ( sizeof ( outbuf ) - len ) < 16 )
break ;
0001-01-01 02:30:17 +02:30
if ( count > = ( unsigned int ) max_number_requested )
0001-01-01 02:30:17 +02:30
break ;
0001-01-01 02:30:17 +02:30
if ( strnequal ( servrec - > serv . name , global_myname , 15 ) )
0001-01-01 02:30:17 +02:30
continue ;
if ( ! ( servrec - > serv . type & SV_TYPE_BACKUP_BROWSER ) )
continue ;
StrnCpy ( p , servrec - > serv . name , 15 ) ;
strupper ( p ) ;
count + + ;
DEBUG ( 5 , ( " send_backup_list_response: Adding server %s number %d \n " ,
p , count ) ) ;
p = skip_string ( p , 1 ) ;
}
SCVAL ( countptr , 0 , count ) ;
len = PTR_DIFF ( p , outbuf ) ;
DEBUG ( 4 , ( " send_backup_list_response: sending response to %s<00> IP %s with %d servers. \n " ,
send_to_name - > name , inet_ntoa ( sendto_ip ) , count ) ) ;
send_mailslot ( True , BROWSE_MAILSLOT ,
outbuf , PTR_DIFF ( p , outbuf ) ,
0001-01-01 02:30:17 +02:30
global_myname , 0 ,
0001-01-01 02:30:17 +02:30
send_to_name - > name , 0 ,
0001-01-01 02:30:17 +02:30
sendto_ip , subrec - > myip , port ) ;
0001-01-01 02:30:17 +02:30
}
/*******************************************************************
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 )
{
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 ;
char * workgroup_name = dgram - > dest_name . name ;
DEBUG ( 3 , ( " process_get_backup_list_request: request from %s IP %s to %s. \n " ,
0001-01-01 02:30:17 +02:30
nmb_namestr ( & dgram - > source_name ) , inet_ntoa ( p - > ip ) ,
nmb_namestr ( & dgram - > dest_name ) ) ) ;
0001-01-01 02:30:17 +02:30
/* We have to be a master browser, or a domain master browser
for the requested workgroup . That means it must be our
workgroup . */
0001-01-01 02:30:17 +02:30
if ( strequal ( workgroup_name , global_myworkgroup ) = = False )
0001-01-01 02:30:17 +02:30
{
DEBUG ( 7 , ( " process_get_backup_list_request: Ignoring announce request for workgroup %s. \n " ,
workgroup_name ) ) ;
return ;
}
if ( ( work = find_workgroup_on_subnet ( subrec , workgroup_name ) ) = = NULL )
{
DEBUG ( 0 , ( " process_get_backup_list_request: Cannot find workgroup %s on \
subnet % s . \ n " , workgroup_name, subrec->subnet_name));
return ;
}
if ( name_type = = 0x1b )
{
/* We must be a domain master browser in order to
process this packet . */
if ( ! AM_DOMAIN_MASTER_BROWSER ( work ) )
{
DEBUG ( 0 , ( " process_get_backup_list_request: domain list requested for workgroup %s \
and I am not a domain master browser . \ n " , workgroup_name));
return ;
}
}
else if ( name_type = = 0x1d )
{
/* We must be a local master browser in order to
process this packet . */
if ( ! AM_LOCAL_MASTER_BROWSER ( work ) )
{
DEBUG ( 0 , ( " process_get_backup_list_request: domain list requested for workgroup %s \
and I am not a local master browser . \ n " , workgroup_name));
return ;
}
}
else
{
DEBUG ( 0 , ( " process_get_backup_list_request: Invalid name type %x - should be 0x1b or 0x1d. \n " ,
name_type ) ) ;
return ;
}
send_backup_list_response ( subrec , work , & dgram - > source_name ,
0001-01-01 02:30:17 +02:30
max_number_requested , token , p - > ip , p - > port ) ;
0001-01-01 02:30:17 +02:30
}
/*******************************************************************
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 )
{
struct dgram_packet * dgram = & p - > packet . dgram ;
int state = CVAL ( buf , 0 ) ;
struct subnet_record * sr ;
DEBUG ( 1 , ( " process_reset_browser: received diagnostic browser reset \
request from % s IP % s state = 0 x % X \ n " ,
0001-01-01 02:30:17 +02:30
nmb_namestr ( & dgram - > source_name ) , inet_ntoa ( p - > ip ) , state ) ) ;
0001-01-01 02:30:17 +02:30
/* 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 ) )
0001-01-01 02:30:17 +02:30
unbecome_local_master_browser ( sr , work , True ) ;
0001-01-01 02:30:17 +02:30
}
}
}
/* 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 ) ;
}
/* Request to stop browsing altogether. */
if ( state & 0x4 )
DEBUG ( 1 , ( " process_reset_browser: ignoring request to stop being a browser. \n " ) ) ;
}
/*******************************************************************
0001-01-01 02:30:17 +02:30
Process an announcement request packet .
0001-01-01 02:30:17 +02:30
We don ' t respond immediately , we just check it ' s a request for
0001-01-01 02:30:17 +02:30
our workgroup and then set the flag telling the announce code
0001-01-01 02:30:17 +02:30
in nmbd_sendannounce . c : announce_my_server_names that an
announcement is needed soon .
0001-01-01 02:30:17 +02:30
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
void process_announce_request ( struct subnet_record * subrec , struct packet_struct * p , char * buf )
{
struct dgram_packet * dgram = & p - > packet . dgram ;
struct work_record * work ;
char * workgroup_name = dgram - > dest_name . name ;
DEBUG ( 3 , ( " process_announce_request: Announce request from %s IP %s to %s. \n " ,
0001-01-01 02:30:17 +02:30
nmb_namestr ( & dgram - > source_name ) , inet_ntoa ( p - > ip ) ,
nmb_namestr ( & dgram - > dest_name ) ) ) ;
0001-01-01 02:30:17 +02:30
/* We only send announcement requests on our workgroup. */
0001-01-01 02:30:17 +02:30
if ( strequal ( workgroup_name , global_myworkgroup ) = = False )
0001-01-01 02:30:17 +02:30
{
DEBUG ( 7 , ( " process_announce_request: Ignoring announce request for workgroup %s. \n " ,
workgroup_name ) ) ;
return ;
}
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 ) ) ;
return ;
}
work - > needannounce = True ;
}
0001-01-01 02:30:17 +02:30
/*******************************************************************
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
0001-01-01 02:30:17 +02:30
through the " lm announce " parameter in smb . conf )
0001-01-01 02:30:17 +02:30
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void process_lm_announce_request ( struct subnet_record * subrec , struct packet_struct * p , char * buf )
{
struct dgram_packet * dgram = & p - > packet . dgram ;
char * workgroup_name = dgram - > dest_name . name ;
DEBUG ( 3 , ( " process_lm_announce_request: Announce request from %s IP %s to %s. \n " ,
0001-01-01 02:30:17 +02:30
nmb_namestr ( & dgram - > source_name ) , inet_ntoa ( p - > ip ) ,
nmb_namestr ( & dgram - > dest_name ) ) ) ;
0001-01-01 02:30:17 +02:30
/* We only send announcement requests on our workgroup. */
0001-01-01 02:30:17 +02:30
if ( strequal ( workgroup_name , global_myworkgroup ) = = False )
0001-01-01 02:30:17 +02:30
{
DEBUG ( 7 , ( " process_lm_announce_request: Ignoring announce request for workgroup %s. \n " ,
workgroup_name ) ) ;
return ;
}
0001-01-01 02:30:17 +02:30
if ( find_workgroup_on_subnet ( subrec , workgroup_name ) = = NULL )
0001-01-01 02:30:17 +02:30
{
DEBUG ( 0 , ( " process_announce_request: Unable to find workgroup %s on subnet ! \n " ,
workgroup_name ) ) ;
return ;
}
found_lm_clients = True ;
}