s3:smbXsrv_tcon: add smbXsrv_tcon_global_traverse()
[Samba.git] / source3 / nmbd / nmbd_winsserver.c
blob6524284791697c9ab1b9bea199fa229fcfe53549
1 /*
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 3 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, see <http://www.gnu.org/licenses/>.
20 Converted to store WINS data in a tdb. Dec 2005. JRA.
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include "nmbd/nmbd.h"
26 #include "util_tdb.h"
28 #define WINS_LIST "wins.dat"
29 #define WINS_VERSION 1
30 #define WINSDB_VERSION 1
32 /****************************************************************************
33 We don't store the NetBIOS scope in the wins.tdb. We key off the (utf8) netbios
34 name (65 bytes with the last byte being the name type).
35 *****************************************************************************/
37 TDB_CONTEXT *wins_tdb;
39 /****************************************************************************
40 Delete all the temporary name records on the in-memory linked list.
41 *****************************************************************************/
43 static void wins_delete_all_tmp_in_memory_records(void)
45 struct name_record *nr = NULL;
46 struct name_record *nrnext = NULL;
48 /* Delete all temporary name records on the wins subnet linked list. */
49 for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
50 nrnext = nr->next;
51 DLIST_REMOVE(wins_server_subnet->namelist, nr);
52 SAFE_FREE(nr->data.ip);
53 SAFE_FREE(nr);
57 /****************************************************************************
58 Delete all the temporary 1b name records on the in-memory linked list.
59 *****************************************************************************/
61 static void wins_delete_all_1b_in_memory_records(void)
63 struct name_record *nr = NULL;
64 struct name_record *nrnext = NULL;
66 /* Delete all temporary 1b name records on the wins subnet linked list. */
67 for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
68 nrnext = nr->next;
69 if (nr->name.name_type == 0x1b) {
70 DLIST_REMOVE(wins_server_subnet->namelist, nr);
71 SAFE_FREE(nr->data.ip);
72 SAFE_FREE(nr);
77 /****************************************************************************
78 Convert a wins.tdb record to a struct name_record. Add in our lp_netbios_scope().
79 *****************************************************************************/
81 static struct name_record *wins_record_to_name_record(TDB_DATA key, TDB_DATA data)
83 struct name_record *namerec = NULL;
84 uint16 nb_flags;
85 unsigned char nr_src;
86 uint32 death_time, refresh_time;
87 uint32 id_low, id_high;
88 uint32 saddr;
89 uint32 wins_flags;
90 uint32 num_ips;
91 size_t len;
92 int i;
94 if (data.dptr == NULL || data.dsize == 0) {
95 return NULL;
98 /* Min size is "wbddddddd" + 1 ip address (4). */
99 if (data.dsize < 2 + 1 + (7*4) + 4) {
100 return NULL;
103 len = tdb_unpack(data.dptr, data.dsize,
104 "wbddddddd",
105 &nb_flags,
106 &nr_src,
107 &death_time,
108 &refresh_time,
109 &id_low,
110 &id_high,
111 &saddr,
112 &wins_flags,
113 &num_ips );
115 namerec = SMB_MALLOC_P(struct name_record);
116 if (!namerec) {
117 return NULL;
119 ZERO_STRUCTP(namerec);
121 namerec->data.ip = SMB_MALLOC_ARRAY(struct in_addr, num_ips);
122 if (!namerec->data.ip) {
123 SAFE_FREE(namerec);
124 return NULL;
127 namerec->subnet = wins_server_subnet;
128 push_ascii_nstring(namerec->name.name, (const char *)key.dptr);
129 namerec->name.name_type = key.dptr[sizeof(unstring)];
130 /* Add the scope. */
131 push_ascii(namerec->name.scope, lp_netbios_scope(), 64, STR_TERMINATE);
133 /* We're using a byte-by-byte compare, so we must be sure that
134 * unused space doesn't have garbage in it.
137 for( i = strlen( namerec->name.name ); i < sizeof( namerec->name.name ); i++ ) {
138 namerec->name.name[i] = '\0';
140 for( i = strlen( namerec->name.scope ); i < sizeof( namerec->name.scope ); i++ ) {
141 namerec->name.scope[i] = '\0';
144 namerec->data.nb_flags = nb_flags;
145 namerec->data.source = (enum name_source)nr_src;
146 namerec->data.death_time = (time_t)death_time;
147 namerec->data.refresh_time = (time_t)refresh_time;
148 namerec->data.id = id_low;
149 #if defined(HAVE_LONGLONG)
150 namerec->data.id |= ((uint64_t)id_high << 32);
151 #endif
152 namerec->data.wins_ip.s_addr = saddr;
153 namerec->data.wins_flags = wins_flags,
154 namerec->data.num_ips = num_ips;
156 for (i = 0; i < num_ips; i++) {
157 namerec->data.ip[i].s_addr = IVAL(data.dptr, len + (i*4));
160 return namerec;
163 /****************************************************************************
164 Convert a struct name_record to a wins.tdb record. Ignore the scope.
165 *****************************************************************************/
167 static TDB_DATA name_record_to_wins_record(const struct name_record *namerec)
169 TDB_DATA data;
170 size_t len = 0;
171 int i;
172 uint32 id_low = (namerec->data.id & 0xFFFFFFFF);
173 #if defined(HAVE_LONGLONG)
174 uint32 id_high = (namerec->data.id >> 32) & 0xFFFFFFFF;
175 #else
176 uint32 id_high = 0;
177 #endif
179 ZERO_STRUCT(data);
181 len = (2 + 1 + (7*4)); /* "wbddddddd" */
182 len += (namerec->data.num_ips * 4);
184 data.dptr = (uint8 *)SMB_MALLOC(len);
185 if (!data.dptr) {
186 return data;
188 data.dsize = len;
190 len = tdb_pack(data.dptr, data.dsize, "wbddddddd",
191 namerec->data.nb_flags,
192 (unsigned char)namerec->data.source,
193 (uint32)namerec->data.death_time,
194 (uint32)namerec->data.refresh_time,
195 id_low,
196 id_high,
197 (uint32)namerec->data.wins_ip.s_addr,
198 (uint32)namerec->data.wins_flags,
199 (uint32)namerec->data.num_ips );
201 for (i = 0; i < namerec->data.num_ips; i++) {
202 SIVAL(data.dptr, len + (i*4), namerec->data.ip[i].s_addr);
205 return data;
208 /****************************************************************************
209 Create key. Key is UNIX codepage namestring (usually utf8 64 byte len) with 1 byte type.
210 *****************************************************************************/
212 static TDB_DATA name_to_key(const struct nmb_name *nmbname)
214 static char keydata[sizeof(unstring) + 1];
215 TDB_DATA key;
217 memset(keydata, '\0', sizeof(keydata));
219 pull_ascii_nstring(keydata, sizeof(unstring), nmbname->name);
220 (void)strupper_m(keydata);
221 keydata[sizeof(unstring)] = nmbname->name_type;
222 key.dptr = (uint8 *)keydata;
223 key.dsize = sizeof(keydata);
225 return key;
228 /****************************************************************************
229 Lookup a given name in the wins.tdb and create a temporary malloc'ed data struct
230 on the linked list. We will free this later in XXXX().
231 *****************************************************************************/
233 struct name_record *find_name_on_wins_subnet(const struct nmb_name *nmbname, bool self_only)
235 TDB_DATA data, key;
236 struct name_record *nr = NULL;
237 struct name_record *namerec = NULL;
239 if (!wins_tdb) {
240 return NULL;
243 key = name_to_key(nmbname);
244 data = tdb_fetch_compat(wins_tdb, key);
246 if (data.dsize == 0) {
247 return NULL;
250 namerec = wins_record_to_name_record(key, data);
252 /* done with the this */
254 SAFE_FREE( data.dptr );
256 if (!namerec) {
257 return NULL;
260 /* Self names only - these include permanent names. */
261 if( self_only && (namerec->data.source != SELF_NAME) && (namerec->data.source != PERMANENT_NAME) ) {
262 DEBUG( 9, ( "find_name_on_wins_subnet: self name %s NOT FOUND\n", nmb_namestr(nmbname) ) );
263 SAFE_FREE(namerec->data.ip);
264 SAFE_FREE(namerec);
265 return NULL;
268 /* Search for this name record on the list. Replace it if found. */
270 for( nr = wins_server_subnet->namelist; nr; nr = nr->next) {
271 if (memcmp(nmbname->name, nr->name.name, 16) == 0) {
272 /* Delete it. */
273 DLIST_REMOVE(wins_server_subnet->namelist, nr);
274 SAFE_FREE(nr->data.ip);
275 SAFE_FREE(nr);
276 break;
280 DLIST_ADD(wins_server_subnet->namelist, namerec);
281 return namerec;
284 /****************************************************************************
285 Overwrite or add a given name in the wins.tdb.
286 *****************************************************************************/
288 static bool store_or_replace_wins_namerec(const struct name_record *namerec, int tdb_flag)
290 TDB_DATA key, data;
291 int ret;
293 if (!wins_tdb) {
294 return False;
297 key = name_to_key(&namerec->name);
298 data = name_record_to_wins_record(namerec);
300 if (data.dptr == NULL) {
301 return False;
304 ret = tdb_store(wins_tdb, key, data, tdb_flag);
306 SAFE_FREE(data.dptr);
307 return (ret == 0) ? True : False;
310 /****************************************************************************
311 Overwrite a given name in the wins.tdb.
312 *****************************************************************************/
314 bool wins_store_changed_namerec(const struct name_record *namerec)
316 return store_or_replace_wins_namerec(namerec, TDB_REPLACE);
319 /****************************************************************************
320 Primary interface into creating and overwriting records in the wins.tdb.
321 *****************************************************************************/
323 bool add_name_to_wins_subnet(const struct name_record *namerec)
325 return store_or_replace_wins_namerec(namerec, TDB_INSERT);
328 /****************************************************************************
329 Delete a given name in the tdb and remove the temporary malloc'ed data struct
330 on the linked list.
331 *****************************************************************************/
333 bool remove_name_from_wins_namelist(struct name_record *namerec)
335 TDB_DATA key;
336 int ret;
338 if (!wins_tdb) {
339 return False;
342 key = name_to_key(&namerec->name);
343 ret = tdb_delete(wins_tdb, key);
345 DLIST_REMOVE(wins_server_subnet->namelist, namerec);
347 /* namerec must be freed by the caller */
349 return (ret == 0) ? True : False;
352 /****************************************************************************
353 Dump out the complete namelist.
354 *****************************************************************************/
356 static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
358 struct name_record *namerec = NULL;
359 XFILE *fp = (XFILE *)state;
361 if (kbuf.dsize != sizeof(unstring) + 1) {
362 return 0;
365 namerec = wins_record_to_name_record(kbuf, dbuf);
366 if (!namerec) {
367 return 0;
370 dump_name_record(namerec, fp);
372 SAFE_FREE(namerec->data.ip);
373 SAFE_FREE(namerec);
374 return 0;
377 void dump_wins_subnet_namelist(XFILE *fp)
379 tdb_traverse(wins_tdb, traverse_fn, (void *)fp);
382 /****************************************************************************
383 Change the wins owner address in the record.
384 *****************************************************************************/
386 static void update_wins_owner(struct name_record *namerec, struct in_addr wins_ip)
388 namerec->data.wins_ip=wins_ip;
391 /****************************************************************************
392 Create the wins flags based on the nb flags and the input value.
393 *****************************************************************************/
395 static void update_wins_flag(struct name_record *namerec, int flags)
397 namerec->data.wins_flags=0x0;
399 /* if it's a group, it can be a normal or a special one */
400 if (namerec->data.nb_flags & NB_GROUP) {
401 if (namerec->name.name_type==0x1C) {
402 namerec->data.wins_flags|=WINS_SGROUP;
403 } else {
404 if (namerec->data.num_ips>1) {
405 namerec->data.wins_flags|=WINS_SGROUP;
406 } else {
407 namerec->data.wins_flags|=WINS_NGROUP;
410 } else {
411 /* can be unique or multi-homed */
412 if (namerec->data.num_ips>1) {
413 namerec->data.wins_flags|=WINS_MHOMED;
414 } else {
415 namerec->data.wins_flags|=WINS_UNIQUE;
419 /* the node type are the same bits */
420 namerec->data.wins_flags|=namerec->data.nb_flags&NB_NODETYPEMASK;
422 /* the static bit is elsewhere */
423 if (namerec->data.death_time == PERMANENT_TTL) {
424 namerec->data.wins_flags|=WINS_STATIC;
427 /* and add the given bits */
428 namerec->data.wins_flags|=flags;
430 DEBUG(8,("update_wins_flag: nbflags: 0x%x, ttl: %d, flags: 0x%x, winsflags: 0x%x\n",
431 namerec->data.nb_flags, (int)namerec->data.death_time, flags, namerec->data.wins_flags));
434 /****************************************************************************
435 Return the general ID value and increase it if requested.
436 *****************************************************************************/
438 static void get_global_id_and_update(uint64_t *current_id, bool update)
441 * it's kept as a static here, to prevent people from messing
442 * with the value directly
445 static uint64_t general_id = 1;
447 DEBUG(5,("get_global_id_and_update: updating version ID: %d\n", (int)general_id));
449 *current_id = general_id;
451 if (update) {
452 general_id++;
456 /****************************************************************************
457 Possibly call the WINS hook external program when a WINS change is made.
458 Also stores the changed record back in the wins_tdb.
459 *****************************************************************************/
461 static void wins_hook(const char *operation, struct name_record *namerec, int ttl)
463 char *command = NULL;
464 char *cmd = lp_wins_hook(talloc_tos());
465 char *p, *namestr;
466 int i;
467 TALLOC_CTX *ctx = talloc_tos();
469 wins_store_changed_namerec(namerec);
471 if (!cmd || !*cmd) {
472 return;
475 for (p=namerec->name.name; *p; p++) {
476 if (!(isalnum((int)*p) || strchr_m("._-",*p))) {
477 DEBUG(3,("not calling wins hook for invalid name %s\n", nmb_namestr(&namerec->name)));
478 return;
482 /* Use the name without the nametype (and scope) appended */
484 namestr = nmb_namestr(&namerec->name);
485 if ((p = strchr(namestr, '<'))) {
486 *p = 0;
489 command = talloc_asprintf(ctx,
490 "%s %s %s %02x %d",
491 cmd,
492 operation,
493 namestr,
494 namerec->name.name_type,
495 ttl);
496 if (!command) {
497 return;
500 for (i=0;i<namerec->data.num_ips;i++) {
501 command = talloc_asprintf_append(command,
502 " %s",
503 inet_ntoa(namerec->data.ip[i]));
504 if (!command) {
505 return;
509 DEBUG(3,("calling wins hook for %s\n", nmb_namestr(&namerec->name)));
510 smbrun(command, NULL);
511 TALLOC_FREE(command);
514 /****************************************************************************
515 Determine if this packet should be allocated to the WINS server.
516 *****************************************************************************/
518 bool packet_is_for_wins_server(struct packet_struct *packet)
520 struct nmb_packet *nmb = &packet->packet.nmb;
522 /* Only unicast packets go to a WINS server. */
523 if((wins_server_subnet == NULL) || (nmb->header.nm_flags.bcast == True)) {
524 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #1.\n"));
525 return False;
528 /* Check for node status requests. */
529 if (nmb->question.question_type != QUESTION_TYPE_NB_QUERY) {
530 return False;
533 switch(nmb->header.opcode) {
535 * A WINS server issues WACKS, not receives them.
537 case NMB_WACK_OPCODE:
538 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #2 (WACK).\n"));
539 return False;
541 * A WINS server only processes registration and
542 * release requests, not responses.
544 case NMB_NAME_REG_OPCODE:
545 case NMB_NAME_MULTIHOMED_REG_OPCODE:
546 case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
547 case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
548 if(nmb->header.response) {
549 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #3 (response = 1).\n"));
550 return False;
552 break;
554 case NMB_NAME_RELEASE_OPCODE:
555 if(nmb->header.response) {
556 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #4 (response = 1).\n"));
557 return False;
559 break;
562 * Only process unicast name queries with rd = 1.
564 case NMB_NAME_QUERY_OPCODE:
565 if(!nmb->header.response && !nmb->header.nm_flags.recursion_desired) {
566 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #5 (response = 1).\n"));
567 return False;
569 break;
572 return True;
575 /****************************************************************************
576 Utility function to decide what ttl to give a register/refresh request.
577 *****************************************************************************/
579 static int get_ttl_from_packet(struct nmb_packet *nmb)
581 int ttl = nmb->additional->ttl;
583 if (ttl < lp_min_wins_ttl()) {
584 ttl = lp_min_wins_ttl();
587 if (ttl > lp_max_wins_ttl()) {
588 ttl = lp_max_wins_ttl();
591 return ttl;
594 /****************************************************************************
595 Load or create the WINS database.
596 *****************************************************************************/
598 bool initialise_wins(void)
600 time_t time_now = time(NULL);
601 XFILE *fp;
602 char line[1024];
604 if(!lp_we_are_a_wins_server()) {
605 return True;
608 /* Open the wins.tdb. */
609 wins_tdb = tdb_open_log(state_path("wins.tdb"), 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
610 O_CREAT|O_RDWR, 0600);
611 if (!wins_tdb) {
612 DEBUG(0,("initialise_wins: failed to open wins.tdb. Error was %s\n",
613 strerror(errno) ));
614 return False;
617 tdb_store_int32(wins_tdb, "WINSDB_VERSION", WINSDB_VERSION);
619 add_samba_names_to_subnet(wins_server_subnet);
621 if((fp = x_fopen(state_path(WINS_LIST),O_RDONLY,0)) == NULL) {
622 DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
623 WINS_LIST, strerror(errno) ));
624 return True;
627 while (!x_feof(fp)) {
628 char *name_str = NULL;
629 char *ip_str = NULL;
630 char *ttl_str = NULL, *nb_flags_str = NULL;
631 unsigned int num_ips;
632 char *name = NULL;
633 struct in_addr *ip_list = NULL;
634 int type = 0;
635 int nb_flags;
636 int ttl;
637 const char *ptr;
638 char *p = NULL;
639 bool got_token;
640 bool was_ip;
641 int i;
642 unsigned int hash;
643 int version;
644 TALLOC_CTX *frame = NULL;
646 /* Read a line from the wins.dat file. Strips whitespace
647 from the beginning and end of the line. */
648 if (!fgets_slash(line,sizeof(line),fp)) {
649 continue;
652 if (*line == '#') {
653 continue;
656 if (strncmp(line,"VERSION ", 8) == 0) {
657 if (sscanf(line,"VERSION %d %u", &version, &hash) != 2 ||
658 version != WINS_VERSION) {
659 DEBUG(0,("Discarding invalid wins.dat file [%s]\n",line));
660 x_fclose(fp);
661 return True;
663 continue;
666 ptr = line;
669 * Now we handle multiple IP addresses per name we need
670 * to iterate over the line twice. The first time to
671 * determine how many IP addresses there are, the second
672 * time to actually parse them into the ip_list array.
675 frame = talloc_stackframe();
676 if (!next_token_talloc(frame,&ptr,&name_str,NULL)) {
677 DEBUG(0,("initialise_wins: Failed to parse name when parsing line %s\n", line ));
678 TALLOC_FREE(frame);
679 continue;
682 if (!next_token_talloc(frame,&ptr,&ttl_str,NULL)) {
683 DEBUG(0,("initialise_wins: Failed to parse time to live when parsing line %s\n", line ));
684 TALLOC_FREE(frame);
685 continue;
689 * Determine the number of IP addresses per line.
691 num_ips = 0;
692 do {
693 got_token = next_token_talloc(frame,&ptr,&ip_str,NULL);
694 was_ip = False;
696 if(got_token && strchr(ip_str, '.')) {
697 num_ips++;
698 was_ip = True;
700 } while(got_token && was_ip);
702 if(num_ips == 0) {
703 DEBUG(0,("initialise_wins: Missing IP address when parsing line %s\n", line ));
704 TALLOC_FREE(frame);
705 continue;
708 if(!got_token) {
709 DEBUG(0,("initialise_wins: Missing nb_flags when parsing line %s\n", line ));
710 TALLOC_FREE(frame);
711 continue;
714 /* Allocate the space for the ip_list. */
715 if((ip_list = SMB_MALLOC_ARRAY( struct in_addr, num_ips)) == NULL) {
716 DEBUG(0,("initialise_wins: Malloc fail !\n"));
717 x_fclose(fp);
718 TALLOC_FREE(frame);
719 return False;
722 /* Reset and re-parse the line. */
723 ptr = line;
724 next_token_talloc(frame,&ptr,&name_str,NULL);
725 next_token_talloc(frame,&ptr,&ttl_str,NULL);
726 for(i = 0; i < num_ips; i++) {
727 next_token_talloc(frame,&ptr, &ip_str, NULL);
728 ip_list[i] = interpret_addr2(ip_str);
730 next_token_talloc(frame,&ptr,&nb_flags_str,NULL);
733 * Deal with SELF or REGISTER name encoding. Default is REGISTER
734 * for compatibility with old nmbds.
737 if(nb_flags_str[strlen(nb_flags_str)-1] == 'S') {
738 DEBUG(5,("initialise_wins: Ignoring SELF name %s\n", line));
739 SAFE_FREE(ip_list);
740 TALLOC_FREE(frame);
741 continue;
744 if(nb_flags_str[strlen(nb_flags_str)-1] == 'R') {
745 nb_flags_str[strlen(nb_flags_str)-1] = '\0';
748 /* Netbios name. # divides the name from the type (hex): netbios#xx */
749 name = name_str;
751 if((p = strchr(name,'#')) != NULL) {
752 *p = 0;
753 sscanf(p+1,"%x",&type);
756 /* Decode the netbios flags (hex) and the time-to-live (in seconds). */
757 sscanf(nb_flags_str,"%x",&nb_flags);
758 sscanf(ttl_str,"%d",&ttl);
760 /* add all entries that have 60 seconds or more to live */
761 if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) {
762 if(ttl != PERMANENT_TTL) {
763 ttl -= time_now;
766 DEBUG( 4, ("initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
767 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
769 (void)add_name_to_subnet( wins_server_subnet, name, type, nb_flags,
770 ttl, REGISTER_NAME, num_ips, ip_list );
771 } else {
772 DEBUG(4, ("initialise_wins: not adding name (ttl problem) "
773 "%s#%02x ttl = %d first IP %s flags = %2x\n",
774 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
777 TALLOC_FREE(frame);
778 SAFE_FREE(ip_list);
781 x_fclose(fp);
782 return True;
785 /****************************************************************************
786 Send a WINS WACK (Wait ACKnowledgement) response.
787 **************************************************************************/
789 static void send_wins_wack_response(int ttl, struct packet_struct *p)
791 struct nmb_packet *nmb = &p->packet.nmb;
792 unsigned char rdata[2];
794 rdata[0] = rdata[1] = 0;
796 /* Taken from nmblib.c - we need to send back almost
797 identical bytes from the requesting packet header. */
799 rdata[0] = (nmb->header.opcode & 0xF) << 3;
800 if (nmb->header.nm_flags.authoritative && nmb->header.response) {
801 rdata[0] |= 0x4;
803 if (nmb->header.nm_flags.trunc) {
804 rdata[0] |= 0x2;
806 if (nmb->header.nm_flags.recursion_desired) {
807 rdata[0] |= 0x1;
809 if (nmb->header.nm_flags.recursion_available && nmb->header.response) {
810 rdata[1] |= 0x80;
812 if (nmb->header.nm_flags.bcast) {
813 rdata[1] |= 0x10;
816 reply_netbios_packet(p, /* Packet to reply to. */
817 0, /* Result code. */
818 NMB_WAIT_ACK, /* nmbd type code. */
819 NMB_WACK_OPCODE, /* opcode. */
820 ttl, /* ttl. */
821 (char *)rdata, /* data to send. */
822 2); /* data length. */
825 /****************************************************************************
826 Send a WINS name registration response.
827 **************************************************************************/
829 static void send_wins_name_registration_response(int rcode, int ttl, struct packet_struct *p)
831 struct nmb_packet *nmb = &p->packet.nmb;
832 char rdata[6];
834 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
836 reply_netbios_packet(p, /* Packet to reply to. */
837 rcode, /* Result code. */
838 WINS_REG, /* nmbd type code. */
839 NMB_NAME_REG_OPCODE, /* opcode. */
840 ttl, /* ttl. */
841 rdata, /* data to send. */
842 6); /* data length. */
845 /***********************************************************************
846 Deal with a name refresh request to a WINS server.
847 ************************************************************************/
849 void wins_process_name_refresh_request( struct subnet_record *subrec,
850 struct packet_struct *p )
852 struct nmb_packet *nmb = &p->packet.nmb;
853 struct nmb_name *question = &nmb->question.question_name;
854 bool bcast = nmb->header.nm_flags.bcast;
855 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
856 bool group = (nb_flags & NB_GROUP) ? True : False;
857 struct name_record *namerec = NULL;
858 int ttl = get_ttl_from_packet(nmb);
859 struct in_addr from_ip;
860 struct in_addr our_fake_ip;
862 our_fake_ip = interpret_addr2("0.0.0.0");
863 putip( (char *)&from_ip, &nmb->additional->rdata[2] );
865 if(bcast) {
867 * We should only get unicast name refresh packets here.
868 * Anyone trying to refresh broadcast should not be going
869 * to a WINS server. Log an error here.
871 if( DEBUGLVL( 0 ) ) {
872 dbgtext( "wins_process_name_refresh_request: " );
873 dbgtext( "Broadcast name refresh request received " );
874 dbgtext( "for name %s ", nmb_namestr(question) );
875 dbgtext( "from IP %s ", inet_ntoa(from_ip) );
876 dbgtext( "on subnet %s. ", subrec->subnet_name );
877 dbgtext( "Error - Broadcasts should not be sent " );
878 dbgtext( "to a WINS server\n" );
880 return;
883 if( DEBUGLVL( 3 ) ) {
884 dbgtext( "wins_process_name_refresh_request: " );
885 dbgtext( "Name refresh for name %s IP %s\n",
886 nmb_namestr(question), inet_ntoa(from_ip) );
890 * See if the name already exists.
891 * If not, handle it as a name registration and return.
893 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
896 * If this is a refresh request and the name doesn't exist then
897 * treat it like a registration request. This allows us to recover
898 * from errors (tridge)
900 if(namerec == NULL) {
901 if( DEBUGLVL( 3 ) ) {
902 dbgtext( "wins_process_name_refresh_request: " );
903 dbgtext( "Name refresh for name %s ",
904 nmb_namestr( question ) );
905 dbgtext( "and the name does not exist. Treating " );
906 dbgtext( "as registration.\n" );
908 wins_process_name_registration_request(subrec,p);
909 return;
913 * if the name is present but not active, simply remove it
914 * and treat the refresh request as a registration & return.
916 if (namerec != NULL && !WINS_STATE_ACTIVE(namerec)) {
917 if( DEBUGLVL( 5 ) ) {
918 dbgtext( "wins_process_name_refresh_request: " );
919 dbgtext( "Name (%s) in WINS ", nmb_namestr(question) );
920 dbgtext( "was not active - removing it.\n" );
922 remove_name_from_namelist( subrec, namerec );
923 namerec = NULL;
924 wins_process_name_registration_request( subrec, p );
925 return;
929 * Check that the group bits for the refreshing name and the
930 * name in our database match. If not, refuse the refresh.
931 * [crh: Why RFS_ERR instead of ACT_ERR? Is this what MS does?]
933 if( (namerec != NULL) &&
934 ( (group && !NAME_GROUP(namerec))
935 || (!group && NAME_GROUP(namerec)) ) ) {
936 if( DEBUGLVL( 3 ) ) {
937 dbgtext( "wins_process_name_refresh_request: " );
938 dbgtext( "Name %s ", nmb_namestr(question) );
939 dbgtext( "group bit = %s does not match ",
940 group ? "True" : "False" );
941 dbgtext( "group bit in WINS for this name.\n" );
943 send_wins_name_registration_response(RFS_ERR, 0, p);
944 return;
948 * For a unique name check that the person refreshing the name is
949 * one of the registered IP addresses. If not - fail the refresh.
950 * Do the same for group names with a type of 0x1c.
951 * Just return success for unique 0x1d refreshes. For normal group
952 * names update the ttl and return success.
954 if( (!group || (group && (question->name_type == 0x1c)))
955 && find_ip_in_name_record(namerec, from_ip) ) {
957 * Update the ttl.
959 update_name_ttl(namerec, ttl);
962 * if the record is a replica:
963 * we take ownership and update the version ID.
965 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
966 update_wins_owner(namerec, our_fake_ip);
967 get_global_id_and_update(&namerec->data.id, True);
970 send_wins_name_registration_response(0, ttl, p);
971 wins_hook("refresh", namerec, ttl);
972 return;
973 } else if((group && (question->name_type == 0x1c))) {
975 * Added by crh for bug #1079.
976 * Fix from Bert Driehuis
978 if( DEBUGLVL( 3 ) ) {
979 dbgtext( "wins_process_name_refresh_request: " );
980 dbgtext( "Name refresh for name %s, ",
981 nmb_namestr(question) );
982 dbgtext( "but IP address %s ", inet_ntoa(from_ip) );
983 dbgtext( "is not yet associated with " );
984 dbgtext( "that name. Treating as registration.\n" );
986 wins_process_name_registration_request(subrec,p);
987 return;
988 } else if(group) {
990 * Normal groups are all registered with an IP address of
991 * 255.255.255.255 so we can't search for the IP address.
993 update_name_ttl(namerec, ttl);
994 wins_hook("refresh", namerec, ttl);
995 send_wins_name_registration_response(0, ttl, p);
996 return;
997 } else if(!group && (question->name_type == 0x1d)) {
999 * Special name type - just pretend the refresh succeeded.
1001 send_wins_name_registration_response(0, ttl, p);
1002 return;
1003 } else {
1005 * Fail the refresh.
1007 if( DEBUGLVL( 3 ) ) {
1008 dbgtext( "wins_process_name_refresh_request: " );
1009 dbgtext( "Name refresh for name %s with IP %s ",
1010 nmb_namestr(question), inet_ntoa(from_ip) );
1011 dbgtext( "and is IP is not known to the name.\n" );
1013 send_wins_name_registration_response(RFS_ERR, 0, p);
1014 return;
1018 /***********************************************************************
1019 Deal with a name registration request query success to a client that
1020 owned the name.
1022 We have a locked pointer to the original packet stashed away in the
1023 userdata pointer. The success here is actually a failure as it means
1024 the client we queried wants to keep the name, so we must return
1025 a registration failure to the original requestor.
1026 ************************************************************************/
1028 static void wins_register_query_success(struct subnet_record *subrec,
1029 struct userdata_struct *userdata,
1030 struct nmb_name *question_name,
1031 struct in_addr ip,
1032 struct res_rec *answers)
1034 struct packet_struct *orig_reg_packet;
1036 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1038 DEBUG(3,("wins_register_query_success: Original client at IP %s still wants the \
1039 name %s. Rejecting registration request.\n", inet_ntoa(ip), nmb_namestr(question_name) ));
1041 send_wins_name_registration_response(ACT_ERR, 0, orig_reg_packet);
1043 orig_reg_packet->locked = False;
1044 free_packet(orig_reg_packet);
1047 /***********************************************************************
1048 Deal with a name registration request query failure to a client that
1049 owned the name.
1051 We have a locked pointer to the original packet stashed away in the
1052 userdata pointer. The failure here is actually a success as it means
1053 the client we queried didn't want to keep the name, so we can remove
1054 the old name record and then successfully add the new name.
1055 ************************************************************************/
1057 static void wins_register_query_fail(struct subnet_record *subrec,
1058 struct response_record *rrec,
1059 struct nmb_name *question_name,
1060 int rcode)
1062 struct userdata_struct *userdata = rrec->userdata;
1063 struct packet_struct *orig_reg_packet;
1064 struct name_record *namerec = NULL;
1066 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1069 * We want to just add the name, as we now know the original owner
1070 * didn't want it. But we can't just do that as an arbitary
1071 * amount of time may have taken place between the name query
1072 * request and this timeout/error response. So we check that
1073 * the name still exists and is in the same state - if so
1074 * we remove it and call wins_process_name_registration_request()
1075 * as we know it will do the right thing now.
1078 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1080 if ((namerec != NULL) && (namerec->data.source == REGISTER_NAME) &&
1081 ip_equal_v4(rrec->packet->ip, *namerec->data.ip)) {
1082 remove_name_from_namelist( subrec, namerec);
1083 namerec = NULL;
1086 if(namerec == NULL) {
1087 wins_process_name_registration_request(subrec, orig_reg_packet);
1088 } else {
1089 DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between "
1090 "querying for name %s in order to replace it and this reply.\n",
1091 nmb_namestr(question_name) ));
1094 orig_reg_packet->locked = False;
1095 free_packet(orig_reg_packet);
1098 /***********************************************************************
1099 Deal with a name registration request to a WINS server.
1101 Use the following pseudocode :
1103 registering_group
1106 +--------name exists
1109 | +--- existing name is group
1110 | | |
1111 | | |
1112 | | +--- add name (return).
1115 | +--- exiting name is unique
1118 | +--- query existing owner (return).
1121 +--------name doesn't exist
1124 +--- add name (return).
1126 registering_unique
1129 +--------name exists
1132 | +--- existing name is group
1133 | | |
1134 | | |
1135 | | +--- fail add (return).
1136 | |
1138 | +--- exiting name is unique
1141 | +--- query existing owner (return).
1144 +--------name doesn't exist
1147 +--- add name (return).
1149 As can be seen from the above, the two cases may be collapsed onto each
1150 other with the exception of the case where the name already exists and
1151 is a group name. This case we handle with an if statement.
1153 ************************************************************************/
1155 void wins_process_name_registration_request(struct subnet_record *subrec,
1156 struct packet_struct *p)
1158 unstring name;
1159 struct nmb_packet *nmb = &p->packet.nmb;
1160 struct nmb_name *question = &nmb->question.question_name;
1161 bool bcast = nmb->header.nm_flags.bcast;
1162 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
1163 int ttl = get_ttl_from_packet(nmb);
1164 struct name_record *namerec = NULL;
1165 struct in_addr from_ip;
1166 bool registering_group_name = (nb_flags & NB_GROUP) ? True : False;
1167 struct in_addr our_fake_ip;
1169 our_fake_ip = interpret_addr2("0.0.0.0");
1170 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1172 if(bcast) {
1174 * We should only get unicast name registration packets here.
1175 * Anyone trying to register broadcast should not be going to a WINS
1176 * server. Log an error here.
1179 DEBUG(0,("wins_process_name_registration_request: broadcast name registration request \
1180 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1181 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1182 return;
1185 DEBUG(3,("wins_process_name_registration_request: %s name registration for name %s \
1186 IP %s\n", registering_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
1189 * See if the name already exists.
1192 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1195 * if the record exists but NOT in active state,
1196 * consider it dead.
1198 if ( (namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1199 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1200 not active - removing it.\n", nmb_namestr(question) ));
1201 remove_name_from_namelist( subrec, namerec );
1202 namerec = NULL;
1206 * Deal with the case where the name found was a dns entry.
1207 * Remove it as we now have a NetBIOS client registering the
1208 * name.
1211 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1212 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1213 a dns lookup - removing it.\n", nmb_namestr(question) ));
1214 remove_name_from_namelist( subrec, namerec );
1215 namerec = NULL;
1219 * Reject if the name exists and is not a REGISTER_NAME.
1220 * (ie. Don't allow any static names to be overwritten.
1223 if((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) {
1224 DEBUG( 3, ( "wins_process_name_registration_request: Attempt \
1225 to register name %s. Name already exists in WINS with source type %d.\n",
1226 nmb_namestr(question), namerec->data.source ));
1227 send_wins_name_registration_response(RFS_ERR, 0, p);
1228 return;
1232 * Special policy decisions based on MS documentation.
1233 * 1). All group names (except names ending in 0x1c) are added as 255.255.255.255.
1234 * 2). All unique names ending in 0x1d are ignored, although a positive response is sent.
1238 * A group name is always added as the local broadcast address, except
1239 * for group names ending in 0x1c.
1240 * Group names with type 0x1c are registered with individual IP addresses.
1243 if(registering_group_name && (question->name_type != 0x1c)) {
1244 from_ip = interpret_addr2("255.255.255.255");
1248 * Ignore all attempts to register a unique 0x1d name, although return success.
1251 if(!registering_group_name && (question->name_type == 0x1d)) {
1252 DEBUG(3,("wins_process_name_registration_request: Ignoring request \
1253 to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
1254 send_wins_name_registration_response(0, ttl, p);
1255 return;
1259 * Next two cases are the 'if statement' mentioned above.
1262 if((namerec != NULL) && NAME_GROUP(namerec)) {
1263 if(registering_group_name) {
1265 * If we are adding a group name, the name exists and is also a group entry just add this
1266 * IP address to it and update the ttl.
1269 DEBUG(3,("wins_process_name_registration_request: Adding IP %s to group name %s.\n",
1270 inet_ntoa(from_ip), nmb_namestr(question) ));
1273 * Check the ip address is not already in the group.
1276 if(!find_ip_in_name_record(namerec, from_ip)) {
1278 * Need to emulate the behaviour of Windows, as
1279 * described in:
1280 * http://lists.samba.org/archive/samba-technical/2001-October/016236.html
1281 * (is there an MS reference for this
1282 * somewhere?) because if the 1c list gets over
1283 * 86 entries, the reply packet is too big
1284 * (rdata>576 bytes) so no reply is sent.
1286 * Keep only the "latest" 25 records, while
1287 * ensuring that the PDC (0x1b) is never removed
1288 * We do this by removing the first entry that
1289 * isn't the 1b entry for the same name,
1290 * on the grounds that insertion is at the end
1291 * of the list, so the oldest entries are at
1292 * the start.
1295 while(namerec->data.num_ips>=25) {
1296 struct name_record *name1brec = NULL;
1298 /* We only do this for 1c types. */
1299 if (namerec->name.name_type != 0x1c) {
1300 break;
1302 DEBUG(3,("wins_process_name_registration_request: "
1303 "More than 25 IPs already in "
1304 "the list. Looking for a 1b "
1305 "record\n"));
1307 /* Ensure we have all the active 1b
1308 * names on the list. */
1309 wins_delete_all_1b_in_memory_records();
1310 fetch_all_active_wins_1b_names();
1312 /* Per the above, find the 1b record,
1313 and then remove the first IP that isn't the same */
1314 for(name1brec = subrec->namelist;
1315 name1brec;
1316 name1brec = name1brec->next ) {
1317 if( WINS_STATE_ACTIVE(name1brec) &&
1318 name1brec->name.name_type == 0x1b) {
1319 DEBUG(3,("wins_process_name_registration_request: "
1320 "Found the #1b record "
1321 "with ip %s\n",
1322 inet_ntoa(name1brec->data.ip[0])));
1323 break;
1326 if(!name1brec) {
1327 DEBUG(3,("wins_process_name_registration_request: "
1328 "Didn't find a #1b name record. "
1329 "Removing the first available "
1330 "entry %s\n",
1331 inet_ntoa(namerec->data.ip[0])));
1332 remove_ip_from_name_record(namerec, namerec->data.ip[0]);
1333 wins_hook("delete", namerec, 0);
1334 } else {
1335 int i;
1336 for(i=0; i<namerec->data.num_ips; i++) {
1337 /* The name1brec should only have
1338 * the single IP address in it,
1339 * so we only check against the first one*/
1340 if(!ip_equal_v4( namerec->data.ip[i], name1brec->data.ip[0])) {
1341 /* The i'th entry isn't the 1b address; delete it */
1342 DEBUG(3,("wins_process_name_registration_request: "
1343 "Entry at %d is not the #1b address. "
1344 "About to remove it\n",
1345 i));
1346 remove_ip_from_name_record(namerec, namerec->data.ip[i]);
1347 wins_hook("delete", namerec, 0);
1348 break;
1353 /* The list is guaranteed to be < 25 entries now
1354 * - safe to add a new one */
1355 add_ip_to_name_record(namerec, from_ip);
1356 /* we need to update the record for replication */
1357 get_global_id_and_update(&namerec->data.id, True);
1360 * if the record is a replica, we must change
1361 * the wins owner to us to make the replication updates
1362 * it on the other wins servers.
1363 * And when the partner will receive this record,
1364 * it will update its own record.
1367 update_wins_owner(namerec, our_fake_ip);
1369 update_name_ttl(namerec, ttl);
1370 wins_hook("refresh", namerec, ttl);
1371 send_wins_name_registration_response(0, ttl, p);
1372 return;
1373 } else {
1376 * If we are adding a unique name, the name exists in the WINS db
1377 * and is a group name then reject the registration.
1379 * explanation: groups have a higher priority than unique names.
1382 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1383 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1384 send_wins_name_registration_response(RFS_ERR, 0, p);
1385 return;
1390 * From here on down we know that if the name exists in the WINS db it is
1391 * a unique name, not a group name.
1395 * If the name exists and is one of our names then check the
1396 * registering IP address. If it's not one of ours then automatically
1397 * reject without doing the query - we know we will reject it.
1400 if ( namerec != NULL ) {
1401 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
1402 if( is_myname(name) ) {
1403 if(!ismyip_v4(from_ip)) {
1404 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1405 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1406 send_wins_name_registration_response(RFS_ERR, 0, p);
1407 return;
1408 } else {
1410 * It's one of our names and one of our IP's - update the ttl.
1412 update_name_ttl(namerec, ttl);
1413 wins_hook("refresh", namerec, ttl);
1414 send_wins_name_registration_response(0, ttl, p);
1415 return;
1418 } else {
1419 name[0] = '\0';
1423 * If the name exists and it is a unique registration and the registering IP
1424 * is the same as the (single) already registered IP then just update the ttl.
1426 * But not if the record is an active replica. IF it's a replica, it means it can be
1427 * the same client which has moved and not yet expired. So we don't update
1428 * the ttl in this case and go beyond to do a WACK and query the old client
1431 if( !registering_group_name
1432 && (namerec != NULL)
1433 && (namerec->data.num_ips == 1)
1434 && ip_equal_v4( namerec->data.ip[0], from_ip )
1435 && ip_equal_v4(namerec->data.wins_ip, our_fake_ip) ) {
1436 update_name_ttl( namerec, ttl );
1437 wins_hook("refresh", namerec, ttl);
1438 send_wins_name_registration_response( 0, ttl, p );
1439 return;
1443 * Finally if the name exists do a query to the registering machine
1444 * to see if they still claim to have the name.
1447 if( namerec != NULL ) {
1448 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1449 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1452 * First send a WACK to the registering machine.
1455 send_wins_wack_response(60, p);
1458 * When the reply comes back we need the original packet.
1459 * Lock this so it won't be freed and then put it into
1460 * the userdata structure.
1463 p->locked = True;
1465 userdata = (struct userdata_struct *)ud;
1467 userdata->copy_fn = NULL;
1468 userdata->free_fn = NULL;
1469 userdata->userdata_len = sizeof(struct packet_struct *);
1470 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1473 * Use the new call to send a query directly to an IP address.
1474 * This sends the query directly to the IP address, and ensures
1475 * the recursion desired flag is not set (you were right Luke :-).
1476 * This function should *only* be called from the WINS server
1477 * code. JRA.
1480 pull_ascii_nstring(name, sizeof(name), question->name);
1481 query_name_from_wins_server( *namerec->data.ip,
1482 name,
1483 question->name_type,
1484 wins_register_query_success,
1485 wins_register_query_fail,
1486 userdata );
1487 return;
1491 * Name did not exist - add it.
1494 pull_ascii_nstring(name, sizeof(name), question->name);
1495 add_name_to_subnet( subrec, name, question->name_type,
1496 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1498 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1499 get_global_id_and_update(&namerec->data.id, True);
1500 update_wins_owner(namerec, our_fake_ip);
1501 update_wins_flag(namerec, WINS_ACTIVE);
1502 wins_hook("add", namerec, ttl);
1505 send_wins_name_registration_response(0, ttl, p);
1508 /***********************************************************************
1509 Deal with a mutihomed name query success to the machine that
1510 requested the multihomed name registration.
1512 We have a locked pointer to the original packet stashed away in the
1513 userdata pointer.
1514 ************************************************************************/
1516 static void wins_multihomed_register_query_success(struct subnet_record *subrec,
1517 struct userdata_struct *userdata,
1518 struct nmb_name *question_name,
1519 struct in_addr ip,
1520 struct res_rec *answers)
1522 struct packet_struct *orig_reg_packet;
1523 struct nmb_packet *nmb;
1524 struct name_record *namerec = NULL;
1525 struct in_addr from_ip;
1526 int ttl;
1527 struct in_addr our_fake_ip;
1529 our_fake_ip = interpret_addr2("0.0.0.0");
1530 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1532 nmb = &orig_reg_packet->packet.nmb;
1534 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1535 ttl = get_ttl_from_packet(nmb);
1538 * We want to just add the new IP, as we now know the requesting
1539 * machine claims to own it. But we can't just do that as an arbitary
1540 * amount of time may have taken place between the name query
1541 * request and this response. So we check that
1542 * the name still exists and is in the same state - if so
1543 * we just add the extra IP and update the ttl.
1546 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1548 if( (namerec == NULL) || (namerec->data.source != REGISTER_NAME) || !WINS_STATE_ACTIVE(namerec) ) {
1549 DEBUG(3,("wins_multihomed_register_query_success: name %s is not in the correct state to add \
1550 a subsequent IP address.\n", nmb_namestr(question_name) ));
1551 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1553 orig_reg_packet->locked = False;
1554 free_packet(orig_reg_packet);
1556 return;
1559 if(!find_ip_in_name_record(namerec, from_ip)) {
1560 add_ip_to_name_record(namerec, from_ip);
1563 get_global_id_and_update(&namerec->data.id, True);
1564 update_wins_owner(namerec, our_fake_ip);
1565 update_wins_flag(namerec, WINS_ACTIVE);
1566 update_name_ttl(namerec, ttl);
1567 wins_hook("add", namerec, ttl);
1568 send_wins_name_registration_response(0, ttl, orig_reg_packet);
1570 orig_reg_packet->locked = False;
1571 free_packet(orig_reg_packet);
1574 /***********************************************************************
1575 Deal with a name registration request query failure to a client that
1576 owned the name.
1578 We have a locked pointer to the original packet stashed away in the
1579 userdata pointer.
1580 ************************************************************************/
1582 static void wins_multihomed_register_query_fail(struct subnet_record *subrec,
1583 struct response_record *rrec,
1584 struct nmb_name *question_name,
1585 int rcode)
1587 struct userdata_struct *userdata = rrec->userdata;
1588 struct packet_struct *orig_reg_packet;
1590 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1592 DEBUG(3,("wins_multihomed_register_query_fail: Registering machine at IP %s failed to answer \
1593 query successfully for name %s.\n", inet_ntoa(orig_reg_packet->ip), nmb_namestr(question_name) ));
1594 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1596 orig_reg_packet->locked = False;
1597 free_packet(orig_reg_packet);
1598 return;
1601 /***********************************************************************
1602 Deal with a multihomed name registration request to a WINS server.
1603 These cannot be group name registrations.
1604 ***********************************************************************/
1606 void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
1607 struct packet_struct *p)
1609 struct nmb_packet *nmb = &p->packet.nmb;
1610 struct nmb_name *question = &nmb->question.question_name;
1611 bool bcast = nmb->header.nm_flags.bcast;
1612 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
1613 int ttl = get_ttl_from_packet(nmb);
1614 struct name_record *namerec = NULL;
1615 struct in_addr from_ip;
1616 bool group = (nb_flags & NB_GROUP) ? True : False;
1617 struct in_addr our_fake_ip;
1618 unstring qname;
1620 our_fake_ip = interpret_addr2("0.0.0.0");
1621 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1623 if(bcast) {
1625 * We should only get unicast name registration packets here.
1626 * Anyone trying to register broadcast should not be going to a WINS
1627 * server. Log an error here.
1630 DEBUG(0,("wins_process_multihomed_name_registration_request: broadcast name registration request \
1631 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1632 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1633 return;
1637 * Only unique names should be registered multihomed.
1640 if(group) {
1641 DEBUG(0,("wins_process_multihomed_name_registration_request: group name registration request \
1642 received for name %s from IP %s on subnet %s. Errror - group names should not be multihomed.\n",
1643 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1644 return;
1647 DEBUG(3,("wins_process_multihomed_name_registration_request: name registration for name %s \
1648 IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ));
1651 * Deal with policy regarding 0x1d names.
1654 if(question->name_type == 0x1d) {
1655 DEBUG(3,("wins_process_multihomed_name_registration_request: Ignoring request \
1656 to register name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
1657 send_wins_name_registration_response(0, ttl, p);
1658 return;
1662 * See if the name already exists.
1665 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1668 * if the record exists but NOT in active state,
1669 * consider it dead.
1672 if ((namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1673 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was not active - removing it.\n", nmb_namestr(question)));
1674 remove_name_from_namelist(subrec, namerec);
1675 namerec = NULL;
1679 * Deal with the case where the name found was a dns entry.
1680 * Remove it as we now have a NetBIOS client registering the
1681 * name.
1684 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1685 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was a dns lookup \
1686 - removing it.\n", nmb_namestr(question) ));
1687 remove_name_from_namelist( subrec, namerec);
1688 namerec = NULL;
1692 * Reject if the name exists and is not a REGISTER_NAME.
1693 * (ie. Don't allow any static names to be overwritten.
1696 if( (namerec != NULL) && (namerec->data.source != REGISTER_NAME) ) {
1697 DEBUG( 3, ( "wins_process_multihomed_name_registration_request: Attempt \
1698 to register name %s. Name already exists in WINS with source type %d.\n",
1699 nmb_namestr(question), namerec->data.source ));
1700 send_wins_name_registration_response(RFS_ERR, 0, p);
1701 return;
1705 * Reject if the name exists and is a GROUP name and is active.
1708 if((namerec != NULL) && NAME_GROUP(namerec) && WINS_STATE_ACTIVE(namerec)) {
1709 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1710 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1711 send_wins_name_registration_response(RFS_ERR, 0, p);
1712 return;
1716 * From here on down we know that if the name exists in the WINS db it is
1717 * a unique name, not a group name.
1721 * If the name exists and is one of our names then check the
1722 * registering IP address. If it's not one of ours then automatically
1723 * reject without doing the query - we know we will reject it.
1726 if((namerec != NULL) && (is_myname(namerec->name.name)) ) {
1727 if(!ismyip_v4(from_ip)) {
1728 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1729 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1730 send_wins_name_registration_response(RFS_ERR, 0, p);
1731 return;
1732 } else {
1734 * It's one of our names and one of our IP's. Ensure the IP is in the record and
1735 * update the ttl. Update the version ID to force replication.
1737 update_name_ttl(namerec, ttl);
1739 if(!find_ip_in_name_record(namerec, from_ip)) {
1740 get_global_id_and_update(&namerec->data.id, True);
1741 update_wins_owner(namerec, our_fake_ip);
1742 update_wins_flag(namerec, WINS_ACTIVE);
1744 add_ip_to_name_record(namerec, from_ip);
1747 wins_hook("refresh", namerec, ttl);
1748 send_wins_name_registration_response(0, ttl, p);
1749 return;
1754 * If the name exists and is active, check if the IP address is already registered
1755 * to that name. If so then update the ttl and reply success.
1758 if((namerec != NULL) && find_ip_in_name_record(namerec, from_ip) && WINS_STATE_ACTIVE(namerec)) {
1759 update_name_ttl(namerec, ttl);
1762 * If it's a replica, we need to become the wins owner
1763 * to force the replication
1765 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
1766 get_global_id_and_update(&namerec->data.id, True);
1767 update_wins_owner(namerec, our_fake_ip);
1768 update_wins_flag(namerec, WINS_ACTIVE);
1771 wins_hook("refresh", namerec, ttl);
1772 send_wins_name_registration_response(0, ttl, p);
1773 return;
1777 * If the name exists do a query to the owner
1778 * to see if they still want the name.
1781 if(namerec != NULL) {
1782 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1783 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1786 * First send a WACK to the registering machine.
1789 send_wins_wack_response(60, p);
1792 * When the reply comes back we need the original packet.
1793 * Lock this so it won't be freed and then put it into
1794 * the userdata structure.
1797 p->locked = True;
1799 userdata = (struct userdata_struct *)ud;
1801 userdata->copy_fn = NULL;
1802 userdata->free_fn = NULL;
1803 userdata->userdata_len = sizeof(struct packet_struct *);
1804 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1807 * Use the new call to send a query directly to an IP address.
1808 * This sends the query directly to the IP address, and ensures
1809 * the recursion desired flag is not set (you were right Luke :-).
1810 * This function should *only* be called from the WINS server
1811 * code. JRA.
1813 * Note that this packet is sent to the current owner of the name,
1814 * not the person who sent the packet
1817 pull_ascii_nstring( qname, sizeof(qname), question->name);
1818 query_name_from_wins_server( namerec->data.ip[0],
1819 qname,
1820 question->name_type,
1821 wins_multihomed_register_query_success,
1822 wins_multihomed_register_query_fail,
1823 userdata );
1825 return;
1829 * Name did not exist - add it.
1832 pull_ascii_nstring( qname, sizeof(qname), question->name);
1833 add_name_to_subnet( subrec, qname, question->name_type,
1834 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1836 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1837 get_global_id_and_update(&namerec->data.id, True);
1838 update_wins_owner(namerec, our_fake_ip);
1839 update_wins_flag(namerec, WINS_ACTIVE);
1840 wins_hook("add", namerec, ttl);
1843 send_wins_name_registration_response(0, ttl, p);
1846 /***********************************************************************
1847 Fetch all *<1b> names from the WINS db and store on the namelist.
1848 ***********************************************************************/
1850 static int fetch_1b_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
1852 struct name_record *namerec = NULL;
1854 if (kbuf.dsize != sizeof(unstring) + 1) {
1855 return 0;
1858 /* Filter out all non-1b names. */
1859 if (kbuf.dptr[sizeof(unstring)] != 0x1b) {
1860 return 0;
1863 namerec = wins_record_to_name_record(kbuf, dbuf);
1864 if (!namerec) {
1865 return 0;
1868 DLIST_ADD(wins_server_subnet->namelist, namerec);
1869 return 0;
1872 void fetch_all_active_wins_1b_names(void)
1874 tdb_traverse(wins_tdb, fetch_1b_traverse_fn, NULL);
1877 /***********************************************************************
1878 Deal with the special name query for *<1b>.
1879 ***********************************************************************/
1881 static void process_wins_dmb_query_request(struct subnet_record *subrec,
1882 struct packet_struct *p)
1884 struct name_record *namerec = NULL;
1885 char *prdata;
1886 int num_ips;
1889 * Go through all the ACTIVE names in the WINS db looking for those
1890 * ending in <1b>. Use this to calculate the number of IP
1891 * addresses we need to return.
1894 num_ips = 0;
1896 /* First, clear the in memory list - we're going to re-populate
1897 it with the tdb_traversal in fetch_all_active_wins_1b_names. */
1899 wins_delete_all_tmp_in_memory_records();
1901 fetch_all_active_wins_1b_names();
1903 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1904 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1905 num_ips += namerec->data.num_ips;
1909 if(num_ips == 0) {
1911 * There are no 0x1b names registered. Return name query fail.
1913 send_wins_name_query_response(NAM_ERR, p, NULL);
1914 return;
1917 if((prdata = (char *)SMB_MALLOC( num_ips * 6 )) == NULL) {
1918 DEBUG(0,("process_wins_dmb_query_request: Malloc fail !.\n"));
1919 return;
1923 * Go through all the names again in the WINS db looking for those
1924 * ending in <1b>. Add their IP addresses into the list we will
1925 * return.
1928 num_ips = 0;
1929 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1930 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1931 int i;
1932 for(i = 0; i < namerec->data.num_ips; i++) {
1933 set_nb_flags(&prdata[num_ips * 6],namerec->data.nb_flags);
1934 putip((char *)&prdata[(num_ips * 6) + 2], &namerec->data.ip[i]);
1935 num_ips++;
1941 * Send back the reply containing the IP list.
1944 reply_netbios_packet(p, /* Packet to reply to. */
1945 0, /* Result code. */
1946 WINS_QUERY, /* nmbd type code. */
1947 NMB_NAME_QUERY_OPCODE, /* opcode. */
1948 lp_min_wins_ttl(), /* ttl. */
1949 prdata, /* data to send. */
1950 num_ips*6); /* data length. */
1952 SAFE_FREE(prdata);
1955 /****************************************************************************
1956 Send a WINS name query response.
1957 **************************************************************************/
1959 void send_wins_name_query_response(int rcode, struct packet_struct *p,
1960 struct name_record *namerec)
1962 char rdata[6];
1963 char *prdata = rdata;
1964 int reply_data_len = 0;
1965 int ttl = 0;
1966 int i;
1968 memset(rdata,'\0',6);
1970 if(rcode == 0) {
1972 int ip_count;
1974 ttl = (namerec->data.death_time != PERMANENT_TTL) ? namerec->data.death_time - p->timestamp : lp_max_wins_ttl();
1976 /* The netbios reply packet data section is limited to 576 bytes. In theory
1977 * this should give us space for 96 addresses, but in practice, 86 appears
1978 * to be the max (don't know why). If we send any more than that,
1979 * reply_netbios_packet will fail to send a reply to avoid a memcpy buffer
1980 * overflow. Keep the count to 85 and it will be ok */
1981 ip_count=namerec->data.num_ips;
1982 if(ip_count>85) {
1983 ip_count=85;
1986 /* Copy all known ip addresses into the return data. */
1987 /* Optimise for the common case of one IP address so we don't need a malloc. */
1989 if( ip_count == 1 ) {
1990 prdata = rdata;
1991 } else {
1992 if((prdata = (char *)SMB_MALLOC( ip_count * 6 )) == NULL) {
1993 DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
1994 return;
1998 for(i = 0; i < ip_count; i++) {
1999 set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
2000 putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
2003 sort_query_replies(prdata, i, p->ip);
2004 reply_data_len = ip_count * 6;
2007 reply_netbios_packet(p, /* Packet to reply to. */
2008 rcode, /* Result code. */
2009 WINS_QUERY, /* nmbd type code. */
2010 NMB_NAME_QUERY_OPCODE, /* opcode. */
2011 ttl, /* ttl. */
2012 prdata, /* data to send. */
2013 reply_data_len); /* data length. */
2015 if(prdata != rdata) {
2016 SAFE_FREE(prdata);
2020 /***********************************************************************
2021 Deal with a name query.
2022 ***********************************************************************/
2024 void wins_process_name_query_request(struct subnet_record *subrec,
2025 struct packet_struct *p)
2027 struct nmb_packet *nmb = &p->packet.nmb;
2028 struct nmb_name *question = &nmb->question.question_name;
2029 struct name_record *namerec = NULL;
2030 unstring qname;
2032 DEBUG(3,("wins_process_name_query: name query for name %s from IP %s\n",
2033 nmb_namestr(question), inet_ntoa(p->ip) ));
2036 * Special name code. If the queried name is *<1b> then search
2037 * the entire WINS database and return a list of all the IP addresses
2038 * registered to any <1b> name. This is to allow domain master browsers
2039 * to discover other domains that may not have a presence on their subnet.
2042 pull_ascii_nstring(qname, sizeof(qname), question->name);
2043 if(strequal( qname, "*") && (question->name_type == 0x1b)) {
2044 process_wins_dmb_query_request( subrec, p);
2045 return;
2048 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2050 if(namerec != NULL) {
2052 * If the name is not anymore in active state then reply not found.
2053 * it's fair even if we keep it in the cache for days.
2055 if (!WINS_STATE_ACTIVE(namerec)) {
2056 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
2057 nmb_namestr(question) ));
2058 send_wins_name_query_response(NAM_ERR, p, namerec);
2059 return;
2063 * If it's a DNSFAIL_NAME then reply name not found.
2066 if( namerec->data.source == DNSFAIL_NAME ) {
2067 DEBUG(3,("wins_process_name_query: name query for name %s returning DNS fail.\n",
2068 nmb_namestr(question) ));
2069 send_wins_name_query_response(NAM_ERR, p, namerec);
2070 return;
2074 * If the name has expired then reply name not found.
2077 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < p->timestamp) ) {
2078 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
2079 nmb_namestr(question) ));
2080 send_wins_name_query_response(NAM_ERR, p, namerec);
2081 return;
2084 DEBUG(3,("wins_process_name_query: name query for name %s returning first IP %s.\n",
2085 nmb_namestr(question), inet_ntoa(namerec->data.ip[0]) ));
2087 send_wins_name_query_response(0, p, namerec);
2088 return;
2092 * Name not found in WINS - try a dns query if it's a 0x20 name.
2095 if(lp_wins_dns_proxy() && ((question->name_type == 0x20) || question->name_type == 0)) {
2096 DEBUG(3,("wins_process_name_query: name query for name %s not found - doing dns lookup.\n",
2097 nmb_namestr(question) ));
2099 queue_dns_query(p, question);
2100 return;
2104 * Name not found - return error.
2107 send_wins_name_query_response(NAM_ERR, p, NULL);
2110 /****************************************************************************
2111 Send a WINS name release response.
2112 **************************************************************************/
2114 static void send_wins_name_release_response(int rcode, struct packet_struct *p)
2116 struct nmb_packet *nmb = &p->packet.nmb;
2117 char rdata[6];
2119 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
2121 reply_netbios_packet(p, /* Packet to reply to. */
2122 rcode, /* Result code. */
2123 NMB_REL, /* nmbd type code. */
2124 NMB_NAME_RELEASE_OPCODE, /* opcode. */
2125 0, /* ttl. */
2126 rdata, /* data to send. */
2127 6); /* data length. */
2130 /***********************************************************************
2131 Deal with a name release.
2132 ***********************************************************************/
2134 void wins_process_name_release_request(struct subnet_record *subrec,
2135 struct packet_struct *p)
2137 struct nmb_packet *nmb = &p->packet.nmb;
2138 struct nmb_name *question = &nmb->question.question_name;
2139 bool bcast = nmb->header.nm_flags.bcast;
2140 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
2141 struct name_record *namerec = NULL;
2142 struct in_addr from_ip;
2143 bool releasing_group_name = (nb_flags & NB_GROUP) ? True : False;
2145 putip((char *)&from_ip,&nmb->additional->rdata[2]);
2147 if(bcast) {
2149 * We should only get unicast name registration packets here.
2150 * Anyone trying to register broadcast should not be going to a WINS
2151 * server. Log an error here.
2154 DEBUG(0,("wins_process_name_release_request: broadcast name registration request \
2155 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
2156 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
2157 return;
2160 DEBUG(3,("wins_process_name_release_request: %s name release for name %s \
2161 IP %s\n", releasing_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
2164 * Deal with policy regarding 0x1d names.
2167 if(!releasing_group_name && (question->name_type == 0x1d)) {
2168 DEBUG(3,("wins_process_name_release_request: Ignoring request \
2169 to release name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
2170 send_wins_name_release_response(0, p);
2171 return;
2175 * See if the name already exists.
2178 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2180 if( (namerec == NULL) || ((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) ) {
2181 send_wins_name_release_response(NAM_ERR, p);
2182 return;
2186 * Check that the sending machine has permission to release this name.
2187 * If it's a group name not ending in 0x1c then just say yes and let
2188 * the group time out.
2191 if(releasing_group_name && (question->name_type != 0x1c)) {
2192 send_wins_name_release_response(0, p);
2193 return;
2197 * Check that the releasing node is on the list of IP addresses
2198 * for this name. Disallow the release if not.
2201 if(!find_ip_in_name_record(namerec, from_ip)) {
2202 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2203 release name %s as IP %s is not one of the known IP's for this name.\n",
2204 nmb_namestr(question), inet_ntoa(from_ip) ));
2205 send_wins_name_release_response(NAM_ERR, p);
2206 return;
2210 * Check if the record is active. IF it's already released
2211 * or tombstoned, refuse the release.
2214 if (!WINS_STATE_ACTIVE(namerec)) {
2215 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2216 release name %s as this record is not active anymore.\n", nmb_namestr(question) ));
2217 send_wins_name_release_response(NAM_ERR, p);
2218 return;
2222 * Check if the record is a 0x1c group
2223 * and has more then one ip
2224 * remove only this address.
2227 if(releasing_group_name && (question->name_type == 0x1c) && (namerec->data.num_ips > 1)) {
2228 remove_ip_from_name_record(namerec, from_ip);
2229 DEBUG(3,("wins_process_name_release_request: Remove IP %s from NAME: %s\n",
2230 inet_ntoa(from_ip),nmb_namestr(question)));
2231 wins_hook("delete", namerec, 0);
2232 send_wins_name_release_response(0, p);
2233 return;
2237 * Send a release response.
2238 * Flag the name as released and update the ttl
2241 namerec->data.wins_flags |= WINS_RELEASED;
2242 update_name_ttl(namerec, EXTINCTION_INTERVAL);
2244 wins_hook("delete", namerec, 0);
2245 send_wins_name_release_response(0, p);
2248 /*******************************************************************
2249 WINS time dependent processing.
2250 ******************************************************************/
2252 static int wins_processing_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2254 time_t t = *(time_t *)state;
2255 bool store_record = False;
2256 struct name_record *namerec = NULL;
2257 struct in_addr our_fake_ip;
2259 our_fake_ip = interpret_addr2("0.0.0.0");
2260 if (kbuf.dsize != sizeof(unstring) + 1) {
2261 return 0;
2264 namerec = wins_record_to_name_record(kbuf, dbuf);
2265 if (!namerec) {
2266 return 0;
2269 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
2270 if( namerec->data.source == SELF_NAME ) {
2271 DEBUG( 3, ( "wins_processing_traverse_fn: Subnet %s not expiring SELF name %s\n",
2272 wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) );
2273 namerec->data.death_time += 300;
2274 store_record = True;
2275 goto done;
2276 } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) {
2277 DEBUG(3,("wins_processing_traverse_fn: deleting timed out DNS name %s\n",
2278 nmb_namestr(&namerec->name)));
2279 remove_name_from_wins_namelist(namerec );
2280 goto done;
2283 /* handle records, samba is the wins owner */
2284 if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
2285 switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2286 case WINS_ACTIVE:
2287 namerec->data.wins_flags&=~WINS_STATE_MASK;
2288 namerec->data.wins_flags|=WINS_RELEASED;
2289 namerec->data.death_time = t + EXTINCTION_INTERVAL;
2290 DEBUG(3,("wins_processing_traverse_fn: expiring %s\n",
2291 nmb_namestr(&namerec->name)));
2292 store_record = True;
2293 goto done;
2294 case WINS_RELEASED:
2295 namerec->data.wins_flags&=~WINS_STATE_MASK;
2296 namerec->data.wins_flags|=WINS_TOMBSTONED;
2297 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2298 get_global_id_and_update(&namerec->data.id, True);
2299 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2300 nmb_namestr(&namerec->name)));
2301 store_record = True;
2302 goto done;
2303 case WINS_TOMBSTONED:
2304 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2305 nmb_namestr(&namerec->name)));
2306 remove_name_from_wins_namelist(namerec );
2307 goto done;
2309 } else {
2310 switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2311 case WINS_ACTIVE:
2312 /* that's not as MS says it should be */
2313 namerec->data.wins_flags&=~WINS_STATE_MASK;
2314 namerec->data.wins_flags|=WINS_TOMBSTONED;
2315 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2316 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2317 nmb_namestr(&namerec->name)));
2318 store_record = True;
2319 goto done;
2320 case WINS_TOMBSTONED:
2321 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2322 nmb_namestr(&namerec->name)));
2323 remove_name_from_wins_namelist(namerec );
2324 goto done;
2325 case WINS_RELEASED:
2326 DEBUG(0,("wins_processing_traverse_fn: %s is in released state and\
2327 we are not the wins owner !\n", nmb_namestr(&namerec->name)));
2328 goto done;
2333 done:
2335 if (store_record) {
2336 wins_store_changed_namerec(namerec);
2339 SAFE_FREE(namerec->data.ip);
2340 SAFE_FREE(namerec);
2342 return 0;
2345 /*******************************************************************
2346 Time dependent wins processing.
2347 ******************************************************************/
2349 void initiate_wins_processing(time_t t)
2351 static time_t lasttime = 0;
2353 if (!lasttime) {
2354 lasttime = t;
2356 if (t - lasttime < 20) {
2357 return;
2360 if(!lp_we_are_a_wins_server()) {
2361 lasttime = t;
2362 return;
2365 tdb_traverse(wins_tdb, wins_processing_traverse_fn, &t);
2367 wins_delete_all_tmp_in_memory_records();
2369 wins_write_database(t, True);
2371 lasttime = t;
2374 /*******************************************************************
2375 Write out one record.
2376 ******************************************************************/
2378 void wins_write_name_record(struct name_record *namerec, XFILE *fp)
2380 int i;
2381 struct tm *tm;
2383 DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) ));
2385 if( namerec->data.death_time != PERMANENT_TTL ) {
2386 char *ts, *nl;
2388 tm = localtime(&namerec->data.death_time);
2389 if (!tm) {
2390 return;
2392 ts = asctime(tm);
2393 if (!ts) {
2394 return;
2396 nl = strrchr( ts, '\n' );
2397 if( NULL != nl ) {
2398 *nl = '\0';
2400 DEBUGADD(4,("TTL = %s ", ts ));
2401 } else {
2402 DEBUGADD(4,("TTL = PERMANENT "));
2405 for (i = 0; i < namerec->data.num_ips; i++) {
2406 DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) ));
2408 DEBUGADD(4,("%2x\n", namerec->data.nb_flags ));
2410 if( namerec->data.source == REGISTER_NAME ) {
2411 unstring name;
2412 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
2413 x_fprintf(fp, "\"%s#%02x\" %d ", name,namerec->name.name_type, /* Ignore scope. */
2414 (int)namerec->data.death_time);
2416 for (i = 0; i < namerec->data.num_ips; i++)
2417 x_fprintf( fp, "%s ", inet_ntoa( namerec->data.ip[i] ) );
2418 x_fprintf( fp, "%2xR\n", namerec->data.nb_flags );
2422 /*******************************************************************
2423 Write out the current WINS database.
2424 ******************************************************************/
2426 static int wins_writedb_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2428 struct name_record *namerec = NULL;
2429 XFILE *fp = (XFILE *)state;
2431 if (kbuf.dsize != sizeof(unstring) + 1) {
2432 return 0;
2435 namerec = wins_record_to_name_record(kbuf, dbuf);
2436 if (!namerec) {
2437 return 0;
2440 wins_write_name_record(namerec, fp);
2442 SAFE_FREE(namerec->data.ip);
2443 SAFE_FREE(namerec);
2444 return 0;
2448 void wins_write_database(time_t t, bool background)
2450 static time_t last_write_time = 0;
2451 char *fname = NULL;
2452 char *fnamenew = NULL;
2454 XFILE *fp;
2456 if (background) {
2457 if (!last_write_time) {
2458 last_write_time = t;
2460 if (t - last_write_time < 120) {
2461 return;
2466 if(!lp_we_are_a_wins_server()) {
2467 return;
2470 /* We will do the writing in a child process to ensure that the parent doesn't block while this is done */
2471 if (background) {
2472 CatchChild();
2473 if (fork()) {
2474 return;
2476 if (tdb_reopen(wins_tdb)) {
2477 DEBUG(0,("wins_write_database: tdb_reopen failed. Error was %s\n",
2478 strerror(errno)));
2479 _exit(0);
2480 return;
2484 if (!(fname = state_path(WINS_LIST))) {
2485 goto err_exit;
2487 /* This is safe as the 0 length means "don't expand". */
2488 all_string_sub(fname,"//", "/", 0);
2490 if (asprintf(&fnamenew, "%s.%u", fname, (unsigned int)getpid()) < 0) {
2491 goto err_exit;
2494 if((fp = x_fopen(fnamenew,O_WRONLY|O_CREAT,0644)) == NULL) {
2495 DEBUG(0,("wins_write_database: Can't open %s. Error was %s\n", fnamenew, strerror(errno)));
2496 goto err_exit;
2499 DEBUG(4,("wins_write_database: Dump of WINS name list.\n"));
2501 x_fprintf(fp,"VERSION %d %u\n", WINS_VERSION, 0);
2503 tdb_traverse(wins_tdb, wins_writedb_traverse_fn, fp);
2505 x_fclose(fp);
2506 chmod(fnamenew,0644);
2507 unlink(fname);
2508 rename(fnamenew,fname);
2510 err_exit:
2512 SAFE_FREE(fnamenew);
2513 TALLOC_FREE(fname);
2515 if (background) {
2516 _exit(0);
2520 #if 0
2521 Until winsrepl is done.
2522 /****************************************************************************
2523 Process a internal Samba message receiving a wins record.
2524 ***************************************************************************/
2526 void nmbd_wins_new_entry(struct messaging_context *msg,
2527 void *private_data,
2528 uint32_t msg_type,
2529 struct server_id server_id,
2530 DATA_BLOB *data)
2532 WINS_RECORD *record;
2533 struct name_record *namerec = NULL;
2534 struct name_record *new_namerec = NULL;
2535 struct nmb_name question;
2536 bool overwrite=False;
2537 struct in_addr our_fake_ip;
2538 int i;
2540 our_fake_ip = interpret_addr2("0.0.0.0");
2541 if (buf==NULL) {
2542 return;
2545 /* Record should use UNIX codepage. Ensure this is so in the wrepld code. JRA. */
2546 record=(WINS_RECORD *)buf;
2548 make_nmb_name(&question, record->name, record->type);
2550 namerec = find_name_on_subnet(wins_server_subnet, &question, FIND_ANY_NAME);
2552 /* record doesn't exist, add it */
2553 if (namerec == NULL) {
2554 DEBUG(3,("nmbd_wins_new_entry: adding new replicated record: %s<%02x> for wins server: %s\n",
2555 record->name, record->type, inet_ntoa(record->wins_ip)));
2557 new_namerec=add_name_to_subnet( wins_server_subnet,
2558 record->name,
2559 record->type,
2560 record->nb_flags,
2561 EXTINCTION_INTERVAL,
2562 REGISTER_NAME,
2563 record->num_ips,
2564 record->ip);
2566 if (new_namerec!=NULL) {
2567 update_wins_owner(new_namerec, record->wins_ip);
2568 update_wins_flag(new_namerec, record->wins_flags);
2569 new_namerec->data.id=record->id;
2571 wins_server_subnet->namelist_changed = True;
2575 /* check if we have a conflict */
2576 if (namerec != NULL) {
2577 /* both records are UNIQUE */
2578 if (namerec->data.wins_flags&WINS_UNIQUE && record->wins_flags&WINS_UNIQUE) {
2580 /* the database record is a replica */
2581 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
2582 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED) {
2583 if (ip_equal_v4(namerec->data.wins_ip, record->wins_ip))
2584 overwrite=True;
2585 } else
2586 overwrite=True;
2587 } else {
2588 /* we are the wins owner of the database record */
2589 /* the 2 records have the same IP address */
2590 if (ip_equal_v4(namerec->data.ip[0], record->ip[0])) {
2591 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED)
2592 get_global_id_and_update(&namerec->data.id, True);
2593 else
2594 overwrite=True;
2596 } else {
2597 /* the 2 records have different IP address */
2598 if (namerec->data.wins_flags&WINS_ACTIVE) {
2599 if (record->wins_flags&WINS_TOMBSTONED)
2600 get_global_id_and_update(&namerec->data.id, True);
2601 if (record->wins_flags&WINS_ACTIVE)
2602 /* send conflict challenge to the replica node */
2604 } else
2605 overwrite=True;
2611 /* the replica is a standard group */
2612 if (record->wins_flags&WINS_NGROUP || record->wins_flags&WINS_SGROUP) {
2613 /* if the database record is unique and active force a name release */
2614 if (namerec->data.wins_flags&WINS_UNIQUE)
2615 /* send a release name to the unique node */
2617 overwrite=True;
2621 /* the replica is a special group */
2622 if (record->wins_flags&WINS_SGROUP && namerec->data.wins_flags&WINS_SGROUP) {
2623 if (namerec->data.wins_flags&WINS_ACTIVE) {
2624 for (i=0; i<record->num_ips; i++)
2625 if(!find_ip_in_name_record(namerec, record->ip[i]))
2626 add_ip_to_name_record(namerec, record->ip[i]);
2627 } else {
2628 overwrite=True;
2632 /* the replica is a multihomed host */
2634 /* I'm giving up on multi homed. Too much complex to understand */
2636 if (record->wins_flags&WINS_MHOMED) {
2637 if (! (namerec->data.wins_flags&WINS_ACTIVE)) {
2638 if ( !(namerec->data.wins_flags&WINS_RELEASED) && !(namerec->data.wins_flags&WINS_NGROUP))
2639 overwrite=True;
2641 else {
2642 if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
2643 overwrite=True;
2645 if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip))
2646 if (namerec->data.wins_flags&WINS_UNIQUE)
2647 get_global_id_and_update(&namerec->data.id, True);
2651 if (record->wins_flags&WINS_ACTIVE && namerec->data.wins_flags&WINS_ACTIVE)
2652 if (namerec->data.wins_flags&WINS_UNIQUE ||
2653 namerec->data.wins_flags&WINS_MHOMED)
2654 if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
2655 overwrite=True;
2659 if (overwrite == False)
2660 DEBUG(3, ("nmbd_wins_new_entry: conflict in adding record: %s<%02x> from wins server: %s\n",
2661 record->name, record->type, inet_ntoa(record->wins_ip)));
2662 else {
2663 DEBUG(3, ("nmbd_wins_new_entry: replacing record: %s<%02x> from wins server: %s\n",
2664 record->name, record->type, inet_ntoa(record->wins_ip)));
2666 /* remove the old record and add a new one */
2667 remove_name_from_namelist( wins_server_subnet, namerec );
2668 new_namerec=add_name_to_subnet( wins_server_subnet, record->name, record->type, record->nb_flags,
2669 EXTINCTION_INTERVAL, REGISTER_NAME, record->num_ips, record->ip);
2670 if (new_namerec!=NULL) {
2671 update_wins_owner(new_namerec, record->wins_ip);
2672 update_wins_flag(new_namerec, record->wins_flags);
2673 new_namerec->data.id=record->id;
2675 wins_server_subnet->namelist_changed = True;
2678 wins_server_subnet->namelist_changed = True;
2683 #endif