ctdb: Accept the key in hex format for the pstore command
[Samba.git] / source3 / nmbd / nmbd_winsserver.c
blob98ec625098744c9abc7618b1d3597e8868cd8143
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_t nb_flags;
85 unsigned char nr_src;
86 uint32_t death_time, refresh_time;
87 uint32_t id_low, id_high;
88 uint32_t saddr;
89 uint32_t wins_flags;
90 uint32_t 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 namerec->data.id |= ((uint64_t)id_high << 32);
150 namerec->data.wins_ip.s_addr = saddr;
151 namerec->data.wins_flags = wins_flags,
152 namerec->data.num_ips = num_ips;
154 for (i = 0; i < num_ips; i++) {
155 namerec->data.ip[i].s_addr = IVAL(data.dptr, len + (i*4));
158 return namerec;
161 /****************************************************************************
162 Convert a struct name_record to a wins.tdb record. Ignore the scope.
163 *****************************************************************************/
165 static TDB_DATA name_record_to_wins_record(const struct name_record *namerec)
167 TDB_DATA data;
168 size_t len = 0;
169 int i;
170 uint32_t id_low = (namerec->data.id & 0xFFFFFFFF);
171 uint32_t id_high = (namerec->data.id >> 32) & 0xFFFFFFFF;
173 ZERO_STRUCT(data);
175 len = (2 + 1 + (7*4)); /* "wbddddddd" */
176 len += (namerec->data.num_ips * 4);
178 data.dptr = (uint8_t *)SMB_MALLOC(len);
179 if (!data.dptr) {
180 return data;
182 data.dsize = len;
184 len = tdb_pack(data.dptr, data.dsize, "wbddddddd",
185 namerec->data.nb_flags,
186 (unsigned char)namerec->data.source,
187 (uint32_t)namerec->data.death_time,
188 (uint32_t)namerec->data.refresh_time,
189 id_low,
190 id_high,
191 (uint32_t)namerec->data.wins_ip.s_addr,
192 (uint32_t)namerec->data.wins_flags,
193 (uint32_t)namerec->data.num_ips );
195 for (i = 0; i < namerec->data.num_ips; i++) {
196 SIVAL(data.dptr, len + (i*4), namerec->data.ip[i].s_addr);
199 return data;
202 /****************************************************************************
203 Create key. Key is UNIX codepage namestring (usually utf8 64 byte len) with 1 byte type.
204 *****************************************************************************/
206 static TDB_DATA name_to_key(const struct nmb_name *nmbname)
208 static char keydata[sizeof(unstring) + 1];
209 TDB_DATA key;
211 memset(keydata, '\0', sizeof(keydata));
213 pull_ascii_nstring(keydata, sizeof(unstring), nmbname->name);
214 (void)strupper_m(keydata);
215 keydata[sizeof(unstring)] = nmbname->name_type;
216 key.dptr = (uint8_t *)keydata;
217 key.dsize = sizeof(keydata);
219 return key;
222 /****************************************************************************
223 Lookup a given name in the wins.tdb and create a temporary malloc'ed data struct
224 on the linked list. We will free this later in XXXX().
225 *****************************************************************************/
227 struct name_record *find_name_on_wins_subnet(const struct nmb_name *nmbname, bool self_only)
229 TDB_DATA data, key;
230 struct name_record *nr = NULL;
231 struct name_record *namerec = NULL;
233 if (!wins_tdb) {
234 return NULL;
237 key = name_to_key(nmbname);
238 data = tdb_fetch(wins_tdb, key);
240 if (data.dsize == 0) {
241 return NULL;
244 namerec = wins_record_to_name_record(key, data);
246 /* done with the this */
248 SAFE_FREE( data.dptr );
250 if (!namerec) {
251 return NULL;
254 /* Self names only - these include permanent names. */
255 if( self_only && (namerec->data.source != SELF_NAME) && (namerec->data.source != PERMANENT_NAME) ) {
256 DEBUG( 9, ( "find_name_on_wins_subnet: self name %s NOT FOUND\n", nmb_namestr(nmbname) ) );
257 SAFE_FREE(namerec->data.ip);
258 SAFE_FREE(namerec);
259 return NULL;
262 /* Search for this name record on the list. Replace it if found. */
264 for( nr = wins_server_subnet->namelist; nr; nr = nr->next) {
265 if (memcmp(nmbname->name, nr->name.name, 16) == 0) {
266 /* Delete it. */
267 DLIST_REMOVE(wins_server_subnet->namelist, nr);
268 SAFE_FREE(nr->data.ip);
269 SAFE_FREE(nr);
270 break;
274 DLIST_ADD(wins_server_subnet->namelist, namerec);
275 return namerec;
278 /****************************************************************************
279 Overwrite or add a given name in the wins.tdb.
280 *****************************************************************************/
282 static bool store_or_replace_wins_namerec(const struct name_record *namerec, int tdb_flag)
284 TDB_DATA key, data;
285 int ret;
287 if (!wins_tdb) {
288 return False;
291 key = name_to_key(&namerec->name);
292 data = name_record_to_wins_record(namerec);
294 if (data.dptr == NULL) {
295 return False;
298 ret = tdb_store(wins_tdb, key, data, tdb_flag);
300 SAFE_FREE(data.dptr);
301 return (ret == 0) ? True : False;
304 /****************************************************************************
305 Overwrite a given name in the wins.tdb.
306 *****************************************************************************/
308 bool wins_store_changed_namerec(const struct name_record *namerec)
310 return store_or_replace_wins_namerec(namerec, TDB_REPLACE);
313 /****************************************************************************
314 Primary interface into creating and overwriting records in the wins.tdb.
315 *****************************************************************************/
317 bool add_name_to_wins_subnet(const struct name_record *namerec)
319 return store_or_replace_wins_namerec(namerec, TDB_INSERT);
322 /****************************************************************************
323 Delete a given name in the tdb and remove the temporary malloc'ed data struct
324 on the linked list.
325 *****************************************************************************/
327 bool remove_name_from_wins_namelist(struct name_record *namerec)
329 TDB_DATA key;
330 int ret;
332 if (!wins_tdb) {
333 return False;
336 key = name_to_key(&namerec->name);
337 ret = tdb_delete(wins_tdb, key);
339 DLIST_REMOVE(wins_server_subnet->namelist, namerec);
341 /* namerec must be freed by the caller */
343 return (ret == 0) ? True : False;
346 /****************************************************************************
347 Dump out the complete namelist.
348 *****************************************************************************/
350 static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
352 struct name_record *namerec = NULL;
353 XFILE *fp = (XFILE *)state;
355 if (kbuf.dsize != sizeof(unstring) + 1) {
356 return 0;
359 namerec = wins_record_to_name_record(kbuf, dbuf);
360 if (!namerec) {
361 return 0;
364 dump_name_record(namerec, fp);
366 SAFE_FREE(namerec->data.ip);
367 SAFE_FREE(namerec);
368 return 0;
371 void dump_wins_subnet_namelist(XFILE *fp)
373 tdb_traverse(wins_tdb, traverse_fn, (void *)fp);
376 /****************************************************************************
377 Change the wins owner address in the record.
378 *****************************************************************************/
380 static void update_wins_owner(struct name_record *namerec, struct in_addr wins_ip)
382 namerec->data.wins_ip=wins_ip;
385 /****************************************************************************
386 Create the wins flags based on the nb flags and the input value.
387 *****************************************************************************/
389 static void update_wins_flag(struct name_record *namerec, int flags)
391 namerec->data.wins_flags=0x0;
393 /* if it's a group, it can be a normal or a special one */
394 if (namerec->data.nb_flags & NB_GROUP) {
395 if (namerec->name.name_type==0x1C) {
396 namerec->data.wins_flags|=WINS_SGROUP;
397 } else {
398 if (namerec->data.num_ips>1) {
399 namerec->data.wins_flags|=WINS_SGROUP;
400 } else {
401 namerec->data.wins_flags|=WINS_NGROUP;
404 } else {
405 /* can be unique or multi-homed */
406 if (namerec->data.num_ips>1) {
407 namerec->data.wins_flags|=WINS_MHOMED;
408 } else {
409 namerec->data.wins_flags|=WINS_UNIQUE;
413 /* the node type are the same bits */
414 namerec->data.wins_flags|=namerec->data.nb_flags&NB_NODETYPEMASK;
416 /* the static bit is elsewhere */
417 if (namerec->data.death_time == PERMANENT_TTL) {
418 namerec->data.wins_flags|=WINS_STATIC;
421 /* and add the given bits */
422 namerec->data.wins_flags|=flags;
424 DEBUG(8,("update_wins_flag: nbflags: 0x%x, ttl: %d, flags: 0x%x, winsflags: 0x%x\n",
425 namerec->data.nb_flags, (int)namerec->data.death_time, flags, namerec->data.wins_flags));
428 /****************************************************************************
429 Return the general ID value and increase it if requested.
430 *****************************************************************************/
432 static void get_global_id_and_update(uint64_t *current_id, bool update)
435 * it's kept as a static here, to prevent people from messing
436 * with the value directly
439 static uint64_t general_id = 1;
441 DEBUG(5,("get_global_id_and_update: updating version ID: %d\n", (int)general_id));
443 *current_id = general_id;
445 if (update) {
446 general_id++;
450 /****************************************************************************
451 Possibly call the WINS hook external program when a WINS change is made.
452 Also stores the changed record back in the wins_tdb.
453 *****************************************************************************/
455 static void wins_hook(const char *operation, struct name_record *namerec, int ttl)
457 char *command = NULL;
458 char *cmd = lp_wins_hook(talloc_tos());
459 char *p, *namestr;
460 int i;
461 TALLOC_CTX *ctx = talloc_tos();
463 wins_store_changed_namerec(namerec);
465 if (!cmd || !*cmd) {
466 return;
469 for (p=namerec->name.name; *p; p++) {
470 if (!(isalnum((int)*p) || strchr_m("._-",*p))) {
471 DEBUG(3,("not calling wins hook for invalid name %s\n", nmb_namestr(&namerec->name)));
472 return;
476 /* Use the name without the nametype (and scope) appended */
478 namestr = nmb_namestr(&namerec->name);
479 if ((p = strchr(namestr, '<'))) {
480 *p = 0;
483 command = talloc_asprintf(ctx,
484 "%s %s %s %02x %d",
485 cmd,
486 operation,
487 namestr,
488 namerec->name.name_type,
489 ttl);
490 if (!command) {
491 return;
494 for (i=0;i<namerec->data.num_ips;i++) {
495 command = talloc_asprintf_append(command,
496 " %s",
497 inet_ntoa(namerec->data.ip[i]));
498 if (!command) {
499 return;
503 DEBUG(3,("calling wins hook for %s\n", nmb_namestr(&namerec->name)));
504 smbrun(command, NULL);
505 TALLOC_FREE(command);
508 /****************************************************************************
509 Determine if this packet should be allocated to the WINS server.
510 *****************************************************************************/
512 bool packet_is_for_wins_server(struct packet_struct *packet)
514 struct nmb_packet *nmb = &packet->packet.nmb;
516 /* Only unicast packets go to a WINS server. */
517 if((wins_server_subnet == NULL) || (nmb->header.nm_flags.bcast == True)) {
518 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #1.\n"));
519 return False;
522 /* Check for node status requests. */
523 if (nmb->question.question_type != QUESTION_TYPE_NB_QUERY) {
524 return False;
527 switch(nmb->header.opcode) {
529 * A WINS server issues WACKS, not receives them.
531 case NMB_WACK_OPCODE:
532 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #2 (WACK).\n"));
533 return False;
535 * A WINS server only processes registration and
536 * release requests, not responses.
538 case NMB_NAME_REG_OPCODE:
539 case NMB_NAME_MULTIHOMED_REG_OPCODE:
540 case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
541 case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
542 if(nmb->header.response) {
543 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #3 (response = 1).\n"));
544 return False;
546 break;
548 case NMB_NAME_RELEASE_OPCODE:
549 if(nmb->header.response) {
550 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #4 (response = 1).\n"));
551 return False;
553 break;
556 * Only process unicast name queries with rd = 1.
558 case NMB_NAME_QUERY_OPCODE:
559 if(!nmb->header.response && !nmb->header.nm_flags.recursion_desired) {
560 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #5 (response = 1).\n"));
561 return False;
563 break;
566 return True;
569 /****************************************************************************
570 Utility function to decide what ttl to give a register/refresh request.
571 *****************************************************************************/
573 static int get_ttl_from_packet(struct nmb_packet *nmb)
575 int ttl = nmb->additional->ttl;
577 if (ttl < lp_min_wins_ttl()) {
578 ttl = lp_min_wins_ttl();
581 if (ttl > lp_max_wins_ttl()) {
582 ttl = lp_max_wins_ttl();
585 return ttl;
588 /****************************************************************************
589 Load or create the WINS database.
590 *****************************************************************************/
592 bool initialise_wins(void)
594 time_t time_now = time(NULL);
595 XFILE *fp;
596 char line[1024];
597 char *db_path;
598 char *list_path;
600 if(!lp_we_are_a_wins_server()) {
601 return True;
604 db_path = state_path("wins.tdb");
605 if (db_path == NULL) {
606 return false;
609 /* Open the wins.tdb. */
610 wins_tdb = tdb_open_log(db_path, 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
611 O_CREAT|O_RDWR, 0600);
612 TALLOC_FREE(db_path);
613 if (!wins_tdb) {
614 DEBUG(0,("initialise_wins: failed to open wins.tdb. Error was %s\n",
615 strerror(errno) ));
616 return False;
619 tdb_store_int32(wins_tdb, "WINSDB_VERSION", WINSDB_VERSION);
621 add_samba_names_to_subnet(wins_server_subnet);
623 list_path = state_path(WINS_LIST);
624 if (list_path == NULL) {
625 tdb_close(wins_tdb);
626 return false;
629 fp = x_fopen(list_path, O_RDONLY, 0);
630 TALLOC_FREE(list_path);
631 if (fp == NULL) {
632 DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
633 WINS_LIST, strerror(errno) ));
634 return True;
637 while (!x_feof(fp)) {
638 char *name_str = NULL;
639 char *ip_str = NULL;
640 char *ttl_str = NULL, *nb_flags_str = NULL;
641 unsigned int num_ips;
642 char *name = NULL;
643 struct in_addr *ip_list = NULL;
644 int type = 0;
645 int nb_flags;
646 int ttl;
647 const char *ptr;
648 char *p = NULL;
649 bool got_token;
650 bool was_ip;
651 int i;
652 unsigned int hash;
653 int version;
654 TALLOC_CTX *frame = NULL;
656 /* Read a line from the wins.dat file. Strips whitespace
657 from the beginning and end of the line. */
658 if (!fgets_slash(line,sizeof(line),fp)) {
659 continue;
662 if (*line == '#') {
663 continue;
666 if (strncmp(line,"VERSION ", 8) == 0) {
667 if (sscanf(line,"VERSION %d %u", &version, &hash) != 2 ||
668 version != WINS_VERSION) {
669 DEBUG(0,("Discarding invalid wins.dat file [%s]\n",line));
670 x_fclose(fp);
671 return True;
673 continue;
676 ptr = line;
679 * Now we handle multiple IP addresses per name we need
680 * to iterate over the line twice. The first time to
681 * determine how many IP addresses there are, the second
682 * time to actually parse them into the ip_list array.
685 frame = talloc_stackframe();
686 if (!next_token_talloc(frame,&ptr,&name_str,NULL)) {
687 DEBUG(0,("initialise_wins: Failed to parse name when parsing line %s\n", line ));
688 TALLOC_FREE(frame);
689 continue;
692 if (!next_token_talloc(frame,&ptr,&ttl_str,NULL)) {
693 DEBUG(0,("initialise_wins: Failed to parse time to live when parsing line %s\n", line ));
694 TALLOC_FREE(frame);
695 continue;
699 * Determine the number of IP addresses per line.
701 num_ips = 0;
702 do {
703 got_token = next_token_talloc(frame,&ptr,&ip_str,NULL);
704 was_ip = False;
706 if(got_token && strchr(ip_str, '.')) {
707 num_ips++;
708 was_ip = True;
710 } while(got_token && was_ip);
712 if(num_ips == 0) {
713 DEBUG(0,("initialise_wins: Missing IP address when parsing line %s\n", line ));
714 TALLOC_FREE(frame);
715 continue;
718 if(!got_token) {
719 DEBUG(0,("initialise_wins: Missing nb_flags when parsing line %s\n", line ));
720 TALLOC_FREE(frame);
721 continue;
724 /* Allocate the space for the ip_list. */
725 if((ip_list = SMB_MALLOC_ARRAY( struct in_addr, num_ips)) == NULL) {
726 DEBUG(0,("initialise_wins: Malloc fail !\n"));
727 x_fclose(fp);
728 TALLOC_FREE(frame);
729 return False;
732 /* Reset and re-parse the line. */
733 ptr = line;
734 next_token_talloc(frame,&ptr,&name_str,NULL);
735 next_token_talloc(frame,&ptr,&ttl_str,NULL);
736 for(i = 0; i < num_ips; i++) {
737 next_token_talloc(frame,&ptr, &ip_str, NULL);
738 ip_list[i] = interpret_addr2(ip_str);
740 next_token_talloc(frame,&ptr,&nb_flags_str,NULL);
743 * Deal with SELF or REGISTER name encoding. Default is REGISTER
744 * for compatibility with old nmbds.
747 if(nb_flags_str[strlen(nb_flags_str)-1] == 'S') {
748 DEBUG(5,("initialise_wins: Ignoring SELF name %s\n", line));
749 SAFE_FREE(ip_list);
750 TALLOC_FREE(frame);
751 continue;
754 if(nb_flags_str[strlen(nb_flags_str)-1] == 'R') {
755 nb_flags_str[strlen(nb_flags_str)-1] = '\0';
758 /* Netbios name. # divides the name from the type (hex): netbios#xx */
759 name = name_str;
761 if((p = strchr(name,'#')) != NULL) {
762 *p = 0;
763 sscanf(p+1,"%x",&type);
766 /* Decode the netbios flags (hex) and the time-to-live (in seconds). */
767 sscanf(nb_flags_str,"%x",&nb_flags);
768 sscanf(ttl_str,"%d",&ttl);
770 /* add all entries that have 60 seconds or more to live */
771 if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) {
772 if(ttl != PERMANENT_TTL) {
773 ttl -= time_now;
776 DEBUG( 4, ("initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
777 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
779 (void)add_name_to_subnet( wins_server_subnet, name, type, nb_flags,
780 ttl, REGISTER_NAME, num_ips, ip_list );
781 } else {
782 DEBUG(4, ("initialise_wins: not adding name (ttl problem) "
783 "%s#%02x ttl = %d first IP %s flags = %2x\n",
784 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
787 TALLOC_FREE(frame);
788 SAFE_FREE(ip_list);
791 x_fclose(fp);
792 return True;
795 /****************************************************************************
796 Send a WINS WACK (Wait ACKnowledgement) response.
797 **************************************************************************/
799 static void send_wins_wack_response(int ttl, struct packet_struct *p)
801 struct nmb_packet *nmb = &p->packet.nmb;
802 unsigned char rdata[2];
804 rdata[0] = rdata[1] = 0;
806 /* Taken from nmblib.c - we need to send back almost
807 identical bytes from the requesting packet header. */
809 rdata[0] = (nmb->header.opcode & 0xF) << 3;
810 if (nmb->header.nm_flags.authoritative && nmb->header.response) {
811 rdata[0] |= 0x4;
813 if (nmb->header.nm_flags.trunc) {
814 rdata[0] |= 0x2;
816 if (nmb->header.nm_flags.recursion_desired) {
817 rdata[0] |= 0x1;
819 if (nmb->header.nm_flags.recursion_available && nmb->header.response) {
820 rdata[1] |= 0x80;
822 if (nmb->header.nm_flags.bcast) {
823 rdata[1] |= 0x10;
826 reply_netbios_packet(p, /* Packet to reply to. */
827 0, /* Result code. */
828 NMB_WAIT_ACK, /* nmbd type code. */
829 NMB_WACK_OPCODE, /* opcode. */
830 ttl, /* ttl. */
831 (char *)rdata, /* data to send. */
832 2); /* data length. */
835 /****************************************************************************
836 Send a WINS name registration response.
837 **************************************************************************/
839 static void send_wins_name_registration_response(int rcode, int ttl, struct packet_struct *p)
841 struct nmb_packet *nmb = &p->packet.nmb;
842 char rdata[6];
844 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
846 reply_netbios_packet(p, /* Packet to reply to. */
847 rcode, /* Result code. */
848 WINS_REG, /* nmbd type code. */
849 NMB_NAME_REG_OPCODE, /* opcode. */
850 ttl, /* ttl. */
851 rdata, /* data to send. */
852 6); /* data length. */
855 /***********************************************************************
856 Deal with a name refresh request to a WINS server.
857 ************************************************************************/
859 void wins_process_name_refresh_request( struct subnet_record *subrec,
860 struct packet_struct *p )
862 struct nmb_packet *nmb = &p->packet.nmb;
863 struct nmb_name *question = &nmb->question.question_name;
864 bool bcast = nmb->header.nm_flags.bcast;
865 uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
866 bool group = (nb_flags & NB_GROUP) ? True : False;
867 struct name_record *namerec = NULL;
868 int ttl = get_ttl_from_packet(nmb);
869 struct in_addr from_ip;
870 struct in_addr our_fake_ip;
872 our_fake_ip = interpret_addr2("0.0.0.0");
873 putip( (char *)&from_ip, &nmb->additional->rdata[2] );
875 if(bcast) {
877 * We should only get unicast name refresh packets here.
878 * Anyone trying to refresh broadcast should not be going
879 * to a WINS server. Log an error here.
881 if( DEBUGLVL( 0 ) ) {
882 dbgtext( "wins_process_name_refresh_request: " );
883 dbgtext( "Broadcast name refresh request received " );
884 dbgtext( "for name %s ", nmb_namestr(question) );
885 dbgtext( "from IP %s ", inet_ntoa(from_ip) );
886 dbgtext( "on subnet %s. ", subrec->subnet_name );
887 dbgtext( "Error - Broadcasts should not be sent " );
888 dbgtext( "to a WINS server\n" );
890 return;
893 if( DEBUGLVL( 3 ) ) {
894 dbgtext( "wins_process_name_refresh_request: " );
895 dbgtext( "Name refresh for name %s IP %s\n",
896 nmb_namestr(question), inet_ntoa(from_ip) );
900 * See if the name already exists.
901 * If not, handle it as a name registration and return.
903 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
906 * If this is a refresh request and the name doesn't exist then
907 * treat it like a registration request. This allows us to recover
908 * from errors (tridge)
910 if(namerec == NULL) {
911 if( DEBUGLVL( 3 ) ) {
912 dbgtext( "wins_process_name_refresh_request: " );
913 dbgtext( "Name refresh for name %s ",
914 nmb_namestr( question ) );
915 dbgtext( "and the name does not exist. Treating " );
916 dbgtext( "as registration.\n" );
918 wins_process_name_registration_request(subrec,p);
919 return;
923 * if the name is present but not active, simply remove it
924 * and treat the refresh request as a registration & return.
926 if (namerec != NULL && !WINS_STATE_ACTIVE(namerec)) {
927 if( DEBUGLVL( 5 ) ) {
928 dbgtext( "wins_process_name_refresh_request: " );
929 dbgtext( "Name (%s) in WINS ", nmb_namestr(question) );
930 dbgtext( "was not active - removing it.\n" );
932 remove_name_from_namelist( subrec, namerec );
933 namerec = NULL;
934 wins_process_name_registration_request( subrec, p );
935 return;
939 * Check that the group bits for the refreshing name and the
940 * name in our database match. If not, refuse the refresh.
941 * [crh: Why RFS_ERR instead of ACT_ERR? Is this what MS does?]
943 if( (namerec != NULL) &&
944 ( (group && !NAME_GROUP(namerec))
945 || (!group && NAME_GROUP(namerec)) ) ) {
946 if( DEBUGLVL( 3 ) ) {
947 dbgtext( "wins_process_name_refresh_request: " );
948 dbgtext( "Name %s ", nmb_namestr(question) );
949 dbgtext( "group bit = %s does not match ",
950 group ? "True" : "False" );
951 dbgtext( "group bit in WINS for this name.\n" );
953 send_wins_name_registration_response(RFS_ERR, 0, p);
954 return;
958 * For a unique name check that the person refreshing the name is
959 * one of the registered IP addresses. If not - fail the refresh.
960 * Do the same for group names with a type of 0x1c.
961 * Just return success for unique 0x1d refreshes. For normal group
962 * names update the ttl and return success.
964 if( (!group || (group && (question->name_type == 0x1c)))
965 && find_ip_in_name_record(namerec, from_ip) ) {
967 * Update the ttl.
969 update_name_ttl(namerec, ttl);
972 * if the record is a replica:
973 * we take ownership and update the version ID.
975 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
976 update_wins_owner(namerec, our_fake_ip);
977 get_global_id_and_update(&namerec->data.id, True);
980 send_wins_name_registration_response(0, ttl, p);
981 wins_hook("refresh", namerec, ttl);
982 return;
983 } else if((group && (question->name_type == 0x1c))) {
985 * Added by crh for bug #1079.
986 * Fix from Bert Driehuis
988 if( DEBUGLVL( 3 ) ) {
989 dbgtext( "wins_process_name_refresh_request: " );
990 dbgtext( "Name refresh for name %s, ",
991 nmb_namestr(question) );
992 dbgtext( "but IP address %s ", inet_ntoa(from_ip) );
993 dbgtext( "is not yet associated with " );
994 dbgtext( "that name. Treating as registration.\n" );
996 wins_process_name_registration_request(subrec,p);
997 return;
998 } else if(group) {
1000 * Normal groups are all registered with an IP address of
1001 * 255.255.255.255 so we can't search for the IP address.
1003 update_name_ttl(namerec, ttl);
1004 wins_hook("refresh", namerec, ttl);
1005 send_wins_name_registration_response(0, ttl, p);
1006 return;
1007 } else if(!group && (question->name_type == 0x1d)) {
1009 * Special name type - just pretend the refresh succeeded.
1011 send_wins_name_registration_response(0, ttl, p);
1012 return;
1013 } else {
1015 * Fail the refresh.
1017 if( DEBUGLVL( 3 ) ) {
1018 dbgtext( "wins_process_name_refresh_request: " );
1019 dbgtext( "Name refresh for name %s with IP %s ",
1020 nmb_namestr(question), inet_ntoa(from_ip) );
1021 dbgtext( "and is IP is not known to the name.\n" );
1023 send_wins_name_registration_response(RFS_ERR, 0, p);
1024 return;
1028 /***********************************************************************
1029 Deal with a name registration request query success to a client that
1030 owned the name.
1032 We have a locked pointer to the original packet stashed away in the
1033 userdata pointer. The success here is actually a failure as it means
1034 the client we queried wants to keep the name, so we must return
1035 a registration failure to the original requestor.
1036 ************************************************************************/
1038 static void wins_register_query_success(struct subnet_record *subrec,
1039 struct userdata_struct *userdata,
1040 struct nmb_name *question_name,
1041 struct in_addr ip,
1042 struct res_rec *answers)
1044 struct packet_struct *orig_reg_packet;
1046 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1048 DEBUG(3,("wins_register_query_success: Original client at IP %s still wants the \
1049 name %s. Rejecting registration request.\n", inet_ntoa(ip), nmb_namestr(question_name) ));
1051 send_wins_name_registration_response(ACT_ERR, 0, orig_reg_packet);
1053 orig_reg_packet->locked = False;
1054 free_packet(orig_reg_packet);
1057 /***********************************************************************
1058 Deal with a name registration request query failure to a client that
1059 owned the name.
1061 We have a locked pointer to the original packet stashed away in the
1062 userdata pointer. The failure here is actually a success as it means
1063 the client we queried didn't want to keep the name, so we can remove
1064 the old name record and then successfully add the new name.
1065 ************************************************************************/
1067 static void wins_register_query_fail(struct subnet_record *subrec,
1068 struct response_record *rrec,
1069 struct nmb_name *question_name,
1070 int rcode)
1072 struct userdata_struct *userdata = rrec->userdata;
1073 struct packet_struct *orig_reg_packet;
1074 struct name_record *namerec = NULL;
1076 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1079 * We want to just add the name, as we now know the original owner
1080 * didn't want it. But we can't just do that as an arbitary
1081 * amount of time may have taken place between the name query
1082 * request and this timeout/error response. So we check that
1083 * the name still exists and is in the same state - if so
1084 * we remove it and call wins_process_name_registration_request()
1085 * as we know it will do the right thing now.
1088 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1090 if ((namerec != NULL) && (namerec->data.source == REGISTER_NAME) &&
1091 ip_equal_v4(rrec->packet->ip, *namerec->data.ip)) {
1092 remove_name_from_namelist( subrec, namerec);
1093 namerec = NULL;
1096 if(namerec == NULL) {
1097 wins_process_name_registration_request(subrec, orig_reg_packet);
1098 } else {
1099 DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between "
1100 "querying for name %s in order to replace it and this reply.\n",
1101 nmb_namestr(question_name) ));
1104 orig_reg_packet->locked = False;
1105 free_packet(orig_reg_packet);
1108 /***********************************************************************
1109 Deal with a name registration request to a WINS server.
1111 Use the following pseudocode :
1113 registering_group
1116 +--------name exists
1119 | +--- existing name is group
1120 | | |
1121 | | |
1122 | | +--- add name (return).
1125 | +--- exiting name is unique
1128 | +--- query existing owner (return).
1131 +--------name doesn't exist
1134 +--- add name (return).
1136 registering_unique
1139 +--------name exists
1142 | +--- existing name is group
1143 | | |
1144 | | |
1145 | | +--- fail add (return).
1146 | |
1148 | +--- exiting name is unique
1151 | +--- query existing owner (return).
1154 +--------name doesn't exist
1157 +--- add name (return).
1159 As can be seen from the above, the two cases may be collapsed onto each
1160 other with the exception of the case where the name already exists and
1161 is a group name. This case we handle with an if statement.
1163 ************************************************************************/
1165 void wins_process_name_registration_request(struct subnet_record *subrec,
1166 struct packet_struct *p)
1168 unstring name;
1169 struct nmb_packet *nmb = &p->packet.nmb;
1170 struct nmb_name *question = &nmb->question.question_name;
1171 bool bcast = nmb->header.nm_flags.bcast;
1172 uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
1173 int ttl = get_ttl_from_packet(nmb);
1174 struct name_record *namerec = NULL;
1175 struct in_addr from_ip;
1176 bool registering_group_name = (nb_flags & NB_GROUP) ? True : False;
1177 struct in_addr our_fake_ip;
1179 our_fake_ip = interpret_addr2("0.0.0.0");
1180 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1182 if(bcast) {
1184 * We should only get unicast name registration packets here.
1185 * Anyone trying to register broadcast should not be going to a WINS
1186 * server. Log an error here.
1189 DEBUG(0,("wins_process_name_registration_request: broadcast name registration request \
1190 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1191 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1192 return;
1195 DEBUG(3,("wins_process_name_registration_request: %s name registration for name %s \
1196 IP %s\n", registering_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
1199 * See if the name already exists.
1202 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1205 * if the record exists but NOT in active state,
1206 * consider it dead.
1208 if ( (namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1209 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1210 not active - removing it.\n", nmb_namestr(question) ));
1211 remove_name_from_namelist( subrec, namerec );
1212 namerec = NULL;
1216 * Deal with the case where the name found was a dns entry.
1217 * Remove it as we now have a NetBIOS client registering the
1218 * name.
1221 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1222 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1223 a dns lookup - removing it.\n", nmb_namestr(question) ));
1224 remove_name_from_namelist( subrec, namerec );
1225 namerec = NULL;
1229 * Reject if the name exists and is not a REGISTER_NAME.
1230 * (ie. Don't allow any static names to be overwritten.
1233 if((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) {
1234 DEBUG( 3, ( "wins_process_name_registration_request: Attempt \
1235 to register name %s. Name already exists in WINS with source type %d.\n",
1236 nmb_namestr(question), namerec->data.source ));
1237 send_wins_name_registration_response(RFS_ERR, 0, p);
1238 return;
1242 * Special policy decisions based on MS documentation.
1243 * 1). All group names (except names ending in 0x1c) are added as 255.255.255.255.
1244 * 2). All unique names ending in 0x1d are ignored, although a positive response is sent.
1248 * A group name is always added as the local broadcast address, except
1249 * for group names ending in 0x1c.
1250 * Group names with type 0x1c are registered with individual IP addresses.
1253 if(registering_group_name && (question->name_type != 0x1c)) {
1254 from_ip = interpret_addr2("255.255.255.255");
1258 * Ignore all attempts to register a unique 0x1d name, although return success.
1261 if(!registering_group_name && (question->name_type == 0x1d)) {
1262 DEBUG(3,("wins_process_name_registration_request: Ignoring request \
1263 to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
1264 send_wins_name_registration_response(0, ttl, p);
1265 return;
1269 * Next two cases are the 'if statement' mentioned above.
1272 if((namerec != NULL) && NAME_GROUP(namerec)) {
1273 if(registering_group_name) {
1275 * If we are adding a group name, the name exists and is also a group entry just add this
1276 * IP address to it and update the ttl.
1279 DEBUG(3,("wins_process_name_registration_request: Adding IP %s to group name %s.\n",
1280 inet_ntoa(from_ip), nmb_namestr(question) ));
1283 * Check the ip address is not already in the group.
1286 if(!find_ip_in_name_record(namerec, from_ip)) {
1288 * Need to emulate the behaviour of Windows, as
1289 * described in:
1290 * http://lists.samba.org/archive/samba-technical/2001-October/016236.html
1291 * (is there an MS reference for this
1292 * somewhere?) because if the 1c list gets over
1293 * 86 entries, the reply packet is too big
1294 * (rdata>576 bytes) so no reply is sent.
1296 * Keep only the "latest" 25 records, while
1297 * ensuring that the PDC (0x1b) is never removed
1298 * We do this by removing the first entry that
1299 * isn't the 1b entry for the same name,
1300 * on the grounds that insertion is at the end
1301 * of the list, so the oldest entries are at
1302 * the start.
1305 while(namerec->data.num_ips>=25) {
1306 struct name_record *name1brec = NULL;
1308 /* We only do this for 1c types. */
1309 if (namerec->name.name_type != 0x1c) {
1310 break;
1312 DEBUG(3,("wins_process_name_registration_request: "
1313 "More than 25 IPs already in "
1314 "the list. Looking for a 1b "
1315 "record\n"));
1317 /* Ensure we have all the active 1b
1318 * names on the list. */
1319 wins_delete_all_1b_in_memory_records();
1320 fetch_all_active_wins_1b_names();
1322 /* Per the above, find the 1b record,
1323 and then remove the first IP that isn't the same */
1324 for(name1brec = subrec->namelist;
1325 name1brec;
1326 name1brec = name1brec->next ) {
1327 if( WINS_STATE_ACTIVE(name1brec) &&
1328 name1brec->name.name_type == 0x1b) {
1329 DEBUG(3,("wins_process_name_registration_request: "
1330 "Found the #1b record "
1331 "with ip %s\n",
1332 inet_ntoa(name1brec->data.ip[0])));
1333 break;
1336 if(!name1brec) {
1337 DEBUG(3,("wins_process_name_registration_request: "
1338 "Didn't find a #1b name record. "
1339 "Removing the first available "
1340 "entry %s\n",
1341 inet_ntoa(namerec->data.ip[0])));
1342 remove_ip_from_name_record(namerec, namerec->data.ip[0]);
1343 wins_hook("delete", namerec, 0);
1344 } else {
1345 int i;
1346 for(i=0; i<namerec->data.num_ips; i++) {
1347 /* The name1brec should only have
1348 * the single IP address in it,
1349 * so we only check against the first one*/
1350 if(!ip_equal_v4( namerec->data.ip[i], name1brec->data.ip[0])) {
1351 /* The i'th entry isn't the 1b address; delete it */
1352 DEBUG(3,("wins_process_name_registration_request: "
1353 "Entry at %d is not the #1b address. "
1354 "About to remove it\n",
1355 i));
1356 remove_ip_from_name_record(namerec, namerec->data.ip[i]);
1357 wins_hook("delete", namerec, 0);
1358 break;
1363 /* The list is guaranteed to be < 25 entries now
1364 * - safe to add a new one */
1365 add_ip_to_name_record(namerec, from_ip);
1366 /* we need to update the record for replication */
1367 get_global_id_and_update(&namerec->data.id, True);
1370 * if the record is a replica, we must change
1371 * the wins owner to us to make the replication updates
1372 * it on the other wins servers.
1373 * And when the partner will receive this record,
1374 * it will update its own record.
1377 update_wins_owner(namerec, our_fake_ip);
1379 update_name_ttl(namerec, ttl);
1380 wins_hook("refresh", namerec, ttl);
1381 send_wins_name_registration_response(0, ttl, p);
1382 return;
1383 } else {
1386 * If we are adding a unique name, the name exists in the WINS db
1387 * and is a group name then reject the registration.
1389 * explanation: groups have a higher priority than unique names.
1392 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1393 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1394 send_wins_name_registration_response(RFS_ERR, 0, p);
1395 return;
1400 * From here on down we know that if the name exists in the WINS db it is
1401 * a unique name, not a group name.
1405 * If the name exists and is one of our names then check the
1406 * registering IP address. If it's not one of ours then automatically
1407 * reject without doing the query - we know we will reject it.
1410 if ( namerec != NULL ) {
1411 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
1412 if( is_myname(name) ) {
1413 if(!ismyip_v4(from_ip)) {
1414 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1415 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1416 send_wins_name_registration_response(RFS_ERR, 0, p);
1417 return;
1418 } else {
1420 * It's one of our names and one of our IP's - update the ttl.
1422 update_name_ttl(namerec, ttl);
1423 wins_hook("refresh", namerec, ttl);
1424 send_wins_name_registration_response(0, ttl, p);
1425 return;
1428 } else {
1429 name[0] = '\0';
1433 * If the name exists and it is a unique registration and the registering IP
1434 * is the same as the (single) already registered IP then just update the ttl.
1436 * But not if the record is an active replica. IF it's a replica, it means it can be
1437 * the same client which has moved and not yet expired. So we don't update
1438 * the ttl in this case and go beyond to do a WACK and query the old client
1441 if( !registering_group_name
1442 && (namerec != NULL)
1443 && (namerec->data.num_ips == 1)
1444 && ip_equal_v4( namerec->data.ip[0], from_ip )
1445 && ip_equal_v4(namerec->data.wins_ip, our_fake_ip) ) {
1446 update_name_ttl( namerec, ttl );
1447 wins_hook("refresh", namerec, ttl);
1448 send_wins_name_registration_response( 0, ttl, p );
1449 return;
1453 * Finally if the name exists do a query to the registering machine
1454 * to see if they still claim to have the name.
1457 if( namerec != NULL ) {
1458 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1459 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1462 * First send a WACK to the registering machine.
1465 send_wins_wack_response(60, p);
1468 * When the reply comes back we need the original packet.
1469 * Lock this so it won't be freed and then put it into
1470 * the userdata structure.
1473 p->locked = True;
1475 userdata = (struct userdata_struct *)ud;
1477 userdata->copy_fn = NULL;
1478 userdata->free_fn = NULL;
1479 userdata->userdata_len = sizeof(struct packet_struct *);
1480 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1483 * Use the new call to send a query directly to an IP address.
1484 * This sends the query directly to the IP address, and ensures
1485 * the recursion desired flag is not set (you were right Luke :-).
1486 * This function should *only* be called from the WINS server
1487 * code. JRA.
1490 pull_ascii_nstring(name, sizeof(name), question->name);
1491 query_name_from_wins_server( *namerec->data.ip,
1492 name,
1493 question->name_type,
1494 wins_register_query_success,
1495 wins_register_query_fail,
1496 userdata );
1497 return;
1501 * Name did not exist - add it.
1504 pull_ascii_nstring(name, sizeof(name), question->name);
1505 add_name_to_subnet( subrec, name, question->name_type,
1506 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1508 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1509 get_global_id_and_update(&namerec->data.id, True);
1510 update_wins_owner(namerec, our_fake_ip);
1511 update_wins_flag(namerec, WINS_ACTIVE);
1512 wins_hook("add", namerec, ttl);
1515 send_wins_name_registration_response(0, ttl, p);
1518 /***********************************************************************
1519 Deal with a mutihomed name query success to the machine that
1520 requested the multihomed name registration.
1522 We have a locked pointer to the original packet stashed away in the
1523 userdata pointer.
1524 ************************************************************************/
1526 static void wins_multihomed_register_query_success(struct subnet_record *subrec,
1527 struct userdata_struct *userdata,
1528 struct nmb_name *question_name,
1529 struct in_addr ip,
1530 struct res_rec *answers)
1532 struct packet_struct *orig_reg_packet;
1533 struct nmb_packet *nmb;
1534 struct name_record *namerec = NULL;
1535 struct in_addr from_ip;
1536 int ttl;
1537 struct in_addr our_fake_ip;
1539 our_fake_ip = interpret_addr2("0.0.0.0");
1540 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1542 nmb = &orig_reg_packet->packet.nmb;
1544 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1545 ttl = get_ttl_from_packet(nmb);
1548 * We want to just add the new IP, as we now know the requesting
1549 * machine claims to own it. But we can't just do that as an arbitary
1550 * amount of time may have taken place between the name query
1551 * request and this response. So we check that
1552 * the name still exists and is in the same state - if so
1553 * we just add the extra IP and update the ttl.
1556 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1558 if( (namerec == NULL) || (namerec->data.source != REGISTER_NAME) || !WINS_STATE_ACTIVE(namerec) ) {
1559 DEBUG(3,("wins_multihomed_register_query_success: name %s is not in the correct state to add \
1560 a subsequent IP address.\n", nmb_namestr(question_name) ));
1561 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1563 orig_reg_packet->locked = False;
1564 free_packet(orig_reg_packet);
1566 return;
1569 if(!find_ip_in_name_record(namerec, from_ip)) {
1570 add_ip_to_name_record(namerec, from_ip);
1573 get_global_id_and_update(&namerec->data.id, True);
1574 update_wins_owner(namerec, our_fake_ip);
1575 update_wins_flag(namerec, WINS_ACTIVE);
1576 update_name_ttl(namerec, ttl);
1577 wins_hook("add", namerec, ttl);
1578 send_wins_name_registration_response(0, ttl, orig_reg_packet);
1580 orig_reg_packet->locked = False;
1581 free_packet(orig_reg_packet);
1584 /***********************************************************************
1585 Deal with a name registration request query failure to a client that
1586 owned the name.
1588 We have a locked pointer to the original packet stashed away in the
1589 userdata pointer.
1590 ************************************************************************/
1592 static void wins_multihomed_register_query_fail(struct subnet_record *subrec,
1593 struct response_record *rrec,
1594 struct nmb_name *question_name,
1595 int rcode)
1597 struct userdata_struct *userdata = rrec->userdata;
1598 struct packet_struct *orig_reg_packet;
1600 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1602 DEBUG(3,("wins_multihomed_register_query_fail: Registering machine at IP %s failed to answer \
1603 query successfully for name %s.\n", inet_ntoa(orig_reg_packet->ip), nmb_namestr(question_name) ));
1604 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1606 orig_reg_packet->locked = False;
1607 free_packet(orig_reg_packet);
1608 return;
1611 /***********************************************************************
1612 Deal with a multihomed name registration request to a WINS server.
1613 These cannot be group name registrations.
1614 ***********************************************************************/
1616 void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
1617 struct packet_struct *p)
1619 struct nmb_packet *nmb = &p->packet.nmb;
1620 struct nmb_name *question = &nmb->question.question_name;
1621 bool bcast = nmb->header.nm_flags.bcast;
1622 uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
1623 int ttl = get_ttl_from_packet(nmb);
1624 struct name_record *namerec = NULL;
1625 struct in_addr from_ip;
1626 bool group = (nb_flags & NB_GROUP) ? True : False;
1627 struct in_addr our_fake_ip;
1628 unstring qname;
1630 our_fake_ip = interpret_addr2("0.0.0.0");
1631 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1633 if(bcast) {
1635 * We should only get unicast name registration packets here.
1636 * Anyone trying to register broadcast should not be going to a WINS
1637 * server. Log an error here.
1640 DEBUG(0,("wins_process_multihomed_name_registration_request: broadcast name registration request \
1641 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1642 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1643 return;
1647 * Only unique names should be registered multihomed.
1650 if(group) {
1651 DEBUG(0,("wins_process_multihomed_name_registration_request: group name registration request \
1652 received for name %s from IP %s on subnet %s. Errror - group names should not be multihomed.\n",
1653 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1654 return;
1657 DEBUG(3,("wins_process_multihomed_name_registration_request: name registration for name %s \
1658 IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ));
1661 * Deal with policy regarding 0x1d names.
1664 if(question->name_type == 0x1d) {
1665 DEBUG(3,("wins_process_multihomed_name_registration_request: Ignoring request \
1666 to register name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
1667 send_wins_name_registration_response(0, ttl, p);
1668 return;
1672 * See if the name already exists.
1675 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1678 * if the record exists but NOT in active state,
1679 * consider it dead.
1682 if ((namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1683 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was not active - removing it.\n", nmb_namestr(question)));
1684 remove_name_from_namelist(subrec, namerec);
1685 namerec = NULL;
1689 * Deal with the case where the name found was a dns entry.
1690 * Remove it as we now have a NetBIOS client registering the
1691 * name.
1694 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1695 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was a dns lookup \
1696 - removing it.\n", nmb_namestr(question) ));
1697 remove_name_from_namelist( subrec, namerec);
1698 namerec = NULL;
1702 * Reject if the name exists and is not a REGISTER_NAME.
1703 * (ie. Don't allow any static names to be overwritten.
1706 if( (namerec != NULL) && (namerec->data.source != REGISTER_NAME) ) {
1707 DEBUG( 3, ( "wins_process_multihomed_name_registration_request: Attempt \
1708 to register name %s. Name already exists in WINS with source type %d.\n",
1709 nmb_namestr(question), namerec->data.source ));
1710 send_wins_name_registration_response(RFS_ERR, 0, p);
1711 return;
1715 * Reject if the name exists and is a GROUP name and is active.
1718 if((namerec != NULL) && NAME_GROUP(namerec) && WINS_STATE_ACTIVE(namerec)) {
1719 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1720 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1721 send_wins_name_registration_response(RFS_ERR, 0, p);
1722 return;
1726 * From here on down we know that if the name exists in the WINS db it is
1727 * a unique name, not a group name.
1731 * If the name exists and is one of our names then check the
1732 * registering IP address. If it's not one of ours then automatically
1733 * reject without doing the query - we know we will reject it.
1736 if((namerec != NULL) && (is_myname(namerec->name.name)) ) {
1737 if(!ismyip_v4(from_ip)) {
1738 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1739 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1740 send_wins_name_registration_response(RFS_ERR, 0, p);
1741 return;
1742 } else {
1744 * It's one of our names and one of our IP's. Ensure the IP is in the record and
1745 * update the ttl. Update the version ID to force replication.
1747 update_name_ttl(namerec, ttl);
1749 if(!find_ip_in_name_record(namerec, from_ip)) {
1750 get_global_id_and_update(&namerec->data.id, True);
1751 update_wins_owner(namerec, our_fake_ip);
1752 update_wins_flag(namerec, WINS_ACTIVE);
1754 add_ip_to_name_record(namerec, from_ip);
1757 wins_hook("refresh", namerec, ttl);
1758 send_wins_name_registration_response(0, ttl, p);
1759 return;
1764 * If the name exists and is active, check if the IP address is already registered
1765 * to that name. If so then update the ttl and reply success.
1768 if((namerec != NULL) && find_ip_in_name_record(namerec, from_ip) && WINS_STATE_ACTIVE(namerec)) {
1769 update_name_ttl(namerec, ttl);
1772 * If it's a replica, we need to become the wins owner
1773 * to force the replication
1775 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
1776 get_global_id_and_update(&namerec->data.id, True);
1777 update_wins_owner(namerec, our_fake_ip);
1778 update_wins_flag(namerec, WINS_ACTIVE);
1781 wins_hook("refresh", namerec, ttl);
1782 send_wins_name_registration_response(0, ttl, p);
1783 return;
1787 * If the name exists do a query to the owner
1788 * to see if they still want the name.
1791 if(namerec != NULL) {
1792 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1793 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1796 * First send a WACK to the registering machine.
1799 send_wins_wack_response(60, p);
1802 * When the reply comes back we need the original packet.
1803 * Lock this so it won't be freed and then put it into
1804 * the userdata structure.
1807 p->locked = True;
1809 userdata = (struct userdata_struct *)ud;
1811 userdata->copy_fn = NULL;
1812 userdata->free_fn = NULL;
1813 userdata->userdata_len = sizeof(struct packet_struct *);
1814 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1817 * Use the new call to send a query directly to an IP address.
1818 * This sends the query directly to the IP address, and ensures
1819 * the recursion desired flag is not set (you were right Luke :-).
1820 * This function should *only* be called from the WINS server
1821 * code. JRA.
1823 * Note that this packet is sent to the current owner of the name,
1824 * not the person who sent the packet
1827 pull_ascii_nstring( qname, sizeof(qname), question->name);
1828 query_name_from_wins_server( namerec->data.ip[0],
1829 qname,
1830 question->name_type,
1831 wins_multihomed_register_query_success,
1832 wins_multihomed_register_query_fail,
1833 userdata );
1835 return;
1839 * Name did not exist - add it.
1842 pull_ascii_nstring( qname, sizeof(qname), question->name);
1843 add_name_to_subnet( subrec, qname, question->name_type,
1844 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1846 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1847 get_global_id_and_update(&namerec->data.id, True);
1848 update_wins_owner(namerec, our_fake_ip);
1849 update_wins_flag(namerec, WINS_ACTIVE);
1850 wins_hook("add", namerec, ttl);
1853 send_wins_name_registration_response(0, ttl, p);
1856 /***********************************************************************
1857 Fetch all *<1b> names from the WINS db and store on the namelist.
1858 ***********************************************************************/
1860 static int fetch_1b_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
1862 struct name_record *namerec = NULL;
1864 if (kbuf.dsize != sizeof(unstring) + 1) {
1865 return 0;
1868 /* Filter out all non-1b names. */
1869 if (kbuf.dptr[sizeof(unstring)] != 0x1b) {
1870 return 0;
1873 namerec = wins_record_to_name_record(kbuf, dbuf);
1874 if (!namerec) {
1875 return 0;
1878 DLIST_ADD(wins_server_subnet->namelist, namerec);
1879 return 0;
1882 void fetch_all_active_wins_1b_names(void)
1884 tdb_traverse(wins_tdb, fetch_1b_traverse_fn, NULL);
1887 /***********************************************************************
1888 Deal with the special name query for *<1b>.
1889 ***********************************************************************/
1891 static void process_wins_dmb_query_request(struct subnet_record *subrec,
1892 struct packet_struct *p)
1894 struct name_record *namerec = NULL;
1895 char *prdata;
1896 int num_ips;
1899 * Go through all the ACTIVE names in the WINS db looking for those
1900 * ending in <1b>. Use this to calculate the number of IP
1901 * addresses we need to return.
1904 num_ips = 0;
1906 /* First, clear the in memory list - we're going to re-populate
1907 it with the tdb_traversal in fetch_all_active_wins_1b_names. */
1909 wins_delete_all_tmp_in_memory_records();
1911 fetch_all_active_wins_1b_names();
1913 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1914 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1915 num_ips += namerec->data.num_ips;
1919 if(num_ips == 0) {
1921 * There are no 0x1b names registered. Return name query fail.
1923 send_wins_name_query_response(NAM_ERR, p, NULL);
1924 return;
1927 if((prdata = (char *)SMB_MALLOC( num_ips * 6 )) == NULL) {
1928 DEBUG(0,("process_wins_dmb_query_request: Malloc fail !.\n"));
1929 return;
1933 * Go through all the names again in the WINS db looking for those
1934 * ending in <1b>. Add their IP addresses into the list we will
1935 * return.
1938 num_ips = 0;
1939 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1940 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1941 int i;
1942 for(i = 0; i < namerec->data.num_ips; i++) {
1943 set_nb_flags(&prdata[num_ips * 6],namerec->data.nb_flags);
1944 putip((char *)&prdata[(num_ips * 6) + 2], &namerec->data.ip[i]);
1945 num_ips++;
1951 * Send back the reply containing the IP list.
1954 reply_netbios_packet(p, /* Packet to reply to. */
1955 0, /* Result code. */
1956 WINS_QUERY, /* nmbd type code. */
1957 NMB_NAME_QUERY_OPCODE, /* opcode. */
1958 lp_min_wins_ttl(), /* ttl. */
1959 prdata, /* data to send. */
1960 num_ips*6); /* data length. */
1962 SAFE_FREE(prdata);
1965 /****************************************************************************
1966 Send a WINS name query response.
1967 **************************************************************************/
1969 void send_wins_name_query_response(int rcode, struct packet_struct *p,
1970 struct name_record *namerec)
1972 char rdata[6];
1973 char *prdata = rdata;
1974 int reply_data_len = 0;
1975 int ttl = 0;
1976 int i;
1978 memset(rdata,'\0',6);
1980 if(rcode == 0) {
1982 int ip_count;
1984 ttl = (namerec->data.death_time != PERMANENT_TTL) ? namerec->data.death_time - p->timestamp : lp_max_wins_ttl();
1986 /* The netbios reply packet data section is limited to 576 bytes. In theory
1987 * this should give us space for 96 addresses, but in practice, 86 appears
1988 * to be the max (don't know why). If we send any more than that,
1989 * reply_netbios_packet will fail to send a reply to avoid a memcpy buffer
1990 * overflow. Keep the count to 85 and it will be ok */
1991 ip_count=namerec->data.num_ips;
1992 if(ip_count>85) {
1993 ip_count=85;
1996 /* Copy all known ip addresses into the return data. */
1997 /* Optimise for the common case of one IP address so we don't need a malloc. */
1999 if( ip_count == 1 ) {
2000 prdata = rdata;
2001 } else {
2002 if((prdata = (char *)SMB_MALLOC( ip_count * 6 )) == NULL) {
2003 DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
2004 return;
2008 for(i = 0; i < ip_count; i++) {
2009 set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
2010 putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
2013 sort_query_replies(prdata, i, p->ip);
2014 reply_data_len = ip_count * 6;
2017 reply_netbios_packet(p, /* Packet to reply to. */
2018 rcode, /* Result code. */
2019 WINS_QUERY, /* nmbd type code. */
2020 NMB_NAME_QUERY_OPCODE, /* opcode. */
2021 ttl, /* ttl. */
2022 prdata, /* data to send. */
2023 reply_data_len); /* data length. */
2025 if(prdata != rdata) {
2026 SAFE_FREE(prdata);
2030 /***********************************************************************
2031 Deal with a name query.
2032 ***********************************************************************/
2034 void wins_process_name_query_request(struct subnet_record *subrec,
2035 struct packet_struct *p)
2037 struct nmb_packet *nmb = &p->packet.nmb;
2038 struct nmb_name *question = &nmb->question.question_name;
2039 struct name_record *namerec = NULL;
2040 unstring qname;
2042 DEBUG(3,("wins_process_name_query: name query for name %s from IP %s\n",
2043 nmb_namestr(question), inet_ntoa(p->ip) ));
2046 * Special name code. If the queried name is *<1b> then search
2047 * the entire WINS database and return a list of all the IP addresses
2048 * registered to any <1b> name. This is to allow domain master browsers
2049 * to discover other domains that may not have a presence on their subnet.
2052 pull_ascii_nstring(qname, sizeof(qname), question->name);
2053 if(strequal( qname, "*") && (question->name_type == 0x1b)) {
2054 process_wins_dmb_query_request( subrec, p);
2055 return;
2058 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2060 if(namerec != NULL) {
2062 * If the name is not anymore in active state then reply not found.
2063 * it's fair even if we keep it in the cache for days.
2065 if (!WINS_STATE_ACTIVE(namerec)) {
2066 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
2067 nmb_namestr(question) ));
2068 send_wins_name_query_response(NAM_ERR, p, namerec);
2069 return;
2073 * If it's a DNSFAIL_NAME then reply name not found.
2076 if( namerec->data.source == DNSFAIL_NAME ) {
2077 DEBUG(3,("wins_process_name_query: name query for name %s returning DNS fail.\n",
2078 nmb_namestr(question) ));
2079 send_wins_name_query_response(NAM_ERR, p, namerec);
2080 return;
2084 * If the name has expired then reply name not found.
2087 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < p->timestamp) ) {
2088 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
2089 nmb_namestr(question) ));
2090 send_wins_name_query_response(NAM_ERR, p, namerec);
2091 return;
2094 DEBUG(3,("wins_process_name_query: name query for name %s returning first IP %s.\n",
2095 nmb_namestr(question), inet_ntoa(namerec->data.ip[0]) ));
2097 send_wins_name_query_response(0, p, namerec);
2098 return;
2102 * Name not found in WINS - try a dns query if it's a 0x20 name.
2105 if(lp_wins_dns_proxy() && ((question->name_type == 0x20) || question->name_type == 0)) {
2106 DEBUG(3,("wins_process_name_query: name query for name %s not found - doing dns lookup.\n",
2107 nmb_namestr(question) ));
2109 queue_dns_query(p, question);
2110 return;
2114 * Name not found - return error.
2117 send_wins_name_query_response(NAM_ERR, p, NULL);
2120 /****************************************************************************
2121 Send a WINS name release response.
2122 **************************************************************************/
2124 static void send_wins_name_release_response(int rcode, struct packet_struct *p)
2126 struct nmb_packet *nmb = &p->packet.nmb;
2127 char rdata[6];
2129 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
2131 reply_netbios_packet(p, /* Packet to reply to. */
2132 rcode, /* Result code. */
2133 NMB_REL, /* nmbd type code. */
2134 NMB_NAME_RELEASE_OPCODE, /* opcode. */
2135 0, /* ttl. */
2136 rdata, /* data to send. */
2137 6); /* data length. */
2140 /***********************************************************************
2141 Deal with a name release.
2142 ***********************************************************************/
2144 void wins_process_name_release_request(struct subnet_record *subrec,
2145 struct packet_struct *p)
2147 struct nmb_packet *nmb = &p->packet.nmb;
2148 struct nmb_name *question = &nmb->question.question_name;
2149 bool bcast = nmb->header.nm_flags.bcast;
2150 uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
2151 struct name_record *namerec = NULL;
2152 struct in_addr from_ip;
2153 bool releasing_group_name = (nb_flags & NB_GROUP) ? True : False;
2155 putip((char *)&from_ip,&nmb->additional->rdata[2]);
2157 if(bcast) {
2159 * We should only get unicast name registration packets here.
2160 * Anyone trying to register broadcast should not be going to a WINS
2161 * server. Log an error here.
2164 DEBUG(0,("wins_process_name_release_request: broadcast name registration request \
2165 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
2166 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
2167 return;
2170 DEBUG(3,("wins_process_name_release_request: %s name release for name %s \
2171 IP %s\n", releasing_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
2174 * Deal with policy regarding 0x1d names.
2177 if(!releasing_group_name && (question->name_type == 0x1d)) {
2178 DEBUG(3,("wins_process_name_release_request: Ignoring request \
2179 to release name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
2180 send_wins_name_release_response(0, p);
2181 return;
2185 * See if the name already exists.
2188 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2190 if( (namerec == NULL) || ((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) ) {
2191 send_wins_name_release_response(NAM_ERR, p);
2192 return;
2196 * Check that the sending machine has permission to release this name.
2197 * If it's a group name not ending in 0x1c then just say yes and let
2198 * the group time out.
2201 if(releasing_group_name && (question->name_type != 0x1c)) {
2202 send_wins_name_release_response(0, p);
2203 return;
2207 * Check that the releasing node is on the list of IP addresses
2208 * for this name. Disallow the release if not.
2211 if(!find_ip_in_name_record(namerec, from_ip)) {
2212 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2213 release name %s as IP %s is not one of the known IP's for this name.\n",
2214 nmb_namestr(question), inet_ntoa(from_ip) ));
2215 send_wins_name_release_response(NAM_ERR, p);
2216 return;
2220 * Check if the record is active. IF it's already released
2221 * or tombstoned, refuse the release.
2224 if (!WINS_STATE_ACTIVE(namerec)) {
2225 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2226 release name %s as this record is not active anymore.\n", nmb_namestr(question) ));
2227 send_wins_name_release_response(NAM_ERR, p);
2228 return;
2232 * Check if the record is a 0x1c group
2233 * and has more then one ip
2234 * remove only this address.
2237 if(releasing_group_name && (question->name_type == 0x1c) && (namerec->data.num_ips > 1)) {
2238 remove_ip_from_name_record(namerec, from_ip);
2239 DEBUG(3,("wins_process_name_release_request: Remove IP %s from NAME: %s\n",
2240 inet_ntoa(from_ip),nmb_namestr(question)));
2241 wins_hook("delete", namerec, 0);
2242 send_wins_name_release_response(0, p);
2243 return;
2247 * Send a release response.
2248 * Flag the name as released and update the ttl
2251 namerec->data.wins_flags |= WINS_RELEASED;
2252 update_name_ttl(namerec, EXTINCTION_INTERVAL);
2254 wins_hook("delete", namerec, 0);
2255 send_wins_name_release_response(0, p);
2258 /*******************************************************************
2259 WINS time dependent processing.
2260 ******************************************************************/
2262 static int wins_processing_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2264 time_t t = *(time_t *)state;
2265 bool store_record = False;
2266 struct name_record *namerec = NULL;
2267 struct in_addr our_fake_ip;
2269 our_fake_ip = interpret_addr2("0.0.0.0");
2270 if (kbuf.dsize != sizeof(unstring) + 1) {
2271 return 0;
2274 namerec = wins_record_to_name_record(kbuf, dbuf);
2275 if (!namerec) {
2276 return 0;
2279 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
2280 if( namerec->data.source == SELF_NAME ) {
2281 DEBUG( 3, ( "wins_processing_traverse_fn: Subnet %s not expiring SELF name %s\n",
2282 wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) );
2283 namerec->data.death_time += 300;
2284 store_record = True;
2285 goto done;
2286 } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) {
2287 DEBUG(3,("wins_processing_traverse_fn: deleting timed out DNS name %s\n",
2288 nmb_namestr(&namerec->name)));
2289 remove_name_from_wins_namelist(namerec );
2290 goto done;
2293 /* handle records, samba is the wins owner */
2294 if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
2295 switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2296 case WINS_ACTIVE:
2297 namerec->data.wins_flags&=~WINS_STATE_MASK;
2298 namerec->data.wins_flags|=WINS_RELEASED;
2299 namerec->data.death_time = t + EXTINCTION_INTERVAL;
2300 DEBUG(3,("wins_processing_traverse_fn: expiring %s\n",
2301 nmb_namestr(&namerec->name)));
2302 store_record = True;
2303 goto done;
2304 case WINS_RELEASED:
2305 namerec->data.wins_flags&=~WINS_STATE_MASK;
2306 namerec->data.wins_flags|=WINS_TOMBSTONED;
2307 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2308 get_global_id_and_update(&namerec->data.id, True);
2309 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2310 nmb_namestr(&namerec->name)));
2311 store_record = True;
2312 goto done;
2313 case WINS_TOMBSTONED:
2314 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2315 nmb_namestr(&namerec->name)));
2316 remove_name_from_wins_namelist(namerec );
2317 goto done;
2319 } else {
2320 switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2321 case WINS_ACTIVE:
2322 /* that's not as MS says it should be */
2323 namerec->data.wins_flags&=~WINS_STATE_MASK;
2324 namerec->data.wins_flags|=WINS_TOMBSTONED;
2325 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2326 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2327 nmb_namestr(&namerec->name)));
2328 store_record = True;
2329 goto done;
2330 case WINS_TOMBSTONED:
2331 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2332 nmb_namestr(&namerec->name)));
2333 remove_name_from_wins_namelist(namerec );
2334 goto done;
2335 case WINS_RELEASED:
2336 DEBUG(0,("wins_processing_traverse_fn: %s is in released state and\
2337 we are not the wins owner !\n", nmb_namestr(&namerec->name)));
2338 goto done;
2343 done:
2345 if (store_record) {
2346 wins_store_changed_namerec(namerec);
2349 SAFE_FREE(namerec->data.ip);
2350 SAFE_FREE(namerec);
2352 return 0;
2355 /*******************************************************************
2356 Time dependent wins processing.
2357 ******************************************************************/
2359 void initiate_wins_processing(time_t t)
2361 static time_t lasttime = 0;
2363 if (!lasttime) {
2364 lasttime = t;
2366 if (t - lasttime < 20) {
2367 return;
2370 if(!lp_we_are_a_wins_server()) {
2371 lasttime = t;
2372 return;
2375 tdb_traverse(wins_tdb, wins_processing_traverse_fn, &t);
2377 wins_delete_all_tmp_in_memory_records();
2379 wins_write_database(t, True);
2381 lasttime = t;
2384 /*******************************************************************
2385 Write out one record.
2386 ******************************************************************/
2388 void wins_write_name_record(struct name_record *namerec, XFILE *fp)
2390 int i;
2391 struct tm *tm;
2393 DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) ));
2395 if( namerec->data.death_time != PERMANENT_TTL ) {
2396 char *ts, *nl;
2398 tm = localtime(&namerec->data.death_time);
2399 if (!tm) {
2400 return;
2402 ts = asctime(tm);
2403 if (!ts) {
2404 return;
2406 nl = strrchr( ts, '\n' );
2407 if( NULL != nl ) {
2408 *nl = '\0';
2410 DEBUGADD(4,("TTL = %s ", ts ));
2411 } else {
2412 DEBUGADD(4,("TTL = PERMANENT "));
2415 for (i = 0; i < namerec->data.num_ips; i++) {
2416 DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) ));
2418 DEBUGADD(4,("%2x\n", namerec->data.nb_flags ));
2420 if( namerec->data.source == REGISTER_NAME ) {
2421 unstring name;
2422 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
2423 x_fprintf(fp, "\"%s#%02x\" %d ", name,namerec->name.name_type, /* Ignore scope. */
2424 (int)namerec->data.death_time);
2426 for (i = 0; i < namerec->data.num_ips; i++)
2427 x_fprintf( fp, "%s ", inet_ntoa( namerec->data.ip[i] ) );
2428 x_fprintf( fp, "%2xR\n", namerec->data.nb_flags );
2432 /*******************************************************************
2433 Write out the current WINS database.
2434 ******************************************************************/
2436 static int wins_writedb_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2438 struct name_record *namerec = NULL;
2439 XFILE *fp = (XFILE *)state;
2441 if (kbuf.dsize != sizeof(unstring) + 1) {
2442 return 0;
2445 namerec = wins_record_to_name_record(kbuf, dbuf);
2446 if (!namerec) {
2447 return 0;
2450 wins_write_name_record(namerec, fp);
2452 SAFE_FREE(namerec->data.ip);
2453 SAFE_FREE(namerec);
2454 return 0;
2458 void wins_write_database(time_t t, bool background)
2460 static time_t last_write_time = 0;
2461 char *fname = NULL;
2462 char *fnamenew = NULL;
2464 XFILE *fp;
2466 if (background) {
2467 if (!last_write_time) {
2468 last_write_time = t;
2470 if (t - last_write_time < 120) {
2471 return;
2476 if(!lp_we_are_a_wins_server()) {
2477 return;
2480 /* We will do the writing in a child process to ensure that the parent doesn't block while this is done */
2481 if (background) {
2482 CatchChild();
2483 if (fork()) {
2484 return;
2486 if (tdb_reopen(wins_tdb)) {
2487 DEBUG(0,("wins_write_database: tdb_reopen failed. Error was %s\n",
2488 strerror(errno)));
2489 _exit(0);
2490 return;
2494 if (!(fname = state_path(WINS_LIST))) {
2495 goto err_exit;
2497 /* This is safe as the 0 length means "don't expand". */
2498 all_string_sub(fname,"//", "/", 0);
2500 if (asprintf(&fnamenew, "%s.%u", fname, (unsigned int)getpid()) < 0) {
2501 goto err_exit;
2504 if((fp = x_fopen(fnamenew,O_WRONLY|O_CREAT,0644)) == NULL) {
2505 DEBUG(0,("wins_write_database: Can't open %s. Error was %s\n", fnamenew, strerror(errno)));
2506 goto err_exit;
2509 DEBUG(4,("wins_write_database: Dump of WINS name list.\n"));
2511 x_fprintf(fp,"VERSION %d %u\n", WINS_VERSION, 0);
2513 tdb_traverse(wins_tdb, wins_writedb_traverse_fn, fp);
2515 x_fclose(fp);
2516 chmod(fnamenew,0644);
2517 unlink(fname);
2518 rename(fnamenew,fname);
2520 err_exit:
2522 SAFE_FREE(fnamenew);
2523 TALLOC_FREE(fname);
2525 if (background) {
2526 _exit(0);
2530 #if 0
2531 Until winsrepl is done.
2532 /****************************************************************************
2533 Process a internal Samba message receiving a wins record.
2534 ***************************************************************************/
2536 void nmbd_wins_new_entry(struct messaging_context *msg,
2537 void *private_data,
2538 uint32_t msg_type,
2539 struct server_id server_id,
2540 DATA_BLOB *data)
2542 WINS_RECORD *record;
2543 struct name_record *namerec = NULL;
2544 struct name_record *new_namerec = NULL;
2545 struct nmb_name question;
2546 bool overwrite=False;
2547 struct in_addr our_fake_ip;
2548 int i;
2550 our_fake_ip = interpret_addr2("0.0.0.0");
2551 if (buf==NULL) {
2552 return;
2555 /* Record should use UNIX codepage. Ensure this is so in the wrepld code. JRA. */
2556 record=(WINS_RECORD *)buf;
2558 make_nmb_name(&question, record->name, record->type);
2560 namerec = find_name_on_subnet(wins_server_subnet, &question, FIND_ANY_NAME);
2562 /* record doesn't exist, add it */
2563 if (namerec == NULL) {
2564 DEBUG(3,("nmbd_wins_new_entry: adding new replicated record: %s<%02x> for wins server: %s\n",
2565 record->name, record->type, inet_ntoa(record->wins_ip)));
2567 new_namerec=add_name_to_subnet( wins_server_subnet,
2568 record->name,
2569 record->type,
2570 record->nb_flags,
2571 EXTINCTION_INTERVAL,
2572 REGISTER_NAME,
2573 record->num_ips,
2574 record->ip);
2576 if (new_namerec!=NULL) {
2577 update_wins_owner(new_namerec, record->wins_ip);
2578 update_wins_flag(new_namerec, record->wins_flags);
2579 new_namerec->data.id=record->id;
2581 wins_server_subnet->namelist_changed = True;
2585 /* check if we have a conflict */
2586 if (namerec != NULL) {
2587 /* both records are UNIQUE */
2588 if (namerec->data.wins_flags&WINS_UNIQUE && record->wins_flags&WINS_UNIQUE) {
2590 /* the database record is a replica */
2591 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
2592 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED) {
2593 if (ip_equal_v4(namerec->data.wins_ip, record->wins_ip))
2594 overwrite=True;
2595 } else
2596 overwrite=True;
2597 } else {
2598 /* we are the wins owner of the database record */
2599 /* the 2 records have the same IP address */
2600 if (ip_equal_v4(namerec->data.ip[0], record->ip[0])) {
2601 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED)
2602 get_global_id_and_update(&namerec->data.id, True);
2603 else
2604 overwrite=True;
2606 } else {
2607 /* the 2 records have different IP address */
2608 if (namerec->data.wins_flags&WINS_ACTIVE) {
2609 if (record->wins_flags&WINS_TOMBSTONED)
2610 get_global_id_and_update(&namerec->data.id, True);
2611 if (record->wins_flags&WINS_ACTIVE)
2612 /* send conflict challenge to the replica node */
2614 } else
2615 overwrite=True;
2621 /* the replica is a standard group */
2622 if (record->wins_flags&WINS_NGROUP || record->wins_flags&WINS_SGROUP) {
2623 /* if the database record is unique and active force a name release */
2624 if (namerec->data.wins_flags&WINS_UNIQUE)
2625 /* send a release name to the unique node */
2627 overwrite=True;
2631 /* the replica is a special group */
2632 if (record->wins_flags&WINS_SGROUP && namerec->data.wins_flags&WINS_SGROUP) {
2633 if (namerec->data.wins_flags&WINS_ACTIVE) {
2634 for (i=0; i<record->num_ips; i++)
2635 if(!find_ip_in_name_record(namerec, record->ip[i]))
2636 add_ip_to_name_record(namerec, record->ip[i]);
2637 } else {
2638 overwrite=True;
2642 /* the replica is a multihomed host */
2644 /* I'm giving up on multi homed. Too much complex to understand */
2646 if (record->wins_flags&WINS_MHOMED) {
2647 if (! (namerec->data.wins_flags&WINS_ACTIVE)) {
2648 if ( !(namerec->data.wins_flags&WINS_RELEASED) && !(namerec->data.wins_flags&WINS_NGROUP))
2649 overwrite=True;
2651 else {
2652 if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
2653 overwrite=True;
2655 if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip))
2656 if (namerec->data.wins_flags&WINS_UNIQUE)
2657 get_global_id_and_update(&namerec->data.id, True);
2661 if (record->wins_flags&WINS_ACTIVE && namerec->data.wins_flags&WINS_ACTIVE)
2662 if (namerec->data.wins_flags&WINS_UNIQUE ||
2663 namerec->data.wins_flags&WINS_MHOMED)
2664 if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
2665 overwrite=True;
2669 if (overwrite == False)
2670 DEBUG(3, ("nmbd_wins_new_entry: conflict in adding record: %s<%02x> from wins server: %s\n",
2671 record->name, record->type, inet_ntoa(record->wins_ip)));
2672 else {
2673 DEBUG(3, ("nmbd_wins_new_entry: replacing record: %s<%02x> from wins server: %s\n",
2674 record->name, record->type, inet_ntoa(record->wins_ip)));
2676 /* remove the old record and add a new one */
2677 remove_name_from_namelist( wins_server_subnet, namerec );
2678 new_namerec=add_name_to_subnet( wins_server_subnet, record->name, record->type, record->nb_flags,
2679 EXTINCTION_INTERVAL, REGISTER_NAME, record->num_ips, record->ip);
2680 if (new_namerec!=NULL) {
2681 update_wins_owner(new_namerec, record->wins_ip);
2682 update_wins_flag(new_namerec, record->wins_flags);
2683 new_namerec->data.id=record->id;
2685 wins_server_subnet->namelist_changed = True;
2688 wins_server_subnet->namelist_changed = True;
2693 #endif