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"
# define TEST_CODE
extern int DEBUGLEVEL ;
extern BOOL CanRecurse ;
extern struct in_addr ipzero ;
extern pstring myname ;
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
/* machine comment for host announcements */
extern pstring ServerComment ;
extern int updatecount ;
extern int workgroup_count ;
/* what server type are we currently */
/****************************************************************************
send a announce request to the local net
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
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-06-04 10:42:03 +04:00
inet_ntoa ( ip ) , work - > work_group ) ) ;
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 + + ;
CVAL ( p , 0 ) = work - > token ; /* flags?? XXXX probably a token*/
p + + ;
StrnCpy ( p , myname , 16 ) ;
strupper ( p ) ;
p = skip_string ( p , 1 ) ;
send_mailslot_reply ( BROWSE_MAILSLOT , ClientDGRAM , outbuf , PTR_DIFF ( p , outbuf ) ,
1996-06-06 15:43:09 +04:00
myname , work - > work_group , 0x20 , 0x1e , ip , * iface_ip ( ip ) ) ;
1996-06-04 10:42:03 +04:00
}
/****************************************************************************
request an announcement
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-05 19:16:09 +04:00
void do_announce_request ( char * info , char * to_name , int announce_type ,
int from ,
1996-06-04 10:42:03 +04:00
int to , struct in_addr dest_ip )
{
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-06-04 19:14:47 +04:00
announce_type , info , inet_ntoa ( dest_ip ) , to_name , to ) ) ;
StrnCpy ( p , info , 16 ) ;
strupper ( p ) ;
p = skip_string ( p , 1 ) ;
send_mailslot_reply ( BROWSE_MAILSLOT , ClientDGRAM , outbuf , PTR_DIFF ( p , outbuf ) ,
1996-06-06 15:43:09 +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 ,
int name_type ,
struct in_addr ip )
{
add_browser_entry ( serv_name , name_type , work_name , 0 , ip ) ;
if ( state = = NAME_QUERY_MST_SRV_CHK )
{
/* announce ourselves as a master browser to serv_name */
do_announce_request ( myname , serv_name , ANN_MasterAnnouncement ,
0x20 , 0 , ip ) ;
}
}
1996-06-04 10:42:03 +04:00
/****************************************************************************
construct a host announcement unicast
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void announce_backup ( void )
{
1996-06-05 19:16:09 +04:00
static time_t lastrun = 0 ;
time_t t = time ( NULL ) ;
pstring outbuf ;
char * p ;
1996-06-10 07:38:08 +04:00
struct subnet_record * d1 ;
1996-06-05 19:16:09 +04:00
int tok ;
if ( ! lastrun ) lastrun = t ;
1996-06-29 22:49:20 +04:00
if ( t < lastrun + CHECK_TIME_ANNOUNCE_BACKUP * 60 )
return ;
1996-06-05 19:16:09 +04:00
lastrun = t ;
for ( tok = 0 ; tok < = workgroup_count ; tok + + )
{
1996-06-10 07:38:08 +04:00
for ( d1 = subnetlist ; d1 ; d1 = d1 - > next )
1996-06-04 10:42:03 +04:00
{
1996-06-05 19:16:09 +04:00
struct work_record * work ;
1996-06-10 07:38:08 +04:00
struct subnet_record * d ;
1996-06-05 19:16:09 +04:00
/* search for unique workgroup: only the name matters */
for ( work = d1 - > workgrouplist ;
work & & ( tok ! = work - > token ) ;
work = work - > next ) ;
if ( ! work ) continue ;
/* found one: announce it across all domains */
1996-06-10 07:38:08 +04:00
for ( d = subnetlist ; d ; d = d - > next )
1996-06-05 19:16:09 +04:00
{
int type = 0 ;
if ( AM_DOMCTL ( work ) ) {
type = 0x1b ;
} else if ( AM_MASTER ( work ) ) {
type = 0x1d ;
} else {
continue ;
}
DEBUG ( 2 , ( " sending announce backup %s workgroup %s(%d) \n " ,
inet_ntoa ( d - > bcast_ip ) , work - > work_group ,
work - > token ) ) ;
bzero ( outbuf , sizeof ( outbuf ) ) ;
p = outbuf ;
CVAL ( p , 0 ) = ANN_GetBackupListReq ;
p + + ;
CVAL ( p , 0 ) = 1 ; /* count? */
SIVAL ( p , 1 , work - > token ) ; /* workgroup unique key index */
p + = 5 ;
p + + ;
send_mailslot_reply ( BROWSE_MAILSLOT ,
ClientDGRAM , outbuf ,
PTR_DIFF ( p , outbuf ) ,
myname , work - > work_group ,
1996-06-06 15:43:09 +04:00
0x0 , type , d - > bcast_ip ,
* iface_ip ( d - > bcast_ip ) ) ;
1996-06-05 19:16:09 +04:00
}
1996-06-04 10:42:03 +04:00
}
1996-06-05 19:16:09 +04:00
}
1996-06-04 10:42:03 +04:00
}
1996-06-29 22:49:20 +04:00
/****************************************************************************
send a host announcement packet
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-07-03 06:58:18 +04:00
static void do_announce_host ( int command ,
1996-06-29 22:49:20 +04:00
char * from_name , int from_type , struct in_addr from_ip ,
char * to_name , int to_type , struct in_addr to_ip ,
1996-07-03 06:58:18 +04:00
time_t announce_interval ,
1996-06-29 22:49:20 +04:00
char * server_name , int server_type , char * server_comment )
{
pstring outbuf ;
char * p ;
bzero ( outbuf , sizeof ( outbuf ) ) ;
p = outbuf + 1 ;
/* command type */
CVAL ( outbuf , 0 ) = command ;
/* announcement parameters */
CVAL ( p , 0 ) = updatecount ;
SIVAL ( p , 1 , announce_interval * 1000 ) ; /* ms - despite the spec */
StrnCpy ( p + 5 , server_name , 16 ) ;
strupper ( p + 5 ) ;
CVAL ( p , 21 ) = 2 ; /* major version */
CVAL ( p , 22 ) = 2 ; /* minor version */
SIVAL ( p , 23 , server_type ) ;
SSVAL ( p , 27 , 0xaa55 ) ; /* browse signature */
SSVAL ( p , 29 , 1 ) ; /* browse version */
strcpy ( p + 31 , server_comment ) ;
p + = 31 ;
p = skip_string ( p , 1 ) ;
/* 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 ) ;
}
/****************************************************************************
announce a server entry
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void announce_server ( struct subnet_record * d , struct work_record * work ,
char * name , char * comment , time_t ttl , int server_type )
{
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 ,
name , 0x00 , d - > myip ,
work - > work_group , 0x1e , d - > bcast_ip ,
1996-07-03 06:58:18 +04:00
ttl * 1000 ,
1996-06-29 22:49:20 +04:00
name , server_type , comment ) ;
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 ,
work - > work_group , 0x00 , d - > myip ,
MSBROWSE , 0x01 , d - > bcast_ip ,
1996-07-03 06:58:18 +04:00
ttl * 1000 ,
1996-06-29 22:49:20 +04:00
name , server_type ? SV_TYPE_DOMAIN_ENUM : 0 , comment ) ;
}
}
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 ,
name , 0x00 , d - > myip ,
work - > work_group , 0x1d , d - > bcast_ip ,
1996-07-03 06:58:18 +04:00
ttl * 1000 ,
1996-06-29 22:49:20 +04:00
name , server_type , comment ) ;
}
}
1996-06-04 10:42:03 +04:00
/****************************************************************************
construct a host announcement unicast
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void announce_host ( void )
{
1996-06-04 19:14:47 +04:00
time_t t = time ( NULL ) ;
1996-06-29 22:49:20 +04:00
struct subnet_record * d ;
1996-06-04 19:14:47 +04:00
pstring comment ;
char * my_name ;
1996-06-04 10:42:03 +04:00
1996-06-04 19:14:47 +04:00
StrnCpy ( comment , * ServerComment ? ServerComment : " NoComment " , 43 ) ;
1996-06-04 10:42:03 +04:00
1996-06-04 19:14:47 +04:00
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 ;
for ( work = d - > workgrouplist ; work ; work = work - > next )
{
uint32 stype = work - > ServerType ;
struct server_record * s ;
BOOL announce = False ;
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 */
1996-07-02 19:31:33 +04:00
work - > announce_interval = MIN ( work - > announce_interval ,
CHECK_TIME_MIN_HOST_ANNCE * 60 ) ;
1996-06-04 19:14:47 +04:00
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 ;
1996-06-08 08:34:45 +04:00
if ( work - > announce_interval < CHECK_TIME_MAX_HOST_ANNCE * 60 )
1996-06-04 19:14:47 +04:00
work - > announce_interval + = 60 ;
work - > lastannounce_time = t ;
1996-06-10 07:38:08 +04:00
if ( ! d - > my_interface ) {
1996-06-04 19:14:47 +04:00
stype & = ~ ( SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_MASTER_BROWSER |
SV_TYPE_DOMAIN_MASTER | SV_TYPE_BACKUP_BROWSER |
SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_MEMBER ) ;
}
for ( s = work - > serverlist ; s ; s = s - > next ) {
if ( strequal ( myname , s - > serv . name ) ) {
announce = True ;
break ;
}
}
if ( announce )
1996-07-02 19:31:33 +04:00
{
1996-06-29 22:49:20 +04:00
announce_server ( d , work , my_name , comment , work - > announce_interval , stype ) ;
1996-07-02 19:31:33 +04:00
}
1996-06-04 19:14:47 +04:00
1996-06-29 22:49:20 +04:00
if ( work - > needannounce )
1996-07-02 19:31:33 +04:00
{
1996-06-29 22:49:20 +04:00
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-07-02 19:31:33 +04:00
}
1996-06-04 10:42:03 +04:00
}
/****************************************************************************
announce myself as a master to all other primary domain conrollers .
BIG NOTE : this code will remain untested until some kind soul that has access
to a couple of windows NT advanced servers runs this version of nmbd for at
least 15 minutes .
this actually gets done in search_and_sync_workgroups ( ) via the
1996-06-29 22:49:20 +04:00
NAME_QUERY_MST_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 ( )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void announce_master ( void )
{
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 ;
time_t t = time ( NULL ) ;
BOOL am_master = False ; /* are we a master of some sort? :-) */
1996-06-04 10:42:03 +04:00
1996-07-02 19:31:33 +04:00
if ( last & & ( t - last < CHECK_TIME_MST_ANNOUNCE * 60 ) )
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
{
struct work_record * work ;
for ( work = d - > workgrouplist ; work ; work = work - > next )
1996-06-04 10:42:03 +04:00
{
1996-06-04 19:14:47 +04:00
if ( AM_MASTER ( work ) )
{
am_master = True ;
}
1996-06-04 10:42:03 +04:00
}
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
{
struct work_record * work ;
for ( work = d - > workgrouplist ; work ; work = work - > next )
1996-06-04 10:42:03 +04:00
{
1996-06-04 19:14:47 +04:00
struct server_record * s ;
for ( s = work - > serverlist ; s ; s = s - > next )
{
if ( strequal ( s - > serv . name , myname ) ) continue ;
/* all PDCs (which should also be master browsers) */
if ( s - > serv . type & SV_TYPE_DOMAIN_CTRL )
1996-06-04 10:42:03 +04:00
{
1996-06-04 19:14:47 +04:00
/* 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 ( ) )
1996-06-04 10:42:03 +04:00
{
1996-06-04 19:14:47 +04:00
struct in_addr ip ;
ip = ipzero ;
1996-06-29 22:49:20 +04:00
queue_netbios_pkt_wins ( d , ClientNMB , NMB_QUERY ,
NAME_QUERY_MST_SRV_CHK ,
work - > work_group , 0x1b , 0 , 0 ,
1996-06-04 19:14:47 +04:00
False , False , ip ) ;
1996-06-04 10:42:03 +04:00
}
1996-06-04 19:14:47 +04:00
else
1996-06-04 10:42:03 +04:00
{
1996-06-10 07:38:08 +04:00
struct subnet_record * d2 ;
for ( d2 = subnetlist ; d2 ; d2 = d2 - > next )
1996-06-04 19:14:47 +04:00
{
1996-06-29 22:49:20 +04:00
queue_netbios_packet ( d , ClientNMB , NMB_QUERY ,
NAME_QUERY_MST_SRV_CHK ,
work - > work_group , 0x1b , 0 , 0 ,
1996-06-04 19:14:47 +04:00
True , False , d2 - > bcast_ip ) ;
}
1996-06-04 10:42:03 +04:00
}
1996-06-04 19:14:47 +04:00
}
1996-06-04 10:42:03 +04:00
}
1996-06-04 19:14:47 +04:00
}
/* 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 ( ) ) ;
1996-06-06 15:43:09 +04:00
if ( zero_ip ( ip ) ) {
1996-06-08 08:34:45 +04:00
ip = d - > bcast_ip ;
1996-06-06 15:43:09 +04:00
bcast = True ;
}
1996-06-04 19:14:47 +04:00
DEBUG ( 2 , ( " Searching for PDC %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 */
1996-06-29 22:49:20 +04:00
queue_netbios_pkt_wins ( d , ClientNMB , NMB_QUERY , NAME_QUERY_MST_SRV_CHK ,
work - > work_group , 0x1b , 0 , 0 ,
1996-06-04 19:14:47 +04:00
bcast , False , ip ) ;
}
1996-06-04 10:42:03 +04:00
}
1996-06-04 19:14:47 +04:00
}
1996-06-04 10:42:03 +04:00
}