mirror of
https://github.com/samba-team/samba.git
synced 2025-01-11 05:18:09 +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:
parent
daf7b5fbd9
commit
236d6adadf
@ -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 packet_type {NMB_PACKET, DGRAM_PACKET};
|
||||
|
||||
enum master_state
|
||||
{
|
||||
MST_NONE,
|
||||
MST_POTENTIAL,
|
||||
MST_BACKUP,
|
||||
MST_MSB,
|
||||
MST_BROWSER,
|
||||
MST_UNBECOMING_MASTER
|
||||
enum master_state {
|
||||
MST_NONE,
|
||||
MST_POTENTIAL,
|
||||
MST_BACKUP,
|
||||
MST_MSB,
|
||||
MST_BROWSER,
|
||||
MST_UNBECOMING_MASTER
|
||||
};
|
||||
|
||||
enum domain_state
|
||||
{
|
||||
DOMAIN_NONE,
|
||||
DOMAIN_WAIT,
|
||||
DOMAIN_MST
|
||||
enum domain_state {
|
||||
DOMAIN_NONE,
|
||||
DOMAIN_WAIT,
|
||||
DOMAIN_MST
|
||||
};
|
||||
|
||||
enum logon_state
|
||||
{
|
||||
LOGON_NONE,
|
||||
LOGON_WAIT,
|
||||
LOGON_SRV
|
||||
enum logon_state {
|
||||
LOGON_NONE,
|
||||
LOGON_WAIT,
|
||||
LOGON_SRV
|
||||
};
|
||||
|
||||
struct subnet_record;
|
||||
|
||||
struct nmb_data
|
||||
{
|
||||
uint16 nb_flags; /* Netbios flags. */
|
||||
int num_ips; /* Number of ip entries. */
|
||||
struct in_addr *ip; /* The ip list for this name. */
|
||||
struct nmb_data {
|
||||
uint16 nb_flags; /* Netbios flags. */
|
||||
int num_ips; /* Number of ip entries. */
|
||||
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 refresh_time; /* The time the record should be refreshed. */
|
||||
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. */
|
||||
|
||||
SMB_BIG_UINT id; /* unique id */
|
||||
struct in_addr wins_ip; /* the adress of the wins server this record comes from */
|
||||
SMB_BIG_UINT id; /* unique id */
|
||||
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. */
|
||||
struct name_record
|
||||
{
|
||||
ubi_trNode node[1];
|
||||
struct subnet_record *subnet;
|
||||
struct nmb_name name; /* The netbios name. */
|
||||
struct nmb_data data; /* The netbios data. */
|
||||
};
|
||||
struct name_record {
|
||||
ubi_trNode node[1];
|
||||
struct subnet_record *subnet;
|
||||
struct nmb_name name; /* The netbios name. */
|
||||
struct nmb_data data; /* The netbios data. */
|
||||
};
|
||||
|
||||
/* Browser cache for synchronising browse lists. */
|
||||
struct browse_cache_record
|
||||
{
|
||||
ubi_dlNode node[1];
|
||||
pstring lmb_name;
|
||||
pstring work_group;
|
||||
struct in_addr ip;
|
||||
time_t sync_time;
|
||||
time_t death_time; /* The time the record must be removed. */
|
||||
};
|
||||
struct browse_cache_record {
|
||||
ubi_dlNode node[1];
|
||||
pstring lmb_name;
|
||||
pstring work_group;
|
||||
struct in_addr ip;
|
||||
time_t sync_time;
|
||||
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
|
||||
contained within lists of domains. */
|
||||
|
||||
struct server_record
|
||||
{
|
||||
struct server_record *next;
|
||||
struct server_record *prev;
|
||||
struct server_record {
|
||||
struct server_record *next;
|
||||
struct server_record *prev;
|
||||
|
||||
struct subnet_record *subnet;
|
||||
struct subnet_record *subnet;
|
||||
|
||||
struct server_info_struct serv;
|
||||
time_t death_time;
|
||||
struct server_info_struct serv;
|
||||
time_t death_time;
|
||||
};
|
||||
|
||||
/* A workgroup structure. It contains a list of servers. */
|
||||
struct work_record
|
||||
{
|
||||
struct work_record *next;
|
||||
struct work_record *prev;
|
||||
struct work_record {
|
||||
struct work_record *next;
|
||||
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. */
|
||||
enum master_state mst_state;
|
||||
/* Stage of development from non-local-master up to local-master browser. */
|
||||
enum master_state mst_state;
|
||||
|
||||
/* Stage of development from non-domain-master to domain-master browser. */
|
||||
enum domain_state dom_state;
|
||||
/* Stage of development from non-domain-master to domain-master browser. */
|
||||
enum domain_state dom_state;
|
||||
|
||||
/* Stage of development from non-logon-server to logon server. */
|
||||
enum logon_state log_state;
|
||||
/* Stage of development from non-logon-server to logon server. */
|
||||
enum logon_state log_state;
|
||||
|
||||
/* Work group info. */
|
||||
fstring work_group;
|
||||
int token; /* Used when communicating with backup browsers. */
|
||||
fstring local_master_browser_name; /* Current local master browser. */
|
||||
/* Work group info. */
|
||||
fstring work_group;
|
||||
int token; /* Used when communicating with backup browsers. */
|
||||
fstring local_master_browser_name; /* Current local master browser. */
|
||||
|
||||
/* Announce info. */
|
||||
time_t lastannounce_time;
|
||||
int announce_interval;
|
||||
BOOL needannounce;
|
||||
/* Announce info. */
|
||||
time_t lastannounce_time;
|
||||
int announce_interval;
|
||||
BOOL needannounce;
|
||||
|
||||
/* Timeout time for this workgroup. 0 means permanent. */
|
||||
time_t death_time;
|
||||
/* Timeout time for this workgroup. 0 means permanent. */
|
||||
time_t death_time;
|
||||
|
||||
/* Election info */
|
||||
BOOL RunningElection;
|
||||
BOOL needelection;
|
||||
int ElectionCount;
|
||||
uint32 ElectionCriterion;
|
||||
/* Election info */
|
||||
BOOL RunningElection;
|
||||
BOOL needelection;
|
||||
int ElectionCount;
|
||||
uint32 ElectionCriterion;
|
||||
|
||||
/* Domain master browser info. Used for efficient syncs. */
|
||||
struct nmb_name dmb_name;
|
||||
struct in_addr dmb_addr;
|
||||
/* Domain master browser info. Used for efficient syncs. */
|
||||
struct nmb_name dmb_name;
|
||||
struct in_addr dmb_addr;
|
||||
};
|
||||
|
||||
/* 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. */
|
||||
|
||||
struct userdata_struct {
|
||||
userdata_copy_fn copy_fn;
|
||||
userdata_free_fn free_fn;
|
||||
unsigned int userdata_len;
|
||||
char data[16]; /* 16 is to ensure alignment/padding on all systems */
|
||||
userdata_copy_fn copy_fn;
|
||||
userdata_free_fn free_fn;
|
||||
unsigned int userdata_len;
|
||||
char data[16]; /* 16 is to ensure alignment/padding on all systems */
|
||||
};
|
||||
|
||||
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. */
|
||||
|
||||
struct response_record
|
||||
{
|
||||
struct response_record *next;
|
||||
struct response_record *prev;
|
||||
struct response_record {
|
||||
struct response_record *next;
|
||||
struct response_record *prev;
|
||||
|
||||
uint16 response_id;
|
||||
uint16 response_id;
|
||||
|
||||
/* Callbacks for packets received or not. */
|
||||
response_function resp_fn;
|
||||
timeout_response_function timeout_fn;
|
||||
/* Callbacks for packets received or not. */
|
||||
response_function resp_fn;
|
||||
timeout_response_function timeout_fn;
|
||||
|
||||
/* Callbacks for the request succeeding or not. */
|
||||
success_function success_fn;
|
||||
fail_function fail_fn;
|
||||
/* Callbacks for the request succeeding or not. */
|
||||
success_function success_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_interval;
|
||||
int repeat_count;
|
||||
time_t repeat_time;
|
||||
time_t repeat_interval;
|
||||
int repeat_count;
|
||||
|
||||
/* Recursion protection. */
|
||||
BOOL in_expiration_processing;
|
||||
/* Recursion protection. */
|
||||
BOOL in_expiration_processing;
|
||||
};
|
||||
|
||||
/* A subnet structure. It contains a list of workgroups and netbios names. */
|
||||
@ -420,42 +411,41 @@ struct response_record
|
||||
*/
|
||||
|
||||
enum subnet_type {
|
||||
NORMAL_SUBNET = 0, /* Subnet listed in interfaces list. */
|
||||
UNICAST_SUBNET = 1, /* Subnet for unicast packets. */
|
||||
REMOTE_BROADCAST_SUBNET = 2, /* Subnet for remote broadcasts. */
|
||||
WINS_SERVER_SUBNET = 3 /* Only created if we are a WINS server. */
|
||||
NORMAL_SUBNET = 0, /* Subnet listed in interfaces list. */
|
||||
UNICAST_SUBNET = 1, /* Subnet for unicast packets. */
|
||||
REMOTE_BROADCAST_SUBNET = 2, /* Subnet for remote broadcasts. */
|
||||
WINS_SERVER_SUBNET = 3 /* Only created if we are a WINS server. */
|
||||
};
|
||||
|
||||
struct subnet_record
|
||||
{
|
||||
struct subnet_record *next;
|
||||
struct subnet_record *prev;
|
||||
struct subnet_record {
|
||||
struct subnet_record *next;
|
||||
struct subnet_record *prev;
|
||||
|
||||
char *subnet_name; /* For Debug identification. */
|
||||
enum subnet_type type; /* To catagorize the subnet. */
|
||||
char *subnet_name; /* For Debug identification. */
|
||||
enum subnet_type type; /* To catagorize the subnet. */
|
||||
|
||||
struct work_record *workgrouplist; /* List of workgroups. */
|
||||
ubi_trRoot namelist[1]; /* List of netbios names. */
|
||||
struct response_record *responselist; /* List of responses expected. */
|
||||
struct work_record *workgrouplist; /* List of workgroups. */
|
||||
ubi_trRoot namelist[1]; /* List of netbios names. */
|
||||
struct response_record *responselist; /* List of responses expected. */
|
||||
|
||||
BOOL namelist_changed;
|
||||
BOOL work_changed;
|
||||
BOOL namelist_changed;
|
||||
BOOL work_changed;
|
||||
|
||||
struct in_addr bcast_ip;
|
||||
struct in_addr mask_ip;
|
||||
struct in_addr myip;
|
||||
int nmb_sock; /* socket to listen for unicast 137. */
|
||||
int dgram_sock; /* socket to listen for unicast 138. */
|
||||
struct in_addr bcast_ip;
|
||||
struct in_addr mask_ip;
|
||||
struct in_addr myip;
|
||||
int nmb_sock; /* socket to listen for unicast 137. */
|
||||
int dgram_sock; /* socket to listen for unicast 138. */
|
||||
};
|
||||
|
||||
/* A resource record. */
|
||||
struct res_rec {
|
||||
struct nmb_name rr_name;
|
||||
int rr_type;
|
||||
int rr_class;
|
||||
int ttl;
|
||||
int rdlength;
|
||||
char rdata[MAX_DGRAM_SIZE];
|
||||
struct nmb_name rr_name;
|
||||
int rr_type;
|
||||
int rr_class;
|
||||
int ttl;
|
||||
int rdlength;
|
||||
char rdata[MAX_DGRAM_SIZE];
|
||||
};
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* An nmb packet. */
|
||||
struct nmb_packet
|
||||
{
|
||||
struct {
|
||||
int name_trn_id;
|
||||
int opcode;
|
||||
BOOL response;
|
||||
struct {
|
||||
BOOL bcast;
|
||||
BOOL recursion_available;
|
||||
BOOL recursion_desired;
|
||||
BOOL trunc;
|
||||
BOOL authoritative;
|
||||
} nm_flags;
|
||||
int rcode;
|
||||
int qdcount;
|
||||
int ancount;
|
||||
int nscount;
|
||||
int arcount;
|
||||
} header;
|
||||
struct nmb_packet {
|
||||
struct {
|
||||
int name_trn_id;
|
||||
int opcode;
|
||||
BOOL response;
|
||||
struct {
|
||||
BOOL bcast;
|
||||
BOOL recursion_available;
|
||||
BOOL recursion_desired;
|
||||
BOOL trunc;
|
||||
BOOL authoritative;
|
||||
} nm_flags;
|
||||
int rcode;
|
||||
int qdcount;
|
||||
int ancount;
|
||||
int nscount;
|
||||
int arcount;
|
||||
} header;
|
||||
|
||||
struct {
|
||||
struct nmb_name question_name;
|
||||
int question_type;
|
||||
int question_class;
|
||||
} question;
|
||||
struct {
|
||||
struct nmb_name question_name;
|
||||
int question_type;
|
||||
int question_class;
|
||||
} question;
|
||||
|
||||
struct res_rec *answers;
|
||||
struct res_rec *nsrecs;
|
||||
struct res_rec *additional;
|
||||
struct res_rec *answers;
|
||||
struct res_rec *nsrecs;
|
||||
struct res_rec *additional;
|
||||
};
|
||||
|
||||
/* msg_type field options - from rfc1002. */
|
||||
@ -511,23 +500,23 @@ struct nmb_packet
|
||||
/* A datagram - this normally contains SMB data in the data[] array. */
|
||||
|
||||
struct dgram_packet {
|
||||
struct {
|
||||
int msg_type;
|
||||
struct {
|
||||
enum node_type node_type;
|
||||
BOOL first;
|
||||
BOOL more;
|
||||
} flags;
|
||||
int dgm_id;
|
||||
struct in_addr source_ip;
|
||||
int source_port;
|
||||
int dgm_length;
|
||||
int packet_offset;
|
||||
} header;
|
||||
struct nmb_name source_name;
|
||||
struct nmb_name dest_name;
|
||||
int datasize;
|
||||
char data[MAX_DGRAM_SIZE];
|
||||
struct {
|
||||
int msg_type;
|
||||
struct {
|
||||
enum node_type node_type;
|
||||
BOOL first;
|
||||
BOOL more;
|
||||
} flags;
|
||||
int dgm_id;
|
||||
struct in_addr source_ip;
|
||||
int source_port;
|
||||
int dgm_length;
|
||||
int packet_offset;
|
||||
} header;
|
||||
struct nmb_name source_name;
|
||||
struct nmb_name dest_name;
|
||||
int datasize;
|
||||
char data[MAX_DGRAM_SIZE];
|
||||
};
|
||||
|
||||
/* 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 *next;
|
||||
struct packet_struct *prev;
|
||||
BOOL locked;
|
||||
struct in_addr ip;
|
||||
int port;
|
||||
int fd;
|
||||
time_t timestamp;
|
||||
enum packet_type packet_type;
|
||||
union {
|
||||
struct nmb_packet nmb;
|
||||
struct dgram_packet dgram;
|
||||
} packet;
|
||||
struct packet_struct *next;
|
||||
struct packet_struct *prev;
|
||||
BOOL locked;
|
||||
struct in_addr ip;
|
||||
int port;
|
||||
int fd;
|
||||
time_t timestamp;
|
||||
enum packet_type packet_type;
|
||||
union {
|
||||
struct nmb_packet nmb;
|
||||
struct dgram_packet dgram;
|
||||
} packet;
|
||||
};
|
||||
|
||||
/* NETLOGON opcodes */
|
||||
|
@ -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 fstrcpy(d,s) safe_strcpy((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
|
||||
* update a lot of code. To make this a little easier here are some
|
||||
|
@ -1484,9 +1484,11 @@ struct cnotify_fns {
|
||||
|
||||
#include "smb_macros.h"
|
||||
|
||||
typedef char nstring[16];
|
||||
|
||||
/* A netbios name structure. */
|
||||
struct nmb_name {
|
||||
char name[16];
|
||||
nstring name;
|
||||
char scope[64];
|
||||
unsigned int name_type;
|
||||
};
|
||||
@ -1494,7 +1496,7 @@ struct nmb_name {
|
||||
|
||||
/* A netbios node status array element. */
|
||||
struct node_status {
|
||||
char name[16];
|
||||
nstring name;
|
||||
unsigned char type;
|
||||
unsigned char flags;
|
||||
};
|
||||
|
@ -529,6 +529,11 @@ size_t push_ascii_pstring(void *dest, const char *src)
|
||||
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.
|
||||
*
|
||||
@ -582,6 +587,11 @@ size_t pull_ascii_fstring(char *dest, const void *src)
|
||||
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.
|
||||
*
|
||||
|
@ -303,6 +303,7 @@ static BOOL reload_nmbd_services(BOOL test)
|
||||
* We use buf here to return BOOL result to process() when reload_interfaces()
|
||||
* detects that there are no subnets.
|
||||
**************************************************************************** */
|
||||
|
||||
static void msg_reload_nmbd_services(int msg_type, pid_t src, void *buf, size_t len)
|
||||
{
|
||||
write_browse_list( 0, True );
|
||||
@ -650,126 +651,120 @@ static BOOL open_sockets(BOOL isdaemon, int port)
|
||||
log_stdout = True;
|
||||
}
|
||||
|
||||
if ( log_stdout && Fork ) {
|
||||
DEBUG(0,("ERROR: Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n"));
|
||||
exit(1);
|
||||
}
|
||||
if ( log_stdout && Fork ) {
|
||||
DEBUG(0,("ERROR: Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n"));
|
||||
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) );
|
||||
DEBUGADD( 0, ( "Copyright Andrew Tridgell and the Samba Team 1994-2003\n" ) );
|
||||
DEBUG( 0, ( "Netbios nameserver version %s started.\n", SAMBA_VERSION_STRING) );
|
||||
DEBUGADD( 0, ( "Copyright Andrew Tridgell and the Samba Team 1994-2003\n" ) );
|
||||
|
||||
if ( !reload_nmbd_services(False) )
|
||||
return(-1);
|
||||
if ( !reload_nmbd_services(False) )
|
||||
return(-1);
|
||||
|
||||
if(!init_names())
|
||||
return -1;
|
||||
if(!init_names())
|
||||
return -1;
|
||||
|
||||
reload_nmbd_services( True );
|
||||
reload_nmbd_services( True );
|
||||
|
||||
if (strequal(lp_workgroup(),"*"))
|
||||
{
|
||||
DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
|
||||
exit(1);
|
||||
}
|
||||
if (strequal(lp_workgroup(),"*")) {
|
||||
DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
set_samba_nb_type();
|
||||
set_samba_nb_type();
|
||||
|
||||
if (!is_daemon && !is_a_socket(0))
|
||||
{
|
||||
DEBUG(0,("standard input is not a socket, assuming -D option\n"));
|
||||
is_daemon = True;
|
||||
}
|
||||
if (!is_daemon && !is_a_socket(0)) {
|
||||
DEBUG(0,("standard input is not a socket, assuming -D option\n"));
|
||||
is_daemon = True;
|
||||
}
|
||||
|
||||
if (is_daemon && !opt_interactive)
|
||||
{
|
||||
DEBUG( 2, ( "Becoming a daemon.\n" ) );
|
||||
become_daemon(Fork);
|
||||
}
|
||||
if (is_daemon && !opt_interactive) {
|
||||
DEBUG( 2, ( "Becoming a daemon.\n" ) );
|
||||
become_daemon(Fork);
|
||||
}
|
||||
|
||||
#if HAVE_SETPGID
|
||||
/*
|
||||
* If we're interactive we want to set our own process group for
|
||||
* signal management.
|
||||
*/
|
||||
if (opt_interactive)
|
||||
setpgid( (pid_t)0, (pid_t)0 );
|
||||
/*
|
||||
* If we're interactive we want to set our own process group for
|
||||
* signal management.
|
||||
*/
|
||||
if (opt_interactive)
|
||||
setpgid( (pid_t)0, (pid_t)0 );
|
||||
#endif
|
||||
|
||||
#ifndef SYNC_DNS
|
||||
/* Setup the async dns. We do it here so it doesn't have all the other
|
||||
stuff initialised and thus chewing memory and sockets */
|
||||
if(lp_we_are_a_wins_server() && lp_dns_proxy()) {
|
||||
start_async_dns();
|
||||
}
|
||||
/* Setup the async dns. We do it here so it doesn't have all the other
|
||||
stuff initialised and thus chewing memory and sockets */
|
||||
if(lp_we_are_a_wins_server() && lp_dns_proxy()) {
|
||||
start_async_dns();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!directory_exist(lp_lockdir(), NULL)) {
|
||||
mkdir(lp_lockdir(), 0755);
|
||||
}
|
||||
if (!directory_exist(lp_lockdir(), NULL)) {
|
||||
mkdir(lp_lockdir(), 0755);
|
||||
}
|
||||
|
||||
pidfile_create("nmbd");
|
||||
message_init();
|
||||
message_register(MSG_FORCE_ELECTION, nmbd_message_election);
|
||||
message_register(MSG_WINS_NEW_ENTRY, nmbd_wins_new_entry);
|
||||
message_register(MSG_SHUTDOWN, nmbd_terminate);
|
||||
message_register(MSG_SMB_CONF_UPDATED, msg_reload_nmbd_services);
|
||||
pidfile_create("nmbd");
|
||||
message_init();
|
||||
message_register(MSG_FORCE_ELECTION, nmbd_message_election);
|
||||
message_register(MSG_WINS_NEW_ENTRY, nmbd_wins_new_entry);
|
||||
message_register(MSG_SHUTDOWN, nmbd_terminate);
|
||||
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 ) ) {
|
||||
kill_async_dns_child();
|
||||
return 1;
|
||||
}
|
||||
if ( !open_sockets( is_daemon, global_nmb_port ) ) {
|
||||
kill_async_dns_child();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Determine all the IP addresses we have. */
|
||||
load_interfaces();
|
||||
/* Determine all the IP addresses we have. */
|
||||
load_interfaces();
|
||||
|
||||
/* Create an nmbd subnet record for each of the above. */
|
||||
if( False == create_subnets() )
|
||||
{
|
||||
DEBUG(0,("ERROR: Failed when creating subnet lists. Exiting.\n"));
|
||||
kill_async_dns_child();
|
||||
exit(1);
|
||||
}
|
||||
/* Create an nmbd subnet record for each of the above. */
|
||||
if( False == create_subnets() ) {
|
||||
DEBUG(0,("ERROR: Failed when creating subnet lists. Exiting.\n"));
|
||||
kill_async_dns_child();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Load in any static local names. */
|
||||
load_lmhosts_file(dyn_LMHOSTSFILE);
|
||||
DEBUG(3,("Loaded hosts file %s\n", dyn_LMHOSTSFILE));
|
||||
/* Load in any static local names. */
|
||||
load_lmhosts_file(dyn_LMHOSTSFILE);
|
||||
DEBUG(3,("Loaded hosts file %s\n", dyn_LMHOSTSFILE));
|
||||
|
||||
/* If we are acting as a WINS server, initialise data structures. */
|
||||
if( !initialise_wins() )
|
||||
{
|
||||
DEBUG( 0, ( "nmbd: Failed when initialising WINS server.\n" ) );
|
||||
kill_async_dns_child();
|
||||
exit(1);
|
||||
}
|
||||
/* If we are acting as a WINS server, initialise data structures. */
|
||||
if( !initialise_wins() ) {
|
||||
DEBUG( 0, ( "nmbd: Failed when initialising WINS server.\n" ) );
|
||||
kill_async_dns_child();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Register nmbd primary workgroup and nmbd names on all
|
||||
* the broadcast subnets, and on the WINS server (if specified).
|
||||
* Also initiate the startup of our primary workgroup (start
|
||||
* elections if we are setup as being able to be a local
|
||||
* master browser.
|
||||
*/
|
||||
/*
|
||||
* Register nmbd primary workgroup and nmbd names on all
|
||||
* the broadcast subnets, and on the WINS server (if specified).
|
||||
* Also initiate the startup of our primary workgroup (start
|
||||
* elections if we are setup as being able to be a local
|
||||
* master browser.
|
||||
*/
|
||||
|
||||
if( False == register_my_workgroup_and_names() )
|
||||
{
|
||||
DEBUG(0,("ERROR: Failed when creating my my workgroup. Exiting.\n"));
|
||||
kill_async_dns_child();
|
||||
exit(1);
|
||||
}
|
||||
if( False == register_my_workgroup_and_names() ) {
|
||||
DEBUG(0,("ERROR: Failed when creating my my workgroup. Exiting.\n"));
|
||||
kill_async_dns_child();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* We can only take signals in the select. */
|
||||
BlockSignals( True, SIGTERM );
|
||||
/* We can only take signals in the select. */
|
||||
BlockSignals( True, SIGTERM );
|
||||
|
||||
process();
|
||||
process();
|
||||
|
||||
if (dbf)
|
||||
x_fclose(dbf);
|
||||
kill_async_dns_child();
|
||||
return(0);
|
||||
if (dbf)
|
||||
x_fclose(dbf);
|
||||
kill_async_dns_child();
|
||||
return(0);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
NBT netbios routines and daemon - version 2
|
||||
Copyright (C) Andrew Tridgell 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
|
||||
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 nmb_name *fail_name)
|
||||
{
|
||||
struct work_record *work = find_workgroup_on_subnet(subrec, fail_name->name);
|
||||
struct server_record *servrec;
|
||||
nstring failname;
|
||||
struct work_record *work;
|
||||
struct server_record *servrec;
|
||||
|
||||
if(!work)
|
||||
{
|
||||
DEBUG(0,("become_domain_master_fail: Error - cannot find \
|
||||
workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
|
||||
return;
|
||||
}
|
||||
pull_ascii_nstring(failname, fail_name->name);
|
||||
work = find_workgroup_on_subnet(subrec, failname);
|
||||
if(!work) {
|
||||
DEBUG(0,("become_domain_master_fail: Error - cannot find \
|
||||
workgroup %s on subnet %s\n", failname, subrec->subnet_name));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the state back to DOMAIN_NONE. */
|
||||
work->dom_state = DOMAIN_NONE;
|
||||
/* Set the state back to DOMAIN_NONE. */
|
||||
work->dom_state = DOMAIN_NONE;
|
||||
|
||||
if((servrec = find_server_in_workgroup( work, global_myname())) == NULL)
|
||||
{
|
||||
DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
|
||||
if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
|
||||
DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
|
||||
in workgroup %s on subnet %s\n",
|
||||
global_myname(), work->work_group, subrec->subnet_name));
|
||||
return;
|
||||
}
|
||||
global_myname(), work->work_group, subrec->subnet_name));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update our server status. */
|
||||
servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
|
||||
/* Update our server status. */
|
||||
servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
|
||||
|
||||
/* Tell the namelist writer to write out a change. */
|
||||
subrec->work_changed = True;
|
||||
/* Tell the namelist writer to write out a change. */
|
||||
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",
|
||||
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,
|
||||
int ttl, struct in_addr registered_ip)
|
||||
{
|
||||
struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
|
||||
struct server_record *servrec;
|
||||
nstring regname;
|
||||
struct work_record *work;
|
||||
struct server_record *servrec;
|
||||
|
||||
if(!work)
|
||||
{
|
||||
DEBUG(0,("become_domain_master_stage2: Error - cannot find \
|
||||
workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
|
||||
return;
|
||||
}
|
||||
pull_ascii_nstring(regname, registered_name->name);
|
||||
work = find_workgroup_on_subnet( subrec, regname);
|
||||
|
||||
if((servrec = find_server_in_workgroup( work, global_myname())) == NULL)
|
||||
{
|
||||
DEBUG(0,("become_domain_master_stage2: Error - cannot find server %s \
|
||||
if(!work) {
|
||||
DEBUG(0,("become_domain_master_stage2: Error - cannot find \
|
||||
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",
|
||||
global_myname(), registered_name->name, subrec->subnet_name));
|
||||
work->dom_state = DOMAIN_NONE;
|
||||
return;
|
||||
}
|
||||
global_myname(), regname, subrec->subnet_name));
|
||||
work->dom_state = DOMAIN_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the state in the workgroup structure. */
|
||||
work->dom_state = DOMAIN_MST; /* Become domain master. */
|
||||
/* Set the state in the workgroup structure. */
|
||||
work->dom_state = DOMAIN_MST; /* Become domain master. */
|
||||
|
||||
/* Update our server status. */
|
||||
servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
|
||||
/* Update our server status. */
|
||||
servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
|
||||
|
||||
/* Tell the namelist writer to write out a change. */
|
||||
subrec->work_changed = True;
|
||||
/* Tell the namelist writer to write out a change. */
|
||||
subrec->work_changed = True;
|
||||
|
||||
if( DEBUGLVL( 0 ) )
|
||||
{
|
||||
dbgtext( "*****\n\nSamba server %s ", global_myname() );
|
||||
dbgtext( "is now a domain master browser for " );
|
||||
dbgtext( "workgroup %s ", work->work_group );
|
||||
dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
|
||||
}
|
||||
if( DEBUGLVL( 0 ) ) {
|
||||
dbgtext( "*****\n\nSamba server %s ", global_myname() );
|
||||
dbgtext( "is now a domain master browser for " );
|
||||
dbgtext( "workgroup %s ", work->work_group );
|
||||
dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
|
||||
}
|
||||
|
||||
if( subrec == unicast_subnet )
|
||||
{
|
||||
struct nmb_name nmbname;
|
||||
struct in_addr my_first_ip;
|
||||
if( subrec == unicast_subnet ) {
|
||||
struct nmb_name nmbname;
|
||||
struct in_addr my_first_ip;
|
||||
|
||||
/* Put our name and first IP address into the
|
||||
workgroup struct as domain master browser. This
|
||||
will stop us syncing with ourself if we are also
|
||||
a local master browser. */
|
||||
/* Put our name and first IP address into the
|
||||
workgroup struct as domain master browser. This
|
||||
will stop us syncing with ourself if we are also
|
||||
a local master browser. */
|
||||
|
||||
make_nmb_name(&nmbname, global_myname(), 0x20);
|
||||
make_nmb_name(&nmbname, global_myname(), 0x20);
|
||||
|
||||
work->dmb_name = nmbname;
|
||||
/* Pick the first interface ip address as the domain master browser ip. */
|
||||
my_first_ip = *iface_n_ip(0);
|
||||
work->dmb_name = nmbname;
|
||||
/* Pick the first interface ip address as the domain master browser ip. */
|
||||
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
|
||||
WINS server. We now expect to become the domain
|
||||
master on the local subnets. If this fails, it's
|
||||
probably a 1.9.16p2 to 1.9.16p11 server's fault.
|
||||
/* We successfully registered by unicast with the
|
||||
WINS server. We now expect to become the domain
|
||||
master on the local subnets. If this fails, it's
|
||||
probably a 1.9.16p2 to 1.9.16p11 server's fault.
|
||||
|
||||
This is a configuration issue that should be addressed
|
||||
by the network administrator - you shouldn't have
|
||||
several machines configured as a domain master browser
|
||||
for the same WINS scope (except if they are 1.9.17 or
|
||||
greater, and you know what you're doing.
|
||||
This is a configuration issue that should be addressed
|
||||
by the network administrator - you shouldn't have
|
||||
several machines configured as a domain master browser
|
||||
for the same WINS scope (except if they are 1.9.17 or
|
||||
greater, and you know what you're doing.
|
||||
|
||||
see docs/DOMAIN.txt.
|
||||
see docs/DOMAIN.txt.
|
||||
|
||||
*/
|
||||
become_domain_master_browser_bcast(work->work_group);
|
||||
}
|
||||
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
|
||||
* 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);
|
||||
}
|
||||
*/
|
||||
become_domain_master_browser_bcast(work->work_group);
|
||||
} 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
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Start the name registration process when becoming a Domain Master Browser
|
||||
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));
|
||||
|
||||
/* First, find the workgroup on the subnet. */
|
||||
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",
|
||||
wg_name, subrec->subnet_name));
|
||||
return;
|
||||
}
|
||||
/* First, find the workgroup on the subnet. */
|
||||
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",
|
||||
wg_name, subrec->subnet_name));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
|
||||
work->dom_state = DOMAIN_WAIT;
|
||||
DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
|
||||
work->dom_state = DOMAIN_WAIT;
|
||||
|
||||
/* WORKGROUP<1b> is the domain master browser name. */
|
||||
register_name(subrec, work->work_group,0x1b,samba_nb_type,
|
||||
become_domain_master_stage2,
|
||||
become_domain_master_fail, NULL);
|
||||
/* WORKGROUP<1b> is the domain master browser name. */
|
||||
register_name(subrec, work->work_group,0x1b,samba_nb_type,
|
||||
become_domain_master_stage2,
|
||||
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 res_rec *rrec)
|
||||
{
|
||||
/* If the given ip is not ours, then we can't become a domain
|
||||
controler as the name is already registered.
|
||||
*/
|
||||
nstring name;
|
||||
pull_ascii_nstring(name, nmbname->name);
|
||||
|
||||
/* BUG note. Samba 1.9.16p11 servers seem to return the broadcast
|
||||
address or zero ip for this query. Pretend this is ok. */
|
||||
/* If the given ip is not ours, then we can't become a domain
|
||||
controler as the name is already registered.
|
||||
*/
|
||||
|
||||
if(ismyip(ip) || ip_equal(allones_ip, ip) || is_zero_ip(ip))
|
||||
{
|
||||
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" );
|
||||
}
|
||||
/* BUG note. Samba 1.9.16p11 servers seem to return the broadcast
|
||||
address or zero ip for this query. Pretend this is ok. */
|
||||
|
||||
become_domain_master_stage1(subrec, nmbname->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), nmbname->name );
|
||||
dbgtext( "registered on subnet %s.\n", subrec->subnet_name );
|
||||
}
|
||||
}
|
||||
if(ismyip(ip) || ip_equal(allones_ip, ip) || is_zero_ip(ip)) {
|
||||
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, 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 nmb_name *question_name, int fail_code)
|
||||
{
|
||||
/* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
|
||||
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;
|
||||
}
|
||||
nstring name;
|
||||
|
||||
/* Otherwise - not having the name allows us to register it. */
|
||||
become_domain_master_stage1(subrec, question_name->name);
|
||||
/* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
|
||||
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)
|
||||
{
|
||||
struct subnet_record *subrec;
|
||||
struct subnet_record *subrec;
|
||||
|
||||
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
|
||||
{
|
||||
struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
|
||||
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
|
||||
struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
|
||||
|
||||
if (work && (work->dom_state == DOMAIN_NONE))
|
||||
{
|
||||
struct nmb_name nmbname;
|
||||
make_nmb_name(&nmbname,workgroup_name,0x1b);
|
||||
if (work && (work->dom_state == DOMAIN_NONE)) {
|
||||
struct nmb_name nmbname;
|
||||
make_nmb_name(&nmbname,workgroup_name,0x1b);
|
||||
|
||||
/*
|
||||
* Check for our name on the given broadcast subnet first, only initiate
|
||||
* further processing if we cannot find it.
|
||||
*/
|
||||
/*
|
||||
* Check for our name on the given broadcast subnet first, only initiate
|
||||
* further processing if we cannot find it.
|
||||
*/
|
||||
|
||||
if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL)
|
||||
{
|
||||
if( DEBUGLVL( 0 ) )
|
||||
{
|
||||
dbgtext( "become_domain_master_browser_bcast:\n" );
|
||||
dbgtext( "Attempting to become domain master browser on " );
|
||||
dbgtext( "workgroup %s on subnet %s\n",
|
||||
workgroup_name, subrec->subnet_name );
|
||||
}
|
||||
if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL) {
|
||||
if( DEBUGLVL( 0 ) ) {
|
||||
dbgtext( "become_domain_master_browser_bcast:\n" );
|
||||
dbgtext( "Attempting to become domain master browser on " );
|
||||
dbgtext( "workgroup %s on subnet %s\n",
|
||||
workgroup_name, subrec->subnet_name );
|
||||
}
|
||||
|
||||
/* Send out a query to establish whether there's a
|
||||
domain controller on the local subnet. If not,
|
||||
we can become a domain controller.
|
||||
*/
|
||||
/* Send out a query to establish whether there's a
|
||||
domain controller on the local subnet. If not,
|
||||
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));
|
||||
|
||||
query_name(subrec, nmbname.name, nmbname.name_type,
|
||||
become_domain_master_query_success,
|
||||
become_domain_master_query_fail,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
query_name(subrec, workgroup_name, nmbname.name_type,
|
||||
become_domain_master_query_success,
|
||||
become_domain_master_query_fail,
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
struct nmb_name nmbname;
|
||||
if (work && (work->dom_state == DOMAIN_NONE)) {
|
||||
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
|
||||
* further processing if we cannot find it.
|
||||
*/
|
||||
/*
|
||||
* Check for our name on the unicast subnet first, only initiate
|
||||
* further processing if we cannot find it.
|
||||
*/
|
||||
|
||||
if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL)
|
||||
{
|
||||
if( DEBUGLVL( 0 ) )
|
||||
{
|
||||
dbgtext( "become_domain_master_browser_wins:\n" );
|
||||
dbgtext( "Attempting to become domain master browser " );
|
||||
dbgtext( "on workgroup %s, subnet %s.\n",
|
||||
workgroup_name, unicast_subnet->subnet_name );
|
||||
}
|
||||
if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL) {
|
||||
if( DEBUGLVL( 0 ) ) {
|
||||
dbgtext( "become_domain_master_browser_wins:\n" );
|
||||
dbgtext( "Attempting to become domain master browser " );
|
||||
dbgtext( "on workgroup %s, subnet %s.\n",
|
||||
workgroup_name, unicast_subnet->subnet_name );
|
||||
}
|
||||
|
||||
/* Send out a query to establish whether there's a
|
||||
domain master broswer registered with WINS. If not,
|
||||
we can become a domain master browser.
|
||||
*/
|
||||
/* Send out a query to establish whether there's a
|
||||
domain master broswer registered with WINS. If not,
|
||||
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",
|
||||
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,
|
||||
become_domain_master_query_success,
|
||||
become_domain_master_query_fail,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
query_name(unicast_subnet, workgroup_name, nmbname.name_type,
|
||||
become_domain_master_query_success,
|
||||
become_domain_master_query_fail,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -363,34 +355,32 @@ for domain master browser name %s on workgroup %s\n",
|
||||
|
||||
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)))
|
||||
return;
|
||||
if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60)))
|
||||
return;
|
||||
|
||||
lastrun = t;
|
||||
lastrun = t;
|
||||
|
||||
/* Do the "internet group" - <1c> names. */
|
||||
if (lp_domain_logons())
|
||||
add_logon_names();
|
||||
/* Do the "internet group" - <1c> names. */
|
||||
if (lp_domain_logons())
|
||||
add_logon_names();
|
||||
|
||||
/* Do the domain master names. */
|
||||
if(lp_domain_master())
|
||||
{
|
||||
if(we_are_a_wins_client())
|
||||
{
|
||||
/* We register the WORKGROUP<1b> name with the WINS
|
||||
server first, and call add_domain_master_bcast()
|
||||
only if this is successful.
|
||||
/* Do the domain master names. */
|
||||
if(lp_domain_master()) {
|
||||
if(we_are_a_wins_client()) {
|
||||
/* We register the WORKGROUP<1b> name with the WINS
|
||||
server first, and call add_domain_master_bcast()
|
||||
only if this is successful.
|
||||
|
||||
This results in domain logon services being gracefully provided,
|
||||
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,
|
||||
cannot provide domain master / domain logon services.
|
||||
*/
|
||||
become_domain_master_browser_wins(lp_workgroup());
|
||||
}
|
||||
else
|
||||
become_domain_master_browser_bcast(lp_workgroup());
|
||||
}
|
||||
This results in domain logon services being gracefully provided,
|
||||
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,
|
||||
cannot provide domain master / domain logon services.
|
||||
*/
|
||||
become_domain_master_browser_wins(lp_workgroup());
|
||||
} else {
|
||||
become_domain_master_browser_bcast(lp_workgroup());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
NBT netbios routines and daemon - version 2
|
||||
Copyright (C) Andrew Tridgell 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
|
||||
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,
|
||||
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)
|
||||
{
|
||||
/* The name needs to be created on the unicast subnet. */
|
||||
(void)add_name_to_subnet( unicast_subnet, nmbname->name,
|
||||
nmbname->name_type, nb_type,
|
||||
PERMANENT_TTL, PERMANENT_NAME, 1, &subrec->myip);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The name already exists on the unicast subnet. Add our local
|
||||
IP for the given broadcast subnet to the name. */
|
||||
add_ip_to_name_record( namerec, subrec->myip);
|
||||
}
|
||||
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. */
|
||||
(void)add_name_to_subnet( unicast_subnet, name,
|
||||
nmbname->name_type, nb_type,
|
||||
PERMANENT_TTL, PERMANENT_NAME, 1, &subrec->myip);
|
||||
} else {
|
||||
/* The name already exists on the unicast subnet. Add our local
|
||||
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,
|
||||
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)
|
||||
{
|
||||
/* Remove this broadcast subnet IP address from the name. */
|
||||
remove_ip_from_name_record( namerec, subrec->myip);
|
||||
if(namerec->data.num_ips == 0)
|
||||
remove_name_from_namelist( unicast_subnet, namerec);
|
||||
}
|
||||
if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) != NULL) {
|
||||
/* Remove this broadcast subnet IP address from the name. */
|
||||
remove_ip_from_name_record( namerec, subrec->myip);
|
||||
if(namerec->data.num_ips == 0)
|
||||
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.
|
||||
******************************************************************/
|
||||
|
||||
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 )
|
||||
{
|
||||
struct work_record *work;
|
||||
struct server_record *servrec;
|
||||
struct nmb_name nmbname;
|
||||
struct work_record *work;
|
||||
struct server_record *servrec;
|
||||
struct nmb_name nmbname;
|
||||
|
||||
if((work = find_workgroup_on_subnet( subrec, workgroup_name)) == NULL)
|
||||
{
|
||||
DEBUG(0,("reset_workgroup_state: Error - cannot find workgroup %s on \
|
||||
if((work = find_workgroup_on_subnet( subrec, workgroup_name)) == NULL) {
|
||||
DEBUG(0,("reset_workgroup_state: Error - cannot find workgroup %s on \
|
||||
subnet %s.\n", workgroup_name, subrec->subnet_name ));
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if((servrec = find_server_in_workgroup( work, global_myname())) == NULL)
|
||||
{
|
||||
DEBUG(0,("reset_workgroup_state: Error - cannot find server %s \
|
||||
if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
|
||||
DEBUG(0,("reset_workgroup_state: Error - cannot find server %s \
|
||||
in workgroup %s on subnet %s\n",
|
||||
global_myname(), work->work_group, subrec->subnet_name));
|
||||
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
|
||||
return;
|
||||
}
|
||||
global_myname(), work->work_group, subrec->subnet_name));
|
||||
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update our server status - remove any master flag and replace
|
||||
it with the potential browser flag. */
|
||||
servrec->serv.type &= ~SV_TYPE_MASTER_BROWSER;
|
||||
servrec->serv.type |= (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0);
|
||||
/* Update our server status - remove any master flag and replace
|
||||
it with the potential browser flag. */
|
||||
servrec->serv.type &= ~SV_TYPE_MASTER_BROWSER;
|
||||
servrec->serv.type |= (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0);
|
||||
|
||||
/* Tell the namelist writer to write out a change. */
|
||||
subrec->work_changed = True;
|
||||
/* Tell the namelist writer to write out a change. */
|
||||
subrec->work_changed = True;
|
||||
|
||||
/* Reset our election flags. */
|
||||
work->ElectionCriterion &= ~0x4;
|
||||
/* Reset our election flags. */
|
||||
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
|
||||
this workgroup. */
|
||||
/* Forget who the local master browser was for
|
||||
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
|
||||
* of the IP addresses of the WORKGROUP<1d> name on the unicast
|
||||
* subnet. This undoes what we did below when we became a local
|
||||
* master browser.
|
||||
*/
|
||||
/*
|
||||
* Ensure the IP address of this subnet is not registered as one
|
||||
* of the IP addresses of the WORKGROUP<1d> name on the unicast
|
||||
* subnet. This undoes what we did below when we became a local
|
||||
* 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)
|
||||
work->needelection = True;
|
||||
if(force_new_election)
|
||||
work->needelection = True;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
@ -138,24 +134,25 @@ static void unbecome_local_master_success(struct subnet_record *subrec,
|
||||
struct nmb_name *released_name,
|
||||
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",
|
||||
nmb_namestr(released_name)));
|
||||
DEBUG(3,("unbecome_local_master_success: released name %s.\n",
|
||||
nmb_namestr(released_name)));
|
||||
|
||||
/* Now reset the workgroup and server state. */
|
||||
reset_workgroup_state( subrec, released_name->name, force_new_election );
|
||||
/* Now reset the workgroup and server state. */
|
||||
pull_ascii_nstring(relname, released_name->name);
|
||||
reset_workgroup_state( subrec, relname, force_new_election );
|
||||
|
||||
if( DEBUGLVL( 0 ) )
|
||||
{
|
||||
dbgtext( "*****\n\n" );
|
||||
dbgtext( "Samba name server %s ", global_myname() );
|
||||
dbgtext( "has stopped being a local master browser " );
|
||||
dbgtext( "for workgroup %s ", released_name->name );
|
||||
dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
|
||||
}
|
||||
if( DEBUGLVL( 0 ) ) {
|
||||
dbgtext( "*****\n\n" );
|
||||
dbgtext( "Samba name server %s ", global_myname() );
|
||||
dbgtext( "has stopped being a local master browser " );
|
||||
dbgtext( "for workgroup %s ", relname );
|
||||
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,
|
||||
struct nmb_name *fail_name)
|
||||
{
|
||||
struct name_record *namerec;
|
||||
struct userdata_struct *userdata = rrec->userdata;
|
||||
BOOL force_new_election = False;
|
||||
struct name_record *namerec;
|
||||
struct userdata_struct *userdata = rrec->userdata;
|
||||
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)));
|
||||
|
||||
/* Do it anyway. */
|
||||
namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
|
||||
if(namerec)
|
||||
remove_name_from_namelist(subrec, namerec);
|
||||
/* Do it anyway. */
|
||||
namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
|
||||
if(namerec)
|
||||
remove_name_from_namelist(subrec, namerec);
|
||||
|
||||
/* Now reset the workgroup and server state. */
|
||||
reset_workgroup_state( subrec, fail_name->name, force_new_election );
|
||||
/* Now reset the workgroup and server state. */
|
||||
pull_ascii_nstring(failname, fail_name->name);
|
||||
reset_workgroup_state( subrec, failname, force_new_election );
|
||||
|
||||
if( DEBUGLVL( 0 ) )
|
||||
{
|
||||
dbgtext( "*****\n\n" );
|
||||
dbgtext( "Samba name server %s ", global_myname() );
|
||||
dbgtext( "has stopped being a local master browser " );
|
||||
dbgtext( "for workgroup %s ", fail_name->name );
|
||||
dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
|
||||
}
|
||||
if( DEBUGLVL( 0 ) ) {
|
||||
dbgtext( "*****\n\n" );
|
||||
dbgtext( "Samba name server %s ", global_myname() );
|
||||
dbgtext( "has stopped being a local master browser " );
|
||||
dbgtext( "for workgroup %s ", failname );
|
||||
dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_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)
|
||||
{
|
||||
struct nmb_name nmbname;
|
||||
struct name_record *namerec;
|
||||
struct nmb_name nmbname;
|
||||
struct name_record *namerec;
|
||||
|
||||
make_nmb_name(&nmbname, workgroup_name, 0x1d);
|
||||
if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL)
|
||||
{
|
||||
struct userdata_struct *userdata;
|
||||
size_t size = sizeof(struct userdata_struct) + sizeof(BOOL);
|
||||
make_nmb_name(&nmbname, workgroup_name, 0x1d);
|
||||
if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL) {
|
||||
struct userdata_struct *userdata;
|
||||
size_t size = sizeof(struct userdata_struct) + sizeof(BOOL);
|
||||
|
||||
if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
|
||||
{
|
||||
DEBUG(0,("release_1d_name: malloc fail.\n"));
|
||||
return;
|
||||
}
|
||||
if((userdata = (struct userdata_struct *)malloc(size)) == NULL) {
|
||||
DEBUG(0,("release_1d_name: malloc fail.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
userdata->copy_fn = NULL;
|
||||
userdata->free_fn = NULL;
|
||||
userdata->userdata_len = sizeof(BOOL);
|
||||
memcpy((char *)userdata->data, &force_new_election, sizeof(BOOL));
|
||||
userdata->copy_fn = NULL;
|
||||
userdata->free_fn = NULL;
|
||||
userdata->userdata_len = sizeof(BOOL);
|
||||
memcpy((char *)userdata->data, &force_new_election, sizeof(BOOL));
|
||||
|
||||
release_name(subrec, namerec,
|
||||
unbecome_local_master_success,
|
||||
unbecome_local_master_fail,
|
||||
userdata);
|
||||
release_name(subrec, namerec,
|
||||
unbecome_local_master_success,
|
||||
unbecome_local_master_fail,
|
||||
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 in_addr released_ip)
|
||||
{
|
||||
DEBUG(4,("release_msbrowse_name_success: Released name %s on subnet %s\n.",
|
||||
nmb_namestr(released_name), subrec->subnet_name ));
|
||||
DEBUG(4,("release_msbrowse_name_success: Released name %s on subnet %s\n.",
|
||||
nmb_namestr(released_name), subrec->subnet_name ));
|
||||
|
||||
/* Remove the permanent MSBROWSE name added into the unicast subnet. */
|
||||
remove_permanent_name_from_unicast( subrec, released_name);
|
||||
/* Remove the permanent MSBROWSE name added into the unicast subnet. */
|
||||
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 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.",
|
||||
nmb_namestr(fail_name), subrec->subnet_name ));
|
||||
DEBUG(4,("release_msbrowse_name_fail: Failed to release name %s on subnet %s\n.",
|
||||
nmb_namestr(fail_name), subrec->subnet_name ));
|
||||
|
||||
/* Release the name anyway. */
|
||||
namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
|
||||
if(namerec)
|
||||
remove_name_from_namelist(subrec, namerec);
|
||||
/* Release the name anyway. */
|
||||
namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
|
||||
if(namerec)
|
||||
remove_name_from_namelist(subrec, namerec);
|
||||
|
||||
/* Remove the permanent MSBROWSE name added into the unicast subnet. */
|
||||
remove_permanent_name_from_unicast( subrec, fail_name);
|
||||
/* Remove the permanent MSBROWSE name added into the unicast subnet. */
|
||||
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,
|
||||
BOOL force_new_election)
|
||||
{
|
||||
struct name_record *namerec;
|
||||
struct nmb_name nmbname;
|
||||
struct name_record *namerec;
|
||||
struct nmb_name nmbname;
|
||||
|
||||
/* 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));
|
||||
|
||||
if(find_server_in_workgroup( work, global_myname()) == NULL)
|
||||
{
|
||||
DEBUG(0,("unbecome_local_master_browser: Error - cannot find server %s \
|
||||
if(find_server_in_workgroup( work, global_myname()) == NULL) {
|
||||
DEBUG(0,("unbecome_local_master_browser: Error - cannot find server %s \
|
||||
in workgroup %s on subnet %s\n",
|
||||
global_myname(), work->work_group, subrec->subnet_name));
|
||||
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
|
||||
return;
|
||||
}
|
||||
global_myname(), work->work_group, subrec->subnet_name));
|
||||
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the state to unbecoming. */
|
||||
work->mst_state = MST_UNBECOMING_MASTER;
|
||||
/* Set the state to unbecoming. */
|
||||
work->mst_state = MST_UNBECOMING_MASTER;
|
||||
|
||||
/*
|
||||
* Release the WORKGROUP<1d> name asap to allow another machine to
|
||||
* claim it.
|
||||
*/
|
||||
/*
|
||||
* Release the WORKGROUP<1d> name asap to allow another machine to
|
||||
* 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. */
|
||||
make_nmb_name(&nmbname, MSBROWSE, 0x1);
|
||||
if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL)
|
||||
{
|
||||
release_name(subrec, namerec,
|
||||
release_msbrowse_name_success,
|
||||
release_msbrowse_name_fail,
|
||||
NULL);
|
||||
}
|
||||
/* Deregister any browser names we may have. */
|
||||
make_nmb_name(&nmbname, MSBROWSE, 0x1);
|
||||
if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL) {
|
||||
release_name(subrec, namerec,
|
||||
release_msbrowse_name_success,
|
||||
release_msbrowse_name_fail,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure we have sent and processed these release packets
|
||||
* before returning - we don't want to process any election
|
||||
* packets before dealing with the 1d release.
|
||||
*/
|
||||
/*
|
||||
* Ensure we have sent and processed these release packets
|
||||
* before returning - we don't want to process any election
|
||||
* 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,
|
||||
int ttl, struct in_addr registered_ip)
|
||||
{
|
||||
int i = 0;
|
||||
struct server_record *sl;
|
||||
struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
|
||||
struct server_record *servrec;
|
||||
int i = 0;
|
||||
struct server_record *sl;
|
||||
struct work_record *work;
|
||||
struct server_record *servrec;
|
||||
nstring regname;
|
||||
|
||||
if(!work)
|
||||
{
|
||||
DEBUG(0,("become_local_master_stage2: Error - cannot find \
|
||||
workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
|
||||
return;
|
||||
}
|
||||
pull_ascii_nstring(regname, registered_name->name);
|
||||
work = find_workgroup_on_subnet( subrec, regname);
|
||||
|
||||
if((servrec = find_server_in_workgroup( work, global_myname())) == NULL)
|
||||
{
|
||||
DEBUG(0,("become_local_master_stage2: Error - cannot find server %s \
|
||||
if(!work) {
|
||||
DEBUG(0,("become_local_master_stage2: Error - cannot find \
|
||||
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",
|
||||
global_myname(), registered_name->name, subrec->subnet_name));
|
||||
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
|
||||
return;
|
||||
}
|
||||
global_myname(), regname, subrec->subnet_name));
|
||||
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
|
||||
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));
|
||||
|
||||
work->mst_state = MST_BROWSER; /* registering WORKGROUP(1d) succeeded */
|
||||
work->mst_state = MST_BROWSER; /* registering WORKGROUP(1d) succeeded */
|
||||
|
||||
/* update our server status */
|
||||
servrec->serv.type |= SV_TYPE_MASTER_BROWSER;
|
||||
servrec->serv.type &= ~SV_TYPE_POTENTIAL_BROWSER;
|
||||
/* update our server status */
|
||||
servrec->serv.type |= SV_TYPE_MASTER_BROWSER;
|
||||
servrec->serv.type &= ~SV_TYPE_POTENTIAL_BROWSER;
|
||||
|
||||
/* Tell the namelist writer to write out a change. */
|
||||
subrec->work_changed = True;
|
||||
/* Tell the namelist writer to write out a change. */
|
||||
subrec->work_changed = True;
|
||||
|
||||
/* Add this name to the workgroup as local master browser. */
|
||||
set_workgroup_local_master_browser_name( work, global_myname());
|
||||
/* Add this name to the workgroup as local master browser. */
|
||||
set_workgroup_local_master_browser_name( work, global_myname());
|
||||
|
||||
/* Count the number of servers we have on our list. If it's
|
||||
less than 10 (just a heuristic) request the servers
|
||||
to announce themselves.
|
||||
*/
|
||||
for( sl = work->serverlist; sl != NULL; sl = sl->next)
|
||||
i++;
|
||||
/* Count the number of servers we have on our list. If it's
|
||||
less than 10 (just a heuristic) request the servers
|
||||
to announce themselves.
|
||||
*/
|
||||
for( sl = work->serverlist; sl != NULL; sl = sl->next)
|
||||
i++;
|
||||
|
||||
if (i < 10)
|
||||
{
|
||||
/* Ask all servers on our local net to announce to us. */
|
||||
broadcast_announce_request(subrec, work);
|
||||
}
|
||||
if (i < 10) {
|
||||
/* Ask all servers on our local net to announce to us. */
|
||||
broadcast_announce_request(subrec, work);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
* this name, and discards the registration. We use the number of IP
|
||||
* 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
|
||||
* master browser for this broadcast subnet.
|
||||
*/
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
* this name, and discards the registration. We use the number of IP
|
||||
* 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
|
||||
* 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
|
||||
master browser as soon as possible that we are a local master browser. */
|
||||
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 );
|
||||
}
|
||||
/* 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. */
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Failed to register the WORKGROUP<1d> name.
|
||||
****************************************************************************/
|
||||
|
||||
static void become_local_master_fail2(struct subnet_record *subrec,
|
||||
struct response_record *rrec,
|
||||
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));
|
||||
|
||||
if(!work)
|
||||
{
|
||||
DEBUG(0,("become_local_master_fail2: Error - cannot find \
|
||||
workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
|
||||
return;
|
||||
}
|
||||
pull_ascii_nstring(failname, fail_name->name);
|
||||
work = find_workgroup_on_subnet( subrec, failname);
|
||||
|
||||
/* Roll back all the way by calling unbecome_local_master_browser(). */
|
||||
unbecome_local_master_browser(subrec, work, False);
|
||||
if(!work) {
|
||||
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,
|
||||
int ttl, struct in_addr registered_ip)
|
||||
{
|
||||
char *work_name = userdata->data;
|
||||
struct work_record *work = find_workgroup_on_subnet( subrec, work_name);
|
||||
char *work_name = userdata->data;
|
||||
struct work_record *work = find_workgroup_on_subnet( subrec, work_name);
|
||||
|
||||
if(!work)
|
||||
{
|
||||
DEBUG(0,("become_local_master_stage1: Error - cannot find \
|
||||
workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
|
||||
return;
|
||||
}
|
||||
if(!work) {
|
||||
DEBUG(0,("become_local_master_stage1: Error - cannot find \
|
||||
%s on subnet %s\n", work_name, subrec->subnet_name));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG(3,("become_local_master_stage1: go to stage 2: register the %s<1d> name.\n",
|
||||
work->work_group));
|
||||
DEBUG(3,("become_local_master_stage1: go to stage 2: register the %s<1d> name.\n",
|
||||
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
|
||||
* the MSBROWSE name to the unicast subnet so that we can answer
|
||||
* unicast requests sent to this name. We create this name directly on
|
||||
* the unicast subnet.
|
||||
*/
|
||||
/*
|
||||
* 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
|
||||
* unicast requests sent to this name. We create this name directly on
|
||||
* 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. */
|
||||
register_name(subrec, work->work_group,0x1d,samba_nb_type,
|
||||
become_local_master_stage2,
|
||||
become_local_master_fail2,
|
||||
NULL);
|
||||
/* Attempt to register the WORKGROUP<1d> name. */
|
||||
register_name(subrec, work->work_group,0x1d,samba_nb_type,
|
||||
become_local_master_stage2,
|
||||
become_local_master_fail2,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -481,29 +477,27 @@ static void become_local_master_fail1(struct subnet_record *subrec,
|
||||
struct response_record *rrec,
|
||||
struct nmb_name *fail_name)
|
||||
{
|
||||
char *work_name = rrec->userdata->data;
|
||||
struct work_record *work = find_workgroup_on_subnet(subrec, work_name);
|
||||
char *work_name = rrec->userdata->data;
|
||||
struct work_record *work = find_workgroup_on_subnet(subrec, work_name);
|
||||
|
||||
if(!work)
|
||||
{
|
||||
DEBUG(0,("become_local_master_fail1: Error - cannot find \
|
||||
if(!work) {
|
||||
DEBUG(0,("become_local_master_fail1: Error - cannot find \
|
||||
workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(find_server_in_workgroup(work, global_myname()) == NULL)
|
||||
{
|
||||
DEBUG(0,("become_local_master_fail1: Error - cannot find server %s \
|
||||
if(find_server_in_workgroup(work, global_myname()) == NULL) {
|
||||
DEBUG(0,("become_local_master_fail1: Error - cannot find server %s \
|
||||
in workgroup %s on subnet %s\n",
|
||||
global_myname(), work->work_group, subrec->subnet_name));
|
||||
return;
|
||||
}
|
||||
global_myname(), work->work_group, subrec->subnet_name));
|
||||
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",
|
||||
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)
|
||||
{
|
||||
struct userdata_struct *userdata;
|
||||
size_t size = sizeof(struct userdata_struct) + sizeof(fstring) + 1;
|
||||
struct userdata_struct *userdata;
|
||||
size_t size = sizeof(struct userdata_struct) + sizeof(fstring) + 1;
|
||||
|
||||
/* Sanity check. */
|
||||
if (!lp_local_master())
|
||||
{
|
||||
DEBUG(0,("become_local_master_browser: Samba not configured as a local master browser.\n"));
|
||||
return;
|
||||
}
|
||||
/* Sanity check. */
|
||||
if (!lp_local_master()) {
|
||||
DEBUG(0,("become_local_master_browser: Samba not configured as a local master browser.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if(!AM_POTENTIAL_MASTER_BROWSER(work))
|
||||
{
|
||||
DEBUG(2,("become_local_master_browser: Awaiting potential browser state. Current state is %d\n",
|
||||
work->mst_state ));
|
||||
return;
|
||||
}
|
||||
if(!AM_POTENTIAL_MASTER_BROWSER(work)) {
|
||||
DEBUG(2,("become_local_master_browser: Awaiting potential browser state. Current state is %d\n",
|
||||
work->mst_state ));
|
||||
return;
|
||||
}
|
||||
|
||||
if(find_server_in_workgroup( work, global_myname()) == NULL)
|
||||
{
|
||||
DEBUG(0,("become_local_master_browser: Error - cannot find server %s \
|
||||
if(find_server_in_workgroup( work, global_myname()) == NULL) {
|
||||
DEBUG(0,("become_local_master_browser: Error - cannot find server %s \
|
||||
in workgroup %s on subnet %s\n",
|
||||
global_myname(), work->work_group, subrec->subnet_name));
|
||||
return;
|
||||
}
|
||||
global_myname(), work->work_group, subrec->subnet_name));
|
||||
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));
|
||||
|
||||
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 */
|
||||
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->ElectionCriterion |= 0x5;
|
||||
work->ElectionCriterion |= 0x5;
|
||||
|
||||
/* Tell the namelist writer to write out a change. */
|
||||
subrec->work_changed = True;
|
||||
/* Tell the namelist writer to write out a change. */
|
||||
subrec->work_changed = True;
|
||||
|
||||
/* Setup the userdata_struct. */
|
||||
if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
|
||||
{
|
||||
DEBUG(0,("become_local_master_browser: malloc fail.\n"));
|
||||
return;
|
||||
}
|
||||
/* Setup the userdata_struct. */
|
||||
if((userdata = (struct userdata_struct *)malloc(size)) == NULL) {
|
||||
DEBUG(0,("become_local_master_browser: malloc fail.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
userdata->copy_fn = NULL;
|
||||
userdata->free_fn = NULL;
|
||||
userdata->userdata_len = strlen(work->work_group)+1;
|
||||
overmalloc_safe_strcpy(userdata->data, work->work_group, size - sizeof(*userdata) - 1);
|
||||
userdata->copy_fn = NULL;
|
||||
userdata->free_fn = NULL;
|
||||
userdata->userdata_len = strlen(work->work_group)+1;
|
||||
overmalloc_safe_strcpy(userdata->data, work->work_group, size - sizeof(*userdata) - 1);
|
||||
|
||||
/* Register the special browser group name. */
|
||||
register_name(subrec, MSBROWSE, 0x01, samba_nb_type|NB_GROUP,
|
||||
become_local_master_stage1,
|
||||
become_local_master_fail1,
|
||||
userdata);
|
||||
/* Register the special browser group name. */
|
||||
register_name(subrec, MSBROWSE, 0x01, samba_nb_type|NB_GROUP,
|
||||
become_local_master_stage1,
|
||||
become_local_master_fail1,
|
||||
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)
|
||||
{
|
||||
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 ));
|
||||
|
||||
#if 0
|
||||
@ -600,5 +590,5 @@ local_master_browser_name for workgroup %s to workgroup name.\n",
|
||||
}
|
||||
#endif
|
||||
|
||||
fstrcpy(work->local_master_browser_name, newname);
|
||||
fstrcpy(work->local_master_browser_name, newname);
|
||||
}
|
||||
|
@ -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,
|
||||
char *browser_name,
|
||||
struct browse_cache_record *create_browser_in_lmb_cache( const char *work_name,
|
||||
const char *browser_name,
|
||||
struct in_addr ip )
|
||||
{
|
||||
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;
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
NBT netbios routines and daemon - version 2
|
||||
Copyright (C) Andrew Tridgell 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
|
||||
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.
|
||||
**************************************************************************/
|
||||
|
||||
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( DEBUGLVL( 0 ) )
|
||||
{
|
||||
dbgtext( "sync_with_lmb:\n" );
|
||||
dbgtext( "Failed to get a workgroup for a local master browser " );
|
||||
dbgtext( "cache entry workgroup " );
|
||||
dbgtext( "%s, server %s\n", browc->work_group, browc->lmb_name );
|
||||
}
|
||||
return;
|
||||
}
|
||||
if( !(work = find_workgroup_on_subnet(unicast_subnet, browc->work_group)) ) {
|
||||
if( DEBUGLVL( 0 ) ) {
|
||||
dbgtext( "sync_with_lmb:\n" );
|
||||
dbgtext( "Failed to get a workgroup for a local master browser " );
|
||||
dbgtext( "cache entry workgroup " );
|
||||
dbgtext( "%s, server %s\n", browc->work_group, browc->lmb_name );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* We should only be doing this if we are a domain master browser for
|
||||
the given workgroup. Ensure this is so. */
|
||||
/* We should only be doing this if we are a domain master browser for
|
||||
the given workgroup. Ensure this is so. */
|
||||
|
||||
if(!AM_DOMAIN_MASTER_BROWSER(work))
|
||||
{
|
||||
if( DEBUGLVL( 0 ) )
|
||||
{
|
||||
dbgtext( "sync_with_lmb:\n" );
|
||||
dbgtext( "We are trying to sync with a local master browser " );
|
||||
dbgtext( "%s for workgroup %s\n", browc->lmb_name, browc->work_group );
|
||||
dbgtext( "and we are not a domain master browser on this workgroup.\n" );
|
||||
dbgtext( "Error!\n" );
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(!AM_DOMAIN_MASTER_BROWSER(work)) {
|
||||
if( DEBUGLVL( 0 ) ) {
|
||||
dbgtext( "sync_with_lmb:\n" );
|
||||
dbgtext( "We are trying to sync with a local master browser " );
|
||||
dbgtext( "%s for workgroup %s\n", browc->lmb_name, browc->work_group );
|
||||
dbgtext( "and we are not a domain master browser on this workgroup.\n" );
|
||||
dbgtext( "Error!\n" );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if( DEBUGLVL( 2 ) )
|
||||
{
|
||||
dbgtext( "sync_with_lmb:\n" );
|
||||
dbgtext( "Initiating sync with local master browser " );
|
||||
dbgtext( "%s<0x20> at IP %s ", browc->lmb_name, inet_ntoa(browc->ip) );
|
||||
dbgtext( "for workgroup %s\n", browc->work_group );
|
||||
}
|
||||
if( DEBUGLVL( 2 ) ) {
|
||||
dbgtext( "sync_with_lmb:\n" );
|
||||
dbgtext( "Initiating sync with local master browser " );
|
||||
dbgtext( "%s<0x20> at IP %s ", browc->lmb_name, inet_ntoa(browc->ip) );
|
||||
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.
|
||||
**************************************************************************/
|
||||
|
||||
void dmb_expire_and_sync_browser_lists(time_t t)
|
||||
{
|
||||
static time_t last_run = 0;
|
||||
struct browse_cache_record *browc;
|
||||
static time_t last_run = 0;
|
||||
struct browse_cache_record *browc;
|
||||
|
||||
/* Only do this every 20 seconds. */
|
||||
if (t - last_run < 20)
|
||||
return;
|
||||
/* Only do this every 20 seconds. */
|
||||
if (t - last_run < 20)
|
||||
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 );
|
||||
browc;
|
||||
browc = (struct browse_cache_record *)ubi_dlNext( browc ) )
|
||||
{
|
||||
if (browc->sync_time < t)
|
||||
sync_with_lmb(browc);
|
||||
}
|
||||
for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist );
|
||||
browc;
|
||||
browc = (struct browse_cache_record *)ubi_dlNext( browc ) ) {
|
||||
if (browc->sync_time < t)
|
||||
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)
|
||||
{
|
||||
pstring outbuf;
|
||||
fstring myname;
|
||||
char *p;
|
||||
pstring outbuf;
|
||||
fstring myname;
|
||||
char *p;
|
||||
|
||||
if(ismyip(work->dmb_addr))
|
||||
{
|
||||
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( "workgroup %s. ", work->work_group );
|
||||
dbgtext( "Do not announce to ourselves.\n" );
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(ismyip(work->dmb_addr)) {
|
||||
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( "workgroup %s. ", work->work_group );
|
||||
dbgtext( "Do not announce to ourselves.\n" );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
memset(outbuf,'\0',sizeof(outbuf));
|
||||
p = outbuf;
|
||||
SCVAL(p,0,ANN_MasterAnnouncement);
|
||||
p++;
|
||||
memset(outbuf,'\0',sizeof(outbuf));
|
||||
p = outbuf;
|
||||
SCVAL(p,0,ANN_MasterAnnouncement);
|
||||
p++;
|
||||
|
||||
fstrcpy(myname, global_myname());
|
||||
strupper_m(myname);
|
||||
myname[15]='\0';
|
||||
push_pstring_base(p, myname, outbuf);
|
||||
fstrcpy(myname, global_myname());
|
||||
strupper_m(myname);
|
||||
myname[15]='\0';
|
||||
/* 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 ) )
|
||||
{
|
||||
dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
|
||||
dbgtext( "Sending local master announce to " );
|
||||
dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name),
|
||||
work->work_group );
|
||||
}
|
||||
if( DEBUGLVL( 4 ) ) {
|
||||
dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
|
||||
dbgtext( "Sending local master announce to " );
|
||||
dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name),
|
||||
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,
|
||||
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)
|
||||
{
|
||||
if( DEBUGLVL( 2 ) )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
nstring dmb_name;
|
||||
|
||||
sync_browse_lists(work, work->dmb_name.name, work->dmb_name.name_type,
|
||||
work->dmb_addr, False, True);
|
||||
if( DEBUGLVL( 2 ) ) {
|
||||
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 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( DEBUGLVL( 0 ) )
|
||||
{
|
||||
dbgtext( "domain_master_node_status_success:\n" );
|
||||
dbgtext( "Unable to find workgroup " );
|
||||
dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );
|
||||
}
|
||||
return;
|
||||
}
|
||||
if( work == NULL ) {
|
||||
if( DEBUGLVL( 0 ) ) {
|
||||
dbgtext( "domain_master_node_status_success:\n" );
|
||||
dbgtext( "Unable to find workgroup " );
|
||||
dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if( DEBUGLVL( 3 ) )
|
||||
{
|
||||
dbgtext( "domain_master_node_status_success:\n" );
|
||||
dbgtext( "Success in node status for workgroup " );
|
||||
dbgtext( "%s from ip %s\n", work->work_group, inet_ntoa(from_ip) );
|
||||
}
|
||||
if( DEBUGLVL( 3 ) ) {
|
||||
dbgtext( "domain_master_node_status_success:\n" );
|
||||
dbgtext( "Success in node status for workgroup " );
|
||||
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
|
||||
the first SERVER<0x20> name. */
|
||||
|
||||
if(answers->rdata != NULL)
|
||||
{
|
||||
char *p = answers->rdata;
|
||||
int numnames = CVAL(p, 0);
|
||||
if(answers->rdata != NULL) {
|
||||
char *p = answers->rdata;
|
||||
int numnames = CVAL(p, 0);
|
||||
|
||||
p += 1;
|
||||
p += 1;
|
||||
|
||||
while (numnames--)
|
||||
{
|
||||
char qname[17];
|
||||
uint16 nb_flags;
|
||||
int name_type;
|
||||
while (numnames--) {
|
||||
nstring qname;
|
||||
uint16 nb_flags;
|
||||
int name_type;
|
||||
|
||||
StrnCpy(qname,p,15);
|
||||
name_type = CVAL(p,15);
|
||||
nb_flags = get_nb_flags(&p[16]);
|
||||
trim_string(qname,NULL," ");
|
||||
pull_ascii_nstring(qname, p);
|
||||
name_type = CVAL(p,15);
|
||||
nb_flags = get_nb_flags(&p[16]);
|
||||
trim_string(qname,NULL," ");
|
||||
|
||||
p += 18;
|
||||
p += 18;
|
||||
|
||||
if(!(nb_flags & NB_GROUP) && (name_type == 0x20))
|
||||
{
|
||||
struct nmb_name nmbname;
|
||||
if(!(nb_flags & NB_GROUP) && (name_type == 0x20)) {
|
||||
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
|
||||
into the workgroup struct. */
|
||||
/* Copy the dmb name and IP address
|
||||
into the workgroup struct. */
|
||||
|
||||
work->dmb_name = nmbname;
|
||||
putip((char *)&work->dmb_addr, &from_ip);
|
||||
work->dmb_name = nmbname;
|
||||
putip((char *)&work->dmb_addr, &from_ip);
|
||||
|
||||
/* Do the local master browser announcement to the domain
|
||||
master browser name and IP. */
|
||||
announce_local_master_browser_to_domain_master_browser( work );
|
||||
/* Do the local master browser announcement to the domain
|
||||
master browser name and IP. */
|
||||
announce_local_master_browser_to_domain_master_browser( work );
|
||||
|
||||
/* Now synchronise lists with the domain master browser. */
|
||||
sync_with_dmb(work);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if( DEBUGLVL( 0 ) )
|
||||
{
|
||||
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) );
|
||||
}
|
||||
/* Now synchronise lists with the domain master browser. */
|
||||
sync_with_dmb(work);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if( DEBUGLVL( 0 ) ) {
|
||||
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,
|
||||
struct response_record *rrec)
|
||||
{
|
||||
struct userdata_struct *userdata = rrec->userdata;
|
||||
struct userdata_struct *userdata = rrec->userdata;
|
||||
|
||||
if( DEBUGLVL( 0 ) )
|
||||
{
|
||||
dbgtext( "domain_master_node_status_fail:\n" );
|
||||
dbgtext( "Doing a node status request to the domain master browser\n" );
|
||||
dbgtext( "for workgroup %s ", userdata ? userdata->data : "NULL" );
|
||||
dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
|
||||
dbgtext( "Cannot sync browser lists.\n" );
|
||||
}
|
||||
if( DEBUGLVL( 0 ) ) {
|
||||
dbgtext( "domain_master_node_status_fail:\n" );
|
||||
dbgtext( "Doing a node status request to the domain master browser\n" );
|
||||
dbgtext( "for workgroup %s ", userdata ? userdata->data : "NULL" );
|
||||
dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
|
||||
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 nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
|
||||
{
|
||||
/*
|
||||
* 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
|
||||
* SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
|
||||
* respond to the SMBSERVER name. To get this name from IP
|
||||
* address we do a Node status request, and look for the first
|
||||
* 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
|
||||
* 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
|
||||
* request.
|
||||
*/
|
||||
/*
|
||||
* 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
|
||||
* SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
|
||||
* respond to the SMBSERVER name. To get this name from IP
|
||||
* address we do a Node status request, and look for the first
|
||||
* 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
|
||||
* 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
|
||||
* request.
|
||||
*/
|
||||
|
||||
struct work_record *work;
|
||||
struct nmb_name nmbname;
|
||||
struct userdata_struct *userdata;
|
||||
size_t size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
|
||||
struct work_record *work;
|
||||
struct nmb_name nmbname;
|
||||
struct userdata_struct *userdata;
|
||||
size_t size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
|
||||
nstring qname;
|
||||
|
||||
if( !(work = find_workgroup_on_subnet(subrec, q_name->name)) )
|
||||
{
|
||||
if( DEBUGLVL( 0 ) )
|
||||
{
|
||||
dbgtext( "find_domain_master_name_query_success:\n" );
|
||||
dbgtext( "Failed to find workgroup %s\n", q_name->name );
|
||||
}
|
||||
return;
|
||||
pull_ascii_nstring(qname, q_name->name);
|
||||
if( !(work = find_workgroup_on_subnet(subrec, qname)) ) {
|
||||
if( DEBUGLVL( 0 ) ) {
|
||||
dbgtext( "find_domain_master_name_query_success:\n" );
|
||||
dbgtext( "Failed to find workgroup %s\n", qname);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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))
|
||||
{
|
||||
/* Do the local master browser announcement to the domain
|
||||
master browser name and IP. */
|
||||
announce_local_master_browser_to_domain_master_browser( work );
|
||||
if(!is_zero_ip(work->dmb_addr) && ip_equal(work->dmb_addr, answer_ip)) {
|
||||
/* Do the local master browser announcement to the domain
|
||||
master browser name and IP. */
|
||||
announce_local_master_browser_to_domain_master_browser( work );
|
||||
|
||||
/* Now synchronise lists with the domain master browser. */
|
||||
sync_with_dmb(work);
|
||||
return;
|
||||
}
|
||||
else
|
||||
zero_ip(&work->dmb_addr);
|
||||
/* Now synchronise lists with the domain master browser. */
|
||||
sync_with_dmb(work);
|
||||
return;
|
||||
} else {
|
||||
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
|
||||
* servers don't answer that name. However we *know* they
|
||||
* have the name workgroup#1b (as we just looked it up).
|
||||
* So do the node status request on this name instead.
|
||||
* Found at LBL labs. JRA.
|
||||
*/
|
||||
/* We used to use the name "*",0x0 here, but some Windows
|
||||
* servers don't answer that name. However we *know* they
|
||||
* have the name workgroup#1b (as we just looked it up).
|
||||
* So do the node status request on this name instead.
|
||||
* 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
|
||||
what workgroup we're talking to when the reply comes
|
||||
back. */
|
||||
/* Put the workgroup name into the userdata so we know
|
||||
what workgroup we're talking to when the reply comes
|
||||
back. */
|
||||
|
||||
/* Setup the userdata_struct - this is copied so we can use
|
||||
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;
|
||||
}
|
||||
/* Setup the userdata_struct - this is copied so we can use
|
||||
a stack variable for this. */
|
||||
|
||||
userdata->copy_fn = NULL;
|
||||
userdata->free_fn = NULL;
|
||||
userdata->userdata_len = strlen(work->work_group)+1;
|
||||
overmalloc_safe_strcpy(userdata->data, work->work_group, size - sizeof(*userdata) - 1);
|
||||
if((userdata = (struct userdata_struct *)malloc(size)) == NULL) {
|
||||
DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
node_status( subrec, &nmbname, answer_ip,
|
||||
domain_master_node_status_success,
|
||||
domain_master_node_status_fail,
|
||||
userdata);
|
||||
userdata->copy_fn = NULL;
|
||||
userdata->free_fn = NULL;
|
||||
userdata->userdata_len = strlen(work->work_group)+1;
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
static void find_domain_master_name_query_fail(struct subnet_record *subrec,
|
||||
struct response_record *rrec,
|
||||
struct nmb_name *question_name, int fail_code)
|
||||
{
|
||||
if( DEBUGLVL( 0 ) )
|
||||
{
|
||||
dbgtext( "find_domain_master_name_query_fail:\n" );
|
||||
dbgtext( "Unable to find the Domain Master Browser name " );
|
||||
dbgtext( "%s for the workgroup %s.\n",
|
||||
nmb_namestr(question_name), question_name->name );
|
||||
dbgtext( "Unable to sync browse lists in this workgroup.\n" );
|
||||
}
|
||||
if( DEBUGLVL( 0 ) ) {
|
||||
dbgtext( "find_domain_master_name_query_fail:\n" );
|
||||
dbgtext( "Unable to find the Domain Master Browser name " );
|
||||
dbgtext( "%s for the workgroup %s.\n",
|
||||
nmb_namestr(question_name), question_name->name );
|
||||
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,
|
||||
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. */
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
/* First, query for the WORKGROUP<1b> name from the WINS server. */
|
||||
query_name(unicast_subnet, work->work_group, 0x1b,
|
||||
find_domain_master_name_query_success,
|
||||
find_domain_master_name_query_fail,
|
||||
NULL);
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -421,89 +398,81 @@ static void get_domain_master_name_node_status_success(struct subnet_record *sub
|
||||
struct res_rec *answers,
|
||||
struct in_addr from_ip)
|
||||
{
|
||||
struct work_record *work;
|
||||
fstring server_name;
|
||||
struct work_record *work;
|
||||
fstring server_name;
|
||||
|
||||
server_name[0] = 0;
|
||||
server_name[0] = 0;
|
||||
|
||||
if( DEBUGLVL( 3 ) )
|
||||
{
|
||||
dbgtext( "get_domain_master_name_node_status_success:\n" );
|
||||
dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
|
||||
}
|
||||
if( DEBUGLVL( 3 ) ) {
|
||||
dbgtext( "get_domain_master_name_node_status_success:\n" );
|
||||
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
|
||||
* the first WORKGROUP<0x1b> name.
|
||||
*/
|
||||
/*
|
||||
* Go through the list of names found at answers->rdata and look for
|
||||
* the first WORKGROUP<0x1b> name.
|
||||
*/
|
||||
|
||||
if(answers->rdata != NULL)
|
||||
{
|
||||
char *p = answers->rdata;
|
||||
int numnames = CVAL(p, 0);
|
||||
if(answers->rdata != NULL) {
|
||||
char *p = answers->rdata;
|
||||
int numnames = CVAL(p, 0);
|
||||
|
||||
p += 1;
|
||||
p += 1;
|
||||
|
||||
while (numnames--)
|
||||
{
|
||||
char qname[17];
|
||||
uint16 nb_flags;
|
||||
int name_type;
|
||||
while (numnames--) {
|
||||
nstring qname;
|
||||
uint16 nb_flags;
|
||||
int name_type;
|
||||
|
||||
StrnCpy(qname,p,15);
|
||||
name_type = CVAL(p,15);
|
||||
nb_flags = get_nb_flags(&p[16]);
|
||||
trim_string(qname,NULL," ");
|
||||
pull_ascii_nstring(qname, p);
|
||||
name_type = CVAL(p,15);
|
||||
nb_flags = get_nb_flags(&p[16]);
|
||||
trim_string(qname,NULL," ");
|
||||
|
||||
p += 18;
|
||||
p += 18;
|
||||
|
||||
if(!(nb_flags & NB_GROUP) && (name_type == 0x00) &&
|
||||
server_name[0] == 0) {
|
||||
/* this is almost certainly the server netbios name */
|
||||
fstrcpy(server_name, qname);
|
||||
continue;
|
||||
}
|
||||
if(!(nb_flags & NB_GROUP) && (name_type == 0x00) &&
|
||||
server_name[0] == 0) {
|
||||
/* this is almost certainly the server netbios name */
|
||||
fstrcpy(server_name, qname);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!(nb_flags & NB_GROUP) && (name_type == 0x1b))
|
||||
{
|
||||
if( DEBUGLVL( 5 ) )
|
||||
{
|
||||
dbgtext( "get_domain_master_name_node_status_success:\n" );
|
||||
dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
|
||||
dbgtext( "is a domain master browser for workgroup " );
|
||||
dbgtext( "%s. Adding this name.\n", qname );
|
||||
}
|
||||
if(!(nb_flags & NB_GROUP) && (name_type == 0x1b)) {
|
||||
if( DEBUGLVL( 5 ) ) {
|
||||
dbgtext( "get_domain_master_name_node_status_success:\n" );
|
||||
dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
|
||||
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
|
||||
* 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;
|
||||
/*
|
||||
* If we don't already know about this workgroup, add it
|
||||
* to the workgroup list on the unicast_subnet.
|
||||
*/
|
||||
|
||||
/* remember who the master is */
|
||||
fstrcpy(work->local_master_browser_name, server_name);
|
||||
make_nmb_name(&nmbname, server_name, 0x20);
|
||||
work->dmb_name = nmbname;
|
||||
work->dmb_addr = from_ip;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
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) );
|
||||
}
|
||||
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 */
|
||||
fstrcpy(work->local_master_browser_name, server_name);
|
||||
make_nmb_name(&nmbname, server_name, 0x20);
|
||||
work->dmb_name = nmbname;
|
||||
work->dmb_addr = from_ip;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} 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,
|
||||
struct response_record *rrec)
|
||||
{
|
||||
if( DEBUGLVL( 0 ) )
|
||||
{
|
||||
dbgtext( "get_domain_master_name_node_status_fail:\n" );
|
||||
dbgtext( "Doing a node status request to the domain master browser " );
|
||||
dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
|
||||
dbgtext( "Cannot get workgroup name.\n" );
|
||||
}
|
||||
if( DEBUGLVL( 0 ) ) {
|
||||
dbgtext( "get_domain_master_name_node_status_fail:\n" );
|
||||
dbgtext( "Doing a node status request to the domain master browser " );
|
||||
dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
|
||||
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 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
|
||||
* 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
|
||||
* the workgroup name that we will add to the unicast subnet as a 'non-local'
|
||||
* workgroup.
|
||||
*/
|
||||
/*
|
||||
* 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
|
||||
* 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'
|
||||
* workgroup.
|
||||
*/
|
||||
|
||||
struct nmb_name nmbname;
|
||||
struct in_addr send_ip;
|
||||
int i;
|
||||
struct nmb_name nmbname;
|
||||
struct in_addr send_ip;
|
||||
int i;
|
||||
|
||||
if( DEBUGLVL( 5 ) )
|
||||
{
|
||||
dbgtext( "find_all_domain_master_names_query_succes:\n" );
|
||||
dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
|
||||
dbgtext( "IP addresses for Domain Master Browsers.\n" );
|
||||
}
|
||||
if( DEBUGLVL( 5 ) ) {
|
||||
dbgtext( "find_all_domain_master_names_query_succes:\n" );
|
||||
dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
|
||||
dbgtext( "IP addresses for Domain Master Browsers.\n" );
|
||||
}
|
||||
|
||||
for(i = 0; i < rrec->rdlength / 6; i++)
|
||||
{
|
||||
/* Initiate the node status requests. */
|
||||
make_nmb_name(&nmbname, "*", 0);
|
||||
for(i = 0; i < rrec->rdlength / 6; i++) {
|
||||
/* Initiate the node status requests. */
|
||||
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( DEBUGLVL( 5 ) )
|
||||
{
|
||||
dbgtext( "find_all_domain_master_names_query_succes:\n" );
|
||||
dbgtext( "Not sending node status to our own IP " );
|
||||
dbgtext( "%s.\n", inet_ntoa(send_ip) );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(ismyip( send_ip )) {
|
||||
if( DEBUGLVL( 5 ) ) {
|
||||
dbgtext( "find_all_domain_master_names_query_succes:\n" );
|
||||
dbgtext( "Not sending node status to our own IP " );
|
||||
dbgtext( "%s.\n", inet_ntoa(send_ip) );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if( DEBUGLVL( 5 ) )
|
||||
{
|
||||
dbgtext( "find_all_domain_master_names_query_success:\n" );
|
||||
dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
|
||||
}
|
||||
if( DEBUGLVL( 5 ) ) {
|
||||
dbgtext( "find_all_domain_master_names_query_success:\n" );
|
||||
dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
|
||||
}
|
||||
|
||||
node_status( subrec, &nmbname, send_ip,
|
||||
get_domain_master_name_node_status_success,
|
||||
get_domain_master_name_node_status_fail,
|
||||
NULL);
|
||||
}
|
||||
node_status( subrec, &nmbname, send_ip,
|
||||
get_domain_master_name_node_status_success,
|
||||
get_domain_master_name_node_status_fail,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -591,13 +554,12 @@ static void find_all_domain_master_names_query_fail(struct subnet_record *subrec
|
||||
struct response_record *rrec,
|
||||
struct nmb_name *question_name, int fail_code)
|
||||
{
|
||||
if( DEBUGLVL( 10 ) )
|
||||
{
|
||||
dbgtext( "find_domain_master_name_query_fail:\n" );
|
||||
dbgtext( "WINS server did not reply to a query for name " );
|
||||
dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
|
||||
dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" );
|
||||
}
|
||||
if( DEBUGLVL( 10 ) ) {
|
||||
dbgtext( "find_domain_master_name_query_fail:\n" );
|
||||
dbgtext( "WINS server did not reply to a query for name " );
|
||||
dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
|
||||
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
|
||||
subnet. This is expensive, so we only do this every 15 minutes.
|
||||
**************************************************************************/
|
||||
|
||||
void collect_all_workgroup_names_from_wins_server(time_t t)
|
||||
{
|
||||
static time_t lastrun = 0;
|
||||
struct work_record *work;
|
||||
struct nmb_name nmbname;
|
||||
static time_t lastrun = 0;
|
||||
struct work_record *work;
|
||||
|
||||
/* Only do this if we are using a WINS server. */
|
||||
if(we_are_a_wins_client() == False)
|
||||
return;
|
||||
/* Only do this if we are using a WINS server. */
|
||||
if(we_are_a_wins_client() == False)
|
||||
return;
|
||||
|
||||
/* 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( DEBUGLVL( 0 ) )
|
||||
{
|
||||
dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
|
||||
dbgtext( "Cannot find my workgroup %s ", lp_workgroup() );
|
||||
dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* 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( DEBUGLVL( 0 ) ) {
|
||||
dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
|
||||
dbgtext( "Cannot find my workgroup %s ", lp_workgroup() );
|
||||
dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(!AM_DOMAIN_MASTER_BROWSER(work))
|
||||
return;
|
||||
if(!AM_DOMAIN_MASTER_BROWSER(work))
|
||||
return;
|
||||
|
||||
if ((lastrun != 0) && (t < lastrun + (15 * 60)))
|
||||
return;
|
||||
if ((lastrun != 0) && (t < lastrun + (15 * 60)))
|
||||
return;
|
||||
|
||||
lastrun = t;
|
||||
lastrun = t;
|
||||
|
||||
make_nmb_name(&nmbname,"*",0x1b);
|
||||
|
||||
/* First, query for the *<1b> name from the WINS server. */
|
||||
query_name(unicast_subnet, nmbname.name, nmbname.name_type,
|
||||
find_all_domain_master_names_query_success,
|
||||
find_all_domain_master_names_query_fail,
|
||||
NULL);
|
||||
/* First, query for the *<1b> name from the WINS server. */
|
||||
query_name(unicast_subnet, "*", 0x1b,
|
||||
find_all_domain_master_names_query_success,
|
||||
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
|
||||
to the number of known workgroups
|
||||
**************************************************************************/
|
||||
|
||||
void sync_all_dmbs(time_t t)
|
||||
{
|
||||
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
|
||||
unicast subnet. */
|
||||
work = find_workgroup_on_subnet(unicast_subnet, lp_workgroup());
|
||||
if (!work) return;
|
||||
if (!work)
|
||||
return;
|
||||
|
||||
if (!AM_DOMAIN_MASTER_BROWSER(work))
|
||||
return;
|
||||
@ -687,7 +647,10 @@ void sync_all_dmbs(time_t t)
|
||||
/* sync with a probability of 1/count */
|
||||
for (work=unicast_subnet->workgrouplist; work; work = work->next) {
|
||||
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;
|
||||
|
||||
@ -699,13 +662,15 @@ void sync_all_dmbs(time_t t)
|
||||
0x20);
|
||||
}
|
||||
|
||||
pull_ascii_nstring(dmb_name, work->dmb_name.name);
|
||||
|
||||
DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
|
||||
work->dmb_name.name,
|
||||
inet_ntoa(work->dmb_addr)));
|
||||
dmb_name, inet_ntoa(work->dmb_addr)));
|
||||
|
||||
sync_browse_lists(work,
|
||||
work->dmb_name.name,
|
||||
dmb_name,
|
||||
work->dmb_name.name_type,
|
||||
work->dmb_addr, False, False);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
NBT netbios routines and daemon - version 2
|
||||
Copyright (C) Andrew Tridgell 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
|
||||
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.
|
||||
**************************************************************************/
|
||||
|
||||
static void send_election_dgram(struct subnet_record *subrec, const char *workgroup_name,
|
||||
uint32 criterion, int timeup,const char *server_name)
|
||||
{
|
||||
pstring outbuf;
|
||||
char *p;
|
||||
pstring outbuf;
|
||||
fstring srv_name;
|
||||
char *p;
|
||||
|
||||
DEBUG(2,("send_election_dgram: Sending election packet for workgroup %s on subnet %s\n",
|
||||
workgroup_name, subrec->subnet_name ));
|
||||
DEBUG(2,("send_election_dgram: Sending election packet for workgroup %s on subnet %s\n",
|
||||
workgroup_name, subrec->subnet_name ));
|
||||
|
||||
memset(outbuf,'\0',sizeof(outbuf));
|
||||
p = outbuf;
|
||||
SCVAL(p,0,ANN_Election); /* Election opcode. */
|
||||
p++;
|
||||
memset(outbuf,'\0',sizeof(outbuf));
|
||||
p = outbuf;
|
||||
SCVAL(p,0,ANN_Election); /* Election opcode. */
|
||||
p++;
|
||||
|
||||
SCVAL(p,0,((criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION));
|
||||
SIVAL(p,1,criterion);
|
||||
SIVAL(p,5,timeup*1000); /* ms - Despite what the spec says. */
|
||||
p += 13;
|
||||
pstrcpy_base(p, server_name, outbuf);
|
||||
strupper_m(p);
|
||||
p = skip_string(p,1);
|
||||
SCVAL(p,0,((criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION));
|
||||
SIVAL(p,1,criterion);
|
||||
SIVAL(p,5,timeup*1000); /* ms - Despite what the spec says. */
|
||||
p += 13;
|
||||
fstrcpy(srv_name, server_name);
|
||||
strupper_m(srv_name);
|
||||
pstrcpy_base(p, srv_name, outbuf);
|
||||
p = skip_string(p,1);
|
||||
|
||||
send_mailslot(False, BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
|
||||
global_myname(), 0,
|
||||
workgroup_name, 0x1e,
|
||||
subrec->bcast_ip, subrec->myip, DGRAM_PORT);
|
||||
send_mailslot(False, BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
|
||||
global_myname(), 0,
|
||||
workgroup_name, 0x1e,
|
||||
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 in_addr answer_ip, struct res_rec *rrec)
|
||||
{
|
||||
DEBUG(3,("check_for_master_browser_success: Local master browser for workgroup %s exists at \
|
||||
IP %s (just checking).\n", answer_name->name, inet_ntoa(answer_ip) ));
|
||||
nstring aname;
|
||||
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,
|
||||
int fail_code)
|
||||
{
|
||||
char *workgroup_name = question_name->name;
|
||||
struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
|
||||
nstring workgroup_name;
|
||||
struct work_record *work;
|
||||
|
||||
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;
|
||||
}
|
||||
pull_ascii_nstring(workgroup_name,question_name->name);
|
||||
|
||||
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())
|
||||
{
|
||||
/* 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 ));
|
||||
if (strequal(work->work_group, lp_workgroup())) {
|
||||
|
||||
/* Setting this means we will participate when the
|
||||
election is run in run_elections(). */
|
||||
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, "");
|
||||
}
|
||||
}
|
||||
if (lp_local_master()) {
|
||||
/* 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
|
||||
election is run in run_elections(). */
|
||||
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)
|
||||
{
|
||||
static time_t lastrun=0;
|
||||
struct subnet_record *subrec;
|
||||
const char *workgroup_name = lp_workgroup();
|
||||
static time_t lastrun=0;
|
||||
struct subnet_record *subrec;
|
||||
const char *workgroup_name = lp_workgroup();
|
||||
|
||||
if (!lastrun)
|
||||
lastrun = t;
|
||||
if (!lastrun)
|
||||
lastrun = t;
|
||||
|
||||
if (t < (lastrun + (CHECK_TIME_MST_BROWSE * 60)))
|
||||
return;
|
||||
if (t < (lastrun + (CHECK_TIME_MST_BROWSE * 60)))
|
||||
return;
|
||||
|
||||
lastrun = t;
|
||||
lastrun = t;
|
||||
|
||||
dump_workgroups(False);
|
||||
dump_workgroups(False);
|
||||
|
||||
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
|
||||
{
|
||||
struct work_record *work;
|
||||
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
|
||||
struct work_record *work;
|
||||
|
||||
for (work = subrec->workgrouplist; work; work = work->next)
|
||||
{
|
||||
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,
|
||||
check_for_master_browser_success,
|
||||
check_for_master_browser_fail,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (work = subrec->workgrouplist; work; work = work->next) {
|
||||
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,
|
||||
check_for_master_browser_success,
|
||||
check_for_master_browser_fail,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
@ -161,56 +161,52 @@ void check_master_browser_exists(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 */
|
||||
if (lastime && (t - lastime < 2))
|
||||
return;
|
||||
/* Send election packets once every 2 seconds - note */
|
||||
if (lastime && (t - lastime < 2))
|
||||
return;
|
||||
|
||||
lastime = t;
|
||||
lastime = t;
|
||||
|
||||
START_PROFILE(run_elections);
|
||||
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
|
||||
{
|
||||
struct work_record *work;
|
||||
START_PROFILE(run_elections);
|
||||
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
|
||||
struct work_record *work;
|
||||
|
||||
for (work = subrec->workgrouplist; work; work = work->next)
|
||||
{
|
||||
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 must listen to.
|
||||
*/
|
||||
struct nmb_name nmbname;
|
||||
for (work = subrec->workgrouplist; work; work = work->next) {
|
||||
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 must listen to.
|
||||
*/
|
||||
struct nmb_name nmbname;
|
||||
|
||||
make_nmb_name(&nmbname, work->work_group, 0x1e);
|
||||
if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) {
|
||||
DEBUG(8,("run_elections: Cannot send election packet yet as name %s not \
|
||||
make_nmb_name(&nmbname, work->work_group, 0x1e);
|
||||
if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) {
|
||||
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 ));
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
send_election_dgram(subrec, work->work_group, work->ElectionCriterion,
|
||||
t - StartupTime, global_myname());
|
||||
send_election_dgram(subrec, work->work_group, work->ElectionCriterion,
|
||||
t - StartupTime, global_myname());
|
||||
|
||||
if (work->ElectionCount++ >= 4)
|
||||
{
|
||||
/* Won election (4 packets were sent out uncontested. */
|
||||
DEBUG(2,("run_elections: >>> Won election for workgroup %s on subnet %s <<<\n",
|
||||
work->work_group, subrec->subnet_name ));
|
||||
if (work->ElectionCount++ >= 4) {
|
||||
/* Won election (4 packets were sent out uncontested. */
|
||||
DEBUG(2,("run_elections: >>> Won election for workgroup %s on subnet %s <<<\n",
|
||||
work->work_group, subrec->subnet_name ));
|
||||
|
||||
work->RunningElection = False;
|
||||
work->RunningElection = False;
|
||||
|
||||
become_local_master_browser(subrec, work);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
END_PROFILE(run_elections);
|
||||
become_local_master_browser(subrec, work);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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,
|
||||
uint32 criterion, int timeup, char *server_name)
|
||||
uint32 criterion, int timeup, const char *server_name)
|
||||
{
|
||||
int mytimeup = time(NULL) - StartupTime;
|
||||
uint32 mycriterion = work->ElectionCriterion;
|
||||
int mytimeup = time(NULL) - StartupTime;
|
||||
uint32 mycriterion = work->ElectionCriterion;
|
||||
|
||||
/* If local master is false then never win
|
||||
in election broadcasts. */
|
||||
if(!lp_local_master())
|
||||
{
|
||||
DEBUG(3,("win_election: Losing election as local master == False\n"));
|
||||
return False;
|
||||
}
|
||||
/* If local master is false then never win in election broadcasts. */
|
||||
if(!lp_local_master()) {
|
||||
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",
|
||||
version, ELECTION_VERSION,
|
||||
criterion, mycriterion,
|
||||
timeup, mytimeup,
|
||||
server_name, global_myname()));
|
||||
DEBUG(4,("win_election: election comparison: %x:%x %x:%x %d:%d %s:%s\n",
|
||||
version, ELECTION_VERSION,
|
||||
criterion, mycriterion,
|
||||
timeup, mytimeup,
|
||||
server_name, global_myname()));
|
||||
|
||||
if (version > ELECTION_VERSION)
|
||||
return(False);
|
||||
if (version < ELECTION_VERSION)
|
||||
return(True);
|
||||
if (version > ELECTION_VERSION)
|
||||
return(False);
|
||||
if (version < ELECTION_VERSION)
|
||||
return(True);
|
||||
|
||||
if (criterion > mycriterion)
|
||||
return(False);
|
||||
if (criterion < mycriterion)
|
||||
return(True);
|
||||
if (criterion > mycriterion)
|
||||
return(False);
|
||||
if (criterion < mycriterion)
|
||||
return(True);
|
||||
|
||||
if (timeup > mytimeup)
|
||||
return(False);
|
||||
if (timeup < mytimeup)
|
||||
return(True);
|
||||
if (timeup > mytimeup)
|
||||
return(False);
|
||||
if (timeup < mytimeup)
|
||||
return(True);
|
||||
|
||||
if (strcasecmp(global_myname(), server_name) > 0)
|
||||
return(False);
|
||||
if (strcasecmp(global_myname(), server_name) > 0)
|
||||
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)
|
||||
{
|
||||
struct dgram_packet *dgram = &p->packet.dgram;
|
||||
int version = CVAL(buf,0);
|
||||
uint32 criterion = IVAL(buf,1);
|
||||
int timeup = IVAL(buf,5)/1000;
|
||||
char *server_name = buf+13;
|
||||
struct work_record *work;
|
||||
char *workgroup_name = dgram->dest_name.name;
|
||||
struct dgram_packet *dgram = &p->packet.dgram;
|
||||
int version = CVAL(buf,0);
|
||||
uint32 criterion = IVAL(buf,1);
|
||||
int timeup = IVAL(buf,5)/1000;
|
||||
nstring server_name;
|
||||
struct work_record *work;
|
||||
nstring workgroup_name;
|
||||
|
||||
START_PROFILE(election);
|
||||
server_name[15] = 0;
|
||||
pull_ascii_nstring(server_name, buf+13);
|
||||
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",
|
||||
server_name,inet_ntoa(p->ip), subrec->subnet_name, workgroup_name ));
|
||||
START_PROFILE(election);
|
||||
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(0,("process_election: Cannot find workgroup %s on subnet %s.\n",
|
||||
workgroup_name, subrec->subnet_name ));
|
||||
goto done;
|
||||
}
|
||||
DEBUG(5,("process_election: vers=%d criterion=%08x timeup=%d\n", version,criterion,timeup));
|
||||
|
||||
if (!strequal(work->work_group, lp_workgroup()))
|
||||
{
|
||||
DEBUG(3,("process_election: ignoring election request for workgroup %s on subnet %s as this \
|
||||
if(( work = find_workgroup_on_subnet(subrec, workgroup_name)) == NULL) {
|
||||
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())) {
|
||||
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 ));
|
||||
goto done;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (win_election(work, version,criterion,timeup,server_name))
|
||||
{
|
||||
/* We take precedence over the requesting server. */
|
||||
if (!work->RunningElection)
|
||||
{
|
||||
/* We weren't running an election - start running one. */
|
||||
if (win_election(work, version,criterion,timeup,server_name)) {
|
||||
/* We take precedence over the requesting server. */
|
||||
if (!work->RunningElection) {
|
||||
/* We weren't running an election - start running one. */
|
||||
|
||||
work->needelection = True;
|
||||
work->ElectionCount=0;
|
||||
}
|
||||
work->needelection = True;
|
||||
work->ElectionCount=0;
|
||||
}
|
||||
|
||||
/* Note that if we were running an election for this workgroup on this
|
||||
subnet already, we just ignore the server we take precedence over. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We lost. Stop participating. */
|
||||
work->needelection = False;
|
||||
/* Note that if we were running an election for this workgroup on this
|
||||
subnet already, we just ignore the server we take precedence over. */
|
||||
} else {
|
||||
/* We lost. Stop participating. */
|
||||
work->needelection = False;
|
||||
|
||||
if (work->RunningElection || AM_LOCAL_MASTER_BROWSER(work))
|
||||
{
|
||||
work->RunningElection = False;
|
||||
DEBUG(3,("process_election: >>> Lost election for workgroup %s on subnet %s <<<\n",
|
||||
work->work_group, subrec->subnet_name ));
|
||||
if (AM_LOCAL_MASTER_BROWSER(work))
|
||||
unbecome_local_master_browser(subrec, work, False);
|
||||
}
|
||||
}
|
||||
if (work->RunningElection || AM_LOCAL_MASTER_BROWSER(work)) {
|
||||
work->RunningElection = False;
|
||||
DEBUG(3,("process_election: >>> Lost election for workgroup %s on subnet %s <<<\n",
|
||||
work->work_group, subrec->subnet_name ));
|
||||
if (AM_LOCAL_MASTER_BROWSER(work))
|
||||
unbecome_local_master_browser(subrec, work, False);
|
||||
}
|
||||
}
|
||||
done:
|
||||
END_PROFILE(election);
|
||||
|
||||
END_PROFILE(election);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -335,57 +326,53 @@ done:
|
||||
|
||||
BOOL check_elections(void)
|
||||
{
|
||||
struct subnet_record *subrec;
|
||||
BOOL run_any_election = False;
|
||||
struct subnet_record *subrec;
|
||||
BOOL run_any_election = False;
|
||||
|
||||
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
|
||||
{
|
||||
struct work_record *work;
|
||||
for (work = subrec->workgrouplist; work; work = work->next)
|
||||
{
|
||||
run_any_election |= work->RunningElection;
|
||||
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
|
||||
struct work_record *work;
|
||||
for (work = subrec->workgrouplist; work; work = work->next) {
|
||||
run_any_election |= work->RunningElection;
|
||||
|
||||
/*
|
||||
* Start an election if we have any chance of winning.
|
||||
* Note this is a change to the previous code, that would
|
||||
* only run an election if nmbd was in the potential browser
|
||||
* state. We need to run elections in any state if we're told
|
||||
* to. JRA.
|
||||
*/
|
||||
/*
|
||||
* Start an election if we have any chance of winning.
|
||||
* Note this is a change to the previous code, that would
|
||||
* only run an election if nmbd was in the potential browser
|
||||
* state. We need to run elections in any state if we're told
|
||||
* to. JRA.
|
||||
*/
|
||||
|
||||
if (work->needelection && !work->RunningElection && lp_local_master())
|
||||
{
|
||||
/*
|
||||
* We can only run an election for a workgroup if we have
|
||||
* registered the WORKGROUP<1e> name, as that's the name
|
||||
* we must listen to.
|
||||
*/
|
||||
struct nmb_name nmbname;
|
||||
if (work->needelection && !work->RunningElection && lp_local_master()) {
|
||||
/*
|
||||
* We can only run an election for a workgroup if we have
|
||||
* registered the WORKGROUP<1e> name, as that's the name
|
||||
* we must listen to.
|
||||
*/
|
||||
struct nmb_name nmbname;
|
||||
|
||||
make_nmb_name(&nmbname, work->work_group, 0x1e);
|
||||
if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) {
|
||||
DEBUG(8,("check_elections: Cannot send election packet yet as name %s not \
|
||||
make_nmb_name(&nmbname, work->work_group, 0x1e);
|
||||
if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) {
|
||||
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 ));
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG(3,("check_elections: >>> Starting election for workgroup %s on subnet %s <<<\n",
|
||||
work->work_group, subrec->subnet_name ));
|
||||
DEBUG(3,("check_elections: >>> Starting election for workgroup %s on subnet %s <<<\n",
|
||||
work->work_group, subrec->subnet_name ));
|
||||
|
||||
work->ElectionCount = 0;
|
||||
work->RunningElection = True;
|
||||
work->needelection = False;
|
||||
}
|
||||
}
|
||||
}
|
||||
return run_any_election;
|
||||
work->ElectionCount = 0;
|
||||
work->RunningElection = True;
|
||||
work->needelection = False;
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
struct subnet_record *subrec;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -201,7 +201,7 @@ static BOOL query_local_namelists(struct subnet_record *subrec, struct nmb_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_fail_function fail_fn,
|
||||
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,
|
||||
char *name, int type,
|
||||
const char *name, int type,
|
||||
query_name_success_function success_fn,
|
||||
query_name_fail_function fail_fn,
|
||||
struct userdata_struct *userdata)
|
||||
|
Loading…
Reference in New Issue
Block a user