2 Unix SMB/CIFS implementation.
3 NBT netbios routines and daemon - version 2
5 Copyright (C) Jeremy Allison 1994-2005
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 Converted to store WINS data in a tdb. Dec 2005. JRA.
26 #define WINS_LIST "wins.dat"
27 #define WINS_VERSION 1
28 #define WINSDB_VERSION 1
30 /****************************************************************************
31 We don't store the NetBIOS scope in the wins.tdb. We key off the (utf8) netbios
32 name (65 bytes with the last byte being the name type).
33 *****************************************************************************/
35 TDB_CONTEXT *wins_tdb;
37 /****************************************************************************
38 Convert a wins.tdb record to a struct name_record. Add in our global_scope().
39 *****************************************************************************/
41 static struct name_record *wins_record_to_name_record(TDB_DATA key, TDB_DATA data)
43 struct name_record *namerec = NULL;
46 uint32 death_time, refresh_time;
47 uint32 id_low, id_high;
54 if (data.dptr == NULL || data.dsize == 0) {
58 /* Min size is "wbddddddd" + 1 ip address (4). */
59 if (data.dsize < 2 + 1 + (7*4) + 4) {
63 len = tdb_unpack(data.dptr, data.dsize,
75 namerec = SMB_MALLOC_P(struct name_record);
80 namerec->data.ip = SMB_MALLOC_ARRAY(struct in_addr, num_ips);
81 if (!namerec->data.ip) {
86 namerec->subnet = wins_server_subnet;
87 push_ascii_nstring(namerec->name.name, key.dptr);
88 namerec->name.name_type = key.dptr[sizeof(unstring)];
90 push_ascii(namerec->name.scope, global_scope(), 64, STR_TERMINATE);
92 /* We're using a byte-by-byte compare, so we must be sure that
93 * unused space doesn't have garbage in it.
96 for( i = strlen( namerec->name.name ); i < sizeof( namerec->name.name ); i++ ) {
97 namerec->name.name[i] = '\0';
99 for( i = strlen( namerec->name.scope ); i < sizeof( namerec->name.scope ); i++ ) {
100 namerec->name.scope[i] = '\0';
103 namerec->data.nb_flags = nb_flags;
104 namerec->data.source = (enum name_source)nr_src;
105 namerec->data.death_time = (time_t)death_time;
106 namerec->data.refresh_time = (time_t)refresh_time;
107 namerec->data.id = id_low;
108 #if defined(HAVE_LONGLONG)
109 namerec->data.id |= ((SMB_BIG_UINT)id_high << 32);
111 namerec->data.wins_ip.s_addr = saddr;
112 namerec->data.wins_flags = wins_flags,
113 namerec->data.num_ips = num_ips;
115 for (i = 0; i < num_ips; i++) {
116 namerec->data.ip[i].s_addr = IVAL(data.dptr, len + (i*4));
122 /****************************************************************************
123 Convert a struct name_record to a wins.tdb record. Ignore the scope.
124 *****************************************************************************/
126 static TDB_DATA name_record_to_wins_record(const struct name_record *namerec)
131 uint32 id_low = (namerec->data.id & 0xFFFFFFFF);
132 #if defined(HAVE_LONGLONG)
133 uint32 id_high = (namerec->data.id >> 32) & 0xFFFFFFFF;
140 len = (2 + 1 + (7*4)); /* "wbddddddd" */
141 len += (namerec->data.num_ips * 4);
143 data.dptr = SMB_MALLOC(len);
149 len = tdb_pack(data.dptr, data.dsize, "wbddddddd",
150 namerec->data.nb_flags,
151 (unsigned char)namerec->data.source,
152 (uint32)namerec->data.death_time,
153 (uint32)namerec->data.refresh_time,
156 (uint32)namerec->data.wins_ip.s_addr,
157 (uint32)namerec->data.wins_flags,
158 (uint32)namerec->data.num_ips );
160 for (i = 0; i < namerec->data.num_ips; i++) {
161 SIVAL(data.dptr, len + (i*4), namerec->data.ip[i].s_addr);
167 /****************************************************************************
168 Create key. Key is UNIX codepage namestring (usually utf8 64 byte len) with 1 byte type.
169 *****************************************************************************/
171 static TDB_DATA name_to_key(const struct nmb_name *nmbname)
173 static char keydata[sizeof(unstring) + 1];
176 memset(keydata, '\0', sizeof(keydata));
178 pull_ascii_nstring(keydata, sizeof(unstring), nmbname->name);
180 keydata[sizeof(unstring)] = nmbname->name_type;
182 key.dsize = sizeof(keydata);
187 /****************************************************************************
188 Lookup a given name in the wins.tdb and create a temporary malloc'ed data struct
189 on the linked list. We will free this later in XXXX().
190 *****************************************************************************/
192 struct name_record *find_name_on_wins_subnet(const struct nmb_name *nmbname, BOOL self_only)
195 struct name_record *nr = NULL;
196 struct name_record *namerec = NULL;
202 key = name_to_key(nmbname);
203 data = tdb_fetch(wins_tdb, key);
205 if (data.dsize == 0) {
209 namerec = wins_record_to_name_record(key, data);
214 /* Search for this name record on the list. Replace it if found. */
216 for( nr = wins_server_subnet->namelist; nr; nr = nr->next) {
217 if (memcmp(nmbname->name, nr->name.name, 16) == 0) {
219 DLIST_REMOVE(wins_server_subnet->namelist, nr);
220 SAFE_FREE(nr->data.ip);
226 DLIST_ADD(wins_server_subnet->namelist, namerec);
230 /****************************************************************************
231 Overwrite or add a given name in the wins.tdb.
232 *****************************************************************************/
234 static BOOL store_or_replace_wins_namerec(const struct name_record *namerec, int tdb_flag)
243 key = name_to_key(&namerec->name);
244 data = name_record_to_wins_record(namerec);
246 if (data.dptr == NULL) {
250 ret = tdb_store(wins_tdb, key, data, tdb_flag);
252 SAFE_FREE(data.dptr);
253 return (ret == 0) ? True : False;
256 /****************************************************************************
257 Overwrite a given name in the wins.tdb.
258 *****************************************************************************/
260 BOOL wins_store_changed_namerec(const struct name_record *namerec)
262 return store_or_replace_wins_namerec(namerec, TDB_REPLACE);
265 /****************************************************************************
266 Primary interface into creating and overwriting records in the wins.tdb.
267 *****************************************************************************/
269 BOOL add_name_to_wins_subnet(const struct name_record *namerec)
271 return store_or_replace_wins_namerec(namerec, TDB_INSERT);
274 /****************************************************************************
275 Delete a given name in the tdb and remove the temporary malloc'ed data struct
277 *****************************************************************************/
279 BOOL remove_name_from_wins_namelist(struct name_record *namerec)
288 key = name_to_key(&namerec->name);
289 ret = tdb_delete(wins_tdb, key);
291 DLIST_REMOVE(wins_server_subnet->namelist, namerec);
292 SAFE_FREE(namerec->data.ip);
293 ZERO_STRUCTP(namerec);
295 return (ret == 0) ? True : False;
298 /****************************************************************************
299 Dump out the complete namelist.
300 *****************************************************************************/
302 static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
304 struct name_record *namerec = NULL;
305 XFILE *fp = (XFILE *)state;
307 if (kbuf.dsize != sizeof(unstring) + 1) {
311 namerec = wins_record_to_name_record(kbuf, dbuf);
316 dump_name_record(namerec, fp);
318 SAFE_FREE(namerec->data.ip);
323 void dump_wins_subnet_namelist(XFILE *fp)
325 tdb_traverse(wins_tdb, traverse_fn, (void *)fp);
328 /****************************************************************************
329 Change the wins owner address in the record.
330 *****************************************************************************/
332 static void update_wins_owner(struct name_record *namerec, struct in_addr wins_ip)
334 namerec->data.wins_ip=wins_ip;
337 /****************************************************************************
338 Create the wins flags based on the nb flags and the input value.
339 *****************************************************************************/
341 static void update_wins_flag(struct name_record *namerec, int flags)
343 namerec->data.wins_flags=0x0;
345 /* if it's a group, it can be a normal or a special one */
346 if (namerec->data.nb_flags & NB_GROUP) {
347 if (namerec->name.name_type==0x1C) {
348 namerec->data.wins_flags|=WINS_SGROUP;
350 if (namerec->data.num_ips>1) {
351 namerec->data.wins_flags|=WINS_SGROUP;
353 namerec->data.wins_flags|=WINS_NGROUP;
357 /* can be unique or multi-homed */
358 if (namerec->data.num_ips>1) {
359 namerec->data.wins_flags|=WINS_MHOMED;
361 namerec->data.wins_flags|=WINS_UNIQUE;
365 /* the node type are the same bits */
366 namerec->data.wins_flags|=namerec->data.nb_flags&NB_NODETYPEMASK;
368 /* the static bit is elsewhere */
369 if (namerec->data.death_time == PERMANENT_TTL) {
370 namerec->data.wins_flags|=WINS_STATIC;
373 /* and add the given bits */
374 namerec->data.wins_flags|=flags;
376 DEBUG(8,("update_wins_flag: nbflags: 0x%x, ttl: 0x%d, flags: 0x%x, winsflags: 0x%x\n",
377 namerec->data.nb_flags, (int)namerec->data.death_time, flags, namerec->data.wins_flags));
380 /****************************************************************************
381 Return the general ID value and increase it if requested.
382 *****************************************************************************/
384 static void get_global_id_and_update(SMB_BIG_UINT *current_id, BOOL update)
387 * it's kept as a static here, to prevent people from messing
388 * with the value directly
391 static SMB_BIG_UINT general_id = 1;
393 DEBUG(5,("get_global_id_and_update: updating version ID: %d\n", (int)general_id));
395 *current_id = general_id;
402 /****************************************************************************
403 Possibly call the WINS hook external program when a WINS change is made.
404 Also stores the changed record back in the wins_tdb.
405 *****************************************************************************/
407 static void wins_hook(const char *operation, struct name_record *namerec, int ttl)
410 char *cmd = lp_wins_hook();
414 wins_store_changed_namerec(namerec);
420 for (p=namerec->name.name; *p; p++) {
421 if (!(isalnum((int)*p) || strchr_m("._-",*p))) {
422 DEBUG(3,("not calling wins hook for invalid name %s\n", nmb_namestr(&namerec->name)));
427 /* Use the name without the nametype (and scope) appended */
429 namestr = nmb_namestr(&namerec->name);
430 if ((p = strchr(namestr, '<'))) {
435 p += slprintf(p, sizeof(command)-1, "%s %s %s %02x %d",
439 namerec->name.name_type,
442 for (i=0;i<namerec->data.num_ips;i++) {
443 p += slprintf(p, sizeof(command) - (p-command) -1, " %s", inet_ntoa(namerec->data.ip[i]));
446 DEBUG(3,("calling wins hook for %s\n", nmb_namestr(&namerec->name)));
447 smbrun(command, NULL);
450 /****************************************************************************
451 Determine if this packet should be allocated to the WINS server.
452 *****************************************************************************/
454 BOOL packet_is_for_wins_server(struct packet_struct *packet)
456 struct nmb_packet *nmb = &packet->packet.nmb;
458 /* Only unicast packets go to a WINS server. */
459 if((wins_server_subnet == NULL) || (nmb->header.nm_flags.bcast == True)) {
460 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #1.\n"));
464 /* Check for node status requests. */
465 if (nmb->question.question_type != QUESTION_TYPE_NB_QUERY) {
469 switch(nmb->header.opcode) {
471 * A WINS server issues WACKS, not receives them.
473 case NMB_WACK_OPCODE:
474 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #2 (WACK).\n"));
477 * A WINS server only processes registration and
478 * release requests, not responses.
480 case NMB_NAME_REG_OPCODE:
481 case NMB_NAME_MULTIHOMED_REG_OPCODE:
482 case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
483 case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
484 if(nmb->header.response) {
485 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #3 (response = 1).\n"));
490 case NMB_NAME_RELEASE_OPCODE:
491 if(nmb->header.response) {
492 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #4 (response = 1).\n"));
498 * Only process unicast name queries with rd = 1.
500 case NMB_NAME_QUERY_OPCODE:
501 if(!nmb->header.response && !nmb->header.nm_flags.recursion_desired) {
502 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #5 (response = 1).\n"));
511 /****************************************************************************
512 Utility function to decide what ttl to give a register/refresh request.
513 *****************************************************************************/
515 static int get_ttl_from_packet(struct nmb_packet *nmb)
517 int ttl = nmb->additional->ttl;
519 if (ttl < lp_min_wins_ttl()) {
520 ttl = lp_min_wins_ttl();
523 if (ttl > lp_max_wins_ttl()) {
524 ttl = lp_max_wins_ttl();
530 /****************************************************************************
531 Load or create the WINS database.
532 *****************************************************************************/
534 BOOL initialise_wins(void)
536 time_t time_now = time(NULL);
540 if(!lp_we_are_a_wins_server()) {
544 /* Open the wins.tdb. */
545 wins_tdb = tdb_open_log(lock_path("wins.tdb"), 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST, O_CREAT|O_RDWR, 0600);
547 DEBUG(0,("initialise_wins: failed to open wins.tdb. Error was %s\n",
552 tdb_store_int32(wins_tdb, "WINSDB_VERSION", WINSDB_VERSION);
554 add_samba_names_to_subnet(wins_server_subnet);
556 if((fp = x_fopen(lock_path(WINS_LIST),O_RDONLY,0)) == NULL) {
557 DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
558 WINS_LIST, strerror(errno) ));
562 while (!x_feof(fp)) {
563 pstring name_str, ip_str, ttl_str, nb_flags_str;
564 unsigned int num_ips;
566 struct in_addr *ip_list;
578 /* Read a line from the wins.dat file. Strips whitespace
579 from the beginning and end of the line. */
580 if (!fgets_slash(line,sizeof(pstring),fp))
586 if (strncmp(line,"VERSION ", 8) == 0) {
587 if (sscanf(line,"VERSION %d %u", &version, &hash) != 2 ||
588 version != WINS_VERSION) {
589 DEBUG(0,("Discarding invalid wins.dat file [%s]\n",line));
599 * Now we handle multiple IP addresses per name we need
600 * to iterate over the line twice. The first time to
601 * determine how many IP addresses there are, the second
602 * time to actually parse them into the ip_list array.
605 if (!next_token(&ptr,name_str,NULL,sizeof(name_str))) {
606 DEBUG(0,("initialise_wins: Failed to parse name when parsing line %s\n", line ));
610 if (!next_token(&ptr,ttl_str,NULL,sizeof(ttl_str))) {
611 DEBUG(0,("initialise_wins: Failed to parse time to live when parsing line %s\n", line ));
616 * Determine the number of IP addresses per line.
620 got_token = next_token(&ptr,ip_str,NULL,sizeof(ip_str));
623 if(got_token && strchr(ip_str, '.')) {
627 } while( got_token && was_ip);
630 DEBUG(0,("initialise_wins: Missing IP address when parsing line %s\n", line ));
635 DEBUG(0,("initialise_wins: Missing nb_flags when parsing line %s\n", line ));
639 /* Allocate the space for the ip_list. */
640 if((ip_list = SMB_MALLOC_ARRAY( struct in_addr, num_ips)) == NULL) {
641 DEBUG(0,("initialise_wins: Malloc fail !\n"));
645 /* Reset and re-parse the line. */
647 next_token(&ptr,name_str,NULL,sizeof(name_str));
648 next_token(&ptr,ttl_str,NULL,sizeof(ttl_str));
649 for(i = 0; i < num_ips; i++) {
650 next_token(&ptr, ip_str, NULL, sizeof(ip_str));
651 ip_list[i] = *interpret_addr2(ip_str);
653 next_token(&ptr,nb_flags_str,NULL, sizeof(nb_flags_str));
656 * Deal with SELF or REGISTER name encoding. Default is REGISTER
657 * for compatibility with old nmbds.
660 if(nb_flags_str[strlen(nb_flags_str)-1] == 'S') {
661 DEBUG(5,("initialise_wins: Ignoring SELF name %s\n", line));
666 if(nb_flags_str[strlen(nb_flags_str)-1] == 'R') {
667 nb_flags_str[strlen(nb_flags_str)-1] = '\0';
670 /* Netbios name. # divides the name from the type (hex): netbios#xx */
671 pstrcpy(name,name_str);
673 if((p = strchr(name,'#')) != NULL) {
675 sscanf(p+1,"%x",&type);
678 /* Decode the netbios flags (hex) and the time-to-live (in seconds). */
679 sscanf(nb_flags_str,"%x",&nb_flags);
680 sscanf(ttl_str,"%d",&ttl);
682 /* add all entries that have 60 seconds or more to live */
683 if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) {
684 if(ttl != PERMANENT_TTL) {
688 DEBUG( 4, ("initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
689 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
691 (void)add_name_to_subnet( wins_server_subnet, name, type, nb_flags,
692 ttl, REGISTER_NAME, num_ips, ip_list );
694 DEBUG(4, ("initialise_wins: not adding name (ttl problem) "
695 "%s#%02x ttl = %d first IP %s flags = %2x\n",
696 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
706 /****************************************************************************
707 Send a WINS WACK (Wait ACKnowledgement) response.
708 **************************************************************************/
710 static void send_wins_wack_response(int ttl, struct packet_struct *p)
712 struct nmb_packet *nmb = &p->packet.nmb;
713 unsigned char rdata[2];
715 rdata[0] = rdata[1] = 0;
717 /* Taken from nmblib.c - we need to send back almost
718 identical bytes from the requesting packet header. */
720 rdata[0] = (nmb->header.opcode & 0xF) << 3;
721 if (nmb->header.nm_flags.authoritative && nmb->header.response) {
724 if (nmb->header.nm_flags.trunc) {
727 if (nmb->header.nm_flags.recursion_desired) {
730 if (nmb->header.nm_flags.recursion_available && nmb->header.response) {
733 if (nmb->header.nm_flags.bcast) {
737 reply_netbios_packet(p, /* Packet to reply to. */
738 0, /* Result code. */
739 NMB_WAIT_ACK, /* nmbd type code. */
740 NMB_WACK_OPCODE, /* opcode. */
742 (char *)rdata, /* data to send. */
743 2); /* data length. */
746 /****************************************************************************
747 Send a WINS name registration response.
748 **************************************************************************/
750 static void send_wins_name_registration_response(int rcode, int ttl, struct packet_struct *p)
752 struct nmb_packet *nmb = &p->packet.nmb;
755 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
757 reply_netbios_packet(p, /* Packet to reply to. */
758 rcode, /* Result code. */
759 WINS_REG, /* nmbd type code. */
760 NMB_NAME_REG_OPCODE, /* opcode. */
762 rdata, /* data to send. */
763 6); /* data length. */
766 /***********************************************************************
767 Deal with a name refresh request to a WINS server.
768 ************************************************************************/
770 void wins_process_name_refresh_request( struct subnet_record *subrec,
771 struct packet_struct *p )
773 struct nmb_packet *nmb = &p->packet.nmb;
774 struct nmb_name *question = &nmb->question.question_name;
775 BOOL bcast = nmb->header.nm_flags.bcast;
776 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
777 BOOL group = (nb_flags & NB_GROUP) ? True : False;
778 struct name_record *namerec = NULL;
779 int ttl = get_ttl_from_packet(nmb);
780 struct in_addr from_ip;
781 struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
783 putip( (char *)&from_ip, &nmb->additional->rdata[2] );
787 * We should only get unicast name refresh packets here.
788 * Anyone trying to refresh broadcast should not be going
789 * to a WINS server. Log an error here.
791 if( DEBUGLVL( 0 ) ) {
792 dbgtext( "wins_process_name_refresh_request: " );
793 dbgtext( "Broadcast name refresh request received " );
794 dbgtext( "for name %s ", nmb_namestr(question) );
795 dbgtext( "from IP %s ", inet_ntoa(from_ip) );
796 dbgtext( "on subnet %s. ", subrec->subnet_name );
797 dbgtext( "Error - Broadcasts should not be sent " );
798 dbgtext( "to a WINS server\n" );
803 if( DEBUGLVL( 3 ) ) {
804 dbgtext( "wins_process_name_refresh_request: " );
805 dbgtext( "Name refresh for name %s IP %s\n",
806 nmb_namestr(question), inet_ntoa(from_ip) );
810 * See if the name already exists.
811 * If not, handle it as a name registration and return.
813 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
816 * If this is a refresh request and the name doesn't exist then
817 * treat it like a registration request. This allows us to recover
818 * from errors (tridge)
820 if(namerec == NULL) {
821 if( DEBUGLVL( 3 ) ) {
822 dbgtext( "wins_process_name_refresh_request: " );
823 dbgtext( "Name refresh for name %s ",
824 nmb_namestr( question ) );
825 dbgtext( "and the name does not exist. Treating " );
826 dbgtext( "as registration.\n" );
828 wins_process_name_registration_request(subrec,p);
833 * if the name is present but not active, simply remove it
834 * and treat the refresh request as a registration & return.
836 if (namerec != NULL && !WINS_STATE_ACTIVE(namerec)) {
837 if( DEBUGLVL( 5 ) ) {
838 dbgtext( "wins_process_name_refresh_request: " );
839 dbgtext( "Name (%s) in WINS ", nmb_namestr(question) );
840 dbgtext( "was not active - removing it.\n" );
842 remove_name_from_namelist( subrec, namerec );
844 wins_process_name_registration_request( subrec, p );
849 * Check that the group bits for the refreshing name and the
850 * name in our database match. If not, refuse the refresh.
851 * [crh: Why RFS_ERR instead of ACT_ERR? Is this what MS does?]
853 if( (namerec != NULL) &&
854 ( (group && !NAME_GROUP(namerec))
855 || (!group && NAME_GROUP(namerec)) ) ) {
856 if( DEBUGLVL( 3 ) ) {
857 dbgtext( "wins_process_name_refresh_request: " );
858 dbgtext( "Name %s ", nmb_namestr(question) );
859 dbgtext( "group bit = %s does not match ",
860 group ? "True" : "False" );
861 dbgtext( "group bit in WINS for this name.\n" );
863 send_wins_name_registration_response(RFS_ERR, 0, p);
868 * For a unique name check that the person refreshing the name is
869 * one of the registered IP addresses. If not - fail the refresh.
870 * Do the same for group names with a type of 0x1c.
871 * Just return success for unique 0x1d refreshes. For normal group
872 * names update the ttl and return success.
874 if( (!group || (group && (question->name_type == 0x1c)))
875 && find_ip_in_name_record(namerec, from_ip) ) {
879 update_name_ttl(namerec, ttl);
882 * if the record is a replica:
883 * we take ownership and update the version ID.
885 if (!ip_equal(namerec->data.wins_ip, our_fake_ip)) {
886 update_wins_owner(namerec, our_fake_ip);
887 get_global_id_and_update(&namerec->data.id, True);
890 send_wins_name_registration_response(0, ttl, p);
891 wins_hook("refresh", namerec, ttl);
893 } else if((group && (question->name_type == 0x1c))) {
895 * Added by crh for bug #1079.
896 * Fix from Bert Driehuis
898 if( DEBUGLVL( 3 ) ) {
899 dbgtext( "wins_process_name_refresh_request: " );
900 dbgtext( "Name refresh for name %s, ",
901 nmb_namestr(question) );
902 dbgtext( "but IP address %s ", inet_ntoa(from_ip) );
903 dbgtext( "is not yet associated with " );
904 dbgtext( "that name. Treating as registration.\n" );
906 wins_process_name_registration_request(subrec,p);
910 * Normal groups are all registered with an IP address of
911 * 255.255.255.255 so we can't search for the IP address.
913 update_name_ttl(namerec, ttl);
914 wins_hook("refresh", namerec, ttl);
915 send_wins_name_registration_response(0, ttl, p);
917 } else if(!group && (question->name_type == 0x1d)) {
919 * Special name type - just pretend the refresh succeeded.
921 send_wins_name_registration_response(0, ttl, p);
927 if( DEBUGLVL( 3 ) ) {
928 dbgtext( "wins_process_name_refresh_request: " );
929 dbgtext( "Name refresh for name %s with IP %s ",
930 nmb_namestr(question), inet_ntoa(from_ip) );
931 dbgtext( "and is IP is not known to the name.\n" );
933 send_wins_name_registration_response(RFS_ERR, 0, p);
938 /***********************************************************************
939 Deal with a name registration request query success to a client that
942 We have a locked pointer to the original packet stashed away in the
943 userdata pointer. The success here is actually a failure as it means
944 the client we queried wants to keep the name, so we must return
945 a registration failure to the original requestor.
946 ************************************************************************/
948 static void wins_register_query_success(struct subnet_record *subrec,
949 struct userdata_struct *userdata,
950 struct nmb_name *question_name,
952 struct res_rec *answers)
954 struct packet_struct *orig_reg_packet;
956 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
958 DEBUG(3,("wins_register_query_success: Original client at IP %s still wants the \
959 name %s. Rejecting registration request.\n", inet_ntoa(ip), nmb_namestr(question_name) ));
961 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
963 orig_reg_packet->locked = False;
964 free_packet(orig_reg_packet);
967 /***********************************************************************
968 Deal with a name registration request query failure to a client that
971 We have a locked pointer to the original packet stashed away in the
972 userdata pointer. The failure here is actually a success as it means
973 the client we queried didn't want to keep the name, so we can remove
974 the old name record and then successfully add the new name.
975 ************************************************************************/
977 static void wins_register_query_fail(struct subnet_record *subrec,
978 struct response_record *rrec,
979 struct nmb_name *question_name,
982 struct userdata_struct *userdata = rrec->userdata;
983 struct packet_struct *orig_reg_packet;
984 struct name_record *namerec = NULL;
986 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
989 * We want to just add the name, as we now know the original owner
990 * didn't want it. But we can't just do that as an arbitary
991 * amount of time may have taken place between the name query
992 * request and this timeout/error response. So we check that
993 * the name still exists and is in the same state - if so
994 * we remove it and call wins_process_name_registration_request()
995 * as we know it will do the right thing now.
998 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1000 if ((namerec != NULL) && (namerec->data.source == REGISTER_NAME) &&
1001 ip_equal(rrec->packet->ip, *namerec->data.ip)) {
1002 remove_name_from_namelist( subrec, namerec);
1006 if(namerec == NULL) {
1007 wins_process_name_registration_request(subrec, orig_reg_packet);
1009 DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between "
1010 "querying for name %s in order to replace it and this reply.\n",
1011 nmb_namestr(question_name) ));
1014 orig_reg_packet->locked = False;
1015 free_packet(orig_reg_packet);
1018 /***********************************************************************
1019 Deal with a name registration request to a WINS server.
1021 Use the following pseudocode :
1026 +--------name exists
1029 | +--- existing name is group
1032 | | +--- add name (return).
1035 | +--- exiting name is unique
1038 | +--- query existing owner (return).
1041 +--------name doesn't exist
1044 +--- add name (return).
1049 +--------name exists
1052 | +--- existing name is group
1055 | | +--- fail add (return).
1058 | +--- exiting name is unique
1061 | +--- query existing owner (return).
1064 +--------name doesn't exist
1067 +--- add name (return).
1069 As can be seen from the above, the two cases may be collapsed onto each
1070 other with the exception of the case where the name already exists and
1071 is a group name. This case we handle with an if statement.
1073 ************************************************************************/
1075 void wins_process_name_registration_request(struct subnet_record *subrec,
1076 struct packet_struct *p)
1079 struct nmb_packet *nmb = &p->packet.nmb;
1080 struct nmb_name *question = &nmb->question.question_name;
1081 BOOL bcast = nmb->header.nm_flags.bcast;
1082 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
1083 int ttl = get_ttl_from_packet(nmb);
1084 struct name_record *namerec = NULL;
1085 struct in_addr from_ip;
1086 BOOL registering_group_name = (nb_flags & NB_GROUP) ? True : False;
1087 struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
1089 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1093 * We should only get unicast name registration packets here.
1094 * Anyone trying to register broadcast should not be going to a WINS
1095 * server. Log an error here.
1098 DEBUG(0,("wins_process_name_registration_request: broadcast name registration request \
1099 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1100 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1104 DEBUG(3,("wins_process_name_registration_request: %s name registration for name %s \
1105 IP %s\n", registering_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
1108 * See if the name already exists.
1111 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1114 * if the record exists but NOT in active state,
1117 if ( (namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1118 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1119 not active - removing it.\n", nmb_namestr(question) ));
1120 remove_name_from_namelist( subrec, namerec );
1125 * Deal with the case where the name found was a dns entry.
1126 * Remove it as we now have a NetBIOS client registering the
1130 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1131 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1132 a dns lookup - removing it.\n", nmb_namestr(question) ));
1133 remove_name_from_namelist( subrec, namerec );
1138 * Reject if the name exists and is not a REGISTER_NAME.
1139 * (ie. Don't allow any static names to be overwritten.
1142 if((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) {
1143 DEBUG( 3, ( "wins_process_name_registration_request: Attempt \
1144 to register name %s. Name already exists in WINS with source type %d.\n",
1145 nmb_namestr(question), namerec->data.source ));
1146 send_wins_name_registration_response(RFS_ERR, 0, p);
1151 * Special policy decisions based on MS documentation.
1152 * 1). All group names (except names ending in 0x1c) are added as 255.255.255.255.
1153 * 2). All unique names ending in 0x1d are ignored, although a positive response is sent.
1157 * A group name is always added as the local broadcast address, except
1158 * for group names ending in 0x1c.
1159 * Group names with type 0x1c are registered with individual IP addresses.
1162 if(registering_group_name && (question->name_type != 0x1c)) {
1163 from_ip = *interpret_addr2("255.255.255.255");
1167 * Ignore all attempts to register a unique 0x1d name, although return success.
1170 if(!registering_group_name && (question->name_type == 0x1d)) {
1171 DEBUG(3,("wins_process_name_registration_request: Ignoring request \
1172 to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
1173 send_wins_name_registration_response(0, ttl, p);
1178 * Next two cases are the 'if statement' mentioned above.
1181 if((namerec != NULL) && NAME_GROUP(namerec)) {
1182 if(registering_group_name) {
1184 * If we are adding a group name, the name exists and is also a group entry just add this
1185 * IP address to it and update the ttl.
1188 DEBUG(3,("wins_process_name_registration_request: Adding IP %s to group name %s.\n",
1189 inet_ntoa(from_ip), nmb_namestr(question) ));
1192 * Check the ip address is not already in the group.
1195 if(!find_ip_in_name_record(namerec, from_ip)) {
1196 add_ip_to_name_record(namerec, from_ip);
1197 /* we need to update the record for replication */
1198 get_global_id_and_update(&namerec->data.id, True);
1201 * if the record is a replica, we must change
1202 * the wins owner to us to make the replication updates
1203 * it on the other wins servers.
1204 * And when the partner will receive this record,
1205 * it will update its own record.
1208 update_wins_owner(namerec, our_fake_ip);
1210 update_name_ttl(namerec, ttl);
1211 wins_hook("refresh", namerec, ttl);
1212 send_wins_name_registration_response(0, ttl, p);
1217 * If we are adding a unique name, the name exists in the WINS db
1218 * and is a group name then reject the registration.
1220 * explanation: groups have a higher priority than unique names.
1223 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1224 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1225 send_wins_name_registration_response(RFS_ERR, 0, p);
1231 * From here on down we know that if the name exists in the WINS db it is
1232 * a unique name, not a group name.
1236 * If the name exists and is one of our names then check the
1237 * registering IP address. If it's not one of ours then automatically
1238 * reject without doing the query - we know we will reject it.
1241 if ( namerec != NULL ) {
1242 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
1247 if( is_myname(name) ) {
1248 if(!ismyip(from_ip)) {
1249 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1250 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1251 send_wins_name_registration_response(RFS_ERR, 0, p);
1255 * It's one of our names and one of our IP's - update the ttl.
1257 update_name_ttl(namerec, ttl);
1258 wins_hook("refresh", namerec, ttl);
1259 send_wins_name_registration_response(0, ttl, p);
1265 * If the name exists and it is a unique registration and the registering IP
1266 * is the same as the (single) already registered IP then just update the ttl.
1268 * But not if the record is an active replica. IF it's a replica, it means it can be
1269 * the same client which has moved and not yet expired. So we don't update
1270 * the ttl in this case and go beyond to do a WACK and query the old client
1273 if( !registering_group_name
1274 && (namerec != NULL)
1275 && (namerec->data.num_ips == 1)
1276 && ip_equal( namerec->data.ip[0], from_ip )
1277 && ip_equal(namerec->data.wins_ip, our_fake_ip) ) {
1278 update_name_ttl( namerec, ttl );
1279 wins_hook("refresh", namerec, ttl);
1280 send_wins_name_registration_response( 0, ttl, p );
1285 * Finally if the name exists do a query to the registering machine
1286 * to see if they still claim to have the name.
1289 if( namerec != NULL ) {
1290 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1291 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1294 * First send a WACK to the registering machine.
1297 send_wins_wack_response(60, p);
1300 * When the reply comes back we need the original packet.
1301 * Lock this so it won't be freed and then put it into
1302 * the userdata structure.
1307 userdata = (struct userdata_struct *)ud;
1309 userdata->copy_fn = NULL;
1310 userdata->free_fn = NULL;
1311 userdata->userdata_len = sizeof(struct packet_struct *);
1312 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1315 * Use the new call to send a query directly to an IP address.
1316 * This sends the query directly to the IP address, and ensures
1317 * the recursion desired flag is not set (you were right Luke :-).
1318 * This function should *only* be called from the WINS server
1322 pull_ascii_nstring(name, sizeof(name), question->name);
1323 query_name_from_wins_server( *namerec->data.ip,
1325 question->name_type,
1326 wins_register_query_success,
1327 wins_register_query_fail,
1333 * Name did not exist - add it.
1336 pull_ascii_nstring(name, sizeof(name), question->name);
1337 add_name_to_subnet( subrec, name, question->name_type,
1338 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1340 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1341 get_global_id_and_update(&namerec->data.id, True);
1342 update_wins_owner(namerec, our_fake_ip);
1343 update_wins_flag(namerec, WINS_ACTIVE);
1344 wins_hook("add", namerec, ttl);
1347 send_wins_name_registration_response(0, ttl, p);
1350 /***********************************************************************
1351 Deal with a mutihomed name query success to the machine that
1352 requested the multihomed name registration.
1354 We have a locked pointer to the original packet stashed away in the
1356 ************************************************************************/
1358 static void wins_multihomed_register_query_success(struct subnet_record *subrec,
1359 struct userdata_struct *userdata,
1360 struct nmb_name *question_name,
1362 struct res_rec *answers)
1364 struct packet_struct *orig_reg_packet;
1365 struct nmb_packet *nmb;
1366 struct name_record *namerec = NULL;
1367 struct in_addr from_ip;
1369 struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
1371 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1373 nmb = &orig_reg_packet->packet.nmb;
1375 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1376 ttl = get_ttl_from_packet(nmb);
1379 * We want to just add the new IP, as we now know the requesting
1380 * machine claims to own it. But we can't just do that as an arbitary
1381 * amount of time may have taken place between the name query
1382 * request and this response. So we check that
1383 * the name still exists and is in the same state - if so
1384 * we just add the extra IP and update the ttl.
1387 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1389 if( (namerec == NULL) || (namerec->data.source != REGISTER_NAME) || !WINS_STATE_ACTIVE(namerec) ) {
1390 DEBUG(3,("wins_multihomed_register_query_success: name %s is not in the correct state to add \
1391 a subsequent IP address.\n", nmb_namestr(question_name) ));
1392 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1394 orig_reg_packet->locked = False;
1395 free_packet(orig_reg_packet);
1400 if(!find_ip_in_name_record(namerec, from_ip)) {
1401 add_ip_to_name_record(namerec, from_ip);
1404 get_global_id_and_update(&namerec->data.id, True);
1405 update_wins_owner(namerec, our_fake_ip);
1406 update_wins_flag(namerec, WINS_ACTIVE);
1407 update_name_ttl(namerec, ttl);
1408 wins_hook("add", namerec, ttl);
1409 send_wins_name_registration_response(0, ttl, orig_reg_packet);
1411 orig_reg_packet->locked = False;
1412 free_packet(orig_reg_packet);
1415 /***********************************************************************
1416 Deal with a name registration request query failure to a client that
1419 We have a locked pointer to the original packet stashed away in the
1421 ************************************************************************/
1423 static void wins_multihomed_register_query_fail(struct subnet_record *subrec,
1424 struct response_record *rrec,
1425 struct nmb_name *question_name,
1428 struct userdata_struct *userdata = rrec->userdata;
1429 struct packet_struct *orig_reg_packet;
1431 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1433 DEBUG(3,("wins_multihomed_register_query_fail: Registering machine at IP %s failed to answer \
1434 query successfully for name %s.\n", inet_ntoa(orig_reg_packet->ip), nmb_namestr(question_name) ));
1435 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1437 orig_reg_packet->locked = False;
1438 free_packet(orig_reg_packet);
1442 /***********************************************************************
1443 Deal with a multihomed name registration request to a WINS server.
1444 These cannot be group name registrations.
1445 ***********************************************************************/
1447 void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
1448 struct packet_struct *p)
1450 struct nmb_packet *nmb = &p->packet.nmb;
1451 struct nmb_name *question = &nmb->question.question_name;
1452 BOOL bcast = nmb->header.nm_flags.bcast;
1453 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
1454 int ttl = get_ttl_from_packet(nmb);
1455 struct name_record *namerec = NULL;
1456 struct in_addr from_ip;
1457 BOOL group = (nb_flags & NB_GROUP) ? True : False;
1458 struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
1461 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1465 * We should only get unicast name registration packets here.
1466 * Anyone trying to register broadcast should not be going to a WINS
1467 * server. Log an error here.
1470 DEBUG(0,("wins_process_multihomed_name_registration_request: broadcast name registration request \
1471 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1472 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1477 * Only unique names should be registered multihomed.
1481 DEBUG(0,("wins_process_multihomed_name_registration_request: group name registration request \
1482 received for name %s from IP %s on subnet %s. Errror - group names should not be multihomed.\n",
1483 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1487 DEBUG(3,("wins_process_multihomed_name_registration_request: name registration for name %s \
1488 IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ));
1491 * Deal with policy regarding 0x1d names.
1494 if(question->name_type == 0x1d) {
1495 DEBUG(3,("wins_process_multihomed_name_registration_request: Ignoring request \
1496 to register name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
1497 send_wins_name_registration_response(0, ttl, p);
1502 * See if the name already exists.
1505 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1508 * if the record exists but NOT in active state,
1512 if ((namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1513 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was not active - removing it.\n", nmb_namestr(question)));
1514 remove_name_from_namelist(subrec, namerec);
1519 * Deal with the case where the name found was a dns entry.
1520 * Remove it as we now have a NetBIOS client registering the
1524 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1525 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was a dns lookup \
1526 - removing it.\n", nmb_namestr(question) ));
1527 remove_name_from_namelist( subrec, namerec);
1532 * Reject if the name exists and is not a REGISTER_NAME.
1533 * (ie. Don't allow any static names to be overwritten.
1536 if( (namerec != NULL) && (namerec->data.source != REGISTER_NAME) ) {
1537 DEBUG( 3, ( "wins_process_multihomed_name_registration_request: Attempt \
1538 to register name %s. Name already exists in WINS with source type %d.\n",
1539 nmb_namestr(question), namerec->data.source ));
1540 send_wins_name_registration_response(RFS_ERR, 0, p);
1545 * Reject if the name exists and is a GROUP name and is active.
1548 if((namerec != NULL) && NAME_GROUP(namerec) && WINS_STATE_ACTIVE(namerec)) {
1549 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1550 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1551 send_wins_name_registration_response(RFS_ERR, 0, p);
1556 * From here on down we know that if the name exists in the WINS db it is
1557 * a unique name, not a group name.
1561 * If the name exists and is one of our names then check the
1562 * registering IP address. If it's not one of ours then automatically
1563 * reject without doing the query - we know we will reject it.
1566 if((namerec != NULL) && (is_myname(namerec->name.name)) ) {
1567 if(!ismyip(from_ip)) {
1568 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1569 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1570 send_wins_name_registration_response(RFS_ERR, 0, p);
1574 * It's one of our names and one of our IP's. Ensure the IP is in the record and
1575 * update the ttl. Update the version ID to force replication.
1577 update_name_ttl(namerec, ttl);
1579 if(!find_ip_in_name_record(namerec, from_ip)) {
1580 get_global_id_and_update(&namerec->data.id, True);
1581 update_wins_owner(namerec, our_fake_ip);
1582 update_wins_flag(namerec, WINS_ACTIVE);
1584 add_ip_to_name_record(namerec, from_ip);
1587 wins_hook("refresh", namerec, ttl);
1588 send_wins_name_registration_response(0, ttl, p);
1594 * If the name exists and is active, check if the IP address is already registered
1595 * to that name. If so then update the ttl and reply success.
1598 if((namerec != NULL) && find_ip_in_name_record(namerec, from_ip) && WINS_STATE_ACTIVE(namerec)) {
1599 update_name_ttl(namerec, ttl);
1602 * If it's a replica, we need to become the wins owner
1603 * to force the replication
1605 if (!ip_equal(namerec->data.wins_ip, our_fake_ip)) {
1606 get_global_id_and_update(&namerec->data.id, True);
1607 update_wins_owner(namerec, our_fake_ip);
1608 update_wins_flag(namerec, WINS_ACTIVE);
1611 wins_hook("refresh", namerec, ttl);
1612 send_wins_name_registration_response(0, ttl, p);
1617 * If the name exists do a query to the owner
1618 * to see if they still want the name.
1621 if(namerec != NULL) {
1622 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1623 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1626 * First send a WACK to the registering machine.
1629 send_wins_wack_response(60, p);
1632 * When the reply comes back we need the original packet.
1633 * Lock this so it won't be freed and then put it into
1634 * the userdata structure.
1639 userdata = (struct userdata_struct *)ud;
1641 userdata->copy_fn = NULL;
1642 userdata->free_fn = NULL;
1643 userdata->userdata_len = sizeof(struct packet_struct *);
1644 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1647 * Use the new call to send a query directly to an IP address.
1648 * This sends the query directly to the IP address, and ensures
1649 * the recursion desired flag is not set (you were right Luke :-).
1650 * This function should *only* be called from the WINS server
1653 * Note that this packet is sent to the current owner of the name,
1654 * not the person who sent the packet
1657 pull_ascii_nstring( qname, sizeof(qname), question->name);
1658 query_name_from_wins_server( namerec->data.ip[0],
1660 question->name_type,
1661 wins_multihomed_register_query_success,
1662 wins_multihomed_register_query_fail,
1669 * Name did not exist - add it.
1672 pull_ascii_nstring( qname, sizeof(qname), question->name);
1673 add_name_to_subnet( subrec, qname, question->name_type,
1674 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1676 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1677 get_global_id_and_update(&namerec->data.id, True);
1678 update_wins_owner(namerec, our_fake_ip);
1679 update_wins_flag(namerec, WINS_ACTIVE);
1680 wins_hook("add", namerec, ttl);
1683 send_wins_name_registration_response(0, ttl, p);
1686 /***********************************************************************
1687 Fetch all *<1b> names from the WINS db and store on the namelist.
1688 ***********************************************************************/
1690 static int fetch_1b_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
1692 struct name_record *namerec = NULL;
1694 if (kbuf.dsize != sizeof(unstring) + 1) {
1698 /* Filter out all non-1b names. */
1699 if (kbuf.dptr[sizeof(unstring)] != 0x1b) {
1703 namerec = wins_record_to_name_record(kbuf, dbuf);
1708 DLIST_ADD(wins_server_subnet->namelist, namerec);
1712 void fetch_all_active_wins_1b_names(void)
1714 tdb_traverse(wins_tdb, fetch_1b_traverse_fn, NULL);
1717 /***********************************************************************
1718 Deal with the special name query for *<1b>.
1719 ***********************************************************************/
1721 static void process_wins_dmb_query_request(struct subnet_record *subrec,
1722 struct packet_struct *p)
1724 struct name_record *namerec = NULL;
1729 * Go through all the ACTIVE names in the WINS db looking for those
1730 * ending in <1b>. Use this to calculate the number of IP
1731 * addresses we need to return.
1736 fetch_all_active_wins_1b_names();
1738 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1739 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1740 num_ips += namerec->data.num_ips;
1746 * There are no 0x1b names registered. Return name query fail.
1748 send_wins_name_query_response(NAM_ERR, p, NULL);
1752 if((prdata = (char *)SMB_MALLOC( num_ips * 6 )) == NULL) {
1753 DEBUG(0,("process_wins_dmb_query_request: Malloc fail !.\n"));
1758 * Go through all the names again in the WINS db looking for those
1759 * ending in <1b>. Add their IP addresses into the list we will
1764 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1765 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1767 for(i = 0; i < namerec->data.num_ips; i++) {
1768 set_nb_flags(&prdata[num_ips * 6],namerec->data.nb_flags);
1769 putip((char *)&prdata[(num_ips * 6) + 2], &namerec->data.ip[i]);
1776 * Send back the reply containing the IP list.
1779 reply_netbios_packet(p, /* Packet to reply to. */
1780 0, /* Result code. */
1781 WINS_QUERY, /* nmbd type code. */
1782 NMB_NAME_QUERY_OPCODE, /* opcode. */
1783 lp_min_wins_ttl(), /* ttl. */
1784 prdata, /* data to send. */
1785 num_ips*6); /* data length. */
1790 /****************************************************************************
1791 Send a WINS name query response.
1792 **************************************************************************/
1794 void send_wins_name_query_response(int rcode, struct packet_struct *p,
1795 struct name_record *namerec)
1798 char *prdata = rdata;
1799 int reply_data_len = 0;
1803 memset(rdata,'\0',6);
1806 ttl = (namerec->data.death_time != PERMANENT_TTL) ? namerec->data.death_time - p->timestamp : lp_max_wins_ttl();
1808 /* Copy all known ip addresses into the return data. */
1809 /* Optimise for the common case of one IP address so we don't need a malloc. */
1811 if( namerec->data.num_ips == 1 ) {
1814 if((prdata = (char *)SMB_MALLOC( namerec->data.num_ips * 6 )) == NULL) {
1815 DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
1820 for(i = 0; i < namerec->data.num_ips; i++) {
1821 set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
1822 putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
1825 sort_query_replies(prdata, i, p->ip);
1826 reply_data_len = namerec->data.num_ips * 6;
1829 reply_netbios_packet(p, /* Packet to reply to. */
1830 rcode, /* Result code. */
1831 WINS_QUERY, /* nmbd type code. */
1832 NMB_NAME_QUERY_OPCODE, /* opcode. */
1834 prdata, /* data to send. */
1835 reply_data_len); /* data length. */
1837 if(prdata != rdata) {
1842 /***********************************************************************
1843 Deal with a name query.
1844 ***********************************************************************/
1846 void wins_process_name_query_request(struct subnet_record *subrec,
1847 struct packet_struct *p)
1849 struct nmb_packet *nmb = &p->packet.nmb;
1850 struct nmb_name *question = &nmb->question.question_name;
1851 struct name_record *namerec = NULL;
1854 DEBUG(3,("wins_process_name_query: name query for name %s from IP %s\n",
1855 nmb_namestr(question), inet_ntoa(p->ip) ));
1858 * Special name code. If the queried name is *<1b> then search
1859 * the entire WINS database and return a list of all the IP addresses
1860 * registered to any <1b> name. This is to allow domain master browsers
1861 * to discover other domains that may not have a presence on their subnet.
1864 pull_ascii_nstring(qname, sizeof(qname), question->name);
1865 if(strequal( qname, "*") && (question->name_type == 0x1b)) {
1866 process_wins_dmb_query_request( subrec, p);
1870 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1872 if(namerec != NULL) {
1874 * If the name is not anymore in active state then reply not found.
1875 * it's fair even if we keep it in the cache for days.
1877 if (!WINS_STATE_ACTIVE(namerec)) {
1878 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
1879 nmb_namestr(question) ));
1880 send_wins_name_query_response(NAM_ERR, p, namerec);
1885 * If it's a DNSFAIL_NAME then reply name not found.
1888 if( namerec->data.source == DNSFAIL_NAME ) {
1889 DEBUG(3,("wins_process_name_query: name query for name %s returning DNS fail.\n",
1890 nmb_namestr(question) ));
1891 send_wins_name_query_response(NAM_ERR, p, namerec);
1896 * If the name has expired then reply name not found.
1899 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < p->timestamp) ) {
1900 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
1901 nmb_namestr(question) ));
1902 send_wins_name_query_response(NAM_ERR, p, namerec);
1906 DEBUG(3,("wins_process_name_query: name query for name %s returning first IP %s.\n",
1907 nmb_namestr(question), inet_ntoa(namerec->data.ip[0]) ));
1909 send_wins_name_query_response(0, p, namerec);
1914 * Name not found in WINS - try a dns query if it's a 0x20 name.
1917 if(lp_dns_proxy() && ((question->name_type == 0x20) || question->name_type == 0)) {
1918 DEBUG(3,("wins_process_name_query: name query for name %s not found - doing dns lookup.\n",
1919 nmb_namestr(question) ));
1921 queue_dns_query(p, question);
1926 * Name not found - return error.
1929 send_wins_name_query_response(NAM_ERR, p, NULL);
1932 /****************************************************************************
1933 Send a WINS name release response.
1934 **************************************************************************/
1936 static void send_wins_name_release_response(int rcode, struct packet_struct *p)
1938 struct nmb_packet *nmb = &p->packet.nmb;
1941 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
1943 reply_netbios_packet(p, /* Packet to reply to. */
1944 rcode, /* Result code. */
1945 NMB_REL, /* nmbd type code. */
1946 NMB_NAME_RELEASE_OPCODE, /* opcode. */
1948 rdata, /* data to send. */
1949 6); /* data length. */
1952 /***********************************************************************
1953 Deal with a name release.
1954 ***********************************************************************/
1956 void wins_process_name_release_request(struct subnet_record *subrec,
1957 struct packet_struct *p)
1959 struct nmb_packet *nmb = &p->packet.nmb;
1960 struct nmb_name *question = &nmb->question.question_name;
1961 BOOL bcast = nmb->header.nm_flags.bcast;
1962 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
1963 struct name_record *namerec = NULL;
1964 struct in_addr from_ip;
1965 BOOL releasing_group_name = (nb_flags & NB_GROUP) ? True : False;;
1967 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1971 * We should only get unicast name registration packets here.
1972 * Anyone trying to register broadcast should not be going to a WINS
1973 * server. Log an error here.
1976 DEBUG(0,("wins_process_name_release_request: broadcast name registration request \
1977 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1978 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1982 DEBUG(3,("wins_process_name_release_request: %s name release for name %s \
1983 IP %s\n", releasing_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
1986 * Deal with policy regarding 0x1d names.
1989 if(!releasing_group_name && (question->name_type == 0x1d)) {
1990 DEBUG(3,("wins_process_name_release_request: Ignoring request \
1991 to release name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
1992 send_wins_name_release_response(0, p);
1997 * See if the name already exists.
2000 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2002 if( (namerec == NULL) || ((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) ) {
2003 send_wins_name_release_response(NAM_ERR, p);
2008 * Check that the sending machine has permission to release this name.
2009 * If it's a group name not ending in 0x1c then just say yes and let
2010 * the group time out.
2013 if(releasing_group_name && (question->name_type != 0x1c)) {
2014 send_wins_name_release_response(0, p);
2019 * Check that the releasing node is on the list of IP addresses
2020 * for this name. Disallow the release if not.
2023 if(!find_ip_in_name_record(namerec, from_ip)) {
2024 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2025 release name %s as IP %s is not one of the known IP's for this name.\n",
2026 nmb_namestr(question), inet_ntoa(from_ip) ));
2027 send_wins_name_release_response(NAM_ERR, p);
2032 * Check if the record is active. IF it's already released
2033 * or tombstoned, refuse the release.
2036 if (!WINS_STATE_ACTIVE(namerec)) {
2037 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2038 release name %s as this record is not active anymore.\n", nmb_namestr(question) ));
2039 send_wins_name_release_response(NAM_ERR, p);
2044 * Check if the record is a 0x1c group
2045 * and has more then one ip
2046 * remove only this address.
2049 if(releasing_group_name && (question->name_type == 0x1c) && (namerec->data.num_ips > 1)) {
2050 remove_ip_from_name_record(namerec, from_ip);
2051 DEBUG(3,("wins_process_name_release_request: Remove IP %s from NAME: %s\n",
2052 inet_ntoa(from_ip),nmb_namestr(question)));
2053 wins_hook("delete", namerec, 0);
2054 send_wins_name_release_response(0, p);
2059 * Send a release response.
2060 * Flag the name as released and update the ttl
2063 namerec->data.wins_flags |= WINS_RELEASED;
2064 update_name_ttl(namerec, EXTINCTION_INTERVAL);
2066 wins_hook("delete", namerec, 0);
2067 send_wins_name_release_response(0, p);
2070 /*******************************************************************
2071 WINS time dependent processing.
2072 ******************************************************************/
2074 static int wins_processing_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2076 time_t t = *(time_t *)state;
2077 BOOL store_record = False;
2078 struct name_record *namerec = NULL;
2079 struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
2081 if (kbuf.dsize != sizeof(unstring) + 1) {
2085 namerec = wins_record_to_name_record(kbuf, dbuf);
2090 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
2091 if( namerec->data.source == SELF_NAME ) {
2092 DEBUG( 3, ( "wins_processing_traverse_fn: Subnet %s not expiring SELF name %s\n",
2093 wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) );
2094 namerec->data.death_time += 300;
2095 store_record = True;
2097 } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) {
2098 DEBUG(3,("wins_processing_traverse_fn: deleting timed out DNS name %s\n",
2099 nmb_namestr(&namerec->name)));
2100 remove_name_from_wins_namelist(namerec );
2104 /* handle records, samba is the wins owner */
2105 if (ip_equal(namerec->data.wins_ip, our_fake_ip)) {
2106 switch (namerec->data.wins_flags | WINS_STATE_MASK) {
2108 namerec->data.wins_flags&=~WINS_STATE_MASK;
2109 namerec->data.wins_flags|=WINS_RELEASED;
2110 namerec->data.death_time = t + EXTINCTION_INTERVAL;
2111 DEBUG(3,("wins_processing_traverse_fn: expiring %s\n",
2112 nmb_namestr(&namerec->name)));
2113 store_record = True;
2116 namerec->data.wins_flags&=~WINS_STATE_MASK;
2117 namerec->data.wins_flags|=WINS_TOMBSTONED;
2118 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2119 get_global_id_and_update(&namerec->data.id, True);
2120 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2121 nmb_namestr(&namerec->name)));
2122 store_record = True;
2124 case WINS_TOMBSTONED:
2125 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2126 nmb_namestr(&namerec->name)));
2127 remove_name_from_wins_namelist(namerec );
2131 switch (namerec->data.wins_flags | WINS_STATE_MASK) {
2133 /* that's not as MS says it should be */
2134 namerec->data.wins_flags&=~WINS_STATE_MASK;
2135 namerec->data.wins_flags|=WINS_TOMBSTONED;
2136 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2137 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2138 nmb_namestr(&namerec->name)));
2139 store_record = True;
2141 case WINS_TOMBSTONED:
2142 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2143 nmb_namestr(&namerec->name)));
2144 remove_name_from_wins_namelist(namerec );
2147 DEBUG(0,("wins_processing_traverse_fn: %s is in released state and\
2148 we are not the wins owner !\n", nmb_namestr(&namerec->name)));
2157 wins_store_changed_namerec(namerec);
2160 SAFE_FREE(namerec->data.ip);
2166 /*******************************************************************
2167 Time dependent wins processing.
2168 ******************************************************************/
2170 void initiate_wins_processing(time_t t)
2172 static time_t lasttime = 0;
2173 struct name_record *nr = NULL;
2174 struct name_record *nrnext = NULL;
2179 if (t - lasttime < 20) {
2183 if(!lp_we_are_a_wins_server()) {
2188 tdb_traverse(wins_tdb, wins_processing_traverse_fn, &t);
2191 /* Delete all temporary name records on the wins subnet linked list. */
2192 for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
2194 DLIST_REMOVE(wins_server_subnet->namelist, nr);
2195 SAFE_FREE(nr->data.ip);
2199 wins_write_database(t, True);
2204 /*******************************************************************
2205 Write out one record.
2206 ******************************************************************/
2208 void wins_write_name_record(struct name_record *namerec, XFILE *fp)
2213 DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) ));
2215 if( namerec->data.death_time != PERMANENT_TTL ) {
2218 tm = localtime(&namerec->data.death_time);
2220 nl = strrchr( ts, '\n' );
2224 DEBUGADD(4,("TTL = %s ", ts ));
2226 DEBUGADD(4,("TTL = PERMANENT "));
2229 for (i = 0; i < namerec->data.num_ips; i++) {
2230 DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) ));
2232 DEBUGADD(4,("%2x\n", namerec->data.nb_flags ));
2234 if( namerec->data.source == REGISTER_NAME ) {
2236 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
2237 x_fprintf(fp, "\"%s#%02x\" %d ", name,namerec->name.name_type, /* Ignore scope. */
2238 (int)namerec->data.death_time);
2240 for (i = 0; i < namerec->data.num_ips; i++)
2241 x_fprintf( fp, "%s ", inet_ntoa( namerec->data.ip[i] ) );
2242 x_fprintf( fp, "%2xR\n", namerec->data.nb_flags );
2246 /*******************************************************************
2247 Write out the current WINS database.
2248 ******************************************************************/
2250 static int wins_writedb_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2252 struct name_record *namerec = NULL;
2253 XFILE *fp = (XFILE *)state;
2255 if (kbuf.dsize != sizeof(unstring) + 1) {
2259 namerec = wins_record_to_name_record(kbuf, dbuf);
2264 wins_write_name_record(namerec, fp);
2266 SAFE_FREE(namerec->data.ip);
2272 void wins_write_database(time_t t, BOOL background)
2274 static time_t last_write_time = 0;
2275 pstring fname, fnamenew;
2280 if (!last_write_time) {
2281 last_write_time = t;
2283 if (t - last_write_time < 120) {
2289 if(!lp_we_are_a_wins_server()) {
2293 /* We will do the writing in a child process to ensure that the parent doesn't block while this is done */
2299 if (tdb_reopen(wins_tdb)) {
2300 DEBUG(0,("wins_write_database: tdb_reopen failed. Error was %s\n",
2306 slprintf(fname,sizeof(fname)-1,"%s/%s", lp_lockdir(), WINS_LIST);
2307 all_string_sub(fname,"//", "/", 0);
2308 slprintf(fnamenew,sizeof(fnamenew)-1,"%s.%u", fname, (unsigned int)sys_getpid());
2310 if((fp = x_fopen(fnamenew,O_WRONLY|O_CREAT,0644)) == NULL) {
2311 DEBUG(0,("wins_write_database: Can't open %s. Error was %s\n", fnamenew, strerror(errno)));
2318 DEBUG(4,("wins_write_database: Dump of WINS name list.\n"));
2320 x_fprintf(fp,"VERSION %d %u\n", WINS_VERSION, 0);
2322 tdb_traverse(wins_tdb, wins_writedb_traverse_fn, fp);
2325 chmod(fnamenew,0644);
2327 rename(fnamenew,fname);
2334 Until winsrepl is done.
2335 /****************************************************************************
2336 Process a internal Samba message receiving a wins record.
2337 ***************************************************************************/
2339 void nmbd_wins_new_entry(int msg_type, struct process_id src,
2340 void *buf, size_t len)
2342 WINS_RECORD *record;
2343 struct name_record *namerec = NULL;
2344 struct name_record *new_namerec = NULL;
2345 struct nmb_name question;
2346 BOOL overwrite=False;
2347 struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
2354 /* Record should use UNIX codepage. Ensure this is so in the wrepld code. JRA. */
2355 record=(WINS_RECORD *)buf;
2357 make_nmb_name(&question, record->name, record->type);
2359 namerec = find_name_on_subnet(wins_server_subnet, &question, FIND_ANY_NAME);
2361 /* record doesn't exist, add it */
2362 if (namerec == NULL) {
2363 DEBUG(3,("nmbd_wins_new_entry: adding new replicated record: %s<%02x> for wins server: %s\n",
2364 record->name, record->type, inet_ntoa(record->wins_ip)));
2366 new_namerec=add_name_to_subnet( wins_server_subnet,
2370 EXTINCTION_INTERVAL,
2375 if (new_namerec!=NULL) {
2376 update_wins_owner(new_namerec, record->wins_ip);
2377 update_wins_flag(new_namerec, record->wins_flags);
2378 new_namerec->data.id=record->id;
2380 wins_server_subnet->namelist_changed = True;
2384 /* check if we have a conflict */
2385 if (namerec != NULL) {
2386 /* both records are UNIQUE */
2387 if (namerec->data.wins_flags&WINS_UNIQUE && record->wins_flags&WINS_UNIQUE) {
2389 /* the database record is a replica */
2390 if (!ip_equal(namerec->data.wins_ip, our_fake_ip)) {
2391 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED) {
2392 if (ip_equal(namerec->data.wins_ip, record->wins_ip))
2397 /* we are the wins owner of the database record */
2398 /* the 2 records have the same IP address */
2399 if (ip_equal(namerec->data.ip[0], record->ip[0])) {
2400 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED)
2401 get_global_id_and_update(&namerec->data.id, True);
2406 /* the 2 records have different IP address */
2407 if (namerec->data.wins_flags&WINS_ACTIVE) {
2408 if (record->wins_flags&WINS_TOMBSTONED)
2409 get_global_id_and_update(&namerec->data.id, True);
2410 if (record->wins_flags&WINS_ACTIVE)
2411 /* send conflict challenge to the replica node */
2420 /* the replica is a standard group */
2421 if (record->wins_flags&WINS_NGROUP || record->wins_flags&WINS_SGROUP) {
2422 /* if the database record is unique and active force a name release */
2423 if (namerec->data.wins_flags&WINS_UNIQUE)
2424 /* send a release name to the unique node */
2430 /* the replica is a special group */
2431 if (record->wins_flags&WINS_SGROUP && namerec->data.wins_flags&WINS_SGROUP) {
2432 if (namerec->data.wins_flags&WINS_ACTIVE) {
2433 for (i=0; i<record->num_ips; i++)
2434 if(!find_ip_in_name_record(namerec, record->ip[i]))
2435 add_ip_to_name_record(namerec, record->ip[i]);
2441 /* the replica is a multihomed host */
2443 /* I'm giving up on multi homed. Too much complex to understand */
2445 if (record->wins_flags&WINS_MHOMED) {
2446 if (! (namerec->data.wins_flags&WINS_ACTIVE)) {
2447 if ( !(namerec->data.wins_flags&WINS_RELEASED) && !(namerec->data.wins_flags&WINS_NGROUP))
2451 if (ip_equal(record->wins_ip, namerec->data.wins_ip))
2454 if (ip_equal(namerec->data.wins_ip, our_fake_ip))
2455 if (namerec->data.wins_flags&WINS_UNIQUE)
2456 get_global_id_and_update(&namerec->data.id, True);
2460 if (record->wins_flags&WINS_ACTIVE && namerec->data.wins_flags&WINS_ACTIVE)
2461 if (namerec->data.wins_flags&WINS_UNIQUE ||
2462 namerec->data.wins_flags&WINS_MHOMED)
2463 if (ip_equal(record->wins_ip, namerec->data.wins_ip))
2468 if (overwrite == False)
2469 DEBUG(3, ("nmbd_wins_new_entry: conflict in adding record: %s<%02x> from wins server: %s\n",
2470 record->name, record->type, inet_ntoa(record->wins_ip)));
2472 DEBUG(3, ("nmbd_wins_new_entry: replacing record: %s<%02x> from wins server: %s\n",
2473 record->name, record->type, inet_ntoa(record->wins_ip)));
2475 /* remove the old record and add a new one */
2476 remove_name_from_namelist( wins_server_subnet, namerec );
2477 new_namerec=add_name_to_subnet( wins_server_subnet, record->name, record->type, record->nb_flags,
2478 EXTINCTION_INTERVAL, REGISTER_NAME, record->num_ips, record->ip);
2479 if (new_namerec!=NULL) {
2480 update_wins_owner(new_namerec, record->wins_ip);
2481 update_wins_flag(new_namerec, record->wins_flags);
2482 new_namerec->data.id=record->id;
2484 wins_server_subnet->namelist_changed = True;
2487 wins_server_subnet->namelist_changed = True;