smbd: Simplify an if-condition
[Samba.git] / source3 / nmbd / nmbd_winsserver.c
blob4d4f19fef8bed8da76f45e78f09b51fdc70e5a22
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"
27 #include "lib/util/util_file.h"
29 #define WINS_LIST "wins.dat"
30 #define WINS_VERSION 1
31 #define WINSDB_VERSION 1
33 /****************************************************************************
34 We don't store the NetBIOS scope in the wins.tdb. We key off the (utf8) netbios
35 name (65 bytes with the last byte being the name type).
36 *****************************************************************************/
38 TDB_CONTEXT *wins_tdb;
40 /****************************************************************************
41 Delete all the temporary name records on the in-memory linked list.
42 *****************************************************************************/
44 static void wins_delete_all_tmp_in_memory_records(void)
46 struct name_record *nr = NULL;
47 struct name_record *nrnext = NULL;
49 /* Delete all temporary name records on the wins subnet linked list. */
50 for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
51 nrnext = nr->next;
52 DLIST_REMOVE(wins_server_subnet->namelist, nr);
53 SAFE_FREE(nr->data.ip);
54 SAFE_FREE(nr);
58 /****************************************************************************
59 Delete all the temporary 1b name records on the in-memory linked list.
60 *****************************************************************************/
62 static void wins_delete_all_1b_in_memory_records(void)
64 struct name_record *nr = NULL;
65 struct name_record *nrnext = NULL;
67 /* Delete all temporary 1b name records on the wins subnet linked list. */
68 for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
69 nrnext = nr->next;
70 if (nr->name.name_type == 0x1b) {
71 DLIST_REMOVE(wins_server_subnet->namelist, nr);
72 SAFE_FREE(nr->data.ip);
73 SAFE_FREE(nr);
78 /****************************************************************************
79 Convert a wins.tdb record to a struct name_record. Add in our lp_netbios_scope().
80 *****************************************************************************/
82 static struct name_record *wins_record_to_name_record(TDB_DATA key, TDB_DATA data)
84 struct name_record *namerec = NULL;
85 uint16_t nb_flags;
86 unsigned char nr_src;
87 uint32_t death_time, refresh_time;
88 uint32_t id_low, id_high;
89 uint32_t saddr;
90 uint32_t wins_flags;
91 uint32_t num_ips;
92 size_t len;
93 int i;
95 if (data.dptr == NULL || data.dsize == 0) {
96 return NULL;
99 /* Min size is "wbddddddd" + 1 ip address (4). */
100 if (data.dsize < 2 + 1 + (7*4) + 4) {
101 return NULL;
104 len = tdb_unpack(data.dptr, data.dsize,
105 "wbddddddd",
106 &nb_flags,
107 &nr_src,
108 &death_time,
109 &refresh_time,
110 &id_low,
111 &id_high,
112 &saddr,
113 &wins_flags,
114 &num_ips );
116 namerec = SMB_MALLOC_P(struct name_record);
117 if (!namerec) {
118 return NULL;
120 ZERO_STRUCTP(namerec);
122 namerec->data.ip = SMB_MALLOC_ARRAY(struct in_addr, num_ips);
123 if (!namerec->data.ip) {
124 SAFE_FREE(namerec);
125 return NULL;
128 namerec->subnet = wins_server_subnet;
129 push_ascii_nstring(namerec->name.name, (const char *)key.dptr);
130 namerec->name.name_type = key.dptr[sizeof(unstring)];
131 /* Add the scope. */
132 push_ascii(namerec->name.scope, lp_netbios_scope(), 64, STR_TERMINATE);
134 /* We're using a byte-by-byte compare, so we must be sure that
135 * unused space doesn't have garbage in it.
138 for( i = strlen( namerec->name.name ); i < sizeof( namerec->name.name ); i++ ) {
139 namerec->name.name[i] = '\0';
141 for( i = strlen( namerec->name.scope ); i < sizeof( namerec->name.scope ); i++ ) {
142 namerec->name.scope[i] = '\0';
145 namerec->data.nb_flags = nb_flags;
146 namerec->data.source = (enum name_source)nr_src;
147 namerec->data.death_time = (time_t)death_time;
148 namerec->data.refresh_time = (time_t)refresh_time;
149 namerec->data.id = id_low;
150 namerec->data.id |= ((uint64_t)id_high << 32);
151 namerec->data.wins_ip.s_addr = saddr;
152 namerec->data.wins_flags = wins_flags,
153 namerec->data.num_ips = num_ips;
155 for (i = 0; i < num_ips; i++) {
156 namerec->data.ip[i].s_addr = IVAL(data.dptr, len + (i*4));
159 return namerec;
162 /****************************************************************************
163 Convert a struct name_record to a wins.tdb record. Ignore the scope.
164 *****************************************************************************/
166 static TDB_DATA name_record_to_wins_record(const struct name_record *namerec)
168 TDB_DATA data;
169 size_t len = 0;
170 int i;
171 uint32_t id_low = (namerec->data.id & 0xFFFFFFFF);
172 uint32_t id_high = (namerec->data.id >> 32) & 0xFFFFFFFF;
174 ZERO_STRUCT(data);
176 len = (2 + 1 + (7*4)); /* "wbddddddd" */
177 len += (namerec->data.num_ips * 4);
179 data.dptr = (uint8_t *)SMB_MALLOC(len);
180 if (!data.dptr) {
181 return data;
183 data.dsize = len;
185 len = tdb_pack(data.dptr, data.dsize, "wbddddddd",
186 namerec->data.nb_flags,
187 (unsigned char)namerec->data.source,
188 (uint32_t)namerec->data.death_time,
189 (uint32_t)namerec->data.refresh_time,
190 id_low,
191 id_high,
192 (uint32_t)namerec->data.wins_ip.s_addr,
193 (uint32_t)namerec->data.wins_flags,
194 (uint32_t)namerec->data.num_ips );
196 for (i = 0; i < namerec->data.num_ips; i++) {
197 SIVAL(data.dptr, len + (i*4), namerec->data.ip[i].s_addr);
200 return data;
203 /****************************************************************************
204 Create key. Key is UNIX codepage namestring (usually utf8 64 byte len) with 1 byte type.
205 *****************************************************************************/
207 static TDB_DATA name_to_key(const struct nmb_name *nmbname)
209 static char keydata[sizeof(unstring) + 1];
210 TDB_DATA key;
212 memset(keydata, '\0', sizeof(keydata));
214 pull_ascii_nstring(keydata, sizeof(unstring), nmbname->name);
215 (void)strupper_m(keydata);
216 keydata[sizeof(unstring)] = nmbname->name_type;
217 key.dptr = (uint8_t *)keydata;
218 key.dsize = sizeof(keydata);
220 return key;
223 /****************************************************************************
224 Lookup a given name in the wins.tdb and create a temporary malloc'ed data struct
225 on the linked list. We will free this later in XXXX().
226 *****************************************************************************/
228 struct name_record *find_name_on_wins_subnet(const struct nmb_name *nmbname, bool self_only)
230 TDB_DATA data, key;
231 struct name_record *nr = NULL;
232 struct name_record *namerec = NULL;
234 if (!wins_tdb) {
235 return NULL;
238 key = name_to_key(nmbname);
239 data = tdb_fetch(wins_tdb, key);
241 if (data.dsize == 0) {
242 return NULL;
245 namerec = wins_record_to_name_record(key, data);
247 /* done with the this */
249 SAFE_FREE( data.dptr );
251 if (!namerec) {
252 return NULL;
255 /* Self names only - these include permanent names. */
256 if( self_only && (namerec->data.source != SELF_NAME) && (namerec->data.source != PERMANENT_NAME) ) {
257 DEBUG( 9, ( "find_name_on_wins_subnet: self name %s NOT FOUND\n", nmb_namestr(nmbname) ) );
258 SAFE_FREE(namerec->data.ip);
259 SAFE_FREE(namerec);
260 return NULL;
263 /* Search for this name record on the list. Replace it if found. */
265 for( nr = wins_server_subnet->namelist; nr; nr = nr->next) {
266 if (memcmp(nmbname->name, nr->name.name, 16) == 0) {
267 /* Delete it. */
268 DLIST_REMOVE(wins_server_subnet->namelist, nr);
269 SAFE_FREE(nr->data.ip);
270 SAFE_FREE(nr);
271 break;
275 DLIST_ADD(wins_server_subnet->namelist, namerec);
276 return namerec;
279 /****************************************************************************
280 Overwrite or add a given name in the wins.tdb.
281 *****************************************************************************/
283 static bool store_or_replace_wins_namerec(const struct name_record *namerec, int tdb_flag)
285 TDB_DATA key, data;
286 int ret;
288 if (!wins_tdb) {
289 return False;
292 key = name_to_key(&namerec->name);
293 data = name_record_to_wins_record(namerec);
295 if (data.dptr == NULL) {
296 return False;
299 ret = tdb_store(wins_tdb, key, data, tdb_flag);
301 SAFE_FREE(data.dptr);
302 return (ret == 0) ? True : False;
305 /****************************************************************************
306 Overwrite a given name in the wins.tdb.
307 *****************************************************************************/
309 bool wins_store_changed_namerec(const struct name_record *namerec)
311 return store_or_replace_wins_namerec(namerec, TDB_REPLACE);
314 /****************************************************************************
315 Primary interface into creating and overwriting records in the wins.tdb.
316 *****************************************************************************/
318 bool add_name_to_wins_subnet(const struct name_record *namerec)
320 return store_or_replace_wins_namerec(namerec, TDB_INSERT);
323 /****************************************************************************
324 Delete a given name in the tdb and remove the temporary malloc'ed data struct
325 on the linked list.
326 *****************************************************************************/
328 bool remove_name_from_wins_namelist(struct name_record *namerec)
330 TDB_DATA key;
331 int ret;
333 if (!wins_tdb) {
334 return False;
337 key = name_to_key(&namerec->name);
338 ret = tdb_delete(wins_tdb, key);
340 DLIST_REMOVE(wins_server_subnet->namelist, namerec);
342 /* namerec must be freed by the caller */
344 return (ret == 0) ? True : False;
347 /****************************************************************************
348 Dump out the complete namelist.
349 *****************************************************************************/
351 static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
353 struct name_record *namerec = NULL;
354 FILE *fp = (FILE *)state;
356 if (kbuf.dsize != sizeof(unstring) + 1) {
357 return 0;
360 namerec = wins_record_to_name_record(kbuf, dbuf);
361 if (!namerec) {
362 return 0;
365 dump_name_record(namerec, fp);
367 SAFE_FREE(namerec->data.ip);
368 SAFE_FREE(namerec);
369 return 0;
372 void dump_wins_subnet_namelist(FILE *fp)
374 tdb_traverse(wins_tdb, traverse_fn, (void *)fp);
377 /****************************************************************************
378 Change the wins owner address in the record.
379 *****************************************************************************/
381 static void update_wins_owner(struct name_record *namerec, struct in_addr wins_ip)
383 namerec->data.wins_ip=wins_ip;
386 /****************************************************************************
387 Create the wins flags based on the nb flags and the input value.
388 *****************************************************************************/
390 static void update_wins_flag(struct name_record *namerec, int flags)
392 namerec->data.wins_flags=0x0;
394 /* if it's a group, it can be a normal or a special one */
395 if (namerec->data.nb_flags & NB_GROUP) {
396 if (namerec->name.name_type==0x1C) {
397 namerec->data.wins_flags|=WINS_SGROUP;
398 } else {
399 if (namerec->data.num_ips>1) {
400 namerec->data.wins_flags|=WINS_SGROUP;
401 } else {
402 namerec->data.wins_flags|=WINS_NGROUP;
405 } else {
406 /* can be unique or multi-homed */
407 if (namerec->data.num_ips>1) {
408 namerec->data.wins_flags|=WINS_MHOMED;
409 } else {
410 namerec->data.wins_flags|=WINS_UNIQUE;
414 /* the node type are the same bits */
415 namerec->data.wins_flags|=namerec->data.nb_flags&NB_NODETYPEMASK;
417 /* the static bit is elsewhere */
418 if (namerec->data.death_time == PERMANENT_TTL) {
419 namerec->data.wins_flags|=WINS_STATIC;
422 /* and add the given bits */
423 namerec->data.wins_flags|=flags;
425 DEBUG(8,("update_wins_flag: nbflags: 0x%x, ttl: %d, flags: 0x%x, winsflags: 0x%x\n",
426 namerec->data.nb_flags, (int)namerec->data.death_time, flags, namerec->data.wins_flags));
429 /****************************************************************************
430 Return the general ID value and increase it if requested.
431 *****************************************************************************/
433 static void get_global_id_and_update(uint64_t *current_id, bool update)
436 * it's kept as a static here, to prevent people from messing
437 * with the value directly
440 static uint64_t general_id = 1;
442 DEBUG(5,("get_global_id_and_update: updating version ID: %d\n", (int)general_id));
444 *current_id = general_id;
446 if (update) {
447 general_id++;
451 /****************************************************************************
452 Possibly call the WINS hook external program when a WINS change is made.
453 Also stores the changed record back in the wins_tdb.
454 *****************************************************************************/
456 static void wins_hook(const char *operation, struct name_record *namerec, int ttl)
458 const struct loadparm_substitution *lp_sub =
459 loadparm_s3_global_substitution();
460 char *command = NULL;
461 char *cmd = lp_wins_hook(talloc_tos(), lp_sub);
462 char *p, *namestr;
463 int i;
464 TALLOC_CTX *ctx = talloc_tos();
466 wins_store_changed_namerec(namerec);
468 if (!cmd || !*cmd) {
469 return;
472 for (p=namerec->name.name; *p; p++) {
473 if (!(isalnum((int)*p) || strchr_m("._-",*p))) {
474 DEBUG(3,("not calling wins hook for invalid name %s\n", nmb_namestr(&namerec->name)));
475 return;
479 /* Use the name without the nametype (and scope) appended */
481 namestr = nmb_namestr(&namerec->name);
482 if ((p = strchr(namestr, '<'))) {
483 *p = 0;
486 command = talloc_asprintf(ctx,
487 "%s %s %s %02x %d",
488 cmd,
489 operation,
490 namestr,
491 namerec->name.name_type,
492 ttl);
493 if (!command) {
494 return;
497 for (i=0;i<namerec->data.num_ips;i++) {
498 command = talloc_asprintf_append(command,
499 " %s",
500 inet_ntoa(namerec->data.ip[i]));
501 if (!command) {
502 return;
506 DEBUG(3,("calling wins hook for %s\n", nmb_namestr(&namerec->name)));
507 smbrun(command, NULL, NULL);
508 TALLOC_FREE(command);
511 /****************************************************************************
512 Determine if this packet should be allocated to the WINS server.
513 *****************************************************************************/
515 bool packet_is_for_wins_server(struct packet_struct *packet)
517 struct nmb_packet *nmb = &packet->packet.nmb;
519 /* Only unicast packets go to a WINS server. */
520 if((wins_server_subnet == NULL) || (nmb->header.nm_flags.bcast == True)) {
521 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #1.\n"));
522 return False;
525 /* Check for node status requests. */
526 if (nmb->question.question_type != QUESTION_TYPE_NB_QUERY) {
527 return False;
530 switch(nmb->header.opcode) {
532 * A WINS server issues WACKS, not receives them.
534 case NMB_WACK_OPCODE:
535 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #2 (WACK).\n"));
536 return False;
538 * A WINS server only processes registration and
539 * release requests, not responses.
541 case NMB_NAME_REG_OPCODE:
542 case NMB_NAME_MULTIHOMED_REG_OPCODE:
543 case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
544 case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
545 if(nmb->header.response) {
546 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #3 (response = 1).\n"));
547 return False;
549 break;
551 case NMB_NAME_RELEASE_OPCODE:
552 if(nmb->header.response) {
553 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #4 (response = 1).\n"));
554 return False;
556 break;
559 * Only process unicast name queries with rd = 1.
561 case NMB_NAME_QUERY_OPCODE:
562 if(!nmb->header.response && !nmb->header.nm_flags.recursion_desired) {
563 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #5 (response = 1).\n"));
564 return False;
566 break;
569 return True;
572 /****************************************************************************
573 Utility function to decide what ttl to give a register/refresh request.
574 *****************************************************************************/
576 static int get_ttl_from_packet(struct nmb_packet *nmb)
578 int ttl = nmb->additional->ttl;
580 if (ttl < lp_min_wins_ttl()) {
581 ttl = lp_min_wins_ttl();
584 if (ttl > lp_max_wins_ttl()) {
585 ttl = lp_max_wins_ttl();
588 return ttl;
591 /****************************************************************************
592 Load or create the WINS database.
593 *****************************************************************************/
595 bool initialise_wins(void)
597 time_t time_now = time(NULL);
598 FILE *fp;
599 char line[1024];
600 char *db_path;
601 char *list_path;
603 if(!lp_we_are_a_wins_server()) {
604 return True;
607 db_path = state_path(talloc_tos(), "wins.tdb");
608 if (db_path == NULL) {
609 return false;
612 /* Open the wins.tdb. */
613 wins_tdb = tdb_open_log(db_path, 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
614 O_CREAT|O_RDWR, 0600);
615 TALLOC_FREE(db_path);
616 if (!wins_tdb) {
617 DEBUG(0,("initialise_wins: failed to open wins.tdb. Error was %s\n",
618 strerror(errno) ));
619 return False;
622 tdb_store_int32(wins_tdb, "WINSDB_VERSION", WINSDB_VERSION);
624 add_samba_names_to_subnet(wins_server_subnet);
626 list_path = state_path(talloc_tos(), WINS_LIST);
627 if (list_path == NULL) {
628 tdb_close(wins_tdb);
629 return false;
632 fp = fopen(list_path, "r");
633 TALLOC_FREE(list_path);
634 if (fp == NULL) {
635 DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
636 WINS_LIST, strerror(errno) ));
637 return True;
640 while (!feof(fp)) {
641 char *name_str = NULL;
642 char *ip_str = NULL;
643 char *ttl_str = NULL, *nb_flags_str = NULL;
644 unsigned int num_ips;
645 char *name = NULL;
646 struct in_addr *ip_list = NULL;
647 int type = 0;
648 int nb_flags;
649 int ttl;
650 const char *ptr;
651 char *p = NULL;
652 bool got_token;
653 bool was_ip;
654 int i;
655 unsigned int hash;
656 int version;
657 TALLOC_CTX *frame = NULL;
659 /* Read a line from the wins.dat file. Strips whitespace
660 from the beginning and end of the line. */
661 if (!fgets_slash(NULL, line, sizeof(line), fp)) {
662 continue;
665 if (*line == '#') {
666 continue;
669 if (strncmp(line,"VERSION ", 8) == 0) {
670 if (sscanf(line,"VERSION %d %u", &version, &hash) != 2 ||
671 version != WINS_VERSION) {
672 DEBUG(0,("Discarding invalid wins.dat file [%s]\n",line));
673 fclose(fp);
674 return True;
676 continue;
679 ptr = line;
682 * Now we handle multiple IP addresses per name we need
683 * to iterate over the line twice. The first time to
684 * determine how many IP addresses there are, the second
685 * time to actually parse them into the ip_list array.
688 frame = talloc_stackframe();
689 if (!next_token_talloc(frame,&ptr,&name_str,NULL)) {
690 DEBUG(0,("initialise_wins: Failed to parse name when parsing line %s\n", line ));
691 TALLOC_FREE(frame);
692 continue;
695 if (!next_token_talloc(frame,&ptr,&ttl_str,NULL)) {
696 DEBUG(0,("initialise_wins: Failed to parse time to live when parsing line %s\n", line ));
697 TALLOC_FREE(frame);
698 continue;
702 * Determine the number of IP addresses per line.
704 num_ips = 0;
705 do {
706 got_token = next_token_talloc(frame,&ptr,&ip_str,NULL);
707 was_ip = False;
709 if(got_token && strchr(ip_str, '.')) {
710 num_ips++;
711 was_ip = True;
713 } while(got_token && was_ip);
715 if(num_ips == 0) {
716 DEBUG(0,("initialise_wins: Missing IP address when parsing line %s\n", line ));
717 TALLOC_FREE(frame);
718 continue;
721 if(!got_token) {
722 DEBUG(0,("initialise_wins: Missing nb_flags when parsing line %s\n", line ));
723 TALLOC_FREE(frame);
724 continue;
727 /* Allocate the space for the ip_list. */
728 if((ip_list = SMB_MALLOC_ARRAY( struct in_addr, num_ips)) == NULL) {
729 DEBUG(0,("initialise_wins: Malloc fail !\n"));
730 fclose(fp);
731 TALLOC_FREE(frame);
732 return False;
735 /* Reset and re-parse the line. */
736 ptr = line;
737 next_token_talloc(frame,&ptr,&name_str,NULL);
738 next_token_talloc(frame,&ptr,&ttl_str,NULL);
739 for(i = 0; i < num_ips; i++) {
740 next_token_talloc(frame,&ptr, &ip_str, NULL);
741 ip_list[i] = interpret_addr2(ip_str);
743 next_token_talloc(frame,&ptr,&nb_flags_str,NULL);
746 * Deal with SELF or REGISTER name encoding. Default is REGISTER
747 * for compatibility with old nmbds.
750 if(nb_flags_str[strlen(nb_flags_str)-1] == 'S') {
751 DEBUG(5,("initialise_wins: Ignoring SELF name %s\n", line));
752 SAFE_FREE(ip_list);
753 TALLOC_FREE(frame);
754 continue;
757 if(nb_flags_str[strlen(nb_flags_str)-1] == 'R') {
758 nb_flags_str[strlen(nb_flags_str)-1] = '\0';
761 /* Netbios name. # divides the name from the type (hex): netbios#xx */
762 name = name_str;
764 if((p = strchr(name,'#')) != NULL) {
765 *p = 0;
766 sscanf(p+1,"%x",&type);
769 /* Decode the netbios flags (hex) and the time-to-live (in seconds). */
770 sscanf(nb_flags_str,"%x",&nb_flags);
771 sscanf(ttl_str,"%d",&ttl);
773 /* add all entries that have 60 seconds or more to live */
774 if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) {
775 if(ttl != PERMANENT_TTL) {
776 ttl -= time_now;
779 DEBUG( 4, ("initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
780 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
782 (void)add_name_to_subnet( wins_server_subnet, name, type, nb_flags,
783 ttl, REGISTER_NAME, num_ips, ip_list );
784 } else {
785 DEBUG(4, ("initialise_wins: not adding name (ttl problem) "
786 "%s#%02x ttl = %d first IP %s flags = %2x\n",
787 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
790 TALLOC_FREE(frame);
791 SAFE_FREE(ip_list);
794 fclose(fp);
795 return True;
798 /****************************************************************************
799 Send a WINS WACK (Wait ACKnowledgement) response.
800 **************************************************************************/
802 static void send_wins_wack_response(int ttl, struct packet_struct *p)
804 struct nmb_packet *nmb = &p->packet.nmb;
805 unsigned char rdata[2];
807 rdata[0] = rdata[1] = 0;
809 /* Taken from nmblib.c - we need to send back almost
810 identical bytes from the requesting packet header. */
812 rdata[0] = (nmb->header.opcode & 0xF) << 3;
813 if (nmb->header.nm_flags.authoritative && nmb->header.response) {
814 rdata[0] |= 0x4;
816 if (nmb->header.nm_flags.trunc) {
817 rdata[0] |= 0x2;
819 if (nmb->header.nm_flags.recursion_desired) {
820 rdata[0] |= 0x1;
822 if (nmb->header.nm_flags.recursion_available && nmb->header.response) {
823 rdata[1] |= 0x80;
825 if (nmb->header.nm_flags.bcast) {
826 rdata[1] |= 0x10;
829 reply_netbios_packet(p, /* Packet to reply to. */
830 0, /* Result code. */
831 NMB_WAIT_ACK, /* nmbd type code. */
832 NMB_WACK_OPCODE, /* opcode. */
833 ttl, /* ttl. */
834 (char *)rdata, /* data to send. */
835 2); /* data length. */
838 /****************************************************************************
839 Send a WINS name registration response.
840 **************************************************************************/
842 static void send_wins_name_registration_response(int rcode, int ttl, struct packet_struct *p)
844 struct nmb_packet *nmb = &p->packet.nmb;
845 char rdata[6];
847 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
849 reply_netbios_packet(p, /* Packet to reply to. */
850 rcode, /* Result code. */
851 WINS_REG, /* nmbd type code. */
852 NMB_NAME_REG_OPCODE, /* opcode. */
853 ttl, /* ttl. */
854 rdata, /* data to send. */
855 6); /* data length. */
858 /***********************************************************************
859 Deal with a name refresh request to a WINS server.
860 ************************************************************************/
862 void wins_process_name_refresh_request( struct subnet_record *subrec,
863 struct packet_struct *p )
865 struct nmb_packet *nmb = &p->packet.nmb;
866 struct nmb_name *question = &nmb->question.question_name;
867 bool bcast = nmb->header.nm_flags.bcast;
868 uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
869 bool group = (nb_flags & NB_GROUP) ? True : False;
870 struct name_record *namerec = NULL;
871 int ttl = get_ttl_from_packet(nmb);
872 struct in_addr from_ip;
873 struct in_addr our_fake_ip;
875 our_fake_ip = interpret_addr2("0.0.0.0");
876 putip( (char *)&from_ip, &nmb->additional->rdata[2] );
878 if(bcast) {
880 * We should only get unicast name refresh packets here.
881 * Anyone trying to refresh broadcast should not be going
882 * to a WINS server. Log an error here.
884 if( DEBUGLVL( 0 ) ) {
885 dbgtext( "wins_process_name_refresh_request: " );
886 dbgtext( "Broadcast name refresh request received " );
887 dbgtext( "for name %s ", nmb_namestr(question) );
888 dbgtext( "from IP %s ", inet_ntoa(from_ip) );
889 dbgtext( "on subnet %s. ", subrec->subnet_name );
890 dbgtext( "Error - Broadcasts should not be sent " );
891 dbgtext( "to a WINS server\n" );
893 return;
896 if( DEBUGLVL( 3 ) ) {
897 dbgtext( "wins_process_name_refresh_request: " );
898 dbgtext( "Name refresh for name %s IP %s\n",
899 nmb_namestr(question), inet_ntoa(from_ip) );
903 * See if the name already exists.
904 * If not, handle it as a name registration and return.
906 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
909 * If this is a refresh request and the name doesn't exist then
910 * treat it like a registration request. This allows us to recover
911 * from errors (tridge)
913 if(namerec == NULL) {
914 if( DEBUGLVL( 3 ) ) {
915 dbgtext( "wins_process_name_refresh_request: " );
916 dbgtext( "Name refresh for name %s ",
917 nmb_namestr( question ) );
918 dbgtext( "and the name does not exist. Treating " );
919 dbgtext( "as registration.\n" );
921 wins_process_name_registration_request(subrec,p);
922 return;
926 * if the name is present but not active, simply remove it
927 * and treat the refresh request as a registration & return.
929 if (namerec != NULL && !WINS_STATE_ACTIVE(namerec)) {
930 if( DEBUGLVL( 5 ) ) {
931 dbgtext( "wins_process_name_refresh_request: " );
932 dbgtext( "Name (%s) in WINS ", nmb_namestr(question) );
933 dbgtext( "was not active - removing it.\n" );
935 remove_name_from_namelist( subrec, namerec );
936 namerec = NULL;
937 wins_process_name_registration_request( subrec, p );
938 return;
942 * Check that the group bits for the refreshing name and the
943 * name in our database match. If not, refuse the refresh.
944 * [crh: Why RFS_ERR instead of ACT_ERR? Is this what MS does?]
946 if( (namerec != NULL) &&
947 ( (group && !NAME_GROUP(namerec))
948 || (!group && NAME_GROUP(namerec)) ) ) {
949 if( DEBUGLVL( 3 ) ) {
950 dbgtext( "wins_process_name_refresh_request: " );
951 dbgtext( "Name %s ", nmb_namestr(question) );
952 dbgtext( "group bit = %s does not match ",
953 group ? "True" : "False" );
954 dbgtext( "group bit in WINS for this name.\n" );
956 send_wins_name_registration_response(RFS_ERR, 0, p);
957 return;
961 * For a unique name check that the person refreshing the name is
962 * one of the registered IP addresses. If not - fail the refresh.
963 * Do the same for group names with a type of 0x1c.
964 * Just return success for unique 0x1d refreshes. For normal group
965 * names update the ttl and return success.
967 if( (!group || (group && (question->name_type == 0x1c)))
968 && find_ip_in_name_record(namerec, from_ip) ) {
970 * Update the ttl.
972 update_name_ttl(namerec, ttl);
975 * if the record is a replica:
976 * we take ownership and update the version ID.
978 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
979 update_wins_owner(namerec, our_fake_ip);
980 get_global_id_and_update(&namerec->data.id, True);
983 send_wins_name_registration_response(0, ttl, p);
984 wins_hook("refresh", namerec, ttl);
985 return;
986 } else if((group && (question->name_type == 0x1c))) {
988 * Added by crh for bug #1079.
989 * Fix from Bert Driehuis
991 if( DEBUGLVL( 3 ) ) {
992 dbgtext( "wins_process_name_refresh_request: " );
993 dbgtext( "Name refresh for name %s, ",
994 nmb_namestr(question) );
995 dbgtext( "but IP address %s ", inet_ntoa(from_ip) );
996 dbgtext( "is not yet associated with " );
997 dbgtext( "that name. Treating as registration.\n" );
999 wins_process_name_registration_request(subrec,p);
1000 return;
1001 } else if(group) {
1003 * Normal groups are all registered with an IP address of
1004 * 255.255.255.255 so we can't search for the IP address.
1006 update_name_ttl(namerec, ttl);
1007 wins_hook("refresh", namerec, ttl);
1008 send_wins_name_registration_response(0, ttl, p);
1009 return;
1010 } else if(!group && (question->name_type == 0x1d)) {
1012 * Special name type - just pretend the refresh succeeded.
1014 send_wins_name_registration_response(0, ttl, p);
1015 return;
1016 } else {
1018 * Fail the refresh.
1020 if( DEBUGLVL( 3 ) ) {
1021 dbgtext( "wins_process_name_refresh_request: " );
1022 dbgtext( "Name refresh for name %s with IP %s ",
1023 nmb_namestr(question), inet_ntoa(from_ip) );
1024 dbgtext( "and is IP is not known to the name.\n" );
1026 send_wins_name_registration_response(RFS_ERR, 0, p);
1027 return;
1031 /***********************************************************************
1032 Deal with a name registration request query success to a client that
1033 owned the name.
1035 We have a locked pointer to the original packet stashed away in the
1036 userdata pointer. The success here is actually a failure as it means
1037 the client we queried wants to keep the name, so we must return
1038 a registration failure to the original requester.
1039 ************************************************************************/
1041 static void wins_register_query_success(struct subnet_record *subrec,
1042 struct userdata_struct *userdata,
1043 struct nmb_name *question_name,
1044 struct in_addr ip,
1045 struct res_rec *answers)
1047 struct packet_struct *orig_reg_packet;
1049 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1051 DEBUG(3,("wins_register_query_success: Original client at IP %s still wants the \
1052 name %s. Rejecting registration request.\n", inet_ntoa(ip), nmb_namestr(question_name) ));
1054 send_wins_name_registration_response(ACT_ERR, 0, orig_reg_packet);
1056 orig_reg_packet->locked = False;
1057 free_packet(orig_reg_packet);
1060 /***********************************************************************
1061 Deal with a name registration request query failure to a client that
1062 owned the name.
1064 We have a locked pointer to the original packet stashed away in the
1065 userdata pointer. The failure here is actually a success as it means
1066 the client we queried didn't want to keep the name, so we can remove
1067 the old name record and then successfully add the new name.
1068 ************************************************************************/
1070 static void wins_register_query_fail(struct subnet_record *subrec,
1071 struct response_record *rrec,
1072 struct nmb_name *question_name,
1073 int rcode)
1075 struct userdata_struct *userdata = rrec->userdata;
1076 struct packet_struct *orig_reg_packet;
1077 struct name_record *namerec = NULL;
1079 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1082 * We want to just add the name, as we now know the original owner
1083 * didn't want it. But we can't just do that as an arbitrary
1084 * amount of time may have taken place between the name query
1085 * request and this timeout/error response. So we check that
1086 * the name still exists and is in the same state - if so
1087 * we remove it and call wins_process_name_registration_request()
1088 * as we know it will do the right thing now.
1091 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1093 if ((namerec != NULL) && (namerec->data.source == REGISTER_NAME) &&
1094 ip_equal_v4(rrec->packet->ip, *namerec->data.ip)) {
1095 remove_name_from_namelist( subrec, namerec);
1096 namerec = NULL;
1099 if(namerec == NULL) {
1100 wins_process_name_registration_request(subrec, orig_reg_packet);
1101 } else {
1102 DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between "
1103 "querying for name %s in order to replace it and this reply.\n",
1104 nmb_namestr(question_name) ));
1107 orig_reg_packet->locked = False;
1108 free_packet(orig_reg_packet);
1111 /***********************************************************************
1112 Deal with a name registration request to a WINS server.
1114 Use the following pseudocode :
1116 registering_group
1119 +--------name exists
1122 | +--- existing name is group
1123 | | |
1124 | | |
1125 | | +--- add name (return).
1128 | +--- exiting name is unique
1131 | +--- query existing owner (return).
1134 +--------name doesn't exist
1137 +--- add name (return).
1139 registering_unique
1142 +--------name exists
1145 | +--- existing name is group
1146 | | |
1147 | | |
1148 | | +--- fail add (return).
1149 | |
1151 | +--- exiting name is unique
1154 | +--- query existing owner (return).
1157 +--------name doesn't exist
1160 +--- add name (return).
1162 As can be seen from the above, the two cases may be collapsed onto each
1163 other with the exception of the case where the name already exists and
1164 is a group name. This case we handle with an if statement.
1166 ************************************************************************/
1168 void wins_process_name_registration_request(struct subnet_record *subrec,
1169 struct packet_struct *p)
1171 unstring name;
1172 struct nmb_packet *nmb = &p->packet.nmb;
1173 struct nmb_name *question = &nmb->question.question_name;
1174 bool bcast = nmb->header.nm_flags.bcast;
1175 uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
1176 int ttl = get_ttl_from_packet(nmb);
1177 struct name_record *namerec = NULL;
1178 struct in_addr from_ip;
1179 bool registering_group_name = (nb_flags & NB_GROUP) ? True : False;
1180 struct in_addr our_fake_ip;
1182 our_fake_ip = interpret_addr2("0.0.0.0");
1183 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1185 if(bcast) {
1187 * We should only get unicast name registration packets here.
1188 * Anyone trying to register broadcast should not be going to a WINS
1189 * server. Log an error here.
1192 DEBUG(0,("wins_process_name_registration_request: broadcast name registration request \
1193 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1194 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1195 return;
1198 DEBUG(3,("wins_process_name_registration_request: %s name registration for name %s \
1199 IP %s\n", registering_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
1202 * See if the name already exists.
1205 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1208 * if the record exists but NOT in active state,
1209 * consider it dead.
1211 if ( (namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1212 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1213 not active - removing it.\n", nmb_namestr(question) ));
1214 remove_name_from_namelist( subrec, namerec );
1215 namerec = NULL;
1219 * Deal with the case where the name found was a dns entry.
1220 * Remove it as we now have a NetBIOS client registering the
1221 * name.
1224 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1225 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1226 a dns lookup - removing it.\n", nmb_namestr(question) ));
1227 remove_name_from_namelist( subrec, namerec );
1228 namerec = NULL;
1232 * Reject if the name exists and is not a REGISTER_NAME.
1233 * (ie. Don't allow any static names to be overwritten.
1236 if((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) {
1237 DEBUG( 3, ( "wins_process_name_registration_request: Attempt \
1238 to register name %s. Name already exists in WINS with source type %d.\n",
1239 nmb_namestr(question), namerec->data.source ));
1240 send_wins_name_registration_response(RFS_ERR, 0, p);
1241 return;
1245 * Special policy decisions based on MS documentation.
1246 * 1). All group names (except names ending in 0x1c) are added as 255.255.255.255.
1247 * 2). All unique names ending in 0x1d are ignored, although a positive response is sent.
1251 * A group name is always added as the local broadcast address, except
1252 * for group names ending in 0x1c.
1253 * Group names with type 0x1c are registered with individual IP addresses.
1256 if(registering_group_name && (question->name_type != 0x1c)) {
1257 from_ip = interpret_addr2("255.255.255.255");
1261 * Ignore all attempts to register a unique 0x1d name, although return success.
1264 if(!registering_group_name && (question->name_type == 0x1d)) {
1265 DEBUG(3,("wins_process_name_registration_request: Ignoring request \
1266 to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
1267 send_wins_name_registration_response(0, ttl, p);
1268 return;
1272 * Next two cases are the 'if statement' mentioned above.
1275 if((namerec != NULL) && NAME_GROUP(namerec)) {
1276 if(registering_group_name) {
1278 * If we are adding a group name, the name exists and is also a group entry just add this
1279 * IP address to it and update the ttl.
1282 DEBUG(3,("wins_process_name_registration_request: Adding IP %s to group name %s.\n",
1283 inet_ntoa(from_ip), nmb_namestr(question) ));
1286 * Check the ip address is not already in the group.
1289 if(!find_ip_in_name_record(namerec, from_ip)) {
1291 * Need to emulate the behaviour of Windows, as
1292 * described in:
1293 * http://lists.samba.org/archive/samba-technical/2001-October/016236.html
1294 * (is there an MS reference for this
1295 * somewhere?) because if the 1c list gets over
1296 * 86 entries, the reply packet is too big
1297 * (rdata>576 bytes) so no reply is sent.
1299 * Keep only the "latest" 25 records, while
1300 * ensuring that the PDC (0x1b) is never removed
1301 * We do this by removing the first entry that
1302 * isn't the 1b entry for the same name,
1303 * on the grounds that insertion is at the end
1304 * of the list, so the oldest entries are at
1305 * the start.
1308 while(namerec->data.num_ips>=25) {
1309 struct name_record *name1brec = NULL;
1311 /* We only do this for 1c types. */
1312 if (namerec->name.name_type != 0x1c) {
1313 break;
1315 DEBUG(3,("wins_process_name_registration_request: "
1316 "More than 25 IPs already in "
1317 "the list. Looking for a 1b "
1318 "record\n"));
1320 /* Ensure we have all the active 1b
1321 * names on the list. */
1322 wins_delete_all_1b_in_memory_records();
1323 fetch_all_active_wins_1b_names();
1325 /* Per the above, find the 1b record,
1326 and then remove the first IP that isn't the same */
1327 for(name1brec = subrec->namelist;
1328 name1brec;
1329 name1brec = name1brec->next ) {
1330 if( WINS_STATE_ACTIVE(name1brec) &&
1331 name1brec->name.name_type == 0x1b) {
1332 DEBUG(3,("wins_process_name_registration_request: "
1333 "Found the #1b record "
1334 "with ip %s\n",
1335 inet_ntoa(name1brec->data.ip[0])));
1336 break;
1339 if(!name1brec) {
1340 DEBUG(3,("wins_process_name_registration_request: "
1341 "Didn't find a #1b name record. "
1342 "Removing the first available "
1343 "entry %s\n",
1344 inet_ntoa(namerec->data.ip[0])));
1345 remove_ip_from_name_record(namerec, namerec->data.ip[0]);
1346 wins_hook("delete", namerec, 0);
1347 } else {
1348 int i;
1349 for(i=0; i<namerec->data.num_ips; i++) {
1350 /* The name1brec should only have
1351 * the single IP address in it,
1352 * so we only check against the first one*/
1353 if(!ip_equal_v4( namerec->data.ip[i], name1brec->data.ip[0])) {
1354 /* The i'th entry isn't the 1b address; delete it */
1355 DEBUG(3,("wins_process_name_registration_request: "
1356 "Entry at %d is not the #1b address. "
1357 "About to remove it\n",
1358 i));
1359 remove_ip_from_name_record(namerec, namerec->data.ip[i]);
1360 wins_hook("delete", namerec, 0);
1361 break;
1366 /* The list is guaranteed to be < 25 entries now
1367 * - safe to add a new one */
1368 add_ip_to_name_record(namerec, from_ip);
1369 /* we need to update the record for replication */
1370 get_global_id_and_update(&namerec->data.id, True);
1373 * if the record is a replica, we must change
1374 * the wins owner to us to make the replication updates
1375 * it on the other wins servers.
1376 * And when the partner will receive this record,
1377 * it will update its own record.
1380 update_wins_owner(namerec, our_fake_ip);
1382 update_name_ttl(namerec, ttl);
1383 wins_hook("refresh", namerec, ttl);
1384 send_wins_name_registration_response(0, ttl, p);
1385 return;
1386 } else {
1389 * If we are adding a unique name, the name exists in the WINS db
1390 * and is a group name then reject the registration.
1392 * explanation: groups have a higher priority than unique names.
1395 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1396 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1397 send_wins_name_registration_response(RFS_ERR, 0, p);
1398 return;
1403 * From here on down we know that if the name exists in the WINS db it is
1404 * a unique name, not a group name.
1408 * If the name exists and is one of our names then check the
1409 * registering IP address. If it's not one of ours then automatically
1410 * reject without doing the query - we know we will reject it.
1413 if ( namerec != NULL ) {
1414 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
1415 if( is_myname(name) ) {
1416 if(!ismyip_v4(from_ip)) {
1417 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1418 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1419 send_wins_name_registration_response(RFS_ERR, 0, p);
1420 return;
1421 } else {
1423 * It's one of our names and one of our IP's - update the ttl.
1425 update_name_ttl(namerec, ttl);
1426 wins_hook("refresh", namerec, ttl);
1427 send_wins_name_registration_response(0, ttl, p);
1428 return;
1431 } else {
1432 name[0] = '\0';
1436 * If the name exists and it is a unique registration and the registering IP
1437 * is the same as the (single) already registered IP then just update the ttl.
1439 * But not if the record is an active replica. IF it's a replica, it means it can be
1440 * the same client which has moved and not yet expired. So we don't update
1441 * the ttl in this case and go beyond to do a WACK and query the old client
1444 if( !registering_group_name
1445 && (namerec != NULL)
1446 && (namerec->data.num_ips == 1)
1447 && ip_equal_v4( namerec->data.ip[0], from_ip )
1448 && ip_equal_v4(namerec->data.wins_ip, our_fake_ip) ) {
1449 update_name_ttl( namerec, ttl );
1450 wins_hook("refresh", namerec, ttl);
1451 send_wins_name_registration_response( 0, ttl, p );
1452 return;
1456 * Finally if the name exists do a query to the registering machine
1457 * to see if they still claim to have the name.
1460 if( namerec != NULL ) {
1461 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1462 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1465 * First send a WACK to the registering machine.
1468 send_wins_wack_response(60, p);
1471 * When the reply comes back we need the original packet.
1472 * Lock this so it won't be freed and then put it into
1473 * the userdata structure.
1476 p->locked = True;
1478 userdata = (struct userdata_struct *)ud;
1480 userdata->copy_fn = NULL;
1481 userdata->free_fn = NULL;
1482 userdata->userdata_len = sizeof(struct packet_struct *);
1483 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1486 * Use the new call to send a query directly to an IP address.
1487 * This sends the query directly to the IP address, and ensures
1488 * the recursion desired flag is not set (you were right Luke :-).
1489 * This function should *only* be called from the WINS server
1490 * code. JRA.
1493 pull_ascii_nstring(name, sizeof(name), question->name);
1494 query_name_from_wins_server( *namerec->data.ip,
1495 name,
1496 question->name_type,
1497 wins_register_query_success,
1498 wins_register_query_fail,
1499 userdata );
1500 return;
1504 * Name did not exist - add it.
1507 pull_ascii_nstring(name, sizeof(name), question->name);
1508 add_name_to_subnet( subrec, name, question->name_type,
1509 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1511 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1512 get_global_id_and_update(&namerec->data.id, True);
1513 update_wins_owner(namerec, our_fake_ip);
1514 update_wins_flag(namerec, WINS_ACTIVE);
1515 wins_hook("add", namerec, ttl);
1518 send_wins_name_registration_response(0, ttl, p);
1521 /***********************************************************************
1522 Deal with a mutihomed name query success to the machine that
1523 requested the multihomed name registration.
1525 We have a locked pointer to the original packet stashed away in the
1526 userdata pointer.
1527 ************************************************************************/
1529 static void wins_multihomed_register_query_success(struct subnet_record *subrec,
1530 struct userdata_struct *userdata,
1531 struct nmb_name *question_name,
1532 struct in_addr ip,
1533 struct res_rec *answers)
1535 struct packet_struct *orig_reg_packet;
1536 struct nmb_packet *nmb;
1537 struct name_record *namerec = NULL;
1538 struct in_addr from_ip;
1539 int ttl;
1540 struct in_addr our_fake_ip;
1542 our_fake_ip = interpret_addr2("0.0.0.0");
1543 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1545 nmb = &orig_reg_packet->packet.nmb;
1547 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1548 ttl = get_ttl_from_packet(nmb);
1551 * We want to just add the new IP, as we now know the requesting
1552 * machine claims to own it. But we can't just do that as an arbitrary
1553 * amount of time may have taken place between the name query
1554 * request and this response. So we check that
1555 * the name still exists and is in the same state - if so
1556 * we just add the extra IP and update the ttl.
1559 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1561 if( (namerec == NULL) || (namerec->data.source != REGISTER_NAME) || !WINS_STATE_ACTIVE(namerec) ) {
1562 DEBUG(3,("wins_multihomed_register_query_success: name %s is not in the correct state to add \
1563 a subsequent IP address.\n", nmb_namestr(question_name) ));
1564 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1566 orig_reg_packet->locked = False;
1567 free_packet(orig_reg_packet);
1569 return;
1572 if(!find_ip_in_name_record(namerec, from_ip)) {
1573 add_ip_to_name_record(namerec, from_ip);
1576 get_global_id_and_update(&namerec->data.id, True);
1577 update_wins_owner(namerec, our_fake_ip);
1578 update_wins_flag(namerec, WINS_ACTIVE);
1579 update_name_ttl(namerec, ttl);
1580 wins_hook("add", namerec, ttl);
1581 send_wins_name_registration_response(0, ttl, orig_reg_packet);
1583 orig_reg_packet->locked = False;
1584 free_packet(orig_reg_packet);
1587 /***********************************************************************
1588 Deal with a name registration request query failure to a client that
1589 owned the name.
1591 We have a locked pointer to the original packet stashed away in the
1592 userdata pointer.
1593 ************************************************************************/
1595 static void wins_multihomed_register_query_fail(struct subnet_record *subrec,
1596 struct response_record *rrec,
1597 struct nmb_name *question_name,
1598 int rcode)
1600 struct userdata_struct *userdata = rrec->userdata;
1601 struct packet_struct *orig_reg_packet;
1603 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1605 DEBUG(3,("wins_multihomed_register_query_fail: Registering machine at IP %s failed to answer \
1606 query successfully for name %s.\n", inet_ntoa(orig_reg_packet->ip), nmb_namestr(question_name) ));
1607 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1609 orig_reg_packet->locked = False;
1610 free_packet(orig_reg_packet);
1611 return;
1614 /***********************************************************************
1615 Deal with a multihomed name registration request to a WINS server.
1616 These cannot be group name registrations.
1617 ***********************************************************************/
1619 void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
1620 struct packet_struct *p)
1622 struct nmb_packet *nmb = &p->packet.nmb;
1623 struct nmb_name *question = &nmb->question.question_name;
1624 bool bcast = nmb->header.nm_flags.bcast;
1625 uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
1626 int ttl = get_ttl_from_packet(nmb);
1627 struct name_record *namerec = NULL;
1628 struct in_addr from_ip;
1629 bool group = (nb_flags & NB_GROUP) ? True : False;
1630 struct in_addr our_fake_ip;
1631 unstring qname;
1633 our_fake_ip = interpret_addr2("0.0.0.0");
1634 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1636 if(bcast) {
1638 * We should only get unicast name registration packets here.
1639 * Anyone trying to register broadcast should not be going to a WINS
1640 * server. Log an error here.
1643 DEBUG(0,("wins_process_multihomed_name_registration_request: broadcast name registration request \
1644 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1645 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1646 return;
1650 * Only unique names should be registered multihomed.
1653 if(group) {
1654 DEBUG(0,("wins_process_multihomed_name_registration_request: group name registration request \
1655 received for name %s from IP %s on subnet %s. Error - group names should not be multihomed.\n",
1656 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1657 return;
1660 DEBUG(3,("wins_process_multihomed_name_registration_request: name registration for name %s \
1661 IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ));
1664 * Deal with policy regarding 0x1d names.
1667 if(question->name_type == 0x1d) {
1668 DEBUG(3,("wins_process_multihomed_name_registration_request: Ignoring request \
1669 to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
1670 send_wins_name_registration_response(0, ttl, p);
1671 return;
1675 * See if the name already exists.
1678 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1681 * if the record exists but NOT in active state,
1682 * consider it dead.
1685 if ((namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1686 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was not active - removing it.\n", nmb_namestr(question)));
1687 remove_name_from_namelist(subrec, namerec);
1688 namerec = NULL;
1692 * Deal with the case where the name found was a dns entry.
1693 * Remove it as we now have a NetBIOS client registering the
1694 * name.
1697 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1698 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was a dns lookup \
1699 - removing it.\n", nmb_namestr(question) ));
1700 remove_name_from_namelist( subrec, namerec);
1701 namerec = NULL;
1705 * Reject if the name exists and is not a REGISTER_NAME.
1706 * (ie. Don't allow any static names to be overwritten.
1709 if( (namerec != NULL) && (namerec->data.source != REGISTER_NAME) ) {
1710 DEBUG( 3, ( "wins_process_multihomed_name_registration_request: Attempt \
1711 to register name %s. Name already exists in WINS with source type %d.\n",
1712 nmb_namestr(question), namerec->data.source ));
1713 send_wins_name_registration_response(RFS_ERR, 0, p);
1714 return;
1718 * Reject if the name exists and is a GROUP name and is active.
1721 if((namerec != NULL) && NAME_GROUP(namerec) && WINS_STATE_ACTIVE(namerec)) {
1722 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1723 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1724 send_wins_name_registration_response(RFS_ERR, 0, p);
1725 return;
1729 * From here on down we know that if the name exists in the WINS db it is
1730 * a unique name, not a group name.
1734 * If the name exists and is one of our names then check the
1735 * registering IP address. If it's not one of ours then automatically
1736 * reject without doing the query - we know we will reject it.
1739 if((namerec != NULL) && (is_myname(namerec->name.name)) ) {
1740 if(!ismyip_v4(from_ip)) {
1741 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1742 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1743 send_wins_name_registration_response(RFS_ERR, 0, p);
1744 return;
1745 } else {
1747 * It's one of our names and one of our IP's. Ensure the IP is in the record and
1748 * update the ttl. Update the version ID to force replication.
1750 update_name_ttl(namerec, ttl);
1752 if(!find_ip_in_name_record(namerec, from_ip)) {
1753 get_global_id_and_update(&namerec->data.id, True);
1754 update_wins_owner(namerec, our_fake_ip);
1755 update_wins_flag(namerec, WINS_ACTIVE);
1757 add_ip_to_name_record(namerec, from_ip);
1760 wins_hook("refresh", namerec, ttl);
1761 send_wins_name_registration_response(0, ttl, p);
1762 return;
1767 * If the name exists and is active, check if the IP address is already registered
1768 * to that name. If so then update the ttl and reply success.
1771 if((namerec != NULL) && find_ip_in_name_record(namerec, from_ip) && WINS_STATE_ACTIVE(namerec)) {
1772 update_name_ttl(namerec, ttl);
1775 * If it's a replica, we need to become the wins owner
1776 * to force the replication
1778 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
1779 get_global_id_and_update(&namerec->data.id, True);
1780 update_wins_owner(namerec, our_fake_ip);
1781 update_wins_flag(namerec, WINS_ACTIVE);
1784 wins_hook("refresh", namerec, ttl);
1785 send_wins_name_registration_response(0, ttl, p);
1786 return;
1790 * If the name exists do a query to the owner
1791 * to see if they still want the name.
1794 if(namerec != NULL) {
1795 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1796 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1799 * First send a WACK to the registering machine.
1802 send_wins_wack_response(60, p);
1805 * When the reply comes back we need the original packet.
1806 * Lock this so it won't be freed and then put it into
1807 * the userdata structure.
1810 p->locked = True;
1812 userdata = (struct userdata_struct *)ud;
1814 userdata->copy_fn = NULL;
1815 userdata->free_fn = NULL;
1816 userdata->userdata_len = sizeof(struct packet_struct *);
1817 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1820 * Use the new call to send a query directly to an IP address.
1821 * This sends the query directly to the IP address, and ensures
1822 * the recursion desired flag is not set (you were right Luke :-).
1823 * This function should *only* be called from the WINS server
1824 * code. JRA.
1826 * Note that this packet is sent to the current owner of the name,
1827 * not the person who sent the packet
1830 pull_ascii_nstring( qname, sizeof(qname), question->name);
1831 query_name_from_wins_server( namerec->data.ip[0],
1832 qname,
1833 question->name_type,
1834 wins_multihomed_register_query_success,
1835 wins_multihomed_register_query_fail,
1836 userdata );
1838 return;
1842 * Name did not exist - add it.
1845 pull_ascii_nstring( qname, sizeof(qname), question->name);
1846 add_name_to_subnet( subrec, qname, question->name_type,
1847 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1849 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1850 get_global_id_and_update(&namerec->data.id, True);
1851 update_wins_owner(namerec, our_fake_ip);
1852 update_wins_flag(namerec, WINS_ACTIVE);
1853 wins_hook("add", namerec, ttl);
1856 send_wins_name_registration_response(0, ttl, p);
1859 /***********************************************************************
1860 Fetch all *<1b> names from the WINS db and store on the namelist.
1861 ***********************************************************************/
1863 static int fetch_1b_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
1865 struct name_record *namerec = NULL;
1867 if (kbuf.dsize != sizeof(unstring) + 1) {
1868 return 0;
1871 /* Filter out all non-1b names. */
1872 if (kbuf.dptr[sizeof(unstring)] != 0x1b) {
1873 return 0;
1876 namerec = wins_record_to_name_record(kbuf, dbuf);
1877 if (!namerec) {
1878 return 0;
1881 DLIST_ADD(wins_server_subnet->namelist, namerec);
1882 return 0;
1885 void fetch_all_active_wins_1b_names(void)
1887 tdb_traverse(wins_tdb, fetch_1b_traverse_fn, NULL);
1890 /***********************************************************************
1891 Deal with the special name query for *<1b>.
1892 ***********************************************************************/
1894 static void process_wins_dmb_query_request(struct subnet_record *subrec,
1895 struct packet_struct *p)
1897 struct name_record *namerec = NULL;
1898 char *prdata;
1899 int num_ips;
1902 * Go through all the ACTIVE names in the WINS db looking for those
1903 * ending in <1b>. Use this to calculate the number of IP
1904 * addresses we need to return.
1907 num_ips = 0;
1909 /* First, clear the in memory list - we're going to re-populate
1910 it with the tdb_traversal in fetch_all_active_wins_1b_names. */
1912 wins_delete_all_tmp_in_memory_records();
1914 fetch_all_active_wins_1b_names();
1916 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1917 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1918 num_ips += namerec->data.num_ips;
1922 if(num_ips == 0) {
1924 * There are no 0x1b names registered. Return name query fail.
1926 send_wins_name_query_response(NAM_ERR, p, NULL);
1927 return;
1930 if((prdata = (char *)SMB_MALLOC( num_ips * 6 )) == NULL) {
1931 DEBUG(0,("process_wins_dmb_query_request: Malloc fail !.\n"));
1932 return;
1936 * Go through all the names again in the WINS db looking for those
1937 * ending in <1b>. Add their IP addresses into the list we will
1938 * return.
1941 num_ips = 0;
1942 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1943 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1944 int i;
1945 for(i = 0; i < namerec->data.num_ips; i++) {
1946 set_nb_flags(&prdata[num_ips * 6],namerec->data.nb_flags);
1947 putip((char *)&prdata[(num_ips * 6) + 2], &namerec->data.ip[i]);
1948 num_ips++;
1954 * Send back the reply containing the IP list.
1957 reply_netbios_packet(p, /* Packet to reply to. */
1958 0, /* Result code. */
1959 WINS_QUERY, /* nmbd type code. */
1960 NMB_NAME_QUERY_OPCODE, /* opcode. */
1961 lp_min_wins_ttl(), /* ttl. */
1962 prdata, /* data to send. */
1963 num_ips*6); /* data length. */
1965 SAFE_FREE(prdata);
1968 /****************************************************************************
1969 Send a WINS name query response.
1970 **************************************************************************/
1972 void send_wins_name_query_response(int rcode, struct packet_struct *p,
1973 struct name_record *namerec)
1975 char rdata[6];
1976 char *prdata = rdata;
1977 int reply_data_len = 0;
1978 int ttl = 0;
1979 int i;
1981 memset(rdata,'\0',6);
1983 if(rcode == 0) {
1985 int ip_count;
1987 ttl = (namerec->data.death_time != PERMANENT_TTL) ? namerec->data.death_time - p->timestamp : lp_max_wins_ttl();
1989 /* The netbios reply packet data section is limited to 576 bytes. In theory
1990 * this should give us space for 96 addresses, but in practice, 86 appears
1991 * to be the max (don't know why). If we send any more than that,
1992 * reply_netbios_packet will fail to send a reply to avoid a memcpy buffer
1993 * overflow. Keep the count to 85 and it will be ok */
1994 ip_count=namerec->data.num_ips;
1995 if(ip_count>85) {
1996 ip_count=85;
1999 /* Copy all known ip addresses into the return data. */
2000 /* Optimise for the common case of one IP address so we don't need a malloc. */
2002 if( ip_count == 1 ) {
2003 prdata = rdata;
2004 } else {
2005 if((prdata = (char *)SMB_MALLOC( ip_count * 6 )) == NULL) {
2006 DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
2007 return;
2011 for(i = 0; i < ip_count; i++) {
2012 set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
2013 putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
2016 sort_query_replies(prdata, i, p->ip);
2017 reply_data_len = ip_count * 6;
2020 reply_netbios_packet(p, /* Packet to reply to. */
2021 rcode, /* Result code. */
2022 WINS_QUERY, /* nmbd type code. */
2023 NMB_NAME_QUERY_OPCODE, /* opcode. */
2024 ttl, /* ttl. */
2025 prdata, /* data to send. */
2026 reply_data_len); /* data length. */
2028 if(prdata != rdata) {
2029 SAFE_FREE(prdata);
2033 /***********************************************************************
2034 Deal with a name query.
2035 ***********************************************************************/
2037 void wins_process_name_query_request(struct subnet_record *subrec,
2038 struct packet_struct *p)
2040 struct nmb_packet *nmb = &p->packet.nmb;
2041 struct nmb_name *question = &nmb->question.question_name;
2042 struct name_record *namerec = NULL;
2043 unstring qname;
2045 DEBUG(3,("wins_process_name_query: name query for name %s from IP %s\n",
2046 nmb_namestr(question), inet_ntoa(p->ip) ));
2049 * Special name code. If the queried name is *<1b> then search
2050 * the entire WINS database and return a list of all the IP addresses
2051 * registered to any <1b> name. This is to allow domain master browsers
2052 * to discover other domains that may not have a presence on their subnet.
2055 pull_ascii_nstring(qname, sizeof(qname), question->name);
2056 if(strequal( qname, "*") && (question->name_type == 0x1b)) {
2057 process_wins_dmb_query_request( subrec, p);
2058 return;
2061 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2063 if(namerec != NULL) {
2065 * If the name is not anymore in active state then reply not found.
2066 * it's fair even if we keep it in the cache for days.
2068 if (!WINS_STATE_ACTIVE(namerec)) {
2069 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
2070 nmb_namestr(question) ));
2071 send_wins_name_query_response(NAM_ERR, p, namerec);
2072 return;
2076 * If it's a DNSFAIL_NAME then reply name not found.
2079 if( namerec->data.source == DNSFAIL_NAME ) {
2080 DEBUG(3,("wins_process_name_query: name query for name %s returning DNS fail.\n",
2081 nmb_namestr(question) ));
2082 send_wins_name_query_response(NAM_ERR, p, namerec);
2083 return;
2087 * If the name has expired then reply name not found.
2090 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < p->timestamp) ) {
2091 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
2092 nmb_namestr(question) ));
2093 send_wins_name_query_response(NAM_ERR, p, namerec);
2094 return;
2097 DEBUG(3,("wins_process_name_query: name query for name %s returning first IP %s.\n",
2098 nmb_namestr(question), inet_ntoa(namerec->data.ip[0]) ));
2100 send_wins_name_query_response(0, p, namerec);
2101 return;
2105 * Name not found in WINS - try a dns query if it's a 0x20 name.
2108 if(lp_wins_dns_proxy() && ((question->name_type == 0x20) || question->name_type == 0)) {
2109 DEBUG(3,("wins_process_name_query: name query for name %s not found - doing dns lookup.\n",
2110 nmb_namestr(question) ));
2112 queue_dns_query(p, question);
2113 return;
2117 * Name not found - return error.
2120 send_wins_name_query_response(NAM_ERR, p, NULL);
2123 /****************************************************************************
2124 Send a WINS name release response.
2125 **************************************************************************/
2127 static void send_wins_name_release_response(int rcode, struct packet_struct *p)
2129 struct nmb_packet *nmb = &p->packet.nmb;
2130 char rdata[6];
2132 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
2134 reply_netbios_packet(p, /* Packet to reply to. */
2135 rcode, /* Result code. */
2136 NMB_REL, /* nmbd type code. */
2137 NMB_NAME_RELEASE_OPCODE, /* opcode. */
2138 0, /* ttl. */
2139 rdata, /* data to send. */
2140 6); /* data length. */
2143 /***********************************************************************
2144 Deal with a name release.
2145 ***********************************************************************/
2147 void wins_process_name_release_request(struct subnet_record *subrec,
2148 struct packet_struct *p)
2150 struct nmb_packet *nmb = &p->packet.nmb;
2151 struct nmb_name *question = &nmb->question.question_name;
2152 bool bcast = nmb->header.nm_flags.bcast;
2153 uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
2154 struct name_record *namerec = NULL;
2155 struct in_addr from_ip;
2156 bool releasing_group_name = (nb_flags & NB_GROUP) ? True : False;
2158 putip((char *)&from_ip,&nmb->additional->rdata[2]);
2160 if(bcast) {
2162 * We should only get unicast name registration packets here.
2163 * Anyone trying to register broadcast should not be going to a WINS
2164 * server. Log an error here.
2167 DEBUG(0,("wins_process_name_release_request: broadcast name registration request \
2168 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
2169 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
2170 return;
2173 DEBUG(3,("wins_process_name_release_request: %s name release for name %s \
2174 IP %s\n", releasing_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
2177 * Deal with policy regarding 0x1d names.
2180 if(!releasing_group_name && (question->name_type == 0x1d)) {
2181 DEBUG(3,("wins_process_name_release_request: Ignoring request \
2182 to release name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
2183 send_wins_name_release_response(0, p);
2184 return;
2188 * See if the name already exists.
2191 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2193 if( (namerec == NULL) || ((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) ) {
2194 send_wins_name_release_response(NAM_ERR, p);
2195 return;
2199 * Check that the sending machine has permission to release this name.
2200 * If it's a group name not ending in 0x1c then just say yes and let
2201 * the group time out.
2204 if(releasing_group_name && (question->name_type != 0x1c)) {
2205 send_wins_name_release_response(0, p);
2206 return;
2210 * Check that the releasing node is on the list of IP addresses
2211 * for this name. Disallow the release if not.
2214 if(!find_ip_in_name_record(namerec, from_ip)) {
2215 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2216 release name %s as IP %s is not one of the known IP's for this name.\n",
2217 nmb_namestr(question), inet_ntoa(from_ip) ));
2218 send_wins_name_release_response(NAM_ERR, p);
2219 return;
2223 * Check if the record is active. IF it's already released
2224 * or tombstoned, refuse the release.
2227 if (!WINS_STATE_ACTIVE(namerec)) {
2228 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2229 release name %s as this record is not active anymore.\n", nmb_namestr(question) ));
2230 send_wins_name_release_response(NAM_ERR, p);
2231 return;
2235 * Check if the record is a 0x1c group
2236 * and has more then one ip
2237 * remove only this address.
2240 if(releasing_group_name && (question->name_type == 0x1c) && (namerec->data.num_ips > 1)) {
2241 remove_ip_from_name_record(namerec, from_ip);
2242 DEBUG(3,("wins_process_name_release_request: Remove IP %s from NAME: %s\n",
2243 inet_ntoa(from_ip),nmb_namestr(question)));
2244 wins_hook("delete", namerec, 0);
2245 send_wins_name_release_response(0, p);
2246 return;
2250 * Send a release response.
2251 * Flag the name as released and update the ttl
2254 namerec->data.wins_flags |= WINS_RELEASED;
2255 update_name_ttl(namerec, EXTINCTION_INTERVAL);
2257 wins_hook("delete", namerec, 0);
2258 send_wins_name_release_response(0, p);
2261 /*******************************************************************
2262 WINS time dependent processing.
2263 ******************************************************************/
2265 static int wins_processing_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2267 time_t t = *(time_t *)state;
2268 bool store_record = False;
2269 struct name_record *namerec = NULL;
2270 struct in_addr our_fake_ip;
2272 our_fake_ip = interpret_addr2("0.0.0.0");
2273 if (kbuf.dsize != sizeof(unstring) + 1) {
2274 return 0;
2277 namerec = wins_record_to_name_record(kbuf, dbuf);
2278 if (!namerec) {
2279 return 0;
2282 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
2283 if( namerec->data.source == SELF_NAME ) {
2284 DEBUG( 3, ( "wins_processing_traverse_fn: Subnet %s not expiring SELF name %s\n",
2285 wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) );
2286 namerec->data.death_time += 300;
2287 store_record = True;
2288 goto done;
2289 } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) {
2290 DEBUG(3,("wins_processing_traverse_fn: deleting timed out DNS name %s\n",
2291 nmb_namestr(&namerec->name)));
2292 remove_name_from_wins_namelist(namerec );
2293 goto done;
2296 /* handle records, samba is the wins owner */
2297 if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
2298 switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2299 case WINS_ACTIVE:
2300 namerec->data.wins_flags&=~WINS_STATE_MASK;
2301 namerec->data.wins_flags|=WINS_RELEASED;
2302 namerec->data.death_time = t + EXTINCTION_INTERVAL;
2303 DEBUG(3,("wins_processing_traverse_fn: expiring %s\n",
2304 nmb_namestr(&namerec->name)));
2305 store_record = True;
2306 goto done;
2307 case WINS_RELEASED:
2308 namerec->data.wins_flags&=~WINS_STATE_MASK;
2309 namerec->data.wins_flags|=WINS_TOMBSTONED;
2310 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2311 get_global_id_and_update(&namerec->data.id, True);
2312 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2313 nmb_namestr(&namerec->name)));
2314 store_record = True;
2315 goto done;
2316 case WINS_TOMBSTONED:
2317 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2318 nmb_namestr(&namerec->name)));
2319 remove_name_from_wins_namelist(namerec );
2320 goto done;
2322 } else {
2323 switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2324 case WINS_ACTIVE:
2325 /* that's not as MS says it should be */
2326 namerec->data.wins_flags&=~WINS_STATE_MASK;
2327 namerec->data.wins_flags|=WINS_TOMBSTONED;
2328 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2329 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2330 nmb_namestr(&namerec->name)));
2331 store_record = True;
2332 goto done;
2333 case WINS_TOMBSTONED:
2334 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2335 nmb_namestr(&namerec->name)));
2336 remove_name_from_wins_namelist(namerec );
2337 goto done;
2338 case WINS_RELEASED:
2339 DEBUG(0,("wins_processing_traverse_fn: %s is in released state and\
2340 we are not the wins owner !\n", nmb_namestr(&namerec->name)));
2341 goto done;
2346 done:
2348 if (store_record) {
2349 wins_store_changed_namerec(namerec);
2352 SAFE_FREE(namerec->data.ip);
2353 SAFE_FREE(namerec);
2355 return 0;
2358 /*******************************************************************
2359 Time dependent wins processing.
2360 ******************************************************************/
2362 void initiate_wins_processing(time_t t)
2364 static time_t lasttime = 0;
2366 if (!lasttime) {
2367 lasttime = t;
2369 if (t - lasttime < 20) {
2370 return;
2373 if(!lp_we_are_a_wins_server()) {
2374 lasttime = t;
2375 return;
2378 tdb_traverse(wins_tdb, wins_processing_traverse_fn, &t);
2380 wins_delete_all_tmp_in_memory_records();
2382 wins_write_database(t, True);
2384 lasttime = t;
2387 /*******************************************************************
2388 Write out one record.
2389 ******************************************************************/
2391 void wins_write_name_record(struct name_record *namerec, FILE *fp)
2393 int i;
2394 struct tm *tm;
2396 DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) ));
2398 if( namerec->data.death_time != PERMANENT_TTL ) {
2399 char *ts, *nl;
2401 tm = localtime(&namerec->data.death_time);
2402 if (!tm) {
2403 return;
2405 ts = asctime(tm);
2406 if (!ts) {
2407 return;
2409 nl = strrchr( ts, '\n' );
2410 if( NULL != nl ) {
2411 *nl = '\0';
2413 DEBUGADD(4,("TTL = %s ", ts ));
2414 } else {
2415 DEBUGADD(4,("TTL = PERMANENT "));
2418 for (i = 0; i < namerec->data.num_ips; i++) {
2419 DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) ));
2421 DEBUGADD(4,("%2x\n", namerec->data.nb_flags ));
2423 if( namerec->data.source == REGISTER_NAME ) {
2424 unstring name;
2425 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
2426 fprintf(fp, "\"%s#%02x\" %d ", name,
2427 namerec->name.name_type, /* Ignore scope. */
2428 (int)namerec->data.death_time);
2430 for (i = 0; i < namerec->data.num_ips; i++)
2431 fprintf(fp, "%s ", inet_ntoa(namerec->data.ip[i]));
2432 fprintf(fp, "%2xR\n", namerec->data.nb_flags);
2436 /*******************************************************************
2437 Write out the current WINS database.
2438 ******************************************************************/
2440 static int wins_writedb_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2442 struct name_record *namerec = NULL;
2443 FILE *fp = (FILE *)state;
2445 if (kbuf.dsize != sizeof(unstring) + 1) {
2446 return 0;
2449 namerec = wins_record_to_name_record(kbuf, dbuf);
2450 if (!namerec) {
2451 return 0;
2454 wins_write_name_record(namerec, fp);
2456 SAFE_FREE(namerec->data.ip);
2457 SAFE_FREE(namerec);
2458 return 0;
2462 void wins_write_database(time_t t, bool background)
2464 static time_t last_write_time = 0;
2465 char *fname = NULL;
2466 char *fnamenew = NULL;
2468 int fd;
2469 FILE *fp;
2471 if (background) {
2472 if (!last_write_time) {
2473 last_write_time = t;
2475 if (t - last_write_time < 120) {
2476 return;
2481 if(!lp_we_are_a_wins_server()) {
2482 return;
2485 /* We will do the writing in a child process to ensure that the parent doesn't block while this is done */
2486 if (background) {
2487 CatchChild();
2488 if (fork()) {
2489 return;
2491 if (tdb_reopen(wins_tdb)) {
2492 DEBUG(0,("wins_write_database: tdb_reopen failed. Error was %s\n",
2493 strerror(errno)));
2494 _exit(0);
2495 return;
2499 if (!(fname = state_path(talloc_tos(), WINS_LIST))) {
2500 goto err_exit;
2502 /* This is safe as the 0 length means "don't expand". */
2503 all_string_sub(fname,"//", "/", 0);
2505 if (asprintf(&fnamenew, "%s.%u", fname, (unsigned int)getpid()) < 0) {
2506 goto err_exit;
2509 fd = open(fnamenew, O_WRONLY|O_CREAT, 0644);
2510 if (fd == -1) {
2511 DBG_ERR("Can't open %s: %s\n", fnamenew, strerror(errno));
2512 goto err_exit;
2515 fp = fdopen(fd, "w");
2516 if (fp == NULL) {
2517 DBG_ERR("fdopen failed: %s\n", strerror(errno));
2518 close(fd);
2519 goto err_exit;
2521 fd = -1;
2523 DEBUG(4,("wins_write_database: Dump of WINS name list.\n"));
2525 fprintf(fp,"VERSION %d %u\n", WINS_VERSION, 0);
2527 tdb_traverse(wins_tdb, wins_writedb_traverse_fn, fp);
2529 fclose(fp);
2530 chmod(fnamenew,0644);
2531 unlink(fname);
2532 rename(fnamenew,fname);
2534 err_exit:
2536 SAFE_FREE(fnamenew);
2537 TALLOC_FREE(fname);
2539 if (background) {
2540 _exit(0);
2544 #if 0
2545 Until winsrepl is done.
2546 /****************************************************************************
2547 Process a internal Samba message receiving a wins record.
2548 ***************************************************************************/
2550 void nmbd_wins_new_entry(struct messaging_context *msg,
2551 void *private_data,
2552 uint32_t msg_type,
2553 struct server_id server_id,
2554 DATA_BLOB *data)
2556 WINS_RECORD *record;
2557 struct name_record *namerec = NULL;
2558 struct name_record *new_namerec = NULL;
2559 struct nmb_name question;
2560 bool overwrite=False;
2561 struct in_addr our_fake_ip;
2562 int i;
2564 our_fake_ip = interpret_addr2("0.0.0.0");
2565 if (buf==NULL) {
2566 return;
2569 /* Record should use UNIX codepage. Ensure this is so in the wrepld code. JRA. */
2570 record=(WINS_RECORD *)buf;
2572 make_nmb_name(&question, record->name, record->type);
2574 namerec = find_name_on_subnet(wins_server_subnet, &question, FIND_ANY_NAME);
2576 /* record doesn't exist, add it */
2577 if (namerec == NULL) {
2578 DEBUG(3,("nmbd_wins_new_entry: adding new replicated record: %s<%02x> for wins server: %s\n",
2579 record->name, record->type, inet_ntoa(record->wins_ip)));
2581 new_namerec=add_name_to_subnet( wins_server_subnet,
2582 record->name,
2583 record->type,
2584 record->nb_flags,
2585 EXTINCTION_INTERVAL,
2586 REGISTER_NAME,
2587 record->num_ips,
2588 record->ip);
2590 if (new_namerec!=NULL) {
2591 update_wins_owner(new_namerec, record->wins_ip);
2592 update_wins_flag(new_namerec, record->wins_flags);
2593 new_namerec->data.id=record->id;
2595 wins_server_subnet->namelist_changed = True;
2599 /* check if we have a conflict */
2600 if (namerec != NULL) {
2601 /* both records are UNIQUE */
2602 if (namerec->data.wins_flags&WINS_UNIQUE && record->wins_flags&WINS_UNIQUE) {
2604 /* the database record is a replica */
2605 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
2606 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED) {
2607 if (ip_equal_v4(namerec->data.wins_ip, record->wins_ip))
2608 overwrite=True;
2609 } else
2610 overwrite=True;
2611 } else {
2612 /* we are the wins owner of the database record */
2613 /* the 2 records have the same IP address */
2614 if (ip_equal_v4(namerec->data.ip[0], record->ip[0])) {
2615 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED)
2616 get_global_id_and_update(&namerec->data.id, True);
2617 else
2618 overwrite=True;
2620 } else {
2621 /* the 2 records have different IP address */
2622 if (namerec->data.wins_flags&WINS_ACTIVE) {
2623 if (record->wins_flags&WINS_TOMBSTONED)
2624 get_global_id_and_update(&namerec->data.id, True);
2625 if (record->wins_flags&WINS_ACTIVE)
2626 /* send conflict challenge to the replica node */
2628 } else
2629 overwrite=True;
2635 /* the replica is a standard group */
2636 if (record->wins_flags&WINS_NGROUP || record->wins_flags&WINS_SGROUP) {
2637 /* if the database record is unique and active force a name release */
2638 if (namerec->data.wins_flags&WINS_UNIQUE)
2639 /* send a release name to the unique node */
2641 overwrite=True;
2645 /* the replica is a special group */
2646 if (record->wins_flags&WINS_SGROUP && namerec->data.wins_flags&WINS_SGROUP) {
2647 if (namerec->data.wins_flags&WINS_ACTIVE) {
2648 for (i=0; i<record->num_ips; i++)
2649 if(!find_ip_in_name_record(namerec, record->ip[i]))
2650 add_ip_to_name_record(namerec, record->ip[i]);
2651 } else {
2652 overwrite=True;
2656 /* the replica is a multihomed host */
2658 /* I'm giving up on multi homed. Too much complex to understand */
2660 if (record->wins_flags&WINS_MHOMED) {
2661 if (! (namerec->data.wins_flags&WINS_ACTIVE)) {
2662 if ( !(namerec->data.wins_flags&WINS_RELEASED) && !(namerec->data.wins_flags&WINS_NGROUP))
2663 overwrite=True;
2665 else {
2666 if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
2667 overwrite=True;
2669 if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip))
2670 if (namerec->data.wins_flags&WINS_UNIQUE)
2671 get_global_id_and_update(&namerec->data.id, True);
2675 if (record->wins_flags&WINS_ACTIVE && namerec->data.wins_flags&WINS_ACTIVE)
2676 if (namerec->data.wins_flags&WINS_UNIQUE ||
2677 namerec->data.wins_flags&WINS_MHOMED)
2678 if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
2679 overwrite=True;
2683 if (overwrite == False)
2684 DEBUG(3, ("nmbd_wins_new_entry: conflict in adding record: %s<%02x> from wins server: %s\n",
2685 record->name, record->type, inet_ntoa(record->wins_ip)));
2686 else {
2687 DEBUG(3, ("nmbd_wins_new_entry: replacing record: %s<%02x> from wins server: %s\n",
2688 record->name, record->type, inet_ntoa(record->wins_ip)));
2690 /* remove the old record and add a new one */
2691 remove_name_from_namelist( wins_server_subnet, namerec );
2692 new_namerec=add_name_to_subnet( wins_server_subnet, record->name, record->type, record->nb_flags,
2693 EXTINCTION_INTERVAL, REGISTER_NAME, record->num_ips, record->ip);
2694 if (new_namerec!=NULL) {
2695 update_wins_owner(new_namerec, record->wins_ip);
2696 update_wins_flag(new_namerec, record->wins_flags);
2697 new_namerec->data.id=record->id;
2699 wins_server_subnet->namelist_changed = True;
2702 wins_server_subnet->namelist_changed = True;
2707 #endif