Unix SMB/CIFS implementation.
NBT netbios routines and daemon - version 2
- Copyright (C) Jeremy Allison 1994-2003
+ Copyright (C) Jeremy Allison 1994-2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ Converted to store WINS data in a tdb. Dec 2005. JRA.
*/
#include "includes.h"
#define WINS_LIST "wins.dat"
#define WINS_VERSION 1
+#define WINSDB_VERSION 1
+
+/****************************************************************************
+ We don't store the NetBIOS scope in the wins.tdb. We key off the (utf8) netbios
+ name (65 bytes with the last byte being the name type).
+*****************************************************************************/
+
+TDB_CONTEXT *wins_tdb;
+
+/****************************************************************************
+ Delete all the temporary name records on the in-memory linked list.
+*****************************************************************************/
+
+static void wins_delete_all_tmp_in_memory_records(void)
+{
+ struct name_record *nr = NULL;
+ struct name_record *nrnext = NULL;
+
+ /* Delete all temporary name records on the wins subnet linked list. */
+ for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
+ nrnext = nr->next;
+ DLIST_REMOVE(wins_server_subnet->namelist, nr);
+ SAFE_FREE(nr->data.ip);
+ SAFE_FREE(nr);
+ }
+}
+
+/****************************************************************************
+ Convert a wins.tdb record to a struct name_record. Add in our global_scope().
+*****************************************************************************/
+
+static struct name_record *wins_record_to_name_record(TDB_DATA key, TDB_DATA data)
+{
+ struct name_record *namerec = NULL;
+ uint16 nb_flags;
+ unsigned char nr_src;
+ uint32 death_time, refresh_time;
+ uint32 id_low, id_high;
+ uint32 saddr;
+ uint32 wins_flags;
+ uint32 num_ips;
+ size_t len;
+ int i;
+
+ if (data.dptr == NULL || data.dsize == 0) {
+ return NULL;
+ }
+
+ /* Min size is "wbddddddd" + 1 ip address (4). */
+ if (data.dsize < 2 + 1 + (7*4) + 4) {
+ return NULL;
+ }
+
+ len = tdb_unpack(data.dptr, data.dsize,
+ "wbddddddd",
+ &nb_flags,
+ &nr_src,
+ &death_time,
+ &refresh_time,
+ &id_low,
+ &id_high,
+ &saddr,
+ &wins_flags,
+ &num_ips );
+
+ namerec = SMB_MALLOC_P(struct name_record);
+ if (!namerec) {
+ return NULL;
+ }
+ ZERO_STRUCTP(namerec);
+
+ namerec->data.ip = SMB_MALLOC_ARRAY(struct in_addr, num_ips);
+ if (!namerec->data.ip) {
+ SAFE_FREE(namerec);
+ return NULL;
+ }
+
+ namerec->subnet = wins_server_subnet;
+ push_ascii_nstring(namerec->name.name, (const char *)key.dptr);
+ namerec->name.name_type = key.dptr[sizeof(unstring)];
+ /* Add the scope. */
+ push_ascii(namerec->name.scope, global_scope(), 64, STR_TERMINATE);
+
+ /* 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( namerec->name.name ); i < sizeof( namerec->name.name ); i++ ) {
+ namerec->name.name[i] = '\0';
+ }
+ for( i = strlen( namerec->name.scope ); i < sizeof( namerec->name.scope ); i++ ) {
+ namerec->name.scope[i] = '\0';
+ }
+
+ namerec->data.nb_flags = nb_flags;
+ namerec->data.source = (enum name_source)nr_src;
+ namerec->data.death_time = (time_t)death_time;
+ namerec->data.refresh_time = (time_t)refresh_time;
+ namerec->data.id = id_low;
+#if defined(HAVE_LONGLONG)
+ namerec->data.id |= ((SMB_BIG_UINT)id_high << 32);
+#endif
+ namerec->data.wins_ip.s_addr = saddr;
+ namerec->data.wins_flags = wins_flags,
+ namerec->data.num_ips = num_ips;
+
+ for (i = 0; i < num_ips; i++) {
+ namerec->data.ip[i].s_addr = IVAL(data.dptr, len + (i*4));
+ }
+
+ return namerec;
+}
+
+/****************************************************************************
+ Convert a struct name_record to a wins.tdb record. Ignore the scope.
+*****************************************************************************/
+
+static TDB_DATA name_record_to_wins_record(const struct name_record *namerec)
+{
+ TDB_DATA data;
+ size_t len = 0;
+ int i;
+ uint32 id_low = (namerec->data.id & 0xFFFFFFFF);
+#if defined(HAVE_LONGLONG)
+ uint32 id_high = (namerec->data.id >> 32) & 0xFFFFFFFF;
+#else
+ uint32 id_high = 0;
+#endif
+
+ ZERO_STRUCT(data);
+
+ len = (2 + 1 + (7*4)); /* "wbddddddd" */
+ len += (namerec->data.num_ips * 4);
+
+ data.dptr = (uint8 *)SMB_MALLOC(len);
+ if (!data.dptr) {
+ return data;
+ }
+ data.dsize = len;
+
+ len = tdb_pack(data.dptr, data.dsize, "wbddddddd",
+ namerec->data.nb_flags,
+ (unsigned char)namerec->data.source,
+ (uint32)namerec->data.death_time,
+ (uint32)namerec->data.refresh_time,
+ id_low,
+ id_high,
+ (uint32)namerec->data.wins_ip.s_addr,
+ (uint32)namerec->data.wins_flags,
+ (uint32)namerec->data.num_ips );
+
+ for (i = 0; i < namerec->data.num_ips; i++) {
+ SIVAL(data.dptr, len + (i*4), namerec->data.ip[i].s_addr);
+ }
+
+ return data;
+}
+
+/****************************************************************************
+ Create key. Key is UNIX codepage namestring (usually utf8 64 byte len) with 1 byte type.
+*****************************************************************************/
+
+static TDB_DATA name_to_key(const struct nmb_name *nmbname)
+{
+ static char keydata[sizeof(unstring) + 1];
+ TDB_DATA key;
+
+ memset(keydata, '\0', sizeof(keydata));
+
+ pull_ascii_nstring(keydata, sizeof(unstring), nmbname->name);
+ strupper_m(keydata);
+ keydata[sizeof(unstring)] = nmbname->name_type;
+ key.dptr = (uint8 *)keydata;
+ key.dsize = sizeof(keydata);
+
+ return key;
+}
+
+/****************************************************************************
+ Lookup a given name in the wins.tdb and create a temporary malloc'ed data struct
+ on the linked list. We will free this later in XXXX().
+*****************************************************************************/
+
+struct name_record *find_name_on_wins_subnet(const struct nmb_name *nmbname, bool self_only)
+{
+ TDB_DATA data, key;
+ struct name_record *nr = NULL;
+ struct name_record *namerec = NULL;
+
+ if (!wins_tdb) {
+ return NULL;
+ }
+
+ key = name_to_key(nmbname);
+ data = tdb_fetch(wins_tdb, key);
+
+ if (data.dsize == 0) {
+ return NULL;
+ }
+
+ namerec = wins_record_to_name_record(key, data);
+
+ /* done with the this */
+
+ SAFE_FREE( data.dptr );
+
+ if (!namerec) {
+ return NULL;
+ }
+
+ /* Self names only - these include permanent names. */
+ if( self_only && (namerec->data.source != SELF_NAME) && (namerec->data.source != PERMANENT_NAME) ) {
+ DEBUG( 9, ( "find_name_on_wins_subnet: self name %s NOT FOUND\n", nmb_namestr(nmbname) ) );
+ SAFE_FREE(namerec->data.ip);
+ SAFE_FREE(namerec);
+ return NULL;
+ }
+
+ /* Search for this name record on the list. Replace it if found. */
+
+ for( nr = wins_server_subnet->namelist; nr; nr = nr->next) {
+ if (memcmp(nmbname->name, nr->name.name, 16) == 0) {
+ /* Delete it. */
+ DLIST_REMOVE(wins_server_subnet->namelist, nr);
+ SAFE_FREE(nr->data.ip);
+ SAFE_FREE(nr);
+ break;
+ }
+ }
+
+ DLIST_ADD(wins_server_subnet->namelist, namerec);
+ return namerec;
+}
+
+/****************************************************************************
+ Overwrite or add a given name in the wins.tdb.
+*****************************************************************************/
+
+static bool store_or_replace_wins_namerec(const struct name_record *namerec, int tdb_flag)
+{
+ TDB_DATA key, data;
+ int ret;
+
+ if (!wins_tdb) {
+ return False;
+ }
+
+ key = name_to_key(&namerec->name);
+ data = name_record_to_wins_record(namerec);
+
+ if (data.dptr == NULL) {
+ return False;
+ }
+
+ ret = tdb_store(wins_tdb, key, data, tdb_flag);
+
+ SAFE_FREE(data.dptr);
+ return (ret == 0) ? True : False;
+}
+
+/****************************************************************************
+ Overwrite a given name in the wins.tdb.
+*****************************************************************************/
+
+bool wins_store_changed_namerec(const struct name_record *namerec)
+{
+ return store_or_replace_wins_namerec(namerec, TDB_REPLACE);
+}
+
+/****************************************************************************
+ Primary interface into creating and overwriting records in the wins.tdb.
+*****************************************************************************/
+
+bool add_name_to_wins_subnet(const struct name_record *namerec)
+{
+ return store_or_replace_wins_namerec(namerec, TDB_INSERT);
+}
+
+/****************************************************************************
+ Delete a given name in the tdb and remove the temporary malloc'ed data struct
+ on the linked list.
+*****************************************************************************/
+
+bool remove_name_from_wins_namelist(struct name_record *namerec)
+{
+ TDB_DATA key;
+ int ret;
+
+ if (!wins_tdb) {
+ return False;
+ }
+
+ key = name_to_key(&namerec->name);
+ ret = tdb_delete(wins_tdb, key);
+
+ DLIST_REMOVE(wins_server_subnet->namelist, namerec);
+
+ /* namerec must be freed by the caller */
+
+ return (ret == 0) ? True : False;
+}
+
+/****************************************************************************
+ Dump out the complete namelist.
+*****************************************************************************/
+
+static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct name_record *namerec = NULL;
+ XFILE *fp = (XFILE *)state;
+
+ if (kbuf.dsize != sizeof(unstring) + 1) {
+ return 0;
+ }
+
+ namerec = wins_record_to_name_record(kbuf, dbuf);
+ if (!namerec) {
+ return 0;
+ }
+
+ dump_name_record(namerec, fp);
+
+ SAFE_FREE(namerec->data.ip);
+ SAFE_FREE(namerec);
+ return 0;
+}
+
+void dump_wins_subnet_namelist(XFILE *fp)
+{
+ tdb_traverse(wins_tdb, traverse_fn, (void *)fp);
+}
/****************************************************************************
Change the wins owner address in the record.
static void update_wins_owner(struct name_record *namerec, struct in_addr wins_ip)
{
- if (namerec==NULL)
- return;
namerec->data.wins_ip=wins_ip;
}
static void update_wins_flag(struct name_record *namerec, int flags)
{
- if (namerec==NULL)
- return;
-
namerec->data.wins_flags=0x0;
/* if it's a group, it can be a normal or a special one */
if (namerec->data.nb_flags & NB_GROUP) {
- if (namerec->name.name_type==0x1C)
+ if (namerec->name.name_type==0x1C) {
namerec->data.wins_flags|=WINS_SGROUP;
- else
- if (namerec->data.num_ips>1)
+ } else {
+ if (namerec->data.num_ips>1) {
namerec->data.wins_flags|=WINS_SGROUP;
- else
+ } else {
namerec->data.wins_flags|=WINS_NGROUP;
+ }
+ }
} else {
/* can be unique or multi-homed */
- if (namerec->data.num_ips>1)
+ if (namerec->data.num_ips>1) {
namerec->data.wins_flags|=WINS_MHOMED;
- else
+ } else {
namerec->data.wins_flags|=WINS_UNIQUE;
+ }
}
/* the node type are the same bits */
namerec->data.wins_flags|=namerec->data.nb_flags&NB_NODETYPEMASK;
/* the static bit is elsewhere */
- if (namerec->data.death_time == PERMANENT_TTL)
+ if (namerec->data.death_time == PERMANENT_TTL) {
namerec->data.wins_flags|=WINS_STATIC;
+ }
/* and add the given bits */
namerec->data.wins_flags|=flags;
Return the general ID value and increase it if requested.
*****************************************************************************/
-static void get_global_id_and_update(SMB_BIG_UINT *current_id, BOOL update)
+static void get_global_id_and_update(SMB_BIG_UINT *current_id, bool update)
{
/*
* it's kept as a static here, to prevent people from messing
*current_id = general_id;
- if (update)
+ if (update) {
general_id++;
+ }
}
/****************************************************************************
Possibly call the WINS hook external program when a WINS change is made.
+ Also stores the changed record back in the wins_tdb.
*****************************************************************************/
static void wins_hook(const char *operation, struct name_record *namerec, int ttl)
{
pstring command;
char *cmd = lp_wins_hook();
- char *p;
+ char *p, *namestr;
int i;
- if (!cmd || !*cmd) return;
+ wins_store_changed_namerec(namerec);
+
+ if (!cmd || !*cmd) {
+ return;
+ }
for (p=namerec->name.name; *p; p++) {
if (!(isalnum((int)*p) || strchr_m("._-",*p))) {
}
}
+ /* Use the name without the nametype (and scope) appended */
+
+ namestr = nmb_namestr(&namerec->name);
+ if ((p = strchr(namestr, '<'))) {
+ *p = 0;
+ }
+
p = command;
p += slprintf(p, sizeof(command)-1, "%s %s %s %02x %d",
cmd,
operation,
- nmb_namestr(&namerec->name),
+ namestr,
namerec->name.name_type,
ttl);
smbrun(command, NULL);
}
-
/****************************************************************************
Determine if this packet should be allocated to the WINS server.
*****************************************************************************/
-BOOL packet_is_for_wins_server(struct packet_struct *packet)
+bool packet_is_for_wins_server(struct packet_struct *packet)
{
struct nmb_packet *nmb = &packet->packet.nmb;
}
/* Check for node status requests. */
- if (nmb->question.question_type != QUESTION_TYPE_NB_QUERY)
+ if (nmb->question.question_type != QUESTION_TYPE_NB_QUERY) {
return False;
+ }
switch(nmb->header.opcode) {
/*
{
int ttl = nmb->additional->ttl;
- if(ttl < lp_min_wins_ttl() )
+ if (ttl < lp_min_wins_ttl()) {
ttl = lp_min_wins_ttl();
+ }
- if(ttl > lp_max_wins_ttl() )
+ if (ttl > lp_max_wins_ttl()) {
ttl = lp_max_wins_ttl();
+ }
return ttl;
}
Load or create the WINS database.
*****************************************************************************/
-BOOL initialise_wins(void)
+bool initialise_wins(void)
{
time_t time_now = time(NULL);
XFILE *fp;
pstring line;
- if(!lp_we_are_a_wins_server())
+ if(!lp_we_are_a_wins_server()) {
return True;
+ }
+
+ /* Open the wins.tdb. */
+ wins_tdb = tdb_open_log(lock_path("wins.tdb"), 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST, O_CREAT|O_RDWR, 0600);
+ if (!wins_tdb) {
+ DEBUG(0,("initialise_wins: failed to open wins.tdb. Error was %s\n",
+ strerror(errno) ));
+ return False;
+ }
+
+ tdb_store_int32(wins_tdb, "WINSDB_VERSION", WINSDB_VERSION);
add_samba_names_to_subnet(wins_server_subnet);
int ttl;
const char *ptr;
char *p;
- BOOL got_token;
- BOOL was_ip;
+ bool got_token;
+ bool was_ip;
int i;
unsigned int hash;
int version;
}
/* Allocate the space for the ip_list. */
- if((ip_list = (struct in_addr *)malloc( num_ips * sizeof(struct in_addr))) == NULL) {
+ if((ip_list = SMB_MALLOC_ARRAY( struct in_addr, num_ips)) == NULL) {
DEBUG(0,("initialise_wins: Malloc fail !\n"));
+ x_fclose(fp);
return False;
}
continue;
}
- if(nb_flags_str[strlen(nb_flags_str)-1] == 'R')
+ if(nb_flags_str[strlen(nb_flags_str)-1] == 'R') {
nb_flags_str[strlen(nb_flags_str)-1] = '\0';
+ }
/* Netbios name. # divides the name from the type (hex): netbios#xx */
pstrcpy(name,name_str);
/* add all entries that have 60 seconds or more to live */
if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) {
- if(ttl != PERMANENT_TTL)
+ if(ttl != PERMANENT_TTL) {
ttl -= time_now;
+ }
DEBUG( 4, ("initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
(void)add_name_to_subnet( wins_server_subnet, name, type, nb_flags,
ttl, REGISTER_NAME, num_ips, ip_list );
} else {
- DEBUG(4, ("initialise_wins: not adding name (ttl problem) %s#%02x ttl = %d first IP %s flags = %2x\n",
+ DEBUG(4, ("initialise_wins: not adding name (ttl problem) "
+ "%s#%02x ttl = %d first IP %s flags = %2x\n",
name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
}
identical bytes from the requesting packet header. */
rdata[0] = (nmb->header.opcode & 0xF) << 3;
- if (nmb->header.nm_flags.authoritative && nmb->header.response)
+ if (nmb->header.nm_flags.authoritative && nmb->header.response) {
rdata[0] |= 0x4;
- if (nmb->header.nm_flags.trunc)
+ }
+ if (nmb->header.nm_flags.trunc) {
rdata[0] |= 0x2;
- if (nmb->header.nm_flags.recursion_desired)
+ }
+ if (nmb->header.nm_flags.recursion_desired) {
rdata[0] |= 0x1;
- if (nmb->header.nm_flags.recursion_available && nmb->header.response)
+ }
+ if (nmb->header.nm_flags.recursion_available && nmb->header.response) {
rdata[1] |= 0x80;
- if (nmb->header.nm_flags.bcast)
+ }
+ if (nmb->header.nm_flags.bcast) {
rdata[1] |= 0x10;
+ }
reply_netbios_packet(p, /* Packet to reply to. */
0, /* Result code. */
Deal with a name refresh request to a WINS server.
************************************************************************/
-void wins_process_name_refresh_request(struct subnet_record *subrec,
- struct packet_struct *p)
+void wins_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;
+ bool bcast = nmb->header.nm_flags.bcast;
uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
- BOOL group = (nb_flags & NB_GROUP) ? True : False;
+ bool group = (nb_flags & NB_GROUP) ? True : False;
struct name_record *namerec = NULL;
int ttl = get_ttl_from_packet(nmb);
struct in_addr from_ip;
struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
- putip((char *)&from_ip,&nmb->additional->rdata[2]);
+ putip( (char *)&from_ip, &nmb->additional->rdata[2] );
if(bcast) {
/*
* We should only get unicast name refresh packets here.
- * Anyone trying to refresh broadcast should not be going to a WINS
- * server. Log an error here.
+ * Anyone trying to refresh broadcast should not be going
+ * to a WINS server. Log an error here.
*/
-
- DEBUG(0,("wins_process_name_refresh_request: broadcast name refresh request \
-received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
- nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "wins_process_name_refresh_request: " );
+ dbgtext( "Broadcast name refresh request received " );
+ dbgtext( "for name %s ", nmb_namestr(question) );
+ dbgtext( "from IP %s ", inet_ntoa(from_ip) );
+ dbgtext( "on subnet %s. ", subrec->subnet_name );
+ dbgtext( "Error - Broadcasts should not be sent " );
+ dbgtext( "to a WINS server\n" );
+ }
return;
}
- DEBUG(3,("wins_process_name_refresh_request: Name refresh for name %s \
-IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ));
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "wins_process_name_refresh_request: " );
+ dbgtext( "Name refresh for name %s IP %s\n",
+ nmb_namestr(question), inet_ntoa(from_ip) );
+ }
/*
* See if the name already exists.
+ * If not, handle it as a name registration and return.
*/
-
namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
/*
* treat it like a registration request. This allows us to recover
* from errors (tridge)
*/
-
if(namerec == NULL) {
- DEBUG(3,("wins_process_name_refresh_request: Name refresh for name %s and \
-the name does not exist. Treating as registration.\n", nmb_namestr(question) ));
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "wins_process_name_refresh_request: " );
+ dbgtext( "Name refresh for name %s ",
+ nmb_namestr( question ) );
+ dbgtext( "and the name does not exist. Treating " );
+ dbgtext( "as registration.\n" );
+ }
wins_process_name_registration_request(subrec,p);
return;
}
/*
- * if the name is present but not active,
- * simply remove it and treat the request
- * as a registration
+ * if the name is present but not active, simply remove it
+ * and treat the refresh request as a registration & return.
*/
if (namerec != NULL && !WINS_STATE_ACTIVE(namerec)) {
- DEBUG(5,("wins_process_name_refresh_request: Name (%s) in WINS was \
-not active - removing it.\n", nmb_namestr(question) ));
+ if( DEBUGLVL( 5 ) ) {
+ dbgtext( "wins_process_name_refresh_request: " );
+ dbgtext( "Name (%s) in WINS ", nmb_namestr(question) );
+ dbgtext( "was not active - removing it.\n" );
+ }
remove_name_from_namelist( subrec, namerec );
namerec = NULL;
- wins_process_name_registration_request(subrec,p);
+ wins_process_name_registration_request( subrec, p );
return;
}
/*
* Check that the group bits for the refreshing name and the
- * name in our database match.
+ * name in our database match. If not, refuse the refresh.
+ * [crh: Why RFS_ERR instead of ACT_ERR? Is this what MS does?]
*/
-
- if((namerec != NULL) && ((group && !NAME_GROUP(namerec)) || (!group && NAME_GROUP(namerec))) ) {
- DEBUG(3,("wins_process_name_refresh_request: Name %s group bit = %s \
-does not match group bit in WINS for this name.\n", nmb_namestr(question), group ? "True" : "False" ));
+ if( (namerec != NULL) &&
+ ( (group && !NAME_GROUP(namerec))
+ || (!group && NAME_GROUP(namerec)) ) ) {
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "wins_process_name_refresh_request: " );
+ dbgtext( "Name %s ", nmb_namestr(question) );
+ dbgtext( "group bit = %s does not match ",
+ group ? "True" : "False" );
+ dbgtext( "group bit in WINS for this name.\n" );
+ }
send_wins_name_registration_response(RFS_ERR, 0, p);
return;
}
/*
- * For a unique name check that the person refreshing the name is one of the registered IP
- * addresses. If not - fail the refresh. Do the same for group names with a type of 0x1c.
- * Just return success for unique 0x1d refreshes. For normal group names update the ttl
- * and return success.
+ * For a unique name check that the person refreshing the name is
+ * one of the registered IP addresses. If not - fail the refresh.
+ * Do the same for group names with a type of 0x1c.
+ * Just return success for unique 0x1d refreshes. For normal group
+ * names update the ttl and return success.
*/
-
- if((!group || (group && (question->name_type == 0x1c))) && find_ip_in_name_record(namerec, from_ip )) {
+ if( (!group || (group && (question->name_type == 0x1c)))
+ && find_ip_in_name_record(namerec, from_ip) ) {
/*
* Update the ttl.
*/
send_wins_name_registration_response(0, ttl, p);
wins_hook("refresh", namerec, ttl);
return;
+ } else if((group && (question->name_type == 0x1c))) {
+ /*
+ * Added by crh for bug #1079.
+ * Fix from Bert Driehuis
+ */
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "wins_process_name_refresh_request: " );
+ dbgtext( "Name refresh for name %s, ",
+ nmb_namestr(question) );
+ dbgtext( "but IP address %s ", inet_ntoa(from_ip) );
+ dbgtext( "is not yet associated with " );
+ dbgtext( "that name. Treating as registration.\n" );
+ }
+ wins_process_name_registration_request(subrec,p);
+ return;
} else if(group) {
/*
- * Normal groups are all registered with an IP address of 255.255.255.255
- * so we can't search for the IP address.
+ * Normal groups are all registered with an IP address of
+ * 255.255.255.255 so we can't search for the IP address.
*/
update_name_ttl(namerec, ttl);
+ wins_hook("refresh", namerec, ttl);
send_wins_name_registration_response(0, ttl, p);
return;
} else if(!group && (question->name_type == 0x1d)) {
/*
* Fail the refresh.
*/
-
- DEBUG(3,("wins_process_name_refresh_request: Name refresh for name %s with IP %s and \
-is IP is not known to the name.\n", nmb_namestr(question), inet_ntoa(from_ip) ));
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "wins_process_name_refresh_request: " );
+ dbgtext( "Name refresh for name %s with IP %s ",
+ nmb_namestr(question), inet_ntoa(from_ip) );
+ dbgtext( "and is IP is not known to the name.\n" );
+ }
send_wins_name_registration_response(RFS_ERR, 0, p);
return;
}
namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
- if( (namerec != NULL) && (namerec->data.source == REGISTER_NAME) && ip_equal(rrec->packet->ip, *namerec->data.ip) ) {
+ if ((namerec != NULL) && (namerec->data.source == REGISTER_NAME) &&
+ ip_equal(rrec->packet->ip, *namerec->data.ip)) {
remove_name_from_namelist( subrec, namerec);
namerec = NULL;
}
- if(namerec == NULL)
+ if(namerec == NULL) {
wins_process_name_registration_request(subrec, orig_reg_packet);
- else
- DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between \
-querying for name %s in order to replace it and this reply.\n", nmb_namestr(question_name) ));
+ } else {
+ DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between "
+ "querying for name %s in order to replace it and this reply.\n",
+ nmb_namestr(question_name) ));
+ }
orig_reg_packet->locked = False;
free_packet(orig_reg_packet);
void wins_process_name_registration_request(struct subnet_record *subrec,
struct packet_struct *p)
{
- nstring name;
+ unstring name;
struct nmb_packet *nmb = &p->packet.nmb;
struct nmb_name *question = &nmb->question.question_name;
- BOOL bcast = nmb->header.nm_flags.bcast;
+ bool bcast = nmb->header.nm_flags.bcast;
uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
int ttl = get_ttl_from_packet(nmb);
struct name_record *namerec = NULL;
struct in_addr from_ip;
- BOOL registering_group_name = (nb_flags & NB_GROUP) ? True : False;
+ bool registering_group_name = (nb_flags & NB_GROUP) ? True : False;
struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
putip((char *)&from_ip,&nmb->additional->rdata[2]);
* Group names with type 0x1c are registered with individual IP addresses.
*/
- if(registering_group_name && (question->name_type != 0x1c))
+ if(registering_group_name && (question->name_type != 0x1c)) {
from_ip = *interpret_addr2("255.255.255.255");
+ }
/*
* Ignore all attempts to register a unique 0x1d name, although return success.
update_wins_owner(namerec, our_fake_ip);
}
update_name_ttl(namerec, ttl);
+ wins_hook("refresh", namerec, ttl);
send_wins_name_registration_response(0, ttl, p);
return;
} else {
* reject without doing the query - we know we will reject it.
*/
- if ( namerec != NULL )
- pull_ascii_nstring(name, namerec->name.name);
-
- if( is_myname(name) ) {
- if(!ismyip(from_ip)) {
- DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
+ if ( namerec != NULL ) {
+ pull_ascii_nstring(name, sizeof(name), namerec->name.name);
+ if( is_myname(name) ) {
+ if(!ismyip_v4(from_ip)) {
+ DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
- send_wins_name_registration_response(RFS_ERR, 0, p);
- return;
- } else {
- /*
- * It's one of our names and one of our IP's - update the ttl.
- */
- update_name_ttl(namerec, ttl);
- send_wins_name_registration_response(0, ttl, p);
- wins_hook("refresh", namerec, ttl);
- return;
+ send_wins_name_registration_response(RFS_ERR, 0, p);
+ return;
+ } else {
+ /*
+ * It's one of our names and one of our IP's - update the ttl.
+ */
+ update_name_ttl(namerec, ttl);
+ wins_hook("refresh", namerec, ttl);
+ send_wins_name_registration_response(0, ttl, p);
+ return;
+ }
}
+ } else {
+ name[0] = '\0';
}
/*
&& ip_equal( namerec->data.ip[0], from_ip )
&& ip_equal(namerec->data.wins_ip, our_fake_ip) ) {
update_name_ttl( namerec, ttl );
- send_wins_name_registration_response( 0, ttl, p );
wins_hook("refresh", namerec, ttl);
+ send_wins_name_registration_response( 0, ttl, p );
return;
}
* code. JRA.
*/
- pull_ascii_nstring(name, question->name);
+ pull_ascii_nstring(name, sizeof(name), question->name);
query_name_from_wins_server( *namerec->data.ip,
name,
question->name_type,
* Name did not exist - add it.
*/
- pull_ascii_nstring(name, question->name);
+ pull_ascii_nstring(name, sizeof(name), question->name);
add_name_to_subnet( subrec, name, question->name_type,
nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
return;
}
- if(!find_ip_in_name_record(namerec, from_ip))
+ if(!find_ip_in_name_record(namerec, from_ip)) {
add_ip_to_name_record(namerec, from_ip);
+ }
get_global_id_and_update(&namerec->data.id, True);
update_wins_owner(namerec, our_fake_ip);
update_wins_flag(namerec, WINS_ACTIVE);
update_name_ttl(namerec, ttl);
- send_wins_name_registration_response(0, ttl, orig_reg_packet);
wins_hook("add", namerec, ttl);
+ send_wins_name_registration_response(0, ttl, orig_reg_packet);
orig_reg_packet->locked = False;
free_packet(orig_reg_packet);
{
struct nmb_packet *nmb = &p->packet.nmb;
struct nmb_name *question = &nmb->question.question_name;
- BOOL bcast = nmb->header.nm_flags.bcast;
+ bool bcast = nmb->header.nm_flags.bcast;
uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
int ttl = get_ttl_from_packet(nmb);
struct name_record *namerec = NULL;
struct in_addr from_ip;
- BOOL group = (nb_flags & NB_GROUP) ? True : False;
+ bool group = (nb_flags & NB_GROUP) ? True : False;
struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
- nstring qname;
+ unstring qname;
putip((char *)&from_ip,&nmb->additional->rdata[2]);
*/
if((namerec != NULL) && (is_myname(namerec->name.name)) ) {
- if(!ismyip(from_ip)) {
+ if(!ismyip_v4(from_ip)) {
DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
send_wins_name_registration_response(RFS_ERR, 0, p);
* It's one of our names and one of our IP's. Ensure the IP is in the record and
* update the ttl. Update the version ID to force replication.
*/
+ update_name_ttl(namerec, ttl);
+
if(!find_ip_in_name_record(namerec, from_ip)) {
get_global_id_and_update(&namerec->data.id, True);
update_wins_owner(namerec, our_fake_ip);
update_wins_flag(namerec, WINS_ACTIVE);
add_ip_to_name_record(namerec, from_ip);
- wins_hook("add", namerec, ttl);
- } else {
- wins_hook("refresh", namerec, ttl);
}
- update_name_ttl(namerec, ttl);
+ wins_hook("refresh", namerec, ttl);
send_wins_name_registration_response(0, ttl, p);
return;
}
update_wins_flag(namerec, WINS_ACTIVE);
}
- send_wins_name_registration_response(0, ttl, p);
wins_hook("refresh", namerec, ttl);
+ send_wins_name_registration_response(0, ttl, p);
return;
}
* not the person who sent the packet
*/
- pull_ascii_nstring( qname, question->name);
+ pull_ascii_nstring( qname, sizeof(qname), question->name);
query_name_from_wins_server( namerec->data.ip[0],
qname,
question->name_type,
* Name did not exist - add it.
*/
- pull_ascii_nstring( qname, question->name);
+ pull_ascii_nstring( qname, sizeof(qname), question->name);
add_name_to_subnet( subrec, qname, question->name_type,
nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
send_wins_name_registration_response(0, ttl, p);
}
+/***********************************************************************
+ Fetch all *<1b> names from the WINS db and store on the namelist.
+***********************************************************************/
+
+static int fetch_1b_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct name_record *namerec = NULL;
+
+ if (kbuf.dsize != sizeof(unstring) + 1) {
+ return 0;
+ }
+
+ /* Filter out all non-1b names. */
+ if (kbuf.dptr[sizeof(unstring)] != 0x1b) {
+ return 0;
+ }
+
+ namerec = wins_record_to_name_record(kbuf, dbuf);
+ if (!namerec) {
+ return 0;
+ }
+
+ DLIST_ADD(wins_server_subnet->namelist, namerec);
+ return 0;
+}
+
+void fetch_all_active_wins_1b_names(void)
+{
+ tdb_traverse(wins_tdb, fetch_1b_traverse_fn, NULL);
+}
+
/***********************************************************************
Deal with the special name query for *<1b>.
***********************************************************************/
*/
num_ips = 0;
- for( namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
- namerec; namerec = (struct name_record *)ubi_trNext( namerec ) ) {
- if(WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b )
+
+ /* First, clear the in memory list - we're going to re-populate
+ it with the tdb_traversal in fetch_all_active_wins_1b_names. */
+
+ wins_delete_all_tmp_in_memory_records();
+
+ fetch_all_active_wins_1b_names();
+
+ for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
+ if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
num_ips += namerec->data.num_ips;
+ }
}
if(num_ips == 0) {
return;
}
- if((prdata = (char *)malloc( num_ips * 6 )) == NULL) {
+ if((prdata = (char *)SMB_MALLOC( num_ips * 6 )) == NULL) {
DEBUG(0,("process_wins_dmb_query_request: Malloc fail !.\n"));
return;
}
*/
num_ips = 0;
- for( namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
- namerec; namerec = (struct name_record *)ubi_trNext( namerec ) ) {
- if(WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
+ for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
+ if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
int i;
for(i = 0; i < namerec->data.num_ips; i++) {
set_nb_flags(&prdata[num_ips * 6],namerec->data.nb_flags);
if( namerec->data.num_ips == 1 ) {
prdata = rdata;
} else {
- if((prdata = (char *)malloc( namerec->data.num_ips * 6 )) == NULL) {
+ if((prdata = (char *)SMB_MALLOC( namerec->data.num_ips * 6 )) == NULL) {
DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
return;
}
prdata, /* data to send. */
reply_data_len); /* data length. */
- if(prdata != rdata)
+ if(prdata != rdata) {
SAFE_FREE(prdata);
+ }
}
/***********************************************************************
struct nmb_packet *nmb = &p->packet.nmb;
struct nmb_name *question = &nmb->question.question_name;
struct name_record *namerec = NULL;
- nstring qname;
+ unstring qname;
DEBUG(3,("wins_process_name_query: name query for name %s from IP %s\n",
nmb_namestr(question), inet_ntoa(p->ip) ));
* to discover other domains that may not have a presence on their subnet.
*/
- pull_ascii_nstring(qname, question->name);
+ pull_ascii_nstring(qname, sizeof(qname), question->name);
if(strequal( qname, "*") && (question->name_type == 0x1b)) {
process_wins_dmb_query_request( subrec, p);
return;
DEBUG(3,("wins_process_name_query: name query for name %s not found - doing dns lookup.\n",
nmb_namestr(question) ));
- queue_dns_query(p, question, &namerec);
+ queue_dns_query(p, question);
return;
}
{
struct nmb_packet *nmb = &p->packet.nmb;
struct nmb_name *question = &nmb->question.question_name;
- BOOL bcast = nmb->header.nm_flags.bcast;
+ bool bcast = nmb->header.nm_flags.bcast;
uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
struct name_record *namerec = NULL;
struct in_addr from_ip;
- BOOL releasing_group_name = (nb_flags & NB_GROUP) ? True : False;;
+ bool releasing_group_name = (nb_flags & NB_GROUP) ? True : False;;
putip((char *)&from_ip,&nmb->additional->rdata[2]);
remove_ip_from_name_record(namerec, from_ip);
DEBUG(3,("wins_process_name_release_request: Remove IP %s from NAME: %s\n",
inet_ntoa(from_ip),nmb_namestr(question)));
+ wins_hook("delete", namerec, 0);
send_wins_name_release_response(0, p);
return;
}
* Flag the name as released and update the ttl
*/
- send_wins_name_release_response(0, p);
-
namerec->data.wins_flags |= WINS_RELEASED;
update_name_ttl(namerec, EXTINCTION_INTERVAL);
wins_hook("delete", namerec, 0);
+ send_wins_name_release_response(0, p);
}
/*******************************************************************
WINS time dependent processing.
******************************************************************/
+static int wins_processing_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ time_t t = *(time_t *)state;
+ bool store_record = False;
+ struct name_record *namerec = NULL;
+ struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
+
+ if (kbuf.dsize != sizeof(unstring) + 1) {
+ return 0;
+ }
+
+ namerec = wins_record_to_name_record(kbuf, dbuf);
+ if (!namerec) {
+ return 0;
+ }
+
+ if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
+ if( namerec->data.source == SELF_NAME ) {
+ DEBUG( 3, ( "wins_processing_traverse_fn: Subnet %s not expiring SELF name %s\n",
+ wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) );
+ namerec->data.death_time += 300;
+ store_record = True;
+ goto done;
+ } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) {
+ DEBUG(3,("wins_processing_traverse_fn: deleting timed out DNS name %s\n",
+ nmb_namestr(&namerec->name)));
+ remove_name_from_wins_namelist(namerec );
+ goto done;
+ }
+
+ /* handle records, samba is the wins owner */
+ if (ip_equal(namerec->data.wins_ip, our_fake_ip)) {
+ switch (namerec->data.wins_flags & WINS_STATE_MASK) {
+ case WINS_ACTIVE:
+ namerec->data.wins_flags&=~WINS_STATE_MASK;
+ namerec->data.wins_flags|=WINS_RELEASED;
+ namerec->data.death_time = t + EXTINCTION_INTERVAL;
+ DEBUG(3,("wins_processing_traverse_fn: expiring %s\n",
+ nmb_namestr(&namerec->name)));
+ store_record = True;
+ goto done;
+ case WINS_RELEASED:
+ namerec->data.wins_flags&=~WINS_STATE_MASK;
+ namerec->data.wins_flags|=WINS_TOMBSTONED;
+ namerec->data.death_time = t + EXTINCTION_TIMEOUT;
+ get_global_id_and_update(&namerec->data.id, True);
+ DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
+ nmb_namestr(&namerec->name)));
+ store_record = True;
+ goto done;
+ case WINS_TOMBSTONED:
+ DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
+ nmb_namestr(&namerec->name)));
+ remove_name_from_wins_namelist(namerec );
+ goto done;
+ }
+ } else {
+ switch (namerec->data.wins_flags & WINS_STATE_MASK) {
+ case WINS_ACTIVE:
+ /* that's not as MS says it should be */
+ namerec->data.wins_flags&=~WINS_STATE_MASK;
+ namerec->data.wins_flags|=WINS_TOMBSTONED;
+ namerec->data.death_time = t + EXTINCTION_TIMEOUT;
+ DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
+ nmb_namestr(&namerec->name)));
+ store_record = True;
+ goto done;
+ case WINS_TOMBSTONED:
+ DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
+ nmb_namestr(&namerec->name)));
+ remove_name_from_wins_namelist(namerec );
+ goto done;
+ case WINS_RELEASED:
+ DEBUG(0,("wins_processing_traverse_fn: %s is in released state and\
+we are not the wins owner !\n", nmb_namestr(&namerec->name)));
+ goto done;
+ }
+ }
+ }
+
+ done:
+
+ if (store_record) {
+ wins_store_changed_namerec(namerec);
+ }
+
+ SAFE_FREE(namerec->data.ip);
+ SAFE_FREE(namerec);
+
+ return 0;
+}
+
+/*******************************************************************
+ Time dependent wins processing.
+******************************************************************/
+
void initiate_wins_processing(time_t t)
{
static time_t lasttime = 0;
- struct name_record *namerec;
- struct name_record *next_namerec;
- struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
- if (!lasttime)
+ if (!lasttime) {
lasttime = t;
- if (t - lasttime < 20)
+ }
+ if (t - lasttime < 20) {
return;
+ }
- lasttime = t;
-
- if(!lp_we_are_a_wins_server())
+ if(!lp_we_are_a_wins_server()) {
+ lasttime = t;
return;
+ }
- for( namerec = (struct name_record *)ubi_trFirst( wins_server_subnet->namelist );
- namerec;
- namerec = next_namerec ) {
- next_namerec = (struct name_record *)ubi_trNext( namerec );
+ tdb_traverse(wins_tdb, wins_processing_traverse_fn, &t);
- if( (namerec->data.death_time != PERMANENT_TTL)
- && (namerec->data.death_time < t) ) {
+ wins_delete_all_tmp_in_memory_records();
- if( namerec->data.source == SELF_NAME ) {
- DEBUG( 3, ( "expire_names_on_subnet: Subnet %s not expiring SELF name %s\n",
- wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) );
- namerec->data.death_time += 300;
- namerec->subnet->namelist_changed = True;
- continue;
- }
+ wins_write_database(t, True);
- /* handle records, samba is the wins owner */
- if (ip_equal(namerec->data.wins_ip, our_fake_ip)) {
- switch (namerec->data.wins_flags | WINS_STATE_MASK) {
- case WINS_ACTIVE:
- namerec->data.wins_flags&=~WINS_STATE_MASK;
- namerec->data.wins_flags|=WINS_RELEASED;
- namerec->data.death_time = t + EXTINCTION_INTERVAL;
- DEBUG(3,("initiate_wins_processing: expiring %s\n", nmb_namestr(&namerec->name)));
- break;
- case WINS_RELEASED:
- namerec->data.wins_flags&=~WINS_STATE_MASK;
- namerec->data.wins_flags|=WINS_TOMBSTONED;
- namerec->data.death_time = t + EXTINCTION_TIMEOUT;
- get_global_id_and_update(&namerec->data.id, True);
- DEBUG(3,("initiate_wins_processing: tombstoning %s\n", nmb_namestr(&namerec->name)));
- break;
- case WINS_TOMBSTONED:
- DEBUG(3,("initiate_wins_processing: deleting %s\n", nmb_namestr(&namerec->name)));
- remove_name_from_namelist( wins_server_subnet, namerec );
- break;
- }
- } else {
- switch (namerec->data.wins_flags | WINS_STATE_MASK) {
- case WINS_ACTIVE:
- /* that's not as MS says it should be */
- namerec->data.wins_flags&=~WINS_STATE_MASK;
- namerec->data.wins_flags|=WINS_TOMBSTONED;
- namerec->data.death_time = t + EXTINCTION_TIMEOUT;
- DEBUG(3,("initiate_wins_processing: tombstoning %s\n", nmb_namestr(&namerec->name)));
- case WINS_TOMBSTONED:
- DEBUG(3,("initiate_wins_processing: deleting %s\n", nmb_namestr(&namerec->name)));
- remove_name_from_namelist( wins_server_subnet, namerec );
- break;
- case WINS_RELEASED:
- DEBUG(0,("initiate_wins_processing: %s is in released state and\
-we are not the wins owner !\n", nmb_namestr(&namerec->name)));
- break;
- }
- }
+ lasttime = t;
+}
+
+/*******************************************************************
+ Write out one record.
+******************************************************************/
+void wins_write_name_record(struct name_record *namerec, XFILE *fp)
+{
+ int i;
+ struct tm *tm;
+
+ DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) ));
+
+ if( namerec->data.death_time != PERMANENT_TTL ) {
+ char *ts, *nl;
+
+ tm = localtime(&namerec->data.death_time);
+ if (!tm) {
+ return;
}
+ ts = asctime(tm);
+ if (!ts) {
+ return;
+ }
+ nl = strrchr( ts, '\n' );
+ if( NULL != nl ) {
+ *nl = '\0';
+ }
+ DEBUGADD(4,("TTL = %s ", ts ));
+ } else {
+ DEBUGADD(4,("TTL = PERMANENT "));
+ }
+
+ for (i = 0; i < namerec->data.num_ips; i++) {
+ DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) ));
}
+ DEBUGADD(4,("%2x\n", namerec->data.nb_flags ));
- if(wins_server_subnet->namelist_changed)
- wins_write_database(True);
+ if( namerec->data.source == REGISTER_NAME ) {
+ unstring name;
+ pull_ascii_nstring(name, sizeof(name), namerec->name.name);
+ x_fprintf(fp, "\"%s#%02x\" %d ", name,namerec->name.name_type, /* Ignore scope. */
+ (int)namerec->data.death_time);
- wins_server_subnet->namelist_changed = False;
+ for (i = 0; i < namerec->data.num_ips; i++)
+ x_fprintf( fp, "%s ", inet_ntoa( namerec->data.ip[i] ) );
+ x_fprintf( fp, "%2xR\n", namerec->data.nb_flags );
+ }
}
/*******************************************************************
Write out the current WINS database.
******************************************************************/
-void wins_write_database(BOOL background)
+static int wins_writedb_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct name_record *namerec = NULL;
+ XFILE *fp = (XFILE *)state;
+
+ if (kbuf.dsize != sizeof(unstring) + 1) {
+ return 0;
+ }
+
+ namerec = wins_record_to_name_record(kbuf, dbuf);
+ if (!namerec) {
+ return 0;
+ }
+
+ wins_write_name_record(namerec, fp);
+
+ SAFE_FREE(namerec->data.ip);
+ SAFE_FREE(namerec);
+ return 0;
+}
+
+
+void wins_write_database(time_t t, bool background)
{
- struct name_record *namerec;
+ static time_t last_write_time = 0;
pstring fname, fnamenew;
XFILE *fp;
- if(!lp_we_are_a_wins_server())
+ if (background) {
+ if (!last_write_time) {
+ last_write_time = t;
+ }
+ if (t - last_write_time < 120) {
+ return;
+ }
+
+ }
+
+ if(!lp_we_are_a_wins_server()) {
return;
+ }
/* We will do the writing in a child process to ensure that the parent doesn't block while this is done */
if (background) {
if (sys_fork()) {
return;
}
+ if (tdb_reopen(wins_tdb)) {
+ DEBUG(0,("wins_write_database: tdb_reopen failed. Error was %s\n",
+ strerror(errno)));
+ _exit(0);
+ return;
+ }
}
slprintf(fname,sizeof(fname)-1,"%s/%s", lp_lockdir(), WINS_LIST);
x_fprintf(fp,"VERSION %d %u\n", WINS_VERSION, 0);
- for( namerec = (struct name_record *)ubi_trFirst( wins_server_subnet->namelist ); namerec; namerec = (struct name_record *)ubi_trNext( namerec ) ) {
- int i;
- struct tm *tm;
-
- DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) ));
-
- if( namerec->data.death_time != PERMANENT_TTL ) {
- char *ts, *nl;
+ tdb_traverse(wins_tdb, wins_writedb_traverse_fn, fp);
- tm = LocalTime(&namerec->data.death_time);
- ts = asctime(tm);
- nl = strrchr( ts, '\n' );
- if( NULL != nl )
- *nl = '\0';
- DEBUGADD(4,("TTL = %s ", ts ));
- } else {
- DEBUGADD(4,("TTL = PERMANENT "));
- }
-
- for (i = 0; i < namerec->data.num_ips; i++)
- DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) ));
- DEBUGADD(4,("%2x\n", namerec->data.nb_flags ));
-
- if( namerec->data.source == REGISTER_NAME ) {
- nstring name;
- pull_ascii_nstring(name, namerec->name.name);
- x_fprintf(fp, "\"%s#%02x\" %d ", name,namerec->name.name_type, /* Ignore scope. */
- (int)namerec->data.death_time);
-
- for (i = 0; i < namerec->data.num_ips; i++)
- x_fprintf( fp, "%s ", inet_ntoa( namerec->data.ip[i] ) );
- x_fprintf( fp, "%2xR\n", namerec->data.nb_flags );
- }
- }
-
x_fclose(fp);
chmod(fnamenew,0644);
unlink(fname);
}
}
+#if 0
+ Until winsrepl is done.
/****************************************************************************
Process a internal Samba message receiving a wins record.
***************************************************************************/
-void nmbd_wins_new_entry(int msg_type, pid_t src, void *buf, size_t len)
+void nmbd_wins_new_entry(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
{
WINS_RECORD *record;
struct name_record *namerec = NULL;
struct name_record *new_namerec = NULL;
struct nmb_name question;
- BOOL overwrite=False;
+ bool overwrite=False;
struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
int i;
- if (buf==NULL)
+ if (buf==NULL) {
return;
+ }
/* Record should use UNIX codepage. Ensure this is so in the wrepld code. JRA. */
record=(WINS_RECORD *)buf;
DEBUG(3,("nmbd_wins_new_entry: adding new replicated record: %s<%02x> for wins server: %s\n",
record->name, record->type, inet_ntoa(record->wins_ip)));
- new_namerec=add_name_to_subnet( wins_server_subnet, record->name, record->type, record->nb_flags,
- EXTINCTION_INTERVAL, REGISTER_NAME, record->num_ips, record->ip);
+ new_namerec=add_name_to_subnet( wins_server_subnet,
+ record->name,
+ record->type,
+ record->nb_flags,
+ EXTINCTION_INTERVAL,
+ REGISTER_NAME,
+ record->num_ips,
+ record->ip);
+
if (new_namerec!=NULL) {
update_wins_owner(new_namerec, record->wins_ip);
update_wins_flag(new_namerec, record->wins_flags);
}
}
+#endif