1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-11 05:18:09 +03:00

Fix the character set handling properly in nmbd. Also fix bug where

iconv wasn't re-initialised on reading of "charset" parameters. This
caused workgroup name to be set incorrectly if it contained an
extended character.
Jeremy.
This commit is contained in:
Jeremy Allison 0001-01-01 00:00:00 +00:00
parent e855dc8c91
commit 84ae44678a
23 changed files with 4756 additions and 5164 deletions

View File

@ -825,8 +825,7 @@ void make_nmb_name( struct nmb_name *n, const char *name, int type)
memset( (char *)n, '\0', sizeof(struct nmb_name) );
push_ascii(n->name, name, sizeof(n->name), STR_TERMINATE|STR_UPPER);
n->name_type = (unsigned int)type & 0xFF;
StrnCpy( n->scope, global_scope(), 63 );
strupper_m( n->scope );
push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
}
/*******************************************************************

View File

@ -26,27 +26,26 @@
static struct name_record *add_dns_result(struct nmb_name *question, struct in_addr addr)
{
int name_type = question->name_type;
char *qname = question->name;
if (!addr.s_addr) {
/* add the fail to WINS cache of names. give it 1 hour in the cache */
DEBUG(3,("add_dns_result: Negative DNS answer for %s\n", qname));
(void)add_name_to_subnet( wins_server_subnet, qname, name_type,
NB_ACTIVE, 60*60, DNSFAIL_NAME, 1, &addr );
return( NULL );
}
int name_type = question->name_type;
nstring qname;
/* add it to our WINS cache of names. give it 2 hours in the cache */
DEBUG(3,("add_dns_result: DNS gave answer for %s of %s\n", qname, inet_ntoa(addr)));
pull_ascii_nstring(qname, question->name);
if (!addr.s_addr) {
/* add the fail to WINS cache of names. give it 1 hour in the cache */
DEBUG(3,("add_dns_result: Negative DNS answer for %s\n", qname));
(void)add_name_to_subnet( wins_server_subnet, qname, name_type,
NB_ACTIVE, 60*60, DNSFAIL_NAME, 1, &addr );
return( NULL );
}
return( add_name_to_subnet( wins_server_subnet, qname, name_type,
/* add it to our WINS cache of names. give it 2 hours in the cache */
DEBUG(3,("add_dns_result: DNS gave answer for %s of %s\n", qname, inet_ntoa(addr)));
return( add_name_to_subnet( wins_server_subnet, qname, name_type,
NB_ACTIVE, 2*60*60, DNS_NAME, 1, &addr ) );
}
#ifndef SYNC_DNS
static int fd_in = -1, fd_out = -1;
@ -70,6 +69,7 @@ static struct packet_struct *dns_current;
return the fd used to gather async dns replies. This is added to the select
loop
****************************************************************************/
int asyncdns_fd(void)
{
return fd_in;
@ -110,7 +110,7 @@ static void asyncdns_process(void)
static void sig_term(int sig)
{
_exit(0);
_exit(0);
}
/***************************************************************************
@ -224,10 +224,10 @@ void run_dns_queue(void)
if (query_current(&r)) {
DEBUG(3,("DNS calling send_wins_name_query_response\n"));
in_dns = 1;
if(namerec == NULL)
send_wins_name_query_response(NAM_ERR, dns_current, NULL);
else
send_wins_name_query_response(0,dns_current,namerec);
if(namerec == NULL)
send_wins_name_query_response(NAM_ERR, dns_current, NULL);
else
send_wins_name_query_response(0,dns_current,namerec);
in_dns = 0;
}
@ -245,10 +245,10 @@ void run_dns_queue(void)
if (nmb_name_equal(question, &r.name)) {
DEBUG(3,("DNS calling send_wins_name_query_response\n"));
in_dns = 1;
if(namerec == NULL)
send_wins_name_query_response(NAM_ERR, p, NULL);
else
send_wins_name_query_response(0,p,namerec);
if(namerec == NULL)
send_wins_name_query_response(NAM_ERR, p, NULL);
else
send_wins_name_query_response(0,p,namerec);
in_dns = 0;
p->locked = False;
@ -269,7 +269,8 @@ void run_dns_queue(void)
if (dns_queue) {
dns_current = dns_queue;
dns_queue = dns_queue->next;
if (dns_queue) dns_queue->prev = NULL;
if (dns_queue)
dns_queue->prev = NULL;
dns_current->next = NULL;
if (!write_child(dns_current)) {
@ -277,12 +278,12 @@ void run_dns_queue(void)
return;
}
}
}
/***************************************************************************
queue a DNS query
****************************************************************************/
BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
struct name_record **n)
{
@ -315,11 +316,14 @@ BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
/***************************************************************************
we use this when we can't do async DNS lookups
****************************************************************************/
BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
struct name_record **n)
{
char *qname = question->name;
struct in_addr dns_ip;
nstring qname;
pull_ascii_nstring(qname, question->name);
DEBUG(3,("DNS search for %s - ", nmb_namestr(question)));
@ -332,18 +336,19 @@ BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question,
BlockSignals(True, SIGTERM);
*n = add_dns_result(question, dns_ip);
if(*n == NULL)
send_wins_name_query_response(NAM_ERR, p, NULL);
else
send_wins_name_query_response(0, p, *n);
if(*n == NULL)
send_wins_name_query_response(NAM_ERR, p, NULL);
else
send_wins_name_query_response(0, p, *n);
return False;
}
/***************************************************************************
With sync dns there is no child to kill on SIGTERM.
****************************************************************************/
void kill_async_dns_child(void)
{
return;
return;
}
#endif

View File

@ -231,7 +231,8 @@ static BOOL reload_interfaces(time_t t)
DEBUG(2,("Found new interface %s\n",
inet_ntoa(iface->ip)));
subrec = make_normal_subnet(iface);
if (subrec) register_my_workgroup_one_subnet(subrec);
if (subrec)
register_my_workgroup_one_subnet(subrec);
}
}

View File

@ -51,6 +51,7 @@ static void send_election_dgram(struct subnet_record *subrec, const char *workgr
p += 13;
fstrcpy(srv_name, server_name);
strupper_m(srv_name);
/* The following call does UNIX -> DOS charset conversion. */
pstrcpy_base(p, srv_name, outbuf);
p = skip_string(p,1);

View File

@ -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,18 +33,18 @@ Send a name release response.
static void send_name_release_response(int rcode, struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
char rdata[6];
struct nmb_packet *nmb = &p->packet.nmb;
char rdata[6];
memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
reply_netbios_packet(p, /* Packet to reply to. */
rcode, /* Result code. */
NMB_REL, /* nmbd type code. */
NMB_NAME_RELEASE_OPCODE, /* opcode. */
0, /* ttl. */
rdata, /* data to send. */
6); /* data length. */
reply_netbios_packet(p, /* Packet to reply to. */
rcode, /* Result code. */
NMB_REL, /* nmbd type code. */
NMB_NAME_RELEASE_OPCODE, /* opcode. */
0, /* ttl. */
rdata, /* data to send. */
6); /* data length. */
}
/****************************************************************************
@ -55,76 +55,74 @@ Ignore it if it's not one of our names.
void process_name_release_request(struct subnet_record *subrec,
struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
struct in_addr owner_ip;
struct nmb_name *question = &nmb->question.question_name;
BOOL bcast = nmb->header.nm_flags.bcast;
uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
BOOL group = (nb_flags & NB_GROUP) ? True : False;
struct name_record *namerec;
int rcode = 0;
struct nmb_packet *nmb = &p->packet.nmb;
struct in_addr owner_ip;
struct nmb_name *question = &nmb->question.question_name;
nstring qname;
BOOL bcast = nmb->header.nm_flags.bcast;
uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
BOOL group = (nb_flags & NB_GROUP) ? True : False;
struct name_record *namerec;
int rcode = 0;
putip((char *)&owner_ip,&nmb->additional->rdata[2]);
putip((char *)&owner_ip,&nmb->additional->rdata[2]);
if(!bcast)
{
/* We should only get broadcast name release packets here.
Anyone trying to release unicast should be going to a WINS
server. If the code gets here, then either we are not a wins
server and they sent it anyway, or we are a WINS server and
the request was malformed. Either way, log an error here.
and send an error reply back.
*/
DEBUG(0,("process_name_release_request: unicast name release request \
if(!bcast) {
/* We should only get broadcast name release packets here.
Anyone trying to release unicast should be going to a WINS
server. If the code gets here, then either we are not a wins
server and they sent it anyway, or we are a WINS server and
the request was malformed. Either way, log an error here.
and send an error reply back.
*/
DEBUG(0,("process_name_release_request: unicast name release request \
received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name));
nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name));
send_name_release_response(FMT_ERR, p);
return;
}
send_name_release_response(FMT_ERR, p);
return;
}
DEBUG(3,("process_name_release_request: Name release on name %s, \
DEBUG(3,("process_name_release_request: Name release on name %s, \
subnet %s from owner IP %s\n",
nmb_namestr(&nmb->question.question_name),
subrec->subnet_name, inet_ntoa(owner_ip)));
nmb_namestr(&nmb->question.question_name),
subrec->subnet_name, inet_ntoa(owner_ip)));
/* If someone is releasing a broadcast group name, just ignore it. */
if( group && !ismyip(owner_ip) )
return;
/* If someone is releasing a broadcast group name, just ignore it. */
if( group && !ismyip(owner_ip) )
return;
/*
* Code to work around a bug in FTP OnNet software NBT implementation.
* They do a broadcast name release for WORKGROUP<0> and WORKGROUP<1e>
* names and *don't set the group bit* !!!!!
*/
/*
* Code to work around a bug in FTP OnNet software NBT implementation.
* They do a broadcast name release for WORKGROUP<0> and WORKGROUP<1e>
* names and *don't set the group bit* !!!!!
*/
if( !group && !ismyip(owner_ip) && strequal(question->name, lp_workgroup()) &&
((question->name_type == 0x0) || (question->name_type == 0x1e)))
{
DEBUG(6,("process_name_release_request: FTP OnNet bug workaround. Ignoring \
pull_ascii_nstring(qname, question->name);
if( !group && !ismyip(owner_ip) && strequal(qname, lp_workgroup()) &&
((question->name_type == 0x0) || (question->name_type == 0x1e))) {
DEBUG(6,("process_name_release_request: FTP OnNet bug workaround. Ignoring \
group release name %s from IP %s on subnet %s with no group bit set.\n",
nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name ));
return;
}
nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name ));
return;
}
namerec = find_name_on_subnet(subrec, &nmb->question.question_name, FIND_ANY_NAME);
namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
/* We only care about someone trying to release one of our names. */
if( namerec
&& ( (namerec->data.source == SELF_NAME)
|| (namerec->data.source == PERMANENT_NAME) ) )
{
rcode = ACT_ERR;
DEBUG(0, ("process_name_release_request: Attempt to release name %s from IP %s \
/* We only care about someone trying to release one of our names. */
if( namerec && ( (namerec->data.source == SELF_NAME)
|| (namerec->data.source == PERMANENT_NAME) ) ) {
rcode = ACT_ERR;
DEBUG(0, ("process_name_release_request: Attempt to release name %s from IP %s \
on subnet %s being rejected as it is one of our names.\n",
nmb_namestr(&nmb->question.question_name), inet_ntoa(owner_ip), subrec->subnet_name));
}
nmb_namestr(&nmb->question.question_name), inet_ntoa(owner_ip), subrec->subnet_name));
}
if(rcode == 0)
return;
if(rcode == 0)
return;
/* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
send_name_release_response(rcode, p);
/* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
send_name_release_response(rcode, p);
}
/****************************************************************************
@ -133,18 +131,18 @@ Send a name registration response.
static void send_name_registration_response(int rcode, int ttl, struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
char rdata[6];
struct nmb_packet *nmb = &p->packet.nmb;
char rdata[6];
memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
reply_netbios_packet(p, /* Packet to reply to. */
rcode, /* Result code. */
NMB_REG, /* nmbd type code. */
NMB_NAME_REG_OPCODE, /* opcode. */
ttl, /* ttl. */
rdata, /* data to send. */
6); /* data length. */
reply_netbios_packet(p, /* Packet to reply to. */
rcode, /* Result code. */
NMB_REG, /* nmbd type code. */
NMB_NAME_REG_OPCODE, /* opcode. */
ttl, /* ttl. */
rdata, /* data to send. */
6); /* data length. */
}
/****************************************************************************
@ -154,38 +152,34 @@ Process a name refresh request on a broadcast subnet.
void process_name_refresh_request(struct subnet_record *subrec,
struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
struct nmb_name *question = &nmb->question.question_name;
BOOL bcast = nmb->header.nm_flags.bcast;
struct in_addr from_ip;
struct nmb_packet *nmb = &p->packet.nmb;
struct nmb_name *question = &nmb->question.question_name;
BOOL bcast = nmb->header.nm_flags.bcast;
struct in_addr from_ip;
putip((char *)&from_ip,&nmb->additional->rdata[2]);
putip((char *)&from_ip,&nmb->additional->rdata[2]);
if(!bcast)
{
/* We should only get broadcast name refresh packets here.
Anyone trying to refresh unicast should be going to a WINS
server. If the code gets here, then either we are not a wins
server and they sent it anyway, or we are a WINS server and
the request was malformed. Either way, log an error here.
and send an error reply back.
*/
DEBUG(0,("process_name_refresh_request: unicast name registration request \
if(!bcast) {
/* We should only get broadcast name refresh packets here.
Anyone trying to refresh unicast should be going to a WINS
server. If the code gets here, then either we are not a wins
server and they sent it anyway, or we are a WINS server and
the request was malformed. Either way, log an error here.
and send an error reply back.
*/
DEBUG(0,("process_name_refresh_request: unicast name registration request \
received for name %s from IP %s on subnet %s.\n",
nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
DEBUG(0,("Error - should be sent to WINS server\n"));
nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
DEBUG(0,("Error - should be sent to WINS server\n"));
send_name_registration_response(FMT_ERR, 0, p);
return;
}
send_name_registration_response(FMT_ERR, 0, p);
return;
}
/* Just log a message. We really don't care about broadcast name
refreshes. */
/* Just log a message. We really don't care about broadcast name refreshes. */
DEBUG(3,("process_name_refresh_request: Name refresh for name %s \
DEBUG(3,("process_name_refresh_request: Name refresh for name %s \
IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
}
/****************************************************************************
@ -195,92 +189,83 @@ Process a name registration request on a broadcast subnet.
void process_name_registration_request(struct subnet_record *subrec,
struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
struct nmb_name *question = &nmb->question.question_name;
BOOL bcast = nmb->header.nm_flags.bcast;
uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
BOOL group = (nb_flags & NB_GROUP) ? True : False;
struct name_record *namerec = NULL;
int ttl = nmb->additional->ttl;
struct in_addr from_ip;
struct nmb_packet *nmb = &p->packet.nmb;
struct nmb_name *question = &nmb->question.question_name;
BOOL bcast = nmb->header.nm_flags.bcast;
uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
BOOL group = (nb_flags & NB_GROUP) ? True : False;
struct name_record *namerec = NULL;
int ttl = nmb->additional->ttl;
struct in_addr from_ip;
putip((char *)&from_ip,&nmb->additional->rdata[2]);
putip((char *)&from_ip,&nmb->additional->rdata[2]);
if(!bcast)
{
/* We should only get broadcast name registration packets here.
Anyone trying to register unicast should be going to a WINS
server. If the code gets here, then either we are not a wins
server and they sent it anyway, or we are a WINS server and
the request was malformed. Either way, log an error here.
and send an error reply back.
*/
DEBUG(0,("process_name_registration_request: unicast name registration request \
if(!bcast) {
/* We should only get broadcast name registration packets here.
Anyone trying to register unicast should be going to a WINS
server. If the code gets here, then either we are not a wins
server and they sent it anyway, or we are a WINS server and
the request was malformed. Either way, log an error here.
and send an error reply back.
*/
DEBUG(0,("process_name_registration_request: unicast name registration request \
received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
send_name_registration_response(FMT_ERR, 0, p);
return;
}
send_name_registration_response(FMT_ERR, 0, p);
return;
}
DEBUG(3,("process_name_registration_request: Name registration for name %s \
DEBUG(3,("process_name_registration_request: Name registration for name %s \
IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
/* See if the name already exists. */
namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
/* See if the name already exists. */
namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
/*
* If the name being registered exists and is a WINS_PROXY_NAME
* then delete the WINS proxy name entry so we don't reply erroneously
* later to queries.
*/
/*
* If the name being registered exists and is a WINS_PROXY_NAME
* then delete the WINS proxy name entry so we don't reply erroneously
* later to queries.
*/
if((namerec != NULL) && (namerec->data.source == WINS_PROXY_NAME))
{
remove_name_from_namelist( subrec, namerec );
namerec = NULL;
}
if((namerec != NULL) && (namerec->data.source == WINS_PROXY_NAME)) {
remove_name_from_namelist( subrec, namerec );
namerec = NULL;
}
if (!group)
{
/* Unique name. */
if (!group) {
/* Unique name. */
if( (namerec != NULL)
&& ( (namerec->data.source == SELF_NAME)
|| (namerec->data.source == PERMANENT_NAME)
|| NAME_GROUP(namerec) ) )
{
/* No-one can register one of Samba's names, nor can they
register a name that's a group name as a unique name */
if( (namerec != NULL)
&& ( (namerec->data.source == SELF_NAME)
|| (namerec->data.source == PERMANENT_NAME)
|| NAME_GROUP(namerec) ) ) {
/* No-one can register one of Samba's names, nor can they
register a name that's a group name as a unique name */
send_name_registration_response(ACT_ERR, 0, p);
return;
}
else if(namerec != NULL)
{
/* Update the namelist record with the new information. */
namerec->data.ip[0] = from_ip;
update_name_ttl(namerec, ttl);
send_name_registration_response(ACT_ERR, 0, p);
return;
} else if(namerec != NULL) {
/* Update the namelist record with the new information. */
namerec->data.ip[0] = from_ip;
update_name_ttl(namerec, ttl);
DEBUG(3,("process_name_registration_request: Updated name record %s \
DEBUG(3,("process_name_registration_request: Updated name record %s \
with IP %s on subnet %s\n",nmb_namestr(&namerec->name),inet_ntoa(from_ip), subrec->subnet_name));
return;
}
}
else
{
/* Group name. */
return;
}
} else {
/* Group name. */
if( (namerec != NULL)
&& !NAME_GROUP(namerec)
&& ( (namerec->data.source == SELF_NAME)
|| (namerec->data.source == PERMANENT_NAME) ) )
{
/* Disallow group names when we have a unique name. */
send_name_registration_response(ACT_ERR, 0, p);
return;
}
}
if( (namerec != NULL)
&& !NAME_GROUP(namerec)
&& ( (namerec->data.source == SELF_NAME)
|| (namerec->data.source == PERMANENT_NAME) ) ) {
/* Disallow group names when we have a unique name. */
send_name_registration_response(ACT_ERR, 0, p);
return;
}
}
}
/****************************************************************************
@ -290,147 +275,150 @@ We put our own names first, then in alphabetical order.
static int status_compare(char *n1,char *n2)
{
int l1,l2,l3;
nstring name1, name2;
int l1,l2,l3;
/* It's a bit tricky because the names are space padded */
for (l1=0;l1<15 && n1[l1] && n1[l1] != ' ';l1++) ;
for (l2=0;l2<15 && n2[l2] && n2[l2] != ' ';l2++) ;
l3 = strlen(global_myname());
pull_ascii_nstring(name1, n1);
pull_ascii_nstring(name2, n2);
n1 = name1;
n2 = name2;
if ((l1==l3) && strncmp(n1,global_myname(),l3) == 0 &&
(l2!=l3 || strncmp(n2,global_myname(),l3) != 0))
return -1;
/* It's a bit tricky because the names are space padded */
for (l1=0;l1<15 && n1[l1] && n1[l1] != ' ';l1++)
;
for (l2=0;l2<15 && n2[l2] && n2[l2] != ' ';l2++)
;
l3 = strlen(global_myname());
if ((l2==l3) && strncmp(n2,global_myname(),l3) == 0 &&
(l1!=l3 || strncmp(n1,global_myname(),l3) != 0))
return 1;
if ((l1==l3) && strncmp(n1,global_myname(),l3) == 0 &&
(l2!=l3 || strncmp(n2,global_myname(),l3) != 0))
return -1;
return memcmp(n1,n2,18);
if ((l2==l3) && strncmp(n2,global_myname(),l3) == 0 &&
(l1!=l3 || strncmp(n1,global_myname(),l3) != 0))
return 1;
return memcmp(n1,n2,sizeof(nstring));
}
/****************************************************************************
Process a node status query
****************************************************************************/
void process_node_status_request(struct subnet_record *subrec, struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
char *qname = nmb->question.question_name.name;
int ques_type = nmb->question.question_name.name_type;
char rdata[MAX_DGRAM_SIZE];
char *countptr, *buf, *bufend, *buf0;
int names_added,i;
struct name_record *namerec;
struct nmb_packet *nmb = &p->packet.nmb;
nstring qname;
int ques_type = nmb->question.question_name.name_type;
char rdata[MAX_DGRAM_SIZE];
char *countptr, *buf, *bufend, *buf0;
int names_added,i;
struct name_record *namerec;
DEBUG(3,("process_node_status_request: status request for name %s from IP %s on \
subnet %s.\n", nmb_namestr(&nmb->question.question_name), inet_ntoa(p->ip),
subrec->subnet_name));
pull_ascii_nstring(qname, nmb->question.question_name.name);
if((namerec = find_name_on_subnet(subrec, &nmb->question.question_name,
FIND_SELF_NAME)) == 0)
{
DEBUG(1,("process_node_status_request: status request for name %s from IP %s on \
DEBUG(3,("process_node_status_request: status request for name %s from IP %s on \
subnet %s.\n", nmb_namestr(&nmb->question.question_name), inet_ntoa(p->ip), subrec->subnet_name));
if((namerec = find_name_on_subnet(subrec, &nmb->question.question_name, FIND_SELF_NAME)) == 0) {
DEBUG(1,("process_node_status_request: status request for name %s from IP %s on \
subnet %s - name not found.\n", nmb_namestr(&nmb->question.question_name),
inet_ntoa(p->ip), subrec->subnet_name));
inet_ntoa(p->ip), subrec->subnet_name));
return;
}
return;
}
/* this is not an exact calculation. the 46 is for the stats buffer
and the 60 is to leave room for the header etc */
bufend = &rdata[MAX_DGRAM_SIZE] - (18 + 46 + 60);
countptr = buf = rdata;
buf += 1;
buf0 = buf;
/* this is not an exact calculation. the 46 is for the stats buffer
and the 60 is to leave room for the header etc */
bufend = &rdata[MAX_DGRAM_SIZE] - (18 + 46 + 60);
countptr = buf = rdata;
buf += 1;
buf0 = buf;
names_added = 0;
names_added = 0;
namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
while (buf < bufend)
{
if( (namerec->data.source == SELF_NAME)
|| (namerec->data.source == PERMANENT_NAME) )
{
int name_type = namerec->name.name_type;
if (!strequal(namerec->name.name,"*") &&
!strequal(namerec->name.name,"__SAMBA__") &&
(name_type < 0x1b || name_type >= 0x20 ||
ques_type < 0x1b || ques_type >= 0x20 ||
strequal(qname, namerec->name.name)))
{
/* Start with the name. */
memset(buf,'\0',18);
slprintf(buf, 17, "%-15.15s",namerec->name.name);
strupper_m(buf);
/* Put the name type and netbios flags in the buffer. */
buf[15] = name_type;
set_nb_flags( &buf[16],namerec->data.nb_flags );
buf[16] |= NB_ACTIVE; /* all our names are active */
while (buf < bufend) {
if( (namerec->data.source == SELF_NAME) || (namerec->data.source == PERMANENT_NAME) ) {
int name_type = namerec->name.name_type;
nstring name;
buf += 18;
pull_ascii_nstring(name, namerec->name.name);
strupper_m(name);
if (!strequal(name,"*") &&
!strequal(name,"__SAMBA__") &&
(name_type < 0x1b || name_type >= 0x20 ||
ques_type < 0x1b || ques_type >= 0x20 ||
strequal(qname, name))) {
/* Start with the name. */
nstring tmp_name;
memset(tmp_name,'\0',sizeof(tmp_name));
snprintf(tmp_name, sizeof(tmp_name), "%-15.15s",name);
push_ascii_nstring(buf, tmp_name);
names_added++;
}
}
/* Put the name type and netbios flags in the buffer. */
/* Remove duplicate names. */
if (names_added > 1) {
qsort( buf0, names_added, 18, QSORT_CAST status_compare );
}
buf[15] = name_type;
set_nb_flags( &buf[16],namerec->data.nb_flags );
buf[16] |= NB_ACTIVE; /* all our names are active */
for( i=1; i < names_added ; i++ )
{
if (memcmp(buf0 + 18*i,buf0 + 18*(i-1),16) == 0)
{
names_added--;
if (names_added == i)
break;
memmove(buf0 + 18*i,buf0 + 18*(i+1),18*(names_added-i));
i--;
}
}
buf += 18;
buf = buf0 + 18*names_added;
names_added++;
}
}
namerec = (struct name_record *)ubi_trNext( namerec );
/* Remove duplicate names. */
if (names_added > 1) {
qsort( buf0, names_added, 18, QSORT_CAST status_compare );
}
if (!namerec)
{
/* End of the subnet specific name list. Now
add the names on the unicast subnet . */
struct subnet_record *uni_subrec = unicast_subnet;
for( i=1; i < names_added ; i++ ) {
if (memcmp(buf0 + 18*i,buf0 + 18*(i-1),16) == 0) {
names_added--;
if (names_added == i)
break;
memmove(buf0 + 18*i,buf0 + 18*(i+1),18*(names_added-i));
i--;
}
}
if (uni_subrec != subrec)
{
subrec = uni_subrec;
namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
}
}
if (!namerec)
break;
buf = buf0 + 18*names_added;
}
namerec = (struct name_record *)ubi_trNext( namerec );
if (!namerec) {
/* End of the subnet specific name list. Now
add the names on the unicast subnet . */
struct subnet_record *uni_subrec = unicast_subnet;
if (uni_subrec != subrec) {
subrec = uni_subrec;
namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
}
}
if (!namerec)
break;
}
SCVAL(countptr,0,names_added);
SCVAL(countptr,0,names_added);
/* We don't send any stats as they could be used to attack
the protocol. */
memset(buf,'\0',46);
/* We don't send any stats as they could be used to attack
the protocol. */
memset(buf,'\0',46);
buf += 46;
buf += 46;
/* Send a NODE STATUS RESPONSE */
reply_netbios_packet(p, /* Packet to reply to. */
0, /* Result code. */
NMB_STATUS, /* nmbd type code. */
NMB_NAME_QUERY_OPCODE, /* opcode. */
0, /* ttl. */
rdata, /* data to send. */
PTR_DIFF(buf,rdata)); /* data length. */
/* Send a NODE STATUS RESPONSE */
reply_netbios_packet(p, /* Packet to reply to. */
0, /* Result code. */
NMB_STATUS, /* nmbd type code. */
NMB_NAME_QUERY_OPCODE, /* opcode. */
0, /* ttl. */
rdata, /* data to send. */
PTR_DIFF(buf,rdata)); /* data length. */
}

View File

@ -28,50 +28,46 @@
/****************************************************************************
Load a lmhosts file.
****************************************************************************/
void load_lmhosts_file(char *fname)
{
pstring name;
int name_type;
struct in_addr ipaddr;
XFILE *fp = startlmhosts( fname );
pstring name;
int name_type;
struct in_addr ipaddr;
XFILE *fp = startlmhosts( fname );
if (!fp) {
DEBUG(2,("load_lmhosts_file: Can't open lmhosts file %s. Error was %s\n",
fname, strerror(errno)));
return;
}
if (!fp) {
DEBUG(2,("load_lmhosts_file: Can't open lmhosts file %s. Error was %s\n",
fname, strerror(errno)));
return;
}
while (getlmhostsent(fp, name, &name_type, &ipaddr) )
{
struct subnet_record *subrec = NULL;
enum name_source source = LMHOSTS_NAME;
while (getlmhostsent(fp, name, &name_type, &ipaddr) ) {
struct subnet_record *subrec = NULL;
enum name_source source = LMHOSTS_NAME;
/* We find a relevent subnet to put this entry on, then add it. */
/* Go through all the broadcast subnets and see if the mask matches. */
for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
{
if(same_net(ipaddr, subrec->bcast_ip, subrec->mask_ip))
break;
}
/* We find a relevent subnet to put this entry on, then add it. */
/* Go through all the broadcast subnets and see if the mask matches. */
for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
if(same_net(ipaddr, subrec->bcast_ip, subrec->mask_ip))
break;
}
/* If none match add the name to the remote_broadcast_subnet. */
if(subrec == NULL)
subrec = remote_broadcast_subnet;
/* If none match add the name to the remote_broadcast_subnet. */
if(subrec == NULL)
subrec = remote_broadcast_subnet;
if(name_type == -1)
{
/* Add the (0) and (0x20) names directly into the namelist for this subnet. */
(void)add_name_to_subnet(subrec,name,0x00,(uint16)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr);
(void)add_name_to_subnet(subrec,name,0x20,(uint16)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr);
}
else
{
/* Add the given name type to the subnet namelist. */
(void)add_name_to_subnet(subrec,name,name_type,(uint16)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr);
}
}
if(name_type == -1) {
/* Add the (0) and (0x20) names directly into the namelist for this subnet. */
(void)add_name_to_subnet(subrec,name,0x00,(uint16)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr);
(void)add_name_to_subnet(subrec,name,0x20,(uint16)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr);
} else {
/* Add the given name type to the subnet namelist. */
(void)add_name_to_subnet(subrec,name,name_type,(uint16)NB_ACTIVE,PERMANENT_TTL,source,1,&ipaddr);
}
}
endlmhosts(fp);
endlmhosts(fp);
}
/****************************************************************************
@ -82,17 +78,16 @@ void load_lmhosts_file(char *fname)
BOOL find_name_in_lmhosts(struct nmb_name *nmbname, struct name_record **namerecp)
{
struct name_record *namerec;
struct name_record *namerec;
*namerecp = NULL;
*namerecp = NULL;
if((namerec = find_name_on_subnet(remote_broadcast_subnet, nmbname,
FIND_ANY_NAME))==NULL)
return False;
if((namerec = find_name_on_subnet(remote_broadcast_subnet, nmbname, FIND_ANY_NAME))==NULL)
return False;
if(!NAME_IS_ACTIVE(namerec) || (namerec->data.source != LMHOSTS_NAME))
return False;
if(!NAME_IS_ACTIVE(namerec) || (namerec->data.source != LMHOSTS_NAME))
return False;
*namerecp = namerec;
return True;
*namerecp = namerec;
return True;
}

View File

@ -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,38 +29,40 @@ extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
/****************************************************************************
Fail to become a Logon server on a subnet.
****************************************************************************/
****************************************************************************/
static void become_logon_server_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_logon_server_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_logon_server_fail: Error - cannot find \
workgroup %s on subnet %s\n", failname, subrec->subnet_name));
return;
}
if((servrec = find_server_in_workgroup( work, global_myname())) == NULL)
{
DEBUG(0,("become_logon_server_fail: Error - cannot find server %s \
if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
DEBUG(0,("become_logon_server_fail: Error - cannot find server %s \
in workgroup %s on subnet %s\n",
global_myname(), fail_name->name, subrec->subnet_name));
work->log_state = LOGON_NONE;
return;
}
global_myname(), failname, subrec->subnet_name));
work->log_state = LOGON_NONE;
return;
}
/* Set the state back to LOGON_NONE. */
work->log_state = LOGON_NONE;
/* Set the state back to LOGON_NONE. */
work->log_state = LOGON_NONE;
servrec->serv.type &= ~SV_TYPE_DOMAIN_CTRL;
servrec->serv.type &= ~SV_TYPE_DOMAIN_CTRL;
DEBUG(0,("become_logon_server_fail: Failed to become a domain master for \
DEBUG(0,("become_logon_server_fail: Failed to become a domain master 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)));
}
@ -74,49 +76,51 @@ static void become_logon_server_success(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 reg_name;
struct work_record *work;
struct server_record *servrec;
if(!work)
{
DEBUG(0,("become_logon_server_success: Error - cannot find \
workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
return;
}
pull_ascii_nstring(reg_name, registered_name->name);
work = find_workgroup_on_subnet( subrec, reg_name);
if(!work) {
DEBUG(0,("become_logon_server_success: Error - cannot find \
workgroup %s on subnet %s\n", reg_name, subrec->subnet_name));
return;
}
if((servrec = find_server_in_workgroup( work, global_myname())) == NULL)
{
DEBUG(0,("become_logon_server_success: Error - cannot find server %s \
if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
DEBUG(0,("become_logon_server_success: Error - cannot find server %s \
in workgroup %s on subnet %s\n",
global_myname(), registered_name->name, subrec->subnet_name));
work->log_state = LOGON_NONE;
return;
}
global_myname(), reg_name, subrec->subnet_name));
work->log_state = LOGON_NONE;
return;
}
/* Set the state in the workgroup structure. */
work->log_state = LOGON_SRV; /* Become domain master. */
/* Set the state in the workgroup structure. */
work->log_state = LOGON_SRV; /* Become domain master. */
/* Update our server status. */
servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MEMBER);
/* To allow Win95 policies to load we need to set type domain
controller.
*/
servrec->serv.type |= SV_TYPE_DOMAIN_CTRL;
/* Update our server status. */
servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MEMBER);
/* To allow Win95 policies to load we need to set type domain
controller.
*/
servrec->serv.type |= SV_TYPE_DOMAIN_CTRL;
/* 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 the WORKGROUP<1C> name to the UNICAST subnet with the IP address
* for this subnet so we will respond to queries on this name.
*/
{
struct nmb_name nmbname;
make_nmb_name(&nmbname,lp_workgroup(),0x1c);
insert_permanent_name_into_unicast(subrec, &nmbname, 0x1c);
}
/*
* Add the WORKGROUP<1C> name to the UNICAST subnet with the IP address
* for this subnet so we will respond to queries on this name.
*/
DEBUG(0,("become_logon_server_success: Samba is now a logon server \
{
struct nmb_name nmbname;
make_nmb_name(&nmbname,lp_workgroup(),0x1c);
insert_permanent_name_into_unicast(subrec, &nmbname, 0x1c);
}
DEBUG(0,("become_logon_server_success: Samba is now a logon server \
for workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
}
@ -128,45 +132,42 @@ for workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
static void become_logon_server(struct subnet_record *subrec,
struct work_record *work)
{
DEBUG(2,("become_logon_server: Atempting to become logon server for workgroup %s \
DEBUG(2,("become_logon_server: Atempting to become logon server for workgroup %s \
on subnet %s\n", work->work_group,subrec->subnet_name));
DEBUG(3,("become_logon_server: go to first stage: register %s<1c> name\n",
work->work_group));
work->log_state = LOGON_WAIT;
DEBUG(3,("become_logon_server: go to first stage: register %s<1c> name\n",
work->work_group));
work->log_state = LOGON_WAIT;
register_name(subrec, work->work_group,0x1c,samba_nb_type|NB_GROUP,
become_logon_server_success,
become_logon_server_fail, NULL);
register_name(subrec, work->work_group,0x1c,samba_nb_type|NB_GROUP,
become_logon_server_success,
become_logon_server_fail, NULL);
}
/*****************************************************************************
Add the internet group <1c> logon names by unicast and broadcast.
****************************************************************************/
void add_logon_names(void)
{
struct subnet_record *subrec;
struct subnet_record *subrec;
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
{
struct work_record *work = find_workgroup_on_subnet(subrec, lp_workgroup());
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
struct work_record *work = find_workgroup_on_subnet(subrec, lp_workgroup());
if (work && (work->log_state == LOGON_NONE))
{
struct nmb_name nmbname;
make_nmb_name(&nmbname,lp_workgroup(),0x1c);
if (work && (work->log_state == LOGON_NONE)) {
struct nmb_name nmbname;
make_nmb_name(&nmbname,lp_workgroup(),0x1c);
if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL)
{
if( DEBUGLVL( 0 ) )
{
dbgtext( "add_domain_logon_names:\n" );
dbgtext( "Attempting to become logon server " );
dbgtext( "for workgroup %s ", lp_workgroup() );
dbgtext( "on subnet %s\n", subrec->subnet_name );
}
become_logon_server(subrec, work);
}
}
}
if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL) {
if( DEBUGLVL( 0 ) ) {
dbgtext( "add_domain_logon_names:\n" );
dbgtext( "Attempting to become logon server " );
dbgtext( "for workgroup %s ", lp_workgroup() );
dbgtext( "on subnet %s\n", subrec->subnet_name );
}
become_logon_server(subrec, work);
}
}
}
}

View File

@ -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
@ -27,20 +27,21 @@ extern uint16 samba_nb_type; /* Samba's NetBIOS type. */
/****************************************************************************
Fail funtion when registering my netbios names.
**************************************************************************/
**************************************************************************/
static void my_name_register_failed(struct subnet_record *subrec,
struct response_record *rrec, struct nmb_name *nmbname)
{
DEBUG(0,("my_name_register_failed: Failed to register my name %s on subnet %s.\n",
nmb_namestr(nmbname), subrec->subnet_name));
DEBUG(0,("my_name_register_failed: Failed to register my name %s on subnet %s.\n",
nmb_namestr(nmbname), subrec->subnet_name));
}
/****************************************************************************
Add my workgroup and my given names to one subnet
Also add the magic Samba names.
**************************************************************************/
**************************************************************************/
void register_my_workgroup_one_subnet(struct subnet_record *subrec)
{
int i;
@ -84,111 +85,104 @@ Exiting.\n", lp_workgroup(), subrec->subnet_name));
static void insert_refresh_name_into_unicast( struct subnet_record *subrec,
struct nmb_name *nmbname, uint16 nb_type )
{
struct name_record *namerec;
struct name_record *namerec;
if (!we_are_a_wins_client()) {
insert_permanent_name_into_unicast(subrec, nmbname, nb_type);
return;
}
if (!we_are_a_wins_client()) {
insert_permanent_name_into_unicast(subrec, nmbname, nb_type);
return;
}
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,
MIN(lp_max_ttl(), MAX_REFRESH_TIME), SELF_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) {
nstring name;
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,
MIN(lp_max_ttl(), MAX_REFRESH_TIME), SELF_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);
}
}
/****************************************************************************
Add my workgroup and my given names to the subnet lists.
Also add the magic Samba names.
**************************************************************************/
**************************************************************************/
BOOL register_my_workgroup_and_names(void)
{
struct subnet_record *subrec;
int i;
struct subnet_record *subrec;
int i;
for(subrec = FIRST_SUBNET;
subrec;
subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
{
register_my_workgroup_one_subnet(subrec);
}
for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
register_my_workgroup_one_subnet(subrec);
}
/* We still need to add the magic Samba
names and the netbios names to the unicast subnet directly. This is
to allow unicast node status requests and queries to still work
in a broadcast only environment. */
/* We still need to add the magic Samba
names and the netbios names to the unicast subnet directly. This is
to allow unicast node status requests and queries to still work
in a broadcast only environment. */
add_samba_names_to_subnet(unicast_subnet);
add_samba_names_to_subnet(unicast_subnet);
for (i=0; my_netbios_names(i); i++)
{
for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
{
/*
* Ensure all the IP addresses are added if we are multihomed.
*/
struct nmb_name nmbname;
for (i=0; my_netbios_names(i); i++) {
for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
/*
* Ensure all the IP addresses are added if we are multihomed.
*/
struct nmb_name nmbname;
make_nmb_name(&nmbname, my_netbios_names(i),0x20);
insert_refresh_name_into_unicast(subrec, &nmbname, samba_nb_type);
make_nmb_name(&nmbname, my_netbios_names(i),0x20);
insert_refresh_name_into_unicast(subrec, &nmbname, samba_nb_type);
make_nmb_name(&nmbname, my_netbios_names(i),0x3);
insert_refresh_name_into_unicast(subrec, &nmbname, samba_nb_type);
make_nmb_name(&nmbname, my_netbios_names(i),0x3);
insert_refresh_name_into_unicast(subrec, &nmbname, samba_nb_type);
make_nmb_name(&nmbname, my_netbios_names(i),0x0);
insert_refresh_name_into_unicast(subrec, &nmbname, samba_nb_type);
}
}
make_nmb_name(&nmbname, my_netbios_names(i),0x0);
insert_refresh_name_into_unicast(subrec, &nmbname, samba_nb_type);
}
}
/*
* Add the WORKGROUP<0> and WORKGROUP<1e> group names to the unicast subnet
* also for the same reasons.
*/
/*
* Add the WORKGROUP<0> and WORKGROUP<1e> group names to the unicast subnet
* also for the same reasons.
*/
for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
{
/*
* Ensure all the IP addresses are added if we are multihomed.
*/
struct nmb_name nmbname;
for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
/*
* Ensure all the IP addresses are added if we are multihomed.
*/
struct nmb_name nmbname;
make_nmb_name(&nmbname, lp_workgroup(), 0x0);
insert_refresh_name_into_unicast(subrec, &nmbname, samba_nb_type|NB_GROUP);
make_nmb_name(&nmbname, lp_workgroup(), 0x0);
insert_refresh_name_into_unicast(subrec, &nmbname, samba_nb_type|NB_GROUP);
make_nmb_name(&nmbname, lp_workgroup(), 0x1e);
insert_refresh_name_into_unicast(subrec, &nmbname, samba_nb_type|NB_GROUP);
}
make_nmb_name(&nmbname, lp_workgroup(), 0x1e);
insert_refresh_name_into_unicast(subrec, &nmbname, samba_nb_type|NB_GROUP);
}
/*
* We need to add the Samba names to the remote broadcast subnet,
* as NT 4.x does directed broadcast requests to the *<0x0> name.
*/
add_samba_names_to_subnet(remote_broadcast_subnet);
/*
* We need to add the Samba names to the remote broadcast subnet,
* as NT 4.x does directed broadcast requests to the *<0x0> name.
*/
return True;
add_samba_names_to_subnet(remote_broadcast_subnet);
return True;
}
/****************************************************************************
Remove all the names we registered.
**************************************************************************/
void release_wins_names(void)
{
struct subnet_record *subrec = unicast_subnet;
struct name_record *namerec, *nextnamerec;
for (namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
namerec;
namerec = nextnamerec) {
for (namerec = (struct name_record *)ubi_trFirst( subrec->namelist ); namerec; namerec = nextnamerec) {
nextnamerec = (struct name_record *)ubi_trNext( namerec );
if( (namerec->data.source == SELF_NAME)
&& !NAME_IS_DEREGISTERING(namerec) )
@ -199,12 +193,14 @@ void release_wins_names(void)
/*******************************************************************
Refresh our registered names with WINS
******************************************************************/
******************************************************************/
void refresh_my_names(time_t t)
{
struct name_record *namerec;
if (wins_srv_count() < 1) return;
if (wins_srv_count() < 1)
return;
for (namerec = (struct name_record *)ubi_trFirst(unicast_subnet->namelist);
namerec;

View File

@ -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
@ -26,152 +26,149 @@
uint16 samba_nb_type = 0; /* samba's NetBIOS name type */
/* ************************************************************************** **
* Set Samba's NetBIOS name type.
* ************************************************************************** **
*/
/**************************************************************************
Set Samba's NetBIOS name type.
***************************************************************************/
void set_samba_nb_type(void)
{
if( lp_wins_support() || wins_srv_count() )
samba_nb_type = NB_HFLAG; /* samba is a 'hybrid' node type. */
else
samba_nb_type = NB_BFLAG; /* samba is broadcast-only node type. */
} /* set_samba_nb_type */
{
if( lp_wins_support() || wins_srv_count() )
samba_nb_type = NB_HFLAG; /* samba is a 'hybrid' node type. */
else
samba_nb_type = NB_BFLAG; /* samba is broadcast-only node type. */
}
/***************************************************************************
Convert a NetBIOS name to upper case.
***************************************************************************/
/* ************************************************************************** **
* Convert a NetBIOS name to upper case.
* ************************************************************************** **
*/
static void upcase_name( struct nmb_name *target, struct nmb_name *source )
{
int i;
{
int i;
nstring targ;
fstring scope;
if( NULL != source )
(void)memcpy( target, source, sizeof( struct nmb_name ) );
if( NULL != source )
memcpy( target, source, sizeof( struct nmb_name ) );
strupper_m( target->name );
strupper_m( target->scope );
pull_ascii_nstring(targ, target->name);
strupper_m( targ );
push_ascii_nstring( target->name, targ);
/* fudge... We're using a byte-by-byte compare, so we must be sure that
* unused space doesn't have garbage in it.
*/
for( i = strlen( target->name ); i < sizeof( target->name ); i++ )
target->name[i] = '\0';
for( i = strlen( target->scope ); i < sizeof( target->scope ); i++ )
target->scope[i] = '\0';
} /* upcase_name */
pull_ascii(scope, target->scope, 64, -1, STR_TERMINATE);
strupper_m( scope );
push_ascii(target->scope, scope, 64, STR_TERMINATE);
/* fudge... We're using a byte-by-byte compare, so we must be sure that
* unused space doesn't have garbage in it.
*/
for( i = strlen( target->name ); i < sizeof( target->name ); i++ )
target->name[i] = '\0';
for( i = strlen( target->scope ); i < sizeof( target->scope ); i++ )
target->scope[i] = '\0';
}
/**************************************************************************
Add a new or overwrite an existing namelist entry.
***************************************************************************/
/* ************************************************************************** **
* Add a new or overwrite an existing namelist entry.
* ************************************************************************** **
*/
static void update_name_in_namelist( struct subnet_record *subrec,
struct name_record *namerec )
{
struct name_record *oldrec = NULL;
{
struct name_record *oldrec = NULL;
(void)ubi_trInsert( subrec->namelist, namerec, &(namerec->name), &oldrec );
if( oldrec )
{
SAFE_FREE( oldrec->data.ip );
SAFE_FREE( oldrec );
}
} /* update_name_in_namelist */
ubi_trInsert( subrec->namelist, namerec, &(namerec->name), &oldrec );
if( oldrec ) {
SAFE_FREE( oldrec->data.ip );
SAFE_FREE( oldrec );
}
}
/**************************************************************************
Remove a name from the namelist.
***************************************************************************/
/* ************************************************************************** **
* Remove a name from the namelist.
* ************************************************************************** **
*/
void remove_name_from_namelist( struct subnet_record *subrec,
struct name_record *namerec )
{
(void)ubi_trRemove( subrec->namelist, namerec );
{
ubi_trRemove( subrec->namelist, namerec );
SAFE_FREE(namerec->data.ip);
ZERO_STRUCTP(namerec);
SAFE_FREE(namerec);
subrec->namelist_changed = True;
}
SAFE_FREE(namerec->data.ip);
/**************************************************************************
Find a name in a subnet.
**************************************************************************/
ZERO_STRUCTP(namerec);
SAFE_FREE(namerec);
subrec->namelist_changed = True;
} /* remove_name_from_namelist */
/* ************************************************************************** **
* Find a name in a subnet.
* ************************************************************************** **
*/
struct name_record *find_name_on_subnet( struct subnet_record *subrec,
struct nmb_name *nmbname,
BOOL self_only )
{
struct nmb_name uc_name[1];
struct name_record *name_ret;
{
struct nmb_name uc_name[1];
struct name_record *name_ret;
upcase_name( uc_name, nmbname );
name_ret = (struct name_record *)ubi_trFind( subrec->namelist, uc_name );
if( name_ret )
{
/* Self names only - these include permanent names. */
if( self_only
&& (name_ret->data.source != SELF_NAME)
&& (name_ret->data.source != PERMANENT_NAME) )
{
DEBUG( 9,
( "find_name_on_subnet: on subnet %s - self name %s NOT FOUND\n",
subrec->subnet_name, nmb_namestr(nmbname) ) );
return( NULL );
}
DEBUG( 9, ("find_name_on_subnet: on subnet %s - found name %s source=%d\n",
subrec->subnet_name, nmb_namestr(nmbname), name_ret->data.source) );
return( name_ret );
}
DEBUG( 9,
( "find_name_on_subnet: on subnet %s - name %s NOT FOUND\n",
subrec->subnet_name, nmb_namestr(nmbname) ) );
return( NULL );
} /* find_name_on_subnet */
upcase_name( uc_name, nmbname );
name_ret = (struct name_record *)ubi_trFind( subrec->namelist, uc_name );
if( name_ret ) {
/* Self names only - these include permanent names. */
if( self_only && (name_ret->data.source != SELF_NAME) && (name_ret->data.source != PERMANENT_NAME) ) {
DEBUG( 9, ( "find_name_on_subnet: on subnet %s - self name %s NOT FOUND\n",
subrec->subnet_name, nmb_namestr(nmbname) ) );
return( NULL );
}
DEBUG( 9, ("find_name_on_subnet: on subnet %s - found name %s source=%d\n",
subrec->subnet_name, nmb_namestr(nmbname), name_ret->data.source) );
return( name_ret );
}
DEBUG( 9, ( "find_name_on_subnet: on subnet %s - name %s NOT FOUND\n",
subrec->subnet_name, nmb_namestr(nmbname) ) );
return( NULL );
}
/**************************************************************************
Find a name over all known broadcast subnets.
************************************************************************/
/* ************************************************************************** **
* Find a name over all known broadcast subnets.
* ************************************************************************** **
*/
struct name_record *find_name_for_remote_broadcast_subnet(
struct nmb_name *nmbname,
BOOL self_only )
{
struct subnet_record *subrec;
struct name_record *namerec = NULL;
{
struct subnet_record *subrec;
struct name_record *namerec = NULL;
for( subrec = FIRST_SUBNET;
subrec;
subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) )
{
if( NULL != (namerec = find_name_on_subnet(subrec, nmbname, self_only)) )
break;
}
for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) ) {
if( NULL != (namerec = find_name_on_subnet(subrec, nmbname, self_only)) )
break;
}
return( namerec );
} /* find_name_for_remote_broadcast_subnet */
return( namerec );
}
/* ************************************************************************** **
* Update the ttl of an entry in a subnet name list.
* ************************************************************************** **
*/
/**************************************************************************
Update the ttl of an entry in a subnet name list.
***************************************************************************/
void update_name_ttl( struct name_record *namerec, int ttl )
{
time_t time_now = time(NULL);
time_t time_now = time(NULL);
if( namerec->data.death_time != PERMANENT_TTL )
namerec->data.death_time = time_now + ttl;
if( namerec->data.death_time != PERMANENT_TTL )
namerec->data.death_time = time_now + ttl;
namerec->data.refresh_time = time_now + MIN((ttl/2), MAX_REFRESH_TIME);
namerec->data.refresh_time = time_now + MIN((ttl/2), MAX_REFRESH_TIME);
namerec->subnet->namelist_changed = True;
} /* update_name_ttl */
namerec->subnet->namelist_changed = True;
}
/**************************************************************************
Add an entry to a subnet name list.
***********************************************************************/
/* ************************************************************************** **
* Add an entry to a subnet name list.
* ************************************************************************** **
*/
struct name_record *add_name_to_subnet( struct subnet_record *subrec,
const char *name,
int type,
@ -181,70 +178,66 @@ struct name_record *add_name_to_subnet( struct subnet_record *subrec,
int num_ips,
struct in_addr *iplist)
{
struct name_record *namerec;
time_t time_now = time(NULL);
struct name_record *namerec;
time_t time_now = time(NULL);
namerec = (struct name_record *)malloc( sizeof(*namerec) );
if( NULL == namerec )
{
DEBUG( 0, ( "add_name_to_subnet: malloc fail.\n" ) );
return( NULL );
}
namerec = (struct name_record *)malloc( sizeof(*namerec) );
if( NULL == namerec ) {
DEBUG( 0, ( "add_name_to_subnet: malloc fail.\n" ) );
return( NULL );
}
memset( (char *)namerec, '\0', sizeof(*namerec) );
namerec->data.ip = (struct in_addr *)malloc( sizeof(struct in_addr)
* num_ips );
if( NULL == namerec->data.ip )
{
DEBUG( 0, ( "add_name_to_subnet: malloc fail when creating ip_flgs.\n" ) );
memset( (char *)namerec, '\0', sizeof(*namerec) );
namerec->data.ip = (struct in_addr *)malloc( sizeof(struct in_addr) * num_ips );
if( NULL == namerec->data.ip ) {
DEBUG( 0, ( "add_name_to_subnet: malloc fail when creating ip_flgs.\n" ) );
ZERO_STRUCTP(namerec);
SAFE_FREE(namerec);
return NULL;
}
ZERO_STRUCTP(namerec);
SAFE_FREE(namerec);
return NULL;
}
namerec->subnet = subrec;
namerec->subnet = subrec;
make_nmb_name(&namerec->name, name, type);
upcase_name(&namerec->name, NULL );
make_nmb_name(&namerec->name, name, type);
upcase_name(&namerec->name, NULL );
/* Enter the name as active. */
namerec->data.nb_flags = nb_flags | NB_ACTIVE;
namerec->data.wins_flags = WINS_ACTIVE;
/* Enter the name as active. */
namerec->data.nb_flags = nb_flags | NB_ACTIVE;
namerec->data.wins_flags = WINS_ACTIVE;
/* If it's our primary name, flag it as so. */
if( strequal( my_netbios_names(0), name ) )
namerec->data.nb_flags |= NB_PERM;
/* If it's our primary name, flag it as so. */
if( strequal( my_netbios_names(0), name ) )
namerec->data.nb_flags |= NB_PERM;
/* Copy the IPs. */
namerec->data.num_ips = num_ips;
memcpy( (namerec->data.ip), iplist, num_ips * sizeof(struct in_addr) );
/* Copy the IPs. */
namerec->data.num_ips = num_ips;
memcpy( (namerec->data.ip), iplist, num_ips * sizeof(struct in_addr) );
/* Data source. */
namerec->data.source = source;
/* Data source. */
namerec->data.source = source;
/* Setup the death_time and refresh_time. */
if( ttl == PERMANENT_TTL )
namerec->data.death_time = PERMANENT_TTL;
else
namerec->data.death_time = time_now + ttl;
/* Setup the death_time and refresh_time. */
if( ttl == PERMANENT_TTL )
namerec->data.death_time = PERMANENT_TTL;
else
namerec->data.death_time = time_now + ttl;
namerec->data.refresh_time = time_now + MIN((ttl/2), MAX_REFRESH_TIME);
namerec->data.refresh_time = time_now + MIN((ttl/2), MAX_REFRESH_TIME);
/* Now add the record to the name list. */
update_name_in_namelist( subrec, namerec );
/* Now add the record to the name list. */
update_name_in_namelist( subrec, namerec );
DEBUG( 3, ( "add_name_to_subnet: Added netbios name %s with first IP %s \
DEBUG( 3, ( "add_name_to_subnet: Added netbios name %s with first IP %s \
ttl=%d nb_flags=%2x to subnet %s\n",
nmb_namestr( &namerec->name ),
inet_ntoa( *iplist ),
ttl,
(unsigned int)nb_flags,
subrec->subnet_name ) );
nmb_namestr( &namerec->name ),
inet_ntoa( *iplist ),
ttl,
(unsigned int)nb_flags,
subrec->subnet_name ) );
subrec->namelist_changed = True;
subrec->namelist_changed = True;
return(namerec);
return(namerec);
}
/*******************************************************************
@ -258,14 +251,17 @@ void standard_success_register(struct subnet_record *subrec,
struct nmb_name *nmbname, uint16 nb_flags, int ttl,
struct in_addr registered_ip)
{
struct name_record *namerec;
struct name_record *namerec;
namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME );
if( NULL == namerec )
(void)add_name_to_subnet( subrec, nmbname->name, nmbname->name_type,
nb_flags, ttl, SELF_NAME, 1, &registered_ip );
else
update_name_ttl( namerec, ttl );
namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME );
if( NULL == namerec ) {
nstring name;
pull_ascii_nstring(name, nmbname->name);
add_name_to_subnet( subrec, name, nmbname->name_type,
nb_flags, ttl, SELF_NAME, 1, &registered_ip );
} else {
update_name_ttl( namerec, ttl );
}
}
/*******************************************************************
@ -279,17 +275,16 @@ void standard_fail_register( struct subnet_record *subrec,
struct response_record *rrec,
struct nmb_name *nmbname )
{
struct name_record *namerec;
struct name_record *namerec;
namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME );
namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME );
DEBUG( 0, ( "standard_fail_register: Failed to register/refresh name %s \
on subnet %s\n",
nmb_namestr(nmbname), subrec->subnet_name) );
DEBUG( 0, ( "standard_fail_register: Failed to register/refresh name %s \
on subnet %s\n", nmb_namestr(nmbname), subrec->subnet_name) );
/* Remove the name from the subnet. */
if( namerec )
remove_name_from_namelist(subrec, namerec);
/* Remove the name from the subnet. */
if( namerec )
remove_name_from_namelist(subrec, namerec);
}
/*******************************************************************
@ -298,13 +293,13 @@ on subnet %s\n",
static void remove_nth_ip_in_record( struct name_record *namerec, int ind)
{
if( ind != namerec->data.num_ips )
memmove( (char *)(&namerec->data.ip[ind]),
(char *)(&namerec->data.ip[ind+1]),
( namerec->data.num_ips - ind - 1) * sizeof(struct in_addr) );
if( ind != namerec->data.num_ips )
memmove( (char *)(&namerec->data.ip[ind]),
(char *)(&namerec->data.ip[ind+1]),
( namerec->data.num_ips - ind - 1) * sizeof(struct in_addr) );
namerec->data.num_ips--;
namerec->subnet->namelist_changed = True;
namerec->data.num_ips--;
namerec->subnet->namelist_changed = True;
}
/*******************************************************************
@ -313,13 +308,13 @@ static void remove_nth_ip_in_record( struct name_record *namerec, int ind)
BOOL find_ip_in_name_record( struct name_record *namerec, struct in_addr ip )
{
int i;
int i;
for(i = 0; i < namerec->data.num_ips; i++)
if(ip_equal( namerec->data.ip[i], ip))
return True;
for(i = 0; i < namerec->data.num_ips; i++)
if(ip_equal( namerec->data.ip[i], ip))
return True;
return False;
return False;
}
/*******************************************************************
@ -328,30 +323,26 @@ BOOL find_ip_in_name_record( struct name_record *namerec, struct in_addr ip )
void add_ip_to_name_record( struct name_record *namerec, struct in_addr new_ip )
{
struct in_addr *new_list;
struct in_addr *new_list;
/* Don't add one we already have. */
if( find_ip_in_name_record( namerec, new_ip ) )
return;
/* Don't add one we already have. */
if( find_ip_in_name_record( namerec, new_ip ) )
return;
new_list = (struct in_addr *)malloc( (namerec->data.num_ips + 1)
* sizeof(struct in_addr) );
if( NULL == new_list )
{
DEBUG(0,("add_ip_to_name_record: Malloc fail !\n"));
return;
}
new_list = (struct in_addr *)malloc( (namerec->data.num_ips + 1) * sizeof(struct in_addr) );
if( NULL == new_list ) {
DEBUG(0,("add_ip_to_name_record: Malloc fail !\n"));
return;
}
memcpy( (char *)new_list,
(char *)namerec->data.ip,
namerec->data.num_ips * sizeof(struct in_addr) );
new_list[namerec->data.num_ips] = new_ip;
memcpy( (char *)new_list, (char *)namerec->data.ip, namerec->data.num_ips * sizeof(struct in_addr) );
new_list[namerec->data.num_ips] = new_ip;
SAFE_FREE(namerec->data.ip);
namerec->data.ip = new_list;
namerec->data.num_ips += 1;
SAFE_FREE(namerec->data.ip);
namerec->data.ip = new_list;
namerec->data.num_ips += 1;
namerec->subnet->namelist_changed = True;
namerec->subnet->namelist_changed = True;
}
/*******************************************************************
@ -361,16 +352,16 @@ void add_ip_to_name_record( struct name_record *namerec, struct in_addr new_ip )
void remove_ip_from_name_record( struct name_record *namerec,
struct in_addr remove_ip )
{
/* Try and find the requested ip address - remove it. */
int i;
int orig_num = namerec->data.num_ips;
/* Try and find the requested ip address - remove it. */
int i;
int orig_num = namerec->data.num_ips;
for(i = 0; i < orig_num; i++)
if( ip_equal( remove_ip, namerec->data.ip[i]) )
{
remove_nth_ip_in_record( namerec, i);
break;
}
for(i = 0; i < orig_num; i++) {
if( ip_equal( remove_ip, namerec->data.ip[i]) ) {
remove_nth_ip_in_record( namerec, i);
break;
}
}
}
/*******************************************************************
@ -384,85 +375,67 @@ void standard_success_release( struct subnet_record *subrec,
struct nmb_name *nmbname,
struct in_addr released_ip )
{
struct name_record *namerec;
struct name_record *namerec;
namerec = find_name_on_subnet( subrec, nmbname, FIND_ANY_NAME );
namerec = find_name_on_subnet( subrec, nmbname, FIND_ANY_NAME );
if( namerec == NULL ) {
DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \
on subnet %s. Name was not found on subnet.\n", nmb_namestr(nmbname), inet_ntoa(released_ip),
subrec->subnet_name) );
return;
} else {
int orig_num = namerec->data.num_ips;
if( namerec == NULL )
{
DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \
on subnet %s. Name was not found on subnet.\n",
nmb_namestr(nmbname),
inet_ntoa(released_ip),
subrec->subnet_name) );
return;
}
else
{
int orig_num = namerec->data.num_ips;
remove_ip_from_name_record( namerec, released_ip );
remove_ip_from_name_record( namerec, released_ip );
if( namerec->data.num_ips == orig_num )
DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \
on subnet %s. This ip is not known for this name.\n", nmb_namestr(nmbname), inet_ntoa(released_ip), subrec->subnet_name ) );
}
if( namerec->data.num_ips == orig_num )
DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \
on subnet %s. This ip is not known for this name.\n",
nmb_namestr(nmbname),
inet_ntoa(released_ip),
subrec->subnet_name ) );
}
if( namerec->data.num_ips == 0 )
remove_name_from_namelist( subrec, namerec );
if( namerec->data.num_ips == 0 )
remove_name_from_namelist( subrec, namerec );
}
/*******************************************************************
Expires old names in a subnet namelist.
******************************************************************/
******************************************************************/
void expire_names_on_subnet(struct subnet_record *subrec, time_t t)
{
struct name_record *namerec;
struct name_record *next_namerec;
struct name_record *namerec;
struct name_record *next_namerec;
for( namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
namerec;
namerec = next_namerec )
{
next_namerec = (struct name_record *)ubi_trNext( namerec );
if( (namerec->data.death_time != PERMANENT_TTL)
&& (namerec->data.death_time < t) )
{
if( namerec->data.source == SELF_NAME )
{
DEBUG( 3, ( "expire_names_on_subnet: Subnet %s not expiring SELF \
name %s\n",
subrec->subnet_name, nmb_namestr(&namerec->name) ) );
namerec->data.death_time += 300;
namerec->subnet->namelist_changed = True;
continue;
}
DEBUG(3,("expire_names_on_subnet: Subnet %s - removing expired name %s\n",
subrec->subnet_name, nmb_namestr(&namerec->name)));
for( namerec = (struct name_record *)ubi_trFirst( subrec->namelist ); namerec; namerec = next_namerec ) {
next_namerec = (struct name_record *)ubi_trNext( namerec );
if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
if( namerec->data.source == SELF_NAME ) {
DEBUG( 3, ( "expire_names_on_subnet: Subnet %s not expiring SELF \
name %s\n", subrec->subnet_name, nmb_namestr(&namerec->name) ) );
namerec->data.death_time += 300;
namerec->subnet->namelist_changed = True;
continue;
}
DEBUG(3,("expire_names_on_subnet: Subnet %s - removing expired name %s\n",
subrec->subnet_name, nmb_namestr(&namerec->name)));
remove_name_from_namelist( subrec, namerec );
}
}
remove_name_from_namelist( subrec, namerec );
}
}
}
/*******************************************************************
Expires old names in all subnet namelists.
******************************************************************/
******************************************************************/
void expire_names(time_t t)
{
struct subnet_record *subrec;
struct subnet_record *subrec;
for( subrec = FIRST_SUBNET;
subrec;
subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec) )
{
expire_names_on_subnet( subrec, t );
}
for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec) ) {
expire_names_on_subnet( subrec, t );
}
}
/****************************************************************************
@ -475,46 +448,39 @@ void expire_names(time_t t)
void add_samba_names_to_subnet( struct subnet_record *subrec )
{
struct in_addr *iplist = &subrec->myip;
int num_ips = 1;
struct in_addr *iplist = &subrec->myip;
int num_ips = 1;
/* These names are added permanently (ttl of zero) and will NOT be
refreshed. */
/* These names are added permanently (ttl of zero) and will NOT be refreshed. */
if( (subrec == unicast_subnet)
|| (subrec == wins_server_subnet)
|| (subrec == remote_broadcast_subnet) )
{
struct subnet_record *bcast_subrecs;
int i;
/* Create an IP list containing all our known subnets. */
if( (subrec == unicast_subnet) || (subrec == wins_server_subnet) || (subrec == remote_broadcast_subnet) ) {
struct subnet_record *bcast_subrecs;
int i;
num_ips = iface_count();
iplist = (struct in_addr *)malloc( num_ips * sizeof(struct in_addr) );
if( NULL == iplist )
{
DEBUG(0,("add_samba_names_to_subnet: Malloc fail !\n"));
return;
}
/* Create an IP list containing all our known subnets. */
for( bcast_subrecs = FIRST_SUBNET, i = 0;
bcast_subrecs;
bcast_subrecs = NEXT_SUBNET_EXCLUDING_UNICAST(bcast_subrecs), i++ )
iplist[i] = bcast_subrecs->myip;
num_ips = iface_count();
iplist = (struct in_addr *)malloc( num_ips * sizeof(struct in_addr) );
if( NULL == iplist ) {
DEBUG(0,("add_samba_names_to_subnet: Malloc fail !\n"));
return;
}
}
for( bcast_subrecs = FIRST_SUBNET, i = 0; bcast_subrecs; bcast_subrecs = NEXT_SUBNET_EXCLUDING_UNICAST(bcast_subrecs), i++ )
iplist[i] = bcast_subrecs->myip;
}
(void)add_name_to_subnet(subrec,"*",0x0,samba_nb_type, PERMANENT_TTL,
PERMANENT_NAME, num_ips, iplist);
(void)add_name_to_subnet(subrec,"*",0x20,samba_nb_type,PERMANENT_TTL,
PERMANENT_NAME, num_ips, iplist);
(void)add_name_to_subnet(subrec,"__SAMBA__",0x20,samba_nb_type,PERMANENT_TTL,
PERMANENT_NAME, num_ips, iplist);
(void)add_name_to_subnet(subrec,"__SAMBA__",0x00,samba_nb_type,PERMANENT_TTL,
PERMANENT_NAME, num_ips, iplist);
add_name_to_subnet(subrec,"*",0x0,samba_nb_type, PERMANENT_TTL,
PERMANENT_NAME, num_ips, iplist);
add_name_to_subnet(subrec,"*",0x20,samba_nb_type,PERMANENT_TTL,
PERMANENT_NAME, num_ips, iplist);
add_name_to_subnet(subrec,"__SAMBA__",0x20,samba_nb_type,PERMANENT_TTL,
PERMANENT_NAME, num_ips, iplist);
add_name_to_subnet(subrec,"__SAMBA__",0x00,samba_nb_type,PERMANENT_TTL,
PERMANENT_NAME, num_ips, iplist);
if(iplist != &subrec->myip)
SAFE_FREE(iplist);
if(iplist != &subrec->myip)
SAFE_FREE(iplist);
}
/****************************************************************************
@ -524,68 +490,65 @@ void add_samba_names_to_subnet( struct subnet_record *subrec )
static void dump_subnet_namelist( struct subnet_record *subrec, XFILE *fp)
{
struct name_record *namerec;
const char *src_type;
struct tm *tm;
int i;
struct name_record *namerec;
const char *src_type;
struct tm *tm;
int i;
x_fprintf(fp, "Subnet %s\n----------------------\n", subrec->subnet_name);
for( namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
namerec;
namerec = (struct name_record *)ubi_trNext( namerec ) )
{
x_fprintf(fp,"\tName = %s\t", nmb_namestr(&namerec->name));
switch(namerec->data.source)
{
case LMHOSTS_NAME:
src_type = "LMHOSTS_NAME";
break;
case WINS_PROXY_NAME:
src_type = "WINS_PROXY_NAME";
break;
case REGISTER_NAME:
src_type = "REGISTER_NAME";
break;
case SELF_NAME:
src_type = "SELF_NAME";
break;
case DNS_NAME:
src_type = "DNS_NAME";
break;
case DNSFAIL_NAME:
src_type = "DNSFAIL_NAME";
break;
case PERMANENT_NAME:
src_type = "PERMANENT_NAME";
break;
default:
src_type = "unknown!";
break;
}
x_fprintf(fp,"Source = %s\nb_flags = %x\t", src_type, namerec->data.nb_flags);
x_fprintf(fp, "Subnet %s\n----------------------\n", subrec->subnet_name);
for( namerec = (struct name_record *)ubi_trFirst( subrec->namelist ); namerec;
namerec = (struct name_record *)ubi_trNext( namerec ) ) {
if(namerec->data.death_time != PERMANENT_TTL)
{
tm = LocalTime(&namerec->data.death_time);
x_fprintf(fp, "death_time = %s\t", asctime(tm));
}
else
x_fprintf(fp, "death_time = PERMANENT\t");
x_fprintf(fp,"\tName = %s\t", nmb_namestr(&namerec->name));
switch(namerec->data.source) {
case LMHOSTS_NAME:
src_type = "LMHOSTS_NAME";
break;
case WINS_PROXY_NAME:
src_type = "WINS_PROXY_NAME";
break;
case REGISTER_NAME:
src_type = "REGISTER_NAME";
break;
case SELF_NAME:
src_type = "SELF_NAME";
break;
case DNS_NAME:
src_type = "DNS_NAME";
break;
case DNSFAIL_NAME:
src_type = "DNSFAIL_NAME";
break;
case PERMANENT_NAME:
src_type = "PERMANENT_NAME";
break;
default:
src_type = "unknown!";
break;
}
if(namerec->data.refresh_time != PERMANENT_TTL)
{
tm = LocalTime(&namerec->data.refresh_time);
x_fprintf(fp, "refresh_time = %s\n", asctime(tm));
}
else
x_fprintf(fp, "refresh_time = PERMANENT\n");
x_fprintf(fp,"Source = %s\nb_flags = %x\t", src_type, namerec->data.nb_flags);
x_fprintf(fp, "\t\tnumber of IPS = %d", namerec->data.num_ips);
for(i = 0; i < namerec->data.num_ips; i++)
x_fprintf(fp, "\t%s", inet_ntoa(namerec->data.ip[i]));
if(namerec->data.death_time != PERMANENT_TTL) {
tm = LocalTime(&namerec->data.death_time);
x_fprintf(fp, "death_time = %s\t", asctime(tm));
} else {
x_fprintf(fp, "death_time = PERMANENT\t");
}
x_fprintf(fp, "\n\n");
}
if(namerec->data.refresh_time != PERMANENT_TTL) {
tm = LocalTime(&namerec->data.refresh_time);
x_fprintf(fp, "refresh_time = %s\n", asctime(tm));
} else {
x_fprintf(fp, "refresh_time = PERMANENT\n");
}
x_fprintf(fp, "\t\tnumber of IPS = %d", namerec->data.num_ips);
for(i = 0; i < namerec->data.num_ips; i++)
x_fprintf(fp, "\t%s", inet_ntoa(namerec->data.ip[i]));
x_fprintf(fp, "\n\n");
}
}
/****************************************************************************
@ -595,30 +558,27 @@ static void dump_subnet_namelist( struct subnet_record *subrec, XFILE *fp)
void dump_all_namelists(void)
{
XFILE *fp;
struct subnet_record *subrec;
XFILE *fp;
struct subnet_record *subrec;
fp = x_fopen(lock_path("namelist.debug"),O_WRONLY|O_CREAT|O_TRUNC, 0644);
fp = x_fopen(lock_path("namelist.debug"),O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (!fp)
{
DEBUG(0,("dump_all_namelists: Can't open file %s. Error was %s\n",
"namelist.debug",strerror(errno)));
return;
}
if (!fp) {
DEBUG(0,("dump_all_namelists: Can't open file %s. Error was %s\n",
"namelist.debug",strerror(errno)));
return;
}
for( subrec = FIRST_SUBNET;
subrec;
subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec) )
dump_subnet_namelist( subrec, fp );
for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec) )
dump_subnet_namelist( subrec, fp );
if( !we_are_a_wins_client() )
dump_subnet_namelist( unicast_subnet, fp );
if( !we_are_a_wins_client() )
dump_subnet_namelist( unicast_subnet, fp );
if( remote_broadcast_subnet->namelist != NULL )
dump_subnet_namelist( remote_broadcast_subnet, fp );
if( remote_broadcast_subnet->namelist != NULL )
dump_subnet_namelist( remote_broadcast_subnet, fp );
if( wins_server_subnet != NULL )
dump_subnet_namelist( wins_server_subnet, fp );
x_fclose( fp );
if( wins_server_subnet != NULL )
dump_subnet_namelist( wins_server_subnet, fp );
x_fclose( fp );
}

View File

@ -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
@ -31,106 +31,95 @@ static void query_name_response( struct subnet_record *subrec,
struct response_record *rrec,
struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
BOOL success = False;
struct nmb_name *question_name =
&rrec->packet->packet.nmb.question.question_name;
struct in_addr answer_ip;
struct nmb_packet *nmb = &p->packet.nmb;
BOOL success = False;
struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
struct in_addr answer_ip;
zero_ip(&answer_ip);
zero_ip(&answer_ip);
/* Ensure we don't retry the query but leave the response record cleanup
to the timeout code. We may get more answer responses in which case
we should mark the name in conflict.. */
rrec->repeat_count = 0;
/* Ensure we don't retry the query but leave the response record cleanup
to the timeout code. We may get more answer responses in which case
we should mark the name in conflict.. */
rrec->repeat_count = 0;
if(rrec->num_msgs == 1)
{
/* This is the first response. */
if(rrec->num_msgs == 1) {
/* This is the first response. */
if(nmb->header.opcode == NMB_WACK_OPCODE)
{
/* WINS server is telling us to wait. Pretend we didn't get
the response but don't send out any more query requests. */
if(nmb->header.opcode == NMB_WACK_OPCODE) {
/* WINS server is telling us to wait. Pretend we didn't get
the response but don't send out any more query requests. */
if( DEBUGLVL( 5 ) )
{
dbgtext( "query_name_response: " );
dbgtext( "WACK from WINS server %s ", inet_ntoa(p->ip) );
dbgtext( "in querying name %s ", nmb_namestr(question_name) );
dbgtext( "on subnet %s.\n", subrec->subnet_name );
}
if( DEBUGLVL( 5 ) ) {
dbgtext( "query_name_response: " );
dbgtext( "WACK from WINS server %s ", inet_ntoa(p->ip) );
dbgtext( "in querying name %s ", nmb_namestr(question_name) );
dbgtext( "on subnet %s.\n", subrec->subnet_name );
}
rrec->repeat_count = 0;
/* How long we should wait for. */
rrec->repeat_time = p->timestamp + nmb->answers->ttl;
rrec->num_msgs--;
return;
}
else if(nmb->header.rcode != 0)
{
success = False;
rrec->repeat_count = 0;
/* How long we should wait for. */
rrec->repeat_time = p->timestamp + nmb->answers->ttl;
rrec->num_msgs--;
return;
} else if(nmb->header.rcode != 0) {
if( DEBUGLVL( 5 ) )
{
dbgtext( "query_name_response: On subnet %s ", subrec->subnet_name );
dbgtext( "- negative response from IP %s ", inet_ntoa(p->ip) );
dbgtext( "for name %s. ", nmb_namestr(question_name) );
dbgtext( "Error code was %d.\n", nmb->header.rcode );
}
}
else
{
if (!nmb->answers)
{
dbgtext( "query_name_response: On subnet %s ", subrec->subnet_name );
dbgtext( "IP %s ", inet_ntoa(p->ip) );
dbgtext( "returned a success response with no answer\n" );
return;
}
success = False;
success = True;
if( DEBUGLVL( 5 ) ) {
dbgtext( "query_name_response: On subnet %s ", subrec->subnet_name );
dbgtext( "- negative response from IP %s ", inet_ntoa(p->ip) );
dbgtext( "for name %s. ", nmb_namestr(question_name) );
dbgtext( "Error code was %d.\n", nmb->header.rcode );
}
} else {
if (!nmb->answers) {
dbgtext( "query_name_response: On subnet %s ", subrec->subnet_name );
dbgtext( "IP %s ", inet_ntoa(p->ip) );
dbgtext( "returned a success response with no answer\n" );
return;
}
putip((char *)&answer_ip,&nmb->answers->rdata[2]);
if( DEBUGLVL( 5 ) )
{
dbgtext( "query_name_response: On subnet %s ", subrec->subnet_name );
dbgtext( "- positive response from IP %s ", inet_ntoa(p->ip) );
dbgtext( "for name %s. ", nmb_namestr(question_name) );
dbgtext( "IP of that name is %s\n", inet_ntoa(answer_ip) );
}
success = True;
/* Interestingly, we could add these names to our namelists, and
change nmbd to a model that checked its own name cache first,
before sending out a query. This is a task for another day, though.
*/
}
}
else if( rrec->num_msgs > 1)
{
if( DEBUGLVL( 0 ) )
{
if (nmb->answers)
putip( (char *)&answer_ip, &nmb->answers->rdata[2] );
dbgtext( "query_name_response: " );
dbgtext( "Multiple (%d) responses ", rrec->num_msgs );
dbgtext( "received for a query on subnet %s ", subrec->subnet_name );
dbgtext( "for name %s.\nThis response ", nmb_namestr(question_name) );
dbgtext( "was from IP %s, reporting ", inet_ntoa(p->ip) );
dbgtext( "an IP address of %s.\n", inet_ntoa(answer_ip) );
}
putip((char *)&answer_ip,&nmb->answers->rdata[2]);
if( DEBUGLVL( 5 ) ) {
dbgtext( "query_name_response: On subnet %s ", subrec->subnet_name );
dbgtext( "- positive response from IP %s ", inet_ntoa(p->ip) );
dbgtext( "for name %s. ", nmb_namestr(question_name) );
dbgtext( "IP of that name is %s\n", inet_ntoa(answer_ip) );
}
/* We have already called the success or fail function, so we
don't call again here. Leave the response record around in
case we get more responses. */
/* Interestingly, we could add these names to our namelists, and
change nmbd to a model that checked its own name cache first,
before sending out a query. This is a task for another day, though.
*/
}
} else if( rrec->num_msgs > 1) {
return;
}
if( DEBUGLVL( 0 ) ) {
if (nmb->answers)
putip( (char *)&answer_ip, &nmb->answers->rdata[2] );
dbgtext( "query_name_response: " );
dbgtext( "Multiple (%d) responses ", rrec->num_msgs );
dbgtext( "received for a query on subnet %s ", subrec->subnet_name );
dbgtext( "for name %s.\nThis response ", nmb_namestr(question_name) );
dbgtext( "was from IP %s, reporting ", inet_ntoa(p->ip) );
dbgtext( "an IP address of %s.\n", inet_ntoa(answer_ip) );
}
/* We have already called the success or fail function, so we
don't call again here. Leave the response record around in
case we get more responses. */
return;
}
if(success && rrec->success_fn)
(*(query_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, answer_ip, nmb->answers);
else if( rrec->fail_fn)
(*(query_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name, nmb->header.rcode);
if(success && rrec->success_fn)
(*(query_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, answer_ip, nmb->answers);
else if( rrec->fail_fn)
(*(query_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name, nmb->header.rcode);
}
@ -141,32 +130,30 @@ static void query_name_response( struct subnet_record *subrec,
static void query_name_timeout_response(struct subnet_record *subrec,
struct response_record *rrec)
{
struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
/* We can only fail here, never succeed. */
BOOL failed = True;
struct nmb_name *question_name = &sent_nmb->question.question_name;
struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
/* We can only fail here, never succeed. */
BOOL failed = True;
struct nmb_name *question_name = &sent_nmb->question.question_name;
if(rrec->num_msgs != 0)
{
/* We got at least one response, and have called the success/fail
function already. */
if(rrec->num_msgs != 0) {
/* We got at least one response, and have called the success/fail
function already. */
failed = False;
}
failed = False;
}
if(failed)
{
if( DEBUGLVL( 5 ) )
{
dbgtext( "query_name_timeout_response: No response to " );
dbgtext( "query for name %s ", nmb_namestr(question_name) );
dbgtext( "on subnet %s.\n", subrec->subnet_name );
}
if(rrec->fail_fn)
(*(query_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name, 0);
}
if(failed) {
if( DEBUGLVL( 5 ) ) {
dbgtext( "query_name_timeout_response: No response to " );
dbgtext( "query for name %s ", nmb_namestr(question_name) );
dbgtext( "on subnet %s.\n", subrec->subnet_name );
}
remove_response_record(subrec, rrec);
if(rrec->fail_fn)
(*(query_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name, 0);
}
remove_response_record(subrec, rrec);
}
/****************************************************************************
@ -177,24 +164,21 @@ static void query_name_timeout_response(struct subnet_record *subrec,
static BOOL query_local_namelists(struct subnet_record *subrec, struct nmb_name *nmbname,
struct name_record **namerecp)
{
struct name_record *namerec;
struct name_record *namerec;
*namerecp = NULL;
*namerecp = NULL;
if(find_name_in_lmhosts(nmbname, namerecp))
return True;
if(find_name_in_lmhosts(nmbname, namerecp))
return True;
if((namerec = find_name_on_subnet(subrec, nmbname, FIND_ANY_NAME))==NULL)
return False;
if((namerec = find_name_on_subnet(subrec, nmbname, FIND_ANY_NAME))==NULL)
return False;
if( NAME_IS_ACTIVE(namerec)
&& ( (namerec->data.source == SELF_NAME)
|| (namerec->data.source == LMHOSTS_NAME) ) )
{
*namerecp = namerec;
return True;
}
return False;
if( NAME_IS_ACTIVE(namerec) && ( (namerec->data.source == SELF_NAME) || (namerec->data.source == LMHOSTS_NAME) ) ) {
*namerecp = namerec;
return True;
}
return False;
}
/****************************************************************************
@ -206,69 +190,57 @@ BOOL query_name(struct subnet_record *subrec, const char *name, int type,
query_name_fail_function fail_fn,
struct userdata_struct *userdata)
{
struct nmb_name nmbname;
struct name_record *namerec;
struct nmb_name nmbname;
struct name_record *namerec;
make_nmb_name(&nmbname, name, type);
make_nmb_name(&nmbname, name, type);
/*
* We need to check our local namelists first.
* It may be an magic name, lmhosts name or just
* a name we have registered.
*/
/*
* We need to check our local namelists first.
* It may be an magic name, lmhosts name or just
* a name we have registered.
*/
if(query_local_namelists(subrec, &nmbname, &namerec) == True)
{
struct res_rec rrec;
int i;
if(query_local_namelists(subrec, &nmbname, &namerec) == True) {
struct res_rec rrec;
int i;
memset((char *)&rrec, '\0', sizeof(struct res_rec));
memset((char *)&rrec, '\0', sizeof(struct res_rec));
/* Fake up the needed res_rec just in case it's used. */
rrec.rr_name = nmbname;
rrec.rr_type = RR_TYPE_NB;
rrec.rr_class = RR_CLASS_IN;
rrec.ttl = PERMANENT_TTL;
rrec.rdlength = namerec->data.num_ips * 6;
if(rrec.rdlength > MAX_DGRAM_SIZE)
{
if( DEBUGLVL( 0 ) )
{
dbgtext( "query_name: nmbd internal error - " );
dbgtext( "there are %d ip addresses ", namerec->data.num_ips );
dbgtext( "for name %s.\n", nmb_namestr(&nmbname) );
}
return False;
}
/* Fake up the needed res_rec just in case it's used. */
rrec.rr_name = nmbname;
rrec.rr_type = RR_TYPE_NB;
rrec.rr_class = RR_CLASS_IN;
rrec.ttl = PERMANENT_TTL;
rrec.rdlength = namerec->data.num_ips * 6;
if(rrec.rdlength > MAX_DGRAM_SIZE) {
if( DEBUGLVL( 0 ) ) {
dbgtext( "query_name: nmbd internal error - " );
dbgtext( "there are %d ip addresses ", namerec->data.num_ips );
dbgtext( "for name %s.\n", nmb_namestr(&nmbname) );
}
return False;
}
for( i = 0; i < namerec->data.num_ips; i++)
{
set_nb_flags( &rrec.rdata[i*6], namerec->data.nb_flags );
putip( &rrec.rdata[(i*6) + 2], (char *)&namerec->data.ip[i]);
}
for( i = 0; i < namerec->data.num_ips; i++) {
set_nb_flags( &rrec.rdata[i*6], namerec->data.nb_flags );
putip( &rrec.rdata[(i*6) + 2], (char *)&namerec->data.ip[i]);
}
/* Call the success function directly. */
if(success_fn)
(*(query_name_success_function)success_fn)(subrec, userdata, &nmbname, namerec->data.ip[0], &rrec);
return False;
}
/* Call the success function directly. */
if(success_fn)
(*(query_name_success_function)success_fn)(subrec, userdata, &nmbname, namerec->data.ip[0], &rrec);
return False;
}
if(queue_query_name( subrec,
query_name_response,
query_name_timeout_response,
success_fn,
fail_fn,
userdata,
&nmbname) == NULL)
{
if( DEBUGLVL( 0 ) )
{
dbgtext( "query_name: Failed to send packet " );
dbgtext( "trying to query name %s\n", nmb_namestr(&nmbname) );
}
return True;
}
return False;
if(queue_query_name( subrec, query_name_response, query_name_timeout_response, success_fn, fail_fn, userdata, &nmbname) == NULL) {
if( DEBUGLVL( 0 ) ) {
dbgtext( "query_name: Failed to send packet " );
dbgtext( "trying to query name %s\n", nmb_namestr(&nmbname) );
}
return True;
}
return False;
}
/****************************************************************************
@ -281,24 +253,16 @@ BOOL query_name_from_wins_server(struct in_addr ip_to,
query_name_fail_function fail_fn,
struct userdata_struct *userdata)
{
struct nmb_name nmbname;
struct nmb_name nmbname;
make_nmb_name(&nmbname, name, type);
make_nmb_name(&nmbname, name, type);
if(queue_query_name_from_wins_server( ip_to,
query_name_response,
query_name_timeout_response,
success_fn,
fail_fn,
userdata,
&nmbname) == NULL)
{
if( DEBUGLVL( 0 ) )
{
dbgtext( "query_name_from_wins_server: Failed to send packet " );
dbgtext( "trying to query name %s\n", nmb_namestr(&nmbname) );
}
return True;
}
return False;
if(queue_query_name_from_wins_server( ip_to, query_name_response, query_name_timeout_response, success_fn, fail_fn, userdata, &nmbname) == NULL) {
if( DEBUGLVL( 0 ) ) {
dbgtext( "query_name_from_wins_server: Failed to send packet " );
dbgtext( "trying to query name %s\n", nmb_namestr(&nmbname) );
}
return True;
}
return False;
}

View File

@ -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
@ -85,7 +85,9 @@ static void register_name_response(struct subnet_record *subrec,
*/
#if 1 /* OLD_SAMBA_SERVER_HACK */
if((nmb->header.rcode == ACT_ERR) && strequal(lp_workgroup(), answer_name->name) &&
nstring ans_name;
pull_ascii_nstring(ans_name, answer_name->name);
if((nmb->header.rcode == ACT_ERR) && strequal(lp_workgroup(), ans_name) &&
(answer_name->name_type == 0x1b)) {
/* Pretend we did not get this. */
rrec->num_msgs--;
@ -161,10 +163,10 @@ static void register_name_response(struct subnet_record *subrec,
remove_response_record(subrec, rrec);
}
/****************************************************************************
Deal with a timeout of a WINS registration request
****************************************************************************/
static void wins_registration_timeout(struct subnet_record *subrec,
struct response_record *rrec)
{
@ -233,7 +235,6 @@ static void wins_registration_timeout(struct subnet_record *subrec,
us trying to register with each of our failover wins servers */
}
/****************************************************************************
Deal with a timeout when registering one of our names.
****************************************************************************/
@ -290,10 +291,10 @@ static void register_name_timeout_response(struct subnet_record *subrec,
remove_response_record(subrec, rrec);
}
/****************************************************************************
initiate one multi-homed name registration packet
Initiate one multi-homed name registration packet.
****************************************************************************/
static void multihomed_register_one(struct nmb_name *nmbname,
uint16 nb_flags,
register_name_success_function success_fn,
@ -336,11 +337,11 @@ static void multihomed_register_one(struct nmb_name *nmbname,
free(userdata);
}
/****************************************************************************
we have finished the registration of one IP and need to see if we have
any more IPs left to register with this group of wins server for this name
We have finished the registration of one IP and need to see if we have
any more IPs left to register with this group of wins server for this name.
****************************************************************************/
static void wins_next_registration(struct response_record *rrec)
{
struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
@ -388,6 +389,7 @@ static void wins_next_registration(struct response_record *rrec)
/****************************************************************************
Try and register one of our names on the unicast subnet - multihomed.
****************************************************************************/
static void multihomed_register_name(struct nmb_name *nmbname, uint16 nb_flags,
register_name_success_function success_fn,
register_name_fail_function fail_fn)
@ -416,6 +418,7 @@ static void multihomed_register_name(struct nmb_name *nmbname, uint16 nb_flags,
struct subnet_record *subrec;
char **wins_tags;
struct in_addr *ip_list;
nstring name;
for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) )
num_ips++;
@ -431,7 +434,8 @@ static void multihomed_register_name(struct nmb_name *nmbname, uint16 nb_flags,
ip_list[i] = subrec->myip;
}
add_name_to_subnet(unicast_subnet, nmbname->name, nmbname->name_type,
pull_ascii_nstring(name, nmbname->name);
add_name_to_subnet(unicast_subnet, name, nmbname->name_type,
nb_flags, lp_max_ttl(), SELF_NAME,
num_ips, ip_list);
@ -456,10 +460,10 @@ static void multihomed_register_name(struct nmb_name *nmbname, uint16 nb_flags,
SAFE_FREE(ip_list);
}
/****************************************************************************
Try and register one of our names.
****************************************************************************/
void register_name(struct subnet_record *subrec,
const char *name, int type, uint16 nb_flags,
register_name_success_function success_fn,
@ -498,10 +502,10 @@ void register_name(struct subnet_record *subrec,
}
}
/****************************************************************************
Try and refresh one of our names. This is *only* called for WINS refresh
****************************************************************************/
void wins_refresh_name(struct name_record *namerec)
{
int t;

View File

@ -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
@ -26,52 +26,52 @@
/****************************************************************************
Deal with a successful node status response.
****************************************************************************/
static void node_status_response(struct subnet_record *subrec,
struct response_record *rrec, struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
struct nmb_name *answer_name = &nmb->answers->rr_name;
struct nmb_packet *nmb = &p->packet.nmb;
struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
struct nmb_name *answer_name = &nmb->answers->rr_name;
/* Sanity check. Ensure that the answer name in the incoming packet is the
same as the requested name in the outgoing packet. */
/* Sanity check. Ensure that the answer name in the incoming packet is the
same as the requested name in the outgoing packet. */
if(!nmb_name_equal(question_name, answer_name))
{
DEBUG(0,("node_status_response: Answer name %s differs from question \
if(!nmb_name_equal(question_name, answer_name)) {
DEBUG(0,("node_status_response: Answer name %s differs from question \
name %s.\n", nmb_namestr(answer_name), nmb_namestr(question_name)));
return;
}
return;
}
DEBUG(5,("node_status_response: response from name %s on subnet %s.\n",
nmb_namestr(answer_name), subrec->subnet_name));
DEBUG(5,("node_status_response: response from name %s on subnet %s.\n",
nmb_namestr(answer_name), subrec->subnet_name));
/* Just send the whole answer resource record for the success function
to parse. */
if(rrec->success_fn)
(*(node_status_success_function)rrec->success_fn)(subrec, rrec->userdata, nmb->answers, p->ip);
/* Just send the whole answer resource record for the success function to parse. */
if(rrec->success_fn)
(*(node_status_success_function)rrec->success_fn)(subrec, rrec->userdata, nmb->answers, p->ip);
/* Ensure we don't retry. */
remove_response_record(subrec, rrec);
/* Ensure we don't retry. */
remove_response_record(subrec, rrec);
}
/****************************************************************************
Deal with a timeout when requesting a node status.
****************************************************************************/
static void node_status_timeout_response(struct subnet_record *subrec,
struct response_record *rrec)
{
struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
struct nmb_name *question_name = &sent_nmb->question.question_name;
struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
struct nmb_name *question_name = &sent_nmb->question.question_name;
DEBUG(5,("node_status_timeout_response: failed to get node status from name %s on subnet %s\n",
nmb_namestr(question_name), subrec->subnet_name));
DEBUG(5,("node_status_timeout_response: failed to get node status from name %s on subnet %s\n",
nmb_namestr(question_name), subrec->subnet_name));
if( rrec->fail_fn)
(*rrec->fail_fn)(subrec, rrec);
if( rrec->fail_fn)
(*rrec->fail_fn)(subrec, rrec);
/* Ensure we don't retry. */
remove_response_record(subrec, rrec);
/* Ensure we don't retry. */
remove_response_record(subrec, rrec);
}
/****************************************************************************
@ -82,13 +82,11 @@ BOOL node_status(struct subnet_record *subrec, struct nmb_name *nmbname,
struct in_addr send_ip, node_status_success_function success_fn,
node_status_fail_function fail_fn, struct userdata_struct *userdata)
{
if(queue_node_status( subrec,
node_status_response, node_status_timeout_response,
success_fn, fail_fn, userdata, nmbname, send_ip)==NULL)
{
DEBUG(0,("node_status: Failed to send packet trying to get node status for \
if(queue_node_status( subrec, node_status_response, node_status_timeout_response,
success_fn, fail_fn, userdata, nmbname, send_ip)==NULL) {
DEBUG(0,("node_status: Failed to send packet trying to get node status for \
name %s, IP address %s\n", nmb_namestr(nmbname), inet_ntoa(send_ip)));
return True;
}
return False;
return True;
}
return False;
}

File diff suppressed because it is too large Load Diff

View File

@ -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
Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
This program is free software; you can redistribute it and/or modify
@ -35,6 +35,7 @@ struct sam_database_info {
/****************************************************************************
Send a message to smbd to do a sam delta sync
**************************************************************************/
static void send_repl_message(uint32 low_serial)
{
TDB_CONTEXT *tdb;
@ -64,432 +65,452 @@ Process a domain logon packet
void process_logon_packet(struct packet_struct *p, char *buf,int len,
const char *mailslot)
{
struct dgram_packet *dgram = &p->packet.dgram;
pstring my_name;
fstring reply_name;
pstring outbuf;
int code;
uint16 token = 0;
uint32 ntversion = 0;
uint16 lmnttoken = 0;
uint16 lm20token = 0;
uint32 domainsidsize;
BOOL short_request = False;
char *getdc;
char *uniuser; /* Unicode user name. */
pstring ascuser;
char *unicomp; /* Unicode computer name. */
struct dgram_packet *dgram = &p->packet.dgram;
pstring my_name;
fstring reply_name;
pstring outbuf;
int code;
uint16 token = 0;
uint32 ntversion = 0;
uint16 lmnttoken = 0;
uint16 lm20token = 0;
uint32 domainsidsize;
BOOL short_request = False;
char *getdc;
char *uniuser; /* Unicode user name. */
pstring ascuser;
char *unicomp; /* Unicode computer name. */
memset(outbuf, 0, sizeof(outbuf));
memset(outbuf, 0, sizeof(outbuf));
if (!lp_domain_logons())
{
DEBUG(3,("process_logon_packet: Logon packet received from IP %s and domain \
if (!lp_domain_logons()) {
DEBUG(3,("process_logon_packet: Logon packet received from IP %s and domain \
logons are not enabled.\n", inet_ntoa(p->ip) ));
return;
}
return;
}
pstrcpy(my_name, global_myname());
pstrcpy(my_name, global_myname());
code = SVAL(buf,0);
DEBUG(1,("process_logon_packet: Logon from %s: code = 0x%x\n", inet_ntoa(p->ip), code));
code = SVAL(buf,0);
DEBUG(1,("process_logon_packet: Logon from %s: code = 0x%x\n", inet_ntoa(p->ip), code));
switch (code)
{
case 0:
{
char *q = buf + 2;
char *machine = q;
char *user = skip_string(machine,1);
switch (code) {
case 0:
{
fstring mach_str, user_str, getdc_str;
char *q = buf + 2;
char *machine = q;
char *user = skip_string(machine,1);
getdc = skip_string(user,1);
q = skip_string(getdc,1);
token = SVAL(q,3);
getdc = skip_string(user,1);
q = skip_string(getdc,1);
token = SVAL(q,3);
fstrcpy(reply_name,my_name);
fstrcpy(reply_name,my_name);
DEBUG(3,("process_logon_packet: Domain login request from %s at IP %s user=%s token=%x\n",
machine,inet_ntoa(p->ip),user,token));
pull_ascii_fstring(mach_str, machine);
pull_ascii_fstring(user_str, user);
pull_ascii_fstring(getdc_str, getdc);
q = outbuf;
SSVAL(q, 0, 6);
q += 2;
DEBUG(3,("process_logon_packet: Domain login request from %s at IP %s user=%s token=%x\n",
mach_str,inet_ntoa(p->ip),user_str,token));
fstrcpy(reply_name, "\\\\");
fstrcat(reply_name, my_name);
fstrcpy(q, reply_name); q = skip_string(q, 1); /* PDC name */
q = outbuf;
SSVAL(q, 0, 6);
q += 2;
SSVAL(q, 0, token);
q += 2;
fstrcpy(reply_name, "\\\\");
fstrcat(reply_name, my_name);
push_ascii_fstring(q, reply_name);
q = skip_string(q, 1); /* PDC name */
dump_data(4, outbuf, PTR_DIFF(q, outbuf));
SSVAL(q, 0, token);
q += 2;
send_mailslot(True, getdc,
outbuf,PTR_DIFF(q,outbuf),
global_myname(), 0x0,
machine,
dgram->source_name.name_type,
p->ip, *iface_ip(p->ip), p->port);
break;
}
dump_data(4, outbuf, PTR_DIFF(q, outbuf));
case QUERYFORPDC:
{
char *q = buf + 2;
char *machine = q;
send_mailslot(True, getdc_str,
outbuf,PTR_DIFF(q,outbuf),
global_myname(), 0x0,
mach_str,
dgram->source_name.name_type,
p->ip, *iface_ip(p->ip), p->port);
break;
}
if (!lp_domain_master())
{
/* We're not Primary Domain Controller -- ignore this */
return;
}
case QUERYFORPDC:
{
fstring mach_str, getdc_str;
nstring source_name;
char *q = buf + 2;
char *machine = q;
getdc = skip_string(machine,1);
q = skip_string(getdc,1);
q = ALIGN2(q, buf);
if (!lp_domain_master()) {
/* We're not Primary Domain Controller -- ignore this */
return;
}
/* at this point we can work out if this is a W9X or NT style
request. Experiments show that the difference is wether the
packet ends here. For a W9X request we now end with a pair of
bytes (usually 0xFE 0xFF) whereas with NT we have two further
strings - the following is a simple way of detecting this */
if (len - PTR_DIFF(q, buf) <= 3) {
short_request = True;
} else {
unicomp = q;
getdc = skip_string(machine,1);
q = skip_string(getdc,1);
q = ALIGN2(q, buf);
/* A full length (NT style) request */
q = skip_unibuf(unicomp, PTR_DIFF(buf + len, unicomp));
/* At this point we can work out if this is a W9X or NT style
request. Experiments show that the difference is wether the
packet ends here. For a W9X request we now end with a pair of
bytes (usually 0xFE 0xFF) whereas with NT we have two further
strings - the following is a simple way of detecting this */
if (len - PTR_DIFF(q, buf) > 8) {
if (len - PTR_DIFF(q, buf) <= 3) {
short_request = True;
} else {
unicomp = q;
/* A full length (NT style) request */
q = skip_unibuf(unicomp, PTR_DIFF(buf + len, unicomp));
if (len - PTR_DIFF(q, buf) > 8) {
/* with NT5 clients we can sometimes
get additional data - a length specificed string
containing the domain name, then 16 bytes of
data (no idea what it is) */
int dom_len = CVAL(q, 0);
q++;
if (dom_len != 0) {
q += dom_len + 1;
}
q += 16;
}
ntversion = IVAL(q, 0);
lmnttoken = SVAL(q, 4);
lm20token = SVAL(q, 6);
}
/* Construct reply. */
q = outbuf;
SSVAL(q, 0, QUERYFORPDC_R);
q += 2;
fstrcpy(reply_name,my_name);
push_ascii_fstring(q, reply_name);
q = skip_string(q, 1); /* PDC name */
/* PDC and domain name */
if (!short_request) {
/* Make a full reply */
q = ALIGN2(q, outbuf);
q += dos_PutUniCode(q, my_name, sizeof(pstring), True); /* PDC name */
q += dos_PutUniCode(q, lp_workgroup(),sizeof(pstring), True); /* Domain name*/
SIVAL(q, 0, 1); /* our nt version */
SSVAL(q, 4, 0xffff); /* our lmnttoken */
SSVAL(q, 6, 0xffff); /* our lm20token */
q += 8;
}
/* RJS, 21-Feb-2000, we send a short reply if the request was short */
pull_ascii_fstring(mach_str, machine);
DEBUG(3,("process_logon_packet: GETDC request from %s at IP %s, \
reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
mach_str,inet_ntoa(p->ip), reply_name, lp_workgroup(),
QUERYFORPDC_R, (uint32)ntversion, (uint32)lmnttoken,
(uint32)lm20token ));
dump_data(4, outbuf, PTR_DIFF(q, outbuf));
pull_ascii_fstring(getdc_str, getdc);
pull_ascii_nstring(source_name, dgram->source_name.name);
send_mailslot(True, getdc_str,
outbuf,PTR_DIFF(q,outbuf),
global_myname(), 0x0,
source_name,
dgram->source_name.name_type,
p->ip, *iface_ip(p->ip), p->port);
return;
}
case SAMLOGON:
{
fstring getdc_str;
nstring source_name;
char *q = buf + 2;
fstring asccomp;
q += 2;
unicomp = q;
uniuser = skip_unibuf(unicomp, PTR_DIFF(buf+len, unicomp));
getdc = skip_unibuf(uniuser,PTR_DIFF(buf+len, uniuser));
q = skip_string(getdc,1);
q += 4; /* Account Control Bits - indicating username type */
domainsidsize = IVAL(q, 0);
q += 4;
DEBUG(3,("process_logon_packet: SAMLOGON sidsize %d, len = %d\n", domainsidsize, len));
if (domainsidsize < (len - PTR_DIFF(q, buf)) && (domainsidsize != 0)) {
q += domainsidsize;
q = ALIGN4(q, buf);
}
DEBUG(3,("process_logon_packet: len = %d PTR_DIFF(q, buf) = %d\n", len, PTR_DIFF(q, buf) ));
if (len - PTR_DIFF(q, buf) > 8) {
/* with NT5 clients we can sometimes
get additional data - a length specificed string
containing the domain name, then 16 bytes of
data (no idea what it is) */
get additional data - a length specificed string
containing the domain name, then 16 bytes of
data (no idea what it is) */
int dom_len = CVAL(q, 0);
q++;
if (dom_len != 0) {
if (dom_len < (len - PTR_DIFF(q, buf)) && (dom_len != 0)) {
q += dom_len + 1;
}
q += 16;
}
ntversion = IVAL(q, 0);
lmnttoken = SVAL(q, 4);
lm20token = SVAL(q, 6);
}
}
/* Construct reply. */
q = outbuf;
SSVAL(q, 0, QUERYFORPDC_R);
q += 2;
ntversion = IVAL(q, 0);
lmnttoken = SVAL(q, 4);
lm20token = SVAL(q, 6);
q += 8;
fstrcpy(reply_name,my_name);
fstrcpy(q, reply_name);
q = skip_string(q, 1); /* PDC name */
DEBUG(3,("process_logon_packet: SAMLOGON sidsize %d ntv %d\n", domainsidsize, ntversion));
/* PDC and domain name */
if (!short_request) /* Make a full reply */
{
q = ALIGN2(q, outbuf);
/*
* we respond regadless of whether the machine is in our password
* database. If it isn't then we let smbd send an appropriate error.
* Let's ignore the SID.
*/
pull_ucs2_pstring(ascuser, uniuser);
pull_ucs2_fstring(asccomp, unicomp);
DEBUG(3,("process_logon_packet: SAMLOGON user %s\n", ascuser));
q += dos_PutUniCode(q, my_name, sizeof(pstring), True); /* PDC name */
q += dos_PutUniCode(q, lp_workgroup(),sizeof(pstring), True); /* Domain name*/
SIVAL(q, 0, 1); /* our nt version */
SSVAL(q, 4, 0xffff); /* our lmnttoken */
SSVAL(q, 6, 0xffff); /* our lm20token */
q += 8;
}
fstrcpy(reply_name, "\\\\"); /* Here it wants \\LOGONSERVER. */
fstrcat(reply_name, my_name);
/* RJS, 21-Feb-2000, we send a short reply if the request was short */
DEBUG(3,("process_logon_packet: SAMLOGON request from %s(%s) for %s, returning logon svr %s domain %s code %x token=%x\n",
asccomp,inet_ntoa(p->ip), ascuser, reply_name, lp_workgroup(),
SAMLOGON_R ,lmnttoken));
DEBUG(3,("process_logon_packet: GETDC request from %s at IP %s, \
reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
machine,inet_ntoa(p->ip), reply_name, lp_workgroup(),
QUERYFORPDC_R, (uint32)ntversion, (uint32)lmnttoken,
(uint32)lm20token ));
/* Construct reply. */
dump_data(4, outbuf, PTR_DIFF(q, outbuf));
q = outbuf;
/* we want the simple version unless we are an ADS PDC..which means */
/* never, at least for now */
if ((ntversion < 11) || (SEC_ADS != lp_security()) || (ROLE_DOMAIN_PDC != lp_server_role())) {
if (SVAL(uniuser, 0) == 0) {
SSVAL(q, 0, SAMLOGON_UNK_R); /* user unknown */
} else {
SSVAL(q, 0, SAMLOGON_R);
}
send_mailslot(True, getdc,
outbuf,PTR_DIFF(q,outbuf),
global_myname(), 0x0,
dgram->source_name.name,
dgram->source_name.name_type,
p->ip, *iface_ip(p->ip), p->port);
return;
}
q += 2;
case SAMLOGON:
{
char *q = buf + 2;
fstring asccomp;
q += 2;
unicomp = q;
uniuser = skip_unibuf(unicomp, PTR_DIFF(buf+len, unicomp));
getdc = skip_unibuf(uniuser,PTR_DIFF(buf+len, uniuser));
q = skip_string(getdc,1);
q += 4; /* Account Control Bits - indicating username type */
domainsidsize = IVAL(q, 0);
q += 4;
DEBUG(3,("process_logon_packet: SAMLOGON sidsize %d, len = %d\n", domainsidsize, len));
if (domainsidsize < (len - PTR_DIFF(q, buf)) && (domainsidsize != 0)) {
q += domainsidsize;
q = ALIGN4(q, buf);
}
DEBUG(3,("process_logon_packet: len = %d PTR_DIFF(q, buf) = %d\n", len, PTR_DIFF(q, buf) ));
if (len - PTR_DIFF(q, buf) > 8) {
/* with NT5 clients we can sometimes
get additional data - a length specificed string
containing the domain name, then 16 bytes of
data (no idea what it is) */
int dom_len = CVAL(q, 0);
q++;
if (dom_len < (len - PTR_DIFF(q, buf)) && (dom_len != 0)) {
q += dom_len + 1;
}
q += 16;
}
ntversion = IVAL(q, 0);
lmnttoken = SVAL(q, 4);
lm20token = SVAL(q, 6);
q += 8;
DEBUG(3,("process_logon_packet: SAMLOGON sidsize %d ntv %d\n", domainsidsize, ntversion));
/*
* we respond regadless of whether the machine is in our password
* database. If it isn't then we let smbd send an appropriate error.
* Let's ignore the SID.
*/
pull_ucs2_pstring(ascuser, uniuser);
pull_ucs2_fstring(asccomp, unicomp);
DEBUG(3,("process_logon_packet: SAMLOGON user %s\n", ascuser));
fstrcpy(reply_name, "\\\\"); /* Here it wants \\LOGONSERVER. */
fstrcat(reply_name, my_name);
DEBUG(3,("process_logon_packet: SAMLOGON request from %s(%s) for %s, returning logon svr %s domain %s code %x token=%x\n",
asccomp,inet_ntoa(p->ip), ascuser, reply_name, lp_workgroup(),
SAMLOGON_R ,lmnttoken));
/* Construct reply. */
q = outbuf;
/* we want the simple version unless we are an ADS PDC..which means */
/* never, at least for now */
if ((ntversion < 11) || (SEC_ADS != lp_security()) || (ROLE_DOMAIN_PDC != lp_server_role())) {
if (SVAL(uniuser, 0) == 0) {
SSVAL(q, 0, SAMLOGON_UNK_R); /* user unknown */
} else {
SSVAL(q, 0, SAMLOGON_R);
}
q += 2;
q += dos_PutUniCode(q, reply_name,sizeof(pstring), True);
q += dos_PutUniCode(q, ascuser, sizeof(pstring), True);
q += dos_PutUniCode(q, lp_workgroup(),sizeof(pstring), True);
}
q += dos_PutUniCode(q, reply_name,sizeof(pstring), True);
q += dos_PutUniCode(q, ascuser, sizeof(pstring), True);
q += dos_PutUniCode(q, lp_workgroup(),sizeof(pstring), True);
}
#ifdef HAVE_ADS
else {
GUID domain_guid;
pstring domain;
pstring hostname;
char *component, *dc, *q1;
uint8 size;
char *q_orig = q;
int str_offset;
else {
GUID domain_guid;
pstring domain;
pstring hostname;
char *component, *dc, *q1;
uint8 size;
char *q_orig = q;
int str_offset;
get_mydomname(domain);
get_myname(hostname);
get_mydomname(domain);
get_myname(hostname);
if (SVAL(uniuser, 0) == 0) {
SIVAL(q, 0, SAMLOGON_AD_UNK_R); /* user unknown */
} else {
SIVAL(q, 0, SAMLOGON_AD_R);
}
q += 4;
if (SVAL(uniuser, 0) == 0) {
SIVAL(q, 0, SAMLOGON_AD_UNK_R); /* user unknown */
} else {
SIVAL(q, 0, SAMLOGON_AD_R);
}
q += 4;
SIVAL(q, 0, ADS_PDC|ADS_GC|ADS_LDAP|ADS_DS|
ADS_KDC|ADS_TIMESERV|ADS_CLOSEST|ADS_WRITABLE);
q += 4;
SIVAL(q, 0, ADS_PDC|ADS_GC|ADS_LDAP|ADS_DS|
ADS_KDC|ADS_TIMESERV|ADS_CLOSEST|ADS_WRITABLE);
q += 4;
/* Push Domain GUID */
if (False == secrets_fetch_domain_guid(domain, &domain_guid)) {
DEBUG(2, ("Could not fetch DomainGUID for %s\n", domain));
return;
}
memcpy(q, &domain_guid, sizeof(domain_guid));
q += sizeof(domain_guid);
/* Push Domain GUID */
if (False == secrets_fetch_domain_guid(domain, &domain_guid)) {
DEBUG(2, ("Could not fetch DomainGUID for %s\n", domain));
return;
}
memcpy(q, &domain_guid, sizeof(domain_guid));
q += sizeof(domain_guid);
/* Forest */
str_offset = q - q_orig;
dc = domain;
q1 = q;
while ((component = strtok(dc, "."))) {
dc = NULL;
size = push_ascii(&q[1], component, -1, 0);
SCVAL(q, 0, size);
q += (size + 1);
}
/* Forest */
str_offset = q - q_orig;
dc = domain;
q1 = q;
while ((component = strtok(dc, "."))) {
dc = NULL;
size = push_ascii(&q[1], component, -1, 0);
SCVAL(q, 0, size);
q += (size + 1);
}
/* Unk0 */
SCVAL(q, 0, 0); q++;
/* Unk0 */
SCVAL(q, 0, 0);
q++;
/* Domain */
SCVAL(q, 0, 0xc0 | ((str_offset >> 8) & 0x3F));
SCVAL(q, 1, str_offset & 0xFF);
q += 2;
/* Domain */
SCVAL(q, 0, 0xc0 | ((str_offset >> 8) & 0x3F));
SCVAL(q, 1, str_offset & 0xFF);
q += 2;
/* Hostname */
size = push_ascii(&q[1], hostname, -1, 0);
SCVAL(q, 0, size);
q += (size + 1);
SCVAL(q, 0, 0xc0 | ((str_offset >> 8) & 0x3F));
SCVAL(q, 1, str_offset & 0xFF);
q += 2;
/* Hostname */
size = push_ascii(&q[1], hostname, -1, 0);
SCVAL(q, 0, size);
q += (size + 1);
SCVAL(q, 0, 0xc0 | ((str_offset >> 8) & 0x3F));
SCVAL(q, 1, str_offset & 0xFF);
q += 2;
/* NETBIOS of domain */
size = push_ascii(&q[1], lp_workgroup(), -1, STR_UPPER);
SCVAL(q, 0, size);
q += (size + 1);
/* NETBIOS of domain */
size = push_ascii(&q[1], lp_workgroup(), -1, STR_UPPER);
SCVAL(q, 0, size);
q += (size + 1);
/* Unk1 */
SCVAL(q, 0, 0); q++;
/* Unk1 */
SCVAL(q, 0, 0);
q++;
/* NETBIOS of hostname */
size = push_ascii(&q[1], my_name, -1, 0);
SCVAL(q, 0, size);
q += (size + 1);
/* NETBIOS of hostname */
size = push_ascii(&q[1], my_name, -1, 0);
SCVAL(q, 0, size);
q += (size + 1);
/* Unk2 */
SCVAL(q, 0, 0); q++;
/* Unk2 */
SCVAL(q, 0, 0);
q++;
/* User name */
if (SVAL(uniuser, 0) != 0) {
size = push_ascii(&q[1], ascuser, -1, 0);
SCVAL(q, 0, size);
q += (size + 1);
}
/* User name */
if (SVAL(uniuser, 0) != 0) {
size = push_ascii(&q[1], ascuser, -1, 0);
SCVAL(q, 0, size);
q += (size + 1);
}
q_orig = q;
/* Site name */
size = push_ascii(&q[1], "Default-First-Site-Name", -1, 0);
SCVAL(q, 0, size);
q += (size + 1);
q_orig = q;
/* Site name */
size = push_ascii(&q[1], "Default-First-Site-Name", -1, 0);
SCVAL(q, 0, size);
q += (size + 1);
/* Site name (2) */
str_offset = q - q_orig;
SCVAL(q, 0, 0xc0 | ((str_offset >> 8) & 0x3F));
SCVAL(q, 1, str_offset & 0xFF);
q += 2;
/* Site name (2) */
str_offset = q - q_orig;
SCVAL(q, 0, 0xc0 | ((str_offset >> 8) & 0x3F));
SCVAL(q, 1, str_offset & 0xFF);
q += 2;
SCVAL(q, 0, PTR_DIFF(q,q1));
SCVAL(q, 1, 0x10); /* unknown */
SCVAL(q, 0, PTR_DIFF(q,q1));
SCVAL(q, 1, 0x10); /* unknown */
SIVAL(q, 0, 0x00000002); q += 4; /* unknown */
SIVAL(q, 0, (iface_ip(p->ip))->s_addr); q += 4;
SIVAL(q, 0, 0x00000000); q += 4; /* unknown */
SIVAL(q, 0, 0x00000000); q += 4; /* unknown */
}
SIVAL(q, 0, 0x00000002);
q += 4; /* unknown */
SIVAL(q, 0, (iface_ip(p->ip))->s_addr);
q += 4;
SIVAL(q, 0, 0x00000000);
q += 4; /* unknown */
SIVAL(q, 0, 0x00000000);
q += 4; /* unknown */
}
#endif
/* tell the client what version we are */
SIVAL(q, 0, ((ntversion < 11) || (SEC_ADS != lp_security())) ? 1 : 13);
/* our ntversion */
SSVAL(q, 4, 0xffff); /* our lmnttoken */
SSVAL(q, 6, 0xffff); /* our lm20token */
q += 8;
/* tell the client what version we are */
SIVAL(q, 0, ((ntversion < 11) || (SEC_ADS != lp_security())) ? 1 : 13);
/* our ntversion */
SSVAL(q, 4, 0xffff); /* our lmnttoken */
SSVAL(q, 6, 0xffff); /* our lm20token */
q += 8;
dump_data(4, outbuf, PTR_DIFF(q, outbuf));
dump_data(4, outbuf, PTR_DIFF(q, outbuf));
send_mailslot(True, getdc,
outbuf,PTR_DIFF(q,outbuf),
global_myname(), 0x0,
dgram->source_name.name,
dgram->source_name.name_type,
p->ip, *iface_ip(p->ip), p->port);
break;
}
pull_ascii_fstring(getdc_str, getdc);
pull_ascii_nstring(source_name, dgram->source_name.name);
/* Announce change to UAS or SAM. Send by the domain controller when a
replication event is required. */
send_mailslot(True, getdc,
outbuf,PTR_DIFF(q,outbuf),
global_myname(), 0x0,
dgram->source_name.name,
dgram->source_name.name_type,
p->ip, *iface_ip(p->ip), p->port);
break;
}
case SAM_UAS_CHANGE: {
struct sam_database_info *db_info;
char *q = buf + 2;
int i, db_count;
uint32 low_serial;
/* Announce change to UAS or SAM. Send by the domain controller when a
replication event is required. */
case SAM_UAS_CHANGE:
{
struct sam_database_info *db_info;
char *q = buf + 2;
int i, db_count;
uint32 low_serial;
/* Header */
/* Header */
low_serial = IVAL(q, 0); q += 4; /* Low serial number */
low_serial = IVAL(q, 0); q += 4; /* Low serial number */
q += 4; /* Date/time */
q += 4; /* Pulse */
q += 4; /* Random */
q += 4; /* Date/time */
q += 4; /* Pulse */
q += 4; /* Random */
/* Domain info */
/* Domain info */
q = skip_string(q, 1); /* PDC name */
q = skip_string(q, 1); /* Domain name */
q = skip_unibuf(q, PTR_DIFF(buf + len, q)); /* Unicode PDC name */
q = skip_unibuf(q, PTR_DIFF(buf + len, q)); /* Unicode domain name */
q = skip_string(q, 1); /* PDC name */
q = skip_string(q, 1); /* Domain name */
q = skip_unibuf(q, PTR_DIFF(buf + len, q)); /* Unicode PDC name */
q = skip_unibuf(q, PTR_DIFF(buf + len, q)); /* Unicode domain name */
/* Database info */
/* Database info */
db_count = SVAL(q, 0); q += 2;
db_count = SVAL(q, 0); q += 2;
db_info = (struct sam_database_info *)
malloc(sizeof(struct sam_database_info) * db_count);
db_info = (struct sam_database_info *)
malloc(sizeof(struct sam_database_info) * db_count);
if (db_info == NULL) {
DEBUG(3, ("out of memory allocating info for %d databases\n",
db_count));
return;
}
if (db_info == NULL) {
DEBUG(3, ("out of memory allocating info for %d databases\n", db_count));
return;
}
for (i = 0; i < db_count; i++) {
db_info[i].index = IVAL(q, 0);
db_info[i].serial_lo = IVAL(q, 4);
db_info[i].serial_hi = IVAL(q, 8);
db_info[i].date_lo = IVAL(q, 12);
db_info[i].date_hi = IVAL(q, 16);
q += 20;
}
for (i = 0; i < db_count; i++) {
db_info[i].index = IVAL(q, 0);
db_info[i].serial_lo = IVAL(q, 4);
db_info[i].serial_hi = IVAL(q, 8);
db_info[i].date_lo = IVAL(q, 12);
db_info[i].date_hi = IVAL(q, 16);
q += 20;
}
/* Domain SID */
/* Domain SID */
q += IVAL(q, 0) + 4; /* 4 byte length plus data */
q += IVAL(q, 0) + 4; /* 4 byte length plus data */
q += 2; /* Alignment? */
q += 2; /* Alignment? */
/* Misc other info */
/* Misc other info */
q += 4; /* NT version (0x1) */
q += 2; /* LMNT token (0xff) */
q += 2; /* LM20 token (0xff) */
q += 4; /* NT version (0x1) */
q += 2; /* LMNT token (0xff) */
q += 2; /* LM20 token (0xff) */
SAFE_FREE(db_info); /* Not sure whether we need to do anything
useful with these */
SAFE_FREE(db_info); /* Not sure whether we need to do anything useful with these */
/* Send message to smbd */
/* Send message to smbd */
send_repl_message(low_serial);
send_repl_message(low_serial);
break;
}
break;
}
default:
{
DEBUG(3,("process_logon_packet: Unknown domain request %d\n",code));
return;
}
}
default:
DEBUG(3,("process_logon_packet: Unknown domain request %d\n",code));
return;
}
}

View File

@ -34,27 +34,26 @@ int num_response_packets = 0;
static void add_response_record(struct subnet_record *subrec,
struct response_record *rrec)
{
struct response_record *rrec2;
struct response_record *rrec2;
num_response_packets++; /* count of total number of packets still around */
num_response_packets++; /* count of total number of packets still around */
DEBUG(4,("add_response_record: adding response record id:%hu to subnet %s. num_records:%d\n",
rrec->response_id, subrec->subnet_name, num_response_packets));
DEBUG(4,("add_response_record: adding response record id:%hu to subnet %s. num_records:%d\n",
rrec->response_id, subrec->subnet_name, num_response_packets));
if (!subrec->responselist)
{
subrec->responselist = rrec;
rrec->prev = NULL;
rrec->next = NULL;
return;
}
if (!subrec->responselist) {
subrec->responselist = rrec;
rrec->prev = NULL;
rrec->next = NULL;
return;
}
for (rrec2 = subrec->responselist; rrec2->next; rrec2 = rrec2->next)
;
for (rrec2 = subrec->responselist; rrec2->next; rrec2 = rrec2->next)
;
rrec2->next = rrec;
rrec->next = NULL;
rrec->prev = rrec2;
rrec2->next = rrec;
rrec->next = NULL;
rrec->prev = rrec2;
}
/***************************************************************************
@ -64,32 +63,31 @@ static void add_response_record(struct subnet_record *subrec,
void remove_response_record(struct subnet_record *subrec,
struct response_record *rrec)
{
if (rrec->prev)
rrec->prev->next = rrec->next;
if (rrec->next)
rrec->next->prev = rrec->prev;
if (rrec->prev)
rrec->prev->next = rrec->next;
if (rrec->next)
rrec->next->prev = rrec->prev;
if (subrec->responselist == rrec)
subrec->responselist = rrec->next;
if (subrec->responselist == rrec)
subrec->responselist = rrec->next;
if(rrec->userdata)
{
if(rrec->userdata->free_fn) {
(*rrec->userdata->free_fn)(rrec->userdata);
} else {
ZERO_STRUCTP(rrec->userdata);
SAFE_FREE(rrec->userdata);
}
}
if(rrec->userdata) {
if(rrec->userdata->free_fn) {
(*rrec->userdata->free_fn)(rrec->userdata);
} else {
ZERO_STRUCTP(rrec->userdata);
SAFE_FREE(rrec->userdata);
}
}
/* Ensure we can delete. */
rrec->packet->locked = False;
free_packet(rrec->packet);
/* Ensure we can delete. */
rrec->packet->locked = False;
free_packet(rrec->packet);
ZERO_STRUCTP(rrec);
SAFE_FREE(rrec);
ZERO_STRUCTP(rrec);
SAFE_FREE(rrec);
num_response_packets--; /* count of total number of packets still around */
num_response_packets--; /* count of total number of packets still around */
}
/****************************************************************************
@ -104,77 +102,70 @@ struct response_record *make_response_record( struct subnet_record *subrec,
fail_function fail_fn,
struct userdata_struct *userdata)
{
struct response_record *rrec;
struct nmb_packet *nmb = &p->packet.nmb;
struct response_record *rrec;
struct nmb_packet *nmb = &p->packet.nmb;
if (!(rrec = (struct response_record *)malloc(sizeof(*rrec))))
{
DEBUG(0,("make_response_queue_record: malloc fail for response_record.\n"));
return NULL;
}
if (!(rrec = (struct response_record *)malloc(sizeof(*rrec)))) {
DEBUG(0,("make_response_queue_record: malloc fail for response_record.\n"));
return NULL;
}
memset((char *)rrec, '\0', sizeof(*rrec));
memset((char *)rrec, '\0', sizeof(*rrec));
rrec->response_id = nmb->header.name_trn_id;
rrec->response_id = nmb->header.name_trn_id;
rrec->resp_fn = resp_fn;
rrec->timeout_fn = timeout_fn;
rrec->success_fn = success_fn;
rrec->fail_fn = fail_fn;
rrec->resp_fn = resp_fn;
rrec->timeout_fn = timeout_fn;
rrec->success_fn = success_fn;
rrec->fail_fn = fail_fn;
rrec->packet = p;
rrec->packet = p;
if(userdata)
{
/* Intelligent userdata. */
if(userdata->copy_fn)
{
if((rrec->userdata = (*userdata->copy_fn)(userdata)) == NULL)
{
DEBUG(0,("make_response_queue_record: copy fail for userdata.\n"));
ZERO_STRUCTP(rrec);
SAFE_FREE(rrec);
return NULL;
}
}
else
{
/* Primitive userdata, do a memcpy. */
if((rrec->userdata = (struct userdata_struct *)
malloc(sizeof(struct userdata_struct)+userdata->userdata_len)) == NULL)
{
DEBUG(0,("make_response_queue_record: malloc fail for userdata.\n"));
ZERO_STRUCTP(rrec);
SAFE_FREE(rrec);
return NULL;
}
rrec->userdata->copy_fn = userdata->copy_fn;
rrec->userdata->free_fn = userdata->free_fn;
rrec->userdata->userdata_len = userdata->userdata_len;
memcpy(rrec->userdata->data, userdata->data, userdata->userdata_len);
}
}
else
rrec->userdata = NULL;
if(userdata) {
/* Intelligent userdata. */
if(userdata->copy_fn) {
if((rrec->userdata = (*userdata->copy_fn)(userdata)) == NULL) {
DEBUG(0,("make_response_queue_record: copy fail for userdata.\n"));
ZERO_STRUCTP(rrec);
SAFE_FREE(rrec);
return NULL;
}
} else {
/* Primitive userdata, do a memcpy. */
if((rrec->userdata = (struct userdata_struct *)
malloc(sizeof(struct userdata_struct)+userdata->userdata_len)) == NULL) {
DEBUG(0,("make_response_queue_record: malloc fail for userdata.\n"));
ZERO_STRUCTP(rrec);
SAFE_FREE(rrec);
return NULL;
}
rrec->userdata->copy_fn = userdata->copy_fn;
rrec->userdata->free_fn = userdata->free_fn;
rrec->userdata->userdata_len = userdata->userdata_len;
memcpy(rrec->userdata->data, userdata->data, userdata->userdata_len);
}
} else {
rrec->userdata = NULL;
}
rrec->num_msgs = 0;
rrec->num_msgs = 0;
if(!nmb->header.nm_flags.bcast)
rrec->repeat_interval = 5; /* 5 seconds for unicast packets. */
else
rrec->repeat_interval = 1; /* XXXX should be in ms */
rrec->repeat_count = 3; /* 3 retries */
rrec->repeat_time = time(NULL) + rrec->repeat_interval; /* initial retry time */
if(!nmb->header.nm_flags.bcast)
rrec->repeat_interval = 5; /* 5 seconds for unicast packets. */
else
rrec->repeat_interval = 1; /* XXXX should be in ms */
rrec->repeat_count = 3; /* 3 retries */
rrec->repeat_time = time(NULL) + rrec->repeat_interval; /* initial retry time */
/* This packet is not being processed. */
rrec->in_expiration_processing = False;
/* This packet is not being processed. */
rrec->in_expiration_processing = False;
/* Lock the packet so we won't lose it while it's on the list. */
p->locked = True;
/* Lock the packet so we won't lose it while it's on the list. */
p->locked = True;
add_response_record(subrec, rrec);
add_response_record(subrec, rrec);
return rrec;
return rrec;
}
/****************************************************************************
@ -184,18 +175,16 @@ struct response_record *make_response_record( struct subnet_record *subrec,
static struct response_record *find_response_record_on_subnet(
struct subnet_record *subrec, uint16 id)
{
struct response_record *rrec = NULL;
struct response_record *rrec = NULL;
for (rrec = subrec->responselist; rrec; rrec = rrec->next)
{
if (rrec->response_id == id)
{
DEBUG(4, ("find_response_record: found response record id = %hu on subnet %s\n",
id, subrec->subnet_name));
break;
}
}
return rrec;
for (rrec = subrec->responselist; rrec; rrec = rrec->next) {
if (rrec->response_id == id) {
DEBUG(4, ("find_response_record: found response record id = %hu on subnet %s\n",
id, subrec->subnet_name));
break;
}
}
return rrec;
}
/****************************************************************************
@ -205,37 +194,34 @@ static struct response_record *find_response_record_on_subnet(
struct response_record *find_response_record(struct subnet_record **ppsubrec,
uint16 id)
{
struct response_record *rrec = NULL;
struct response_record *rrec = NULL;
for ((*ppsubrec) = FIRST_SUBNET; (*ppsubrec);
(*ppsubrec) = NEXT_SUBNET_INCLUDING_UNICAST(*ppsubrec))
{
if((rrec = find_response_record_on_subnet(*ppsubrec, id)) != NULL)
return rrec;
}
for ((*ppsubrec) = FIRST_SUBNET; (*ppsubrec);
(*ppsubrec) = NEXT_SUBNET_INCLUDING_UNICAST(*ppsubrec)) {
if((rrec = find_response_record_on_subnet(*ppsubrec, id)) != NULL)
return rrec;
}
/* There should never be response records on the remote_broadcast subnet.
Sanity check to ensure this is so. */
if(remote_broadcast_subnet->responselist != NULL)
{
DEBUG(0,("find_response_record: response record found on subnet %s. This should \
/* There should never be response records on the remote_broadcast subnet.
Sanity check to ensure this is so. */
if(remote_broadcast_subnet->responselist != NULL) {
DEBUG(0,("find_response_record: response record found on subnet %s. This should \
never happen !\n", remote_broadcast_subnet->subnet_name));
}
}
/* Now check the WINS server subnet if it exists. */
if(wins_server_subnet != NULL)
{
*ppsubrec = wins_server_subnet;
if((rrec = find_response_record_on_subnet(*ppsubrec, id))!= NULL)
return rrec;
}
/* Now check the WINS server subnet if it exists. */
if(wins_server_subnet != NULL) {
*ppsubrec = wins_server_subnet;
if((rrec = find_response_record_on_subnet(*ppsubrec, id))!= NULL)
return rrec;
}
DEBUG(0,("find_response_record: response packet id %hu received with no \
DEBUG(0,("find_response_record: response packet id %hu received with no \
matching record.\n", id));
*ppsubrec = NULL;
*ppsubrec = NULL;
return NULL;
return NULL;
}
/****************************************************************************
@ -244,21 +230,19 @@ matching record.\n", id));
BOOL is_refresh_already_queued(struct subnet_record *subrec, struct name_record *namerec)
{
struct response_record *rrec = NULL;
struct response_record *rrec = NULL;
for (rrec = subrec->responselist; rrec; rrec = rrec->next)
{
struct packet_struct *p = rrec->packet;
struct nmb_packet *nmb = &p->packet.nmb;
for (rrec = subrec->responselist; rrec; rrec = rrec->next) {
struct packet_struct *p = rrec->packet;
struct nmb_packet *nmb = &p->packet.nmb;
if((nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) ||
(nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9))
{
/* Yes it's a queued refresh - check if the name is correct. */
if(nmb_name_equal(&nmb->question.question_name, &namerec->name))
return True;
}
}
if((nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) ||
(nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9)) {
/* Yes it's a queued refresh - check if the name is correct. */
if(nmb_name_equal(&nmb->question.question_name, &namerec->name))
return True;
}
}
return False;
}
return False;
}

View File

@ -35,21 +35,21 @@ extern BOOL found_lm_clients;
void send_browser_reset(int reset_type, const char *to_name, int to_type, struct in_addr to_ip)
{
pstring outbuf;
char *p;
pstring outbuf;
char *p;
DEBUG(3,("send_browser_reset: sending reset request type %d to %s<%02x> IP %s.\n",
reset_type, to_name, to_type, inet_ntoa(to_ip) ));
DEBUG(3,("send_browser_reset: sending reset request type %d to %s<%02x> IP %s.\n",
reset_type, to_name, to_type, inet_ntoa(to_ip) ));
memset(outbuf,'\0',sizeof(outbuf));
p = outbuf;
SCVAL(p,0,ANN_ResetBrowserState);
p++;
SCVAL(p,0,reset_type);
p++;
memset(outbuf,'\0',sizeof(outbuf));
p = outbuf;
SCVAL(p,0,ANN_ResetBrowserState);
p++;
SCVAL(p,0,reset_type);
p++;
send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
global_myname(), 0x0, to_name, to_type, to_ip,
send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
global_myname(), 0x0, to_name, to_type, to_ip,
FIRST_SUBNET->myip, DGRAM_PORT);
}
@ -60,25 +60,25 @@ void send_browser_reset(int reset_type, const char *to_name, int to_type, struct
void broadcast_announce_request(struct subnet_record *subrec, struct work_record *work)
{
pstring outbuf;
char *p;
pstring outbuf;
char *p;
work->needannounce = True;
work->needannounce = True;
DEBUG(3,("broadcast_announce_request: sending announce request for workgroup %s \
DEBUG(3,("broadcast_announce_request: sending announce request for workgroup %s \
to subnet %s\n", work->work_group, subrec->subnet_name));
memset(outbuf,'\0',sizeof(outbuf));
p = outbuf;
SCVAL(p,0,ANN_AnnouncementRequest);
p++;
memset(outbuf,'\0',sizeof(outbuf));
p = outbuf;
SCVAL(p,0,ANN_AnnouncementRequest);
p++;
SCVAL(p,0,work->token); /* (local) Unique workgroup token id. */
p++;
p += push_string(NULL, p+1, global_myname(), 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
SCVAL(p,0,work->token); /* (local) Unique workgroup token id. */
p++;
p += push_string(NULL, p+1, global_myname(), 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
send_mailslot(False, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
global_myname(), 0x0, work->work_group,0x1e, subrec->bcast_ip,
send_mailslot(False, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
global_myname(), 0x0, work->work_group,0x1e, subrec->bcast_ip,
subrec->myip, DGRAM_PORT);
}
@ -91,33 +91,33 @@ static void send_announcement(struct subnet_record *subrec, int announce_type,
time_t announce_interval,
const char *server_name, int server_type, const char *server_comment)
{
pstring outbuf;
char *p;
pstring outbuf;
char *p;
memset(outbuf,'\0',sizeof(outbuf));
p = outbuf+1;
memset(outbuf,'\0',sizeof(outbuf));
p = outbuf+1;
SCVAL(outbuf,0,announce_type);
SCVAL(outbuf,0,announce_type);
/* Announcement parameters. */
SCVAL(p,0,updatecount);
SIVAL(p,1,announce_interval*1000); /* Milliseconds - despite the spec. */
/* Announcement parameters. */
SCVAL(p,0,updatecount);
SIVAL(p,1,announce_interval*1000); /* Milliseconds - despite the spec. */
push_string(NULL, p+5, server_name, 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
push_string(NULL, p+5, server_name, 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
SCVAL(p,21,lp_major_announce_version()); /* Major version. */
SCVAL(p,22,lp_minor_announce_version()); /* Minor version. */
SCVAL(p,21,lp_major_announce_version()); /* Major version. */
SCVAL(p,22,lp_minor_announce_version()); /* Minor version. */
SIVAL(p,23,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
/* Browse version: got from NT/AS 4.00 - Value defined in smb.h (JHT). */
SSVAL(p,27,BROWSER_ELECTION_VERSION);
SSVAL(p,29,BROWSER_CONSTANT); /* Browse signature. */
SIVAL(p,23,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
/* Browse version: got from NT/AS 4.00 - Value defined in smb.h (JHT). */
SSVAL(p,27,BROWSER_ELECTION_VERSION);
SSVAL(p,29,BROWSER_CONSTANT); /* Browse signature. */
p += 31 + push_string(NULL, p+31, server_comment, -1, STR_ASCII|STR_TERMINATE);
p += 31 + push_string(NULL, p+31, server_comment, -1, STR_ASCII|STR_TERMINATE);
send_mailslot(False,BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
DGRAM_PORT);
send_mailslot(False,BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
DGRAM_PORT);
}
/****************************************************************************
@ -129,28 +129,23 @@ static void send_lm_announcement(struct subnet_record *subrec, int announce_type
time_t announce_interval,
char *server_name, int server_type, char *server_comment)
{
pstring outbuf;
char *p=outbuf;
pstring outbuf;
char *p=outbuf;
memset(outbuf,'\0',sizeof(outbuf));
memset(outbuf,'\0',sizeof(outbuf));
SSVAL(p,0,announce_type);
SIVAL(p,2,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
SCVAL(p,6,lp_major_announce_version()); /* Major version. */
SCVAL(p,7,lp_minor_announce_version()); /* Minor version. */
SSVAL(p,8,announce_interval); /* In seconds - according to spec. */
SSVAL(p,0,announce_type);
SIVAL(p,2,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
SCVAL(p,6,lp_major_announce_version()); /* Major version. */
SCVAL(p,7,lp_minor_announce_version()); /* Minor version. */
SSVAL(p,8,announce_interval); /* In seconds - according to spec. */
p += 10;
/*StrnCpy(p,server_name,15);
strupper_m(p);
p = skip_string(p,1);
pstrcpy(p,server_comment);
p = skip_string(p,1);*/
p += push_string(NULL, p, server_name, 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
p += push_string(NULL, p, server_comment, sizeof(pstring)-15, STR_ASCII|STR_UPPER|STR_TERMINATE);
p += 10;
p += push_string(NULL, p, server_name, 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
p += push_string(NULL, p, server_comment, sizeof(pstring)-15, STR_ASCII|STR_UPPER|STR_TERMINATE);
send_mailslot(False,LANMAN_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
send_mailslot(False,LANMAN_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
DGRAM_PORT);
}
@ -161,20 +156,20 @@ static void send_lm_announcement(struct subnet_record *subrec, int announce_type
static void send_local_master_announcement(struct subnet_record *subrec, struct work_record *work,
struct server_record *servrec)
{
/* Ensure we don't have the prohibited bit set. */
uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
/* Ensure we don't have the prohibited bit set. */
uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
DEBUG(3,("send_local_master_announcement: type %x for name %s on subnet %s for workgroup %s\n",
type, global_myname(), subrec->subnet_name, work->work_group));
DEBUG(3,("send_local_master_announcement: type %x for name %s on subnet %s for workgroup %s\n",
type, global_myname(), subrec->subnet_name, work->work_group));
send_announcement(subrec, ANN_LocalMasterAnnouncement,
global_myname(), /* From nbt name. */
work->work_group, 0x1e, /* To nbt name. */
subrec->bcast_ip, /* To ip. */
work->announce_interval, /* Time until next announce. */
global_myname(), /* Name to announce. */
type, /* Type field. */
servrec->serv.comment);
send_announcement(subrec, ANN_LocalMasterAnnouncement,
global_myname(), /* From nbt name. */
work->work_group, 0x1e, /* To nbt name. */
subrec->bcast_ip, /* To ip. */
work->announce_interval, /* Time until next announce. */
global_myname(), /* Name to announce. */
type, /* Type field. */
servrec->serv.comment);
}
/****************************************************************************
@ -183,17 +178,17 @@ static void send_local_master_announcement(struct subnet_record *subrec, struct
static void send_workgroup_announcement(struct subnet_record *subrec, struct work_record *work)
{
DEBUG(3,("send_workgroup_announcement: on subnet %s for workgroup %s\n",
subrec->subnet_name, work->work_group));
DEBUG(3,("send_workgroup_announcement: on subnet %s for workgroup %s\n",
subrec->subnet_name, work->work_group));
send_announcement(subrec, ANN_DomainAnnouncement,
global_myname(), /* From nbt name. */
MSBROWSE, 0x1, /* To nbt name. */
subrec->bcast_ip, /* To ip. */
work->announce_interval, /* Time until next announce. */
work->work_group, /* Name to announce. */
SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT, /* workgroup announce flags. */
global_myname()); /* From name as comment. */
send_announcement(subrec, ANN_DomainAnnouncement,
global_myname(), /* From nbt name. */
MSBROWSE, 0x1, /* To nbt name. */
subrec->bcast_ip, /* To ip. */
work->announce_interval, /* Time until next announce. */
work->work_group, /* Name to announce. */
SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT, /* workgroup announce flags. */
global_myname()); /* From name as comment. */
}
/****************************************************************************
@ -203,20 +198,20 @@ static void send_workgroup_announcement(struct subnet_record *subrec, struct wor
static void send_host_announcement(struct subnet_record *subrec, struct work_record *work,
struct server_record *servrec)
{
/* Ensure we don't have the prohibited bits set. */
uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
/* Ensure we don't have the prohibited bits set. */
uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
DEBUG(3,("send_host_announcement: type %x for host %s on subnet %s for workgroup %s\n",
type, servrec->serv.name, subrec->subnet_name, work->work_group));
DEBUG(3,("send_host_announcement: type %x for host %s on subnet %s for workgroup %s\n",
type, servrec->serv.name, subrec->subnet_name, work->work_group));
send_announcement(subrec, ANN_HostAnnouncement,
servrec->serv.name, /* From nbt name. */
work->work_group, 0x1d, /* To nbt name. */
subrec->bcast_ip, /* To ip. */
work->announce_interval, /* Time until next announce. */
servrec->serv.name, /* Name to announce. */
type, /* Type field. */
servrec->serv.comment);
send_announcement(subrec, ANN_HostAnnouncement,
servrec->serv.name, /* From nbt name. */
work->work_group, 0x1d, /* To nbt name. */
subrec->bcast_ip, /* To ip. */
work->announce_interval, /* Time until next announce. */
servrec->serv.name, /* Name to announce. */
type, /* Type field. */
servrec->serv.comment);
}
/****************************************************************************
@ -226,20 +221,20 @@ static void send_host_announcement(struct subnet_record *subrec, struct work_rec
static void send_lm_host_announcement(struct subnet_record *subrec, struct work_record *work,
struct server_record *servrec, int lm_interval)
{
/* Ensure we don't have the prohibited bits set. */
uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
/* Ensure we don't have the prohibited bits set. */
uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
DEBUG(3,("send_lm_host_announcement: type %x for host %s on subnet %s for workgroup %s, ttl: %d\n",
type, servrec->serv.name, subrec->subnet_name, work->work_group, lm_interval));
DEBUG(3,("send_lm_host_announcement: type %x for host %s on subnet %s for workgroup %s, ttl: %d\n",
type, servrec->serv.name, subrec->subnet_name, work->work_group, lm_interval));
send_lm_announcement(subrec, ANN_HostAnnouncement,
servrec->serv.name, /* From nbt name. */
work->work_group, 0x00, /* To nbt name. */
subrec->bcast_ip, /* To ip. */
lm_interval, /* Time until next announce. */
servrec->serv.name, /* Name to announce. */
type, /* Type field. */
servrec->serv.comment);
send_lm_announcement(subrec, ANN_HostAnnouncement,
servrec->serv.name, /* From nbt name. */
work->work_group, 0x00, /* To nbt name. */
subrec->bcast_ip, /* To ip. */
lm_interval, /* Time until next announce. */
servrec->serv.name, /* Name to announce (fstring not netbios name struct). */
type, /* Type field. */
servrec->serv.comment);
}
/****************************************************************************
@ -249,18 +244,15 @@ static void send_lm_host_announcement(struct subnet_record *subrec, struct work_
static void announce_server(struct subnet_record *subrec, struct work_record *work,
struct server_record *servrec)
{
/* Only do domain announcements if we are a master and it's
our primary name we're being asked to announce. */
/* Only do domain announcements if we are a master and it's
our primary name we're being asked to announce. */
if (AM_LOCAL_MASTER_BROWSER(work) && strequal(global_myname(),servrec->serv.name))
{
send_local_master_announcement(subrec, work, servrec);
send_workgroup_announcement(subrec, work);
}
else
{
send_host_announcement(subrec, work, servrec);
}
if (AM_LOCAL_MASTER_BROWSER(work) && strequal(global_myname(),servrec->serv.name)) {
send_local_master_announcement(subrec, work, servrec);
send_workgroup_announcement(subrec, work);
} else {
send_host_announcement(subrec, work, servrec);
}
}
/****************************************************************************
@ -270,43 +262,39 @@ static void announce_server(struct subnet_record *subrec, struct work_record *wo
void announce_my_server_names(time_t t)
{
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, lp_workgroup());
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
struct work_record *work = find_workgroup_on_subnet(subrec, lp_workgroup());
if(work)
{
struct server_record *servrec;
if(work) {
struct server_record *servrec;
if (work->needannounce)
{
/* Drop back to a max 3 minute announce. This is to prevent a
single lost packet from breaking things for too long. */
if (work->needannounce) {
/* Drop back to a max 3 minute announce. This is to prevent a
single lost packet from breaking things for too long. */
work->announce_interval = MIN(work->announce_interval,
CHECK_TIME_MIN_HOST_ANNCE*60);
work->lastannounce_time = t - (work->announce_interval+1);
work->needannounce = False;
}
work->announce_interval = MIN(work->announce_interval,
CHECK_TIME_MIN_HOST_ANNCE*60);
work->lastannounce_time = t - (work->announce_interval+1);
work->needannounce = False;
}
/* Announce every minute at first then progress to every 12 mins */
if ((t - work->lastannounce_time) < work->announce_interval)
continue;
/* Announce every minute at first then progress to every 12 mins */
if ((t - work->lastannounce_time) < work->announce_interval)
continue;
if (work->announce_interval < (CHECK_TIME_MAX_HOST_ANNCE * 60))
work->announce_interval += 60;
if (work->announce_interval < (CHECK_TIME_MAX_HOST_ANNCE * 60))
work->announce_interval += 60;
work->lastannounce_time = t;
work->lastannounce_time = t;
for (servrec = work->serverlist; servrec; servrec = servrec->next)
{
if (is_myname(servrec->serv.name))
announce_server(subrec, work, servrec);
}
} /* if work */
} /* for subrec */
for (servrec = work->serverlist; servrec; servrec = servrec->next) {
if (is_myname(servrec->serv.name))
announce_server(subrec, work, servrec);
}
} /* if work */
} /* for subrec */
}
/****************************************************************************
@ -316,47 +304,42 @@ void announce_my_server_names(time_t t)
void announce_my_lm_server_names(time_t t)
{
struct subnet_record *subrec;
static time_t last_lm_announce_time=0;
int announce_interval = lp_lm_interval();
int lm_announce = lp_lm_announce();
struct subnet_record *subrec;
static time_t last_lm_announce_time=0;
int announce_interval = lp_lm_interval();
int lm_announce = lp_lm_announce();
if ((announce_interval <= 0) || (lm_announce <= 0))
{
/* user absolutely does not want LM announcements to be sent. */
return;
}
if ((announce_interval <= 0) || (lm_announce <= 0)) {
/* user absolutely does not want LM announcements to be sent. */
return;
}
if ((lm_announce >= 2) && (!found_lm_clients))
{
/* has been set to 2 (Auto) but no LM clients detected (yet). */
return;
}
if ((lm_announce >= 2) && (!found_lm_clients)) {
/* has been set to 2 (Auto) but no LM clients detected (yet). */
return;
}
/* Otherwise: must have been set to 1 (Yes), or LM clients *have*
been detected. */
/* Otherwise: must have been set to 1 (Yes), or LM clients *have*
been detected. */
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
{
struct work_record *work = find_workgroup_on_subnet(subrec, lp_workgroup());
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
struct work_record *work = find_workgroup_on_subnet(subrec, lp_workgroup());
if(work)
{
struct server_record *servrec;
if(work) {
struct server_record *servrec;
if (last_lm_announce_time && ((t - last_lm_announce_time) < announce_interval ))
continue;
if (last_lm_announce_time && ((t - last_lm_announce_time) < announce_interval ))
continue;
last_lm_announce_time = t;
last_lm_announce_time = t;
for (servrec = work->serverlist; servrec; servrec = servrec->next)
{
if (is_myname(servrec->serv.name))
/* skipping equivalent of announce_server() */
send_lm_host_announcement(subrec, work, servrec, announce_interval);
}
} /* if work */
} /* for subrec */
for (servrec = work->serverlist; servrec; servrec = servrec->next) {
if (is_myname(servrec->serv.name))
/* skipping equivalent of announce_server() */
send_lm_host_announcement(subrec, work, servrec, announce_interval);
}
} /* if work */
} /* for subrec */
}
/* Announce timer. Moved into global static so it can be reset
@ -370,7 +353,7 @@ static time_t announce_timer_last=0;
void reset_announce_timer(void)
{
announce_timer_last = time(NULL) - (CHECK_TIME_MST_ANNOUNCE * 60);
announce_timer_last = time(NULL) - (CHECK_TIME_MST_ANNOUNCE * 60);
}
/****************************************************************************
@ -379,45 +362,40 @@ void reset_announce_timer(void)
void announce_myself_to_domain_master_browser(time_t t)
{
struct subnet_record *subrec;
struct work_record *work;
struct subnet_record *subrec;
struct work_record *work;
if(!we_are_a_wins_client())
{
DEBUG(10,("announce_myself_to_domain_master_browser: no unicast subnet, ignoring.\n"));
return;
}
if(!we_are_a_wins_client()) {
DEBUG(10,("announce_myself_to_domain_master_browser: no unicast subnet, ignoring.\n"));
return;
}
if (!announce_timer_last)
announce_timer_last = t;
if (!announce_timer_last)
announce_timer_last = t;
if ((t-announce_timer_last) < (CHECK_TIME_MST_ANNOUNCE * 60))
{
DEBUG(10,("announce_myself_to_domain_master_browser: t (%d) - last(%d) < %d\n",
(int)t, (int)announce_timer_last,
CHECK_TIME_MST_ANNOUNCE * 60 ));
return;
}
if ((t-announce_timer_last) < (CHECK_TIME_MST_ANNOUNCE * 60)) {
DEBUG(10,("announce_myself_to_domain_master_browser: t (%d) - last(%d) < %d\n",
(int)t, (int)announce_timer_last,
CHECK_TIME_MST_ANNOUNCE * 60 ));
return;
}
announce_timer_last = t;
announce_timer_last = t;
/* Look over all our broadcast subnets to see if any of them
has the state set as local master browser. */
/* Look over all our broadcast subnets to see if any of them
has the state set as local master browser. */
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
{
for (work = subrec->workgrouplist; work; work = work->next)
{
if (AM_LOCAL_MASTER_BROWSER(work))
{
DEBUG(4,( "announce_myself_to_domain_master_browser: I am a local master browser for \
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
for (work = subrec->workgrouplist; work; work = work->next) {
if (AM_LOCAL_MASTER_BROWSER(work)) {
DEBUG(4,( "announce_myself_to_domain_master_browser: I am a local master browser for \
workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
/* Look in nmbd_browsersync.c for the rest of this code. */
announce_and_sync_with_domain_master_browser(subrec, work);
}
}
}
/* Look in nmbd_browsersync.c for the rest of this code. */
announce_and_sync_with_domain_master_browser(subrec, work);
}
}
}
}
/****************************************************************************
@ -427,49 +405,43 @@ This must *only* be called on shutdown.
void announce_my_servers_removed(void)
{
int announce_interval = lp_lm_interval();
int lm_announce = lp_lm_announce();
struct subnet_record *subrec;
int announce_interval = lp_lm_interval();
int lm_announce = lp_lm_announce();
struct subnet_record *subrec;
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
{
struct work_record *work;
for (work = subrec->workgrouplist; work; work = work->next)
{
struct server_record *servrec;
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
struct work_record *work;
for (work = subrec->workgrouplist; work; work = work->next) {
struct server_record *servrec;
work->announce_interval = 0;
for (servrec = work->serverlist; servrec; servrec = servrec->next)
{
if (!is_myname(servrec->serv.name))
continue;
servrec->serv.type = 0;
if(AM_LOCAL_MASTER_BROWSER(work))
send_local_master_announcement(subrec, work, servrec);
send_host_announcement(subrec, work, servrec);
work->announce_interval = 0;
for (servrec = work->serverlist; servrec; servrec = servrec->next) {
if (!is_myname(servrec->serv.name))
continue;
servrec->serv.type = 0;
if(AM_LOCAL_MASTER_BROWSER(work))
send_local_master_announcement(subrec, work, servrec);
send_host_announcement(subrec, work, servrec);
if ((announce_interval <= 0) || (lm_announce <= 0)) {
/* user absolutely does not want LM announcements to be sent. */
continue;
}
if ((announce_interval <= 0) || (lm_announce <= 0))
{
/* user absolutely does not want LM announcements to be sent. */
continue;
}
if ((lm_announce >= 2) && (!found_lm_clients)) {
/* has been set to 2 (Auto) but no LM clients detected (yet). */
continue;
}
if ((lm_announce >= 2) && (!found_lm_clients))
{
/* has been set to 2 (Auto) but no LM clients detected (yet). */
continue;
}
/*
* lm announce was set or we have seen lm announcements, so do
* a lm announcement of host removed.
*/
/*
* lm announce was set or we have seen lm announcements, so do
* a lm announcement of host removed.
*/
send_lm_host_announcement(subrec, work, servrec, 0);
}
}
}
send_lm_host_announcement(subrec, work, servrec, 0);
}
}
}
}
/****************************************************************************
@ -480,132 +452,127 @@ void announce_my_servers_removed(void)
void announce_remote(time_t t)
{
char *s;
const char *ptr;
static time_t last_time = 0;
pstring s2;
struct in_addr addr;
char *comment;
int stype = lp_default_server_announce();
char *s;
const char *ptr;
static time_t last_time = 0;
pstring s2;
struct in_addr addr;
char *comment;
int stype = lp_default_server_announce();
if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
return;
if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
return;
last_time = t;
last_time = t;
s = lp_remote_announce();
if (!*s)
return;
s = lp_remote_announce();
if (!*s)
return;
comment = string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH);
comment = string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH);
for (ptr=s; next_token(&ptr,s2,NULL,sizeof(s2)); )
{
/* The entries are of the form a.b.c.d/WORKGROUP with
WORKGROUP being optional */
const char *wgroup;
char *pwgroup;
int i;
for (ptr=s; next_token(&ptr,s2,NULL,sizeof(s2)); ) {
/* The entries are of the form a.b.c.d/WORKGROUP with
WORKGROUP being optional */
const char *wgroup;
char *pwgroup;
int i;
pwgroup = strchr_m(s2,'/');
if (pwgroup)
*pwgroup++ = 0;
if (!pwgroup || !*pwgroup)
wgroup = lp_workgroup();
else
wgroup = pwgroup;
pwgroup = strchr_m(s2,'/');
if (pwgroup)
*pwgroup++ = 0;
if (!pwgroup || !*pwgroup)
wgroup = lp_workgroup();
else
wgroup = pwgroup;
addr = *interpret_addr2(s2);
addr = *interpret_addr2(s2);
/* Announce all our names including aliases */
/* Give the ip address as the address of our first
broadcast subnet. */
/* Announce all our names including aliases */
/* Give the ip address as the address of our first
broadcast subnet. */
for(i=0; my_netbios_names(i); i++)
{
const char *name = my_netbios_names(i);
for(i=0; my_netbios_names(i); i++) {
const char *name = my_netbios_names(i);
DEBUG(5,("announce_remote: Doing remote announce for server %s to IP %s.\n",
name, inet_ntoa(addr) ));
DEBUG(5,("announce_remote: Doing remote announce for server %s to IP %s.\n",
name, inet_ntoa(addr) ));
send_announcement(FIRST_SUBNET, ANN_HostAnnouncement,
name, /* From nbt name. */
wgroup, 0x1d, /* To nbt name. */
addr, /* To ip. */
REMOTE_ANNOUNCE_INTERVAL, /* Time until next announce. */
name, /* Name to announce. */
stype, /* Type field. */
comment);
}
}
send_announcement(FIRST_SUBNET, ANN_HostAnnouncement,
name, /* From nbt name. */
wgroup, 0x1d, /* To nbt name. */
addr, /* To ip. */
REMOTE_ANNOUNCE_INTERVAL, /* Time until next announce. */
name, /* Name to announce. */
stype, /* Type field. */
comment);
}
}
}
/****************************************************************************
Implement the 'remote browse sync' feature Andrew added.
These are used to put our browse lists into remote browse lists.
**************************************************************************/
**************************************************************************/
void browse_sync_remote(time_t t)
{
char *s;
const char *ptr;
static time_t last_time = 0;
pstring s2;
struct in_addr addr;
struct work_record *work;
pstring outbuf;
char *p;
fstring myname;
char *s;
const char *ptr;
static time_t last_time = 0;
pstring s2;
struct in_addr addr;
struct work_record *work;
pstring outbuf;
char *p;
fstring myname;
if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
return;
if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
return;
last_time = t;
last_time = t;
s = lp_remote_browse_sync();
if (!*s)
return;
s = lp_remote_browse_sync();
if (!*s)
return;
/*
* We only do this if we are the local master browser
* for our workgroup on the firsst subnet.
*/
/*
* We only do this if we are the local master browser
* for our workgroup on the firsst subnet.
*/
if((work = find_workgroup_on_subnet(FIRST_SUBNET, lp_workgroup())) == NULL)
{
DEBUG(0,("browse_sync_remote: Cannot find workgroup %s on subnet %s\n",
lp_workgroup(), FIRST_SUBNET->subnet_name ));
return;
}
if((work = find_workgroup_on_subnet(FIRST_SUBNET, lp_workgroup())) == NULL) {
DEBUG(0,("browse_sync_remote: Cannot find workgroup %s on subnet %s\n",
lp_workgroup(), FIRST_SUBNET->subnet_name ));
return;
}
if(!AM_LOCAL_MASTER_BROWSER(work))
{
DEBUG(5,("browse_sync_remote: We can only do this if we are a local master browser \
if(!AM_LOCAL_MASTER_BROWSER(work)) {
DEBUG(5,("browse_sync_remote: We can only do this if we are a local master browser \
for workgroup %s on subnet %s.\n", lp_workgroup(), FIRST_SUBNET->subnet_name ));
return;
}
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';
push_pstring_base(p, myname, outbuf);
p = skip_string(p,1);
p = skip_string(p,1);
for (ptr=s; next_token(&ptr,s2,NULL,sizeof(s2)); )
{
/* The entries are of the form a.b.c.d */
addr = *interpret_addr2(s2);
for (ptr=s; next_token(&ptr,s2,NULL,sizeof(s2)); ) {
/* The entries are of the form a.b.c.d */
addr = *interpret_addr2(s2);
DEBUG(5,("announce_remote: Doing remote browse sync announce for server %s to IP %s.\n",
global_myname(), inet_ntoa(addr) ));
DEBUG(5,("announce_remote: Doing remote browse sync announce for server %s to IP %s.\n",
global_myname(), inet_ntoa(addr) ));
send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
global_myname(), 0x0, "*", 0x0, addr, FIRST_SUBNET->myip, DGRAM_PORT);
}
send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
global_myname(), 0x0, "*", 0x0, addr, FIRST_SUBNET->myip, DGRAM_PORT);
}
}

View File

@ -33,28 +33,26 @@ int updatecount = 0;
void remove_all_servers(struct work_record *work)
{
struct server_record *servrec;
struct server_record *nexts;
struct server_record *servrec;
struct server_record *nexts;
for (servrec = work->serverlist; servrec; servrec = nexts)
{
DEBUG(7,("remove_all_servers: Removing server %s\n",servrec->serv.name));
nexts = servrec->next;
for (servrec = work->serverlist; servrec; servrec = nexts) {
DEBUG(7,("remove_all_servers: Removing server %s\n",servrec->serv.name));
nexts = servrec->next;
if (servrec->prev)
servrec->prev->next = servrec->next;
if (servrec->next)
servrec->next->prev = servrec->prev;
if (servrec->prev)
servrec->prev->next = servrec->next;
if (servrec->next)
servrec->next->prev = servrec->prev;
if (work->serverlist == servrec)
work->serverlist = servrec->next;
if (work->serverlist == servrec)
work->serverlist = servrec->next;
ZERO_STRUCTP(servrec);
SAFE_FREE(servrec);
ZERO_STRUCTP(servrec);
SAFE_FREE(servrec);
}
}
work->subnet->work_changed = True;
work->subnet->work_changed = True;
}
/***************************************************************************
@ -64,23 +62,22 @@ void remove_all_servers(struct work_record *work)
static void add_server_to_workgroup(struct work_record *work,
struct server_record *servrec)
{
struct server_record *servrec2;
struct server_record *servrec2;
if (!work->serverlist)
{
work->serverlist = servrec;
servrec->prev = NULL;
servrec->next = NULL;
return;
}
if (!work->serverlist) {
work->serverlist = servrec;
servrec->prev = NULL;
servrec->next = NULL;
return;
}
for (servrec2 = work->serverlist; servrec2->next; servrec2 = servrec2->next)
;
for (servrec2 = work->serverlist; servrec2->next; servrec2 = servrec2->next)
;
servrec2->next = servrec;
servrec->next = NULL;
servrec->prev = servrec2;
work->subnet->work_changed = True;
servrec2->next = servrec;
servrec->next = NULL;
servrec->prev = servrec2;
work->subnet->work_changed = True;
}
/****************************************************************************
@ -89,14 +86,13 @@ static void add_server_to_workgroup(struct work_record *work,
struct server_record *find_server_in_workgroup(struct work_record *work, const char *name)
{
struct server_record *ret;
struct server_record *ret;
for (ret = work->serverlist; ret; ret = ret->next)
{
if (strequal(ret->serv.name,name))
return ret;
}
return NULL;
for (ret = work->serverlist; ret; ret = ret->next) {
if (strequal(ret->serv.name,name))
return ret;
}
return NULL;
}
@ -106,17 +102,17 @@ struct server_record *find_server_in_workgroup(struct work_record *work, const c
void remove_server_from_workgroup(struct work_record *work, struct server_record *servrec)
{
if (servrec->prev)
servrec->prev->next = servrec->next;
if (servrec->next)
servrec->next->prev = servrec->prev;
if (servrec->prev)
servrec->prev->next = servrec->next;
if (servrec->next)
servrec->next->prev = servrec->prev;
if (work->serverlist == servrec)
work->serverlist = servrec->next;
if (work->serverlist == servrec)
work->serverlist = servrec->next;
ZERO_STRUCTP(servrec);
SAFE_FREE(servrec);
work->subnet->work_changed = True;
ZERO_STRUCTP(servrec);
SAFE_FREE(servrec);
work->subnet->work_changed = True;
}
/****************************************************************************
@ -127,47 +123,44 @@ struct server_record *create_server_on_workgroup(struct work_record *work,
const char *name,int servertype,
int ttl, const char *comment)
{
struct server_record *servrec;
struct server_record *servrec;
if (name[0] == '*')
{
DEBUG(7,("create_server_on_workgroup: not adding name starting with '*' (%s)\n",
name));
return (NULL);
}
if (name[0] == '*') {
DEBUG(7,("create_server_on_workgroup: not adding name starting with '*' (%s)\n",
name));
return (NULL);
}
if((servrec = find_server_in_workgroup(work, name)) != NULL)
{
DEBUG(0,("create_server_on_workgroup: Server %s already exists on \
if((servrec = find_server_in_workgroup(work, name)) != NULL) {
DEBUG(0,("create_server_on_workgroup: Server %s already exists on \
workgroup %s. This is a bug.\n", name, work->work_group));
return NULL;
}
return NULL;
}
if((servrec = (struct server_record *)malloc(sizeof(*servrec))) == NULL)
{
DEBUG(0,("create_server_entry_on_workgroup: malloc fail !\n"));
return NULL;
}
if((servrec = (struct server_record *)malloc(sizeof(*servrec))) == NULL) {
DEBUG(0,("create_server_entry_on_workgroup: malloc fail !\n"));
return NULL;
}
memset((char *)servrec,'\0',sizeof(*servrec));
memset((char *)servrec,'\0',sizeof(*servrec));
servrec->subnet = work->subnet;
servrec->subnet = work->subnet;
fstrcpy(servrec->serv.name,name);
fstrcpy(servrec->serv.comment,comment);
strupper_m(servrec->serv.name);
servrec->serv.type = servertype;
fstrcpy(servrec->serv.name,name);
fstrcpy(servrec->serv.comment,comment);
strupper_m(servrec->serv.name);
servrec->serv.type = servertype;
update_server_ttl(servrec, ttl);
update_server_ttl(servrec, ttl);
add_server_to_workgroup(work, servrec);
add_server_to_workgroup(work, servrec);
DEBUG(3,("create_server_on_workgroup: Created server entry %s of type %x (%s) on \
DEBUG(3,("create_server_on_workgroup: Created server entry %s of type %x (%s) on \
workgroup %s.\n", name,servertype,comment, work->work_group));
work->subnet->work_changed = True;
work->subnet->work_changed = True;
return(servrec);
return(servrec);
}
/*******************************************************************
@ -176,15 +169,15 @@ workgroup %s.\n", name,servertype,comment, work->work_group));
void update_server_ttl(struct server_record *servrec, int ttl)
{
if(ttl > lp_max_ttl())
ttl = lp_max_ttl();
if(ttl > lp_max_ttl())
ttl = lp_max_ttl();
if(is_myname(servrec->serv.name))
servrec->death_time = PERMANENT_TTL;
else
servrec->death_time = (ttl != PERMANENT_TTL) ? time(NULL)+(ttl*3) : PERMANENT_TTL;
if(is_myname(servrec->serv.name))
servrec->death_time = PERMANENT_TTL;
else
servrec->death_time = (ttl != PERMANENT_TTL) ? time(NULL)+(ttl*3) : PERMANENT_TTL;
servrec->subnet->work_changed = True;
servrec->subnet->work_changed = True;
}
/*******************************************************************
@ -195,20 +188,18 @@ void update_server_ttl(struct server_record *servrec, int ttl)
void expire_servers(struct work_record *work, time_t t)
{
struct server_record *servrec;
struct server_record *nexts;
struct server_record *servrec;
struct server_record *nexts;
for (servrec = work->serverlist; servrec; servrec = nexts)
{
nexts = servrec->next;
for (servrec = work->serverlist; servrec; servrec = nexts) {
nexts = servrec->next;
if ((servrec->death_time != PERMANENT_TTL) && ((t == -1) || (servrec->death_time < t)))
{
DEBUG(3,("expire_old_servers: Removing timed out server %s\n",servrec->serv.name));
remove_server_from_workgroup(work, servrec);
work->subnet->work_changed = True;
}
}
if ((servrec->death_time != PERMANENT_TTL) && ((t == -1) || (servrec->death_time < t))) {
DEBUG(3,("expire_old_servers: Removing timed out server %s\n",servrec->serv.name));
remove_server_from_workgroup(work, servrec);
work->subnet->work_changed = True;
}
}
}
/*******************************************************************
@ -221,33 +212,30 @@ static uint32 write_this_server_name( struct subnet_record *subrec,
struct work_record *work,
struct server_record *servrec)
{
struct subnet_record *ssub;
struct work_record *iwork;
struct subnet_record *ssub;
struct work_record *iwork;
/* Go through all the subnets we have already seen. */
for (ssub = FIRST_SUBNET; ssub != subrec; ssub = NEXT_SUBNET_INCLUDING_UNICAST(ssub))
{
for(iwork = ssub->workgrouplist; iwork; iwork = iwork->next)
{
if(find_server_in_workgroup( iwork, servrec->serv.name) != NULL)
{
/*
* We have already written out this server record, don't
* do it again. This gives precedence to servers we have seen
* on the broadcast subnets over servers that may have been
* added via a sync on the unicast_subet.
*
* The correct way to do this is to have a serverlist file
* per subnet - this means changes to smbd as well. I may
* add this at a later date (JRA).
*/
/* Go through all the subnets we have already seen. */
for (ssub = FIRST_SUBNET; ssub != subrec; ssub = NEXT_SUBNET_INCLUDING_UNICAST(ssub)) {
for(iwork = ssub->workgrouplist; iwork; iwork = iwork->next) {
if(find_server_in_workgroup( iwork, servrec->serv.name) != NULL) {
/*
* We have already written out this server record, don't
* do it again. This gives precedence to servers we have seen
* on the broadcast subnets over servers that may have been
* added via a sync on the unicast_subet.
*
* The correct way to do this is to have a serverlist file
* per subnet - this means changes to smbd as well. I may
* add this at a later date (JRA).
*/
return 0;
}
}
}
return 0;
}
}
}
return servrec->serv.type;
return servrec->serv.type;
}
/*******************************************************************
@ -261,30 +249,29 @@ static uint32 write_this_server_name( struct subnet_record *subrec,
static uint32 write_this_workgroup_name( struct subnet_record *subrec,
struct work_record *work)
{
struct subnet_record *ssub;
struct subnet_record *ssub;
if(strequal(lp_workgroup(), work->work_group))
return 0;
if(strequal(lp_workgroup(), work->work_group))
return 0;
/* This is a workgroup we have seen on a broadcast subnet. All
these have the same type. */
/* This is a workgroup we have seen on a broadcast subnet. All
these have the same type. */
if(subrec != unicast_subnet)
return (SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT|SV_TYPE_LOCAL_LIST_ONLY);
if(subrec != unicast_subnet)
return (SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT|SV_TYPE_LOCAL_LIST_ONLY);
for(ssub = FIRST_SUBNET; ssub; ssub = NEXT_SUBNET_EXCLUDING_UNICAST(ssub))
{
/* This is the unicast subnet so check if we've already written out
this subnet when we passed over the broadcast subnets. */
for(ssub = FIRST_SUBNET; ssub; ssub = NEXT_SUBNET_EXCLUDING_UNICAST(ssub)) {
/* This is the unicast subnet so check if we've already written out
this subnet when we passed over the broadcast subnets. */
if(find_workgroup_on_subnet( ssub, work->work_group) != NULL)
return 0;
}
if(find_workgroup_on_subnet( ssub, work->work_group) != NULL)
return 0;
}
/* All workgroups on the unicast subnet (except our own, which we
have already written out) cannot be local. */
/* All workgroups on the unicast subnet (except our own, which we
have already written out) cannot be local. */
return (SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT);
return (SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT);
}
/*******************************************************************
@ -306,143 +293,130 @@ void write_browse_list_entry(XFILE *fp, const char *name, uint32 rec_type,
void write_browse_list(time_t t, BOOL force_write)
{
struct subnet_record *subrec;
struct work_record *work;
struct server_record *servrec;
pstring fname,fnamenew;
uint32 stype;
int i;
XFILE *fp;
BOOL list_changed = force_write;
static time_t lasttime = 0;
struct subnet_record *subrec;
struct work_record *work;
struct server_record *servrec;
pstring fname,fnamenew;
uint32 stype;
int i;
XFILE *fp;
BOOL list_changed = force_write;
static time_t lasttime = 0;
/* Always dump if we're being told to by a signal. */
if(force_write == False)
{
if (!lasttime)
lasttime = t;
if (t - lasttime < 5)
return;
}
/* Always dump if we're being told to by a signal. */
if(force_write == False) {
if (!lasttime)
lasttime = t;
if (t - lasttime < 5)
return;
}
lasttime = t;
lasttime = t;
dump_workgroups(force_write);
dump_workgroups(force_write);
for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
{
if(subrec->work_changed)
{
list_changed = True;
break;
}
}
for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
if(subrec->work_changed) {
list_changed = True;
break;
}
}
if(!list_changed)
return;
if(!list_changed)
return;
updatecount++;
updatecount++;
pstrcpy(fname,lp_lockdir());
trim_string(fname,NULL,"/");
pstrcat(fname,"/");
pstrcat(fname,SERVER_LIST);
pstrcpy(fnamenew,fname);
pstrcat(fnamenew,".");
pstrcpy(fname,lp_lockdir());
trim_string(fname,NULL,"/");
pstrcat(fname,"/");
pstrcat(fname,SERVER_LIST);
pstrcpy(fnamenew,fname);
pstrcat(fnamenew,".");
fp = x_fopen(fnamenew,O_WRONLY|O_CREAT|O_TRUNC, 0644);
fp = x_fopen(fnamenew,O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (!fp)
{
DEBUG(0,("write_browse_list: Can't open file %s. Error was %s\n",
fnamenew,strerror(errno)));
return;
}
if (!fp) {
DEBUG(0,("write_browse_list: Can't open file %s. Error was %s\n",
fnamenew,strerror(errno)));
return;
}
/*
* Write out a record for our workgroup. Use the record from the first
* subnet.
*/
/*
* Write out a record for our workgroup. Use the record from the first
* subnet.
*/
if((work = find_workgroup_on_subnet(FIRST_SUBNET, lp_workgroup())) == NULL)
{
DEBUG(0,("write_browse_list: Fatal error - cannot find my workgroup %s\n",
lp_workgroup()));
x_fclose(fp);
return;
}
if((work = find_workgroup_on_subnet(FIRST_SUBNET, lp_workgroup())) == NULL) {
DEBUG(0,("write_browse_list: Fatal error - cannot find my workgroup %s\n",
lp_workgroup()));
x_fclose(fp);
return;
}
write_browse_list_entry(fp, work->work_group,
SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT|SV_TYPE_LOCAL_LIST_ONLY,
work->local_master_browser_name, work->work_group);
write_browse_list_entry(fp, work->work_group,
SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT|SV_TYPE_LOCAL_LIST_ONLY,
work->local_master_browser_name, work->work_group);
/*
* We need to do something special for our own names.
* This is due to the fact that we may be a local master browser on
* one of our broadcast subnets, and a domain master on the unicast
* subnet. We iterate over the subnets and only write out the name
* once.
*/
/*
* We need to do something special for our own names.
* This is due to the fact that we may be a local master browser on
* one of our broadcast subnets, and a domain master on the unicast
* subnet. We iterate over the subnets and only write out the name
* once.
*/
for (i=0; my_netbios_names(i); i++)
{
stype = 0;
for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
{
if((work = find_workgroup_on_subnet( subrec, lp_workgroup() )) == NULL)
continue;
if((servrec = find_server_in_workgroup( work, my_netbios_names(i))) == NULL)
continue;
for (i=0; my_netbios_names(i); i++) {
stype = 0;
for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
if((work = find_workgroup_on_subnet( subrec, lp_workgroup() )) == NULL)
continue;
if((servrec = find_server_in_workgroup( work, my_netbios_names(i))) == NULL)
continue;
stype |= servrec->serv.type;
}
stype |= servrec->serv.type;
}
/* Output server details, plus what workgroup they're in. */
write_browse_list_entry(fp, my_netbios_names(i), stype,
string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH), lp_workgroup());
}
/* Output server details, plus what workgroup they're in. */
write_browse_list_entry(fp, my_netbios_names(i), stype,
string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH), lp_workgroup());
}
for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
{
subrec->work_changed = False;
for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
subrec->work_changed = False;
for (work = subrec->workgrouplist; work ; work = work->next)
{
/* Write out a workgroup record for a workgroup. */
uint32 wg_type = write_this_workgroup_name( subrec, work);
for (work = subrec->workgrouplist; work ; work = work->next) {
/* Write out a workgroup record for a workgroup. */
uint32 wg_type = write_this_workgroup_name( subrec, work);
if(wg_type)
{
write_browse_list_entry(fp, work->work_group, wg_type,
work->local_master_browser_name,
work->work_group);
}
if(wg_type) {
write_browse_list_entry(fp, work->work_group, wg_type,
work->local_master_browser_name,
work->work_group);
}
/* Now write out any server records a workgroup may have. */
/* Now write out any server records a workgroup may have. */
for (servrec = work->serverlist; servrec ; servrec = servrec->next)
{
uint32 serv_type;
for (servrec = work->serverlist; servrec ; servrec = servrec->next) {
uint32 serv_type;
/* We have already written our names here. */
if(is_myname(servrec->serv.name))
continue;
/* We have already written our names here. */
if(is_myname(servrec->serv.name))
continue;
serv_type = write_this_server_name(subrec, work, servrec);
if(serv_type)
{
/* Output server details, plus what workgroup they're in. */
write_browse_list_entry(fp, servrec->serv.name, serv_type,
servrec->serv.comment, work->work_group);
}
}
}
}
serv_type = write_this_server_name(subrec, work, servrec);
if(serv_type) {
/* Output server details, plus what workgroup they're in. */
write_browse_list_entry(fp, servrec->serv.name, serv_type,
servrec->serv.comment, work->work_group);
}
}
}
}
x_fclose(fp);
unlink(fname);
chmod(fnamenew,0644);
rename(fnamenew,fname);
DEBUG(3,("write_browse_list: Wrote browse list into file %s\n",fname));
x_fclose(fp);
unlink(fname);
chmod(fnamenew,0644);
rename(fnamenew,fname);
DEBUG(3,("write_browse_list: Wrote browse list into file %s\n",fname));
}

View File

@ -63,28 +63,27 @@ static void add_subnet(struct subnet_record *subrec)
* ************************************************************************** **
*/
static int namelist_entry_compare( ubi_trItemPtr Item, ubi_trNodePtr Node )
{
struct name_record *NR = (struct name_record *)Node;
{
struct name_record *NR = (struct name_record *)Node;
if( DEBUGLVL( 10 ) )
{
struct nmb_name *Iname = (struct nmb_name *)Item;
if( DEBUGLVL( 10 ) ) {
struct nmb_name *Iname = (struct nmb_name *)Item;
Debug1( "nmbd_subnetdb:namelist_entry_compare()\n" );
Debug1( "%d == memcmp( \"%s\", \"%s\", %d )\n",
memcmp( Item, &(NR->name), sizeof(struct nmb_name) ),
nmb_namestr(Iname), nmb_namestr(&NR->name), (int)sizeof(struct nmb_name) );
}
return( memcmp( Item, &(NR->name), sizeof(struct nmb_name) ) );
} /* namelist_entry_compare */
Debug1( "nmbd_subnetdb:namelist_entry_compare()\n" );
Debug1( "%d == memcmp( \"%s\", \"%s\", %d )\n",
memcmp( Item, &(NR->name), sizeof(struct nmb_name) ),
nmb_namestr(Iname), nmb_namestr(&NR->name), (int)sizeof(struct nmb_name) );
}
return( memcmp( Item, &(NR->name), sizeof(struct nmb_name) ) );
}
/****************************************************************************
stop listening on a subnet
we don't free the record as we don't have proper reference counting for it
yet and it may be in use by a response record
****************************************************************************/
void close_subnet(struct subnet_record *subrec)
{
DLIST_REMOVE(subnetlist, subrec);
@ -99,8 +98,6 @@ void close_subnet(struct subnet_record *subrec)
}
}
/****************************************************************************
Create a subnet entry.
****************************************************************************/
@ -109,102 +106,90 @@ static struct subnet_record *make_subnet(const char *name, enum subnet_type type
struct in_addr myip, struct in_addr bcast_ip,
struct in_addr mask_ip)
{
struct subnet_record *subrec = NULL;
int nmb_sock, dgram_sock;
struct subnet_record *subrec = NULL;
int nmb_sock, dgram_sock;
/* Check if we are creating a non broadcast subnet - if so don't create
sockets.
*/
/* Check if we are creating a non broadcast subnet - if so don't create
sockets. */
if(type != NORMAL_SUBNET)
{
nmb_sock = -1;
dgram_sock = -1;
}
else
{
/*
* Attempt to open the sockets on port 137/138 for this interface
* and bind them.
* Fail the subnet creation if this fails.
*/
if(type != NORMAL_SUBNET) {
nmb_sock = -1;
dgram_sock = -1;
} else {
/*
* Attempt to open the sockets on port 137/138 for this interface
* and bind them.
* Fail the subnet creation if this fails.
*/
if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,0, myip.s_addr,True)) == -1)
{
if( DEBUGLVL( 0 ) )
{
Debug1( "nmbd_subnetdb:make_subnet()\n" );
Debug1( " Failed to open nmb socket on interface %s ", inet_ntoa(myip) );
Debug1( "for port %d. ", global_nmb_port );
Debug1( "Error was %s\n", strerror(errno) );
}
return NULL;
}
if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,0, myip.s_addr,True)) == -1) {
if( DEBUGLVL( 0 ) ) {
Debug1( "nmbd_subnetdb:make_subnet()\n" );
Debug1( " Failed to open nmb socket on interface %s ", inet_ntoa(myip) );
Debug1( "for port %d. ", global_nmb_port );
Debug1( "Error was %s\n", strerror(errno) );
}
return NULL;
}
if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, myip.s_addr,True)) == -1)
{
if( DEBUGLVL( 0 ) )
{
Debug1( "nmbd_subnetdb:make_subnet()\n" );
Debug1( " Failed to open dgram socket on interface %s ", inet_ntoa(myip) );
Debug1( "for port %d. ", DGRAM_PORT );
Debug1( "Error was %s\n", strerror(errno) );
}
return NULL;
}
if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, myip.s_addr,True)) == -1) {
if( DEBUGLVL( 0 ) ) {
Debug1( "nmbd_subnetdb:make_subnet()\n" );
Debug1( " Failed to open dgram socket on interface %s ", inet_ntoa(myip) );
Debug1( "for port %d. ", DGRAM_PORT );
Debug1( "Error was %s\n", strerror(errno) );
}
return NULL;
}
/* Make sure we can broadcast from these sockets. */
set_socket_options(nmb_sock,"SO_BROADCAST");
set_socket_options(dgram_sock,"SO_BROADCAST");
/* Make sure we can broadcast from these sockets. */
set_socket_options(nmb_sock,"SO_BROADCAST");
set_socket_options(dgram_sock,"SO_BROADCAST");
}
}
subrec = (struct subnet_record *)malloc(sizeof(*subrec));
subrec = (struct subnet_record *)malloc(sizeof(*subrec));
if (!subrec) {
DEBUG(0,("make_subnet: malloc fail !\n"));
close(nmb_sock);
close(dgram_sock);
return(NULL);
}
if (!subrec)
{
DEBUG(0,("make_subnet: malloc fail !\n"));
close(nmb_sock);
close(dgram_sock);
return(NULL);
}
memset( (char *)subrec, '\0', sizeof(*subrec) );
(void)ubi_trInitTree( subrec->namelist,
namelist_entry_compare,
ubi_trOVERWRITE );
memset( (char *)subrec, '\0', sizeof(*subrec) );
(void)ubi_trInitTree( subrec->namelist,
namelist_entry_compare,
ubi_trOVERWRITE );
if((subrec->subnet_name = strdup(name)) == NULL)
{
DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
close(nmb_sock);
close(dgram_sock);
ZERO_STRUCTP(subrec);
SAFE_FREE(subrec);
return(NULL);
}
if((subrec->subnet_name = strdup(name)) == NULL) {
DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
close(nmb_sock);
close(dgram_sock);
ZERO_STRUCTP(subrec);
SAFE_FREE(subrec);
return(NULL);
}
DEBUG(2, ("making subnet name:%s ", name ));
DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip)));
DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip)));
DEBUG(2, ("making subnet name:%s ", name ));
DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip)));
DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip)));
subrec->namelist_changed = False;
subrec->work_changed = False;
subrec->namelist_changed = False;
subrec->work_changed = False;
subrec->bcast_ip = bcast_ip;
subrec->mask_ip = mask_ip;
subrec->myip = myip;
subrec->type = type;
subrec->nmb_sock = nmb_sock;
subrec->dgram_sock = dgram_sock;
subrec->bcast_ip = bcast_ip;
subrec->mask_ip = mask_ip;
subrec->myip = myip;
subrec->type = type;
subrec->nmb_sock = nmb_sock;
subrec->dgram_sock = dgram_sock;
return subrec;
return subrec;
}
/****************************************************************************
Create a normal subnet
**************************************************************************/
struct subnet_record *make_normal_subnet(struct interface *iface)
{
struct subnet_record *subrec;
@ -217,100 +202,99 @@ struct subnet_record *make_normal_subnet(struct interface *iface)
return subrec;
}
/****************************************************************************
Create subnet entries.
**************************************************************************/
BOOL create_subnets(void)
{
int num_interfaces = iface_count();
int i;
struct in_addr unicast_ip, ipzero;
extern struct in_addr loopback_ip;
int num_interfaces = iface_count();
int i;
struct in_addr unicast_ip, ipzero;
extern struct in_addr loopback_ip;
if(num_interfaces == 0) {
DEBUG(0,("create_subnets: No local interfaces !\n"));
DEBUG(0,("create_subnets: Waiting for an interface to appear ...\n"));
while (iface_count() == 0) {
sleep(5);
load_interfaces();
}
}
if(num_interfaces == 0) {
DEBUG(0,("create_subnets: No local interfaces !\n"));
DEBUG(0,("create_subnets: Waiting for an interface to appear ...\n"));
while (iface_count() == 0) {
sleep(5);
load_interfaces();
}
}
num_interfaces = iface_count();
num_interfaces = iface_count();
/*
* Create subnets from all the local interfaces and thread them onto
* the linked list.
*/
/*
* Create subnets from all the local interfaces and thread them onto
* the linked list.
*/
for (i = 0 ; i < num_interfaces; i++)
{
struct interface *iface = get_interface(i);
for (i = 0 ; i < num_interfaces; i++) {
struct interface *iface = get_interface(i);
/*
* We don't want to add a loopback interface, in case
* someone has added 127.0.0.1 for smbd, nmbd needs to
* ignore it here. JRA.
*/
/*
* We don't want to add a loopback interface, in case
* someone has added 127.0.0.1 for smbd, nmbd needs to
* ignore it here. JRA.
*/
if (ip_equal(iface->ip, loopback_ip)) {
DEBUG(2,("create_subnets: Ignoring loopback interface.\n" ));
continue;
}
if (ip_equal(iface->ip, loopback_ip)) {
DEBUG(2,("create_subnets: Ignoring loopback interface.\n" ));
continue;
}
if (!make_normal_subnet(iface)) return False;
}
if (!make_normal_subnet(iface))
return False;
}
if (lp_we_are_a_wins_server()) {
/* Pick the first interface ip address as the WINS server ip. */
unicast_ip = *iface_n_ip(0);
} else {
/* note that we do not set the wins server IP here. We just
set it at zero and let the wins registration code cope
with getting the IPs right for each packet */
zero_ip(&unicast_ip);
}
if (lp_we_are_a_wins_server()) {
/* Pick the first interface ip address as the WINS server ip. */
unicast_ip = *iface_n_ip(0);
} else {
/* note that we do not set the wins server IP here. We just
set it at zero and let the wins registration code cope
with getting the IPs right for each packet */
zero_ip(&unicast_ip);
}
/*
* Create the unicast and remote broadcast subnets.
* Don't put these onto the linked list.
* The ip address of the unicast subnet is set to be
* the WINS server address, if it exists, or ipzero if not.
*/
/*
* Create the unicast and remote broadcast subnets.
* Don't put these onto the linked list.
* The ip address of the unicast subnet is set to be
* the WINS server address, if it exists, or ipzero if not.
*/
unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET,
unicast_ip, unicast_ip, unicast_ip);
unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET,
unicast_ip, unicast_ip, unicast_ip);
zero_ip(&ipzero);
zero_ip(&ipzero);
remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
REMOTE_BROADCAST_SUBNET,
ipzero, ipzero, ipzero);
remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
REMOTE_BROADCAST_SUBNET,
ipzero, ipzero, ipzero);
if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
return False;
if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
return False;
/*
* If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
* the linked list.
*/
/*
* If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
* the linked list.
*/
if (lp_we_are_a_wins_server())
{
if( (wins_server_subnet = make_subnet( "WINS_SERVER_SUBNET",
WINS_SERVER_SUBNET,
ipzero, ipzero, ipzero )) == NULL )
return False;
}
if (lp_we_are_a_wins_server()) {
if( (wins_server_subnet = make_subnet( "WINS_SERVER_SUBNET",
WINS_SERVER_SUBNET,
ipzero, ipzero, ipzero )) == NULL )
return False;
}
return True;
return True;
}
/*******************************************************************
Function to tell us if we can use the unicast subnet.
******************************************************************/
BOOL we_are_a_wins_client(void)
{
if (wins_srv_count() > 0) {
@ -326,12 +310,12 @@ Access function used by NEXT_SUBNET_INCLUDING_UNICAST
struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec)
{
if(subrec == unicast_subnet)
return NULL;
else if((subrec->next == NULL) && we_are_a_wins_client())
return unicast_subnet;
else
return subrec->next;
if(subrec == unicast_subnet)
return NULL;
else if((subrec->next == NULL) && we_are_a_wins_client())
return unicast_subnet;
else
return subrec->next;
}
/*******************************************************************
@ -343,19 +327,18 @@ struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec
struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec)
{
if(subrec == unicast_subnet)
{
if(wins_server_subnet)
return wins_server_subnet;
else
return NULL;
}
if(subrec == unicast_subnet) {
if(wins_server_subnet)
return wins_server_subnet;
else
return NULL;
}
if(wins_server_subnet && subrec == wins_server_subnet)
return NULL;
if(wins_server_subnet && subrec == wins_server_subnet)
return NULL;
if((subrec->next == NULL) && we_are_a_wins_client())
return unicast_subnet;
else
return subrec->next;
if((subrec->next == NULL) && we_are_a_wins_client())
return unicast_subnet;
else
return subrec->next;
}

View File

@ -47,6 +47,7 @@ static XFILE *fp;
This is the NetServerEnum callback.
Note sname and comment are in UNIX codepage format.
******************************************************************/
static void callback(const char *sname, uint32 stype,
const char *comment, void *state)
{
@ -58,6 +59,7 @@ static void callback(const char *sname, uint32 stype,
Log in on the remote server's SMB port to their IPC$ service,
do a NetServerEnum and record the results in fname
******************************************************************/
static void sync_child(char *name, int nm_type,
char *workgroup,
struct in_addr ip, BOOL local, BOOL servers,
@ -78,10 +80,9 @@ static void sync_child(char *name, int nm_type,
}
make_nmb_name(&calling, local_machine, 0x0);
make_nmb_name(&called , name , nm_type);
make_nmb_name(&called , name, nm_type);
if (!cli_session_request(&cli, &calling, &called))
{
if (!cli_session_request(&cli, &calling, &called)) {
cli_shutdown(&cli);
return;
}
@ -120,12 +121,12 @@ static void sync_child(char *name, int nm_type,
cli_shutdown(&cli);
}
/*******************************************************************
initialise a browse sync with another browse server. Log in on the
remote server's SMB port to their IPC$ service, do a NetServerEnum
and record the results
******************************************************************/
void sync_browse_lists(struct work_record *work,
char *name, int nm_type,
struct in_addr ip, BOOL local, BOOL servers)
@ -182,8 +183,9 @@ done:
}
/**********************************************************************
handle one line from a completed sync file
Handle one line from a completed sync file.
**********************************************************************/
static void complete_one(struct sync_record *s,
char *sname, uint32 stype, char *comment)
{
@ -235,10 +237,10 @@ static void complete_one(struct sync_record *s,
create_server_on_workgroup(work, sname,stype, lp_max_ttl(), comment);
}
/**********************************************************************
read the completed sync info
**********************************************************************/
Read the completed sync info.
**********************************************************************/
static void complete_sync(struct sync_record *s)
{
XFILE *f;
@ -251,11 +253,13 @@ static void complete_sync(struct sync_record *s)
f = x_fopen(s->fname,O_RDONLY, 0);
if (!f) return;
if (!f)
return;
while (!x_feof(f)) {
if (!fgets_slash(line,sizeof(pstring),f)) continue;
if (!fgets_slash(line,sizeof(pstring),f))
continue;
ptr = line;
@ -281,8 +285,9 @@ static void complete_sync(struct sync_record *s)
}
/**********************************************************************
check for completion of any of the child processes
**********************************************************************/
Check for completion of any of the child processes.
**********************************************************************/
void sync_check_completion(void)
{
struct sync_record *s, *next;

View File

@ -30,92 +30,85 @@ static void wins_proxy_name_query_request_success( struct subnet_record *subrec,
struct userdata_struct *userdata,
struct nmb_name *nmbname, struct in_addr ip, struct res_rec *rrec)
{
struct packet_struct *original_packet;
struct subnet_record *orig_broadcast_subnet;
struct name_record *namerec;
uint16 nb_flags;
int num_ips;
int i;
int ttl = 3600; /* By default one hour in the cache. */
struct in_addr *iplist;
nstring name;
struct packet_struct *original_packet;
struct subnet_record *orig_broadcast_subnet;
struct name_record *namerec;
uint16 nb_flags;
int num_ips;
int i;
int ttl = 3600; /* By default one hour in the cache. */
struct in_addr *iplist;
/* Extract the original packet and the original broadcast subnet from
the userdata. */
/* Extract the original packet and the original broadcast subnet from
the userdata. */
memcpy( (char *)&orig_broadcast_subnet, userdata->data, sizeof(struct subnet_record *) );
memcpy( (char *)&original_packet, &userdata->data[sizeof(struct subnet_record *)],
sizeof(struct packet_struct *) );
memcpy( (char *)&orig_broadcast_subnet, userdata->data, sizeof(struct subnet_record *) );
memcpy( (char *)&original_packet, &userdata->data[sizeof(struct subnet_record *)],
sizeof(struct packet_struct *) );
nb_flags = get_nb_flags( rrec->rdata );
nb_flags = get_nb_flags( rrec->rdata );
num_ips = rrec->rdlength / 6;
if(num_ips == 0)
{
DEBUG(0,("wins_proxy_name_query_request_success: Invalid number of IP records (0) \
num_ips = rrec->rdlength / 6;
if(num_ips == 0) {
DEBUG(0,("wins_proxy_name_query_request_success: Invalid number of IP records (0) \
returned for name %s.\n", nmb_namestr(nmbname) ));
return;
}
return;
}
if(num_ips == 1)
iplist = &ip;
else
{
if((iplist = (struct in_addr *)malloc( num_ips * sizeof(struct in_addr) )) == NULL)
{
DEBUG(0,("wins_proxy_name_query_request_success: malloc fail !\n"));
return;
}
if(num_ips == 1) {
iplist = &ip;
} else {
if((iplist = (struct in_addr *)malloc( num_ips * sizeof(struct in_addr) )) == NULL) {
DEBUG(0,("wins_proxy_name_query_request_success: malloc fail !\n"));
return;
}
for(i = 0; i < num_ips; i++)
putip( (char *)&iplist[i], (char *)&rrec->rdata[ (i*6) + 2]);
}
for(i = 0; i < num_ips; i++)
putip( (char *)&iplist[i], (char *)&rrec->rdata[ (i*6) + 2]);
}
/* Add the queried name to the original subnet as a WINS_PROXY_NAME. */
/* Add the queried name to the original subnet as a WINS_PROXY_NAME. */
if(rrec == PERMANENT_TTL)
ttl = lp_max_ttl();
if(rrec == PERMANENT_TTL)
ttl = lp_max_ttl();
namerec = add_name_to_subnet( orig_broadcast_subnet, nmbname->name,
nmbname->name_type, nb_flags, ttl,
WINS_PROXY_NAME, num_ips, iplist );
pull_ascii_nstring(name, nmbname->name);
namerec = add_name_to_subnet( orig_broadcast_subnet, name,
nmbname->name_type, nb_flags, ttl,
WINS_PROXY_NAME, num_ips, iplist );
if(iplist != &ip)
SAFE_FREE(iplist);
if(iplist != &ip)
SAFE_FREE(iplist);
/*
* Check that none of the IP addresses we are returning is on the
* same broadcast subnet as the original requesting packet. If it
* is then don't reply (although we still need to add the name
* to the cache) as the actual machine will be replying also
* and we don't want two replies to a broadcast query.
*/
/*
* Check that none of the IP addresses we are returning is on the
* same broadcast subnet as the original requesting packet. If it
* is then don't reply (although we still need to add the name
* to the cache) as the actual machine will be replying also
* and we don't want two replies to a broadcast query.
*/
if(namerec && original_packet->packet.nmb.header.nm_flags.bcast)
{
for( i = 0; i < namerec->data.num_ips; i++)
{
if( same_net( namerec->data.ip[i],
orig_broadcast_subnet->myip,
orig_broadcast_subnet->mask_ip ) )
{
DEBUG( 5, ( "wins_proxy_name_query_request_success: name %s is a WINS \
if(namerec && original_packet->packet.nmb.header.nm_flags.bcast) {
for( i = 0; i < namerec->data.num_ips; i++) {
if( same_net( namerec->data.ip[i], orig_broadcast_subnet->myip,
orig_broadcast_subnet->mask_ip ) ) {
DEBUG( 5, ( "wins_proxy_name_query_request_success: name %s is a WINS \
proxy name and is also on the same subnet (%s) as the requestor. \
Not replying.\n",
nmb_namestr(&namerec->name),
orig_broadcast_subnet->subnet_name ) );
return;
}
}
}
Not replying.\n", nmb_namestr(&namerec->name), orig_broadcast_subnet->subnet_name ) );
return;
}
}
}
/* Finally reply to the original name query. */
reply_netbios_packet(original_packet, /* Packet to reply to. */
0, /* Result code. */
NMB_QUERY, /* nmbd type code. */
NMB_NAME_QUERY_OPCODE, /* opcode. */
ttl, /* ttl. */
rrec->rdata, /* data to send. */
rrec->rdlength); /* data length. */
/* Finally reply to the original name query. */
reply_netbios_packet(original_packet, /* Packet to reply to. */
0, /* Result code. */
NMB_QUERY, /* nmbd type code. */
NMB_NAME_QUERY_OPCODE, /* opcode. */
ttl, /* ttl. */
rrec->rdata, /* data to send. */
rrec->rdlength); /* data length. */
}
/****************************************************************************
@ -126,7 +119,7 @@ static void wins_proxy_name_query_request_fail(struct subnet_record *subrec,
struct response_record *rrec,
struct nmb_name *question_name, int fail_code)
{
DEBUG(4,("wins_proxy_name_query_request_fail: WINS server returned error code %d for lookup \
DEBUG(4,("wins_proxy_name_query_request_fail: WINS server returned error code %d for lookup \
of name %s.\n", fail_code, nmb_namestr(question_name) ));
}
@ -137,38 +130,35 @@ proxy query returns.
static struct userdata_struct *wins_proxy_userdata_copy_fn(struct userdata_struct *userdata)
{
struct packet_struct *p, *copy_of_p;
struct userdata_struct *new_userdata =
(struct userdata_struct *)malloc( userdata->userdata_len );
struct packet_struct *p, *copy_of_p;
struct userdata_struct *new_userdata = (struct userdata_struct *)malloc( userdata->userdata_len );
if(new_userdata == NULL)
return NULL;
if(new_userdata == NULL)
return NULL;
new_userdata->copy_fn = userdata->copy_fn;
new_userdata->free_fn = userdata->free_fn;
new_userdata->userdata_len = userdata->userdata_len;
new_userdata->copy_fn = userdata->copy_fn;
new_userdata->free_fn = userdata->free_fn;
new_userdata->userdata_len = userdata->userdata_len;
/* Copy the subnet_record pointer. */
memcpy( new_userdata->data, userdata->data, sizeof(struct subnet_record *) );
/* Copy the subnet_record pointer. */
memcpy( new_userdata->data, userdata->data, sizeof(struct subnet_record *) );
/* Extract the pointer to the packet struct */
memcpy((char *)&p, &userdata->data[sizeof(struct subnet_record *)],
sizeof(struct packet_struct *) );
/* Extract the pointer to the packet struct */
memcpy((char *)&p, &userdata->data[sizeof(struct subnet_record *)], sizeof(struct packet_struct *) );
/* Do a deep copy of the packet. */
if((copy_of_p = copy_packet(p)) == NULL)
{
SAFE_FREE(new_userdata);
return NULL;
}
/* Do a deep copy of the packet. */
if((copy_of_p = copy_packet(p)) == NULL) {
SAFE_FREE(new_userdata);
return NULL;
}
/* Lock the copy. */
copy_of_p->locked = True;
/* Lock the copy. */
copy_of_p->locked = True;
memcpy( &new_userdata->data[sizeof(struct subnet_record *)], (char *)&copy_of_p,
sizeof(struct packet_struct *) );
memcpy( &new_userdata->data[sizeof(struct subnet_record *)], (char *)&copy_of_p,
sizeof(struct packet_struct *) );
return new_userdata;
return new_userdata;
}
/****************************************************************************
@ -178,18 +168,18 @@ proxy query returned.
static void wins_proxy_userdata_free_fn(struct userdata_struct *userdata)
{
struct packet_struct *p;
struct packet_struct *p;
/* Extract the pointer to the packet struct */
memcpy((char *)&p, &userdata->data[sizeof(struct subnet_record *)],
sizeof(struct packet_struct *));
/* Extract the pointer to the packet struct */
memcpy((char *)&p, &userdata->data[sizeof(struct subnet_record *)],
sizeof(struct packet_struct *));
/* Unlock the packet. */
p->locked = False;
/* Unlock the packet. */
p->locked = False;
free_packet(p);
ZERO_STRUCTP(userdata);
SAFE_FREE(userdata);
free_packet(p);
ZERO_STRUCTP(userdata);
SAFE_FREE(userdata);
}
/****************************************************************************
@ -200,22 +190,24 @@ void make_wins_proxy_name_query_request( struct subnet_record *subrec,
struct packet_struct *incoming_packet,
struct nmb_name *question_name)
{
long *ud[(sizeof(struct userdata_struct) + sizeof(struct subrec *) +
sizeof(struct packet_struct *))/sizeof(long *) + 1];
struct userdata_struct *userdata = (struct userdata_struct *)ud;
long *ud[(sizeof(struct userdata_struct) + sizeof(struct subrec *) +
sizeof(struct packet_struct *))/sizeof(long *) + 1];
struct userdata_struct *userdata = (struct userdata_struct *)ud;
nstring qname;
memset(ud, '\0', sizeof(ud));
memset(ud, '\0', sizeof(ud));
userdata->copy_fn = wins_proxy_userdata_copy_fn;
userdata->free_fn = wins_proxy_userdata_free_fn;
userdata->userdata_len = sizeof(ud);
memcpy( userdata->data, (char *)&subrec, sizeof(struct subnet_record *));
memcpy( &userdata->data[sizeof(struct subnet_record *)], (char *)&incoming_packet,
sizeof(struct packet_struct *));
userdata->copy_fn = wins_proxy_userdata_copy_fn;
userdata->free_fn = wins_proxy_userdata_free_fn;
userdata->userdata_len = sizeof(ud);
memcpy( userdata->data, (char *)&subrec, sizeof(struct subnet_record *));
memcpy( &userdata->data[sizeof(struct subnet_record *)], (char *)&incoming_packet,
sizeof(struct packet_struct *));
/* Now use the unicast subnet to query the name with the WINS server. */
query_name( unicast_subnet, question_name->name, question_name->name_type,
wins_proxy_name_query_request_success,
wins_proxy_name_query_request_fail,
userdata);
/* Now use the unicast subnet to query the name with the WINS server. */
pull_ascii_nstring(qname, question_name->name);
query_name( unicast_subnet, qname, question_name->name_type,
wins_proxy_name_query_request_success,
wins_proxy_name_query_request_fail,
userdata);
}

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,7 @@ int workgroup_count = 0; /* unique index key: one for each workgroup */
/****************************************************************************
Add a workgroup into the list.
**************************************************************************/
**************************************************************************/
static void add_workgroup(struct subnet_record *subrec, struct work_record *work)
{
@ -42,164 +42,153 @@ static void add_workgroup(struct subnet_record *subrec, struct work_record *work
/****************************************************************************
Create an empty workgroup.
**************************************************************************/
**************************************************************************/
static struct work_record *create_workgroup(const char *name, int ttl)
{
struct work_record *work;
struct subnet_record *subrec;
int t = -1;
struct work_record *work;
struct subnet_record *subrec;
int t = -1;
if((work = (struct work_record *)malloc(sizeof(*work))) == NULL)
{
DEBUG(0,("create_workgroup: malloc fail !\n"));
return NULL;
}
memset((char *)work, '\0', sizeof(*work));
if((work = (struct work_record *)malloc(sizeof(*work))) == NULL) {
DEBUG(0,("create_workgroup: malloc fail !\n"));
return NULL;
}
memset((char *)work, '\0', sizeof(*work));
fstrcpy(work->work_group,name);
work->serverlist = NULL;
fstrcpy(work->work_group,name);
work->serverlist = NULL;
work->RunningElection = False;
work->ElectionCount = 0;
work->announce_interval = 0;
work->needelection = False;
work->needannounce = True;
work->lastannounce_time = time(NULL);
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
work->dom_state = DOMAIN_NONE;
work->log_state = LOGON_NONE;
work->RunningElection = False;
work->ElectionCount = 0;
work->announce_interval = 0;
work->needelection = False;
work->needannounce = True;
work->lastannounce_time = time(NULL);
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
work->dom_state = DOMAIN_NONE;
work->log_state = LOGON_NONE;
work->death_time = (ttl != PERMANENT_TTL) ? time(NULL)+(ttl*3) : PERMANENT_TTL;
work->death_time = (ttl != PERMANENT_TTL) ? time(NULL)+(ttl*3) : PERMANENT_TTL;
/* Make sure all token representations of workgroups are unique. */
/* Make sure all token representations of workgroups are unique. */
for (subrec = FIRST_SUBNET; subrec && (t == -1);
subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
{
struct work_record *w;
for (w = subrec->workgrouplist; w && t == -1; w = w->next)
{
if (strequal(w->work_group, work->work_group))
t = w->token;
}
}
for (subrec = FIRST_SUBNET; subrec && (t == -1); subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
struct work_record *w;
for (w = subrec->workgrouplist; w && t == -1; w = w->next) {
if (strequal(w->work_group, work->work_group))
t = w->token;
}
}
if (t == -1)
work->token = ++workgroup_count;
else
work->token = t;
if (t == -1)
work->token = ++workgroup_count;
else
work->token = t;
/* No known local master browser as yet. */
*work->local_master_browser_name = '\0';
/* No known local master browser as yet. */
*work->local_master_browser_name = '\0';
/* No known domain master browser as yet. */
*work->dmb_name.name = '\0';
zero_ip(&work->dmb_addr);
/* No known domain master browser as yet. */
*work->dmb_name.name = '\0';
zero_ip(&work->dmb_addr);
/* WfWg uses 01040b01 */
/* Win95 uses 01041501 */
/* NTAS uses ???????? */
work->ElectionCriterion = (MAINTAIN_LIST)|(BROWSER_ELECTION_VERSION<<8);
work->ElectionCriterion |= (lp_os_level() << 24);
if (lp_domain_master())
work->ElectionCriterion |= 0x80;
/* WfWg uses 01040b01 */
/* Win95 uses 01041501 */
/* NTAS uses ???????? */
work->ElectionCriterion = (MAINTAIN_LIST)|(BROWSER_ELECTION_VERSION<<8);
work->ElectionCriterion |= (lp_os_level() << 24);
if (lp_domain_master())
work->ElectionCriterion |= 0x80;
return work;
return work;
}
/*******************************************************************
Remove a workgroup.
******************************************************************/
******************************************************************/
static struct work_record *remove_workgroup_from_subnet(struct subnet_record *subrec,
struct work_record *work)
{
struct work_record *ret_work = NULL;
struct work_record *ret_work = NULL;
DEBUG(3,("remove_workgroup: Removing workgroup %s\n", work->work_group));
DEBUG(3,("remove_workgroup: Removing workgroup %s\n", work->work_group));
ret_work = work->next;
ret_work = work->next;
remove_all_servers(work);
remove_all_servers(work);
if (!work->serverlist)
{
if (work->prev)
work->prev->next = work->next;
if (work->next)
work->next->prev = work->prev;
if (!work->serverlist) {
if (work->prev)
work->prev->next = work->next;
if (work->next)
work->next->prev = work->prev;
if (subrec->workgrouplist == work)
subrec->workgrouplist = work->next;
if (subrec->workgrouplist == work)
subrec->workgrouplist = work->next;
ZERO_STRUCTP(work);
SAFE_FREE(work);
}
ZERO_STRUCTP(work);
SAFE_FREE(work);
}
subrec->work_changed = True;
subrec->work_changed = True;
return ret_work;
return ret_work;
}
/****************************************************************************
Find a workgroup in the workgroup list of a subnet.
**************************************************************************/
**************************************************************************/
struct work_record *find_workgroup_on_subnet(struct subnet_record *subrec,
const char *name)
{
struct work_record *ret;
struct work_record *ret;
DEBUG(4, ("find_workgroup_on_subnet: workgroup search for %s on subnet %s: ",
name, subrec->subnet_name));
DEBUG(4, ("find_workgroup_on_subnet: workgroup search for %s on subnet %s: ",
name, subrec->subnet_name));
for (ret = subrec->workgrouplist; ret; ret = ret->next)
{
if (!strcmp(ret->work_group,name))
{
DEBUGADD(4, ("found.\n"));
return(ret);
}
}
DEBUGADD(4, ("not found.\n"));
return NULL;
for (ret = subrec->workgrouplist; ret; ret = ret->next) {
if (strequal(ret->work_group,name)) {
DEBUGADD(4, ("found.\n"));
return(ret);
}
}
DEBUGADD(4, ("not found.\n"));
return NULL;
}
/****************************************************************************
Create a workgroup in the workgroup list of the subnet.
**************************************************************************/
**************************************************************************/
struct work_record *create_workgroup_on_subnet(struct subnet_record *subrec,
const char *name, int ttl)
{
struct work_record *work = NULL;
struct work_record *work = NULL;
DEBUG(4,("create_workgroup_on_subnet: creating group %s on subnet %s\n",
name, subrec->subnet_name));
DEBUG(4,("create_workgroup_on_subnet: creating group %s on subnet %s\n",
name, subrec->subnet_name));
if ((work = create_workgroup(name, ttl)))
{
add_workgroup(subrec, work);
if ((work = create_workgroup(name, ttl))) {
add_workgroup(subrec, work);
subrec->work_changed = True;
return(work);
}
subrec->work_changed = True;
return(work);
}
return NULL;
return NULL;
}
/****************************************************************************
Update a workgroup ttl.
**************************************************************************/
**************************************************************************/
void update_workgroup_ttl(struct work_record *work, int ttl)
{
if(work->death_time != PERMANENT_TTL)
work->death_time = time(NULL)+(ttl*3);
work->subnet->work_changed = True;
if(work->death_time != PERMANENT_TTL)
work->death_time = time(NULL)+(ttl*3);
work->subnet->work_changed = True;
}
/****************************************************************************
@ -210,8 +199,8 @@ void update_workgroup_ttl(struct work_record *work, int ttl)
static void fail_register(struct subnet_record *subrec, struct response_record *rrec,
struct nmb_name *nmbname)
{
DEBUG(0,("fail_register: Failed to register name %s on subnet %s.\n",
nmb_namestr(nmbname), subrec->subnet_name));
DEBUG(0,("fail_register: Failed to register name %s on subnet %s.\n",
nmb_namestr(nmbname), subrec->subnet_name));
}
/****************************************************************************
@ -220,50 +209,38 @@ static void fail_register(struct subnet_record *subrec, struct response_record *
void initiate_myworkgroup_startup(struct subnet_record *subrec, struct work_record *work)
{
int i;
int i;
if(!strequal(lp_workgroup(), work->work_group))
return;
if(!strequal(lp_workgroup(), work->work_group))
return;
/* If this is a broadcast subnet then start elections on it
if we are so configured. */
/* If this is a broadcast subnet then start elections on it if we are so configured. */
if ((subrec != unicast_subnet) && (subrec != remote_broadcast_subnet) &&
(subrec != wins_server_subnet) && lp_preferred_master() &&
lp_local_master())
{
DEBUG(3, ("initiate_myworkgroup_startup: preferred master startup for \
if ((subrec != unicast_subnet) && (subrec != remote_broadcast_subnet) &&
(subrec != wins_server_subnet) && lp_preferred_master() && lp_local_master()) {
DEBUG(3, ("initiate_myworkgroup_startup: preferred master startup for \
workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
work->needelection = True;
work->ElectionCriterion |= (1<<3);
}
work->needelection = True;
work->ElectionCriterion |= (1<<3);
}
/* Register the WORKGROUP<0> and WORKGROUP<1e> names on the network. */
/* Register the WORKGROUP<0> and WORKGROUP<1e> names on the network. */
register_name(subrec,lp_workgroup(),0x0,samba_nb_type|NB_GROUP,
NULL,
fail_register,NULL);
register_name(subrec,lp_workgroup(),0x1e,samba_nb_type|NB_GROUP,
NULL,
fail_register,NULL);
for( i = 0; my_netbios_names(i); i++)
{
const char *name = my_netbios_names(i);
int stype = lp_default_server_announce() | (lp_local_master() ?
SV_TYPE_POTENTIAL_BROWSER : 0 );
register_name(subrec,lp_workgroup(),0x0,samba_nb_type|NB_GROUP, NULL, fail_register,NULL);
register_name(subrec,lp_workgroup(),0x1e,samba_nb_type|NB_GROUP, NULL, fail_register,NULL);
for( i = 0; my_netbios_names(i); i++) {
const char *name = my_netbios_names(i);
int stype = lp_default_server_announce() | (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0 );
if(!strequal(global_myname(), name))
stype &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_POTENTIAL_BROWSER|
SV_TYPE_DOMAIN_MASTER|SV_TYPE_DOMAIN_MEMBER);
if(!strequal(global_myname(), name))
stype &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_POTENTIAL_BROWSER|SV_TYPE_DOMAIN_MASTER|SV_TYPE_DOMAIN_MEMBER);
create_server_on_workgroup(work,name,stype|SV_TYPE_LOCAL_LIST_ONLY,
PERMANENT_TTL,
string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
DEBUG(3,("initiate_myworkgroup_startup: Added server name entry %s \
create_server_on_workgroup(work,name,stype|SV_TYPE_LOCAL_LIST_ONLY, PERMANENT_TTL,
string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH));
DEBUG(3,("initiate_myworkgroup_startup: Added server name entry %s \
on subnet %s\n", name, subrec->subnet_name));
}
}
}
/****************************************************************************
@ -272,43 +249,34 @@ on subnet %s\n", name, subrec->subnet_name));
void dump_workgroups(BOOL force_write)
{
struct subnet_record *subrec;
int debuglevel = force_write ? 0 : 4;
struct subnet_record *subrec;
int debuglevel = force_write ? 0 : 4;
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
{
if (subrec->workgrouplist)
{
struct work_record *work;
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
if (subrec->workgrouplist) {
struct work_record *work;
if( DEBUGLVL( debuglevel ) )
{
dbgtext( "dump_workgroups()\n " );
dbgtext( "dump workgroup on subnet %15s: ", subrec->subnet_name );
dbgtext( "netmask=%15s:\n", inet_ntoa(subrec->mask_ip) );
}
for (work = subrec->workgrouplist; work; work = work->next)
{
DEBUGADD( debuglevel, ( "\t%s(%d) current master browser = %s\n",
work->work_group,
work->token,
*work->local_master_browser_name
? work->local_master_browser_name : "UNKNOWN" ) );
if (work->serverlist)
{
struct server_record *servrec;
for (servrec = work->serverlist; servrec; servrec = servrec->next)
{
DEBUGADD( debuglevel, ( "\t\t%s %8x (%s)\n",
servrec->serv.name,
servrec->serv.type,
servrec->serv.comment ) );
}
}
}
}
}
if( DEBUGLVL( debuglevel ) ) {
dbgtext( "dump_workgroups()\n " );
dbgtext( "dump workgroup on subnet %15s: ", subrec->subnet_name );
dbgtext( "netmask=%15s:\n", inet_ntoa(subrec->mask_ip) );
}
for (work = subrec->workgrouplist; work; work = work->next) {
DEBUGADD( debuglevel, ( "\t%s(%d) current master browser = %s\n", work->work_group,
work->token, *work->local_master_browser_name ? work->local_master_browser_name : "UNKNOWN" ) );
if (work->serverlist) {
struct server_record *servrec;
for (servrec = work->serverlist; servrec; servrec = servrec->next) {
DEBUGADD( debuglevel, ( "\t\t%s %8x (%s)\n",
servrec->serv.name,
servrec->serv.type,
servrec->serv.comment ) );
}
}
}
}
}
}
/****************************************************************************
@ -318,25 +286,22 @@ void dump_workgroups(BOOL force_write)
void expire_workgroups_and_servers(time_t t)
{
struct subnet_record *subrec;
struct subnet_record *subrec;
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
{
struct work_record *work;
struct work_record *nextwork;
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
struct work_record *work;
struct work_record *nextwork;
for (work = subrec->workgrouplist; work; work = nextwork)
{
nextwork = work->next;
expire_servers(work, t);
for (work = subrec->workgrouplist; work; work = nextwork) {
nextwork = work->next;
expire_servers(work, t);
if ((work->serverlist == NULL) && (work->death_time != PERMANENT_TTL) &&
((t == -1) || (work->death_time < t)))
{
DEBUG(3,("expire_workgroups_and_servers: Removing timed out workgroup %s\n",
work->work_group));
remove_workgroup_from_subnet(subrec, work);
}
}
}
if ((work->serverlist == NULL) && (work->death_time != PERMANENT_TTL) &&
((t == -1) || (work->death_time < t))) {
DEBUG(3,("expire_workgroups_and_servers: Removing timed out workgroup %s\n",
work->work_group));
remove_workgroup_from_subnet(subrec, work);
}
}
}
}

View File

@ -563,6 +563,7 @@ static BOOL handle_debug_list( const char *pszParmValue, char **ptr );
static BOOL handle_workgroup( const char *pszParmValue, char **ptr );
static BOOL handle_netbios_aliases( const char *pszParmValue, char **ptr );
static BOOL handle_netbios_scope( const char *pszParmValue, char **ptr );
static BOOL handle_charset( const char *pszParmValue, char **ptr );
static BOOL handle_ldap_suffix ( const char *pszParmValue, char **ptr );
static BOOL handle_ldap_sub_suffix ( const char *pszParmValue, char **ptr );
@ -753,9 +754,9 @@ static const struct enum_list enum_map_to_guest[] = {
static struct parm_struct parm_table[] = {
{"Base Options", P_SEP, P_SEPARATOR},
{"dos charset", P_STRING, P_GLOBAL, &Globals.dos_charset, NULL, NULL, FLAG_ADVANCED},
{"unix charset", P_STRING, P_GLOBAL, &Globals.unix_charset, NULL, NULL, FLAG_ADVANCED},
{"display charset", P_STRING, P_GLOBAL, &Globals.display_charset, NULL, NULL, FLAG_ADVANCED},
{"dos charset", P_STRING, P_GLOBAL, &Globals.dos_charset, handle_charset, NULL, FLAG_ADVANCED},
{"unix charset", P_STRING, P_GLOBAL, &Globals.unix_charset, handle_charset, NULL, FLAG_ADVANCED},
{"display charset", P_STRING, P_GLOBAL, &Globals.display_charset, handle_charset, NULL, FLAG_ADVANCED},
{"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT},
{"path", P_STRING, P_LOCAL, &sDefault.szPath, NULL, NULL, FLAG_BASIC | FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT},
{"directory", P_STRING, P_LOCAL, &sDefault.szPath, NULL, NULL, FLAG_HIDE},
@ -2701,7 +2702,6 @@ static BOOL handle_netbios_name(const char *pszParmValue, char **ptr)
standard_sub_basic(current_user_info.smb_name, netbios_name,sizeof(netbios_name));
ret = set_global_myname(netbios_name);
string_set(&Globals.szNetbiosName,global_myname());
@ -2711,6 +2711,13 @@ static BOOL handle_netbios_name(const char *pszParmValue, char **ptr)
return ret;
}
static BOOL handle_charset(const char *pszParmValue, char **ptr)
{
string_set(ptr, pszParmValue);
init_iconv();
return True;
}
static BOOL handle_workgroup(const char *pszParmValue, char **ptr)
{
BOOL ret;