diff options
author | Jeremy Allison <jra@samba.org> | 2005-12-06 23:06:38 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 11:05:45 -0500 |
commit | a342681792724c1ae8561ba8d352c4ee6e2a5332 (patch) | |
tree | db15ef035492900ca8723aa41894cf5d6ded3810 | |
parent | 1fa8039397175331d9f5e8b5e3897e9bba14484a (diff) | |
download | samba-a342681792724c1ae8561ba8d352c4ee6e2a5332.tar.gz samba-a342681792724c1ae8561ba8d352c4ee6e2a5332.tar.xz samba-a342681792724c1ae8561ba8d352c4ee6e2a5332.zip |
r12107: Move to a tdb-based wins database. At the moment we still
use it as though it were an in-memory db and dump out to
a flat file every 2 mins, but that can now change.
Jeremy.
-rw-r--r-- | source/Makefile.in | 9 | ||||
-rw-r--r-- | source/include/includes.h | 6 | ||||
-rw-r--r-- | source/include/nameserv.h | 6 | ||||
-rw-r--r-- | source/include/smb.h | 7 | ||||
-rw-r--r-- | source/libsmb/nmblib.c | 2 | ||||
-rw-r--r-- | source/nmbd/asyncdns.c | 26 | ||||
-rw-r--r-- | source/nmbd/nmbd.c | 5 | ||||
-rw-r--r-- | source/nmbd/nmbd_browserdb.c | 22 | ||||
-rw-r--r-- | source/nmbd/nmbd_browsesync.c | 6 | ||||
-rw-r--r-- | source/nmbd/nmbd_incomingrequests.c | 6 | ||||
-rw-r--r-- | source/nmbd/nmbd_mynames.c | 8 | ||||
-rw-r--r-- | source/nmbd/nmbd_namelistdb.c | 327 | ||||
-rw-r--r-- | source/nmbd/nmbd_subnetdb.c | 33 | ||||
-rw-r--r-- | source/nmbd/nmbd_winsproxy.c | 22 | ||||
-rw-r--r-- | source/nmbd/nmbd_winsserver.c | 801 |
15 files changed, 891 insertions, 395 deletions
diff --git a/source/Makefile.in b/source/Makefile.in index a80b16df715..bb3f72847b1 100644 --- a/source/Makefile.in +++ b/source/Makefile.in @@ -219,9 +219,6 @@ READLINE_OBJ = lib/readline.o # Be sure to include them into your application POPT_LIB_OBJ = lib/popt_common.o -UBIQX_OBJ = ubiqx/ubi_BinTree.o ubiqx/ubi_Cache.o ubiqx/ubi_SplayTree.o \ - ubiqx/ubi_dLinkList.o ubiqx/ubi_sLinkList.o - PARAM_OBJ = dynconfig.o param/loadparm.o param/params.o KRBCLIENT_OBJ = libads/kerberos.o libads/ads_status.o @@ -441,13 +438,13 @@ NMBD_OBJ1 = nmbd/asyncdns.o nmbd/nmbd.o nmbd/nmbd_become_dmb.o \ nmbd/nmbd_subnetdb.o nmbd/nmbd_winsproxy.o nmbd/nmbd_winsserver.o \ nmbd/nmbd_workgroupdb.o nmbd/nmbd_synclists.o -NMBD_OBJ = $(NMBD_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) $(UBIQX_OBJ) \ +NMBD_OBJ = $(NMBD_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \ $(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(SECRETS_OBJ) $(POPT_LIB_OBJ) WREPL_OBJ1 = wrepld/server.o wrepld/process.o wrepld/parser.o wrepld/socket.o \ wrepld/partners.o -WREPL_OBJ = $(WREPL_OBJ1) $(PARAM_OBJ) $(UBIQX_OBJ) \ +WREPL_OBJ = $(WREPL_OBJ1) $(PARAM_OBJ) \ $(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(SECRETS_OBJ) \ $(LIBSAMBA_OBJ) @@ -543,7 +540,7 @@ LIBSMBSHAREMODES_OBJ = libsmb/smb_share_modes.o tdb/tdb.o tdb/spinlock.o LIBBIGBALLOFMUD_MAJOR = 0 -LIBBIGBALLOFMUD_OBJ = $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(UBIQX_OBJ) $(SECRETS_OBJ) \ +LIBBIGBALLOFMUD_OBJ = $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(SECRETS_OBJ) \ $(LIBSMB_OBJ) $(LIBMSRPC_OBJ) $(RPC_PARSE_OBJ) $(PASSDB_OBJ) \ $(GROUPDB_OBJ) $(KRBCLIENT_OBJ) $(SMBLDAP_OBJ) diff --git a/source/include/includes.h b/source/include/includes.h index cde199eed8b..80fc3feed98 100644 --- a/source/include/includes.h +++ b/source/include/includes.h @@ -863,8 +863,6 @@ extern int errno; /* Lists, trees, caching, database... */ #include "xfile.h" #include "intl.h" -#include "ubi_sLinkList.h" -#include "ubi_dLinkList.h" #include "dlinklist.h" #include "tdb/tdb.h" #include "tdb/spinlock.h" @@ -887,10 +885,6 @@ extern int errno; #include "util_getent.h" -#ifndef UBI_BINTREE_H -#include "ubi_Cache.h" -#endif /* UBI_BINTREE_H */ - #include "debugparse.h" #include "version.h" diff --git a/source/include/nameserv.h b/source/include/nameserv.h index ec3d56c06b7..9f6bf76a093 100644 --- a/source/include/nameserv.h +++ b/source/include/nameserv.h @@ -217,7 +217,7 @@ struct nmb_data { /* This structure represents an entry in a local netbios name list. */ struct name_record { - ubi_trNode node[1]; + struct name_record *prev, *next; struct subnet_record *subnet; struct nmb_name name; /* The netbios name. */ struct nmb_data data; /* The netbios data. */ @@ -225,7 +225,7 @@ struct name_record { /* Browser cache for synchronising browse lists. */ struct browse_cache_record { - ubi_dlNode node[1]; + struct browse_cache_record *prev, *next; unstring lmb_name; unstring work_group; struct in_addr ip; @@ -425,7 +425,7 @@ struct subnet_record { enum subnet_type type; /* To catagorize the subnet. */ struct work_record *workgrouplist; /* List of workgroups. */ - ubi_trRoot namelist[1]; /* List of netbios names. */ + struct name_record *namelist; /* List of netbios names. */ struct response_record *responselist; /* List of responses expected. */ BOOL namelist_changed; diff --git a/source/include/smb.h b/source/include/smb.h index b2d28b7d70e..a3dce53a4ca 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -1530,17 +1530,14 @@ struct node_status_extra { /* There really is more here ... */ }; -struct pwd_info -{ +struct pwd_info { BOOL null_pwd; BOOL cleartext; fstring password; - }; -typedef struct user_struct -{ +typedef struct user_struct { struct user_struct *next, *prev; uint16 vuid; /* Tag for this entry. */ uid_t uid; /* uid of a validated user */ diff --git a/source/libsmb/nmblib.c b/source/libsmb/nmblib.c index 164f85be7bf..4d84d7bc499 100644 --- a/source/libsmb/nmblib.c +++ b/source/libsmb/nmblib.c @@ -331,7 +331,7 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name) Useful for debugging messages. ******************************************************************/ -char *nmb_namestr(struct nmb_name *n) +char *nmb_namestr(const struct nmb_name *n) { static int i=0; static fstring ret[4]; diff --git a/source/nmbd/asyncdns.c b/source/nmbd/asyncdns.c index 4db54ea198c..c0626d11619 100644 --- a/source/nmbd/asyncdns.c +++ b/source/nmbd/asyncdns.c @@ -34,16 +34,18 @@ static struct name_record *add_dns_result(struct nmb_name *question, struct in_a 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, + add_name_to_subnet( wins_server_subnet, qname, name_type, NB_ACTIVE, 60*60, DNSFAIL_NAME, 1, &addr ); - return( NULL ); + return NULL; } /* 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 ) ); + add_name_to_subnet( wins_server_subnet, qname, name_type, + NB_ACTIVE, 2*60*60, DNS_NAME, 1, &addr); + + return find_name_on_subnet(wins_server_subnet, question, FIND_ANY_NAME); } #ifndef SYNC_DNS @@ -283,8 +285,7 @@ void run_dns_queue(void) queue a DNS query ****************************************************************************/ -BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question, - struct name_record **n) +BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question) { if (in_dns || fd_in == -1) return False; @@ -316,9 +317,9 @@ 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) +BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question) { + struct name_record *namerec = NULL; struct in_addr dns_ip; unstring qname; @@ -334,11 +335,12 @@ BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question, /* Re-block TERM signal. */ BlockSignals(True, SIGTERM); - *n = add_dns_result(question, dns_ip); - if(*n == NULL) + namerec = add_dns_result(question, dns_ip); + if(namerec == NULL) { send_wins_name_query_response(NAM_ERR, p, NULL); - else - send_wins_name_query_response(0, p, *n); + } else { + send_wins_name_query_response(0, p, namerec); + } return False; } diff --git a/source/nmbd/nmbd.c b/source/nmbd/nmbd.c index 01fdb8e74cf..78411d34176 100644 --- a/source/nmbd/nmbd.c +++ b/source/nmbd/nmbd.c @@ -58,7 +58,7 @@ static void terminate(void) DEBUG(0,("Got SIGTERM: going down...\n")); /* Write out wins.dat file if samba is a WINS server */ - wins_write_database(False); + wins_write_database(0,False); /* Remove all SELF registered names from WINS */ release_wins_names(); @@ -773,7 +773,10 @@ static BOOL open_sockets(BOOL isdaemon, int port) pidfile_create("nmbd"); message_init(); message_register(MSG_FORCE_ELECTION, nmbd_message_election); +#if 0 + /* Until winsrepl is done. */ message_register(MSG_WINS_NEW_ENTRY, nmbd_wins_new_entry); +#endif message_register(MSG_SHUTDOWN, nmbd_terminate); message_register(MSG_SMB_CONF_UPDATED, msg_reload_nmbd_services); message_register(MSG_SEND_PACKET, msg_nmbd_send_packet); diff --git a/source/nmbd/nmbd_browserdb.c b/source/nmbd/nmbd_browserdb.c index e8797a99d51..e27e483702a 100644 --- a/source/nmbd/nmbd_browserdb.c +++ b/source/nmbd/nmbd_browserdb.c @@ -35,7 +35,7 @@ * lmb_browserlist - This is our local master browser list. */ -ubi_dlNewList( lmb_browserlist ); +struct browse_cache_record *lmb_browserlist; /* -------------------------------------------------------------------------- ** * Functions... @@ -52,7 +52,8 @@ ubi_dlNewList( lmb_browserlist ); */ static void remove_lmb_browser_entry( struct browse_cache_record *browc ) { - safe_free( ubi_dlRemThis( lmb_browserlist, browc ) ); + DLIST_REMOVE(lmb_browserlist, browc); + SAFE_FREE(browc); } /* ************************************************************************** ** @@ -85,6 +86,7 @@ struct browse_cache_record *create_browser_in_lmb_cache( const char *work_name, struct in_addr ip ) { struct browse_cache_record *browc; + struct browse_cache_record *tmp_browc; time_t now = time( NULL ); browc = SMB_MALLOC_P(struct browse_cache_record); @@ -113,7 +115,7 @@ struct browse_cache_record *create_browser_in_lmb_cache( const char *work_name, browc->ip = ip; - (void)ubi_dlAddTail( lmb_browserlist, browc ); + DLIST_ADD_END(lmb_browserlist, browc, tmp_browc); if( DEBUGLVL( 3 ) ) { Debug1( "nmbd_browserdb:create_browser_in_lmb_cache()\n" ); @@ -138,12 +140,13 @@ struct browse_cache_record *find_browser_in_lmb_cache( const char *browser_name { struct browse_cache_record *browc; - for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist ); - browc; browc = (struct browse_cache_record *)ubi_dlNext( browc ) ) - if( strequal( browser_name, browc->lmb_name ) ) + for( browc = lmb_browserlist; browc; browc = browc->next ) { + if( strequal( browser_name, browc->lmb_name ) ) { break; + } + } - return( browc ); + return browc; } /* ************************************************************************** ** @@ -160,9 +163,8 @@ void expire_lmb_browsers( time_t t ) struct browse_cache_record *browc; struct browse_cache_record *nextbrowc; - for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist ); - browc; browc = nextbrowc ) { - nextbrowc = (struct browse_cache_record *)ubi_dlNext( browc ); + for( browc = lmb_browserlist; browc; browc = nextbrowc) { + nextbrowc = browc->next; if( browc->death_time < t ) { if( DEBUGLVL( 3 ) ) { diff --git a/source/nmbd/nmbd_browsesync.c b/source/nmbd/nmbd_browsesync.c index 03234bb98fa..9535a3115a6 100644 --- a/source/nmbd/nmbd_browsesync.c +++ b/source/nmbd/nmbd_browsesync.c @@ -24,7 +24,7 @@ #include "includes.h" /* This is our local master browser list database. */ -extern ubi_dlList lmb_browserlist[]; +extern struct browse_cache_record *lmb_browserlist; /**************************************************************************** As a domain master browser, do a sync with a local master browser. @@ -87,9 +87,7 @@ void dmb_expire_and_sync_browser_lists(time_t t) expire_lmb_browsers(t); - for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist ); - browc; - browc = (struct browse_cache_record *)ubi_dlNext( browc ) ) { + for( browc = lmb_browserlist; browc; browc = browc->next ) { if (browc->sync_time < t) sync_with_lmb(browc); } diff --git a/source/nmbd/nmbd_incomingrequests.c b/source/nmbd/nmbd_incomingrequests.c index 7fac8c25739..eaef7097b4a 100644 --- a/source/nmbd/nmbd_incomingrequests.c +++ b/source/nmbd/nmbd_incomingrequests.c @@ -339,7 +339,7 @@ subnet %s - name not found.\n", nmb_namestr(&nmb->question.question_name), names_added = 0; - namerec = (struct name_record *)ubi_trFirst( subrec->namelist ); + namerec = subrec->namelist; while (buf < bufend) { if( (namerec->data.source == SELF_NAME) || (namerec->data.source == PERMANENT_NAME) ) { @@ -389,7 +389,7 @@ subnet %s - name not found.\n", nmb_namestr(&nmb->question.question_name), buf = buf0 + 18*names_added; - namerec = (struct name_record *)ubi_trNext( namerec ); + namerec = namerec->next; if (!namerec) { /* End of the subnet specific name list. Now @@ -398,7 +398,7 @@ subnet %s - name not found.\n", nmb_namestr(&nmb->question.question_name), if (uni_subrec != subrec) { subrec = uni_subrec; - namerec = (struct name_record *)ubi_trFirst( subrec->namelist ); + namerec = subrec->namelist; } } if (!namerec) diff --git a/source/nmbd/nmbd_mynames.c b/source/nmbd/nmbd_mynames.c index 07247d5495e..f34d98172c6 100644 --- a/source/nmbd/nmbd_mynames.c +++ b/source/nmbd/nmbd_mynames.c @@ -182,8 +182,8 @@ 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) { - nextnamerec = (struct name_record *)ubi_trNext( namerec ); + for (namerec = subrec->namelist; namerec; namerec = nextnamerec) { + nextnamerec = namerec->next; if( (namerec->data.source == SELF_NAME) && !NAME_IS_DEREGISTERING(namerec) ) release_name( subrec, namerec, standard_success_release, @@ -202,9 +202,7 @@ void refresh_my_names(time_t t) if (wins_srv_count() < 1) return; - for (namerec = (struct name_record *)ubi_trFirst(unicast_subnet->namelist); - namerec; - namerec = (struct name_record *)ubi_trNext(namerec)) { + for (namerec = unicast_subnet->namelist; namerec; namerec = namerec->next) { /* Each SELF name has an individual time to be refreshed. */ if ((namerec->data.source == SELF_NAME) && (namerec->data.refresh_time < t) && diff --git a/source/nmbd/nmbd_namelistdb.c b/source/nmbd/nmbd_namelistdb.c index 88d5ea52f58..894b8776134 100644 --- a/source/nmbd/nmbd_namelistdb.c +++ b/source/nmbd/nmbd_namelistdb.c @@ -32,24 +32,26 @@ uint16 samba_nb_type = 0; /* samba's NetBIOS name type */ void set_samba_nb_type(void) { - if( lp_wins_support() || wins_srv_count() ) + if( lp_wins_support() || wins_srv_count() ) { samba_nb_type = NB_HFLAG; /* samba is a 'hybrid' node type. */ - else + } else { samba_nb_type = NB_BFLAG; /* samba is broadcast-only node type. */ + } } /*************************************************************************** Convert a NetBIOS name to upper case. ***************************************************************************/ -static void upcase_name( struct nmb_name *target, struct nmb_name *source ) +static void upcase_name( struct nmb_name *target, const struct nmb_name *source ) { int i; unstring targ; fstring scope; - if( NULL != source ) + if( NULL != source ) { memcpy( target, source, sizeof( struct nmb_name ) ); + } pull_ascii_nstring(targ, sizeof(targ), target->name); strupper_m( targ ); @@ -63,25 +65,11 @@ static void upcase_name( struct nmb_name *target, struct nmb_name *source ) * unused space doesn't have garbage in it. */ - for( i = strlen( target->name ); i < sizeof( target->name ); i++ ) + for( i = strlen( target->name ); i < sizeof( target->name ); i++ ) { target->name[i] = '\0'; - for( i = strlen( target->scope ); i < sizeof( target->scope ); i++ ) + } + for( i = strlen( target->scope ); i < sizeof( target->scope ); i++ ) { target->scope[i] = '\0'; -} - -/************************************************************************** - 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; - - ubi_trInsert( subrec->namelist, namerec, &namerec->name, &oldrec ); - if( oldrec ) { - SAFE_FREE( oldrec->data.ip ); - SAFE_FREE( oldrec ); } } @@ -89,64 +77,81 @@ static void update_name_in_namelist( struct subnet_record *subrec, Remove a name from the namelist. ***************************************************************************/ -void remove_name_from_namelist( struct subnet_record *subrec, - struct name_record *namerec ) +void remove_name_from_namelist(struct subnet_record *subrec, + struct name_record *namerec ) { - ubi_trRemove( subrec->namelist, namerec ); + if (subrec == wins_server_subnet) { + remove_name_from_wins_namelist(namerec); + } else { + subrec->namelist_changed = True; + } + DLIST_REMOVE(subrec->namelist, namerec); SAFE_FREE(namerec->data.ip); ZERO_STRUCTP(namerec); SAFE_FREE(namerec); - subrec->namelist_changed = True; } /************************************************************************** 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 name_record *find_name_on_subnet(struct subnet_record *subrec, + const struct nmb_name *nmbname, + BOOL self_only) { - struct nmb_name uc_name[1]; + struct nmb_name uc_name; struct name_record *name_ret; - upcase_name( uc_name, nmbname ); - name_ret = (struct name_record *)ubi_trFind( subrec->namelist, uc_name ); + upcase_name( &uc_name, nmbname ); + + if (subrec == wins_server_subnet) { + return find_name_on_wins_subnet(&uc_name, self_only); + } + + for( name_ret = subrec->namelist; name_ret; name_ret = name_ret->next) { + if (memcmp(&uc_name, &name_ret->name, sizeof(struct nmb_name)) == 0) { + break; + } + } + 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 ); + return False; } 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 ); + + 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 ); + + return NULL; } /************************************************************************** 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 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 name_record *namerec; for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) ) { - if( NULL != (namerec = find_name_on_subnet(subrec, nmbname, self_only)) ) - break; + namerec = find_name_on_subnet(subrec, nmbname, self_only); + if (namerec) { + return namerec; + } } - return( namerec ); + return NULL; } /************************************************************************** @@ -157,34 +162,40 @@ void update_name_ttl( struct name_record *namerec, int ttl ) { time_t time_now = time(NULL); - if( namerec->data.death_time != PERMANENT_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->subnet->namelist_changed = True; + if (namerec->subnet == wins_server_subnet) { + wins_store_changed_namerec(namerec); + } else { + namerec->subnet->namelist_changed = True; + } } /************************************************************************** Add an entry to a subnet name list. ***********************************************************************/ -struct name_record *add_name_to_subnet( struct subnet_record *subrec, - const char *name, - int type, - uint16 nb_flags, - int ttl, - enum name_source source, - int num_ips, - struct in_addr *iplist) +BOOL add_name_to_subnet( struct subnet_record *subrec, + const char *name, + int type, + uint16 nb_flags, + int ttl, + enum name_source source, + int num_ips, + struct in_addr *iplist) { + BOOL ret = False; struct name_record *namerec; time_t time_now = time(NULL); namerec = SMB_MALLOC_P(struct name_record); if( NULL == namerec ) { DEBUG( 0, ( "add_name_to_subnet: malloc fail.\n" ) ); - return( NULL ); + return False; } memset( (char *)namerec, '\0', sizeof(*namerec) ); @@ -193,7 +204,7 @@ struct name_record *add_name_to_subnet( struct subnet_record *subrec, DEBUG( 0, ( "add_name_to_subnet: malloc fail when creating ip_flgs.\n" ) ); ZERO_STRUCTP(namerec); SAFE_FREE(namerec); - return NULL; + return False; } namerec->subnet = subrec; @@ -206,8 +217,9 @@ struct name_record *add_name_to_subnet( struct subnet_record *subrec, namerec->data.wins_flags = WINS_ACTIVE; /* If it's our primary name, flag it as so. */ - if( strequal( my_netbios_names(0), name ) ) + if (strequal( my_netbios_names(0), name )) { namerec->data.nb_flags |= NB_PERM; + } /* Copy the IPs. */ namerec->data.num_ips = num_ips; @@ -217,16 +229,14 @@ struct name_record *add_name_to_subnet( struct subnet_record *subrec, namerec->data.source = source; /* Setup the death_time and refresh_time. */ - if( ttl == PERMANENT_TTL ) + if (ttl == PERMANENT_TTL) { namerec->data.death_time = PERMANENT_TTL; - else + } else { namerec->data.death_time = time_now + ttl; + } 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 ); - 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 ), @@ -235,9 +245,20 @@ ttl=%d nb_flags=%2x to subnet %s\n", (unsigned int)nb_flags, subrec->subnet_name ) ); - subrec->namelist_changed = True; + /* Now add the record to the name list. */ + + if (subrec == wins_server_subnet) { + ret = add_name_to_wins_subnet(namerec); + /* Free namerec - it's stored in the tdb. */ + SAFE_FREE(namerec->data.ip); + SAFE_FREE(namerec); + } else { + DLIST_ADD(subrec->namelist, namerec); + subrec->namelist_changed = True; + ret = True; + } - return(namerec); + return ret; } /******************************************************************* @@ -253,8 +274,8 @@ void standard_success_register(struct subnet_record *subrec, { struct name_record *namerec; - namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME ); - if( NULL == namerec ) { + namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME); + if (namerec == NULL) { unstring name; pull_ascii_nstring(name, sizeof(name), nmbname->name); add_name_to_subnet( subrec, name, nmbname->name_type, @@ -277,14 +298,15 @@ void standard_fail_register( struct subnet_record *subrec, { 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) ); /* Remove the name from the subnet. */ - if( namerec ) + if( namerec ) { remove_name_from_namelist(subrec, namerec); + } } /******************************************************************* @@ -293,13 +315,18 @@ on subnet %s\n", nmb_namestr(nmbname), subrec->subnet_name) ); static void remove_nth_ip_in_record( struct name_record *namerec, int ind) { - if( ind != namerec->data.num_ips ) + 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; + if (namerec->subnet == wins_server_subnet) { + wins_store_changed_namerec(namerec); + } else { + namerec->subnet->namelist_changed = True; + } } /******************************************************************* @@ -310,9 +337,11 @@ BOOL find_ip_in_name_record( struct name_record *namerec, struct in_addr ip ) { int i; - for(i = 0; i < namerec->data.num_ips; i++) - if(ip_equal( namerec->data.ip[i], ip)) + for(i = 0; i < namerec->data.num_ips; i++) { + if(ip_equal( namerec->data.ip[i], ip)) { return True; + } + } return False; } @@ -326,8 +355,9 @@ void add_ip_to_name_record( struct name_record *namerec, struct in_addr new_ip ) struct in_addr *new_list; /* Don't add one we already have. */ - if( find_ip_in_name_record( namerec, new_ip ) ) + if( find_ip_in_name_record( namerec, new_ip )) { return; + } new_list = SMB_MALLOC_ARRAY( struct in_addr, namerec->data.num_ips + 1); if( NULL == new_list ) { @@ -342,7 +372,11 @@ void add_ip_to_name_record( struct name_record *namerec, struct in_addr new_ip ) namerec->data.ip = new_list; namerec->data.num_ips += 1; - namerec->subnet->namelist_changed = True; + if (namerec->subnet == wins_server_subnet) { + wins_store_changed_namerec(namerec); + } else { + namerec->subnet->namelist_changed = True; + } } /******************************************************************* @@ -388,26 +422,29 @@ on subnet %s. Name was not found on subnet.\n", nmb_namestr(nmbname), inet_ntoa( remove_ip_from_name_record( namerec, released_ip ); - if( namerec->data.num_ips == orig_num ) + 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 ) + if( namerec->data.num_ips == 0 ) { remove_name_from_namelist( subrec, namerec ); + } } /******************************************************************* - Expires old names in a subnet namelist. + Expires old names in a subnet namelist. + NB. Does not touch the wins_subnet - no wins specific processing here. ******************************************************************/ -void expire_names_on_subnet(struct subnet_record *subrec, time_t t) +static void expire_names_on_subnet(struct subnet_record *subrec, time_t t) { 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 ); + for( namerec = subrec->namelist; namerec; namerec = next_namerec ) { + next_namerec = namerec->next; 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 \ @@ -420,13 +457,14 @@ name %s\n", subrec->subnet_name, nmb_namestr(&namerec->name) ) ); 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. + Expires old names in all subnet namelists. + NB. Does not touch the wins_subnet. ******************************************************************/ void expire_names(time_t t) @@ -479,75 +517,85 @@ void add_samba_names_to_subnet( struct subnet_record *subrec ) add_name_to_subnet(subrec,"__SAMBA__",0x00,samba_nb_type,PERMANENT_TTL, PERMANENT_NAME, num_ips, iplist); - if(iplist != &subrec->myip) + if(iplist != &subrec->myip) { SAFE_FREE(iplist); + } } /**************************************************************************** - Dump the contents of the namelists on all the subnets (including unicast) - into a file. Initiated by SIGHUP - used to debug the state of the namelists. + Dump a name_record struct. **************************************************************************/ -static void dump_subnet_namelist( struct subnet_record *subrec, XFILE *fp) +void dump_name_record( struct name_record *namerec, XFILE *fp) { - 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,"\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,"Source = %s\nb_flags = %x\t", src_type, namerec->data.nb_flags); - 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"); - } + 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"); + } - 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"); - } + 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, "\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"); + +} + +/**************************************************************************** + Dump the contents of the namelists on all the subnets (including unicast) + into a file. Initiated by SIGHUP - used to debug the state of the namelists. +**************************************************************************/ - x_fprintf(fp, "\n\n"); +static void dump_subnet_namelist( struct subnet_record *subrec, XFILE *fp) +{ + struct name_record *namerec; + x_fprintf(fp, "Subnet %s\n----------------------\n", subrec->subnet_name); + for( namerec = subrec->namelist; namerec; namerec = namerec->next) { + dump_name_record(namerec, fp); } } @@ -569,16 +617,21 @@ void dump_all_namelists(void) return; } - for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec) ) + for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) { dump_subnet_namelist( subrec, fp ); + } - if( !we_are_a_wins_client() ) + if (!we_are_a_wins_client()) { dump_subnet_namelist( unicast_subnet, fp ); + } - if( remote_broadcast_subnet->namelist != NULL ) + if (remote_broadcast_subnet->namelist != NULL) { dump_subnet_namelist( remote_broadcast_subnet, fp ); + } + + if (wins_server_subnet != NULL) { + dump_wins_subnet_namelist(fp ); + } - if( wins_server_subnet != NULL ) - dump_subnet_namelist( wins_server_subnet, fp ); x_fclose( fp ); } diff --git a/source/nmbd/nmbd_subnetdb.c b/source/nmbd/nmbd_subnetdb.c index b53a6d7328f..b2e1178bebc 100644 --- a/source/nmbd/nmbd_subnetdb.c +++ b/source/nmbd/nmbd_subnetdb.c @@ -51,34 +51,6 @@ static void add_subnet(struct subnet_record *subrec) DLIST_ADD(subnetlist, subrec); } -/* ************************************************************************** ** - * Comparison routine for ordering the splay-tree based namelists assoicated - * with each subnet record. - * - * Input: Item - Pointer to the comparison key. - * Node - Pointer to a node the splay tree. - * - * Output: The return value will be <0 , ==0, or >0 depending upon the - * ordinal relationship of the two keys. - * - * ************************************************************************** ** - */ -static int namelist_entry_compare( ubi_trItemPtr Item, ubi_trNodePtr Node ) -{ - struct name_record *NR = (struct name_record *)Node; - - 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) ) ); -} - /**************************************************************************** stop listening on a subnet we don't free the record as we don't have proper reference counting for it @@ -156,10 +128,7 @@ static struct subnet_record *make_subnet(const char *name, enum subnet_type type return(NULL); } - memset( (char *)subrec, '\0', sizeof(*subrec) ); - (void)ubi_trInitTree( subrec->namelist, - namelist_entry_compare, - ubi_trOVERWRITE ); + ZERO_STRUCTP(subrec); if((subrec->subnet_name = SMB_STRDUP(name)) == NULL) { DEBUG(0,("make_subnet: malloc fail for subnet name !\n")); diff --git a/source/nmbd/nmbd_winsproxy.c b/source/nmbd/nmbd_winsproxy.c index 75319724616..d6dc6261c84 100644 --- a/source/nmbd/nmbd_winsproxy.c +++ b/source/nmbd/nmbd_winsproxy.c @@ -33,7 +33,7 @@ static void wins_proxy_name_query_request_success( struct subnet_record *subrec, unstring name; struct packet_struct *original_packet; struct subnet_record *orig_broadcast_subnet; - struct name_record *namerec; + struct name_record *namerec = NULL; uint16 nb_flags; int num_ips; int i; @@ -64,22 +64,34 @@ returned for name %s.\n", nmb_namestr(nmbname) )); return; } - for(i = 0; i < num_ips; i++) + 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. */ - if(rrec == PERMANENT_TTL) + if(rrec == PERMANENT_TTL) { ttl = lp_max_ttl(); + } pull_ascii_nstring(name, sizeof(name), nmbname->name); - namerec = add_name_to_subnet( orig_broadcast_subnet, name, + add_name_to_subnet( orig_broadcast_subnet, name, nmbname->name_type, nb_flags, ttl, WINS_PROXY_NAME, num_ips, iplist ); - if(iplist != &ip) + namerec = find_name_on_subnet(orig_broadcast_subnet, nmbname, FIND_ANY_NAME); + if (!namerec) { + DEBUG(0,("wins_proxy_name_query_request_success: failed to add " + "name %s to subnet %s !\n", + name, + orig_broadcast_subnet->subnet_name )); + return; + } + + if(iplist != &ip) { SAFE_FREE(iplist); + } /* * Check that none of the IP addresses we are returning is on the diff --git a/source/nmbd/nmbd_winsserver.c b/source/nmbd/nmbd_winsserver.c index 8a1f82c8b17..5c234bf8dcc 100644 --- a/source/nmbd/nmbd_winsserver.c +++ b/source/nmbd/nmbd_winsserver.c @@ -2,7 +2,7 @@ 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 @@ -18,12 +18,312 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + 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; + +/**************************************************************************** + 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; + } + + 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, 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 = 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 = 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); + if (!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); + SAFE_FREE(namerec->data.ip); + ZERO_STRUCTP(namerec); + SAFE_FREE(namerec); + 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. @@ -31,8 +331,6 @@ static void update_wins_owner(struct name_record *namerec, struct in_addr wins_ip) { - if (namerec==NULL) - return; namerec->data.wins_ip=wins_ip; } @@ -42,34 +340,35 @@ static void update_wins_owner(struct name_record *namerec, struct in_addr wins_i 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; @@ -95,12 +394,14 @@ static void get_global_id_and_update(SMB_BIG_UINT *current_id, BOOL update) *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) @@ -110,7 +411,11 @@ static void wins_hook(const char *operation, struct name_record *namerec, int tt 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))) { @@ -122,8 +427,9 @@ static void wins_hook(const char *operation, struct name_record *namerec, int tt /* Use the name without the nametype (and scope) appended */ namestr = nmb_namestr(&namerec->name); - if ((p = strchr(namestr, '<'))) + if ((p = strchr(namestr, '<'))) { *p = 0; + } p = command; p += slprintf(p, sizeof(command)-1, "%s %s %s %02x %d", @@ -141,7 +447,6 @@ static void wins_hook(const char *operation, struct name_record *namerec, int tt smbrun(command, NULL); } - /**************************************************************************** Determine if this packet should be allocated to the WINS server. *****************************************************************************/ @@ -157,8 +462,9 @@ BOOL packet_is_for_wins_server(struct packet_struct *packet) } /* 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) { /* @@ -210,11 +516,13 @@ static int get_ttl_from_packet(struct nmb_packet *nmb) { 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; } @@ -229,8 +537,19 @@ BOOL initialise_wins(void) 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); @@ -344,8 +663,9 @@ BOOL initialise_wins(void) 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); @@ -361,8 +681,9 @@ BOOL initialise_wins(void) /* 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)); @@ -370,7 +691,8 @@ BOOL initialise_wins(void) (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)); } @@ -396,16 +718,21 @@ static void send_wins_wack_response(int ttl, struct packet_struct *p) 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. */ @@ -545,7 +872,7 @@ void wins_process_name_refresh_request( struct subnet_record *subrec, * names update the ttl and return success. */ if( (!group || (group && (question->name_type == 0x1c))) - && find_ip_in_name_record(namerec, from_ip) ) { + && find_ip_in_name_record(namerec, from_ip) ) { /* * Update the ttl. */ @@ -584,6 +911,7 @@ void wins_process_name_refresh_request( struct subnet_record *subrec, * 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)) { @@ -669,16 +997,19 @@ static void wins_register_query_fail(struct subnet_record *subrec, 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); @@ -828,8 +1159,9 @@ to register name %s. Name already exists in WINS with source type %d.\n", * 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. @@ -876,6 +1208,7 @@ to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) )); 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 { @@ -905,8 +1238,11 @@ already exists in WINS as a GROUP name.\n", nmb_namestr(question) )); * reject without doing the query - we know we will reject it. */ - if ( namerec != NULL ) + if ( namerec != NULL ) { pull_ascii_nstring(name, sizeof(name), namerec->name.name); + } else { + name[0] = '\0'; + } if( is_myname(name) ) { if(!ismyip(from_ip)) { @@ -919,8 +1255,8 @@ is one of our (WINS server) names. Denying registration.\n", nmb_namestr(questio * 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); + send_wins_name_registration_response(0, ttl, p); return; } } @@ -940,8 +1276,8 @@ is one of our (WINS server) names. Denying registration.\n", nmb_namestr(questio && 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; } @@ -1061,15 +1397,16 @@ a subsequent IP address.\n", nmb_namestr(question_name) )); 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); @@ -1237,18 +1574,17 @@ is one of our (WINS server) names. Denying registration.\n", nmb_namestr(questio * 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; } @@ -1272,8 +1608,8 @@ is one of our (WINS server) names. Denying registration.\n", nmb_namestr(questio 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; } @@ -1348,6 +1684,37 @@ is one of our (WINS server) names. Denying registration.\n", nmb_namestr(questio } /*********************************************************************** + 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>. ***********************************************************************/ @@ -1365,10 +1732,13 @@ static void process_wins_dmb_query_request(struct subnet_record *subrec, */ 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 ) + + 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) { @@ -1391,9 +1761,8 @@ static void process_wins_dmb_query_request(struct subnet_record *subrec, */ 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); @@ -1465,8 +1834,9 @@ void send_wins_name_query_response(int rcode, struct packet_struct *p, prdata, /* data to send. */ reply_data_len); /* data length. */ - if(prdata != rdata) + if(prdata != rdata) { SAFE_FREE(prdata); + } } /*********************************************************************** @@ -1548,7 +1918,7 @@ void wins_process_name_query_request(struct subnet_record *subrec, 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; } @@ -1680,6 +2050,7 @@ release name %s as this record is not active anymore.\n", nmb_namestr(question) 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; } @@ -1689,118 +2060,235 @@ release name %s as this record is not active anymore.\n", nmb_namestr(question) * 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"); + struct name_record *nr = NULL; + struct name_record *nrnext = NULL; - if (!lasttime) + if (!lasttime) { lasttime = t; - if (t - lasttime < 20) + } + if (t - lasttime < 20) { return; + } + + if(!lp_we_are_a_wins_server()) { + lasttime = t; + return; + } + + tdb_traverse(wins_tdb, wins_processing_traverse_fn, &t); + + + /* 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); + } + + wins_write_database(t, True); lasttime = t; +} - if(!lp_we_are_a_wins_server()) - return; +/******************************************************************* + Write out one record. +******************************************************************/ - for( namerec = (struct name_record *)ubi_trFirst( wins_server_subnet->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, ( "initiate_wins_processing: 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; - } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) { - DEBUG(3,("initiate_wins_processing: deleting timed out DNS name %s\n", - nmb_namestr(&namerec->name))); - remove_name_from_namelist( wins_server_subnet, namerec ); - continue; - } +void wins_write_name_record(struct name_record *namerec, XFILE *fp) +{ + int i; + struct tm *tm; - /* 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; - } - } + DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) )); + + if( namerec->data.death_time != PERMANENT_TTL ) { + char *ts, *nl; + 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(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) { @@ -1808,6 +2296,11 @@ void wins_write_database(BOOL background) if (sys_fork()) { return; } + if (tdb_reopen(wins_tdb)) { + DEBUG(0,("wins_write_database: tdb_reopen failed. Error was %s\n", + strerror(errno))); + return; + } } slprintf(fname,sizeof(fname)-1,"%s/%s", lp_lockdir(), WINS_LIST); @@ -1826,41 +2319,8 @@ void wins_write_database(BOOL background) 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; - - 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 ")); - } + tdb_traverse(wins_tdb, wins_writedb_traverse_fn, fp); - 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 ) { - 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); - - 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); @@ -1870,6 +2330,8 @@ void wins_write_database(BOOL background) } } +#if 0 + Until winsrepl is done. /**************************************************************************** Process a internal Samba message receiving a wins record. ***************************************************************************/ @@ -1885,8 +2347,9 @@ void nmbd_wins_new_entry(int msg_type, struct process_id src, 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; @@ -1900,8 +2363,15 @@ void nmbd_wins_new_entry(int msg_type, struct process_id src, 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); @@ -2019,3 +2489,4 @@ void nmbd_wins_new_entry(int msg_type, struct process_id src, } } +#endif |