1
0
mirror of https://github.com/samba-team/samba.git synced 2025-09-24 05:44:20 +03:00

Half-way though the big conversion of all nmbd access to wire elements being

converted to pull/push_ascii. This will not work right at the moment for non
English codepages, but compiles - I will finish the work over the weekend.
Then nmbd should be completely codepage correct.
Jeremy.
This commit is contained in:
Jeremy Allison
-
parent daf7b5fbd9
commit 236d6adadf
12 changed files with 1896 additions and 1984 deletions

View File

@@ -176,124 +176,116 @@ enum name_source {LMHOSTS_NAME, REGISTER_NAME, SELF_NAME, DNS_NAME,
enum node_type {B_NODE=0, P_NODE=1, M_NODE=2, NBDD_NODE=3}; enum node_type {B_NODE=0, P_NODE=1, M_NODE=2, NBDD_NODE=3};
enum packet_type {NMB_PACKET, DGRAM_PACKET}; enum packet_type {NMB_PACKET, DGRAM_PACKET};
enum master_state enum master_state {
{ MST_NONE,
MST_NONE, MST_POTENTIAL,
MST_POTENTIAL, MST_BACKUP,
MST_BACKUP, MST_MSB,
MST_MSB, MST_BROWSER,
MST_BROWSER, MST_UNBECOMING_MASTER
MST_UNBECOMING_MASTER
}; };
enum domain_state enum domain_state {
{ DOMAIN_NONE,
DOMAIN_NONE, DOMAIN_WAIT,
DOMAIN_WAIT, DOMAIN_MST
DOMAIN_MST
}; };
enum logon_state enum logon_state {
{ LOGON_NONE,
LOGON_NONE, LOGON_WAIT,
LOGON_WAIT, LOGON_SRV
LOGON_SRV
}; };
struct subnet_record; struct subnet_record;
struct nmb_data struct nmb_data {
{ uint16 nb_flags; /* Netbios flags. */
uint16 nb_flags; /* Netbios flags. */ int num_ips; /* Number of ip entries. */
int num_ips; /* Number of ip entries. */ struct in_addr *ip; /* The ip list for this name. */
struct in_addr *ip; /* The ip list for this name. */
enum name_source source; /* Where the name came from. */ enum name_source source; /* Where the name came from. */
time_t death_time; /* The time the record must be removed (do not remove if 0). */ time_t death_time; /* The time the record must be removed (do not remove if 0). */
time_t refresh_time; /* The time the record should be refreshed. */ time_t refresh_time; /* The time the record should be refreshed. */
SMB_BIG_UINT id; /* unique id */ SMB_BIG_UINT id; /* unique id */
struct in_addr wins_ip; /* the adress of the wins server this record comes from */ struct in_addr wins_ip; /* the adress of the wins server this record comes from */
int wins_flags; /* similar to the netbios flags but different ! */ int wins_flags; /* similar to the netbios flags but different ! */
}; };
/* This structure represents an entry in a local netbios name list. */ /* This structure represents an entry in a local netbios name list. */
struct name_record struct name_record {
{ ubi_trNode node[1];
ubi_trNode node[1]; struct subnet_record *subnet;
struct subnet_record *subnet; struct nmb_name name; /* The netbios name. */
struct nmb_name name; /* The netbios name. */ struct nmb_data data; /* The netbios data. */
struct nmb_data data; /* The netbios data. */ };
};
/* Browser cache for synchronising browse lists. */ /* Browser cache for synchronising browse lists. */
struct browse_cache_record struct browse_cache_record {
{ ubi_dlNode node[1];
ubi_dlNode node[1]; pstring lmb_name;
pstring lmb_name; pstring work_group;
pstring work_group; struct in_addr ip;
struct in_addr ip; time_t sync_time;
time_t sync_time; time_t death_time; /* The time the record must be removed. */
time_t death_time; /* The time the record must be removed. */ };
};
/* This is used to hold the list of servers in my domain, and is /* This is used to hold the list of servers in my domain, and is
contained within lists of domains. */ contained within lists of domains. */
struct server_record struct server_record {
{ struct server_record *next;
struct server_record *next; struct server_record *prev;
struct server_record *prev;
struct subnet_record *subnet; struct subnet_record *subnet;
struct server_info_struct serv; struct server_info_struct serv;
time_t death_time; time_t death_time;
}; };
/* A workgroup structure. It contains a list of servers. */ /* A workgroup structure. It contains a list of servers. */
struct work_record struct work_record {
{ struct work_record *next;
struct work_record *next; struct work_record *prev;
struct work_record *prev;
struct subnet_record *subnet; struct subnet_record *subnet;
struct server_record *serverlist; struct server_record *serverlist;
/* Stage of development from non-local-master up to local-master browser. */ /* Stage of development from non-local-master up to local-master browser. */
enum master_state mst_state; enum master_state mst_state;
/* Stage of development from non-domain-master to domain-master browser. */ /* Stage of development from non-domain-master to domain-master browser. */
enum domain_state dom_state; enum domain_state dom_state;
/* Stage of development from non-logon-server to logon server. */ /* Stage of development from non-logon-server to logon server. */
enum logon_state log_state; enum logon_state log_state;
/* Work group info. */ /* Work group info. */
fstring work_group; fstring work_group;
int token; /* Used when communicating with backup browsers. */ int token; /* Used when communicating with backup browsers. */
fstring local_master_browser_name; /* Current local master browser. */ fstring local_master_browser_name; /* Current local master browser. */
/* Announce info. */ /* Announce info. */
time_t lastannounce_time; time_t lastannounce_time;
int announce_interval; int announce_interval;
BOOL needannounce; BOOL needannounce;
/* Timeout time for this workgroup. 0 means permanent. */ /* Timeout time for this workgroup. 0 means permanent. */
time_t death_time; time_t death_time;
/* Election info */ /* Election info */
BOOL RunningElection; BOOL RunningElection;
BOOL needelection; BOOL needelection;
int ElectionCount; int ElectionCount;
uint32 ElectionCriterion; uint32 ElectionCriterion;
/* Domain master browser info. Used for efficient syncs. */ /* Domain master browser info. Used for efficient syncs. */
struct nmb_name dmb_name; struct nmb_name dmb_name;
struct in_addr dmb_addr; struct in_addr dmb_addr;
}; };
/* typedefs needed to define copy & free functions for userdata. */ /* typedefs needed to define copy & free functions for userdata. */
@@ -305,10 +297,10 @@ typedef void (*userdata_free_fn)(struct userdata_struct *);
/* Structure to define any userdata passed around. */ /* Structure to define any userdata passed around. */
struct userdata_struct { struct userdata_struct {
userdata_copy_fn copy_fn; userdata_copy_fn copy_fn;
userdata_free_fn free_fn; userdata_free_fn free_fn;
unsigned int userdata_len; unsigned int userdata_len;
char data[16]; /* 16 is to ensure alignment/padding on all systems */ char data[16]; /* 16 is to ensure alignment/padding on all systems */
}; };
struct response_record; struct response_record;
@@ -382,33 +374,32 @@ typedef void (*node_status_fail_function)( struct subnet_record *,
/* Initiated name queries are recorded in this list to track any responses. */ /* Initiated name queries are recorded in this list to track any responses. */
struct response_record struct response_record {
{ struct response_record *next;
struct response_record *next; struct response_record *prev;
struct response_record *prev;
uint16 response_id; uint16 response_id;
/* Callbacks for packets received or not. */ /* Callbacks for packets received or not. */
response_function resp_fn; response_function resp_fn;
timeout_response_function timeout_fn; timeout_response_function timeout_fn;
/* Callbacks for the request succeeding or not. */ /* Callbacks for the request succeeding or not. */
success_function success_fn; success_function success_fn;
fail_function fail_fn; fail_function fail_fn;
struct packet_struct *packet; struct packet_struct *packet;
struct userdata_struct *userdata; struct userdata_struct *userdata;
int num_msgs; int num_msgs;
time_t repeat_time; time_t repeat_time;
time_t repeat_interval; time_t repeat_interval;
int repeat_count; int repeat_count;
/* Recursion protection. */ /* Recursion protection. */
BOOL in_expiration_processing; BOOL in_expiration_processing;
}; };
/* A subnet structure. It contains a list of workgroups and netbios names. */ /* A subnet structure. It contains a list of workgroups and netbios names. */
@@ -420,42 +411,41 @@ struct response_record
*/ */
enum subnet_type { enum subnet_type {
NORMAL_SUBNET = 0, /* Subnet listed in interfaces list. */ NORMAL_SUBNET = 0, /* Subnet listed in interfaces list. */
UNICAST_SUBNET = 1, /* Subnet for unicast packets. */ UNICAST_SUBNET = 1, /* Subnet for unicast packets. */
REMOTE_BROADCAST_SUBNET = 2, /* Subnet for remote broadcasts. */ REMOTE_BROADCAST_SUBNET = 2, /* Subnet for remote broadcasts. */
WINS_SERVER_SUBNET = 3 /* Only created if we are a WINS server. */ WINS_SERVER_SUBNET = 3 /* Only created if we are a WINS server. */
}; };
struct subnet_record struct subnet_record {
{ struct subnet_record *next;
struct subnet_record *next; struct subnet_record *prev;
struct subnet_record *prev;
char *subnet_name; /* For Debug identification. */ char *subnet_name; /* For Debug identification. */
enum subnet_type type; /* To catagorize the subnet. */ enum subnet_type type; /* To catagorize the subnet. */
struct work_record *workgrouplist; /* List of workgroups. */ struct work_record *workgrouplist; /* List of workgroups. */
ubi_trRoot namelist[1]; /* List of netbios names. */ ubi_trRoot namelist[1]; /* List of netbios names. */
struct response_record *responselist; /* List of responses expected. */ struct response_record *responselist; /* List of responses expected. */
BOOL namelist_changed; BOOL namelist_changed;
BOOL work_changed; BOOL work_changed;
struct in_addr bcast_ip; struct in_addr bcast_ip;
struct in_addr mask_ip; struct in_addr mask_ip;
struct in_addr myip; struct in_addr myip;
int nmb_sock; /* socket to listen for unicast 137. */ int nmb_sock; /* socket to listen for unicast 137. */
int dgram_sock; /* socket to listen for unicast 138. */ int dgram_sock; /* socket to listen for unicast 138. */
}; };
/* A resource record. */ /* A resource record. */
struct res_rec { struct res_rec {
struct nmb_name rr_name; struct nmb_name rr_name;
int rr_type; int rr_type;
int rr_class; int rr_class;
int ttl; int ttl;
int rdlength; int rdlength;
char rdata[MAX_DGRAM_SIZE]; char rdata[MAX_DGRAM_SIZE];
}; };
/* Define these so we can pass info back to caller of name_query */ /* Define these so we can pass info back to caller of name_query */
@@ -467,35 +457,34 @@ struct res_rec {
#define NM_FLAGS_B 0x01 /* Broadcast */ #define NM_FLAGS_B 0x01 /* Broadcast */
/* An nmb packet. */ /* An nmb packet. */
struct nmb_packet struct nmb_packet {
{ struct {
struct { int name_trn_id;
int name_trn_id; int opcode;
int opcode; BOOL response;
BOOL response; struct {
struct { BOOL bcast;
BOOL bcast; BOOL recursion_available;
BOOL recursion_available; BOOL recursion_desired;
BOOL recursion_desired; BOOL trunc;
BOOL trunc; BOOL authoritative;
BOOL authoritative; } nm_flags;
} nm_flags; int rcode;
int rcode; int qdcount;
int qdcount; int ancount;
int ancount; int nscount;
int nscount; int arcount;
int arcount; } header;
} header;
struct { struct {
struct nmb_name question_name; struct nmb_name question_name;
int question_type; int question_type;
int question_class; int question_class;
} question; } question;
struct res_rec *answers; struct res_rec *answers;
struct res_rec *nsrecs; struct res_rec *nsrecs;
struct res_rec *additional; struct res_rec *additional;
}; };
/* msg_type field options - from rfc1002. */ /* msg_type field options - from rfc1002. */
@@ -511,23 +500,23 @@ struct nmb_packet
/* A datagram - this normally contains SMB data in the data[] array. */ /* A datagram - this normally contains SMB data in the data[] array. */
struct dgram_packet { struct dgram_packet {
struct { struct {
int msg_type; int msg_type;
struct { struct {
enum node_type node_type; enum node_type node_type;
BOOL first; BOOL first;
BOOL more; BOOL more;
} flags; } flags;
int dgm_id; int dgm_id;
struct in_addr source_ip; struct in_addr source_ip;
int source_port; int source_port;
int dgm_length; int dgm_length;
int packet_offset; int packet_offset;
} header; } header;
struct nmb_name source_name; struct nmb_name source_name;
struct nmb_name dest_name; struct nmb_name dest_name;
int datasize; int datasize;
char data[MAX_DGRAM_SIZE]; char data[MAX_DGRAM_SIZE];
}; };
/* Define a structure used to queue packets. This will be a linked /* Define a structure used to queue packets. This will be a linked
@@ -535,18 +524,18 @@ struct dgram_packet {
struct packet_struct struct packet_struct
{ {
struct packet_struct *next; struct packet_struct *next;
struct packet_struct *prev; struct packet_struct *prev;
BOOL locked; BOOL locked;
struct in_addr ip; struct in_addr ip;
int port; int port;
int fd; int fd;
time_t timestamp; time_t timestamp;
enum packet_type packet_type; enum packet_type packet_type;
union { union {
struct nmb_packet nmb; struct nmb_packet nmb;
struct dgram_packet dgram; struct dgram_packet dgram;
} packet; } packet;
}; };
/* NETLOGON opcodes */ /* NETLOGON opcodes */

View File

@@ -124,6 +124,7 @@ size_t __unsafe_string_function_usage_here_char__(void);
#define pstrcat(d,s) safe_strcat((d), (s),sizeof(pstring)-1) #define pstrcat(d,s) safe_strcat((d), (s),sizeof(pstring)-1)
#define fstrcpy(d,s) safe_strcpy((d),(s),sizeof(fstring)-1) #define fstrcpy(d,s) safe_strcpy((d),(s),sizeof(fstring)-1)
#define fstrcat(d,s) safe_strcat((d),(s),sizeof(fstring)-1) #define fstrcat(d,s) safe_strcat((d),(s),sizeof(fstring)-1)
#define nstrcpy(d,s) safe_strcpy((d), (s),sizeof(nstring)-1)
/* the addition of the DEVELOPER checks in safe_strcpy means we must /* the addition of the DEVELOPER checks in safe_strcpy means we must
* update a lot of code. To make this a little easier here are some * update a lot of code. To make this a little easier here are some

View File

@@ -1484,9 +1484,11 @@ struct cnotify_fns {
#include "smb_macros.h" #include "smb_macros.h"
typedef char nstring[16];
/* A netbios name structure. */ /* A netbios name structure. */
struct nmb_name { struct nmb_name {
char name[16]; nstring name;
char scope[64]; char scope[64];
unsigned int name_type; unsigned int name_type;
}; };
@@ -1494,7 +1496,7 @@ struct nmb_name {
/* A netbios node status array element. */ /* A netbios node status array element. */
struct node_status { struct node_status {
char name[16]; nstring name;
unsigned char type; unsigned char type;
unsigned char flags; unsigned char flags;
}; };

View File

@@ -529,6 +529,11 @@ size_t push_ascii_pstring(void *dest, const char *src)
return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE); return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
} }
size_t push_ascii_nstring(void *dest, const char *src)
{
return push_ascii(dest, src, sizeof(nstring), STR_TERMINATE);
}
/** /**
* Copy a string from a dos codepage source to a unix char* destination. * Copy a string from a dos codepage source to a unix char* destination.
* *
@@ -582,6 +587,11 @@ size_t pull_ascii_fstring(char *dest, const void *src)
return pull_ascii(dest, src, sizeof(fstring), -1, STR_TERMINATE); return pull_ascii(dest, src, sizeof(fstring), -1, STR_TERMINATE);
} }
size_t pull_ascii_nstring(char *dest, const void *src)
{
return pull_ascii(dest, src, sizeof(nstring), sizeof(nstring), STR_TERMINATE);
}
/** /**
* Copy a string from a char* src to a unicode destination. * Copy a string from a char* src to a unicode destination.
* *

View File

@@ -303,6 +303,7 @@ static BOOL reload_nmbd_services(BOOL test)
* We use buf here to return BOOL result to process() when reload_interfaces() * We use buf here to return BOOL result to process() when reload_interfaces()
* detects that there are no subnets. * detects that there are no subnets.
**************************************************************************** */ **************************************************************************** */
static void msg_reload_nmbd_services(int msg_type, pid_t src, void *buf, size_t len) static void msg_reload_nmbd_services(int msg_type, pid_t src, void *buf, size_t len)
{ {
write_browse_list( 0, True ); write_browse_list( 0, True );
@@ -650,126 +651,120 @@ static BOOL open_sockets(BOOL isdaemon, int port)
log_stdout = True; log_stdout = True;
} }
if ( log_stdout && Fork ) { if ( log_stdout && Fork ) {
DEBUG(0,("ERROR: Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n")); DEBUG(0,("ERROR: Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n"));
exit(1); exit(1);
} }
setup_logging( argv[0], log_stdout ); setup_logging( argv[0], log_stdout );
reopen_logs(); reopen_logs();
DEBUG( 0, ( "Netbios nameserver version %s started.\n", SAMBA_VERSION_STRING) ); DEBUG( 0, ( "Netbios nameserver version %s started.\n", SAMBA_VERSION_STRING) );
DEBUGADD( 0, ( "Copyright Andrew Tridgell and the Samba Team 1994-2003\n" ) ); DEBUGADD( 0, ( "Copyright Andrew Tridgell and the Samba Team 1994-2003\n" ) );
if ( !reload_nmbd_services(False) ) if ( !reload_nmbd_services(False) )
return(-1); return(-1);
if(!init_names()) if(!init_names())
return -1; return -1;
reload_nmbd_services( True ); reload_nmbd_services( True );
if (strequal(lp_workgroup(),"*")) if (strequal(lp_workgroup(),"*")) {
{ DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n")); exit(1);
exit(1); }
}
set_samba_nb_type(); set_samba_nb_type();
if (!is_daemon && !is_a_socket(0)) if (!is_daemon && !is_a_socket(0)) {
{ DEBUG(0,("standard input is not a socket, assuming -D option\n"));
DEBUG(0,("standard input is not a socket, assuming -D option\n")); is_daemon = True;
is_daemon = True; }
}
if (is_daemon && !opt_interactive) if (is_daemon && !opt_interactive) {
{ DEBUG( 2, ( "Becoming a daemon.\n" ) );
DEBUG( 2, ( "Becoming a daemon.\n" ) ); become_daemon(Fork);
become_daemon(Fork); }
}
#if HAVE_SETPGID #if HAVE_SETPGID
/* /*
* If we're interactive we want to set our own process group for * If we're interactive we want to set our own process group for
* signal management. * signal management.
*/ */
if (opt_interactive) if (opt_interactive)
setpgid( (pid_t)0, (pid_t)0 ); setpgid( (pid_t)0, (pid_t)0 );
#endif #endif
#ifndef SYNC_DNS #ifndef SYNC_DNS
/* Setup the async dns. We do it here so it doesn't have all the other /* Setup the async dns. We do it here so it doesn't have all the other
stuff initialised and thus chewing memory and sockets */ stuff initialised and thus chewing memory and sockets */
if(lp_we_are_a_wins_server() && lp_dns_proxy()) { if(lp_we_are_a_wins_server() && lp_dns_proxy()) {
start_async_dns(); start_async_dns();
} }
#endif #endif
if (!directory_exist(lp_lockdir(), NULL)) { if (!directory_exist(lp_lockdir(), NULL)) {
mkdir(lp_lockdir(), 0755); mkdir(lp_lockdir(), 0755);
} }
pidfile_create("nmbd"); pidfile_create("nmbd");
message_init(); message_init();
message_register(MSG_FORCE_ELECTION, nmbd_message_election); message_register(MSG_FORCE_ELECTION, nmbd_message_election);
message_register(MSG_WINS_NEW_ENTRY, nmbd_wins_new_entry); message_register(MSG_WINS_NEW_ENTRY, nmbd_wins_new_entry);
message_register(MSG_SHUTDOWN, nmbd_terminate); message_register(MSG_SHUTDOWN, nmbd_terminate);
message_register(MSG_SMB_CONF_UPDATED, msg_reload_nmbd_services); message_register(MSG_SMB_CONF_UPDATED, msg_reload_nmbd_services);
DEBUG( 3, ( "Opening sockets %d\n", global_nmb_port ) ); DEBUG( 3, ( "Opening sockets %d\n", global_nmb_port ) );
if ( !open_sockets( is_daemon, global_nmb_port ) ) { if ( !open_sockets( is_daemon, global_nmb_port ) ) {
kill_async_dns_child(); kill_async_dns_child();
return 1; return 1;
} }
/* Determine all the IP addresses we have. */ /* Determine all the IP addresses we have. */
load_interfaces(); load_interfaces();
/* Create an nmbd subnet record for each of the above. */ /* Create an nmbd subnet record for each of the above. */
if( False == create_subnets() ) if( False == create_subnets() ) {
{ DEBUG(0,("ERROR: Failed when creating subnet lists. Exiting.\n"));
DEBUG(0,("ERROR: Failed when creating subnet lists. Exiting.\n")); kill_async_dns_child();
kill_async_dns_child(); exit(1);
exit(1); }
}
/* Load in any static local names. */ /* Load in any static local names. */
load_lmhosts_file(dyn_LMHOSTSFILE); load_lmhosts_file(dyn_LMHOSTSFILE);
DEBUG(3,("Loaded hosts file %s\n", dyn_LMHOSTSFILE)); DEBUG(3,("Loaded hosts file %s\n", dyn_LMHOSTSFILE));
/* If we are acting as a WINS server, initialise data structures. */ /* If we are acting as a WINS server, initialise data structures. */
if( !initialise_wins() ) if( !initialise_wins() ) {
{ DEBUG( 0, ( "nmbd: Failed when initialising WINS server.\n" ) );
DEBUG( 0, ( "nmbd: Failed when initialising WINS server.\n" ) ); kill_async_dns_child();
kill_async_dns_child(); exit(1);
exit(1); }
}
/* /*
* Register nmbd primary workgroup and nmbd names on all * Register nmbd primary workgroup and nmbd names on all
* the broadcast subnets, and on the WINS server (if specified). * the broadcast subnets, and on the WINS server (if specified).
* Also initiate the startup of our primary workgroup (start * Also initiate the startup of our primary workgroup (start
* elections if we are setup as being able to be a local * elections if we are setup as being able to be a local
* master browser. * master browser.
*/ */
if( False == register_my_workgroup_and_names() ) if( False == register_my_workgroup_and_names() ) {
{ DEBUG(0,("ERROR: Failed when creating my my workgroup. Exiting.\n"));
DEBUG(0,("ERROR: Failed when creating my my workgroup. Exiting.\n")); kill_async_dns_child();
kill_async_dns_child(); exit(1);
exit(1); }
}
/* We can only take signals in the select. */ /* We can only take signals in the select. */
BlockSignals( True, SIGTERM ); BlockSignals( True, SIGTERM );
process(); process();
if (dbf) if (dbf)
x_fclose(dbf); x_fclose(dbf);
kill_async_dns_child(); kill_async_dns_child();
return(0); return(0);
} }

View File

@@ -3,7 +3,7 @@
NBT netbios routines and daemon - version 2 NBT netbios routines and daemon - version 2
Copyright (C) Andrew Tridgell 1994-1998 Copyright (C) Andrew Tridgell 1994-1998
Copyright (C) Luke Kenneth Casson Leighton 1994-1998 Copyright (C) Luke Kenneth Casson Leighton 1994-1998
Copyright (C) Jeremy Allison 1994-1998 Copyright (C) Jeremy Allison 1994-2003
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -37,36 +37,37 @@ static void become_domain_master_fail(struct subnet_record *subrec,
struct response_record *rrec, struct response_record *rrec,
struct nmb_name *fail_name) struct nmb_name *fail_name)
{ {
struct work_record *work = find_workgroup_on_subnet(subrec, fail_name->name); nstring failname;
struct server_record *servrec; struct work_record *work;
struct server_record *servrec;
if(!work) pull_ascii_nstring(failname, fail_name->name);
{ work = find_workgroup_on_subnet(subrec, failname);
DEBUG(0,("become_domain_master_fail: Error - cannot find \ if(!work) {
workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name)); DEBUG(0,("become_domain_master_fail: Error - cannot find \
return; workgroup %s on subnet %s\n", failname, subrec->subnet_name));
} return;
}
/* Set the state back to DOMAIN_NONE. */ /* Set the state back to DOMAIN_NONE. */
work->dom_state = DOMAIN_NONE; work->dom_state = DOMAIN_NONE;
if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
{ DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
in workgroup %s on subnet %s\n", in workgroup %s on subnet %s\n",
global_myname(), work->work_group, subrec->subnet_name)); global_myname(), work->work_group, subrec->subnet_name));
return; return;
} }
/* Update our server status. */ /* Update our server status. */
servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER; servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
/* Tell the namelist writer to write out a change. */ /* Tell the namelist writer to write out a change. */
subrec->work_changed = True; subrec->work_changed = True;
DEBUG(0,("become_domain_master_fail: Failed to become a domain master browser for \ DEBUG(0,("become_domain_master_fail: Failed to become a domain master browser for \
workgroup %s on subnet %s. Couldn't register name %s.\n", workgroup %s on subnet %s. Couldn't register name %s.\n",
work->work_group, subrec->subnet_name, nmb_namestr(fail_name))); work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
} }
/**************************************************************************** /****************************************************************************
@@ -79,115 +80,112 @@ static void become_domain_master_stage2(struct subnet_record *subrec,
uint16 nb_flags, uint16 nb_flags,
int ttl, struct in_addr registered_ip) int ttl, struct in_addr registered_ip)
{ {
struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name); nstring regname;
struct server_record *servrec; struct work_record *work;
struct server_record *servrec;
if(!work) pull_ascii_nstring(regname, registered_name->name);
{ work = find_workgroup_on_subnet( subrec, regname);
DEBUG(0,("become_domain_master_stage2: Error - cannot find \
workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
return;
}
if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) if(!work) {
{ DEBUG(0,("become_domain_master_stage2: Error - cannot find \
DEBUG(0,("become_domain_master_stage2: Error - cannot find server %s \ workgroup %s on subnet %s\n", regname, subrec->subnet_name));
return;
}
if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
DEBUG(0,("become_domain_master_stage2: Error - cannot find server %s \
in workgroup %s on subnet %s\n", in workgroup %s on subnet %s\n",
global_myname(), registered_name->name, subrec->subnet_name)); global_myname(), regname, subrec->subnet_name));
work->dom_state = DOMAIN_NONE; work->dom_state = DOMAIN_NONE;
return; return;
} }
/* Set the state in the workgroup structure. */ /* Set the state in the workgroup structure. */
work->dom_state = DOMAIN_MST; /* Become domain master. */ work->dom_state = DOMAIN_MST; /* Become domain master. */
/* Update our server status. */ /* Update our server status. */
servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER); servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
/* Tell the namelist writer to write out a change. */ /* Tell the namelist writer to write out a change. */
subrec->work_changed = True; subrec->work_changed = True;
if( DEBUGLVL( 0 ) ) if( DEBUGLVL( 0 ) ) {
{ dbgtext( "*****\n\nSamba server %s ", global_myname() );
dbgtext( "*****\n\nSamba server %s ", global_myname() ); dbgtext( "is now a domain master browser for " );
dbgtext( "is now a domain master browser for " ); dbgtext( "workgroup %s ", work->work_group );
dbgtext( "workgroup %s ", work->work_group ); dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name ); }
}
if( subrec == unicast_subnet ) if( subrec == unicast_subnet ) {
{ struct nmb_name nmbname;
struct nmb_name nmbname; struct in_addr my_first_ip;
struct in_addr my_first_ip;
/* Put our name and first IP address into the /* Put our name and first IP address into the
workgroup struct as domain master browser. This workgroup struct as domain master browser. This
will stop us syncing with ourself if we are also will stop us syncing with ourself if we are also
a local master browser. */ a local master browser. */
make_nmb_name(&nmbname, global_myname(), 0x20); make_nmb_name(&nmbname, global_myname(), 0x20);
work->dmb_name = nmbname; work->dmb_name = nmbname;
/* Pick the first interface ip address as the domain master browser ip. */ /* Pick the first interface ip address as the domain master browser ip. */
my_first_ip = *iface_n_ip(0); my_first_ip = *iface_n_ip(0);
putip((char *)&work->dmb_addr, &my_first_ip); putip((char *)&work->dmb_addr, &my_first_ip);
/* We successfully registered by unicast with the /* We successfully registered by unicast with the
WINS server. We now expect to become the domain WINS server. We now expect to become the domain
master on the local subnets. If this fails, it's master on the local subnets. If this fails, it's
probably a 1.9.16p2 to 1.9.16p11 server's fault. probably a 1.9.16p2 to 1.9.16p11 server's fault.
This is a configuration issue that should be addressed This is a configuration issue that should be addressed
by the network administrator - you shouldn't have by the network administrator - you shouldn't have
several machines configured as a domain master browser several machines configured as a domain master browser
for the same WINS scope (except if they are 1.9.17 or for the same WINS scope (except if they are 1.9.17 or
greater, and you know what you're doing. greater, and you know what you're doing.
see docs/DOMAIN.txt. see docs/DOMAIN.txt.
*/ */
become_domain_master_browser_bcast(work->work_group); become_domain_master_browser_bcast(work->work_group);
} } else {
else /*
{ * Now we are a domain master on a broadcast subnet, we need to add
/* * the WORKGROUP<1b> name to the unicast subnet so that we can answer
* Now we are a domain master on a broadcast subnet, we need to add * unicast requests sent to this name. This bug wasn't found for a while
* the WORKGROUP<1b> name to the unicast subnet so that we can answer * as it is strange to have a DMB without using WINS. JRA.
* unicast requests sent to this name. This bug wasn't found for a while */
* as it is strange to have a DMB without using WINS. JRA. insert_permanent_name_into_unicast(subrec, registered_name, nb_flags);
*/ }
insert_permanent_name_into_unicast(subrec, registered_name, nb_flags);
}
} }
/**************************************************************************** /****************************************************************************
Start the name registration process when becoming a Domain Master Browser Start the name registration process when becoming a Domain Master Browser
on a subnet. on a subnet.
****************************************************************************/ ****************************************************************************/
static void become_domain_master_stage1(struct subnet_record *subrec, char *wg_name) static void become_domain_master_stage1(struct subnet_record *subrec, const char *wg_name)
{ {
struct work_record *work; struct work_record *work;
DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \ DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \
workgroup %s on subnet %s\n", wg_name, subrec->subnet_name)); workgroup %s on subnet %s\n", wg_name, subrec->subnet_name));
/* First, find the workgroup on the subnet. */ /* First, find the workgroup on the subnet. */
if((work = find_workgroup_on_subnet( subrec, wg_name )) == NULL) if((work = find_workgroup_on_subnet( subrec, wg_name )) == NULL) {
{ DEBUG(0,("become_domain_master_stage1: Error - unable to find workgroup %s on subnet %s.\n",
DEBUG(0,("become_domain_master_stage1: Error - unable to find workgroup %s on subnet %s.\n", wg_name, subrec->subnet_name));
wg_name, subrec->subnet_name)); return;
return; }
}
DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n")); DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
work->dom_state = DOMAIN_WAIT; work->dom_state = DOMAIN_WAIT;
/* WORKGROUP<1b> is the domain master browser name. */ /* WORKGROUP<1b> is the domain master browser name. */
register_name(subrec, work->work_group,0x1b,samba_nb_type, register_name(subrec, work->work_group,0x1b,samba_nb_type,
become_domain_master_stage2, become_domain_master_stage2,
become_domain_master_fail, NULL); become_domain_master_fail, NULL);
} }
/**************************************************************************** /****************************************************************************
@@ -202,37 +200,35 @@ static void become_domain_master_query_success(struct subnet_record *subrec,
struct nmb_name *nmbname, struct in_addr ip, struct nmb_name *nmbname, struct in_addr ip,
struct res_rec *rrec) struct res_rec *rrec)
{ {
/* If the given ip is not ours, then we can't become a domain nstring name;
controler as the name is already registered. pull_ascii_nstring(name, nmbname->name);
*/
/* BUG note. Samba 1.9.16p11 servers seem to return the broadcast /* If the given ip is not ours, then we can't become a domain
address or zero ip for this query. Pretend this is ok. */ controler as the name is already registered.
*/
if(ismyip(ip) || ip_equal(allones_ip, ip) || is_zero_ip(ip)) /* BUG note. Samba 1.9.16p11 servers seem to return the broadcast
{ address or zero ip for this query. Pretend this is ok. */
if( DEBUGLVL( 3 ) )
{
dbgtext( "become_domain_master_query_success():\n" );
dbgtext( "Our address (%s) ", inet_ntoa(ip) );
dbgtext( "returned in query for name %s ", nmb_namestr(nmbname) );
dbgtext( "(domain master browser name) " );
dbgtext( "on subnet %s.\n", subrec->subnet_name );
dbgtext( "Continuing with domain master code.\n" );
}
become_domain_master_stage1(subrec, nmbname->name); if(ismyip(ip) || ip_equal(allones_ip, ip) || is_zero_ip(ip)) {
} if( DEBUGLVL( 3 ) ) {
else dbgtext( "become_domain_master_query_success():\n" );
{ dbgtext( "Our address (%s) ", inet_ntoa(ip) );
if( DEBUGLVL( 0 ) ) dbgtext( "returned in query for name %s ", nmb_namestr(nmbname) );
{ dbgtext( "(domain master browser name) " );
dbgtext( "become_domain_master_query_success:\n" ); dbgtext( "on subnet %s.\n", subrec->subnet_name );
dbgtext( "There is already a domain master browser at " ); dbgtext( "Continuing with domain master code.\n" );
dbgtext( "IP %s for workgroup %s ", inet_ntoa(ip), nmbname->name ); }
dbgtext( "registered on subnet %s.\n", subrec->subnet_name );
} become_domain_master_stage1(subrec, name);
} } else {
if( DEBUGLVL( 0 ) ) {
dbgtext( "become_domain_master_query_success:\n" );
dbgtext( "There is already a domain master browser at " );
dbgtext( "IP %s for workgroup %s ", inet_ntoa(ip), name );
dbgtext( "registered on subnet %s.\n", subrec->subnet_name );
}
}
} }
/**************************************************************************** /****************************************************************************
@@ -245,18 +241,21 @@ static void become_domain_master_query_fail(struct subnet_record *subrec,
struct response_record *rrec, struct response_record *rrec,
struct nmb_name *question_name, int fail_code) struct nmb_name *question_name, int fail_code)
{ {
/* If the query was unicast, and the error is not NAM_ERR (name didn't exist), nstring name;
then this is a failure. Otherwise, not finding the name is what we want. */
if((subrec == unicast_subnet) && (fail_code != NAM_ERR))
{
DEBUG(0,("become_domain_master_query_fail: Error %d returned when \
querying WINS server for name %s.\n",
fail_code, nmb_namestr(question_name)));
return;
}
/* Otherwise - not having the name allows us to register it. */ /* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
become_domain_master_stage1(subrec, question_name->name); then this is a failure. Otherwise, not finding the name is what we want. */
if((subrec == unicast_subnet) && (fail_code != NAM_ERR)) {
DEBUG(0,("become_domain_master_query_fail: Error %d returned when \
querying WINS server for name %s.\n",
fail_code, nmb_namestr(question_name)));
return;
}
/* Otherwise - not having the name allows us to register it. */
pull_ascii_nstring(name, question_name->name);
become_domain_master_stage1(subrec, name);
} }
/**************************************************************************** /****************************************************************************
@@ -265,47 +264,43 @@ querying WINS server for name %s.\n",
static void become_domain_master_browser_bcast(const char *workgroup_name) static void become_domain_master_browser_bcast(const char *workgroup_name)
{ {
struct subnet_record *subrec; struct subnet_record *subrec;
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
{ struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
if (work && (work->dom_state == DOMAIN_NONE)) if (work && (work->dom_state == DOMAIN_NONE)) {
{ struct nmb_name nmbname;
struct nmb_name nmbname; make_nmb_name(&nmbname,workgroup_name,0x1b);
make_nmb_name(&nmbname,workgroup_name,0x1b);
/* /*
* Check for our name on the given broadcast subnet first, only initiate * Check for our name on the given broadcast subnet first, only initiate
* further processing if we cannot find it. * further processing if we cannot find it.
*/ */
if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL) if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL) {
{ if( DEBUGLVL( 0 ) ) {
if( DEBUGLVL( 0 ) ) dbgtext( "become_domain_master_browser_bcast:\n" );
{ dbgtext( "Attempting to become domain master browser on " );
dbgtext( "become_domain_master_browser_bcast:\n" ); dbgtext( "workgroup %s on subnet %s\n",
dbgtext( "Attempting to become domain master browser on " ); workgroup_name, subrec->subnet_name );
dbgtext( "workgroup %s on subnet %s\n", }
workgroup_name, subrec->subnet_name );
}
/* Send out a query to establish whether there's a /* Send out a query to establish whether there's a
domain controller on the local subnet. If not, domain controller on the local subnet. If not,
we can become a domain controller. we can become a domain controller.
*/ */
DEBUG(0,("become_domain_master_browser_bcast: querying subnet %s \ DEBUG(0,("become_domain_master_browser_bcast: querying subnet %s \
for domain master browser on workgroup %s\n", subrec->subnet_name, workgroup_name)); for domain master browser on workgroup %s\n", subrec->subnet_name, workgroup_name));
query_name(subrec, nmbname.name, nmbname.name_type, query_name(subrec, workgroup_name, nmbname.name_type,
become_domain_master_query_success, become_domain_master_query_success,
become_domain_master_query_fail, become_domain_master_query_fail,
NULL); NULL);
} }
} }
} }
} }
/**************************************************************************** /****************************************************************************
@@ -314,46 +309,43 @@ for domain master browser on workgroup %s\n", subrec->subnet_name, workgroup_nam
static void become_domain_master_browser_wins(const char *workgroup_name) static void become_domain_master_browser_wins(const char *workgroup_name)
{ {
struct work_record *work; struct work_record *work;
work = find_workgroup_on_subnet(unicast_subnet, workgroup_name); work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
if (work && (work->dom_state == DOMAIN_NONE)) if (work && (work->dom_state == DOMAIN_NONE)) {
{ struct nmb_name nmbname;
struct nmb_name nmbname;
make_nmb_name(&nmbname,workgroup_name,0x1b); make_nmb_name(&nmbname,workgroup_name,0x1b);
/* /*
* Check for our name on the unicast subnet first, only initiate * Check for our name on the unicast subnet first, only initiate
* further processing if we cannot find it. * further processing if we cannot find it.
*/ */
if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL) if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL) {
{ if( DEBUGLVL( 0 ) ) {
if( DEBUGLVL( 0 ) ) dbgtext( "become_domain_master_browser_wins:\n" );
{ dbgtext( "Attempting to become domain master browser " );
dbgtext( "become_domain_master_browser_wins:\n" ); dbgtext( "on workgroup %s, subnet %s.\n",
dbgtext( "Attempting to become domain master browser " ); workgroup_name, unicast_subnet->subnet_name );
dbgtext( "on workgroup %s, subnet %s.\n", }
workgroup_name, unicast_subnet->subnet_name );
}
/* Send out a query to establish whether there's a /* Send out a query to establish whether there's a
domain master broswer registered with WINS. If not, domain master broswer registered with WINS. If not,
we can become a domain master browser. we can become a domain master browser.
*/ */
DEBUG(0,("become_domain_master_browser_wins: querying WINS server from IP %s \ DEBUG(0,("become_domain_master_browser_wins: querying WINS server from IP %s \
for domain master browser name %s on workgroup %s\n", for domain master browser name %s on workgroup %s\n",
inet_ntoa(unicast_subnet->myip), nmb_namestr(&nmbname), workgroup_name)); inet_ntoa(unicast_subnet->myip), nmb_namestr(&nmbname), workgroup_name));
query_name(unicast_subnet, nmbname.name, nmbname.name_type, query_name(unicast_subnet, workgroup_name, nmbname.name_type,
become_domain_master_query_success, become_domain_master_query_success,
become_domain_master_query_fail, become_domain_master_query_fail,
NULL); NULL);
} }
} }
} }
/**************************************************************************** /****************************************************************************
@@ -363,34 +355,32 @@ for domain master browser name %s on workgroup %s\n",
void add_domain_names(time_t t) void add_domain_names(time_t t)
{ {
static time_t lastrun = 0; static time_t lastrun = 0;
if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60))) if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60)))
return; return;
lastrun = t; lastrun = t;
/* Do the "internet group" - <1c> names. */ /* Do the "internet group" - <1c> names. */
if (lp_domain_logons()) if (lp_domain_logons())
add_logon_names(); add_logon_names();
/* Do the domain master names. */ /* Do the domain master names. */
if(lp_domain_master()) if(lp_domain_master()) {
{ if(we_are_a_wins_client()) {
if(we_are_a_wins_client()) /* We register the WORKGROUP<1b> name with the WINS
{ server first, and call add_domain_master_bcast()
/* We register the WORKGROUP<1b> name with the WINS only if this is successful.
server first, and call add_domain_master_bcast()
only if this is successful.
This results in domain logon services being gracefully provided, This results in domain logon services being gracefully provided,
as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11. as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11.
1.9.16p2 to 1.9.16p11 - due to a bug in namelogon.c, 1.9.16p2 to 1.9.16p11 - due to a bug in namelogon.c,
cannot provide domain master / domain logon services. cannot provide domain master / domain logon services.
*/ */
become_domain_master_browser_wins(lp_workgroup()); become_domain_master_browser_wins(lp_workgroup());
} } else {
else become_domain_master_browser_bcast(lp_workgroup());
become_domain_master_browser_bcast(lp_workgroup()); }
} }
} }

View File

@@ -3,7 +3,7 @@
NBT netbios routines and daemon - version 2 NBT netbios routines and daemon - version 2
Copyright (C) Andrew Tridgell 1994-1998 Copyright (C) Andrew Tridgell 1994-1998
Copyright (C) Luke Kenneth Casson Leighton 1994-1998 Copyright (C) Luke Kenneth Casson Leighton 1994-1998
Copyright (C) Jeremy Allison 1994-1998 Copyright (C) Jeremy Allison 1994-2003
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -33,21 +33,20 @@ extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
void insert_permanent_name_into_unicast( struct subnet_record *subrec, void insert_permanent_name_into_unicast( struct subnet_record *subrec,
struct nmb_name *nmbname, uint16 nb_type ) struct nmb_name *nmbname, uint16 nb_type )
{ {
struct name_record *namerec; nstring name;
struct name_record *namerec;
if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) == NULL) if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) == NULL) {
{ pull_ascii_nstring(name, nmbname->name);
/* The name needs to be created on the unicast subnet. */ /* The name needs to be created on the unicast subnet. */
(void)add_name_to_subnet( unicast_subnet, nmbname->name, (void)add_name_to_subnet( unicast_subnet, name,
nmbname->name_type, nb_type, nmbname->name_type, nb_type,
PERMANENT_TTL, PERMANENT_NAME, 1, &subrec->myip); PERMANENT_TTL, PERMANENT_NAME, 1, &subrec->myip);
} } else {
else /* The name already exists on the unicast subnet. Add our local
{ IP for the given broadcast subnet to the name. */
/* The name already exists on the unicast subnet. Add our local add_ip_to_name_record( namerec, subrec->myip);
IP for the given broadcast subnet to the name. */ }
add_ip_to_name_record( namerec, subrec->myip);
}
} }
/******************************************************************* /*******************************************************************
@@ -57,15 +56,14 @@ void insert_permanent_name_into_unicast( struct subnet_record *subrec,
static void remove_permanent_name_from_unicast( struct subnet_record *subrec, static void remove_permanent_name_from_unicast( struct subnet_record *subrec,
struct nmb_name *nmbname ) struct nmb_name *nmbname )
{ {
struct name_record *namerec; struct name_record *namerec;
if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) != NULL) if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) != NULL) {
{ /* Remove this broadcast subnet IP address from the name. */
/* Remove this broadcast subnet IP address from the name. */ remove_ip_from_name_record( namerec, subrec->myip);
remove_ip_from_name_record( namerec, subrec->myip); if(namerec->data.num_ips == 0)
if(namerec->data.num_ips == 0) remove_name_from_namelist( unicast_subnet, namerec);
remove_name_from_namelist( unicast_subnet, namerec); }
}
} }
/******************************************************************* /*******************************************************************
@@ -73,60 +71,58 @@ static void remove_permanent_name_from_unicast( struct subnet_record *subrec,
state back to potential browser, or none. state back to potential browser, or none.
******************************************************************/ ******************************************************************/
static void reset_workgroup_state( struct subnet_record *subrec, char *workgroup_name, static void reset_workgroup_state( struct subnet_record *subrec, const char *workgroup_name,
BOOL force_new_election ) BOOL force_new_election )
{ {
struct work_record *work; struct work_record *work;
struct server_record *servrec; struct server_record *servrec;
struct nmb_name nmbname; struct nmb_name nmbname;
if((work = find_workgroup_on_subnet( subrec, workgroup_name)) == NULL) if((work = find_workgroup_on_subnet( subrec, workgroup_name)) == NULL) {
{ DEBUG(0,("reset_workgroup_state: Error - cannot find workgroup %s on \
DEBUG(0,("reset_workgroup_state: Error - cannot find workgroup %s on \
subnet %s.\n", workgroup_name, subrec->subnet_name )); subnet %s.\n", workgroup_name, subrec->subnet_name ));
return; return;
} }
if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
{ DEBUG(0,("reset_workgroup_state: Error - cannot find server %s \
DEBUG(0,("reset_workgroup_state: Error - cannot find server %s \
in workgroup %s on subnet %s\n", in workgroup %s on subnet %s\n",
global_myname(), work->work_group, subrec->subnet_name)); global_myname(), work->work_group, subrec->subnet_name));
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE; work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
return; return;
} }
/* Update our server status - remove any master flag and replace /* Update our server status - remove any master flag and replace
it with the potential browser flag. */ it with the potential browser flag. */
servrec->serv.type &= ~SV_TYPE_MASTER_BROWSER; servrec->serv.type &= ~SV_TYPE_MASTER_BROWSER;
servrec->serv.type |= (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0); servrec->serv.type |= (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0);
/* Tell the namelist writer to write out a change. */ /* Tell the namelist writer to write out a change. */
subrec->work_changed = True; subrec->work_changed = True;
/* Reset our election flags. */ /* Reset our election flags. */
work->ElectionCriterion &= ~0x4; work->ElectionCriterion &= ~0x4;
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE; work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
/* Forget who the local master browser was for /* Forget who the local master browser was for
this workgroup. */ this workgroup. */
set_workgroup_local_master_browser_name( work, ""); set_workgroup_local_master_browser_name( work, "");
/* /*
* Ensure the IP address of this subnet is not registered as one * Ensure the IP address of this subnet is not registered as one
* of the IP addresses of the WORKGROUP<1d> name on the unicast * of the IP addresses of the WORKGROUP<1d> name on the unicast
* subnet. This undoes what we did below when we became a local * subnet. This undoes what we did below when we became a local
* master browser. * master browser.
*/ */
make_nmb_name(&nmbname, work->work_group, 0x1d); make_nmb_name(&nmbname, work->work_group, 0x1d);
remove_permanent_name_from_unicast( subrec, &nmbname); remove_permanent_name_from_unicast( subrec, &nmbname);
if(force_new_election) if(force_new_election)
work->needelection = True; work->needelection = True;
} }
/******************************************************************* /*******************************************************************
@@ -138,24 +134,25 @@ static void unbecome_local_master_success(struct subnet_record *subrec,
struct nmb_name *released_name, struct nmb_name *released_name,
struct in_addr released_ip) struct in_addr released_ip)
{ {
BOOL force_new_election = False; BOOL force_new_election = False;
nstring relname;
memcpy((char *)&force_new_election, userdata->data, sizeof(BOOL)); memcpy((char *)&force_new_election, userdata->data, sizeof(BOOL));
DEBUG(3,("unbecome_local_master_success: released name %s.\n", DEBUG(3,("unbecome_local_master_success: released name %s.\n",
nmb_namestr(released_name))); nmb_namestr(released_name)));
/* Now reset the workgroup and server state. */ /* Now reset the workgroup and server state. */
reset_workgroup_state( subrec, released_name->name, force_new_election ); pull_ascii_nstring(relname, released_name->name);
reset_workgroup_state( subrec, relname, force_new_election );
if( DEBUGLVL( 0 ) ) if( DEBUGLVL( 0 ) ) {
{ dbgtext( "*****\n\n" );
dbgtext( "*****\n\n" ); dbgtext( "Samba name server %s ", global_myname() );
dbgtext( "Samba name server %s ", global_myname() ); dbgtext( "has stopped being a local master browser " );
dbgtext( "has stopped being a local master browser " ); dbgtext( "for workgroup %s ", relname );
dbgtext( "for workgroup %s ", released_name->name ); dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name ); }
}
} }
@@ -166,67 +163,66 @@ static void unbecome_local_master_success(struct subnet_record *subrec,
static void unbecome_local_master_fail(struct subnet_record *subrec, struct response_record *rrec, static void unbecome_local_master_fail(struct subnet_record *subrec, struct response_record *rrec,
struct nmb_name *fail_name) struct nmb_name *fail_name)
{ {
struct name_record *namerec; struct name_record *namerec;
struct userdata_struct *userdata = rrec->userdata; struct userdata_struct *userdata = rrec->userdata;
BOOL force_new_election = False; BOOL force_new_election = False;
nstring failname;
memcpy((char *)&force_new_election, userdata->data, sizeof(BOOL)); memcpy((char *)&force_new_election, userdata->data, sizeof(BOOL));
DEBUG(0,("unbecome_local_master_fail: failed to release name %s. \ DEBUG(0,("unbecome_local_master_fail: failed to release name %s. \
Removing from namelist anyway.\n", nmb_namestr(fail_name))); Removing from namelist anyway.\n", nmb_namestr(fail_name)));
/* Do it anyway. */ /* Do it anyway. */
namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME); namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
if(namerec) if(namerec)
remove_name_from_namelist(subrec, namerec); remove_name_from_namelist(subrec, namerec);
/* Now reset the workgroup and server state. */ /* Now reset the workgroup and server state. */
reset_workgroup_state( subrec, fail_name->name, force_new_election ); pull_ascii_nstring(failname, fail_name->name);
reset_workgroup_state( subrec, failname, force_new_election );
if( DEBUGLVL( 0 ) ) if( DEBUGLVL( 0 ) ) {
{ dbgtext( "*****\n\n" );
dbgtext( "*****\n\n" ); dbgtext( "Samba name server %s ", global_myname() );
dbgtext( "Samba name server %s ", global_myname() ); dbgtext( "has stopped being a local master browser " );
dbgtext( "has stopped being a local master browser " ); dbgtext( "for workgroup %s ", failname );
dbgtext( "for workgroup %s ", fail_name->name ); dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name ); }
}
} }
/******************************************************************* /*******************************************************************
Utility function to remove the WORKGROUP<1d> name. Utility function to remove the WORKGROUP<1d> name.
******************************************************************/ ******************************************************************/
static void release_1d_name( struct subnet_record *subrec, char *workgroup_name, static void release_1d_name( struct subnet_record *subrec, const char *workgroup_name,
BOOL force_new_election) BOOL force_new_election)
{ {
struct nmb_name nmbname; struct nmb_name nmbname;
struct name_record *namerec; struct name_record *namerec;
make_nmb_name(&nmbname, workgroup_name, 0x1d); make_nmb_name(&nmbname, workgroup_name, 0x1d);
if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL) if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL) {
{ struct userdata_struct *userdata;
struct userdata_struct *userdata; size_t size = sizeof(struct userdata_struct) + sizeof(BOOL);
size_t size = sizeof(struct userdata_struct) + sizeof(BOOL);
if((userdata = (struct userdata_struct *)malloc(size)) == NULL) if((userdata = (struct userdata_struct *)malloc(size)) == NULL) {
{ DEBUG(0,("release_1d_name: malloc fail.\n"));
DEBUG(0,("release_1d_name: malloc fail.\n")); return;
return; }
}
userdata->copy_fn = NULL; userdata->copy_fn = NULL;
userdata->free_fn = NULL; userdata->free_fn = NULL;
userdata->userdata_len = sizeof(BOOL); userdata->userdata_len = sizeof(BOOL);
memcpy((char *)userdata->data, &force_new_election, sizeof(BOOL)); memcpy((char *)userdata->data, &force_new_election, sizeof(BOOL));
release_name(subrec, namerec, release_name(subrec, namerec,
unbecome_local_master_success, unbecome_local_master_success,
unbecome_local_master_fail, unbecome_local_master_fail,
userdata); userdata);
zero_free(userdata, size); zero_free(userdata, size);
} }
} }
/******************************************************************* /*******************************************************************
@@ -238,11 +234,11 @@ static void release_msbrowse_name_success(struct subnet_record *subrec,
struct nmb_name *released_name, struct nmb_name *released_name,
struct in_addr released_ip) struct in_addr released_ip)
{ {
DEBUG(4,("release_msbrowse_name_success: Released name %s on subnet %s\n.", DEBUG(4,("release_msbrowse_name_success: Released name %s on subnet %s\n.",
nmb_namestr(released_name), subrec->subnet_name )); nmb_namestr(released_name), subrec->subnet_name ));
/* Remove the permanent MSBROWSE name added into the unicast subnet. */ /* Remove the permanent MSBROWSE name added into the unicast subnet. */
remove_permanent_name_from_unicast( subrec, released_name); remove_permanent_name_from_unicast( subrec, released_name);
} }
/******************************************************************* /*******************************************************************
@@ -253,18 +249,18 @@ static void release_msbrowse_name_fail( struct subnet_record *subrec,
struct response_record *rrec, struct response_record *rrec,
struct nmb_name *fail_name) struct nmb_name *fail_name)
{ {
struct name_record *namerec; struct name_record *namerec;
DEBUG(4,("release_msbrowse_name_fail: Failed to release name %s on subnet %s\n.", DEBUG(4,("release_msbrowse_name_fail: Failed to release name %s on subnet %s\n.",
nmb_namestr(fail_name), subrec->subnet_name )); nmb_namestr(fail_name), subrec->subnet_name ));
/* Release the name anyway. */ /* Release the name anyway. */
namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME); namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
if(namerec) if(namerec)
remove_name_from_namelist(subrec, namerec); remove_name_from_namelist(subrec, namerec);
/* Remove the permanent MSBROWSE name added into the unicast subnet. */ /* Remove the permanent MSBROWSE name added into the unicast subnet. */
remove_permanent_name_from_unicast( subrec, fail_name); remove_permanent_name_from_unicast( subrec, fail_name);
} }
/******************************************************************* /*******************************************************************
@@ -275,50 +271,48 @@ static void release_msbrowse_name_fail( struct subnet_record *subrec,
void unbecome_local_master_browser(struct subnet_record *subrec, struct work_record *work, void unbecome_local_master_browser(struct subnet_record *subrec, struct work_record *work,
BOOL force_new_election) BOOL force_new_election)
{ {
struct name_record *namerec; struct name_record *namerec;
struct nmb_name nmbname; struct nmb_name nmbname;
/* Sanity check. */ /* Sanity check. */
DEBUG(2,("unbecome_local_master_browser: unbecoming local master for workgroup %s \ DEBUG(2,("unbecome_local_master_browser: unbecoming local master for workgroup %s \
on subnet %s\n",work->work_group, subrec->subnet_name)); on subnet %s\n",work->work_group, subrec->subnet_name));
if(find_server_in_workgroup( work, global_myname()) == NULL) if(find_server_in_workgroup( work, global_myname()) == NULL) {
{ DEBUG(0,("unbecome_local_master_browser: Error - cannot find server %s \
DEBUG(0,("unbecome_local_master_browser: Error - cannot find server %s \
in workgroup %s on subnet %s\n", in workgroup %s on subnet %s\n",
global_myname(), work->work_group, subrec->subnet_name)); global_myname(), work->work_group, subrec->subnet_name));
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE; work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
return; return;
} }
/* Set the state to unbecoming. */ /* Set the state to unbecoming. */
work->mst_state = MST_UNBECOMING_MASTER; work->mst_state = MST_UNBECOMING_MASTER;
/* /*
* Release the WORKGROUP<1d> name asap to allow another machine to * Release the WORKGROUP<1d> name asap to allow another machine to
* claim it. * claim it.
*/ */
release_1d_name( subrec, work->work_group, force_new_election); release_1d_name( subrec, work->work_group, force_new_election);
/* Deregister any browser names we may have. */ /* Deregister any browser names we may have. */
make_nmb_name(&nmbname, MSBROWSE, 0x1); make_nmb_name(&nmbname, MSBROWSE, 0x1);
if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL) if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL) {
{ release_name(subrec, namerec,
release_name(subrec, namerec, release_msbrowse_name_success,
release_msbrowse_name_success, release_msbrowse_name_fail,
release_msbrowse_name_fail, NULL);
NULL); }
}
/* /*
* Ensure we have sent and processed these release packets * Ensure we have sent and processed these release packets
* before returning - we don't want to process any election * before returning - we don't want to process any election
* packets before dealing with the 1d release. * packets before dealing with the 1d release.
*/ */
retransmit_or_expire_response_records(time(NULL)); retransmit_or_expire_response_records(time(NULL));
} }
/**************************************************************************** /****************************************************************************
@@ -332,104 +326,107 @@ static void become_local_master_stage2(struct subnet_record *subrec,
uint16 nb_flags, uint16 nb_flags,
int ttl, struct in_addr registered_ip) int ttl, struct in_addr registered_ip)
{ {
int i = 0; int i = 0;
struct server_record *sl; struct server_record *sl;
struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name); struct work_record *work;
struct server_record *servrec; struct server_record *servrec;
nstring regname;
if(!work) pull_ascii_nstring(regname, registered_name->name);
{ work = find_workgroup_on_subnet( subrec, regname);
DEBUG(0,("become_local_master_stage2: Error - cannot find \
workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
return;
}
if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) if(!work) {
{ DEBUG(0,("become_local_master_stage2: Error - cannot find \
DEBUG(0,("become_local_master_stage2: Error - cannot find server %s \ workgroup %s on subnet %s\n", regname, subrec->subnet_name));
return;
}
if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
DEBUG(0,("become_local_master_stage2: Error - cannot find server %s \
in workgroup %s on subnet %s\n", in workgroup %s on subnet %s\n",
global_myname(), registered_name->name, subrec->subnet_name)); global_myname(), regname, subrec->subnet_name));
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE; work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
return; return;
} }
DEBUG(3,("become_local_master_stage2: registered as master browser for workgroup %s \ DEBUG(3,("become_local_master_stage2: registered as master browser for workgroup %s \
on subnet %s\n", work->work_group, subrec->subnet_name)); on subnet %s\n", work->work_group, subrec->subnet_name));
work->mst_state = MST_BROWSER; /* registering WORKGROUP(1d) succeeded */ work->mst_state = MST_BROWSER; /* registering WORKGROUP(1d) succeeded */
/* update our server status */ /* update our server status */
servrec->serv.type |= SV_TYPE_MASTER_BROWSER; servrec->serv.type |= SV_TYPE_MASTER_BROWSER;
servrec->serv.type &= ~SV_TYPE_POTENTIAL_BROWSER; servrec->serv.type &= ~SV_TYPE_POTENTIAL_BROWSER;
/* Tell the namelist writer to write out a change. */ /* Tell the namelist writer to write out a change. */
subrec->work_changed = True; subrec->work_changed = True;
/* Add this name to the workgroup as local master browser. */ /* Add this name to the workgroup as local master browser. */
set_workgroup_local_master_browser_name( work, global_myname()); set_workgroup_local_master_browser_name( work, global_myname());
/* Count the number of servers we have on our list. If it's /* Count the number of servers we have on our list. If it's
less than 10 (just a heuristic) request the servers less than 10 (just a heuristic) request the servers
to announce themselves. to announce themselves.
*/ */
for( sl = work->serverlist; sl != NULL; sl = sl->next) for( sl = work->serverlist; sl != NULL; sl = sl->next)
i++; i++;
if (i < 10) if (i < 10) {
{ /* Ask all servers on our local net to announce to us. */
/* Ask all servers on our local net to announce to us. */ broadcast_announce_request(subrec, work);
broadcast_announce_request(subrec, work); }
}
/* /*
* Now we are a local master on a broadcast subnet, we need to add * Now we are a local master on a broadcast subnet, we need to add
* the WORKGROUP<1d> name to the unicast subnet so that we can answer * the WORKGROUP<1d> name to the unicast subnet so that we can answer
* unicast requests sent to this name. We can create this name directly on * unicast requests sent to this name. We can create this name directly on
* the unicast subnet as a WINS server always returns true when registering * the unicast subnet as a WINS server always returns true when registering
* this name, and discards the registration. We use the number of IP * this name, and discards the registration. We use the number of IP
* addresses registered to this name as a reference count, as we * addresses registered to this name as a reference count, as we
* remove this broadcast subnet IP address from it when we stop becoming a local * remove this broadcast subnet IP address from it when we stop becoming a local
* master browser for this broadcast subnet. * master browser for this broadcast subnet.
*/ */
insert_permanent_name_into_unicast( subrec, registered_name, nb_flags); insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
/* Reset the announce master browser timer so that we try and tell a domain /* Reset the announce master browser timer so that we try and tell a domain
master browser as soon as possible that we are a local master browser. */ master browser as soon as possible that we are a local master browser. */
reset_announce_timer(); reset_announce_timer();
if( DEBUGLVL( 0 ) )
{
dbgtext( "*****\n\n" );
dbgtext( "Samba name server %s ", global_myname() );
dbgtext( "is now a local master browser " );
dbgtext( "for workgroup %s ", work->work_group );
dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
}
if( DEBUGLVL( 0 ) ) {
dbgtext( "*****\n\n" );
dbgtext( "Samba name server %s ", global_myname() );
dbgtext( "is now a local master browser " );
dbgtext( "for workgroup %s ", work->work_group );
dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
}
} }
/**************************************************************************** /****************************************************************************
Failed to register the WORKGROUP<1d> name. Failed to register the WORKGROUP<1d> name.
****************************************************************************/ ****************************************************************************/
static void become_local_master_fail2(struct subnet_record *subrec, static void become_local_master_fail2(struct subnet_record *subrec,
struct response_record *rrec, struct response_record *rrec,
struct nmb_name *fail_name) struct nmb_name *fail_name)
{ {
struct work_record *work = find_workgroup_on_subnet( subrec, fail_name->name); nstring failname;
struct work_record *work;
DEBUG(0,("become_local_master_fail2: failed to register name %s on subnet %s. \ DEBUG(0,("become_local_master_fail2: failed to register name %s on subnet %s. \
Failed to become a local master browser.\n", nmb_namestr(fail_name), subrec->subnet_name)); Failed to become a local master browser.\n", nmb_namestr(fail_name), subrec->subnet_name));
if(!work) pull_ascii_nstring(failname, fail_name->name);
{ work = find_workgroup_on_subnet( subrec, failname);
DEBUG(0,("become_local_master_fail2: Error - cannot find \
workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
return;
}
/* Roll back all the way by calling unbecome_local_master_browser(). */ if(!work) {
unbecome_local_master_browser(subrec, work, False); DEBUG(0,("become_local_master_fail2: Error - cannot find \
workgroup %s on subnet %s\n", failname, subrec->subnet_name));
return;
}
/* Roll back all the way by calling unbecome_local_master_browser(). */
unbecome_local_master_browser(subrec, work, False);
} }
/**************************************************************************** /****************************************************************************
@@ -442,35 +439,34 @@ static void become_local_master_stage1(struct subnet_record *subrec,
uint16 nb_flags, uint16 nb_flags,
int ttl, struct in_addr registered_ip) int ttl, struct in_addr registered_ip)
{ {
char *work_name = userdata->data; char *work_name = userdata->data;
struct work_record *work = find_workgroup_on_subnet( subrec, work_name); struct work_record *work = find_workgroup_on_subnet( subrec, work_name);
if(!work) if(!work) {
{ DEBUG(0,("become_local_master_stage1: Error - cannot find \
DEBUG(0,("become_local_master_stage1: Error - cannot find \ %s on subnet %s\n", work_name, subrec->subnet_name));
workgroup %s on subnet %s\n", work_name, subrec->subnet_name)); return;
return; }
}
DEBUG(3,("become_local_master_stage1: go to stage 2: register the %s<1d> name.\n", DEBUG(3,("become_local_master_stage1: go to stage 2: register the %s<1d> name.\n",
work->work_group)); work->work_group));
work->mst_state = MST_MSB; /* Registering MSBROWSE was successful. */ work->mst_state = MST_MSB; /* Registering MSBROWSE was successful. */
/* /*
* We registered the MSBROWSE name on a broadcast subnet, now need to add * We registered the MSBROWSE name on a broadcast subnet, now need to add
* the MSBROWSE name to the unicast subnet so that we can answer * the MSBROWSE name to the unicast subnet so that we can answer
* unicast requests sent to this name. We create this name directly on * unicast requests sent to this name. We create this name directly on
* the unicast subnet. * the unicast subnet.
*/ */
insert_permanent_name_into_unicast( subrec, registered_name, nb_flags); insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
/* Attempt to register the WORKGROUP<1d> name. */ /* Attempt to register the WORKGROUP<1d> name. */
register_name(subrec, work->work_group,0x1d,samba_nb_type, register_name(subrec, work->work_group,0x1d,samba_nb_type,
become_local_master_stage2, become_local_master_stage2,
become_local_master_fail2, become_local_master_fail2,
NULL); NULL);
} }
/**************************************************************************** /****************************************************************************
@@ -481,29 +477,27 @@ static void become_local_master_fail1(struct subnet_record *subrec,
struct response_record *rrec, struct response_record *rrec,
struct nmb_name *fail_name) struct nmb_name *fail_name)
{ {
char *work_name = rrec->userdata->data; char *work_name = rrec->userdata->data;
struct work_record *work = find_workgroup_on_subnet(subrec, work_name); struct work_record *work = find_workgroup_on_subnet(subrec, work_name);
if(!work) if(!work) {
{ DEBUG(0,("become_local_master_fail1: Error - cannot find \
DEBUG(0,("become_local_master_fail1: Error - cannot find \
workgroup %s on subnet %s\n", work_name, subrec->subnet_name)); workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
return; return;
} }
if(find_server_in_workgroup(work, global_myname()) == NULL) if(find_server_in_workgroup(work, global_myname()) == NULL) {
{ DEBUG(0,("become_local_master_fail1: Error - cannot find server %s \
DEBUG(0,("become_local_master_fail1: Error - cannot find server %s \
in workgroup %s on subnet %s\n", in workgroup %s on subnet %s\n",
global_myname(), work->work_group, subrec->subnet_name)); global_myname(), work->work_group, subrec->subnet_name));
return; return;
} }
reset_workgroup_state( subrec, work->work_group, False ); reset_workgroup_state( subrec, work->work_group, False );
DEBUG(0,("become_local_master_fail1: Failed to become a local master browser for \ DEBUG(0,("become_local_master_fail1: Failed to become a local master browser for \
workgroup %s on subnet %s. Couldn't register name %s.\n", workgroup %s on subnet %s. Couldn't register name %s.\n",
work->work_group, subrec->subnet_name, nmb_namestr(fail_name))); work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
} }
/****************************************************************** /******************************************************************
@@ -517,61 +511,57 @@ workgroup %s on subnet %s. Couldn't register name %s.\n",
void become_local_master_browser(struct subnet_record *subrec, struct work_record *work) void become_local_master_browser(struct subnet_record *subrec, struct work_record *work)
{ {
struct userdata_struct *userdata; struct userdata_struct *userdata;
size_t size = sizeof(struct userdata_struct) + sizeof(fstring) + 1; size_t size = sizeof(struct userdata_struct) + sizeof(fstring) + 1;
/* Sanity check. */ /* Sanity check. */
if (!lp_local_master()) if (!lp_local_master()) {
{ DEBUG(0,("become_local_master_browser: Samba not configured as a local master browser.\n"));
DEBUG(0,("become_local_master_browser: Samba not configured as a local master browser.\n")); return;
return; }
}
if(!AM_POTENTIAL_MASTER_BROWSER(work)) if(!AM_POTENTIAL_MASTER_BROWSER(work)) {
{ DEBUG(2,("become_local_master_browser: Awaiting potential browser state. Current state is %d\n",
DEBUG(2,("become_local_master_browser: Awaiting potential browser state. Current state is %d\n", work->mst_state ));
work->mst_state )); return;
return; }
}
if(find_server_in_workgroup( work, global_myname()) == NULL) if(find_server_in_workgroup( work, global_myname()) == NULL) {
{ DEBUG(0,("become_local_master_browser: Error - cannot find server %s \
DEBUG(0,("become_local_master_browser: Error - cannot find server %s \
in workgroup %s on subnet %s\n", in workgroup %s on subnet %s\n",
global_myname(), work->work_group, subrec->subnet_name)); global_myname(), work->work_group, subrec->subnet_name));
return; return;
} }
DEBUG(2,("become_local_master_browser: Starting to become a master browser for workgroup \ DEBUG(2,("become_local_master_browser: Starting to become a master browser for workgroup \
%s on subnet %s\n", work->work_group, subrec->subnet_name)); %s on subnet %s\n", work->work_group, subrec->subnet_name));
DEBUG(3,("become_local_master_browser: first stage - attempt to register ^1^2__MSBROWSE__^2^1\n")); DEBUG(3,("become_local_master_browser: first stage - attempt to register ^1^2__MSBROWSE__^2^1\n"));
work->mst_state = MST_BACKUP; /* an election win was successful */ work->mst_state = MST_BACKUP; /* an election win was successful */
work->ElectionCriterion |= 0x5; work->ElectionCriterion |= 0x5;
/* Tell the namelist writer to write out a change. */ /* Tell the namelist writer to write out a change. */
subrec->work_changed = True; subrec->work_changed = True;
/* Setup the userdata_struct. */ /* Setup the userdata_struct. */
if((userdata = (struct userdata_struct *)malloc(size)) == NULL) if((userdata = (struct userdata_struct *)malloc(size)) == NULL) {
{ DEBUG(0,("become_local_master_browser: malloc fail.\n"));
DEBUG(0,("become_local_master_browser: malloc fail.\n")); return;
return; }
}
userdata->copy_fn = NULL; userdata->copy_fn = NULL;
userdata->free_fn = NULL; userdata->free_fn = NULL;
userdata->userdata_len = strlen(work->work_group)+1; userdata->userdata_len = strlen(work->work_group)+1;
overmalloc_safe_strcpy(userdata->data, work->work_group, size - sizeof(*userdata) - 1); overmalloc_safe_strcpy(userdata->data, work->work_group, size - sizeof(*userdata) - 1);
/* Register the special browser group name. */ /* Register the special browser group name. */
register_name(subrec, MSBROWSE, 0x01, samba_nb_type|NB_GROUP, register_name(subrec, MSBROWSE, 0x01, samba_nb_type|NB_GROUP,
become_local_master_stage1, become_local_master_stage1,
become_local_master_fail1, become_local_master_fail1,
userdata); userdata);
zero_free(userdata, size); zero_free(userdata, size);
} }
/*************************************************************** /***************************************************************
@@ -583,7 +573,7 @@ in workgroup %s on subnet %s\n",
void set_workgroup_local_master_browser_name( struct work_record *work, const char *newname) void set_workgroup_local_master_browser_name( struct work_record *work, const char *newname)
{ {
DEBUG(5,("set_workgroup_local_master_browser_name: setting local master name to '%s' \ DEBUG(5,("set_workgroup_local_master_browser_name: setting local master name to '%s' \
for workgroup %s.\n", newname, work->work_group )); for workgroup %s.\n", newname, work->work_group ));
#if 0 #if 0
@@ -600,5 +590,5 @@ local_master_browser_name for workgroup %s to workgroup name.\n",
} }
#endif #endif
fstrcpy(work->local_master_browser_name, newname); fstrcpy(work->local_master_browser_name, newname);
} }

View File

@@ -80,8 +80,8 @@ void update_browser_death_time( struct browse_cache_record *browc )
* *
* ************************************************************************** ** * ************************************************************************** **
*/ */
struct browse_cache_record *create_browser_in_lmb_cache( char *work_name, struct browse_cache_record *create_browser_in_lmb_cache( const char *work_name,
char *browser_name, const char *browser_name,
struct in_addr ip ) struct in_addr ip )
{ {
struct browse_cache_record *browc; struct browse_cache_record *browc;
@@ -134,7 +134,7 @@ struct browse_cache_record *create_browser_in_lmb_cache( char *work_name,
* *
* ************************************************************************** ** * ************************************************************************** **
*/ */
struct browse_cache_record *find_browser_in_lmb_cache( char *browser_name ) struct browse_cache_record *find_browser_in_lmb_cache( const char *browser_name )
{ {
struct browse_cache_record *browc; struct browse_cache_record *browc;

View File

@@ -3,7 +3,7 @@
NBT netbios routines and daemon - version 2 NBT netbios routines and daemon - version 2
Copyright (C) Andrew Tridgell 1994-1998 Copyright (C) Andrew Tridgell 1994-1998
Copyright (C) Luke Kenneth Casson Leighton 1994-1998 Copyright (C) Luke Kenneth Casson Leighton 1994-1998
Copyright (C) Jeremy Allison 1994-1998 Copyright (C) Jeremy Allison 1994-2003
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -29,74 +29,70 @@ extern ubi_dlList lmb_browserlist[];
/**************************************************************************** /****************************************************************************
As a domain master browser, do a sync with a local master browser. As a domain master browser, do a sync with a local master browser.
**************************************************************************/ **************************************************************************/
static void sync_with_lmb(struct browse_cache_record *browc) static void sync_with_lmb(struct browse_cache_record *browc)
{ {
struct work_record *work; struct work_record *work;
if( !(work = find_workgroup_on_subnet(unicast_subnet, browc->work_group)) ) if( !(work = find_workgroup_on_subnet(unicast_subnet, browc->work_group)) ) {
{ if( DEBUGLVL( 0 ) ) {
if( DEBUGLVL( 0 ) ) dbgtext( "sync_with_lmb:\n" );
{ dbgtext( "Failed to get a workgroup for a local master browser " );
dbgtext( "sync_with_lmb:\n" ); dbgtext( "cache entry workgroup " );
dbgtext( "Failed to get a workgroup for a local master browser " ); dbgtext( "%s, server %s\n", browc->work_group, browc->lmb_name );
dbgtext( "cache entry workgroup " ); }
dbgtext( "%s, server %s\n", browc->work_group, browc->lmb_name ); return;
} }
return;
}
/* We should only be doing this if we are a domain master browser for /* We should only be doing this if we are a domain master browser for
the given workgroup. Ensure this is so. */ the given workgroup. Ensure this is so. */
if(!AM_DOMAIN_MASTER_BROWSER(work)) if(!AM_DOMAIN_MASTER_BROWSER(work)) {
{ if( DEBUGLVL( 0 ) ) {
if( DEBUGLVL( 0 ) ) dbgtext( "sync_with_lmb:\n" );
{ dbgtext( "We are trying to sync with a local master browser " );
dbgtext( "sync_with_lmb:\n" ); dbgtext( "%s for workgroup %s\n", browc->lmb_name, browc->work_group );
dbgtext( "We are trying to sync with a local master browser " ); dbgtext( "and we are not a domain master browser on this workgroup.\n" );
dbgtext( "%s for workgroup %s\n", browc->lmb_name, browc->work_group ); dbgtext( "Error!\n" );
dbgtext( "and we are not a domain master browser on this workgroup.\n" ); }
dbgtext( "Error!\n" ); return;
} }
return;
}
if( DEBUGLVL( 2 ) ) if( DEBUGLVL( 2 ) ) {
{ dbgtext( "sync_with_lmb:\n" );
dbgtext( "sync_with_lmb:\n" ); dbgtext( "Initiating sync with local master browser " );
dbgtext( "Initiating sync with local master browser " ); dbgtext( "%s<0x20> at IP %s ", browc->lmb_name, inet_ntoa(browc->ip) );
dbgtext( "%s<0x20> at IP %s ", browc->lmb_name, inet_ntoa(browc->ip) ); dbgtext( "for workgroup %s\n", browc->work_group );
dbgtext( "for workgroup %s\n", browc->work_group ); }
}
sync_browse_lists(work, browc->lmb_name, 0x20, browc->ip, True, True); sync_browse_lists(work, browc->lmb_name, 0x20, browc->ip, True, True);
browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60); browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60);
} }
/**************************************************************************** /****************************************************************************
Sync or expire any local master browsers. Sync or expire any local master browsers.
**************************************************************************/ **************************************************************************/
void dmb_expire_and_sync_browser_lists(time_t t) void dmb_expire_and_sync_browser_lists(time_t t)
{ {
static time_t last_run = 0; static time_t last_run = 0;
struct browse_cache_record *browc; struct browse_cache_record *browc;
/* Only do this every 20 seconds. */ /* Only do this every 20 seconds. */
if (t - last_run < 20) if (t - last_run < 20)
return; return;
last_run = t; last_run = t;
expire_lmb_browsers(t); expire_lmb_browsers(t);
for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist ); for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist );
browc; browc;
browc = (struct browse_cache_record *)ubi_dlNext( browc ) ) browc = (struct browse_cache_record *)ubi_dlNext( browc ) ) {
{ if (browc->sync_time < t)
if (browc->sync_time < t) sync_with_lmb(browc);
sync_with_lmb(browc); }
}
} }
/**************************************************************************** /****************************************************************************
@@ -105,46 +101,43 @@ As a local master browser, send an announce packet to the domain master browser.
static void announce_local_master_browser_to_domain_master_browser( struct work_record *work) static void announce_local_master_browser_to_domain_master_browser( struct work_record *work)
{ {
pstring outbuf; pstring outbuf;
fstring myname; fstring myname;
char *p; char *p;
if(ismyip(work->dmb_addr)) if(ismyip(work->dmb_addr)) {
{ if( DEBUGLVL( 2 ) ) {
if( DEBUGLVL( 2 ) ) dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
{ dbgtext( "We are both a domain and a local master browser for " );
dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" ); dbgtext( "workgroup %s. ", work->work_group );
dbgtext( "We are both a domain and a local master browser for " ); dbgtext( "Do not announce to ourselves.\n" );
dbgtext( "workgroup %s. ", work->work_group ); }
dbgtext( "Do not announce to ourselves.\n" ); return;
} }
return;
}
memset(outbuf,'\0',sizeof(outbuf)); memset(outbuf,'\0',sizeof(outbuf));
p = outbuf; p = outbuf;
SCVAL(p,0,ANN_MasterAnnouncement); SCVAL(p,0,ANN_MasterAnnouncement);
p++; p++;
fstrcpy(myname, global_myname()); fstrcpy(myname, global_myname());
strupper_m(myname); strupper_m(myname);
myname[15]='\0'; myname[15]='\0';
push_pstring_base(p, myname, outbuf); /* The call below does CH_UNIX -> CH_DOS conversion. JRA */
push_pstring_base(p, myname, outbuf);
p = skip_string(p,1); p = skip_string(p,1);
if( DEBUGLVL( 4 ) ) if( DEBUGLVL( 4 ) ) {
{ dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" ); dbgtext( "Sending local master announce to " );
dbgtext( "Sending local master announce to " ); dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name),
dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name), work->work_group );
work->work_group ); }
}
send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf), send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
global_myname(), 0x0, work->dmb_name.name, 0x0, global_myname(), 0x0, work->dmb_name.name, 0x0,
work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT); work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT);
} }
/**************************************************************************** /****************************************************************************
@@ -153,17 +146,19 @@ As a local master browser, do a sync with a domain master browser.
static void sync_with_dmb(struct work_record *work) static void sync_with_dmb(struct work_record *work)
{ {
if( DEBUGLVL( 2 ) ) nstring dmb_name;
{
dbgtext( "sync_with_dmb:\n" );
dbgtext( "Initiating sync with domain master browser " );
dbgtext( "%s ", nmb_namestr(&work->dmb_name) );
dbgtext( "at IP %s ", inet_ntoa(work->dmb_addr) );
dbgtext( "for workgroup %s\n", work->work_group );
}
sync_browse_lists(work, work->dmb_name.name, work->dmb_name.name_type, if( DEBUGLVL( 2 ) ) {
work->dmb_addr, False, True); dbgtext( "sync_with_dmb:\n" );
dbgtext( "Initiating sync with domain master browser " );
dbgtext( "%s ", nmb_namestr(&work->dmb_name) );
dbgtext( "at IP %s ", inet_ntoa(work->dmb_addr) );
dbgtext( "for workgroup %s\n", work->work_group );
}
pull_ascii_nstring(dmb_name, work->dmb_name.name);
sync_browse_lists(work, dmb_name, work->dmb_name.name_type,
work->dmb_addr, False, True);
} }
/**************************************************************************** /****************************************************************************
@@ -175,78 +170,69 @@ static void domain_master_node_status_success(struct subnet_record *subrec,
struct res_rec *answers, struct res_rec *answers,
struct in_addr from_ip) struct in_addr from_ip)
{ {
struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data); struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
if( work == NULL ) if( work == NULL ) {
{ if( DEBUGLVL( 0 ) ) {
if( DEBUGLVL( 0 ) ) dbgtext( "domain_master_node_status_success:\n" );
{ dbgtext( "Unable to find workgroup " );
dbgtext( "domain_master_node_status_success:\n" ); dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );
dbgtext( "Unable to find workgroup " ); }
dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name ); return;
} }
return;
}
if( DEBUGLVL( 3 ) ) if( DEBUGLVL( 3 ) ) {
{ dbgtext( "domain_master_node_status_success:\n" );
dbgtext( "domain_master_node_status_success:\n" ); dbgtext( "Success in node status for workgroup " );
dbgtext( "Success in node status for workgroup " ); dbgtext( "%s from ip %s\n", work->work_group, inet_ntoa(from_ip) );
dbgtext( "%s from ip %s\n", work->work_group, inet_ntoa(from_ip) ); }
}
/* Go through the list of names found at answers->rdata and look for /* Go through the list of names found at answers->rdata and look for
the first SERVER<0x20> name. */ the first SERVER<0x20> name. */
if(answers->rdata != NULL) if(answers->rdata != NULL) {
{ char *p = answers->rdata;
char *p = answers->rdata; int numnames = CVAL(p, 0);
int numnames = CVAL(p, 0);
p += 1; p += 1;
while (numnames--) while (numnames--) {
{ nstring qname;
char qname[17]; uint16 nb_flags;
uint16 nb_flags; int name_type;
int name_type;
StrnCpy(qname,p,15); pull_ascii_nstring(qname, p);
name_type = CVAL(p,15); name_type = CVAL(p,15);
nb_flags = get_nb_flags(&p[16]); nb_flags = get_nb_flags(&p[16]);
trim_string(qname,NULL," "); trim_string(qname,NULL," ");
p += 18; p += 18;
if(!(nb_flags & NB_GROUP) && (name_type == 0x20)) if(!(nb_flags & NB_GROUP) && (name_type == 0x20)) {
{ struct nmb_name nmbname;
struct nmb_name nmbname;
make_nmb_name(&nmbname, qname, name_type); make_nmb_name(&nmbname, qname, name_type);
/* Copy the dmb name and IP address /* Copy the dmb name and IP address
into the workgroup struct. */ into the workgroup struct. */
work->dmb_name = nmbname; work->dmb_name = nmbname;
putip((char *)&work->dmb_addr, &from_ip); putip((char *)&work->dmb_addr, &from_ip);
/* Do the local master browser announcement to the domain /* Do the local master browser announcement to the domain
master browser name and IP. */ master browser name and IP. */
announce_local_master_browser_to_domain_master_browser( work ); announce_local_master_browser_to_domain_master_browser( work );
/* Now synchronise lists with the domain master browser. */ /* Now synchronise lists with the domain master browser. */
sync_with_dmb(work); sync_with_dmb(work);
break; break;
} }
} }
} } else if( DEBUGLVL( 0 ) ) {
else dbgtext( "domain_master_node_status_success:\n" );
if( DEBUGLVL( 0 ) ) dbgtext( "Failed to find a SERVER<0x20> name in reply from IP " );
{ dbgtext( "%s.\n", inet_ntoa(from_ip) );
dbgtext( "domain_master_node_status_success:\n" ); }
dbgtext( "Failed to find a SERVER<0x20> name in reply from IP " );
dbgtext( "%s.\n", inet_ntoa(from_ip) );
}
} }
/**************************************************************************** /****************************************************************************
@@ -256,16 +242,15 @@ static void domain_master_node_status_success(struct subnet_record *subrec,
static void domain_master_node_status_fail(struct subnet_record *subrec, static void domain_master_node_status_fail(struct subnet_record *subrec,
struct response_record *rrec) struct response_record *rrec)
{ {
struct userdata_struct *userdata = rrec->userdata; struct userdata_struct *userdata = rrec->userdata;
if( DEBUGLVL( 0 ) ) if( DEBUGLVL( 0 ) ) {
{ dbgtext( "domain_master_node_status_fail:\n" );
dbgtext( "domain_master_node_status_fail:\n" ); dbgtext( "Doing a node status request to the domain master browser\n" );
dbgtext( "Doing a node status request to the domain master browser\n" ); dbgtext( "for workgroup %s ", userdata ? userdata->data : "NULL" );
dbgtext( "for workgroup %s ", userdata ? userdata->data : "NULL" ); dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) ); dbgtext( "Cannot sync browser lists.\n" );
dbgtext( "Cannot sync browser lists.\n" ); }
}
} }
/**************************************************************************** /****************************************************************************
@@ -276,100 +261,99 @@ static void find_domain_master_name_query_success(struct subnet_record *subrec,
struct userdata_struct *userdata_in, struct userdata_struct *userdata_in,
struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec) struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
{ {
/* /*
* Unfortunately, finding the IP address of the Domain Master Browser, * Unfortunately, finding the IP address of the Domain Master Browser,
* as we have here, is not enough. We need to now do a sync to the * as we have here, is not enough. We need to now do a sync to the
* SERVERNAME<0x20> NetBIOS name, as only recent NT servers will * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
* respond to the SMBSERVER name. To get this name from IP * respond to the SMBSERVER name. To get this name from IP
* address we do a Node status request, and look for the first * address we do a Node status request, and look for the first
* NAME<0x20> in the response, and take that as the server name. * NAME<0x20> in the response, and take that as the server name.
* We also keep a cache of the Domain Master Browser name for this * We also keep a cache of the Domain Master Browser name for this
* workgroup in the Workgroup struct, so that if the same IP addess * workgroup in the Workgroup struct, so that if the same IP addess
* is returned every time, we don't need to do the node status * is returned every time, we don't need to do the node status
* request. * request.
*/ */
struct work_record *work; struct work_record *work;
struct nmb_name nmbname; struct nmb_name nmbname;
struct userdata_struct *userdata; struct userdata_struct *userdata;
size_t size = sizeof(struct userdata_struct) + sizeof(fstring)+1; size_t size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
nstring qname;
if( !(work = find_workgroup_on_subnet(subrec, q_name->name)) ) pull_ascii_nstring(qname, q_name->name);
{ if( !(work = find_workgroup_on_subnet(subrec, qname)) ) {
if( DEBUGLVL( 0 ) ) if( DEBUGLVL( 0 ) ) {
{ dbgtext( "find_domain_master_name_query_success:\n" );
dbgtext( "find_domain_master_name_query_success:\n" ); dbgtext( "Failed to find workgroup %s\n", qname);
dbgtext( "Failed to find workgroup %s\n", q_name->name ); }
} return;
return;
} }
/* First check if we already have a dmb for this workgroup. */ /* First check if we already have a dmb for this workgroup. */
if(!is_zero_ip(work->dmb_addr) && ip_equal(work->dmb_addr, answer_ip)) if(!is_zero_ip(work->dmb_addr) && ip_equal(work->dmb_addr, answer_ip)) {
{ /* Do the local master browser announcement to the domain
/* Do the local master browser announcement to the domain master browser name and IP. */
master browser name and IP. */ announce_local_master_browser_to_domain_master_browser( work );
announce_local_master_browser_to_domain_master_browser( work );
/* Now synchronise lists with the domain master browser. */ /* Now synchronise lists with the domain master browser. */
sync_with_dmb(work); sync_with_dmb(work);
return; return;
} } else {
else zero_ip(&work->dmb_addr);
zero_ip(&work->dmb_addr); }
/* Now initiate the node status request. */ /* Now initiate the node status request. */
/* We used to use the name "*",0x0 here, but some Windows /* We used to use the name "*",0x0 here, but some Windows
* servers don't answer that name. However we *know* they * servers don't answer that name. However we *know* they
* have the name workgroup#1b (as we just looked it up). * have the name workgroup#1b (as we just looked it up).
* So do the node status request on this name instead. * So do the node status request on this name instead.
* Found at LBL labs. JRA. * Found at LBL labs. JRA.
*/ */
make_nmb_name(&nmbname,work->work_group,0x1b); make_nmb_name(&nmbname,work->work_group,0x1b);
/* Put the workgroup name into the userdata so we know /* Put the workgroup name into the userdata so we know
what workgroup we're talking to when the reply comes what workgroup we're talking to when the reply comes
back. */ back. */
/* Setup the userdata_struct - this is copied so we can use /* Setup the userdata_struct - this is copied so we can use
a stack variable for this. */ a stack variable for this. */
if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
{
DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
return;
}
userdata->copy_fn = NULL; if((userdata = (struct userdata_struct *)malloc(size)) == NULL) {
userdata->free_fn = NULL; DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
userdata->userdata_len = strlen(work->work_group)+1; return;
overmalloc_safe_strcpy(userdata->data, work->work_group, size - sizeof(*userdata) - 1); }
node_status( subrec, &nmbname, answer_ip, userdata->copy_fn = NULL;
domain_master_node_status_success, userdata->free_fn = NULL;
domain_master_node_status_fail, userdata->userdata_len = strlen(work->work_group)+1;
userdata); overmalloc_safe_strcpy(userdata->data, work->work_group, size - sizeof(*userdata) - 1);
zero_free(userdata, size); node_status( subrec, &nmbname, answer_ip,
domain_master_node_status_success,
domain_master_node_status_fail,
userdata);
zero_free(userdata, size);
} }
/**************************************************************************** /****************************************************************************
Function called when a query for a WORKGROUP<1b> name fails. Function called when a query for a WORKGROUP<1b> name fails.
****************************************************************************/ ****************************************************************************/
static void find_domain_master_name_query_fail(struct subnet_record *subrec, static void find_domain_master_name_query_fail(struct subnet_record *subrec,
struct response_record *rrec, struct response_record *rrec,
struct nmb_name *question_name, int fail_code) struct nmb_name *question_name, int fail_code)
{ {
if( DEBUGLVL( 0 ) ) if( DEBUGLVL( 0 ) ) {
{ dbgtext( "find_domain_master_name_query_fail:\n" );
dbgtext( "find_domain_master_name_query_fail:\n" ); dbgtext( "Unable to find the Domain Master Browser name " );
dbgtext( "Unable to find the Domain Master Browser name " ); dbgtext( "%s for the workgroup %s.\n",
dbgtext( "%s for the workgroup %s.\n", nmb_namestr(question_name), question_name->name );
nmb_namestr(question_name), question_name->name ); dbgtext( "Unable to sync browse lists in this workgroup.\n" );
dbgtext( "Unable to sync browse lists in this workgroup.\n" ); }
}
} }
/**************************************************************************** /****************************************************************************
@@ -381,27 +365,20 @@ full domain browse lists from it onto the given subnet.
void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec, void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
struct work_record *work) struct work_record *work)
{ {
struct nmb_name nmbname; /* Only do this if we are using a WINS server. */
if(we_are_a_wins_client() == False) {
if( DEBUGLVL( 10 ) ) {
dbgtext( "announce_and_sync_with_domain_master_browser:\n" );
dbgtext( "Ignoring, as we are not a WINS client.\n" );
}
return;
}
/* Only do this if we are using a WINS server. */ /* First, query for the WORKGROUP<1b> name from the WINS server. */
if(we_are_a_wins_client() == False) query_name(unicast_subnet, work->work_group, 0x1b,
{
if( DEBUGLVL( 10 ) )
{
dbgtext( "announce_and_sync_with_domain_master_browser:\n" );
dbgtext( "Ignoring, as we are not a WINS client.\n" );
}
return;
}
make_nmb_name(&nmbname,work->work_group,0x1b);
/* First, query for the WORKGROUP<1b> name from the WINS server. */
query_name(unicast_subnet, nmbname.name, nmbname.name_type,
find_domain_master_name_query_success, find_domain_master_name_query_success,
find_domain_master_name_query_fail, find_domain_master_name_query_fail,
NULL); NULL);
} }
/**************************************************************************** /****************************************************************************
@@ -421,89 +398,81 @@ static void get_domain_master_name_node_status_success(struct subnet_record *sub
struct res_rec *answers, struct res_rec *answers,
struct in_addr from_ip) struct in_addr from_ip)
{ {
struct work_record *work; struct work_record *work;
fstring server_name; fstring server_name;
server_name[0] = 0; server_name[0] = 0;
if( DEBUGLVL( 3 ) ) if( DEBUGLVL( 3 ) ) {
{ dbgtext( "get_domain_master_name_node_status_success:\n" );
dbgtext( "get_domain_master_name_node_status_success:\n" ); dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) ); }
}
/* /*
* Go through the list of names found at answers->rdata and look for * Go through the list of names found at answers->rdata and look for
* the first WORKGROUP<0x1b> name. * the first WORKGROUP<0x1b> name.
*/ */
if(answers->rdata != NULL) if(answers->rdata != NULL) {
{ char *p = answers->rdata;
char *p = answers->rdata; int numnames = CVAL(p, 0);
int numnames = CVAL(p, 0);
p += 1; p += 1;
while (numnames--) while (numnames--) {
{ nstring qname;
char qname[17]; uint16 nb_flags;
uint16 nb_flags; int name_type;
int name_type;
StrnCpy(qname,p,15); pull_ascii_nstring(qname, p);
name_type = CVAL(p,15); name_type = CVAL(p,15);
nb_flags = get_nb_flags(&p[16]); nb_flags = get_nb_flags(&p[16]);
trim_string(qname,NULL," "); trim_string(qname,NULL," ");
p += 18; p += 18;
if(!(nb_flags & NB_GROUP) && (name_type == 0x00) && if(!(nb_flags & NB_GROUP) && (name_type == 0x00) &&
server_name[0] == 0) { server_name[0] == 0) {
/* this is almost certainly the server netbios name */ /* this is almost certainly the server netbios name */
fstrcpy(server_name, qname); fstrcpy(server_name, qname);
continue; continue;
} }
if(!(nb_flags & NB_GROUP) && (name_type == 0x1b)) if(!(nb_flags & NB_GROUP) && (name_type == 0x1b)) {
{ if( DEBUGLVL( 5 ) ) {
if( DEBUGLVL( 5 ) ) dbgtext( "get_domain_master_name_node_status_success:\n" );
{ dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
dbgtext( "get_domain_master_name_node_status_success:\n" ); dbgtext( "is a domain master browser for workgroup " );
dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) ); dbgtext( "%s. Adding this name.\n", qname );
dbgtext( "is a domain master browser for workgroup " ); }
dbgtext( "%s. Adding this name.\n", qname );
}
/* /*
* If we don't already know about this workgroup, add it * If we don't already know about this workgroup, add it
* to the workgroup list on the unicast_subnet. * to the workgroup list on the unicast_subnet.
*/ */
if((work = find_workgroup_on_subnet( subrec, qname)) == NULL)
{
struct nmb_name nmbname;
/*
* Add it - with an hour in the cache.
*/
if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
return;
/* remember who the master is */ if((work = find_workgroup_on_subnet( subrec, qname)) == NULL) {
fstrcpy(work->local_master_browser_name, server_name); struct nmb_name nmbname;
make_nmb_name(&nmbname, server_name, 0x20); /*
work->dmb_name = nmbname; * Add it - with an hour in the cache.
work->dmb_addr = from_ip; */
} if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
break; return;
}
} /* remember who the master is */
} fstrcpy(work->local_master_browser_name, server_name);
else make_nmb_name(&nmbname, server_name, 0x20);
if( DEBUGLVL( 0 ) ) work->dmb_name = nmbname;
{ work->dmb_addr = from_ip;
dbgtext( "get_domain_master_name_node_status_success:\n" ); }
dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " ); break;
dbgtext( "%s.\n", inet_ntoa(from_ip) ); }
} }
} else if( DEBUGLVL( 0 ) ) {
dbgtext( "get_domain_master_name_node_status_success:\n" );
dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " );
dbgtext( "%s.\n", inet_ntoa(from_ip) );
}
} }
/**************************************************************************** /****************************************************************************
@@ -513,13 +482,12 @@ static void get_domain_master_name_node_status_success(struct subnet_record *sub
static void get_domain_master_name_node_status_fail(struct subnet_record *subrec, static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
struct response_record *rrec) struct response_record *rrec)
{ {
if( DEBUGLVL( 0 ) ) if( DEBUGLVL( 0 ) ) {
{ dbgtext( "get_domain_master_name_node_status_fail:\n" );
dbgtext( "get_domain_master_name_node_status_fail:\n" ); dbgtext( "Doing a node status request to the domain master browser " );
dbgtext( "Doing a node status request to the domain master browser " ); dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) ); dbgtext( "Cannot get workgroup name.\n" );
dbgtext( "Cannot get workgroup name.\n" ); }
}
} }
/**************************************************************************** /****************************************************************************
@@ -530,58 +498,53 @@ static void find_all_domain_master_names_query_success(struct subnet_record *sub
struct userdata_struct *userdata_in, struct userdata_struct *userdata_in,
struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec) struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
{ {
/* /*
* We now have a list of all the domain master browsers for all workgroups * We now have a list of all the domain master browsers for all workgroups
* that have registered with the WINS server. Now do a node status request * that have registered with the WINS server. Now do a node status request
* to each one and look for the first 1b name in the reply. This will be * to each one and look for the first 1b name in the reply. This will be
* the workgroup name that we will add to the unicast subnet as a 'non-local' * the workgroup name that we will add to the unicast subnet as a 'non-local'
* workgroup. * workgroup.
*/ */
struct nmb_name nmbname; struct nmb_name nmbname;
struct in_addr send_ip; struct in_addr send_ip;
int i; int i;
if( DEBUGLVL( 5 ) ) if( DEBUGLVL( 5 ) ) {
{ dbgtext( "find_all_domain_master_names_query_succes:\n" );
dbgtext( "find_all_domain_master_names_query_succes:\n" ); dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) ); dbgtext( "IP addresses for Domain Master Browsers.\n" );
dbgtext( "IP addresses for Domain Master Browsers.\n" ); }
}
for(i = 0; i < rrec->rdlength / 6; i++) for(i = 0; i < rrec->rdlength / 6; i++) {
{ /* Initiate the node status requests. */
/* Initiate the node status requests. */ make_nmb_name(&nmbname, "*", 0);
make_nmb_name(&nmbname, "*", 0);
putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]); putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
/* /*
* Don't send node status requests to ourself. * Don't send node status requests to ourself.
*/ */
if(ismyip( send_ip )) if(ismyip( send_ip )) {
{ if( DEBUGLVL( 5 ) ) {
if( DEBUGLVL( 5 ) ) dbgtext( "find_all_domain_master_names_query_succes:\n" );
{ dbgtext( "Not sending node status to our own IP " );
dbgtext( "find_all_domain_master_names_query_succes:\n" ); dbgtext( "%s.\n", inet_ntoa(send_ip) );
dbgtext( "Not sending node status to our own IP " ); }
dbgtext( "%s.\n", inet_ntoa(send_ip) ); continue;
} }
continue;
}
if( DEBUGLVL( 5 ) ) if( DEBUGLVL( 5 ) ) {
{ dbgtext( "find_all_domain_master_names_query_success:\n" );
dbgtext( "find_all_domain_master_names_query_success:\n" ); dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) ); }
}
node_status( subrec, &nmbname, send_ip, node_status( subrec, &nmbname, send_ip,
get_domain_master_name_node_status_success, get_domain_master_name_node_status_success,
get_domain_master_name_node_status_fail, get_domain_master_name_node_status_fail,
NULL); NULL);
} }
} }
/**************************************************************************** /****************************************************************************
@@ -591,13 +554,12 @@ static void find_all_domain_master_names_query_fail(struct subnet_record *subrec
struct response_record *rrec, struct response_record *rrec,
struct nmb_name *question_name, int fail_code) struct nmb_name *question_name, int fail_code)
{ {
if( DEBUGLVL( 10 ) ) if( DEBUGLVL( 10 ) ) {
{ dbgtext( "find_domain_master_name_query_fail:\n" );
dbgtext( "find_domain_master_name_query_fail:\n" ); dbgtext( "WINS server did not reply to a query for name " );
dbgtext( "WINS server did not reply to a query for name " ); dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) ); dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" );
dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" ); }
}
} }
/**************************************************************************** /****************************************************************************
@@ -608,43 +570,39 @@ static void find_all_domain_master_names_query_fail(struct subnet_record *subrec
<1b> name in the reply - this is the workgroup name. Add this to the unicast <1b> name in the reply - this is the workgroup name. Add this to the unicast
subnet. This is expensive, so we only do this every 15 minutes. subnet. This is expensive, so we only do this every 15 minutes.
**************************************************************************/ **************************************************************************/
void collect_all_workgroup_names_from_wins_server(time_t t) void collect_all_workgroup_names_from_wins_server(time_t t)
{ {
static time_t lastrun = 0; static time_t lastrun = 0;
struct work_record *work; struct work_record *work;
struct nmb_name nmbname;
/* Only do this if we are using a WINS server. */ /* Only do this if we are using a WINS server. */
if(we_are_a_wins_client() == False) if(we_are_a_wins_client() == False)
return; return;
/* Check to see if we are a domain master browser on the unicast subnet. */ /* Check to see if we are a domain master browser on the unicast subnet. */
if((work = find_workgroup_on_subnet( unicast_subnet, lp_workgroup())) == NULL) if((work = find_workgroup_on_subnet( unicast_subnet, lp_workgroup())) == NULL) {
{ if( DEBUGLVL( 0 ) ) {
if( DEBUGLVL( 0 ) ) dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
{ dbgtext( "Cannot find my workgroup %s ", lp_workgroup() );
dbgtext( "collect_all_workgroup_names_from_wins_server:\n" ); dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
dbgtext( "Cannot find my workgroup %s ", lp_workgroup() ); }
dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name ); return;
} }
return;
}
if(!AM_DOMAIN_MASTER_BROWSER(work)) if(!AM_DOMAIN_MASTER_BROWSER(work))
return; return;
if ((lastrun != 0) && (t < lastrun + (15 * 60))) if ((lastrun != 0) && (t < lastrun + (15 * 60)))
return; return;
lastrun = t; lastrun = t;
make_nmb_name(&nmbname,"*",0x1b); /* First, query for the *<1b> name from the WINS server. */
query_name(unicast_subnet, "*", 0x1b,
/* First, query for the *<1b> name from the WINS server. */ find_all_domain_master_names_query_success,
query_name(unicast_subnet, nmbname.name, nmbname.name_type, find_all_domain_master_names_query_fail,
find_all_domain_master_names_query_success, NULL);
find_all_domain_master_names_query_fail,
NULL);
} }
@@ -656,6 +614,7 @@ To prevent exponential network traffic with large numbers of workgroups
we use a randomised system where sync probability is inversely proportional we use a randomised system where sync probability is inversely proportional
to the number of known workgroups to the number of known workgroups
**************************************************************************/ **************************************************************************/
void sync_all_dmbs(time_t t) void sync_all_dmbs(time_t t)
{ {
static time_t lastrun = 0; static time_t lastrun = 0;
@@ -669,7 +628,8 @@ void sync_all_dmbs(time_t t)
/* Check to see if we are a domain master browser on the /* Check to see if we are a domain master browser on the
unicast subnet. */ unicast subnet. */
work = find_workgroup_on_subnet(unicast_subnet, lp_workgroup()); work = find_workgroup_on_subnet(unicast_subnet, lp_workgroup());
if (!work) return; if (!work)
return;
if (!AM_DOMAIN_MASTER_BROWSER(work)) if (!AM_DOMAIN_MASTER_BROWSER(work))
return; return;
@@ -687,7 +647,10 @@ void sync_all_dmbs(time_t t)
/* sync with a probability of 1/count */ /* sync with a probability of 1/count */
for (work=unicast_subnet->workgrouplist; work; work = work->next) { for (work=unicast_subnet->workgrouplist; work; work = work->next) {
if (strcmp(lp_workgroup(), work->work_group)) { if (strcmp(lp_workgroup(), work->work_group)) {
if (((unsigned)sys_random()) % count != 0) continue; nstring dmb_name;
if (((unsigned)sys_random()) % count != 0)
continue;
lastrun = t; lastrun = t;
@@ -699,13 +662,15 @@ void sync_all_dmbs(time_t t)
0x20); 0x20);
} }
pull_ascii_nstring(dmb_name, work->dmb_name.name);
DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n", DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
work->dmb_name.name, dmb_name, inet_ntoa(work->dmb_addr)));
inet_ntoa(work->dmb_addr)));
sync_browse_lists(work, sync_browse_lists(work,
work->dmb_name.name, dmb_name,
work->dmb_name.name_type, work->dmb_name.name_type,
work->dmb_addr, False, False); work->dmb_addr, False, False);
} }
} }
} }

View File

@@ -3,7 +3,7 @@
NBT netbios routines and daemon - version 2 NBT netbios routines and daemon - version 2
Copyright (C) Andrew Tridgell 1994-1998 Copyright (C) Andrew Tridgell 1994-1998
Copyright (C) Luke Kenneth Casson Leighton 1994-1998 Copyright (C) Luke Kenneth Casson Leighton 1994-1998
Copyright (C) Jeremy Allison 1994-1998 Copyright (C) Jeremy Allison 1994-2003
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -29,32 +29,35 @@ extern time_t StartupTime;
/**************************************************************************** /****************************************************************************
Send an election datagram packet. Send an election datagram packet.
**************************************************************************/ **************************************************************************/
static void send_election_dgram(struct subnet_record *subrec, const char *workgroup_name, static void send_election_dgram(struct subnet_record *subrec, const char *workgroup_name,
uint32 criterion, int timeup,const char *server_name) uint32 criterion, int timeup,const char *server_name)
{ {
pstring outbuf; pstring outbuf;
char *p; fstring srv_name;
char *p;
DEBUG(2,("send_election_dgram: Sending election packet for workgroup %s on subnet %s\n", DEBUG(2,("send_election_dgram: Sending election packet for workgroup %s on subnet %s\n",
workgroup_name, subrec->subnet_name )); workgroup_name, subrec->subnet_name ));
memset(outbuf,'\0',sizeof(outbuf)); memset(outbuf,'\0',sizeof(outbuf));
p = outbuf; p = outbuf;
SCVAL(p,0,ANN_Election); /* Election opcode. */ SCVAL(p,0,ANN_Election); /* Election opcode. */
p++; p++;
SCVAL(p,0,((criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION)); SCVAL(p,0,((criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION));
SIVAL(p,1,criterion); SIVAL(p,1,criterion);
SIVAL(p,5,timeup*1000); /* ms - Despite what the spec says. */ SIVAL(p,5,timeup*1000); /* ms - Despite what the spec says. */
p += 13; p += 13;
pstrcpy_base(p, server_name, outbuf); fstrcpy(srv_name, server_name);
strupper_m(p); strupper_m(srv_name);
p = skip_string(p,1); pstrcpy_base(p, srv_name, outbuf);
p = skip_string(p,1);
send_mailslot(False, BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf), send_mailslot(False, BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
global_myname(), 0, global_myname(), 0,
workgroup_name, 0x1e, workgroup_name, 0x1e,
subrec->bcast_ip, subrec->myip, DGRAM_PORT); subrec->bcast_ip, subrec->myip, DGRAM_PORT);
} }
/******************************************************************* /*******************************************************************
@@ -66,8 +69,10 @@ static void check_for_master_browser_success(struct subnet_record *subrec,
struct nmb_name *answer_name, struct nmb_name *answer_name,
struct in_addr answer_ip, struct res_rec *rrec) struct in_addr answer_ip, struct res_rec *rrec)
{ {
DEBUG(3,("check_for_master_browser_success: Local master browser for workgroup %s exists at \ nstring aname;
IP %s (just checking).\n", answer_name->name, inet_ntoa(answer_ip) )); pull_ascii_nstring(aname, answer_name->name);
DEBUG(3,("check_for_master_browser_success: Local master browser for workgroup %s exists at \
IP %s (just checking).\n", aname, inet_ntoa(answer_ip) ));
} }
/******************************************************************* /*******************************************************************
@@ -79,41 +84,39 @@ static void check_for_master_browser_fail( struct subnet_record *subrec,
struct nmb_name *question_name, struct nmb_name *question_name,
int fail_code) int fail_code)
{ {
char *workgroup_name = question_name->name; nstring workgroup_name;
struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name); struct work_record *work;
if(work == NULL) pull_ascii_nstring(workgroup_name,question_name->name);
{
DEBUG(0,("check_for_master_browser_fail: Unable to find workgroup %s on subnet %s.=\n",
workgroup_name, subrec->subnet_name ));
return;
}
if (strequal(work->work_group, lp_workgroup())) work = find_workgroup_on_subnet(subrec, workgroup_name);
{ if(work == NULL) {
DEBUG(0,("check_for_master_browser_fail: Unable to find workgroup %s on subnet %s.=\n",
workgroup_name, subrec->subnet_name ));
return;
}
if (lp_local_master()) if (strequal(work->work_group, lp_workgroup())) {
{
/* We have discovered that there is no local master
browser, and we are configured to initiate
an election that we will participate in.
*/
DEBUG(2,("check_for_master_browser_fail: Forcing election on workgroup %s subnet %s\n",
work->work_group, subrec->subnet_name ));
/* Setting this means we will participate when the if (lp_local_master()) {
election is run in run_elections(). */ /* We have discovered that there is no local master
work->needelection = True; browser, and we are configured to initiate
} an election that we will participate in.
else */
{ DEBUG(2,("check_for_master_browser_fail: Forcing election on workgroup %s subnet %s\n",
/* We need to force an election, because we are configured work->work_group, subrec->subnet_name ));
not to become the local master, but we still need one,
having detected that one doesn't exist. /* Setting this means we will participate when the
*/ election is run in run_elections(). */
send_election_dgram(subrec, work->work_group, 0, 0, ""); work->needelection = True;
} } else {
} /* We need to force an election, because we are configured
not to become the local master, but we still need one,
having detected that one doesn't exist.
*/
send_election_dgram(subrec, work->work_group, 0, 0, "");
}
}
} }
/******************************************************************* /*******************************************************************
@@ -123,36 +126,33 @@ static void check_for_master_browser_fail( struct subnet_record *subrec,
void check_master_browser_exists(time_t t) void check_master_browser_exists(time_t t)
{ {
static time_t lastrun=0; static time_t lastrun=0;
struct subnet_record *subrec; struct subnet_record *subrec;
const char *workgroup_name = lp_workgroup(); const char *workgroup_name = lp_workgroup();
if (!lastrun) if (!lastrun)
lastrun = t; lastrun = t;
if (t < (lastrun + (CHECK_TIME_MST_BROWSE * 60))) if (t < (lastrun + (CHECK_TIME_MST_BROWSE * 60)))
return; return;
lastrun = t; lastrun = t;
dump_workgroups(False); dump_workgroups(False);
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
{ struct work_record *work;
struct work_record *work;
for (work = subrec->workgrouplist; work; work = work->next) for (work = subrec->workgrouplist; work; work = work->next) {
{ if (strequal(work->work_group, workgroup_name) && !AM_LOCAL_MASTER_BROWSER(work)) {
if (strequal(work->work_group, workgroup_name) && !AM_LOCAL_MASTER_BROWSER(work)) /* Do a name query for the local master browser on this net. */
{ query_name( subrec, work->work_group, 0x1d,
/* Do a name query for the local master browser on this net. */ check_for_master_browser_success,
query_name( subrec, work->work_group, 0x1d, check_for_master_browser_fail,
check_for_master_browser_success, NULL);
check_for_master_browser_fail, }
NULL); }
} }
}
}
} }
/******************************************************************* /*******************************************************************
@@ -161,56 +161,52 @@ void check_master_browser_exists(time_t t)
void run_elections(time_t t) void run_elections(time_t t)
{ {
static time_t lastime = 0; static time_t lastime = 0;
struct subnet_record *subrec; struct subnet_record *subrec;
/* Send election packets once every 2 seconds - note */ /* Send election packets once every 2 seconds - note */
if (lastime && (t - lastime < 2)) if (lastime && (t - lastime < 2))
return; return;
lastime = t; lastime = t;
START_PROFILE(run_elections); START_PROFILE(run_elections);
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
{ struct work_record *work;
struct work_record *work;
for (work = subrec->workgrouplist; work; work = work->next) for (work = subrec->workgrouplist; work; work = work->next) {
{ if (work->RunningElection) {
if (work->RunningElection) /*
{ * We can only run an election for a workgroup if we have
/* * registered the WORKGROUP<1e> name, as that's the name
* We can only run an election for a workgroup if we have * we must listen to.
* registered the WORKGROUP<1e> name, as that's the name */
* we must listen to. struct nmb_name nmbname;
*/
struct nmb_name nmbname;
make_nmb_name(&nmbname, work->work_group, 0x1e); make_nmb_name(&nmbname, work->work_group, 0x1e);
if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) { if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) {
DEBUG(8,("run_elections: Cannot send election packet yet as name %s not \ DEBUG(8,("run_elections: Cannot send election packet yet as name %s not \
yet registered on subnet %s\n", nmb_namestr(&nmbname), subrec->subnet_name )); yet registered on subnet %s\n", nmb_namestr(&nmbname), subrec->subnet_name ));
continue; continue;
} }
send_election_dgram(subrec, work->work_group, work->ElectionCriterion, send_election_dgram(subrec, work->work_group, work->ElectionCriterion,
t - StartupTime, global_myname()); t - StartupTime, global_myname());
if (work->ElectionCount++ >= 4) if (work->ElectionCount++ >= 4) {
{ /* Won election (4 packets were sent out uncontested. */
/* Won election (4 packets were sent out uncontested. */ DEBUG(2,("run_elections: >>> Won election for workgroup %s on subnet %s <<<\n",
DEBUG(2,("run_elections: >>> Won election for workgroup %s on subnet %s <<<\n", work->work_group, subrec->subnet_name ));
work->work_group, subrec->subnet_name ));
work->RunningElection = False; work->RunningElection = False;
become_local_master_browser(subrec, work); become_local_master_browser(subrec, work);
} }
} }
} }
} }
END_PROFILE(run_elections); END_PROFILE(run_elections);
} }
/******************************************************************* /*******************************************************************
@@ -218,44 +214,42 @@ yet registered on subnet %s\n", nmb_namestr(&nmbname), subrec->subnet_name ));
******************************************************************/ ******************************************************************/
static BOOL win_election(struct work_record *work, int version, static BOOL win_election(struct work_record *work, int version,
uint32 criterion, int timeup, char *server_name) uint32 criterion, int timeup, const char *server_name)
{ {
int mytimeup = time(NULL) - StartupTime; int mytimeup = time(NULL) - StartupTime;
uint32 mycriterion = work->ElectionCriterion; uint32 mycriterion = work->ElectionCriterion;
/* If local master is false then never win /* If local master is false then never win in election broadcasts. */
in election broadcasts. */ if(!lp_local_master()) {
if(!lp_local_master()) DEBUG(3,("win_election: Losing election as local master == False\n"));
{ return False;
DEBUG(3,("win_election: Losing election as local master == False\n")); }
return False;
}
DEBUG(4,("win_election: election comparison: %x:%x %x:%x %d:%d %s:%s\n", DEBUG(4,("win_election: election comparison: %x:%x %x:%x %d:%d %s:%s\n",
version, ELECTION_VERSION, version, ELECTION_VERSION,
criterion, mycriterion, criterion, mycriterion,
timeup, mytimeup, timeup, mytimeup,
server_name, global_myname())); server_name, global_myname()));
if (version > ELECTION_VERSION) if (version > ELECTION_VERSION)
return(False); return(False);
if (version < ELECTION_VERSION) if (version < ELECTION_VERSION)
return(True); return(True);
if (criterion > mycriterion) if (criterion > mycriterion)
return(False); return(False);
if (criterion < mycriterion) if (criterion < mycriterion)
return(True); return(True);
if (timeup > mytimeup) if (timeup > mytimeup)
return(False); return(False);
if (timeup < mytimeup) if (timeup < mytimeup)
return(True); return(True);
if (strcasecmp(global_myname(), server_name) > 0) if (strcasecmp(global_myname(), server_name) > 0)
return(False); return(False);
return(True); return(True);
} }
/******************************************************************* /*******************************************************************
@@ -264,66 +258,63 @@ static BOOL win_election(struct work_record *work, int version,
void process_election(struct subnet_record *subrec, struct packet_struct *p, char *buf) void process_election(struct subnet_record *subrec, struct packet_struct *p, char *buf)
{ {
struct dgram_packet *dgram = &p->packet.dgram; struct dgram_packet *dgram = &p->packet.dgram;
int version = CVAL(buf,0); int version = CVAL(buf,0);
uint32 criterion = IVAL(buf,1); uint32 criterion = IVAL(buf,1);
int timeup = IVAL(buf,5)/1000; int timeup = IVAL(buf,5)/1000;
char *server_name = buf+13; nstring server_name;
struct work_record *work; struct work_record *work;
char *workgroup_name = dgram->dest_name.name; nstring workgroup_name;
START_PROFILE(election); pull_ascii_nstring(server_name, buf+13);
server_name[15] = 0; pull_ascii_nstring(workgroup_name, dgram->dest_name.name);
DEBUG(3,("process_election: Election request from %s at IP %s on subnet %s for workgroup %s.\n", START_PROFILE(election);
server_name,inet_ntoa(p->ip), subrec->subnet_name, workgroup_name )); server_name[15] = 0;
DEBUG(5,("process_election: vers=%d criterion=%08x timeup=%d\n", version,criterion,timeup)); DEBUG(3,("process_election: Election request from %s at IP %s on subnet %s for workgroup %s.\n",
server_name,inet_ntoa(p->ip), subrec->subnet_name, workgroup_name ));
if(( work = find_workgroup_on_subnet(subrec, workgroup_name)) == NULL) DEBUG(5,("process_election: vers=%d criterion=%08x timeup=%d\n", version,criterion,timeup));
{
DEBUG(0,("process_election: Cannot find workgroup %s on subnet %s.\n",
workgroup_name, subrec->subnet_name ));
goto done;
}
if (!strequal(work->work_group, lp_workgroup())) if(( work = find_workgroup_on_subnet(subrec, workgroup_name)) == NULL) {
{ DEBUG(0,("process_election: Cannot find workgroup %s on subnet %s.\n",
DEBUG(3,("process_election: ignoring election request for workgroup %s on subnet %s as this \ workgroup_name, subrec->subnet_name ));
goto done;
}
if (!strequal(work->work_group, lp_workgroup())) {
DEBUG(3,("process_election: ignoring election request for workgroup %s on subnet %s as this \
is not my workgroup.\n", work->work_group, subrec->subnet_name )); is not my workgroup.\n", work->work_group, subrec->subnet_name ));
goto done; goto done;
} }
if (win_election(work, version,criterion,timeup,server_name)) if (win_election(work, version,criterion,timeup,server_name)) {
{ /* We take precedence over the requesting server. */
/* We take precedence over the requesting server. */ if (!work->RunningElection) {
if (!work->RunningElection) /* We weren't running an election - start running one. */
{
/* We weren't running an election - start running one. */
work->needelection = True; work->needelection = True;
work->ElectionCount=0; work->ElectionCount=0;
} }
/* Note that if we were running an election for this workgroup on this /* Note that if we were running an election for this workgroup on this
subnet already, we just ignore the server we take precedence over. */ subnet already, we just ignore the server we take precedence over. */
} } else {
else /* We lost. Stop participating. */
{ work->needelection = False;
/* We lost. Stop participating. */
work->needelection = False;
if (work->RunningElection || AM_LOCAL_MASTER_BROWSER(work)) if (work->RunningElection || AM_LOCAL_MASTER_BROWSER(work)) {
{ work->RunningElection = False;
work->RunningElection = False; DEBUG(3,("process_election: >>> Lost election for workgroup %s on subnet %s <<<\n",
DEBUG(3,("process_election: >>> Lost election for workgroup %s on subnet %s <<<\n", work->work_group, subrec->subnet_name ));
work->work_group, subrec->subnet_name )); if (AM_LOCAL_MASTER_BROWSER(work))
if (AM_LOCAL_MASTER_BROWSER(work)) unbecome_local_master_browser(subrec, work, False);
unbecome_local_master_browser(subrec, work, False); }
} }
}
done: done:
END_PROFILE(election);
END_PROFILE(election);
} }
/**************************************************************************** /****************************************************************************
@@ -335,57 +326,53 @@ done:
BOOL check_elections(void) BOOL check_elections(void)
{ {
struct subnet_record *subrec; struct subnet_record *subrec;
BOOL run_any_election = False; BOOL run_any_election = False;
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
{ struct work_record *work;
struct work_record *work; for (work = subrec->workgrouplist; work; work = work->next) {
for (work = subrec->workgrouplist; work; work = work->next) run_any_election |= work->RunningElection;
{
run_any_election |= work->RunningElection;
/* /*
* Start an election if we have any chance of winning. * Start an election if we have any chance of winning.
* Note this is a change to the previous code, that would * Note this is a change to the previous code, that would
* only run an election if nmbd was in the potential browser * only run an election if nmbd was in the potential browser
* state. We need to run elections in any state if we're told * state. We need to run elections in any state if we're told
* to. JRA. * to. JRA.
*/ */
if (work->needelection && !work->RunningElection && lp_local_master()) if (work->needelection && !work->RunningElection && lp_local_master()) {
{ /*
/* * We can only run an election for a workgroup if we have
* We can only run an election for a workgroup if we have * registered the WORKGROUP<1e> name, as that's the name
* registered the WORKGROUP<1e> name, as that's the name * we must listen to.
* we must listen to. */
*/ struct nmb_name nmbname;
struct nmb_name nmbname;
make_nmb_name(&nmbname, work->work_group, 0x1e); make_nmb_name(&nmbname, work->work_group, 0x1e);
if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) { if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) {
DEBUG(8,("check_elections: Cannot send election packet yet as name %s not \ DEBUG(8,("check_elections: Cannot send election packet yet as name %s not \
yet registered on subnet %s\n", nmb_namestr(&nmbname), subrec->subnet_name )); yet registered on subnet %s\n", nmb_namestr(&nmbname), subrec->subnet_name ));
continue; continue;
} }
DEBUG(3,("check_elections: >>> Starting election for workgroup %s on subnet %s <<<\n", DEBUG(3,("check_elections: >>> Starting election for workgroup %s on subnet %s <<<\n",
work->work_group, subrec->subnet_name )); work->work_group, subrec->subnet_name ));
work->ElectionCount = 0; work->ElectionCount = 0;
work->RunningElection = True; work->RunningElection = True;
work->needelection = False; work->needelection = False;
} }
} }
} }
return run_any_election; return run_any_election;
} }
/**************************************************************************** /****************************************************************************
process a internal Samba message forcing an election Process a internal Samba message forcing an election.
***************************************************************************/ ***************************************************************************/
void nmbd_message_election(int msg_type, pid_t src, void *buf, size_t len) void nmbd_message_election(int msg_type, pid_t src, void *buf, size_t len)
{ {
struct subnet_record *subrec; struct subnet_record *subrec;

File diff suppressed because it is too large Load Diff

View File

@@ -201,7 +201,7 @@ static BOOL query_local_namelists(struct subnet_record *subrec, struct nmb_name
Try and query for a name. Try and query for a name.
****************************************************************************/ ****************************************************************************/
BOOL query_name(struct subnet_record *subrec, char *name, int type, BOOL query_name(struct subnet_record *subrec, const char *name, int type,
query_name_success_function success_fn, query_name_success_function success_fn,
query_name_fail_function fail_fn, query_name_fail_function fail_fn,
struct userdata_struct *userdata) struct userdata_struct *userdata)
@@ -276,7 +276,7 @@ BOOL query_name(struct subnet_record *subrec, char *name, int type,
****************************************************************************/ ****************************************************************************/
BOOL query_name_from_wins_server(struct in_addr ip_to, BOOL query_name_from_wins_server(struct in_addr ip_to,
char *name, int type, const char *name, int type,
query_name_success_function success_fn, query_name_success_function success_fn,
query_name_fail_function fail_fn, query_name_fail_function fail_fn,
struct userdata_struct *userdata) struct userdata_struct *userdata)