1996-06-04 10:42:03 +04:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
NBT netbios routines and daemon - version 2
Copyright ( C ) Andrew Tridgell 1994 - 1995
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 .
Revision History :
14 jan 96 : lkcl @ pires . co . uk
added multiple workgroup domain master support
*/
# include "includes.h"
1996-10-02 19:41:30 +04:00
# define TEST_CODE
1996-06-04 10:42:03 +04:00
extern int DEBUGLEVEL ;
extern BOOL CanRecurse ;
extern struct in_addr ipzero ;
1996-10-02 19:41:30 +04:00
extern pstring myname ;
1996-06-04 10:42:03 +04:00
extern int ClientDGRAM ;
extern int ClientNMB ;
/* this is our domain/workgroup/server database */
1996-06-10 07:38:08 +04:00
extern struct subnet_record * subnetlist ;
1996-06-04 10:42:03 +04:00
extern int updatecount ;
1996-10-02 19:41:30 +04:00
extern int workgroup_count ;
1996-06-04 10:42:03 +04:00
1996-10-02 19:41:30 +04:00
extern struct in_addr ipgrp ;
1996-06-04 10:42:03 +04:00
1996-08-16 17:03:26 +04:00
1996-06-04 10:42:03 +04:00
/****************************************************************************
1996-10-02 19:41:30 +04:00
send a announce request to the local net
1996-06-04 10:42:03 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void announce_request ( struct work_record * work , struct in_addr ip )
{
pstring outbuf ;
char * p ;
if ( ! work ) return ;
work - > needannounce = True ;
1996-06-05 19:16:09 +04:00
DEBUG ( 2 , ( " sending announce request to %s for workgroup %s \n " ,
1996-10-02 19:41:30 +04:00
inet_ntoa ( ip ) , work - > work_group ) ) ;
1996-06-04 10:42:03 +04:00
bzero ( outbuf , sizeof ( outbuf ) ) ;
p = outbuf ;
1996-06-05 19:16:09 +04:00
CVAL ( p , 0 ) = ANN_AnnouncementRequest ;
1996-06-04 10:42:03 +04:00
p + + ;
1996-07-07 16:36:18 +04:00
CVAL ( p , 0 ) = work - > token ; /* (local) unique workgroup token id */
1996-06-04 10:42:03 +04:00
p + + ;
1996-10-02 19:41:30 +04:00
StrnCpy ( p , myname , 16 ) ;
strupper ( p ) ;
1996-06-04 10:42:03 +04:00
p = skip_string ( p , 1 ) ;
1996-07-07 16:36:18 +04:00
/* XXXX note: if we sent the announcement request to 0x1d instead
of 0x1e , then we could get the master browser to announce to
us instead of the members of the workgroup . wha - hey ! */
1996-06-04 10:42:03 +04:00
send_mailslot_reply ( BROWSE_MAILSLOT , ClientDGRAM , outbuf , PTR_DIFF ( p , outbuf ) ,
1996-10-02 19:41:30 +04:00
myname , work - > work_group , 0x20 , 0x1e , ip , * iface_ip ( ip ) ) ;
1996-06-04 10:42:03 +04:00
}
/****************************************************************************
request an announcement
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-10-02 19:41:30 +04:00
void do_announce_request ( char * info , char * to_name , int announce_type ,
int from ,
int to , struct in_addr dest_ip )
1996-06-04 10:42:03 +04:00
{
1996-06-04 19:14:47 +04:00
pstring outbuf ;
char * p ;
bzero ( outbuf , sizeof ( outbuf ) ) ;
p = outbuf ;
1996-06-05 19:16:09 +04:00
CVAL ( p , 0 ) = announce_type ;
1996-06-04 19:14:47 +04:00
p + + ;
1996-06-05 19:16:09 +04:00
DEBUG ( 2 , ( " sending announce type %d: info %s to %s - server %s(%x) \n " ,
1996-10-02 19:41:30 +04:00
announce_type , info , inet_ntoa ( dest_ip ) , to_name , to ) ) ;
1996-06-04 19:14:47 +04:00
StrnCpy ( p , info , 16 ) ;
strupper ( p ) ;
p = skip_string ( p , 1 ) ;
send_mailslot_reply ( BROWSE_MAILSLOT , ClientDGRAM , outbuf , PTR_DIFF ( p , outbuf ) ,
1996-10-02 19:41:30 +04:00
myname , to_name , from , to , dest_ip , * iface_ip ( dest_ip ) ) ;
1996-06-04 10:42:03 +04:00
}
1996-07-02 19:31:33 +04:00
/****************************************************************************
find a server responsible for a workgroup , and sync browse lists
control ends up back here via response_name_query .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void sync_server ( enum state_type state , char * serv_name , char * work_name ,
1996-10-02 19:41:30 +04:00
int name_type ,
struct in_addr ip )
{
1996-08-01 21:49:40 +04:00
/* with a domain master we can get the whole list (not local only list) */
1996-08-13 16:35:28 +04:00
BOOL local_only = ( state ! = NAME_STATUS_DOM_SRV_CHK ) ;
1996-07-02 19:31:33 +04:00
1996-08-01 21:49:40 +04:00
add_browser_entry ( serv_name , name_type , work_name , 0 , ip , local_only ) ;
1996-10-02 19:41:30 +04:00
if ( state = = NAME_STATUS_DOM_SRV_CHK )
1996-07-07 16:36:18 +04:00
{
/* announce ourselves as a master browser to serv_name */
1996-10-02 19:41:30 +04:00
do_announce_request ( myname , serv_name , ANN_MasterAnnouncement ,
0x20 , 0 , ip ) ;
1996-07-07 16:36:18 +04:00
}
1996-07-02 19:31:33 +04:00
}
1996-06-29 22:49:20 +04:00
/****************************************************************************
send a host announcement packet
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-08-01 21:49:40 +04:00
void do_announce_host ( int command ,
1996-10-02 19:41:30 +04:00
char * from_name , int from_type , struct in_addr from_ip ,
char * to_name , int to_type , struct in_addr to_ip ,
time_t announce_interval ,
char * server_name , int server_type , char * server_comment )
1996-06-29 22:49:20 +04:00
{
1996-10-02 19:41:30 +04:00
pstring outbuf ;
char * p ;
1996-06-29 22:49:20 +04:00
1996-10-02 19:41:30 +04:00
bzero ( outbuf , sizeof ( outbuf ) ) ;
p = outbuf + 1 ;
1996-06-29 22:49:20 +04:00
1996-10-02 19:41:30 +04:00
/* command type */
CVAL ( outbuf , 0 ) = command ;
1996-06-29 22:49:20 +04:00
1996-10-02 19:41:30 +04:00
/* announcement parameters */
CVAL ( p , 0 ) = updatecount ;
SIVAL ( p , 1 , announce_interval * 1000 ) ; /* ms - despite the spec */
1996-06-29 22:49:20 +04:00
1996-10-02 19:41:30 +04:00
StrnCpy ( p + 5 , server_name , 16 ) ;
strupper ( p + 5 ) ;
1996-06-29 22:49:20 +04:00
1996-10-02 19:41:30 +04:00
CVAL ( p , 21 ) = 0x02 ; /* major version */
CVAL ( p , 22 ) = 0x02 ; /* minor version */
1996-06-29 22:49:20 +04:00
1996-10-02 19:41:30 +04:00
SIVAL ( p , 23 , server_type ) ;
SSVAL ( p , 27 , 0x010f ) ; /* browse version: got from NT/AS 4.00 */
SSVAL ( p , 29 , 0xaa55 ) ; /* browse signature */
1996-06-29 22:49:20 +04:00
1996-10-02 19:41:30 +04:00
strcpy ( p + 31 , server_comment ) ;
p + = 31 ;
p = skip_string ( p , 1 ) ;
1996-06-29 22:49:20 +04:00
1996-07-17 22:33:36 +04:00
debug_browse_data ( outbuf , PTR_DIFF ( p , outbuf ) ) ;
1996-10-02 19:41:30 +04:00
/* send the announcement */
send_mailslot_reply ( BROWSE_MAILSLOT , ClientDGRAM , outbuf ,
PTR_DIFF ( p , outbuf ) ,
from_name , to_name ,
from_type , to_type ,
to_ip , from_ip ) ;
1996-06-29 22:49:20 +04:00
}
1996-07-07 16:36:18 +04:00
/****************************************************************************
remove all samba ' s server entries
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void remove_my_servers ( void )
{
1996-10-02 19:41:30 +04:00
struct subnet_record * d ;
for ( d = subnetlist ; d ; d = d - > next )
{
struct work_record * work ;
for ( work = d - > workgrouplist ; work ; work = work - > next )
{
struct server_record * s ;
for ( s = work - > serverlist ; s ; s = s - > next )
{
if ( ! strequal ( myname , s - > serv . name ) ) continue ;
announce_server ( d , work , s - > serv . name , s - > serv . comment , 0 , 0 ) ;
}
}
}
1996-07-07 16:36:18 +04:00
}
1996-06-29 22:49:20 +04:00
/****************************************************************************
announce a server entry
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void announce_server ( struct subnet_record * d , struct work_record * work ,
1996-10-02 19:41:30 +04:00
char * name , char * comment , time_t ttl , int server_type )
1996-06-29 22:49:20 +04:00
{
1996-10-02 18:09:22 +04:00
/* domain type cannot have anything in it that might confuse
a client into thinking that the domain is in fact a server .
( SV_TYPE_SERVER_UNIX , for example )
*/
uint32 domain_type = SV_TYPE_DOMAIN_ENUM | SV_TYPE_NT ;
1996-08-01 21:49:40 +04:00
BOOL wins_iface = ip_equal ( d - > bcast_ip , ipgrp ) ;
if ( wins_iface & & server_type ! = 0 )
1996-06-29 22:49:20 +04:00
{
1996-08-01 21:49:40 +04:00
/* wins pseudo-ip interface */
if ( ! AM_MASTER ( work ) )
1996-06-29 22:49:20 +04:00
{
1996-10-02 19:41:30 +04:00
/* non-master announce by unicast to the domain
master */
1996-08-01 21:49:40 +04:00
if ( ! lp_wins_support ( ) & & * lp_wins_server ( ) )
{
/* look up the domain master with the WINS server */
queue_netbios_pkt_wins ( d , ClientNMB , NMB_QUERY ,
NAME_QUERY_ANNOUNCE_HOST ,
1996-10-02 19:41:30 +04:00
work - > work_group , 0x1b , 0 , ttl * 1000 ,
1996-08-01 21:49:40 +04:00
server_type , name , comment ,
False , False , ipzero , d - > bcast_ip ) ;
1996-07-17 22:33:36 +04:00
}
1996-08-01 21:49:40 +04:00
else
{
1996-08-05 22:19:41 +04:00
/* we are the WINS server, but not the domain master. */
/* XXXX we need to look up the domain master in our
WINS database list , and do_announce_host ( ) . maybe
we could do a name query on the unsuspecting domain
master just to make sure it ' s awake . */
1996-08-01 21:49:40 +04:00
}
}
/* XXXX any other kinds of announcements we need to consider here?
e . g local master browsers . . . no . local master browsers do
1996-10-02 19:41:30 +04:00
local master announcements to their domain master . they even
use WINS lookup of the domain master if another wins server
is being used !
1996-08-01 21:49:40 +04:00
*/
1996-06-29 22:49:20 +04:00
}
else
{
1996-08-01 21:49:40 +04:00
if ( AM_MASTER ( work ) )
{
DEBUG ( 3 , ( " sending local master announce to %s for %s(1e) \n " ,
inet_ntoa ( d - > bcast_ip ) , work - > work_group ) ) ;
do_announce_host ( ANN_LocalMasterAnnouncement ,
1996-10-02 19:41:30 +04:00
name , 0x00 , d - > myip ,
work - > work_group , 0x1e , d - > bcast_ip ,
ttl * 1000 ,
name , server_type , comment ) ;
1996-08-01 21:49:40 +04:00
DEBUG ( 3 , ( " sending domain announce to %s for %s \n " ,
inet_ntoa ( d - > bcast_ip ) , work - > work_group ) ) ;
/* XXXX should we do a domain-announce-kill? */
if ( server_type ! = 0 )
{
do_announce_host ( ANN_DomainAnnouncement ,
1996-10-02 19:41:30 +04:00
name , 0x00 , d - > myip ,
MSBROWSE , 0x01 , d - > bcast_ip ,
ttl * 1000 ,
work - > work_group , server_type ? domain_type : 0 ,
name ) ;
1996-08-01 21:49:40 +04:00
}
}
else
{
DEBUG ( 3 , ( " sending host announce to %s for %s(1d) \n " ,
inet_ntoa ( d - > bcast_ip ) , work - > work_group ) ) ;
do_announce_host ( ANN_HostAnnouncement ,
1996-10-02 19:41:30 +04:00
name , 0x00 , d - > myip ,
work - > work_group , 0x1d , d - > bcast_ip ,
ttl * 1000 ,
name , server_type , comment ) ;
1996-08-01 21:49:40 +04:00
}
1996-06-29 22:49:20 +04:00
}
}
1996-06-04 10:42:03 +04:00
/****************************************************************************
construct a host announcement unicast
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-10-07 05:56:21 +04:00
void announce_host ( time_t t )
1996-06-04 10:42:03 +04:00
{
1996-06-29 22:49:20 +04:00
struct subnet_record * d ;
1996-06-04 19:14:47 +04:00
pstring comment ;
1996-10-02 19:41:30 +04:00
char * my_name ;
StrnCpy ( comment , lp_serverstring ( ) , 43 ) ;
my_name = * myname ? myname : " NoName " ;
1996-06-04 10:42:03 +04:00
1996-06-10 07:38:08 +04:00
for ( d = subnetlist ; d ; d = d - > next )
1996-06-04 19:14:47 +04:00
{
struct work_record * work ;
1996-07-17 22:33:36 +04:00
if ( ip_equal ( d - > bcast_ip , ipgrp ) ) continue ;
1996-06-04 19:14:47 +04:00
for ( work = d - > workgrouplist ; work ; work = work - > next )
1996-10-02 19:41:30 +04:00
{
uint32 stype = work - > ServerType ;
struct server_record * s ;
BOOL announce = False ;
1996-07-07 16:36:18 +04:00
/* must work on the code that does announcements at up to
30 seconds later if a master browser sends us a request
announce .
*/
1996-10-02 19:41:30 +04:00
if ( work - > needannounce ) {
/* drop back to a max 3 minute announce - this is to prevent a
single lost packet from stuffing things up for too long */
work - > announce_interval = MIN ( work - > announce_interval ,
CHECK_TIME_MIN_HOST_ANNCE * 60 ) ;
work - > lastannounce_time = t - ( work - > announce_interval + 1 ) ;
}
/* announce every minute at first then progress to every 12 mins */
if ( work - > lastannounce_time & &
( t - work - > lastannounce_time ) < work - > announce_interval )
continue ;
if ( work - > announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60 )
work - > announce_interval + = 60 ;
work - > lastannounce_time = t ;
for ( s = work - > serverlist ; s ; s = s - > next ) {
if ( strequal ( myname , s - > serv . name ) ) {
announce = True ;
break ;
}
}
if ( announce ) {
announce_server ( d , work , my_name , comment ,
work - > announce_interval , stype ) ;
}
if ( work - > needannounce )
{
work - > needannounce = False ;
break ;
/* sorry: can't do too many announces. do some more later */
}
}
1996-07-02 19:31:33 +04:00
}
1996-06-04 10:42:03 +04:00
}
/****************************************************************************
1996-10-02 19:41:30 +04:00
announce myself as a master to all other primary domain conrollers .
1996-06-04 10:42:03 +04:00
this actually gets done in search_and_sync_workgroups ( ) via the
1996-10-02 19:41:30 +04:00
NAME_QUERY_DOM_SRV_CHK command , if there is a response from the
1996-06-04 10:42:03 +04:00
name query initiated here . see response_name_query ( )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-10-07 05:56:21 +04:00
void announce_master ( time_t t )
1996-06-04 10:42:03 +04:00
{
1996-06-10 07:38:08 +04:00
struct subnet_record * d ;
1996-06-04 19:14:47 +04:00
static time_t last = 0 ;
BOOL am_master = False ; /* are we a master of some sort? :-) */
1996-06-04 10:42:03 +04:00
1996-07-09 22:01:46 +04:00
if ( ! last ) last = t ;
if ( t - last < CHECK_TIME_MST_ANNOUNCE * 60 )
1996-10-02 19:41:30 +04:00
return ;
1996-06-04 10:42:03 +04:00
1996-06-04 19:14:47 +04:00
last = t ;
1996-06-04 10:42:03 +04:00
1996-06-10 07:38:08 +04:00
for ( d = subnetlist ; d ; d = d - > next )
1996-06-04 19:14:47 +04:00
{
1996-10-02 19:41:30 +04:00
struct work_record * work ;
for ( work = d - > workgrouplist ; work ; work = work - > next )
{
if ( AM_MASTER ( work ) )
{
am_master = True ;
}
}
1996-06-04 19:14:47 +04:00
}
if ( ! am_master ) return ; /* only proceed if we are a master browser */
1996-06-10 07:38:08 +04:00
for ( d = subnetlist ; d ; d = d - > next )
1996-06-04 19:14:47 +04:00
{
1996-10-02 19:41:30 +04:00
struct work_record * work ;
for ( work = d - > workgrouplist ; work ; work = work - > next )
{
struct server_record * s ;
for ( s = work - > serverlist ; s ; s = s - > next )
{
if ( strequal ( s - > serv . name , myname ) ) continue ;
/* all DOMs (which should also be master browsers) */
if ( s - > serv . type & SV_TYPE_DOMAIN_CTRL )
{
/* check the existence of a pdc for this workgroup, and if
one exists at the specified ip , sync with it and announce
ourselves as a master browser to it */
if ( ! * lp_domain_controller ( ) | |
! strequal ( lp_domain_controller ( ) , s - > serv . name ) )
{
if ( ! lp_wins_support ( ) & & * lp_wins_server ( ) )
{
queue_netbios_pkt_wins ( d , ClientNMB , NMB_QUERY ,
NAME_QUERY_DOM_SRV_CHK ,
work - > work_group , 0x1b , 0 , 0 , 0 , NULL , NULL ,
False , False , ipzero , ipzero ) ;
}
else
{
struct subnet_record * d2 ;
for ( d2 = subnetlist ; d2 ; d2 = d2 - > next )
{
queue_netbios_packet ( d , ClientNMB , NMB_QUERY ,
NAME_QUERY_DOM_SRV_CHK ,
work - > work_group , 0x1b , 0 , 0 , 0 , NULL , NULL ,
True , False , d2 - > bcast_ip , d2 - > bcast_ip ) ;
}
}
}
}
}
/* now do primary domain controller - the one that's not
necessarily in our browse lists , although it ought to be
this pdc is the one that we get TOLD about through smb . conf .
basically , if it ' s on a subnet that we know about , it may end
up in our browse lists ( which is why it ' s explicitly excluded
in the code above ) */
if ( * lp_domain_controller ( ) )
{
struct in_addr ip ;
BOOL bcast = False ;
ip = * interpret_addr2 ( lp_domain_controller ( ) ) ;
if ( zero_ip ( ip ) ) {
ip = d - > bcast_ip ;
bcast = True ;
}
DEBUG ( 2 , ( " Searching for DOM %s at %s \n " ,
lp_domain_controller ( ) , inet_ntoa ( ip ) ) ) ;
/* check the existence of a pdc for this workgroup, and if
one exists at the specified ip , sync with it and announce
ourselves as a master browser to it */
queue_netbios_pkt_wins ( d , ClientNMB , NMB_QUERY , NAME_QUERY_DOM_SRV_CHK ,
work - > work_group , 0x1b , 0 , 0 , 0 , NULL , NULL ,
bcast , False , ip , ip ) ;
}
}
1996-06-04 19:14:47 +04:00
}
1996-06-04 10:42:03 +04:00
}
1996-08-16 17:03:26 +04:00
/****************************************************************************
do all the " remote " announcements . These are used to put ourselves
on a remote browse list . They are done blind , no checking is done to
see if there is actually a browse master at the other end .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-10-07 05:56:21 +04:00
void announce_remote ( time_t t )
1996-08-16 17:03:26 +04:00
{
char * s , * ptr ;
static time_t last_time = 0 ;
pstring s2 ;
struct in_addr addr ;
char * comment , * workgroup ;
1996-08-21 10:09:00 +04:00
int stype = DFLT_SERVER_TYPE ;
1996-08-16 17:03:26 +04:00
if ( last_time & & t < last_time + REMOTE_ANNOUNCE_INTERVAL )
return ;
last_time = t ;
s = lp_remote_announce ( ) ;
if ( ! * s ) return ;
1996-10-02 19:41:30 +04:00
comment = lp_serverstring ( ) ;
workgroup = lp_workgroup ( ) ;
1996-08-16 17:03:26 +04:00
1996-10-02 19:41:30 +04:00
for ( ptr = s ; next_token ( & ptr , s2 , NULL ) ; ) {
1996-08-16 17:03:26 +04:00
/* the entries are of the form a.b.c.d/WORKGROUP with
WORKGROUP being optional */
char * wgroup ;
wgroup = strchr ( s2 , ' / ' ) ;
if ( wgroup ) * wgroup + + = 0 ;
if ( ! wgroup | | ! * wgroup )
wgroup = workgroup ;
addr = * interpret_addr2 ( s2 ) ;
1996-10-02 19:41:30 +04:00
do_announce_host ( ANN_HostAnnouncement , myname , 0x20 , * iface_ip ( addr ) ,
wgroup , 0x1e , addr ,
REMOTE_ANNOUNCE_INTERVAL ,
myname , stype , comment ) ;
1996-08-16 17:03:26 +04:00
}
1996-10-02 19:41:30 +04:00
1996-08-16 17:03:26 +04:00
}