s3-security: use shared SECINFO_SACL define.
[Samba/ekacnet.git] / source3 / nmbd / nmbd_winsserver.c
blobbe2c6a24438129d6a1fe93ed0ade91368727b31b
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"
25 #define WINS_LIST "wins.dat"
26 #define WINS_VERSION 1
27 #define WINSDB_VERSION 1
29 /****************************************************************************
30 We don't store the NetBIOS scope in the wins.tdb. We key off the (utf8) netbios
31 name (65 bytes with the last byte being the name type).
32 *****************************************************************************/
34 TDB_CONTEXT *wins_tdb;
36 /****************************************************************************
37 Delete all the temporary name records on the in-memory linked list.
38 *****************************************************************************/
40 static void wins_delete_all_tmp_in_memory_records(void)
42 struct name_record *nr = NULL;
43 struct name_record *nrnext = NULL;
45 /* Delete all temporary name records on the wins subnet linked list. */
46 for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
47 nrnext = nr->next;
48 DLIST_REMOVE(wins_server_subnet->namelist, nr);
49 SAFE_FREE(nr->data.ip);
50 SAFE_FREE(nr);
54 /****************************************************************************
55 Delete all the temporary 1b name records on the in-memory linked list.
56 *****************************************************************************/
58 static void wins_delete_all_1b_in_memory_records(void)
60 struct name_record *nr = NULL;
61 struct name_record *nrnext = NULL;
63 /* Delete all temporary 1b name records on the wins subnet linked list. */
64 for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
65 nrnext = nr->next;
66 if (nr->name.name_type == 0x1b) {
67 DLIST_REMOVE(wins_server_subnet->namelist, nr);
68 SAFE_FREE(nr->data.ip);
69 SAFE_FREE(nr);
74 /****************************************************************************
75 Convert a wins.tdb record to a struct name_record. Add in our global_scope().
76 *****************************************************************************/
78 static struct name_record *wins_record_to_name_record(TDB_DATA key, TDB_DATA data)
80 struct name_record *namerec = NULL;
81 uint16 nb_flags;
82 unsigned char nr_src;
83 uint32 death_time, refresh_time;
84 uint32 id_low, id_high;
85 uint32 saddr;
86 uint32 wins_flags;
87 uint32 num_ips;
88 size_t len;
89 int i;
91 if (data.dptr == NULL || data.dsize == 0) {
92 return NULL;
95 /* Min size is "wbddddddd" + 1 ip address (4). */
96 if (data.dsize < 2 + 1 + (7*4) + 4) {
97 return NULL;
100 len = tdb_unpack(data.dptr, data.dsize,
101 "wbddddddd",
102 &nb_flags,
103 &nr_src,
104 &death_time,
105 &refresh_time,
106 &id_low,
107 &id_high,
108 &saddr,
109 &wins_flags,
110 &num_ips );
112 namerec = SMB_MALLOC_P(struct name_record);
113 if (!namerec) {
114 return NULL;
116 ZERO_STRUCTP(namerec);
118 namerec->data.ip = SMB_MALLOC_ARRAY(struct in_addr, num_ips);
119 if (!namerec->data.ip) {
120 SAFE_FREE(namerec);
121 return NULL;
124 namerec->subnet = wins_server_subnet;
125 push_ascii_nstring(namerec->name.name, (const char *)key.dptr);
126 namerec->name.name_type = key.dptr[sizeof(unstring)];
127 /* Add the scope. */
128 push_ascii(namerec->name.scope, global_scope(), 64, STR_TERMINATE);
130 /* We're using a byte-by-byte compare, so we must be sure that
131 * unused space doesn't have garbage in it.
134 for( i = strlen( namerec->name.name ); i < sizeof( namerec->name.name ); i++ ) {
135 namerec->name.name[i] = '\0';
137 for( i = strlen( namerec->name.scope ); i < sizeof( namerec->name.scope ); i++ ) {
138 namerec->name.scope[i] = '\0';
141 namerec->data.nb_flags = nb_flags;
142 namerec->data.source = (enum name_source)nr_src;
143 namerec->data.death_time = (time_t)death_time;
144 namerec->data.refresh_time = (time_t)refresh_time;
145 namerec->data.id = id_low;
146 #if defined(HAVE_LONGLONG)
147 namerec->data.id |= ((uint64_t)id_high << 32);
148 #endif
149 namerec->data.wins_ip.s_addr = saddr;
150 namerec->data.wins_flags = wins_flags,
151 namerec->data.num_ips = num_ips;
153 for (i = 0; i < num_ips; i++) {
154 namerec->data.ip[i].s_addr = IVAL(data.dptr, len + (i*4));
157 return namerec;
160 /****************************************************************************
161 Convert a struct name_record to a wins.tdb record. Ignore the scope.
162 *****************************************************************************/
164 static TDB_DATA name_record_to_wins_record(const struct name_record *namerec)
166 TDB_DATA data;
167 size_t len = 0;
168 int i;
169 uint32 id_low = (namerec->data.id & 0xFFFFFFFF);
170 #if defined(HAVE_LONGLONG)
171 uint32 id_high = (namerec->data.id >> 32) & 0xFFFFFFFF;
172 #else
173 uint32 id_high = 0;
174 #endif
176 ZERO_STRUCT(data);
178 len = (2 + 1 + (7*4)); /* "wbddddddd" */
179 len += (namerec->data.num_ips * 4);
181 data.dptr = (uint8 *)SMB_MALLOC(len);
182 if (!data.dptr) {
183 return data;
185 data.dsize = len;
187 len = tdb_pack(data.dptr, data.dsize, "wbddddddd",
188 namerec->data.nb_flags,
189 (unsigned char)namerec->data.source,
190 (uint32)namerec->data.death_time,
191 (uint32)namerec->data.refresh_time,
192 id_low,
193 id_high,
194 (uint32)namerec->data.wins_ip.s_addr,
195 (uint32)namerec->data.wins_flags,
196 (uint32)namerec->data.num_ips );
198 for (i = 0; i < namerec->data.num_ips; i++) {
199 SIVAL(data.dptr, len + (i*4), namerec->data.ip[i].s_addr);
202 return data;
205 /****************************************************************************
206 Create key. Key is UNIX codepage namestring (usually utf8 64 byte len) with 1 byte type.
207 *****************************************************************************/
209 static TDB_DATA name_to_key(const struct nmb_name *nmbname)
211 static char keydata[sizeof(unstring) + 1];
212 TDB_DATA key;
214 memset(keydata, '\0', sizeof(keydata));
216 pull_ascii_nstring(keydata, sizeof(unstring), nmbname->name);
217 strupper_m(keydata);
218 keydata[sizeof(unstring)] = nmbname->name_type;
219 key.dptr = (uint8 *)keydata;
220 key.dsize = sizeof(keydata);
222 return key;
225 /****************************************************************************
226 Lookup a given name in the wins.tdb and create a temporary malloc'ed data struct
227 on the linked list. We will free this later in XXXX().
228 *****************************************************************************/
230 struct name_record *find_name_on_wins_subnet(const struct nmb_name *nmbname, bool self_only)
232 TDB_DATA data, key;
233 struct name_record *nr = NULL;
234 struct name_record *namerec = NULL;
236 if (!wins_tdb) {
237 return NULL;
240 key = name_to_key(nmbname);
241 data = tdb_fetch(wins_tdb, key);
243 if (data.dsize == 0) {
244 return NULL;
247 namerec = wins_record_to_name_record(key, data);
249 /* done with the this */
251 SAFE_FREE( data.dptr );
253 if (!namerec) {
254 return NULL;
257 /* Self names only - these include permanent names. */
258 if( self_only && (namerec->data.source != SELF_NAME) && (namerec->data.source != PERMANENT_NAME) ) {
259 DEBUG( 9, ( "find_name_on_wins_subnet: self name %s NOT FOUND\n", nmb_namestr(nmbname) ) );
260 SAFE_FREE(namerec->data.ip);
261 SAFE_FREE(namerec);
262 return NULL;
265 /* Search for this name record on the list. Replace it if found. */
267 for( nr = wins_server_subnet->namelist; nr; nr = nr->next) {
268 if (memcmp(nmbname->name, nr->name.name, 16) == 0) {
269 /* Delete it. */
270 DLIST_REMOVE(wins_server_subnet->namelist, nr);
271 SAFE_FREE(nr->data.ip);
272 SAFE_FREE(nr);
273 break;
277 DLIST_ADD(wins_server_subnet->namelist, namerec);
278 return namerec;
281 /****************************************************************************
282 Overwrite or add a given name in the wins.tdb.
283 *****************************************************************************/
285 static bool store_or_replace_wins_namerec(const struct name_record *namerec, int tdb_flag)
287 TDB_DATA key, data;
288 int ret;
290 if (!wins_tdb) {
291 return False;
294 key = name_to_key(&namerec->name);
295 data = name_record_to_wins_record(namerec);
297 if (data.dptr == NULL) {
298 return False;
301 ret = tdb_store(wins_tdb, key, data, tdb_flag);
303 SAFE_FREE(data.dptr);
304 return (ret == 0) ? True : False;
307 /****************************************************************************
308 Overwrite a given name in the wins.tdb.
309 *****************************************************************************/
311 bool wins_store_changed_namerec(const struct name_record *namerec)
313 return store_or_replace_wins_namerec(namerec, TDB_REPLACE);
316 /****************************************************************************
317 Primary interface into creating and overwriting records in the wins.tdb.
318 *****************************************************************************/
320 bool add_name_to_wins_subnet(const struct name_record *namerec)
322 return store_or_replace_wins_namerec(namerec, TDB_INSERT);
325 /****************************************************************************
326 Delete a given name in the tdb and remove the temporary malloc'ed data struct
327 on the linked list.
328 *****************************************************************************/
330 bool remove_name_from_wins_namelist(struct name_record *namerec)
332 TDB_DATA key;
333 int ret;
335 if (!wins_tdb) {
336 return False;
339 key = name_to_key(&namerec->name);
340 ret = tdb_delete(wins_tdb, key);
342 DLIST_REMOVE(wins_server_subnet->namelist, namerec);
344 /* namerec must be freed by the caller */
346 return (ret == 0) ? True : False;
349 /****************************************************************************
350 Dump out the complete namelist.
351 *****************************************************************************/
353 static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
355 struct name_record *namerec = NULL;
356 XFILE *fp = (XFILE *)state;
358 if (kbuf.dsize != sizeof(unstring) + 1) {
359 return 0;
362 namerec = wins_record_to_name_record(kbuf, dbuf);
363 if (!namerec) {
364 return 0;
367 dump_name_record(namerec, fp);
369 SAFE_FREE(namerec->data.ip);
370 SAFE_FREE(namerec);
371 return 0;
374 void dump_wins_subnet_namelist(XFILE *fp)
376 tdb_traverse(wins_tdb, traverse_fn, (void *)fp);
379 /****************************************************************************
380 Change the wins owner address in the record.
381 *****************************************************************************/
383 static void update_wins_owner(struct name_record *namerec, struct in_addr wins_ip)
385 namerec->data.wins_ip=wins_ip;
388 /****************************************************************************
389 Create the wins flags based on the nb flags and the input value.
390 *****************************************************************************/
392 static void update_wins_flag(struct name_record *namerec, int flags)
394 namerec->data.wins_flags=0x0;
396 /* if it's a group, it can be a normal or a special one */
397 if (namerec->data.nb_flags & NB_GROUP) {
398 if (namerec->name.name_type==0x1C) {
399 namerec->data.wins_flags|=WINS_SGROUP;
400 } else {
401 if (namerec->data.num_ips>1) {
402 namerec->data.wins_flags|=WINS_SGROUP;
403 } else {
404 namerec->data.wins_flags|=WINS_NGROUP;
407 } else {
408 /* can be unique or multi-homed */
409 if (namerec->data.num_ips>1) {
410 namerec->data.wins_flags|=WINS_MHOMED;
411 } else {
412 namerec->data.wins_flags|=WINS_UNIQUE;
416 /* the node type are the same bits */
417 namerec->data.wins_flags|=namerec->data.nb_flags&NB_NODETYPEMASK;
419 /* the static bit is elsewhere */
420 if (namerec->data.death_time == PERMANENT_TTL) {
421 namerec->data.wins_flags|=WINS_STATIC;
424 /* and add the given bits */
425 namerec->data.wins_flags|=flags;
427 DEBUG(8,("update_wins_flag: nbflags: 0x%x, ttl: 0x%d, flags: 0x%x, winsflags: 0x%x\n",
428 namerec->data.nb_flags, (int)namerec->data.death_time, flags, namerec->data.wins_flags));
431 /****************************************************************************
432 Return the general ID value and increase it if requested.
433 *****************************************************************************/
435 static void get_global_id_and_update(uint64_t *current_id, bool update)
438 * it's kept as a static here, to prevent people from messing
439 * with the value directly
442 static uint64_t general_id = 1;
444 DEBUG(5,("get_global_id_and_update: updating version ID: %d\n", (int)general_id));
446 *current_id = general_id;
448 if (update) {
449 general_id++;
453 /****************************************************************************
454 Possibly call the WINS hook external program when a WINS change is made.
455 Also stores the changed record back in the wins_tdb.
456 *****************************************************************************/
458 static void wins_hook(const char *operation, struct name_record *namerec, int ttl)
460 char *command = NULL;
461 char *cmd = lp_wins_hook();
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);
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 XFILE *fp;
599 char line[1024];
601 if(!lp_we_are_a_wins_server()) {
602 return True;
605 /* Open the wins.tdb. */
606 wins_tdb = tdb_open_log(state_path("wins.tdb"), 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST, O_CREAT|O_RDWR, 0600);
607 if (!wins_tdb) {
608 DEBUG(0,("initialise_wins: failed to open wins.tdb. Error was %s\n",
609 strerror(errno) ));
610 return False;
613 tdb_store_int32(wins_tdb, "WINSDB_VERSION", WINSDB_VERSION);
615 add_samba_names_to_subnet(wins_server_subnet);
617 if((fp = x_fopen(state_path(WINS_LIST),O_RDONLY,0)) == NULL) {
618 DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
619 WINS_LIST, strerror(errno) ));
620 return True;
623 while (!x_feof(fp)) {
624 char *name_str = NULL;
625 char *ip_str = NULL;
626 char *ttl_str = NULL, *nb_flags_str = NULL;
627 unsigned int num_ips;
628 char *name = NULL;
629 struct in_addr *ip_list = NULL;
630 int type = 0;
631 int nb_flags;
632 int ttl;
633 const char *ptr;
634 char *p = NULL;
635 bool got_token;
636 bool was_ip;
637 int i;
638 unsigned int hash;
639 int version;
640 TALLOC_CTX *frame = NULL;
642 /* Read a line from the wins.dat file. Strips whitespace
643 from the beginning and end of the line. */
644 if (!fgets_slash(line,sizeof(line),fp)) {
645 continue;
648 if (*line == '#') {
649 continue;
652 if (strncmp(line,"VERSION ", 8) == 0) {
653 if (sscanf(line,"VERSION %d %u", &version, &hash) != 2 ||
654 version != WINS_VERSION) {
655 DEBUG(0,("Discarding invalid wins.dat file [%s]\n",line));
656 x_fclose(fp);
657 return True;
659 continue;
662 ptr = line;
665 * Now we handle multiple IP addresses per name we need
666 * to iterate over the line twice. The first time to
667 * determine how many IP addresses there are, the second
668 * time to actually parse them into the ip_list array.
671 frame = talloc_stackframe();
672 if (!next_token_talloc(frame,&ptr,&name_str,NULL)) {
673 DEBUG(0,("initialise_wins: Failed to parse name when parsing line %s\n", line ));
674 TALLOC_FREE(frame);
675 continue;
678 if (!next_token_talloc(frame,&ptr,&ttl_str,NULL)) {
679 DEBUG(0,("initialise_wins: Failed to parse time to live when parsing line %s\n", line ));
680 TALLOC_FREE(frame);
681 continue;
685 * Determine the number of IP addresses per line.
687 num_ips = 0;
688 do {
689 got_token = next_token_talloc(frame,&ptr,&ip_str,NULL);
690 was_ip = False;
692 if(got_token && strchr(ip_str, '.')) {
693 num_ips++;
694 was_ip = True;
696 } while(got_token && was_ip);
698 if(num_ips == 0) {
699 DEBUG(0,("initialise_wins: Missing IP address when parsing line %s\n", line ));
700 TALLOC_FREE(frame);
701 continue;
704 if(!got_token) {
705 DEBUG(0,("initialise_wins: Missing nb_flags when parsing line %s\n", line ));
706 TALLOC_FREE(frame);
707 continue;
710 /* Allocate the space for the ip_list. */
711 if((ip_list = SMB_MALLOC_ARRAY( struct in_addr, num_ips)) == NULL) {
712 DEBUG(0,("initialise_wins: Malloc fail !\n"));
713 x_fclose(fp);
714 TALLOC_FREE(frame);
715 return False;
718 /* Reset and re-parse the line. */
719 ptr = line;
720 next_token_talloc(frame,&ptr,&name_str,NULL);
721 next_token_talloc(frame,&ptr,&ttl_str,NULL);
722 for(i = 0; i < num_ips; i++) {
723 next_token_talloc(frame,&ptr, &ip_str, NULL);
724 ip_list[i] = interpret_addr2(ip_str);
726 next_token_talloc(frame,&ptr,&nb_flags_str,NULL);
729 * Deal with SELF or REGISTER name encoding. Default is REGISTER
730 * for compatibility with old nmbds.
733 if(nb_flags_str[strlen(nb_flags_str)-1] == 'S') {
734 DEBUG(5,("initialise_wins: Ignoring SELF name %s\n", line));
735 SAFE_FREE(ip_list);
736 TALLOC_FREE(frame);
737 continue;
740 if(nb_flags_str[strlen(nb_flags_str)-1] == 'R') {
741 nb_flags_str[strlen(nb_flags_str)-1] = '\0';
744 /* Netbios name. # divides the name from the type (hex): netbios#xx */
745 name = name_str;
747 if((p = strchr(name,'#')) != NULL) {
748 *p = 0;
749 sscanf(p+1,"%x",&type);
752 /* Decode the netbios flags (hex) and the time-to-live (in seconds). */
753 sscanf(nb_flags_str,"%x",&nb_flags);
754 sscanf(ttl_str,"%d",&ttl);
756 /* add all entries that have 60 seconds or more to live */
757 if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) {
758 if(ttl != PERMANENT_TTL) {
759 ttl -= time_now;
762 DEBUG( 4, ("initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
763 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
765 (void)add_name_to_subnet( wins_server_subnet, name, type, nb_flags,
766 ttl, REGISTER_NAME, num_ips, ip_list );
767 } else {
768 DEBUG(4, ("initialise_wins: not adding name (ttl problem) "
769 "%s#%02x ttl = %d first IP %s flags = %2x\n",
770 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
773 TALLOC_FREE(frame);
774 SAFE_FREE(ip_list);
777 x_fclose(fp);
778 return True;
781 /****************************************************************************
782 Send a WINS WACK (Wait ACKnowledgement) response.
783 **************************************************************************/
785 static void send_wins_wack_response(int ttl, struct packet_struct *p)
787 struct nmb_packet *nmb = &p->packet.nmb;
788 unsigned char rdata[2];
790 rdata[0] = rdata[1] = 0;
792 /* Taken from nmblib.c - we need to send back almost
793 identical bytes from the requesting packet header. */
795 rdata[0] = (nmb->header.opcode & 0xF) << 3;
796 if (nmb->header.nm_flags.authoritative && nmb->header.response) {
797 rdata[0] |= 0x4;
799 if (nmb->header.nm_flags.trunc) {
800 rdata[0] |= 0x2;
802 if (nmb->header.nm_flags.recursion_desired) {
803 rdata[0] |= 0x1;
805 if (nmb->header.nm_flags.recursion_available && nmb->header.response) {
806 rdata[1] |= 0x80;
808 if (nmb->header.nm_flags.bcast) {
809 rdata[1] |= 0x10;
812 reply_netbios_packet(p, /* Packet to reply to. */
813 0, /* Result code. */
814 NMB_WAIT_ACK, /* nmbd type code. */
815 NMB_WACK_OPCODE, /* opcode. */
816 ttl, /* ttl. */
817 (char *)rdata, /* data to send. */
818 2); /* data length. */
821 /****************************************************************************
822 Send a WINS name registration response.
823 **************************************************************************/
825 static void send_wins_name_registration_response(int rcode, int ttl, struct packet_struct *p)
827 struct nmb_packet *nmb = &p->packet.nmb;
828 char rdata[6];
830 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
832 reply_netbios_packet(p, /* Packet to reply to. */
833 rcode, /* Result code. */
834 WINS_REG, /* nmbd type code. */
835 NMB_NAME_REG_OPCODE, /* opcode. */
836 ttl, /* ttl. */
837 rdata, /* data to send. */
838 6); /* data length. */
841 /***********************************************************************
842 Deal with a name refresh request to a WINS server.
843 ************************************************************************/
845 void wins_process_name_refresh_request( struct subnet_record *subrec,
846 struct packet_struct *p )
848 struct nmb_packet *nmb = &p->packet.nmb;
849 struct nmb_name *question = &nmb->question.question_name;
850 bool bcast = nmb->header.nm_flags.bcast;
851 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
852 bool group = (nb_flags & NB_GROUP) ? True : False;
853 struct name_record *namerec = NULL;
854 int ttl = get_ttl_from_packet(nmb);
855 struct in_addr from_ip;
856 struct in_addr our_fake_ip;
858 our_fake_ip = interpret_addr2("0.0.0.0");
859 putip( (char *)&from_ip, &nmb->additional->rdata[2] );
861 if(bcast) {
863 * We should only get unicast name refresh packets here.
864 * Anyone trying to refresh broadcast should not be going
865 * to a WINS server. Log an error here.
867 if( DEBUGLVL( 0 ) ) {
868 dbgtext( "wins_process_name_refresh_request: " );
869 dbgtext( "Broadcast name refresh request received " );
870 dbgtext( "for name %s ", nmb_namestr(question) );
871 dbgtext( "from IP %s ", inet_ntoa(from_ip) );
872 dbgtext( "on subnet %s. ", subrec->subnet_name );
873 dbgtext( "Error - Broadcasts should not be sent " );
874 dbgtext( "to a WINS server\n" );
876 return;
879 if( DEBUGLVL( 3 ) ) {
880 dbgtext( "wins_process_name_refresh_request: " );
881 dbgtext( "Name refresh for name %s IP %s\n",
882 nmb_namestr(question), inet_ntoa(from_ip) );
886 * See if the name already exists.
887 * If not, handle it as a name registration and return.
889 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
892 * If this is a refresh request and the name doesn't exist then
893 * treat it like a registration request. This allows us to recover
894 * from errors (tridge)
896 if(namerec == NULL) {
897 if( DEBUGLVL( 3 ) ) {
898 dbgtext( "wins_process_name_refresh_request: " );
899 dbgtext( "Name refresh for name %s ",
900 nmb_namestr( question ) );
901 dbgtext( "and the name does not exist. Treating " );
902 dbgtext( "as registration.\n" );
904 wins_process_name_registration_request(subrec,p);
905 return;
909 * if the name is present but not active, simply remove it
910 * and treat the refresh request as a registration & return.
912 if (namerec != NULL && !WINS_STATE_ACTIVE(namerec)) {
913 if( DEBUGLVL( 5 ) ) {
914 dbgtext( "wins_process_name_refresh_request: " );
915 dbgtext( "Name (%s) in WINS ", nmb_namestr(question) );
916 dbgtext( "was not active - removing it.\n" );
918 remove_name_from_namelist( subrec, namerec );
919 namerec = NULL;
920 wins_process_name_registration_request( subrec, p );
921 return;
925 * Check that the group bits for the refreshing name and the
926 * name in our database match. If not, refuse the refresh.
927 * [crh: Why RFS_ERR instead of ACT_ERR? Is this what MS does?]
929 if( (namerec != NULL) &&
930 ( (group && !NAME_GROUP(namerec))
931 || (!group && NAME_GROUP(namerec)) ) ) {
932 if( DEBUGLVL( 3 ) ) {
933 dbgtext( "wins_process_name_refresh_request: " );
934 dbgtext( "Name %s ", nmb_namestr(question) );
935 dbgtext( "group bit = %s does not match ",
936 group ? "True" : "False" );
937 dbgtext( "group bit in WINS for this name.\n" );
939 send_wins_name_registration_response(RFS_ERR, 0, p);
940 return;
944 * For a unique name check that the person refreshing the name is
945 * one of the registered IP addresses. If not - fail the refresh.
946 * Do the same for group names with a type of 0x1c.
947 * Just return success for unique 0x1d refreshes. For normal group
948 * names update the ttl and return success.
950 if( (!group || (group && (question->name_type == 0x1c)))
951 && find_ip_in_name_record(namerec, from_ip) ) {
953 * Update the ttl.
955 update_name_ttl(namerec, ttl);
958 * if the record is a replica:
959 * we take ownership and update the version ID.
961 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
962 update_wins_owner(namerec, our_fake_ip);
963 get_global_id_and_update(&namerec->data.id, True);
966 send_wins_name_registration_response(0, ttl, p);
967 wins_hook("refresh", namerec, ttl);
968 return;
969 } else if((group && (question->name_type == 0x1c))) {
971 * Added by crh for bug #1079.
972 * Fix from Bert Driehuis
974 if( DEBUGLVL( 3 ) ) {
975 dbgtext( "wins_process_name_refresh_request: " );
976 dbgtext( "Name refresh for name %s, ",
977 nmb_namestr(question) );
978 dbgtext( "but IP address %s ", inet_ntoa(from_ip) );
979 dbgtext( "is not yet associated with " );
980 dbgtext( "that name. Treating as registration.\n" );
982 wins_process_name_registration_request(subrec,p);
983 return;
984 } else if(group) {
986 * Normal groups are all registered with an IP address of
987 * 255.255.255.255 so we can't search for the IP address.
989 update_name_ttl(namerec, ttl);
990 wins_hook("refresh", namerec, ttl);
991 send_wins_name_registration_response(0, ttl, p);
992 return;
993 } else if(!group && (question->name_type == 0x1d)) {
995 * Special name type - just pretend the refresh succeeded.
997 send_wins_name_registration_response(0, ttl, p);
998 return;
999 } else {
1001 * Fail the refresh.
1003 if( DEBUGLVL( 3 ) ) {
1004 dbgtext( "wins_process_name_refresh_request: " );
1005 dbgtext( "Name refresh for name %s with IP %s ",
1006 nmb_namestr(question), inet_ntoa(from_ip) );
1007 dbgtext( "and is IP is not known to the name.\n" );
1009 send_wins_name_registration_response(RFS_ERR, 0, p);
1010 return;
1014 /***********************************************************************
1015 Deal with a name registration request query success to a client that
1016 owned the name.
1018 We have a locked pointer to the original packet stashed away in the
1019 userdata pointer. The success here is actually a failure as it means
1020 the client we queried wants to keep the name, so we must return
1021 a registration failure to the original requestor.
1022 ************************************************************************/
1024 static void wins_register_query_success(struct subnet_record *subrec,
1025 struct userdata_struct *userdata,
1026 struct nmb_name *question_name,
1027 struct in_addr ip,
1028 struct res_rec *answers)
1030 struct packet_struct *orig_reg_packet;
1032 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1034 DEBUG(3,("wins_register_query_success: Original client at IP %s still wants the \
1035 name %s. Rejecting registration request.\n", inet_ntoa(ip), nmb_namestr(question_name) ));
1037 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1039 orig_reg_packet->locked = False;
1040 free_packet(orig_reg_packet);
1043 /***********************************************************************
1044 Deal with a name registration request query failure to a client that
1045 owned the name.
1047 We have a locked pointer to the original packet stashed away in the
1048 userdata pointer. The failure here is actually a success as it means
1049 the client we queried didn't want to keep the name, so we can remove
1050 the old name record and then successfully add the new name.
1051 ************************************************************************/
1053 static void wins_register_query_fail(struct subnet_record *subrec,
1054 struct response_record *rrec,
1055 struct nmb_name *question_name,
1056 int rcode)
1058 struct userdata_struct *userdata = rrec->userdata;
1059 struct packet_struct *orig_reg_packet;
1060 struct name_record *namerec = NULL;
1062 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1065 * We want to just add the name, as we now know the original owner
1066 * didn't want it. But we can't just do that as an arbitary
1067 * amount of time may have taken place between the name query
1068 * request and this timeout/error response. So we check that
1069 * the name still exists and is in the same state - if so
1070 * we remove it and call wins_process_name_registration_request()
1071 * as we know it will do the right thing now.
1074 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1076 if ((namerec != NULL) && (namerec->data.source == REGISTER_NAME) &&
1077 ip_equal_v4(rrec->packet->ip, *namerec->data.ip)) {
1078 remove_name_from_namelist( subrec, namerec);
1079 namerec = NULL;
1082 if(namerec == NULL) {
1083 wins_process_name_registration_request(subrec, orig_reg_packet);
1084 } else {
1085 DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between "
1086 "querying for name %s in order to replace it and this reply.\n",
1087 nmb_namestr(question_name) ));
1090 orig_reg_packet->locked = False;
1091 free_packet(orig_reg_packet);
1094 /***********************************************************************
1095 Deal with a name registration request to a WINS server.
1097 Use the following pseudocode :
1099 registering_group
1102 +--------name exists
1105 | +--- existing name is group
1106 | | |
1107 | | |
1108 | | +--- add name (return).
1111 | +--- exiting name is unique
1114 | +--- query existing owner (return).
1117 +--------name doesn't exist
1120 +--- add name (return).
1122 registering_unique
1125 +--------name exists
1128 | +--- existing name is group
1129 | | |
1130 | | |
1131 | | +--- fail add (return).
1132 | |
1134 | +--- exiting name is unique
1137 | +--- query existing owner (return).
1140 +--------name doesn't exist
1143 +--- add name (return).
1145 As can be seen from the above, the two cases may be collapsed onto each
1146 other with the exception of the case where the name already exists and
1147 is a group name. This case we handle with an if statement.
1149 ************************************************************************/
1151 void wins_process_name_registration_request(struct subnet_record *subrec,
1152 struct packet_struct *p)
1154 unstring name;
1155 struct nmb_packet *nmb = &p->packet.nmb;
1156 struct nmb_name *question = &nmb->question.question_name;
1157 bool bcast = nmb->header.nm_flags.bcast;
1158 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
1159 int ttl = get_ttl_from_packet(nmb);
1160 struct name_record *namerec = NULL;
1161 struct in_addr from_ip;
1162 bool registering_group_name = (nb_flags & NB_GROUP) ? True : False;
1163 struct in_addr our_fake_ip;
1165 our_fake_ip = interpret_addr2("0.0.0.0");
1166 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1168 if(bcast) {
1170 * We should only get unicast name registration packets here.
1171 * Anyone trying to register broadcast should not be going to a WINS
1172 * server. Log an error here.
1175 DEBUG(0,("wins_process_name_registration_request: broadcast name registration request \
1176 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1177 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1178 return;
1181 DEBUG(3,("wins_process_name_registration_request: %s name registration for name %s \
1182 IP %s\n", registering_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
1185 * See if the name already exists.
1188 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1191 * if the record exists but NOT in active state,
1192 * consider it dead.
1194 if ( (namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1195 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1196 not active - removing it.\n", nmb_namestr(question) ));
1197 remove_name_from_namelist( subrec, namerec );
1198 namerec = NULL;
1202 * Deal with the case where the name found was a dns entry.
1203 * Remove it as we now have a NetBIOS client registering the
1204 * name.
1207 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1208 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1209 a dns lookup - removing it.\n", nmb_namestr(question) ));
1210 remove_name_from_namelist( subrec, namerec );
1211 namerec = NULL;
1215 * Reject if the name exists and is not a REGISTER_NAME.
1216 * (ie. Don't allow any static names to be overwritten.
1219 if((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) {
1220 DEBUG( 3, ( "wins_process_name_registration_request: Attempt \
1221 to register name %s. Name already exists in WINS with source type %d.\n",
1222 nmb_namestr(question), namerec->data.source ));
1223 send_wins_name_registration_response(RFS_ERR, 0, p);
1224 return;
1228 * Special policy decisions based on MS documentation.
1229 * 1). All group names (except names ending in 0x1c) are added as 255.255.255.255.
1230 * 2). All unique names ending in 0x1d are ignored, although a positive response is sent.
1234 * A group name is always added as the local broadcast address, except
1235 * for group names ending in 0x1c.
1236 * Group names with type 0x1c are registered with individual IP addresses.
1239 if(registering_group_name && (question->name_type != 0x1c)) {
1240 from_ip = interpret_addr2("255.255.255.255");
1244 * Ignore all attempts to register a unique 0x1d name, although return success.
1247 if(!registering_group_name && (question->name_type == 0x1d)) {
1248 DEBUG(3,("wins_process_name_registration_request: Ignoring request \
1249 to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
1250 send_wins_name_registration_response(0, ttl, p);
1251 return;
1255 * Next two cases are the 'if statement' mentioned above.
1258 if((namerec != NULL) && NAME_GROUP(namerec)) {
1259 if(registering_group_name) {
1261 * If we are adding a group name, the name exists and is also a group entry just add this
1262 * IP address to it and update the ttl.
1265 DEBUG(3,("wins_process_name_registration_request: Adding IP %s to group name %s.\n",
1266 inet_ntoa(from_ip), nmb_namestr(question) ));
1269 * Check the ip address is not already in the group.
1272 if(!find_ip_in_name_record(namerec, from_ip)) {
1274 * Need to emulate the behaviour of Windows, as
1275 * described in:
1276 * http://lists.samba.org/archive/samba-technical/2001-October/016236.html
1277 * (is there an MS reference for this
1278 * somewhere?) because if the 1c list gets over
1279 * 86 entries, the reply packet is too big
1280 * (rdata>576 bytes) so no reply is sent.
1282 * Keep only the "latest" 25 records, while
1283 * ensuring that the PDC (0x1b) is never removed
1284 * We do this by removing the first entry that
1285 * isn't the 1b entry for the same name,
1286 * on the grounds that insertion is at the end
1287 * of the list, so the oldest entries are at
1288 * the start.
1291 while(namerec->data.num_ips>=25) {
1292 struct name_record *name1brec = NULL;
1294 /* We only do this for 1c types. */
1295 if (namerec->name.name_type != 0x1c) {
1296 break;
1298 DEBUG(3,("wins_process_name_registration_request: "
1299 "More than 25 IPs already in "
1300 "the list. Looking for a 1b "
1301 "record\n"));
1303 /* Ensure we have all the active 1b
1304 * names on the list. */
1305 wins_delete_all_1b_in_memory_records();
1306 fetch_all_active_wins_1b_names();
1308 /* Per the above, find the 1b record,
1309 and then remove the first IP that isn't the same */
1310 for(name1brec = subrec->namelist;
1311 name1brec;
1312 name1brec = name1brec->next ) {
1313 if( WINS_STATE_ACTIVE(name1brec) &&
1314 name1brec->name.name_type == 0x1b) {
1315 DEBUG(3,("wins_process_name_registration_request: "
1316 "Found the #1b record "
1317 "with ip %s\n",
1318 inet_ntoa(name1brec->data.ip[0])));
1319 break;
1322 if(!name1brec) {
1323 DEBUG(3,("wins_process_name_registration_request: "
1324 "Didn't find a #1b name record. "
1325 "Removing the first available "
1326 "entry %s\n",
1327 inet_ntoa(namerec->data.ip[0])));
1328 remove_ip_from_name_record(namerec, namerec->data.ip[0]);
1329 wins_hook("delete", namerec, 0);
1330 } else {
1331 int i;
1332 for(i=0; i<namerec->data.num_ips; i++) {
1333 /* The name1brec should only have
1334 * the single IP address in it,
1335 * so we only check against the first one*/
1336 if(!ip_equal_v4( namerec->data.ip[i], name1brec->data.ip[0])) {
1337 /* The i'th entry isn't the 1b address; delete it */
1338 DEBUG(3,("wins_process_name_registration_request: "
1339 "Entry at %d is not the #1b address. "
1340 "About to remove it\n",
1341 i));
1342 remove_ip_from_name_record(namerec, namerec->data.ip[i]);
1343 wins_hook("delete", namerec, 0);
1344 break;
1349 /* The list is guaranteed to be < 25 entries now
1350 * - safe to add a new one */
1351 add_ip_to_name_record(namerec, from_ip);
1352 /* we need to update the record for replication */
1353 get_global_id_and_update(&namerec->data.id, True);
1356 * if the record is a replica, we must change
1357 * the wins owner to us to make the replication updates
1358 * it on the other wins servers.
1359 * And when the partner will receive this record,
1360 * it will update its own record.
1363 update_wins_owner(namerec, our_fake_ip);
1365 update_name_ttl(namerec, ttl);
1366 wins_hook("refresh", namerec, ttl);
1367 send_wins_name_registration_response(0, ttl, p);
1368 return;
1369 } else {
1372 * If we are adding a unique name, the name exists in the WINS db
1373 * and is a group name then reject the registration.
1375 * explanation: groups have a higher priority than unique names.
1378 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1379 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1380 send_wins_name_registration_response(RFS_ERR, 0, p);
1381 return;
1386 * From here on down we know that if the name exists in the WINS db it is
1387 * a unique name, not a group name.
1391 * If the name exists and is one of our names then check the
1392 * registering IP address. If it's not one of ours then automatically
1393 * reject without doing the query - we know we will reject it.
1396 if ( namerec != NULL ) {
1397 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
1398 if( is_myname(name) ) {
1399 if(!ismyip_v4(from_ip)) {
1400 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1401 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1402 send_wins_name_registration_response(RFS_ERR, 0, p);
1403 return;
1404 } else {
1406 * It's one of our names and one of our IP's - update the ttl.
1408 update_name_ttl(namerec, ttl);
1409 wins_hook("refresh", namerec, ttl);
1410 send_wins_name_registration_response(0, ttl, p);
1411 return;
1414 } else {
1415 name[0] = '\0';
1419 * If the name exists and it is a unique registration and the registering IP
1420 * is the same as the (single) already registered IP then just update the ttl.
1422 * But not if the record is an active replica. IF it's a replica, it means it can be
1423 * the same client which has moved and not yet expired. So we don't update
1424 * the ttl in this case and go beyond to do a WACK and query the old client
1427 if( !registering_group_name
1428 && (namerec != NULL)
1429 && (namerec->data.num_ips == 1)
1430 && ip_equal_v4( namerec->data.ip[0], from_ip )
1431 && ip_equal_v4(namerec->data.wins_ip, our_fake_ip) ) {
1432 update_name_ttl( namerec, ttl );
1433 wins_hook("refresh", namerec, ttl);
1434 send_wins_name_registration_response( 0, ttl, p );
1435 return;
1439 * Finally if the name exists do a query to the registering machine
1440 * to see if they still claim to have the name.
1443 if( namerec != NULL ) {
1444 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1445 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1448 * First send a WACK to the registering machine.
1451 send_wins_wack_response(60, p);
1454 * When the reply comes back we need the original packet.
1455 * Lock this so it won't be freed and then put it into
1456 * the userdata structure.
1459 p->locked = True;
1461 userdata = (struct userdata_struct *)ud;
1463 userdata->copy_fn = NULL;
1464 userdata->free_fn = NULL;
1465 userdata->userdata_len = sizeof(struct packet_struct *);
1466 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1469 * Use the new call to send a query directly to an IP address.
1470 * This sends the query directly to the IP address, and ensures
1471 * the recursion desired flag is not set (you were right Luke :-).
1472 * This function should *only* be called from the WINS server
1473 * code. JRA.
1476 pull_ascii_nstring(name, sizeof(name), question->name);
1477 query_name_from_wins_server( *namerec->data.ip,
1478 name,
1479 question->name_type,
1480 wins_register_query_success,
1481 wins_register_query_fail,
1482 userdata );
1483 return;
1487 * Name did not exist - add it.
1490 pull_ascii_nstring(name, sizeof(name), question->name);
1491 add_name_to_subnet( subrec, name, question->name_type,
1492 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1494 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1495 get_global_id_and_update(&namerec->data.id, True);
1496 update_wins_owner(namerec, our_fake_ip);
1497 update_wins_flag(namerec, WINS_ACTIVE);
1498 wins_hook("add", namerec, ttl);
1501 send_wins_name_registration_response(0, ttl, p);
1504 /***********************************************************************
1505 Deal with a mutihomed name query success to the machine that
1506 requested the multihomed name registration.
1508 We have a locked pointer to the original packet stashed away in the
1509 userdata pointer.
1510 ************************************************************************/
1512 static void wins_multihomed_register_query_success(struct subnet_record *subrec,
1513 struct userdata_struct *userdata,
1514 struct nmb_name *question_name,
1515 struct in_addr ip,
1516 struct res_rec *answers)
1518 struct packet_struct *orig_reg_packet;
1519 struct nmb_packet *nmb;
1520 struct name_record *namerec = NULL;
1521 struct in_addr from_ip;
1522 int ttl;
1523 struct in_addr our_fake_ip;
1525 our_fake_ip = interpret_addr2("0.0.0.0");
1526 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1528 nmb = &orig_reg_packet->packet.nmb;
1530 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1531 ttl = get_ttl_from_packet(nmb);
1534 * We want to just add the new IP, as we now know the requesting
1535 * machine claims to own it. But we can't just do that as an arbitary
1536 * amount of time may have taken place between the name query
1537 * request and this response. So we check that
1538 * the name still exists and is in the same state - if so
1539 * we just add the extra IP and update the ttl.
1542 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1544 if( (namerec == NULL) || (namerec->data.source != REGISTER_NAME) || !WINS_STATE_ACTIVE(namerec) ) {
1545 DEBUG(3,("wins_multihomed_register_query_success: name %s is not in the correct state to add \
1546 a subsequent IP address.\n", nmb_namestr(question_name) ));
1547 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1549 orig_reg_packet->locked = False;
1550 free_packet(orig_reg_packet);
1552 return;
1555 if(!find_ip_in_name_record(namerec, from_ip)) {
1556 add_ip_to_name_record(namerec, from_ip);
1559 get_global_id_and_update(&namerec->data.id, True);
1560 update_wins_owner(namerec, our_fake_ip);
1561 update_wins_flag(namerec, WINS_ACTIVE);
1562 update_name_ttl(namerec, ttl);
1563 wins_hook("add", namerec, ttl);
1564 send_wins_name_registration_response(0, ttl, orig_reg_packet);
1566 orig_reg_packet->locked = False;
1567 free_packet(orig_reg_packet);
1570 /***********************************************************************
1571 Deal with a name registration request query failure to a client that
1572 owned the name.
1574 We have a locked pointer to the original packet stashed away in the
1575 userdata pointer.
1576 ************************************************************************/
1578 static void wins_multihomed_register_query_fail(struct subnet_record *subrec,
1579 struct response_record *rrec,
1580 struct nmb_name *question_name,
1581 int rcode)
1583 struct userdata_struct *userdata = rrec->userdata;
1584 struct packet_struct *orig_reg_packet;
1586 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1588 DEBUG(3,("wins_multihomed_register_query_fail: Registering machine at IP %s failed to answer \
1589 query successfully for name %s.\n", inet_ntoa(orig_reg_packet->ip), nmb_namestr(question_name) ));
1590 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1592 orig_reg_packet->locked = False;
1593 free_packet(orig_reg_packet);
1594 return;
1597 /***********************************************************************
1598 Deal with a multihomed name registration request to a WINS server.
1599 These cannot be group name registrations.
1600 ***********************************************************************/
1602 void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
1603 struct packet_struct *p)
1605 struct nmb_packet *nmb = &p->packet.nmb;
1606 struct nmb_name *question = &nmb->question.question_name;
1607 bool bcast = nmb->header.nm_flags.bcast;
1608 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
1609 int ttl = get_ttl_from_packet(nmb);
1610 struct name_record *namerec = NULL;
1611 struct in_addr from_ip;
1612 bool group = (nb_flags & NB_GROUP) ? True : False;
1613 struct in_addr our_fake_ip;
1614 unstring qname;
1616 our_fake_ip = interpret_addr2("0.0.0.0");
1617 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1619 if(bcast) {
1621 * We should only get unicast name registration packets here.
1622 * Anyone trying to register broadcast should not be going to a WINS
1623 * server. Log an error here.
1626 DEBUG(0,("wins_process_multihomed_name_registration_request: broadcast name registration request \
1627 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1628 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1629 return;
1633 * Only unique names should be registered multihomed.
1636 if(group) {
1637 DEBUG(0,("wins_process_multihomed_name_registration_request: group name registration request \
1638 received for name %s from IP %s on subnet %s. Errror - group names should not be multihomed.\n",
1639 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1640 return;
1643 DEBUG(3,("wins_process_multihomed_name_registration_request: name registration for name %s \
1644 IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ));
1647 * Deal with policy regarding 0x1d names.
1650 if(question->name_type == 0x1d) {
1651 DEBUG(3,("wins_process_multihomed_name_registration_request: Ignoring request \
1652 to register name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
1653 send_wins_name_registration_response(0, ttl, p);
1654 return;
1658 * See if the name already exists.
1661 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1664 * if the record exists but NOT in active state,
1665 * consider it dead.
1668 if ((namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1669 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was not active - removing it.\n", nmb_namestr(question)));
1670 remove_name_from_namelist(subrec, namerec);
1671 namerec = NULL;
1675 * Deal with the case where the name found was a dns entry.
1676 * Remove it as we now have a NetBIOS client registering the
1677 * name.
1680 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1681 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was a dns lookup \
1682 - removing it.\n", nmb_namestr(question) ));
1683 remove_name_from_namelist( subrec, namerec);
1684 namerec = NULL;
1688 * Reject if the name exists and is not a REGISTER_NAME.
1689 * (ie. Don't allow any static names to be overwritten.
1692 if( (namerec != NULL) && (namerec->data.source != REGISTER_NAME) ) {
1693 DEBUG( 3, ( "wins_process_multihomed_name_registration_request: Attempt \
1694 to register name %s. Name already exists in WINS with source type %d.\n",
1695 nmb_namestr(question), namerec->data.source ));
1696 send_wins_name_registration_response(RFS_ERR, 0, p);
1697 return;
1701 * Reject if the name exists and is a GROUP name and is active.
1704 if((namerec != NULL) && NAME_GROUP(namerec) && WINS_STATE_ACTIVE(namerec)) {
1705 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1706 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1707 send_wins_name_registration_response(RFS_ERR, 0, p);
1708 return;
1712 * From here on down we know that if the name exists in the WINS db it is
1713 * a unique name, not a group name.
1717 * If the name exists and is one of our names then check the
1718 * registering IP address. If it's not one of ours then automatically
1719 * reject without doing the query - we know we will reject it.
1722 if((namerec != NULL) && (is_myname(namerec->name.name)) ) {
1723 if(!ismyip_v4(from_ip)) {
1724 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1725 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1726 send_wins_name_registration_response(RFS_ERR, 0, p);
1727 return;
1728 } else {
1730 * It's one of our names and one of our IP's. Ensure the IP is in the record and
1731 * update the ttl. Update the version ID to force replication.
1733 update_name_ttl(namerec, ttl);
1735 if(!find_ip_in_name_record(namerec, from_ip)) {
1736 get_global_id_and_update(&namerec->data.id, True);
1737 update_wins_owner(namerec, our_fake_ip);
1738 update_wins_flag(namerec, WINS_ACTIVE);
1740 add_ip_to_name_record(namerec, from_ip);
1743 wins_hook("refresh", namerec, ttl);
1744 send_wins_name_registration_response(0, ttl, p);
1745 return;
1750 * If the name exists and is active, check if the IP address is already registered
1751 * to that name. If so then update the ttl and reply success.
1754 if((namerec != NULL) && find_ip_in_name_record(namerec, from_ip) && WINS_STATE_ACTIVE(namerec)) {
1755 update_name_ttl(namerec, ttl);
1758 * If it's a replica, we need to become the wins owner
1759 * to force the replication
1761 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
1762 get_global_id_and_update(&namerec->data.id, True);
1763 update_wins_owner(namerec, our_fake_ip);
1764 update_wins_flag(namerec, WINS_ACTIVE);
1767 wins_hook("refresh", namerec, ttl);
1768 send_wins_name_registration_response(0, ttl, p);
1769 return;
1773 * If the name exists do a query to the owner
1774 * to see if they still want the name.
1777 if(namerec != NULL) {
1778 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1779 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1782 * First send a WACK to the registering machine.
1785 send_wins_wack_response(60, p);
1788 * When the reply comes back we need the original packet.
1789 * Lock this so it won't be freed and then put it into
1790 * the userdata structure.
1793 p->locked = True;
1795 userdata = (struct userdata_struct *)ud;
1797 userdata->copy_fn = NULL;
1798 userdata->free_fn = NULL;
1799 userdata->userdata_len = sizeof(struct packet_struct *);
1800 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1803 * Use the new call to send a query directly to an IP address.
1804 * This sends the query directly to the IP address, and ensures
1805 * the recursion desired flag is not set (you were right Luke :-).
1806 * This function should *only* be called from the WINS server
1807 * code. JRA.
1809 * Note that this packet is sent to the current owner of the name,
1810 * not the person who sent the packet
1813 pull_ascii_nstring( qname, sizeof(qname), question->name);
1814 query_name_from_wins_server( namerec->data.ip[0],
1815 qname,
1816 question->name_type,
1817 wins_multihomed_register_query_success,
1818 wins_multihomed_register_query_fail,
1819 userdata );
1821 return;
1825 * Name did not exist - add it.
1828 pull_ascii_nstring( qname, sizeof(qname), question->name);
1829 add_name_to_subnet( subrec, qname, question->name_type,
1830 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1832 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1833 get_global_id_and_update(&namerec->data.id, True);
1834 update_wins_owner(namerec, our_fake_ip);
1835 update_wins_flag(namerec, WINS_ACTIVE);
1836 wins_hook("add", namerec, ttl);
1839 send_wins_name_registration_response(0, ttl, p);
1842 /***********************************************************************
1843 Fetch all *<1b> names from the WINS db and store on the namelist.
1844 ***********************************************************************/
1846 static int fetch_1b_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
1848 struct name_record *namerec = NULL;
1850 if (kbuf.dsize != sizeof(unstring) + 1) {
1851 return 0;
1854 /* Filter out all non-1b names. */
1855 if (kbuf.dptr[sizeof(unstring)] != 0x1b) {
1856 return 0;
1859 namerec = wins_record_to_name_record(kbuf, dbuf);
1860 if (!namerec) {
1861 return 0;
1864 DLIST_ADD(wins_server_subnet->namelist, namerec);
1865 return 0;
1868 void fetch_all_active_wins_1b_names(void)
1870 tdb_traverse(wins_tdb, fetch_1b_traverse_fn, NULL);
1873 /***********************************************************************
1874 Deal with the special name query for *<1b>.
1875 ***********************************************************************/
1877 static void process_wins_dmb_query_request(struct subnet_record *subrec,
1878 struct packet_struct *p)
1880 struct name_record *namerec = NULL;
1881 char *prdata;
1882 int num_ips;
1885 * Go through all the ACTIVE names in the WINS db looking for those
1886 * ending in <1b>. Use this to calculate the number of IP
1887 * addresses we need to return.
1890 num_ips = 0;
1892 /* First, clear the in memory list - we're going to re-populate
1893 it with the tdb_traversal in fetch_all_active_wins_1b_names. */
1895 wins_delete_all_tmp_in_memory_records();
1897 fetch_all_active_wins_1b_names();
1899 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1900 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1901 num_ips += namerec->data.num_ips;
1905 if(num_ips == 0) {
1907 * There are no 0x1b names registered. Return name query fail.
1909 send_wins_name_query_response(NAM_ERR, p, NULL);
1910 return;
1913 if((prdata = (char *)SMB_MALLOC( num_ips * 6 )) == NULL) {
1914 DEBUG(0,("process_wins_dmb_query_request: Malloc fail !.\n"));
1915 return;
1919 * Go through all the names again in the WINS db looking for those
1920 * ending in <1b>. Add their IP addresses into the list we will
1921 * return.
1924 num_ips = 0;
1925 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1926 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1927 int i;
1928 for(i = 0; i < namerec->data.num_ips; i++) {
1929 set_nb_flags(&prdata[num_ips * 6],namerec->data.nb_flags);
1930 putip((char *)&prdata[(num_ips * 6) + 2], &namerec->data.ip[i]);
1931 num_ips++;
1937 * Send back the reply containing the IP list.
1940 reply_netbios_packet(p, /* Packet to reply to. */
1941 0, /* Result code. */
1942 WINS_QUERY, /* nmbd type code. */
1943 NMB_NAME_QUERY_OPCODE, /* opcode. */
1944 lp_min_wins_ttl(), /* ttl. */
1945 prdata, /* data to send. */
1946 num_ips*6); /* data length. */
1948 SAFE_FREE(prdata);
1951 /****************************************************************************
1952 Send a WINS name query response.
1953 **************************************************************************/
1955 void send_wins_name_query_response(int rcode, struct packet_struct *p,
1956 struct name_record *namerec)
1958 char rdata[6];
1959 char *prdata = rdata;
1960 int reply_data_len = 0;
1961 int ttl = 0;
1962 int i;
1964 memset(rdata,'\0',6);
1966 if(rcode == 0) {
1968 int ip_count;
1970 ttl = (namerec->data.death_time != PERMANENT_TTL) ? namerec->data.death_time - p->timestamp : lp_max_wins_ttl();
1972 /* The netbios reply packet data section is limited to 576 bytes. In theory
1973 * this should give us space for 96 addresses, but in practice, 86 appears
1974 * to be the max (don't know why). If we send any more than that,
1975 * reply_netbios_packet will fail to send a reply to avoid a memcpy buffer
1976 * overflow. Keep the count to 85 and it will be ok */
1977 ip_count=namerec->data.num_ips;
1978 if(ip_count>85) {
1979 ip_count=85;
1982 /* Copy all known ip addresses into the return data. */
1983 /* Optimise for the common case of one IP address so we don't need a malloc. */
1985 if( ip_count == 1 ) {
1986 prdata = rdata;
1987 } else {
1988 if((prdata = (char *)SMB_MALLOC( ip_count * 6 )) == NULL) {
1989 DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
1990 return;
1994 for(i = 0; i < ip_count; i++) {
1995 set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
1996 putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
1999 sort_query_replies(prdata, i, p->ip);
2000 reply_data_len = ip_count * 6;
2003 reply_netbios_packet(p, /* Packet to reply to. */
2004 rcode, /* Result code. */
2005 WINS_QUERY, /* nmbd type code. */
2006 NMB_NAME_QUERY_OPCODE, /* opcode. */
2007 ttl, /* ttl. */
2008 prdata, /* data to send. */
2009 reply_data_len); /* data length. */
2011 if(prdata != rdata) {
2012 SAFE_FREE(prdata);
2016 /***********************************************************************
2017 Deal with a name query.
2018 ***********************************************************************/
2020 void wins_process_name_query_request(struct subnet_record *subrec,
2021 struct packet_struct *p)
2023 struct nmb_packet *nmb = &p->packet.nmb;
2024 struct nmb_name *question = &nmb->question.question_name;
2025 struct name_record *namerec = NULL;
2026 unstring qname;
2028 DEBUG(3,("wins_process_name_query: name query for name %s from IP %s\n",
2029 nmb_namestr(question), inet_ntoa(p->ip) ));
2032 * Special name code. If the queried name is *<1b> then search
2033 * the entire WINS database and return a list of all the IP addresses
2034 * registered to any <1b> name. This is to allow domain master browsers
2035 * to discover other domains that may not have a presence on their subnet.
2038 pull_ascii_nstring(qname, sizeof(qname), question->name);
2039 if(strequal( qname, "*") && (question->name_type == 0x1b)) {
2040 process_wins_dmb_query_request( subrec, p);
2041 return;
2044 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2046 if(namerec != NULL) {
2048 * If the name is not anymore in active state then reply not found.
2049 * it's fair even if we keep it in the cache for days.
2051 if (!WINS_STATE_ACTIVE(namerec)) {
2052 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
2053 nmb_namestr(question) ));
2054 send_wins_name_query_response(NAM_ERR, p, namerec);
2055 return;
2059 * If it's a DNSFAIL_NAME then reply name not found.
2062 if( namerec->data.source == DNSFAIL_NAME ) {
2063 DEBUG(3,("wins_process_name_query: name query for name %s returning DNS fail.\n",
2064 nmb_namestr(question) ));
2065 send_wins_name_query_response(NAM_ERR, p, namerec);
2066 return;
2070 * If the name has expired then reply name not found.
2073 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < p->timestamp) ) {
2074 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
2075 nmb_namestr(question) ));
2076 send_wins_name_query_response(NAM_ERR, p, namerec);
2077 return;
2080 DEBUG(3,("wins_process_name_query: name query for name %s returning first IP %s.\n",
2081 nmb_namestr(question), inet_ntoa(namerec->data.ip[0]) ));
2083 send_wins_name_query_response(0, p, namerec);
2084 return;
2088 * Name not found in WINS - try a dns query if it's a 0x20 name.
2091 if(lp_dns_proxy() && ((question->name_type == 0x20) || question->name_type == 0)) {
2092 DEBUG(3,("wins_process_name_query: name query for name %s not found - doing dns lookup.\n",
2093 nmb_namestr(question) ));
2095 queue_dns_query(p, question);
2096 return;
2100 * Name not found - return error.
2103 send_wins_name_query_response(NAM_ERR, p, NULL);
2106 /****************************************************************************
2107 Send a WINS name release response.
2108 **************************************************************************/
2110 static void send_wins_name_release_response(int rcode, struct packet_struct *p)
2112 struct nmb_packet *nmb = &p->packet.nmb;
2113 char rdata[6];
2115 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
2117 reply_netbios_packet(p, /* Packet to reply to. */
2118 rcode, /* Result code. */
2119 NMB_REL, /* nmbd type code. */
2120 NMB_NAME_RELEASE_OPCODE, /* opcode. */
2121 0, /* ttl. */
2122 rdata, /* data to send. */
2123 6); /* data length. */
2126 /***********************************************************************
2127 Deal with a name release.
2128 ***********************************************************************/
2130 void wins_process_name_release_request(struct subnet_record *subrec,
2131 struct packet_struct *p)
2133 struct nmb_packet *nmb = &p->packet.nmb;
2134 struct nmb_name *question = &nmb->question.question_name;
2135 bool bcast = nmb->header.nm_flags.bcast;
2136 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
2137 struct name_record *namerec = NULL;
2138 struct in_addr from_ip;
2139 bool releasing_group_name = (nb_flags & NB_GROUP) ? True : False;;
2141 putip((char *)&from_ip,&nmb->additional->rdata[2]);
2143 if(bcast) {
2145 * We should only get unicast name registration packets here.
2146 * Anyone trying to register broadcast should not be going to a WINS
2147 * server. Log an error here.
2150 DEBUG(0,("wins_process_name_release_request: broadcast name registration request \
2151 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
2152 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
2153 return;
2156 DEBUG(3,("wins_process_name_release_request: %s name release for name %s \
2157 IP %s\n", releasing_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
2160 * Deal with policy regarding 0x1d names.
2163 if(!releasing_group_name && (question->name_type == 0x1d)) {
2164 DEBUG(3,("wins_process_name_release_request: Ignoring request \
2165 to release name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
2166 send_wins_name_release_response(0, p);
2167 return;
2171 * See if the name already exists.
2174 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2176 if( (namerec == NULL) || ((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) ) {
2177 send_wins_name_release_response(NAM_ERR, p);
2178 return;
2182 * Check that the sending machine has permission to release this name.
2183 * If it's a group name not ending in 0x1c then just say yes and let
2184 * the group time out.
2187 if(releasing_group_name && (question->name_type != 0x1c)) {
2188 send_wins_name_release_response(0, p);
2189 return;
2193 * Check that the releasing node is on the list of IP addresses
2194 * for this name. Disallow the release if not.
2197 if(!find_ip_in_name_record(namerec, from_ip)) {
2198 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2199 release name %s as IP %s is not one of the known IP's for this name.\n",
2200 nmb_namestr(question), inet_ntoa(from_ip) ));
2201 send_wins_name_release_response(NAM_ERR, p);
2202 return;
2206 * Check if the record is active. IF it's already released
2207 * or tombstoned, refuse the release.
2210 if (!WINS_STATE_ACTIVE(namerec)) {
2211 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2212 release name %s as this record is not active anymore.\n", nmb_namestr(question) ));
2213 send_wins_name_release_response(NAM_ERR, p);
2214 return;
2218 * Check if the record is a 0x1c group
2219 * and has more then one ip
2220 * remove only this address.
2223 if(releasing_group_name && (question->name_type == 0x1c) && (namerec->data.num_ips > 1)) {
2224 remove_ip_from_name_record(namerec, from_ip);
2225 DEBUG(3,("wins_process_name_release_request: Remove IP %s from NAME: %s\n",
2226 inet_ntoa(from_ip),nmb_namestr(question)));
2227 wins_hook("delete", namerec, 0);
2228 send_wins_name_release_response(0, p);
2229 return;
2233 * Send a release response.
2234 * Flag the name as released and update the ttl
2237 namerec->data.wins_flags |= WINS_RELEASED;
2238 update_name_ttl(namerec, EXTINCTION_INTERVAL);
2240 wins_hook("delete", namerec, 0);
2241 send_wins_name_release_response(0, p);
2244 /*******************************************************************
2245 WINS time dependent processing.
2246 ******************************************************************/
2248 static int wins_processing_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2250 time_t t = *(time_t *)state;
2251 bool store_record = False;
2252 struct name_record *namerec = NULL;
2253 struct in_addr our_fake_ip;
2255 our_fake_ip = interpret_addr2("0.0.0.0");
2256 if (kbuf.dsize != sizeof(unstring) + 1) {
2257 return 0;
2260 namerec = wins_record_to_name_record(kbuf, dbuf);
2261 if (!namerec) {
2262 return 0;
2265 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
2266 if( namerec->data.source == SELF_NAME ) {
2267 DEBUG( 3, ( "wins_processing_traverse_fn: Subnet %s not expiring SELF name %s\n",
2268 wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) );
2269 namerec->data.death_time += 300;
2270 store_record = True;
2271 goto done;
2272 } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) {
2273 DEBUG(3,("wins_processing_traverse_fn: deleting timed out DNS name %s\n",
2274 nmb_namestr(&namerec->name)));
2275 remove_name_from_wins_namelist(namerec );
2276 goto done;
2279 /* handle records, samba is the wins owner */
2280 if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
2281 switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2282 case WINS_ACTIVE:
2283 namerec->data.wins_flags&=~WINS_STATE_MASK;
2284 namerec->data.wins_flags|=WINS_RELEASED;
2285 namerec->data.death_time = t + EXTINCTION_INTERVAL;
2286 DEBUG(3,("wins_processing_traverse_fn: expiring %s\n",
2287 nmb_namestr(&namerec->name)));
2288 store_record = True;
2289 goto done;
2290 case WINS_RELEASED:
2291 namerec->data.wins_flags&=~WINS_STATE_MASK;
2292 namerec->data.wins_flags|=WINS_TOMBSTONED;
2293 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2294 get_global_id_and_update(&namerec->data.id, True);
2295 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2296 nmb_namestr(&namerec->name)));
2297 store_record = True;
2298 goto done;
2299 case WINS_TOMBSTONED:
2300 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2301 nmb_namestr(&namerec->name)));
2302 remove_name_from_wins_namelist(namerec );
2303 goto done;
2305 } else {
2306 switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2307 case WINS_ACTIVE:
2308 /* that's not as MS says it should be */
2309 namerec->data.wins_flags&=~WINS_STATE_MASK;
2310 namerec->data.wins_flags|=WINS_TOMBSTONED;
2311 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
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;
2321 case WINS_RELEASED:
2322 DEBUG(0,("wins_processing_traverse_fn: %s is in released state and\
2323 we are not the wins owner !\n", nmb_namestr(&namerec->name)));
2324 goto done;
2329 done:
2331 if (store_record) {
2332 wins_store_changed_namerec(namerec);
2335 SAFE_FREE(namerec->data.ip);
2336 SAFE_FREE(namerec);
2338 return 0;
2341 /*******************************************************************
2342 Time dependent wins processing.
2343 ******************************************************************/
2345 void initiate_wins_processing(time_t t)
2347 static time_t lasttime = 0;
2349 if (!lasttime) {
2350 lasttime = t;
2352 if (t - lasttime < 20) {
2353 return;
2356 if(!lp_we_are_a_wins_server()) {
2357 lasttime = t;
2358 return;
2361 tdb_traverse(wins_tdb, wins_processing_traverse_fn, &t);
2363 wins_delete_all_tmp_in_memory_records();
2365 wins_write_database(t, True);
2367 lasttime = t;
2370 /*******************************************************************
2371 Write out one record.
2372 ******************************************************************/
2374 void wins_write_name_record(struct name_record *namerec, XFILE *fp)
2376 int i;
2377 struct tm *tm;
2379 DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) ));
2381 if( namerec->data.death_time != PERMANENT_TTL ) {
2382 char *ts, *nl;
2384 tm = localtime(&namerec->data.death_time);
2385 if (!tm) {
2386 return;
2388 ts = asctime(tm);
2389 if (!ts) {
2390 return;
2392 nl = strrchr( ts, '\n' );
2393 if( NULL != nl ) {
2394 *nl = '\0';
2396 DEBUGADD(4,("TTL = %s ", ts ));
2397 } else {
2398 DEBUGADD(4,("TTL = PERMANENT "));
2401 for (i = 0; i < namerec->data.num_ips; i++) {
2402 DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) ));
2404 DEBUGADD(4,("%2x\n", namerec->data.nb_flags ));
2406 if( namerec->data.source == REGISTER_NAME ) {
2407 unstring name;
2408 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
2409 x_fprintf(fp, "\"%s#%02x\" %d ", name,namerec->name.name_type, /* Ignore scope. */
2410 (int)namerec->data.death_time);
2412 for (i = 0; i < namerec->data.num_ips; i++)
2413 x_fprintf( fp, "%s ", inet_ntoa( namerec->data.ip[i] ) );
2414 x_fprintf( fp, "%2xR\n", namerec->data.nb_flags );
2418 /*******************************************************************
2419 Write out the current WINS database.
2420 ******************************************************************/
2422 static int wins_writedb_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2424 struct name_record *namerec = NULL;
2425 XFILE *fp = (XFILE *)state;
2427 if (kbuf.dsize != sizeof(unstring) + 1) {
2428 return 0;
2431 namerec = wins_record_to_name_record(kbuf, dbuf);
2432 if (!namerec) {
2433 return 0;
2436 wins_write_name_record(namerec, fp);
2438 SAFE_FREE(namerec->data.ip);
2439 SAFE_FREE(namerec);
2440 return 0;
2444 void wins_write_database(time_t t, bool background)
2446 static time_t last_write_time = 0;
2447 char *fname = NULL;
2448 char *fnamenew = NULL;
2450 XFILE *fp;
2452 if (background) {
2453 if (!last_write_time) {
2454 last_write_time = t;
2456 if (t - last_write_time < 120) {
2457 return;
2462 if(!lp_we_are_a_wins_server()) {
2463 return;
2466 /* We will do the writing in a child process to ensure that the parent doesn't block while this is done */
2467 if (background) {
2468 CatchChild();
2469 if (sys_fork()) {
2470 return;
2472 if (tdb_reopen(wins_tdb)) {
2473 DEBUG(0,("wins_write_database: tdb_reopen failed. Error was %s\n",
2474 strerror(errno)));
2475 _exit(0);
2476 return;
2480 if (!(fname = state_path(WINS_LIST))) {
2481 goto err_exit;
2483 /* This is safe as the 0 length means "don't expand". */
2484 all_string_sub(fname,"//", "/", 0);
2486 if (asprintf(&fnamenew, "%s.%u", fname, (unsigned int)sys_getpid()) < 0) {
2487 goto err_exit;
2490 if((fp = x_fopen(fnamenew,O_WRONLY|O_CREAT,0644)) == NULL) {
2491 DEBUG(0,("wins_write_database: Can't open %s. Error was %s\n", fnamenew, strerror(errno)));
2492 goto err_exit;
2495 DEBUG(4,("wins_write_database: Dump of WINS name list.\n"));
2497 x_fprintf(fp,"VERSION %d %u\n", WINS_VERSION, 0);
2499 tdb_traverse(wins_tdb, wins_writedb_traverse_fn, fp);
2501 x_fclose(fp);
2502 chmod(fnamenew,0644);
2503 unlink(fname);
2504 rename(fnamenew,fname);
2506 err_exit:
2508 SAFE_FREE(fnamenew);
2509 TALLOC_FREE(fname);
2511 if (background) {
2512 _exit(0);
2516 #if 0
2517 Until winsrepl is done.
2518 /****************************************************************************
2519 Process a internal Samba message receiving a wins record.
2520 ***************************************************************************/
2522 void nmbd_wins_new_entry(struct messaging_context *msg,
2523 void *private_data,
2524 uint32_t msg_type,
2525 struct server_id server_id,
2526 DATA_BLOB *data)
2528 WINS_RECORD *record;
2529 struct name_record *namerec = NULL;
2530 struct name_record *new_namerec = NULL;
2531 struct nmb_name question;
2532 bool overwrite=False;
2533 struct in_addr our_fake_ip;
2534 int i;
2536 our_fake_ip = interpret_addr2("0.0.0.0");
2537 if (buf==NULL) {
2538 return;
2541 /* Record should use UNIX codepage. Ensure this is so in the wrepld code. JRA. */
2542 record=(WINS_RECORD *)buf;
2544 make_nmb_name(&question, record->name, record->type);
2546 namerec = find_name_on_subnet(wins_server_subnet, &question, FIND_ANY_NAME);
2548 /* record doesn't exist, add it */
2549 if (namerec == NULL) {
2550 DEBUG(3,("nmbd_wins_new_entry: adding new replicated record: %s<%02x> for wins server: %s\n",
2551 record->name, record->type, inet_ntoa(record->wins_ip)));
2553 new_namerec=add_name_to_subnet( wins_server_subnet,
2554 record->name,
2555 record->type,
2556 record->nb_flags,
2557 EXTINCTION_INTERVAL,
2558 REGISTER_NAME,
2559 record->num_ips,
2560 record->ip);
2562 if (new_namerec!=NULL) {
2563 update_wins_owner(new_namerec, record->wins_ip);
2564 update_wins_flag(new_namerec, record->wins_flags);
2565 new_namerec->data.id=record->id;
2567 wins_server_subnet->namelist_changed = True;
2571 /* check if we have a conflict */
2572 if (namerec != NULL) {
2573 /* both records are UNIQUE */
2574 if (namerec->data.wins_flags&WINS_UNIQUE && record->wins_flags&WINS_UNIQUE) {
2576 /* the database record is a replica */
2577 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
2578 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED) {
2579 if (ip_equal_v4(namerec->data.wins_ip, record->wins_ip))
2580 overwrite=True;
2581 } else
2582 overwrite=True;
2583 } else {
2584 /* we are the wins owner of the database record */
2585 /* the 2 records have the same IP address */
2586 if (ip_equal_v4(namerec->data.ip[0], record->ip[0])) {
2587 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED)
2588 get_global_id_and_update(&namerec->data.id, True);
2589 else
2590 overwrite=True;
2592 } else {
2593 /* the 2 records have different IP address */
2594 if (namerec->data.wins_flags&WINS_ACTIVE) {
2595 if (record->wins_flags&WINS_TOMBSTONED)
2596 get_global_id_and_update(&namerec->data.id, True);
2597 if (record->wins_flags&WINS_ACTIVE)
2598 /* send conflict challenge to the replica node */
2600 } else
2601 overwrite=True;
2607 /* the replica is a standard group */
2608 if (record->wins_flags&WINS_NGROUP || record->wins_flags&WINS_SGROUP) {
2609 /* if the database record is unique and active force a name release */
2610 if (namerec->data.wins_flags&WINS_UNIQUE)
2611 /* send a release name to the unique node */
2613 overwrite=True;
2617 /* the replica is a special group */
2618 if (record->wins_flags&WINS_SGROUP && namerec->data.wins_flags&WINS_SGROUP) {
2619 if (namerec->data.wins_flags&WINS_ACTIVE) {
2620 for (i=0; i<record->num_ips; i++)
2621 if(!find_ip_in_name_record(namerec, record->ip[i]))
2622 add_ip_to_name_record(namerec, record->ip[i]);
2623 } else {
2624 overwrite=True;
2628 /* the replica is a multihomed host */
2630 /* I'm giving up on multi homed. Too much complex to understand */
2632 if (record->wins_flags&WINS_MHOMED) {
2633 if (! (namerec->data.wins_flags&WINS_ACTIVE)) {
2634 if ( !(namerec->data.wins_flags&WINS_RELEASED) && !(namerec->data.wins_flags&WINS_NGROUP))
2635 overwrite=True;
2637 else {
2638 if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
2639 overwrite=True;
2641 if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip))
2642 if (namerec->data.wins_flags&WINS_UNIQUE)
2643 get_global_id_and_update(&namerec->data.id, True);
2647 if (record->wins_flags&WINS_ACTIVE && namerec->data.wins_flags&WINS_ACTIVE)
2648 if (namerec->data.wins_flags&WINS_UNIQUE ||
2649 namerec->data.wins_flags&WINS_MHOMED)
2650 if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
2651 overwrite=True;
2655 if (overwrite == False)
2656 DEBUG(3, ("nmbd_wins_new_entry: conflict in adding record: %s<%02x> from wins server: %s\n",
2657 record->name, record->type, inet_ntoa(record->wins_ip)));
2658 else {
2659 DEBUG(3, ("nmbd_wins_new_entry: replacing record: %s<%02x> from wins server: %s\n",
2660 record->name, record->type, inet_ntoa(record->wins_ip)));
2662 /* remove the old record and add a new one */
2663 remove_name_from_namelist( wins_server_subnet, namerec );
2664 new_namerec=add_name_to_subnet( wins_server_subnet, record->name, record->type, record->nb_flags,
2665 EXTINCTION_INTERVAL, REGISTER_NAME, record->num_ips, record->ip);
2666 if (new_namerec!=NULL) {
2667 update_wins_owner(new_namerec, record->wins_ip);
2668 update_wins_flag(new_namerec, record->wins_flags);
2669 new_namerec->data.id=record->id;
2671 wins_server_subnet->namelist_changed = True;
2674 wins_server_subnet->namelist_changed = True;
2679 #endif