nsswitch: fix a segfault in the krb5 locator plugin
[Samba/wip.git] / source3 / nmbd / nmbd_winsserver.c
blob2f48bc737f3c6eca511696bcdcf7047ced9b4f82
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 "nmbd/nmbd.h"
26 #define WINS_LIST "wins.dat"
27 #define WINS_VERSION 1
28 #define WINSDB_VERSION 1
30 /****************************************************************************
31 We don't store the NetBIOS scope in the wins.tdb. We key off the (utf8) netbios
32 name (65 bytes with the last byte being the name type).
33 *****************************************************************************/
35 TDB_CONTEXT *wins_tdb;
37 /****************************************************************************
38 Delete all the temporary name records on the in-memory linked list.
39 *****************************************************************************/
41 static void wins_delete_all_tmp_in_memory_records(void)
43 struct name_record *nr = NULL;
44 struct name_record *nrnext = NULL;
46 /* Delete all temporary name records on the wins subnet linked list. */
47 for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
48 nrnext = nr->next;
49 DLIST_REMOVE(wins_server_subnet->namelist, nr);
50 SAFE_FREE(nr->data.ip);
51 SAFE_FREE(nr);
55 /****************************************************************************
56 Delete all the temporary 1b name records on the in-memory linked list.
57 *****************************************************************************/
59 static void wins_delete_all_1b_in_memory_records(void)
61 struct name_record *nr = NULL;
62 struct name_record *nrnext = NULL;
64 /* Delete all temporary 1b name records on the wins subnet linked list. */
65 for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
66 nrnext = nr->next;
67 if (nr->name.name_type == 0x1b) {
68 DLIST_REMOVE(wins_server_subnet->namelist, nr);
69 SAFE_FREE(nr->data.ip);
70 SAFE_FREE(nr);
75 /****************************************************************************
76 Convert a wins.tdb record to a struct name_record. Add in our global_scope().
77 *****************************************************************************/
79 static struct name_record *wins_record_to_name_record(TDB_DATA key, TDB_DATA data)
81 struct name_record *namerec = NULL;
82 uint16 nb_flags;
83 unsigned char nr_src;
84 uint32 death_time, refresh_time;
85 uint32 id_low, id_high;
86 uint32 saddr;
87 uint32 wins_flags;
88 uint32 num_ips;
89 size_t len;
90 int i;
92 if (data.dptr == NULL || data.dsize == 0) {
93 return NULL;
96 /* Min size is "wbddddddd" + 1 ip address (4). */
97 if (data.dsize < 2 + 1 + (7*4) + 4) {
98 return NULL;
101 len = tdb_unpack(data.dptr, data.dsize,
102 "wbddddddd",
103 &nb_flags,
104 &nr_src,
105 &death_time,
106 &refresh_time,
107 &id_low,
108 &id_high,
109 &saddr,
110 &wins_flags,
111 &num_ips );
113 namerec = SMB_MALLOC_P(struct name_record);
114 if (!namerec) {
115 return NULL;
117 ZERO_STRUCTP(namerec);
119 namerec->data.ip = SMB_MALLOC_ARRAY(struct in_addr, num_ips);
120 if (!namerec->data.ip) {
121 SAFE_FREE(namerec);
122 return NULL;
125 namerec->subnet = wins_server_subnet;
126 push_ascii_nstring(namerec->name.name, (const char *)key.dptr);
127 namerec->name.name_type = key.dptr[sizeof(unstring)];
128 /* Add the scope. */
129 push_ascii(namerec->name.scope, global_scope(), 64, STR_TERMINATE);
131 /* We're using a byte-by-byte compare, so we must be sure that
132 * unused space doesn't have garbage in it.
135 for( i = strlen( namerec->name.name ); i < sizeof( namerec->name.name ); i++ ) {
136 namerec->name.name[i] = '\0';
138 for( i = strlen( namerec->name.scope ); i < sizeof( namerec->name.scope ); i++ ) {
139 namerec->name.scope[i] = '\0';
142 namerec->data.nb_flags = nb_flags;
143 namerec->data.source = (enum name_source)nr_src;
144 namerec->data.death_time = (time_t)death_time;
145 namerec->data.refresh_time = (time_t)refresh_time;
146 namerec->data.id = id_low;
147 #if defined(HAVE_LONGLONG)
148 namerec->data.id |= ((uint64_t)id_high << 32);
149 #endif
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 id_low = (namerec->data.id & 0xFFFFFFFF);
171 #if defined(HAVE_LONGLONG)
172 uint32 id_high = (namerec->data.id >> 32) & 0xFFFFFFFF;
173 #else
174 uint32 id_high = 0;
175 #endif
177 ZERO_STRUCT(data);
179 len = (2 + 1 + (7*4)); /* "wbddddddd" */
180 len += (namerec->data.num_ips * 4);
182 data.dptr = (uint8 *)SMB_MALLOC(len);
183 if (!data.dptr) {
184 return data;
186 data.dsize = len;
188 len = tdb_pack(data.dptr, data.dsize, "wbddddddd",
189 namerec->data.nb_flags,
190 (unsigned char)namerec->data.source,
191 (uint32)namerec->data.death_time,
192 (uint32)namerec->data.refresh_time,
193 id_low,
194 id_high,
195 (uint32)namerec->data.wins_ip.s_addr,
196 (uint32)namerec->data.wins_flags,
197 (uint32)namerec->data.num_ips );
199 for (i = 0; i < namerec->data.num_ips; i++) {
200 SIVAL(data.dptr, len + (i*4), namerec->data.ip[i].s_addr);
203 return data;
206 /****************************************************************************
207 Create key. Key is UNIX codepage namestring (usually utf8 64 byte len) with 1 byte type.
208 *****************************************************************************/
210 static TDB_DATA name_to_key(const struct nmb_name *nmbname)
212 static char keydata[sizeof(unstring) + 1];
213 TDB_DATA key;
215 memset(keydata, '\0', sizeof(keydata));
217 pull_ascii_nstring(keydata, sizeof(unstring), nmbname->name);
218 strupper_m(keydata);
219 keydata[sizeof(unstring)] = nmbname->name_type;
220 key.dptr = (uint8 *)keydata;
221 key.dsize = sizeof(keydata);
223 return key;
226 /****************************************************************************
227 Lookup a given name in the wins.tdb and create a temporary malloc'ed data struct
228 on the linked list. We will free this later in XXXX().
229 *****************************************************************************/
231 struct name_record *find_name_on_wins_subnet(const struct nmb_name *nmbname, bool self_only)
233 TDB_DATA data, key;
234 struct name_record *nr = NULL;
235 struct name_record *namerec = NULL;
237 if (!wins_tdb) {
238 return NULL;
241 key = name_to_key(nmbname);
242 data = tdb_fetch(wins_tdb, key);
244 if (data.dsize == 0) {
245 return NULL;
248 namerec = wins_record_to_name_record(key, data);
250 /* done with the this */
252 SAFE_FREE( data.dptr );
254 if (!namerec) {
255 return NULL;
258 /* Self names only - these include permanent names. */
259 if( self_only && (namerec->data.source != SELF_NAME) && (namerec->data.source != PERMANENT_NAME) ) {
260 DEBUG( 9, ( "find_name_on_wins_subnet: self name %s NOT FOUND\n", nmb_namestr(nmbname) ) );
261 SAFE_FREE(namerec->data.ip);
262 SAFE_FREE(namerec);
263 return NULL;
266 /* Search for this name record on the list. Replace it if found. */
268 for( nr = wins_server_subnet->namelist; nr; nr = nr->next) {
269 if (memcmp(nmbname->name, nr->name.name, 16) == 0) {
270 /* Delete it. */
271 DLIST_REMOVE(wins_server_subnet->namelist, nr);
272 SAFE_FREE(nr->data.ip);
273 SAFE_FREE(nr);
274 break;
278 DLIST_ADD(wins_server_subnet->namelist, namerec);
279 return namerec;
282 /****************************************************************************
283 Overwrite or add a given name in the wins.tdb.
284 *****************************************************************************/
286 static bool store_or_replace_wins_namerec(const struct name_record *namerec, int tdb_flag)
288 TDB_DATA key, data;
289 int ret;
291 if (!wins_tdb) {
292 return False;
295 key = name_to_key(&namerec->name);
296 data = name_record_to_wins_record(namerec);
298 if (data.dptr == NULL) {
299 return False;
302 ret = tdb_store(wins_tdb, key, data, tdb_flag);
304 SAFE_FREE(data.dptr);
305 return (ret == 0) ? True : False;
308 /****************************************************************************
309 Overwrite a given name in the wins.tdb.
310 *****************************************************************************/
312 bool wins_store_changed_namerec(const struct name_record *namerec)
314 return store_or_replace_wins_namerec(namerec, TDB_REPLACE);
317 /****************************************************************************
318 Primary interface into creating and overwriting records in the wins.tdb.
319 *****************************************************************************/
321 bool add_name_to_wins_subnet(const struct name_record *namerec)
323 return store_or_replace_wins_namerec(namerec, TDB_INSERT);
326 /****************************************************************************
327 Delete a given name in the tdb and remove the temporary malloc'ed data struct
328 on the linked list.
329 *****************************************************************************/
331 bool remove_name_from_wins_namelist(struct name_record *namerec)
333 TDB_DATA key;
334 int ret;
336 if (!wins_tdb) {
337 return False;
340 key = name_to_key(&namerec->name);
341 ret = tdb_delete(wins_tdb, key);
343 DLIST_REMOVE(wins_server_subnet->namelist, namerec);
345 /* namerec must be freed by the caller */
347 return (ret == 0) ? True : False;
350 /****************************************************************************
351 Dump out the complete namelist.
352 *****************************************************************************/
354 static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
356 struct name_record *namerec = NULL;
357 XFILE *fp = (XFILE *)state;
359 if (kbuf.dsize != sizeof(unstring) + 1) {
360 return 0;
363 namerec = wins_record_to_name_record(kbuf, dbuf);
364 if (!namerec) {
365 return 0;
368 dump_name_record(namerec, fp);
370 SAFE_FREE(namerec->data.ip);
371 SAFE_FREE(namerec);
372 return 0;
375 void dump_wins_subnet_namelist(XFILE *fp)
377 tdb_traverse(wins_tdb, traverse_fn, (void *)fp);
380 /****************************************************************************
381 Change the wins owner address in the record.
382 *****************************************************************************/
384 static void update_wins_owner(struct name_record *namerec, struct in_addr wins_ip)
386 namerec->data.wins_ip=wins_ip;
389 /****************************************************************************
390 Create the wins flags based on the nb flags and the input value.
391 *****************************************************************************/
393 static void update_wins_flag(struct name_record *namerec, int flags)
395 namerec->data.wins_flags=0x0;
397 /* if it's a group, it can be a normal or a special one */
398 if (namerec->data.nb_flags & NB_GROUP) {
399 if (namerec->name.name_type==0x1C) {
400 namerec->data.wins_flags|=WINS_SGROUP;
401 } else {
402 if (namerec->data.num_ips>1) {
403 namerec->data.wins_flags|=WINS_SGROUP;
404 } else {
405 namerec->data.wins_flags|=WINS_NGROUP;
408 } else {
409 /* can be unique or multi-homed */
410 if (namerec->data.num_ips>1) {
411 namerec->data.wins_flags|=WINS_MHOMED;
412 } else {
413 namerec->data.wins_flags|=WINS_UNIQUE;
417 /* the node type are the same bits */
418 namerec->data.wins_flags|=namerec->data.nb_flags&NB_NODETYPEMASK;
420 /* the static bit is elsewhere */
421 if (namerec->data.death_time == PERMANENT_TTL) {
422 namerec->data.wins_flags|=WINS_STATIC;
425 /* and add the given bits */
426 namerec->data.wins_flags|=flags;
428 DEBUG(8,("update_wins_flag: nbflags: 0x%x, ttl: %d, flags: 0x%x, winsflags: 0x%x\n",
429 namerec->data.nb_flags, (int)namerec->data.death_time, flags, namerec->data.wins_flags));
432 /****************************************************************************
433 Return the general ID value and increase it if requested.
434 *****************************************************************************/
436 static void get_global_id_and_update(uint64_t *current_id, bool update)
439 * it's kept as a static here, to prevent people from messing
440 * with the value directly
443 static uint64_t general_id = 1;
445 DEBUG(5,("get_global_id_and_update: updating version ID: %d\n", (int)general_id));
447 *current_id = general_id;
449 if (update) {
450 general_id++;
454 /****************************************************************************
455 Possibly call the WINS hook external program when a WINS change is made.
456 Also stores the changed record back in the wins_tdb.
457 *****************************************************************************/
459 static void wins_hook(const char *operation, struct name_record *namerec, int ttl)
461 char *command = NULL;
462 char *cmd = lp_wins_hook();
463 char *p, *namestr;
464 int i;
465 TALLOC_CTX *ctx = talloc_tos();
467 wins_store_changed_namerec(namerec);
469 if (!cmd || !*cmd) {
470 return;
473 for (p=namerec->name.name; *p; p++) {
474 if (!(isalnum((int)*p) || strchr_m("._-",*p))) {
475 DEBUG(3,("not calling wins hook for invalid name %s\n", nmb_namestr(&namerec->name)));
476 return;
480 /* Use the name without the nametype (and scope) appended */
482 namestr = nmb_namestr(&namerec->name);
483 if ((p = strchr(namestr, '<'))) {
484 *p = 0;
487 command = talloc_asprintf(ctx,
488 "%s %s %s %02x %d",
489 cmd,
490 operation,
491 namestr,
492 namerec->name.name_type,
493 ttl);
494 if (!command) {
495 return;
498 for (i=0;i<namerec->data.num_ips;i++) {
499 command = talloc_asprintf_append(command,
500 " %s",
501 inet_ntoa(namerec->data.ip[i]));
502 if (!command) {
503 return;
507 DEBUG(3,("calling wins hook for %s\n", nmb_namestr(&namerec->name)));
508 smbrun(command, NULL);
509 TALLOC_FREE(command);
512 /****************************************************************************
513 Determine if this packet should be allocated to the WINS server.
514 *****************************************************************************/
516 bool packet_is_for_wins_server(struct packet_struct *packet)
518 struct nmb_packet *nmb = &packet->packet.nmb;
520 /* Only unicast packets go to a WINS server. */
521 if((wins_server_subnet == NULL) || (nmb->header.nm_flags.bcast == True)) {
522 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #1.\n"));
523 return False;
526 /* Check for node status requests. */
527 if (nmb->question.question_type != QUESTION_TYPE_NB_QUERY) {
528 return False;
531 switch(nmb->header.opcode) {
533 * A WINS server issues WACKS, not receives them.
535 case NMB_WACK_OPCODE:
536 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #2 (WACK).\n"));
537 return False;
539 * A WINS server only processes registration and
540 * release requests, not responses.
542 case NMB_NAME_REG_OPCODE:
543 case NMB_NAME_MULTIHOMED_REG_OPCODE:
544 case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
545 case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
546 if(nmb->header.response) {
547 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #3 (response = 1).\n"));
548 return False;
550 break;
552 case NMB_NAME_RELEASE_OPCODE:
553 if(nmb->header.response) {
554 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #4 (response = 1).\n"));
555 return False;
557 break;
560 * Only process unicast name queries with rd = 1.
562 case NMB_NAME_QUERY_OPCODE:
563 if(!nmb->header.response && !nmb->header.nm_flags.recursion_desired) {
564 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #5 (response = 1).\n"));
565 return False;
567 break;
570 return True;
573 /****************************************************************************
574 Utility function to decide what ttl to give a register/refresh request.
575 *****************************************************************************/
577 static int get_ttl_from_packet(struct nmb_packet *nmb)
579 int ttl = nmb->additional->ttl;
581 if (ttl < lp_min_wins_ttl()) {
582 ttl = lp_min_wins_ttl();
585 if (ttl > lp_max_wins_ttl()) {
586 ttl = lp_max_wins_ttl();
589 return ttl;
592 /****************************************************************************
593 Load or create the WINS database.
594 *****************************************************************************/
596 bool initialise_wins(void)
598 time_t time_now = time(NULL);
599 XFILE *fp;
600 char line[1024];
602 if(!lp_we_are_a_wins_server()) {
603 return True;
606 /* Open the wins.tdb. */
607 wins_tdb = tdb_open_log(state_path("wins.tdb"), 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
608 O_CREAT|O_RDWR, 0600);
609 if (!wins_tdb) {
610 DEBUG(0,("initialise_wins: failed to open wins.tdb. Error was %s\n",
611 strerror(errno) ));
612 return False;
615 tdb_store_int32(wins_tdb, "WINSDB_VERSION", WINSDB_VERSION);
617 add_samba_names_to_subnet(wins_server_subnet);
619 if((fp = x_fopen(state_path(WINS_LIST),O_RDONLY,0)) == NULL) {
620 DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
621 WINS_LIST, strerror(errno) ));
622 return True;
625 while (!x_feof(fp)) {
626 char *name_str = NULL;
627 char *ip_str = NULL;
628 char *ttl_str = NULL, *nb_flags_str = NULL;
629 unsigned int num_ips;
630 char *name = NULL;
631 struct in_addr *ip_list = NULL;
632 int type = 0;
633 int nb_flags;
634 int ttl;
635 const char *ptr;
636 char *p = NULL;
637 bool got_token;
638 bool was_ip;
639 int i;
640 unsigned int hash;
641 int version;
642 TALLOC_CTX *frame = NULL;
644 /* Read a line from the wins.dat file. Strips whitespace
645 from the beginning and end of the line. */
646 if (!fgets_slash(line,sizeof(line),fp)) {
647 continue;
650 if (*line == '#') {
651 continue;
654 if (strncmp(line,"VERSION ", 8) == 0) {
655 if (sscanf(line,"VERSION %d %u", &version, &hash) != 2 ||
656 version != WINS_VERSION) {
657 DEBUG(0,("Discarding invalid wins.dat file [%s]\n",line));
658 x_fclose(fp);
659 return True;
661 continue;
664 ptr = line;
667 * Now we handle multiple IP addresses per name we need
668 * to iterate over the line twice. The first time to
669 * determine how many IP addresses there are, the second
670 * time to actually parse them into the ip_list array.
673 frame = talloc_stackframe();
674 if (!next_token_talloc(frame,&ptr,&name_str,NULL)) {
675 DEBUG(0,("initialise_wins: Failed to parse name when parsing line %s\n", line ));
676 TALLOC_FREE(frame);
677 continue;
680 if (!next_token_talloc(frame,&ptr,&ttl_str,NULL)) {
681 DEBUG(0,("initialise_wins: Failed to parse time to live when parsing line %s\n", line ));
682 TALLOC_FREE(frame);
683 continue;
687 * Determine the number of IP addresses per line.
689 num_ips = 0;
690 do {
691 got_token = next_token_talloc(frame,&ptr,&ip_str,NULL);
692 was_ip = False;
694 if(got_token && strchr(ip_str, '.')) {
695 num_ips++;
696 was_ip = True;
698 } while(got_token && was_ip);
700 if(num_ips == 0) {
701 DEBUG(0,("initialise_wins: Missing IP address when parsing line %s\n", line ));
702 TALLOC_FREE(frame);
703 continue;
706 if(!got_token) {
707 DEBUG(0,("initialise_wins: Missing nb_flags when parsing line %s\n", line ));
708 TALLOC_FREE(frame);
709 continue;
712 /* Allocate the space for the ip_list. */
713 if((ip_list = SMB_MALLOC_ARRAY( struct in_addr, num_ips)) == NULL) {
714 DEBUG(0,("initialise_wins: Malloc fail !\n"));
715 x_fclose(fp);
716 TALLOC_FREE(frame);
717 return False;
720 /* Reset and re-parse the line. */
721 ptr = line;
722 next_token_talloc(frame,&ptr,&name_str,NULL);
723 next_token_talloc(frame,&ptr,&ttl_str,NULL);
724 for(i = 0; i < num_ips; i++) {
725 next_token_talloc(frame,&ptr, &ip_str, NULL);
726 ip_list[i] = interpret_addr2(ip_str);
728 next_token_talloc(frame,&ptr,&nb_flags_str,NULL);
731 * Deal with SELF or REGISTER name encoding. Default is REGISTER
732 * for compatibility with old nmbds.
735 if(nb_flags_str[strlen(nb_flags_str)-1] == 'S') {
736 DEBUG(5,("initialise_wins: Ignoring SELF name %s\n", line));
737 SAFE_FREE(ip_list);
738 TALLOC_FREE(frame);
739 continue;
742 if(nb_flags_str[strlen(nb_flags_str)-1] == 'R') {
743 nb_flags_str[strlen(nb_flags_str)-1] = '\0';
746 /* Netbios name. # divides the name from the type (hex): netbios#xx */
747 name = name_str;
749 if((p = strchr(name,'#')) != NULL) {
750 *p = 0;
751 sscanf(p+1,"%x",&type);
754 /* Decode the netbios flags (hex) and the time-to-live (in seconds). */
755 sscanf(nb_flags_str,"%x",&nb_flags);
756 sscanf(ttl_str,"%d",&ttl);
758 /* add all entries that have 60 seconds or more to live */
759 if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) {
760 if(ttl != PERMANENT_TTL) {
761 ttl -= time_now;
764 DEBUG( 4, ("initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
765 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
767 (void)add_name_to_subnet( wins_server_subnet, name, type, nb_flags,
768 ttl, REGISTER_NAME, num_ips, ip_list );
769 } else {
770 DEBUG(4, ("initialise_wins: not adding name (ttl problem) "
771 "%s#%02x ttl = %d first IP %s flags = %2x\n",
772 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
775 TALLOC_FREE(frame);
776 SAFE_FREE(ip_list);
779 x_fclose(fp);
780 return True;
783 /****************************************************************************
784 Send a WINS WACK (Wait ACKnowledgement) response.
785 **************************************************************************/
787 static void send_wins_wack_response(int ttl, struct packet_struct *p)
789 struct nmb_packet *nmb = &p->packet.nmb;
790 unsigned char rdata[2];
792 rdata[0] = rdata[1] = 0;
794 /* Taken from nmblib.c - we need to send back almost
795 identical bytes from the requesting packet header. */
797 rdata[0] = (nmb->header.opcode & 0xF) << 3;
798 if (nmb->header.nm_flags.authoritative && nmb->header.response) {
799 rdata[0] |= 0x4;
801 if (nmb->header.nm_flags.trunc) {
802 rdata[0] |= 0x2;
804 if (nmb->header.nm_flags.recursion_desired) {
805 rdata[0] |= 0x1;
807 if (nmb->header.nm_flags.recursion_available && nmb->header.response) {
808 rdata[1] |= 0x80;
810 if (nmb->header.nm_flags.bcast) {
811 rdata[1] |= 0x10;
814 reply_netbios_packet(p, /* Packet to reply to. */
815 0, /* Result code. */
816 NMB_WAIT_ACK, /* nmbd type code. */
817 NMB_WACK_OPCODE, /* opcode. */
818 ttl, /* ttl. */
819 (char *)rdata, /* data to send. */
820 2); /* data length. */
823 /****************************************************************************
824 Send a WINS name registration response.
825 **************************************************************************/
827 static void send_wins_name_registration_response(int rcode, int ttl, struct packet_struct *p)
829 struct nmb_packet *nmb = &p->packet.nmb;
830 char rdata[6];
832 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
834 reply_netbios_packet(p, /* Packet to reply to. */
835 rcode, /* Result code. */
836 WINS_REG, /* nmbd type code. */
837 NMB_NAME_REG_OPCODE, /* opcode. */
838 ttl, /* ttl. */
839 rdata, /* data to send. */
840 6); /* data length. */
843 /***********************************************************************
844 Deal with a name refresh request to a WINS server.
845 ************************************************************************/
847 void wins_process_name_refresh_request( struct subnet_record *subrec,
848 struct packet_struct *p )
850 struct nmb_packet *nmb = &p->packet.nmb;
851 struct nmb_name *question = &nmb->question.question_name;
852 bool bcast = nmb->header.nm_flags.bcast;
853 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
854 bool group = (nb_flags & NB_GROUP) ? True : False;
855 struct name_record *namerec = NULL;
856 int ttl = get_ttl_from_packet(nmb);
857 struct in_addr from_ip;
858 struct in_addr our_fake_ip;
860 our_fake_ip = interpret_addr2("0.0.0.0");
861 putip( (char *)&from_ip, &nmb->additional->rdata[2] );
863 if(bcast) {
865 * We should only get unicast name refresh packets here.
866 * Anyone trying to refresh broadcast should not be going
867 * to a WINS server. Log an error here.
869 if( DEBUGLVL( 0 ) ) {
870 dbgtext( "wins_process_name_refresh_request: " );
871 dbgtext( "Broadcast name refresh request received " );
872 dbgtext( "for name %s ", nmb_namestr(question) );
873 dbgtext( "from IP %s ", inet_ntoa(from_ip) );
874 dbgtext( "on subnet %s. ", subrec->subnet_name );
875 dbgtext( "Error - Broadcasts should not be sent " );
876 dbgtext( "to a WINS server\n" );
878 return;
881 if( DEBUGLVL( 3 ) ) {
882 dbgtext( "wins_process_name_refresh_request: " );
883 dbgtext( "Name refresh for name %s IP %s\n",
884 nmb_namestr(question), inet_ntoa(from_ip) );
888 * See if the name already exists.
889 * If not, handle it as a name registration and return.
891 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
894 * If this is a refresh request and the name doesn't exist then
895 * treat it like a registration request. This allows us to recover
896 * from errors (tridge)
898 if(namerec == NULL) {
899 if( DEBUGLVL( 3 ) ) {
900 dbgtext( "wins_process_name_refresh_request: " );
901 dbgtext( "Name refresh for name %s ",
902 nmb_namestr( question ) );
903 dbgtext( "and the name does not exist. Treating " );
904 dbgtext( "as registration.\n" );
906 wins_process_name_registration_request(subrec,p);
907 return;
911 * if the name is present but not active, simply remove it
912 * and treat the refresh request as a registration & return.
914 if (namerec != NULL && !WINS_STATE_ACTIVE(namerec)) {
915 if( DEBUGLVL( 5 ) ) {
916 dbgtext( "wins_process_name_refresh_request: " );
917 dbgtext( "Name (%s) in WINS ", nmb_namestr(question) );
918 dbgtext( "was not active - removing it.\n" );
920 remove_name_from_namelist( subrec, namerec );
921 namerec = NULL;
922 wins_process_name_registration_request( subrec, p );
923 return;
927 * Check that the group bits for the refreshing name and the
928 * name in our database match. If not, refuse the refresh.
929 * [crh: Why RFS_ERR instead of ACT_ERR? Is this what MS does?]
931 if( (namerec != NULL) &&
932 ( (group && !NAME_GROUP(namerec))
933 || (!group && NAME_GROUP(namerec)) ) ) {
934 if( DEBUGLVL( 3 ) ) {
935 dbgtext( "wins_process_name_refresh_request: " );
936 dbgtext( "Name %s ", nmb_namestr(question) );
937 dbgtext( "group bit = %s does not match ",
938 group ? "True" : "False" );
939 dbgtext( "group bit in WINS for this name.\n" );
941 send_wins_name_registration_response(RFS_ERR, 0, p);
942 return;
946 * For a unique name check that the person refreshing the name is
947 * one of the registered IP addresses. If not - fail the refresh.
948 * Do the same for group names with a type of 0x1c.
949 * Just return success for unique 0x1d refreshes. For normal group
950 * names update the ttl and return success.
952 if( (!group || (group && (question->name_type == 0x1c)))
953 && find_ip_in_name_record(namerec, from_ip) ) {
955 * Update the ttl.
957 update_name_ttl(namerec, ttl);
960 * if the record is a replica:
961 * we take ownership and update the version ID.
963 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
964 update_wins_owner(namerec, our_fake_ip);
965 get_global_id_and_update(&namerec->data.id, True);
968 send_wins_name_registration_response(0, ttl, p);
969 wins_hook("refresh", namerec, ttl);
970 return;
971 } else if((group && (question->name_type == 0x1c))) {
973 * Added by crh for bug #1079.
974 * Fix from Bert Driehuis
976 if( DEBUGLVL( 3 ) ) {
977 dbgtext( "wins_process_name_refresh_request: " );
978 dbgtext( "Name refresh for name %s, ",
979 nmb_namestr(question) );
980 dbgtext( "but IP address %s ", inet_ntoa(from_ip) );
981 dbgtext( "is not yet associated with " );
982 dbgtext( "that name. Treating as registration.\n" );
984 wins_process_name_registration_request(subrec,p);
985 return;
986 } else if(group) {
988 * Normal groups are all registered with an IP address of
989 * 255.255.255.255 so we can't search for the IP address.
991 update_name_ttl(namerec, ttl);
992 wins_hook("refresh", namerec, ttl);
993 send_wins_name_registration_response(0, ttl, p);
994 return;
995 } else if(!group && (question->name_type == 0x1d)) {
997 * Special name type - just pretend the refresh succeeded.
999 send_wins_name_registration_response(0, ttl, p);
1000 return;
1001 } else {
1003 * Fail the refresh.
1005 if( DEBUGLVL( 3 ) ) {
1006 dbgtext( "wins_process_name_refresh_request: " );
1007 dbgtext( "Name refresh for name %s with IP %s ",
1008 nmb_namestr(question), inet_ntoa(from_ip) );
1009 dbgtext( "and is IP is not known to the name.\n" );
1011 send_wins_name_registration_response(RFS_ERR, 0, p);
1012 return;
1016 /***********************************************************************
1017 Deal with a name registration request query success to a client that
1018 owned the name.
1020 We have a locked pointer to the original packet stashed away in the
1021 userdata pointer. The success here is actually a failure as it means
1022 the client we queried wants to keep the name, so we must return
1023 a registration failure to the original requestor.
1024 ************************************************************************/
1026 static void wins_register_query_success(struct subnet_record *subrec,
1027 struct userdata_struct *userdata,
1028 struct nmb_name *question_name,
1029 struct in_addr ip,
1030 struct res_rec *answers)
1032 struct packet_struct *orig_reg_packet;
1034 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1036 DEBUG(3,("wins_register_query_success: Original client at IP %s still wants the \
1037 name %s. Rejecting registration request.\n", inet_ntoa(ip), nmb_namestr(question_name) ));
1039 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1041 orig_reg_packet->locked = False;
1042 free_packet(orig_reg_packet);
1045 /***********************************************************************
1046 Deal with a name registration request query failure to a client that
1047 owned the name.
1049 We have a locked pointer to the original packet stashed away in the
1050 userdata pointer. The failure here is actually a success as it means
1051 the client we queried didn't want to keep the name, so we can remove
1052 the old name record and then successfully add the new name.
1053 ************************************************************************/
1055 static void wins_register_query_fail(struct subnet_record *subrec,
1056 struct response_record *rrec,
1057 struct nmb_name *question_name,
1058 int rcode)
1060 struct userdata_struct *userdata = rrec->userdata;
1061 struct packet_struct *orig_reg_packet;
1062 struct name_record *namerec = NULL;
1064 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1067 * We want to just add the name, as we now know the original owner
1068 * didn't want it. But we can't just do that as an arbitary
1069 * amount of time may have taken place between the name query
1070 * request and this timeout/error response. So we check that
1071 * the name still exists and is in the same state - if so
1072 * we remove it and call wins_process_name_registration_request()
1073 * as we know it will do the right thing now.
1076 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1078 if ((namerec != NULL) && (namerec->data.source == REGISTER_NAME) &&
1079 ip_equal_v4(rrec->packet->ip, *namerec->data.ip)) {
1080 remove_name_from_namelist( subrec, namerec);
1081 namerec = NULL;
1084 if(namerec == NULL) {
1085 wins_process_name_registration_request(subrec, orig_reg_packet);
1086 } else {
1087 DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between "
1088 "querying for name %s in order to replace it and this reply.\n",
1089 nmb_namestr(question_name) ));
1092 orig_reg_packet->locked = False;
1093 free_packet(orig_reg_packet);
1096 /***********************************************************************
1097 Deal with a name registration request to a WINS server.
1099 Use the following pseudocode :
1101 registering_group
1104 +--------name exists
1107 | +--- existing name is group
1108 | | |
1109 | | |
1110 | | +--- add name (return).
1113 | +--- exiting name is unique
1116 | +--- query existing owner (return).
1119 +--------name doesn't exist
1122 +--- add name (return).
1124 registering_unique
1127 +--------name exists
1130 | +--- existing name is group
1131 | | |
1132 | | |
1133 | | +--- fail add (return).
1134 | |
1136 | +--- exiting name is unique
1139 | +--- query existing owner (return).
1142 +--------name doesn't exist
1145 +--- add name (return).
1147 As can be seen from the above, the two cases may be collapsed onto each
1148 other with the exception of the case where the name already exists and
1149 is a group name. This case we handle with an if statement.
1151 ************************************************************************/
1153 void wins_process_name_registration_request(struct subnet_record *subrec,
1154 struct packet_struct *p)
1156 unstring name;
1157 struct nmb_packet *nmb = &p->packet.nmb;
1158 struct nmb_name *question = &nmb->question.question_name;
1159 bool bcast = nmb->header.nm_flags.bcast;
1160 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
1161 int ttl = get_ttl_from_packet(nmb);
1162 struct name_record *namerec = NULL;
1163 struct in_addr from_ip;
1164 bool registering_group_name = (nb_flags & NB_GROUP) ? True : False;
1165 struct in_addr our_fake_ip;
1167 our_fake_ip = interpret_addr2("0.0.0.0");
1168 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1170 if(bcast) {
1172 * We should only get unicast name registration packets here.
1173 * Anyone trying to register broadcast should not be going to a WINS
1174 * server. Log an error here.
1177 DEBUG(0,("wins_process_name_registration_request: broadcast name registration request \
1178 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1179 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1180 return;
1183 DEBUG(3,("wins_process_name_registration_request: %s name registration for name %s \
1184 IP %s\n", registering_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
1187 * See if the name already exists.
1190 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1193 * if the record exists but NOT in active state,
1194 * consider it dead.
1196 if ( (namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1197 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1198 not active - removing it.\n", nmb_namestr(question) ));
1199 remove_name_from_namelist( subrec, namerec );
1200 namerec = NULL;
1204 * Deal with the case where the name found was a dns entry.
1205 * Remove it as we now have a NetBIOS client registering the
1206 * name.
1209 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1210 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1211 a dns lookup - removing it.\n", nmb_namestr(question) ));
1212 remove_name_from_namelist( subrec, namerec );
1213 namerec = NULL;
1217 * Reject if the name exists and is not a REGISTER_NAME.
1218 * (ie. Don't allow any static names to be overwritten.
1221 if((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) {
1222 DEBUG( 3, ( "wins_process_name_registration_request: Attempt \
1223 to register name %s. Name already exists in WINS with source type %d.\n",
1224 nmb_namestr(question), namerec->data.source ));
1225 send_wins_name_registration_response(RFS_ERR, 0, p);
1226 return;
1230 * Special policy decisions based on MS documentation.
1231 * 1). All group names (except names ending in 0x1c) are added as 255.255.255.255.
1232 * 2). All unique names ending in 0x1d are ignored, although a positive response is sent.
1236 * A group name is always added as the local broadcast address, except
1237 * for group names ending in 0x1c.
1238 * Group names with type 0x1c are registered with individual IP addresses.
1241 if(registering_group_name && (question->name_type != 0x1c)) {
1242 from_ip = interpret_addr2("255.255.255.255");
1246 * Ignore all attempts to register a unique 0x1d name, although return success.
1249 if(!registering_group_name && (question->name_type == 0x1d)) {
1250 DEBUG(3,("wins_process_name_registration_request: Ignoring request \
1251 to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
1252 send_wins_name_registration_response(0, ttl, p);
1253 return;
1257 * Next two cases are the 'if statement' mentioned above.
1260 if((namerec != NULL) && NAME_GROUP(namerec)) {
1261 if(registering_group_name) {
1263 * If we are adding a group name, the name exists and is also a group entry just add this
1264 * IP address to it and update the ttl.
1267 DEBUG(3,("wins_process_name_registration_request: Adding IP %s to group name %s.\n",
1268 inet_ntoa(from_ip), nmb_namestr(question) ));
1271 * Check the ip address is not already in the group.
1274 if(!find_ip_in_name_record(namerec, from_ip)) {
1276 * Need to emulate the behaviour of Windows, as
1277 * described in:
1278 * http://lists.samba.org/archive/samba-technical/2001-October/016236.html
1279 * (is there an MS reference for this
1280 * somewhere?) because if the 1c list gets over
1281 * 86 entries, the reply packet is too big
1282 * (rdata>576 bytes) so no reply is sent.
1284 * Keep only the "latest" 25 records, while
1285 * ensuring that the PDC (0x1b) is never removed
1286 * We do this by removing the first entry that
1287 * isn't the 1b entry for the same name,
1288 * on the grounds that insertion is at the end
1289 * of the list, so the oldest entries are at
1290 * the start.
1293 while(namerec->data.num_ips>=25) {
1294 struct name_record *name1brec = NULL;
1296 /* We only do this for 1c types. */
1297 if (namerec->name.name_type != 0x1c) {
1298 break;
1300 DEBUG(3,("wins_process_name_registration_request: "
1301 "More than 25 IPs already in "
1302 "the list. Looking for a 1b "
1303 "record\n"));
1305 /* Ensure we have all the active 1b
1306 * names on the list. */
1307 wins_delete_all_1b_in_memory_records();
1308 fetch_all_active_wins_1b_names();
1310 /* Per the above, find the 1b record,
1311 and then remove the first IP that isn't the same */
1312 for(name1brec = subrec->namelist;
1313 name1brec;
1314 name1brec = name1brec->next ) {
1315 if( WINS_STATE_ACTIVE(name1brec) &&
1316 name1brec->name.name_type == 0x1b) {
1317 DEBUG(3,("wins_process_name_registration_request: "
1318 "Found the #1b record "
1319 "with ip %s\n",
1320 inet_ntoa(name1brec->data.ip[0])));
1321 break;
1324 if(!name1brec) {
1325 DEBUG(3,("wins_process_name_registration_request: "
1326 "Didn't find a #1b name record. "
1327 "Removing the first available "
1328 "entry %s\n",
1329 inet_ntoa(namerec->data.ip[0])));
1330 remove_ip_from_name_record(namerec, namerec->data.ip[0]);
1331 wins_hook("delete", namerec, 0);
1332 } else {
1333 int i;
1334 for(i=0; i<namerec->data.num_ips; i++) {
1335 /* The name1brec should only have
1336 * the single IP address in it,
1337 * so we only check against the first one*/
1338 if(!ip_equal_v4( namerec->data.ip[i], name1brec->data.ip[0])) {
1339 /* The i'th entry isn't the 1b address; delete it */
1340 DEBUG(3,("wins_process_name_registration_request: "
1341 "Entry at %d is not the #1b address. "
1342 "About to remove it\n",
1343 i));
1344 remove_ip_from_name_record(namerec, namerec->data.ip[i]);
1345 wins_hook("delete", namerec, 0);
1346 break;
1351 /* The list is guaranteed to be < 25 entries now
1352 * - safe to add a new one */
1353 add_ip_to_name_record(namerec, from_ip);
1354 /* we need to update the record for replication */
1355 get_global_id_and_update(&namerec->data.id, True);
1358 * if the record is a replica, we must change
1359 * the wins owner to us to make the replication updates
1360 * it on the other wins servers.
1361 * And when the partner will receive this record,
1362 * it will update its own record.
1365 update_wins_owner(namerec, our_fake_ip);
1367 update_name_ttl(namerec, ttl);
1368 wins_hook("refresh", namerec, ttl);
1369 send_wins_name_registration_response(0, ttl, p);
1370 return;
1371 } else {
1374 * If we are adding a unique name, the name exists in the WINS db
1375 * and is a group name then reject the registration.
1377 * explanation: groups have a higher priority than unique names.
1380 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1381 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1382 send_wins_name_registration_response(RFS_ERR, 0, p);
1383 return;
1388 * From here on down we know that if the name exists in the WINS db it is
1389 * a unique name, not a group name.
1393 * If the name exists and is one of our names then check the
1394 * registering IP address. If it's not one of ours then automatically
1395 * reject without doing the query - we know we will reject it.
1398 if ( namerec != NULL ) {
1399 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
1400 if( is_myname(name) ) {
1401 if(!ismyip_v4(from_ip)) {
1402 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1403 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1404 send_wins_name_registration_response(RFS_ERR, 0, p);
1405 return;
1406 } else {
1408 * It's one of our names and one of our IP's - update the ttl.
1410 update_name_ttl(namerec, ttl);
1411 wins_hook("refresh", namerec, ttl);
1412 send_wins_name_registration_response(0, ttl, p);
1413 return;
1416 } else {
1417 name[0] = '\0';
1421 * If the name exists and it is a unique registration and the registering IP
1422 * is the same as the (single) already registered IP then just update the ttl.
1424 * But not if the record is an active replica. IF it's a replica, it means it can be
1425 * the same client which has moved and not yet expired. So we don't update
1426 * the ttl in this case and go beyond to do a WACK and query the old client
1429 if( !registering_group_name
1430 && (namerec != NULL)
1431 && (namerec->data.num_ips == 1)
1432 && ip_equal_v4( namerec->data.ip[0], from_ip )
1433 && ip_equal_v4(namerec->data.wins_ip, our_fake_ip) ) {
1434 update_name_ttl( namerec, ttl );
1435 wins_hook("refresh", namerec, ttl);
1436 send_wins_name_registration_response( 0, ttl, p );
1437 return;
1441 * Finally if the name exists do a query to the registering machine
1442 * to see if they still claim to have the name.
1445 if( namerec != NULL ) {
1446 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1447 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1450 * First send a WACK to the registering machine.
1453 send_wins_wack_response(60, p);
1456 * When the reply comes back we need the original packet.
1457 * Lock this so it won't be freed and then put it into
1458 * the userdata structure.
1461 p->locked = True;
1463 userdata = (struct userdata_struct *)ud;
1465 userdata->copy_fn = NULL;
1466 userdata->free_fn = NULL;
1467 userdata->userdata_len = sizeof(struct packet_struct *);
1468 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1471 * Use the new call to send a query directly to an IP address.
1472 * This sends the query directly to the IP address, and ensures
1473 * the recursion desired flag is not set (you were right Luke :-).
1474 * This function should *only* be called from the WINS server
1475 * code. JRA.
1478 pull_ascii_nstring(name, sizeof(name), question->name);
1479 query_name_from_wins_server( *namerec->data.ip,
1480 name,
1481 question->name_type,
1482 wins_register_query_success,
1483 wins_register_query_fail,
1484 userdata );
1485 return;
1489 * Name did not exist - add it.
1492 pull_ascii_nstring(name, sizeof(name), question->name);
1493 add_name_to_subnet( subrec, name, question->name_type,
1494 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1496 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1497 get_global_id_and_update(&namerec->data.id, True);
1498 update_wins_owner(namerec, our_fake_ip);
1499 update_wins_flag(namerec, WINS_ACTIVE);
1500 wins_hook("add", namerec, ttl);
1503 send_wins_name_registration_response(0, ttl, p);
1506 /***********************************************************************
1507 Deal with a mutihomed name query success to the machine that
1508 requested the multihomed name registration.
1510 We have a locked pointer to the original packet stashed away in the
1511 userdata pointer.
1512 ************************************************************************/
1514 static void wins_multihomed_register_query_success(struct subnet_record *subrec,
1515 struct userdata_struct *userdata,
1516 struct nmb_name *question_name,
1517 struct in_addr ip,
1518 struct res_rec *answers)
1520 struct packet_struct *orig_reg_packet;
1521 struct nmb_packet *nmb;
1522 struct name_record *namerec = NULL;
1523 struct in_addr from_ip;
1524 int ttl;
1525 struct in_addr our_fake_ip;
1527 our_fake_ip = interpret_addr2("0.0.0.0");
1528 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1530 nmb = &orig_reg_packet->packet.nmb;
1532 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1533 ttl = get_ttl_from_packet(nmb);
1536 * We want to just add the new IP, as we now know the requesting
1537 * machine claims to own it. But we can't just do that as an arbitary
1538 * amount of time may have taken place between the name query
1539 * request and this response. So we check that
1540 * the name still exists and is in the same state - if so
1541 * we just add the extra IP and update the ttl.
1544 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1546 if( (namerec == NULL) || (namerec->data.source != REGISTER_NAME) || !WINS_STATE_ACTIVE(namerec) ) {
1547 DEBUG(3,("wins_multihomed_register_query_success: name %s is not in the correct state to add \
1548 a subsequent IP address.\n", nmb_namestr(question_name) ));
1549 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1551 orig_reg_packet->locked = False;
1552 free_packet(orig_reg_packet);
1554 return;
1557 if(!find_ip_in_name_record(namerec, from_ip)) {
1558 add_ip_to_name_record(namerec, from_ip);
1561 get_global_id_and_update(&namerec->data.id, True);
1562 update_wins_owner(namerec, our_fake_ip);
1563 update_wins_flag(namerec, WINS_ACTIVE);
1564 update_name_ttl(namerec, ttl);
1565 wins_hook("add", namerec, ttl);
1566 send_wins_name_registration_response(0, ttl, orig_reg_packet);
1568 orig_reg_packet->locked = False;
1569 free_packet(orig_reg_packet);
1572 /***********************************************************************
1573 Deal with a name registration request query failure to a client that
1574 owned the name.
1576 We have a locked pointer to the original packet stashed away in the
1577 userdata pointer.
1578 ************************************************************************/
1580 static void wins_multihomed_register_query_fail(struct subnet_record *subrec,
1581 struct response_record *rrec,
1582 struct nmb_name *question_name,
1583 int rcode)
1585 struct userdata_struct *userdata = rrec->userdata;
1586 struct packet_struct *orig_reg_packet;
1588 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1590 DEBUG(3,("wins_multihomed_register_query_fail: Registering machine at IP %s failed to answer \
1591 query successfully for name %s.\n", inet_ntoa(orig_reg_packet->ip), nmb_namestr(question_name) ));
1592 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1594 orig_reg_packet->locked = False;
1595 free_packet(orig_reg_packet);
1596 return;
1599 /***********************************************************************
1600 Deal with a multihomed name registration request to a WINS server.
1601 These cannot be group name registrations.
1602 ***********************************************************************/
1604 void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
1605 struct packet_struct *p)
1607 struct nmb_packet *nmb = &p->packet.nmb;
1608 struct nmb_name *question = &nmb->question.question_name;
1609 bool bcast = nmb->header.nm_flags.bcast;
1610 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
1611 int ttl = get_ttl_from_packet(nmb);
1612 struct name_record *namerec = NULL;
1613 struct in_addr from_ip;
1614 bool group = (nb_flags & NB_GROUP) ? True : False;
1615 struct in_addr our_fake_ip;
1616 unstring qname;
1618 our_fake_ip = interpret_addr2("0.0.0.0");
1619 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1621 if(bcast) {
1623 * We should only get unicast name registration packets here.
1624 * Anyone trying to register broadcast should not be going to a WINS
1625 * server. Log an error here.
1628 DEBUG(0,("wins_process_multihomed_name_registration_request: broadcast name registration request \
1629 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1630 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1631 return;
1635 * Only unique names should be registered multihomed.
1638 if(group) {
1639 DEBUG(0,("wins_process_multihomed_name_registration_request: group name registration request \
1640 received for name %s from IP %s on subnet %s. Errror - group names should not be multihomed.\n",
1641 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1642 return;
1645 DEBUG(3,("wins_process_multihomed_name_registration_request: name registration for name %s \
1646 IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ));
1649 * Deal with policy regarding 0x1d names.
1652 if(question->name_type == 0x1d) {
1653 DEBUG(3,("wins_process_multihomed_name_registration_request: Ignoring request \
1654 to register name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
1655 send_wins_name_registration_response(0, ttl, p);
1656 return;
1660 * See if the name already exists.
1663 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1666 * if the record exists but NOT in active state,
1667 * consider it dead.
1670 if ((namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1671 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was not active - removing it.\n", nmb_namestr(question)));
1672 remove_name_from_namelist(subrec, namerec);
1673 namerec = NULL;
1677 * Deal with the case where the name found was a dns entry.
1678 * Remove it as we now have a NetBIOS client registering the
1679 * name.
1682 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1683 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was a dns lookup \
1684 - removing it.\n", nmb_namestr(question) ));
1685 remove_name_from_namelist( subrec, namerec);
1686 namerec = NULL;
1690 * Reject if the name exists and is not a REGISTER_NAME.
1691 * (ie. Don't allow any static names to be overwritten.
1694 if( (namerec != NULL) && (namerec->data.source != REGISTER_NAME) ) {
1695 DEBUG( 3, ( "wins_process_multihomed_name_registration_request: Attempt \
1696 to register name %s. Name already exists in WINS with source type %d.\n",
1697 nmb_namestr(question), namerec->data.source ));
1698 send_wins_name_registration_response(RFS_ERR, 0, p);
1699 return;
1703 * Reject if the name exists and is a GROUP name and is active.
1706 if((namerec != NULL) && NAME_GROUP(namerec) && WINS_STATE_ACTIVE(namerec)) {
1707 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1708 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1709 send_wins_name_registration_response(RFS_ERR, 0, p);
1710 return;
1714 * From here on down we know that if the name exists in the WINS db it is
1715 * a unique name, not a group name.
1719 * If the name exists and is one of our names then check the
1720 * registering IP address. If it's not one of ours then automatically
1721 * reject without doing the query - we know we will reject it.
1724 if((namerec != NULL) && (is_myname(namerec->name.name)) ) {
1725 if(!ismyip_v4(from_ip)) {
1726 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1727 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1728 send_wins_name_registration_response(RFS_ERR, 0, p);
1729 return;
1730 } else {
1732 * It's one of our names and one of our IP's. Ensure the IP is in the record and
1733 * update the ttl. Update the version ID to force replication.
1735 update_name_ttl(namerec, ttl);
1737 if(!find_ip_in_name_record(namerec, from_ip)) {
1738 get_global_id_and_update(&namerec->data.id, True);
1739 update_wins_owner(namerec, our_fake_ip);
1740 update_wins_flag(namerec, WINS_ACTIVE);
1742 add_ip_to_name_record(namerec, from_ip);
1745 wins_hook("refresh", namerec, ttl);
1746 send_wins_name_registration_response(0, ttl, p);
1747 return;
1752 * If the name exists and is active, check if the IP address is already registered
1753 * to that name. If so then update the ttl and reply success.
1756 if((namerec != NULL) && find_ip_in_name_record(namerec, from_ip) && WINS_STATE_ACTIVE(namerec)) {
1757 update_name_ttl(namerec, ttl);
1760 * If it's a replica, we need to become the wins owner
1761 * to force the replication
1763 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
1764 get_global_id_and_update(&namerec->data.id, True);
1765 update_wins_owner(namerec, our_fake_ip);
1766 update_wins_flag(namerec, WINS_ACTIVE);
1769 wins_hook("refresh", namerec, ttl);
1770 send_wins_name_registration_response(0, ttl, p);
1771 return;
1775 * If the name exists do a query to the owner
1776 * to see if they still want the name.
1779 if(namerec != NULL) {
1780 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1781 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1784 * First send a WACK to the registering machine.
1787 send_wins_wack_response(60, p);
1790 * When the reply comes back we need the original packet.
1791 * Lock this so it won't be freed and then put it into
1792 * the userdata structure.
1795 p->locked = True;
1797 userdata = (struct userdata_struct *)ud;
1799 userdata->copy_fn = NULL;
1800 userdata->free_fn = NULL;
1801 userdata->userdata_len = sizeof(struct packet_struct *);
1802 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1805 * Use the new call to send a query directly to an IP address.
1806 * This sends the query directly to the IP address, and ensures
1807 * the recursion desired flag is not set (you were right Luke :-).
1808 * This function should *only* be called from the WINS server
1809 * code. JRA.
1811 * Note that this packet is sent to the current owner of the name,
1812 * not the person who sent the packet
1815 pull_ascii_nstring( qname, sizeof(qname), question->name);
1816 query_name_from_wins_server( namerec->data.ip[0],
1817 qname,
1818 question->name_type,
1819 wins_multihomed_register_query_success,
1820 wins_multihomed_register_query_fail,
1821 userdata );
1823 return;
1827 * Name did not exist - add it.
1830 pull_ascii_nstring( qname, sizeof(qname), question->name);
1831 add_name_to_subnet( subrec, qname, question->name_type,
1832 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1834 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1835 get_global_id_and_update(&namerec->data.id, True);
1836 update_wins_owner(namerec, our_fake_ip);
1837 update_wins_flag(namerec, WINS_ACTIVE);
1838 wins_hook("add", namerec, ttl);
1841 send_wins_name_registration_response(0, ttl, p);
1844 /***********************************************************************
1845 Fetch all *<1b> names from the WINS db and store on the namelist.
1846 ***********************************************************************/
1848 static int fetch_1b_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
1850 struct name_record *namerec = NULL;
1852 if (kbuf.dsize != sizeof(unstring) + 1) {
1853 return 0;
1856 /* Filter out all non-1b names. */
1857 if (kbuf.dptr[sizeof(unstring)] != 0x1b) {
1858 return 0;
1861 namerec = wins_record_to_name_record(kbuf, dbuf);
1862 if (!namerec) {
1863 return 0;
1866 DLIST_ADD(wins_server_subnet->namelist, namerec);
1867 return 0;
1870 void fetch_all_active_wins_1b_names(void)
1872 tdb_traverse(wins_tdb, fetch_1b_traverse_fn, NULL);
1875 /***********************************************************************
1876 Deal with the special name query for *<1b>.
1877 ***********************************************************************/
1879 static void process_wins_dmb_query_request(struct subnet_record *subrec,
1880 struct packet_struct *p)
1882 struct name_record *namerec = NULL;
1883 char *prdata;
1884 int num_ips;
1887 * Go through all the ACTIVE names in the WINS db looking for those
1888 * ending in <1b>. Use this to calculate the number of IP
1889 * addresses we need to return.
1892 num_ips = 0;
1894 /* First, clear the in memory list - we're going to re-populate
1895 it with the tdb_traversal in fetch_all_active_wins_1b_names. */
1897 wins_delete_all_tmp_in_memory_records();
1899 fetch_all_active_wins_1b_names();
1901 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1902 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1903 num_ips += namerec->data.num_ips;
1907 if(num_ips == 0) {
1909 * There are no 0x1b names registered. Return name query fail.
1911 send_wins_name_query_response(NAM_ERR, p, NULL);
1912 return;
1915 if((prdata = (char *)SMB_MALLOC( num_ips * 6 )) == NULL) {
1916 DEBUG(0,("process_wins_dmb_query_request: Malloc fail !.\n"));
1917 return;
1921 * Go through all the names again in the WINS db looking for those
1922 * ending in <1b>. Add their IP addresses into the list we will
1923 * return.
1926 num_ips = 0;
1927 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1928 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1929 int i;
1930 for(i = 0; i < namerec->data.num_ips; i++) {
1931 set_nb_flags(&prdata[num_ips * 6],namerec->data.nb_flags);
1932 putip((char *)&prdata[(num_ips * 6) + 2], &namerec->data.ip[i]);
1933 num_ips++;
1939 * Send back the reply containing the IP list.
1942 reply_netbios_packet(p, /* Packet to reply to. */
1943 0, /* Result code. */
1944 WINS_QUERY, /* nmbd type code. */
1945 NMB_NAME_QUERY_OPCODE, /* opcode. */
1946 lp_min_wins_ttl(), /* ttl. */
1947 prdata, /* data to send. */
1948 num_ips*6); /* data length. */
1950 SAFE_FREE(prdata);
1953 /****************************************************************************
1954 Send a WINS name query response.
1955 **************************************************************************/
1957 void send_wins_name_query_response(int rcode, struct packet_struct *p,
1958 struct name_record *namerec)
1960 char rdata[6];
1961 char *prdata = rdata;
1962 int reply_data_len = 0;
1963 int ttl = 0;
1964 int i;
1966 memset(rdata,'\0',6);
1968 if(rcode == 0) {
1970 int ip_count;
1972 ttl = (namerec->data.death_time != PERMANENT_TTL) ? namerec->data.death_time - p->timestamp : lp_max_wins_ttl();
1974 /* The netbios reply packet data section is limited to 576 bytes. In theory
1975 * this should give us space for 96 addresses, but in practice, 86 appears
1976 * to be the max (don't know why). If we send any more than that,
1977 * reply_netbios_packet will fail to send a reply to avoid a memcpy buffer
1978 * overflow. Keep the count to 85 and it will be ok */
1979 ip_count=namerec->data.num_ips;
1980 if(ip_count>85) {
1981 ip_count=85;
1984 /* Copy all known ip addresses into the return data. */
1985 /* Optimise for the common case of one IP address so we don't need a malloc. */
1987 if( ip_count == 1 ) {
1988 prdata = rdata;
1989 } else {
1990 if((prdata = (char *)SMB_MALLOC( ip_count * 6 )) == NULL) {
1991 DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
1992 return;
1996 for(i = 0; i < ip_count; i++) {
1997 set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
1998 putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
2001 sort_query_replies(prdata, i, p->ip);
2002 reply_data_len = ip_count * 6;
2005 reply_netbios_packet(p, /* Packet to reply to. */
2006 rcode, /* Result code. */
2007 WINS_QUERY, /* nmbd type code. */
2008 NMB_NAME_QUERY_OPCODE, /* opcode. */
2009 ttl, /* ttl. */
2010 prdata, /* data to send. */
2011 reply_data_len); /* data length. */
2013 if(prdata != rdata) {
2014 SAFE_FREE(prdata);
2018 /***********************************************************************
2019 Deal with a name query.
2020 ***********************************************************************/
2022 void wins_process_name_query_request(struct subnet_record *subrec,
2023 struct packet_struct *p)
2025 struct nmb_packet *nmb = &p->packet.nmb;
2026 struct nmb_name *question = &nmb->question.question_name;
2027 struct name_record *namerec = NULL;
2028 unstring qname;
2030 DEBUG(3,("wins_process_name_query: name query for name %s from IP %s\n",
2031 nmb_namestr(question), inet_ntoa(p->ip) ));
2034 * Special name code. If the queried name is *<1b> then search
2035 * the entire WINS database and return a list of all the IP addresses
2036 * registered to any <1b> name. This is to allow domain master browsers
2037 * to discover other domains that may not have a presence on their subnet.
2040 pull_ascii_nstring(qname, sizeof(qname), question->name);
2041 if(strequal( qname, "*") && (question->name_type == 0x1b)) {
2042 process_wins_dmb_query_request( subrec, p);
2043 return;
2046 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2048 if(namerec != NULL) {
2050 * If the name is not anymore in active state then reply not found.
2051 * it's fair even if we keep it in the cache for days.
2053 if (!WINS_STATE_ACTIVE(namerec)) {
2054 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
2055 nmb_namestr(question) ));
2056 send_wins_name_query_response(NAM_ERR, p, namerec);
2057 return;
2061 * If it's a DNSFAIL_NAME then reply name not found.
2064 if( namerec->data.source == DNSFAIL_NAME ) {
2065 DEBUG(3,("wins_process_name_query: name query for name %s returning DNS fail.\n",
2066 nmb_namestr(question) ));
2067 send_wins_name_query_response(NAM_ERR, p, namerec);
2068 return;
2072 * If the name has expired then reply name not found.
2075 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < p->timestamp) ) {
2076 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
2077 nmb_namestr(question) ));
2078 send_wins_name_query_response(NAM_ERR, p, namerec);
2079 return;
2082 DEBUG(3,("wins_process_name_query: name query for name %s returning first IP %s.\n",
2083 nmb_namestr(question), inet_ntoa(namerec->data.ip[0]) ));
2085 send_wins_name_query_response(0, p, namerec);
2086 return;
2090 * Name not found in WINS - try a dns query if it's a 0x20 name.
2093 if(lp_dns_proxy() && ((question->name_type == 0x20) || question->name_type == 0)) {
2094 DEBUG(3,("wins_process_name_query: name query for name %s not found - doing dns lookup.\n",
2095 nmb_namestr(question) ));
2097 queue_dns_query(p, question);
2098 return;
2102 * Name not found - return error.
2105 send_wins_name_query_response(NAM_ERR, p, NULL);
2108 /****************************************************************************
2109 Send a WINS name release response.
2110 **************************************************************************/
2112 static void send_wins_name_release_response(int rcode, struct packet_struct *p)
2114 struct nmb_packet *nmb = &p->packet.nmb;
2115 char rdata[6];
2117 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
2119 reply_netbios_packet(p, /* Packet to reply to. */
2120 rcode, /* Result code. */
2121 NMB_REL, /* nmbd type code. */
2122 NMB_NAME_RELEASE_OPCODE, /* opcode. */
2123 0, /* ttl. */
2124 rdata, /* data to send. */
2125 6); /* data length. */
2128 /***********************************************************************
2129 Deal with a name release.
2130 ***********************************************************************/
2132 void wins_process_name_release_request(struct subnet_record *subrec,
2133 struct packet_struct *p)
2135 struct nmb_packet *nmb = &p->packet.nmb;
2136 struct nmb_name *question = &nmb->question.question_name;
2137 bool bcast = nmb->header.nm_flags.bcast;
2138 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
2139 struct name_record *namerec = NULL;
2140 struct in_addr from_ip;
2141 bool releasing_group_name = (nb_flags & NB_GROUP) ? True : False;
2143 putip((char *)&from_ip,&nmb->additional->rdata[2]);
2145 if(bcast) {
2147 * We should only get unicast name registration packets here.
2148 * Anyone trying to register broadcast should not be going to a WINS
2149 * server. Log an error here.
2152 DEBUG(0,("wins_process_name_release_request: broadcast name registration request \
2153 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
2154 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
2155 return;
2158 DEBUG(3,("wins_process_name_release_request: %s name release for name %s \
2159 IP %s\n", releasing_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
2162 * Deal with policy regarding 0x1d names.
2165 if(!releasing_group_name && (question->name_type == 0x1d)) {
2166 DEBUG(3,("wins_process_name_release_request: Ignoring request \
2167 to release name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
2168 send_wins_name_release_response(0, p);
2169 return;
2173 * See if the name already exists.
2176 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2178 if( (namerec == NULL) || ((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) ) {
2179 send_wins_name_release_response(NAM_ERR, p);
2180 return;
2184 * Check that the sending machine has permission to release this name.
2185 * If it's a group name not ending in 0x1c then just say yes and let
2186 * the group time out.
2189 if(releasing_group_name && (question->name_type != 0x1c)) {
2190 send_wins_name_release_response(0, p);
2191 return;
2195 * Check that the releasing node is on the list of IP addresses
2196 * for this name. Disallow the release if not.
2199 if(!find_ip_in_name_record(namerec, from_ip)) {
2200 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2201 release name %s as IP %s is not one of the known IP's for this name.\n",
2202 nmb_namestr(question), inet_ntoa(from_ip) ));
2203 send_wins_name_release_response(NAM_ERR, p);
2204 return;
2208 * Check if the record is active. IF it's already released
2209 * or tombstoned, refuse the release.
2212 if (!WINS_STATE_ACTIVE(namerec)) {
2213 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2214 release name %s as this record is not active anymore.\n", nmb_namestr(question) ));
2215 send_wins_name_release_response(NAM_ERR, p);
2216 return;
2220 * Check if the record is a 0x1c group
2221 * and has more then one ip
2222 * remove only this address.
2225 if(releasing_group_name && (question->name_type == 0x1c) && (namerec->data.num_ips > 1)) {
2226 remove_ip_from_name_record(namerec, from_ip);
2227 DEBUG(3,("wins_process_name_release_request: Remove IP %s from NAME: %s\n",
2228 inet_ntoa(from_ip),nmb_namestr(question)));
2229 wins_hook("delete", namerec, 0);
2230 send_wins_name_release_response(0, p);
2231 return;
2235 * Send a release response.
2236 * Flag the name as released and update the ttl
2239 namerec->data.wins_flags |= WINS_RELEASED;
2240 update_name_ttl(namerec, EXTINCTION_INTERVAL);
2242 wins_hook("delete", namerec, 0);
2243 send_wins_name_release_response(0, p);
2246 /*******************************************************************
2247 WINS time dependent processing.
2248 ******************************************************************/
2250 static int wins_processing_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2252 time_t t = *(time_t *)state;
2253 bool store_record = False;
2254 struct name_record *namerec = NULL;
2255 struct in_addr our_fake_ip;
2257 our_fake_ip = interpret_addr2("0.0.0.0");
2258 if (kbuf.dsize != sizeof(unstring) + 1) {
2259 return 0;
2262 namerec = wins_record_to_name_record(kbuf, dbuf);
2263 if (!namerec) {
2264 return 0;
2267 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
2268 if( namerec->data.source == SELF_NAME ) {
2269 DEBUG( 3, ( "wins_processing_traverse_fn: Subnet %s not expiring SELF name %s\n",
2270 wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) );
2271 namerec->data.death_time += 300;
2272 store_record = True;
2273 goto done;
2274 } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) {
2275 DEBUG(3,("wins_processing_traverse_fn: deleting timed out DNS name %s\n",
2276 nmb_namestr(&namerec->name)));
2277 remove_name_from_wins_namelist(namerec );
2278 goto done;
2281 /* handle records, samba is the wins owner */
2282 if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
2283 switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2284 case WINS_ACTIVE:
2285 namerec->data.wins_flags&=~WINS_STATE_MASK;
2286 namerec->data.wins_flags|=WINS_RELEASED;
2287 namerec->data.death_time = t + EXTINCTION_INTERVAL;
2288 DEBUG(3,("wins_processing_traverse_fn: expiring %s\n",
2289 nmb_namestr(&namerec->name)));
2290 store_record = True;
2291 goto done;
2292 case WINS_RELEASED:
2293 namerec->data.wins_flags&=~WINS_STATE_MASK;
2294 namerec->data.wins_flags|=WINS_TOMBSTONED;
2295 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2296 get_global_id_and_update(&namerec->data.id, True);
2297 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2298 nmb_namestr(&namerec->name)));
2299 store_record = True;
2300 goto done;
2301 case WINS_TOMBSTONED:
2302 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2303 nmb_namestr(&namerec->name)));
2304 remove_name_from_wins_namelist(namerec );
2305 goto done;
2307 } else {
2308 switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2309 case WINS_ACTIVE:
2310 /* that's not as MS says it should be */
2311 namerec->data.wins_flags&=~WINS_STATE_MASK;
2312 namerec->data.wins_flags|=WINS_TOMBSTONED;
2313 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2314 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2315 nmb_namestr(&namerec->name)));
2316 store_record = True;
2317 goto done;
2318 case WINS_TOMBSTONED:
2319 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2320 nmb_namestr(&namerec->name)));
2321 remove_name_from_wins_namelist(namerec );
2322 goto done;
2323 case WINS_RELEASED:
2324 DEBUG(0,("wins_processing_traverse_fn: %s is in released state and\
2325 we are not the wins owner !\n", nmb_namestr(&namerec->name)));
2326 goto done;
2331 done:
2333 if (store_record) {
2334 wins_store_changed_namerec(namerec);
2337 SAFE_FREE(namerec->data.ip);
2338 SAFE_FREE(namerec);
2340 return 0;
2343 /*******************************************************************
2344 Time dependent wins processing.
2345 ******************************************************************/
2347 void initiate_wins_processing(time_t t)
2349 static time_t lasttime = 0;
2351 if (!lasttime) {
2352 lasttime = t;
2354 if (t - lasttime < 20) {
2355 return;
2358 if(!lp_we_are_a_wins_server()) {
2359 lasttime = t;
2360 return;
2363 tdb_traverse(wins_tdb, wins_processing_traverse_fn, &t);
2365 wins_delete_all_tmp_in_memory_records();
2367 wins_write_database(t, True);
2369 lasttime = t;
2372 /*******************************************************************
2373 Write out one record.
2374 ******************************************************************/
2376 void wins_write_name_record(struct name_record *namerec, XFILE *fp)
2378 int i;
2379 struct tm *tm;
2381 DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) ));
2383 if( namerec->data.death_time != PERMANENT_TTL ) {
2384 char *ts, *nl;
2386 tm = localtime(&namerec->data.death_time);
2387 if (!tm) {
2388 return;
2390 ts = asctime(tm);
2391 if (!ts) {
2392 return;
2394 nl = strrchr( ts, '\n' );
2395 if( NULL != nl ) {
2396 *nl = '\0';
2398 DEBUGADD(4,("TTL = %s ", ts ));
2399 } else {
2400 DEBUGADD(4,("TTL = PERMANENT "));
2403 for (i = 0; i < namerec->data.num_ips; i++) {
2404 DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) ));
2406 DEBUGADD(4,("%2x\n", namerec->data.nb_flags ));
2408 if( namerec->data.source == REGISTER_NAME ) {
2409 unstring name;
2410 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
2411 x_fprintf(fp, "\"%s#%02x\" %d ", name,namerec->name.name_type, /* Ignore scope. */
2412 (int)namerec->data.death_time);
2414 for (i = 0; i < namerec->data.num_ips; i++)
2415 x_fprintf( fp, "%s ", inet_ntoa( namerec->data.ip[i] ) );
2416 x_fprintf( fp, "%2xR\n", namerec->data.nb_flags );
2420 /*******************************************************************
2421 Write out the current WINS database.
2422 ******************************************************************/
2424 static int wins_writedb_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2426 struct name_record *namerec = NULL;
2427 XFILE *fp = (XFILE *)state;
2429 if (kbuf.dsize != sizeof(unstring) + 1) {
2430 return 0;
2433 namerec = wins_record_to_name_record(kbuf, dbuf);
2434 if (!namerec) {
2435 return 0;
2438 wins_write_name_record(namerec, fp);
2440 SAFE_FREE(namerec->data.ip);
2441 SAFE_FREE(namerec);
2442 return 0;
2446 void wins_write_database(time_t t, bool background)
2448 static time_t last_write_time = 0;
2449 char *fname = NULL;
2450 char *fnamenew = NULL;
2452 XFILE *fp;
2454 if (background) {
2455 if (!last_write_time) {
2456 last_write_time = t;
2458 if (t - last_write_time < 120) {
2459 return;
2464 if(!lp_we_are_a_wins_server()) {
2465 return;
2468 /* We will do the writing in a child process to ensure that the parent doesn't block while this is done */
2469 if (background) {
2470 CatchChild();
2471 if (sys_fork()) {
2472 return;
2474 if (tdb_reopen(wins_tdb)) {
2475 DEBUG(0,("wins_write_database: tdb_reopen failed. Error was %s\n",
2476 strerror(errno)));
2477 _exit(0);
2478 return;
2482 if (!(fname = state_path(WINS_LIST))) {
2483 goto err_exit;
2485 /* This is safe as the 0 length means "don't expand". */
2486 all_string_sub(fname,"//", "/", 0);
2488 if (asprintf(&fnamenew, "%s.%u", fname, (unsigned int)sys_getpid()) < 0) {
2489 goto err_exit;
2492 if((fp = x_fopen(fnamenew,O_WRONLY|O_CREAT,0644)) == NULL) {
2493 DEBUG(0,("wins_write_database: Can't open %s. Error was %s\n", fnamenew, strerror(errno)));
2494 goto err_exit;
2497 DEBUG(4,("wins_write_database: Dump of WINS name list.\n"));
2499 x_fprintf(fp,"VERSION %d %u\n", WINS_VERSION, 0);
2501 tdb_traverse(wins_tdb, wins_writedb_traverse_fn, fp);
2503 x_fclose(fp);
2504 chmod(fnamenew,0644);
2505 unlink(fname);
2506 rename(fnamenew,fname);
2508 err_exit:
2510 SAFE_FREE(fnamenew);
2511 TALLOC_FREE(fname);
2513 if (background) {
2514 _exit(0);
2518 #if 0
2519 Until winsrepl is done.
2520 /****************************************************************************
2521 Process a internal Samba message receiving a wins record.
2522 ***************************************************************************/
2524 void nmbd_wins_new_entry(struct messaging_context *msg,
2525 void *private_data,
2526 uint32_t msg_type,
2527 struct server_id server_id,
2528 DATA_BLOB *data)
2530 WINS_RECORD *record;
2531 struct name_record *namerec = NULL;
2532 struct name_record *new_namerec = NULL;
2533 struct nmb_name question;
2534 bool overwrite=False;
2535 struct in_addr our_fake_ip;
2536 int i;
2538 our_fake_ip = interpret_addr2("0.0.0.0");
2539 if (buf==NULL) {
2540 return;
2543 /* Record should use UNIX codepage. Ensure this is so in the wrepld code. JRA. */
2544 record=(WINS_RECORD *)buf;
2546 make_nmb_name(&question, record->name, record->type);
2548 namerec = find_name_on_subnet(wins_server_subnet, &question, FIND_ANY_NAME);
2550 /* record doesn't exist, add it */
2551 if (namerec == NULL) {
2552 DEBUG(3,("nmbd_wins_new_entry: adding new replicated record: %s<%02x> for wins server: %s\n",
2553 record->name, record->type, inet_ntoa(record->wins_ip)));
2555 new_namerec=add_name_to_subnet( wins_server_subnet,
2556 record->name,
2557 record->type,
2558 record->nb_flags,
2559 EXTINCTION_INTERVAL,
2560 REGISTER_NAME,
2561 record->num_ips,
2562 record->ip);
2564 if (new_namerec!=NULL) {
2565 update_wins_owner(new_namerec, record->wins_ip);
2566 update_wins_flag(new_namerec, record->wins_flags);
2567 new_namerec->data.id=record->id;
2569 wins_server_subnet->namelist_changed = True;
2573 /* check if we have a conflict */
2574 if (namerec != NULL) {
2575 /* both records are UNIQUE */
2576 if (namerec->data.wins_flags&WINS_UNIQUE && record->wins_flags&WINS_UNIQUE) {
2578 /* the database record is a replica */
2579 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
2580 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED) {
2581 if (ip_equal_v4(namerec->data.wins_ip, record->wins_ip))
2582 overwrite=True;
2583 } else
2584 overwrite=True;
2585 } else {
2586 /* we are the wins owner of the database record */
2587 /* the 2 records have the same IP address */
2588 if (ip_equal_v4(namerec->data.ip[0], record->ip[0])) {
2589 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED)
2590 get_global_id_and_update(&namerec->data.id, True);
2591 else
2592 overwrite=True;
2594 } else {
2595 /* the 2 records have different IP address */
2596 if (namerec->data.wins_flags&WINS_ACTIVE) {
2597 if (record->wins_flags&WINS_TOMBSTONED)
2598 get_global_id_and_update(&namerec->data.id, True);
2599 if (record->wins_flags&WINS_ACTIVE)
2600 /* send conflict challenge to the replica node */
2602 } else
2603 overwrite=True;
2609 /* the replica is a standard group */
2610 if (record->wins_flags&WINS_NGROUP || record->wins_flags&WINS_SGROUP) {
2611 /* if the database record is unique and active force a name release */
2612 if (namerec->data.wins_flags&WINS_UNIQUE)
2613 /* send a release name to the unique node */
2615 overwrite=True;
2619 /* the replica is a special group */
2620 if (record->wins_flags&WINS_SGROUP && namerec->data.wins_flags&WINS_SGROUP) {
2621 if (namerec->data.wins_flags&WINS_ACTIVE) {
2622 for (i=0; i<record->num_ips; i++)
2623 if(!find_ip_in_name_record(namerec, record->ip[i]))
2624 add_ip_to_name_record(namerec, record->ip[i]);
2625 } else {
2626 overwrite=True;
2630 /* the replica is a multihomed host */
2632 /* I'm giving up on multi homed. Too much complex to understand */
2634 if (record->wins_flags&WINS_MHOMED) {
2635 if (! (namerec->data.wins_flags&WINS_ACTIVE)) {
2636 if ( !(namerec->data.wins_flags&WINS_RELEASED) && !(namerec->data.wins_flags&WINS_NGROUP))
2637 overwrite=True;
2639 else {
2640 if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
2641 overwrite=True;
2643 if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip))
2644 if (namerec->data.wins_flags&WINS_UNIQUE)
2645 get_global_id_and_update(&namerec->data.id, True);
2649 if (record->wins_flags&WINS_ACTIVE && namerec->data.wins_flags&WINS_ACTIVE)
2650 if (namerec->data.wins_flags&WINS_UNIQUE ||
2651 namerec->data.wins_flags&WINS_MHOMED)
2652 if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
2653 overwrite=True;
2657 if (overwrite == False)
2658 DEBUG(3, ("nmbd_wins_new_entry: conflict in adding record: %s<%02x> from wins server: %s\n",
2659 record->name, record->type, inet_ntoa(record->wins_ip)));
2660 else {
2661 DEBUG(3, ("nmbd_wins_new_entry: replacing record: %s<%02x> from wins server: %s\n",
2662 record->name, record->type, inet_ntoa(record->wins_ip)));
2664 /* remove the old record and add a new one */
2665 remove_name_from_namelist( wins_server_subnet, namerec );
2666 new_namerec=add_name_to_subnet( wins_server_subnet, record->name, record->type, record->nb_flags,
2667 EXTINCTION_INTERVAL, REGISTER_NAME, record->num_ips, record->ip);
2668 if (new_namerec!=NULL) {
2669 update_wins_owner(new_namerec, record->wins_ip);
2670 update_wins_flag(new_namerec, record->wins_flags);
2671 new_namerec->data.id=record->id;
2673 wins_server_subnet->namelist_changed = True;
2676 wins_server_subnet->namelist_changed = True;
2681 #endif