WHATSNEW: Update changes.
[Samba.git] / source / nmbd / nmbd_winsserver.c
blob96938b011a26c05d888653dc003f27477baa2df7
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 Convert a wins.tdb record to a struct name_record. Add in our global_scope().
56 *****************************************************************************/
58 static struct name_record *wins_record_to_name_record(TDB_DATA key, TDB_DATA data)
60 struct name_record *namerec = NULL;
61 uint16 nb_flags;
62 unsigned char nr_src;
63 uint32 death_time, refresh_time;
64 uint32 id_low, id_high;
65 uint32 saddr;
66 uint32 wins_flags;
67 uint32 num_ips;
68 size_t len;
69 int i;
71 if (data.dptr == NULL || data.dsize == 0) {
72 return NULL;
75 /* Min size is "wbddddddd" + 1 ip address (4). */
76 if (data.dsize < 2 + 1 + (7*4) + 4) {
77 return NULL;
80 len = tdb_unpack(data.dptr, data.dsize,
81 "wbddddddd",
82 &nb_flags,
83 &nr_src,
84 &death_time,
85 &refresh_time,
86 &id_low,
87 &id_high,
88 &saddr,
89 &wins_flags,
90 &num_ips );
92 namerec = SMB_MALLOC_P(struct name_record);
93 if (!namerec) {
94 return NULL;
96 ZERO_STRUCTP(namerec);
98 namerec->data.ip = SMB_MALLOC_ARRAY(struct in_addr, num_ips);
99 if (!namerec->data.ip) {
100 SAFE_FREE(namerec);
101 return NULL;
104 namerec->subnet = wins_server_subnet;
105 push_ascii_nstring(namerec->name.name, (const char *)key.dptr);
106 namerec->name.name_type = key.dptr[sizeof(unstring)];
107 /* Add the scope. */
108 push_ascii(namerec->name.scope, global_scope(), 64, STR_TERMINATE);
110 /* We're using a byte-by-byte compare, so we must be sure that
111 * unused space doesn't have garbage in it.
114 for( i = strlen( namerec->name.name ); i < sizeof( namerec->name.name ); i++ ) {
115 namerec->name.name[i] = '\0';
117 for( i = strlen( namerec->name.scope ); i < sizeof( namerec->name.scope ); i++ ) {
118 namerec->name.scope[i] = '\0';
121 namerec->data.nb_flags = nb_flags;
122 namerec->data.source = (enum name_source)nr_src;
123 namerec->data.death_time = (time_t)death_time;
124 namerec->data.refresh_time = (time_t)refresh_time;
125 namerec->data.id = id_low;
126 #if defined(HAVE_LONGLONG)
127 namerec->data.id |= ((SMB_BIG_UINT)id_high << 32);
128 #endif
129 namerec->data.wins_ip.s_addr = saddr;
130 namerec->data.wins_flags = wins_flags,
131 namerec->data.num_ips = num_ips;
133 for (i = 0; i < num_ips; i++) {
134 namerec->data.ip[i].s_addr = IVAL(data.dptr, len + (i*4));
137 return namerec;
140 /****************************************************************************
141 Convert a struct name_record to a wins.tdb record. Ignore the scope.
142 *****************************************************************************/
144 static TDB_DATA name_record_to_wins_record(const struct name_record *namerec)
146 TDB_DATA data;
147 size_t len = 0;
148 int i;
149 uint32 id_low = (namerec->data.id & 0xFFFFFFFF);
150 #if defined(HAVE_LONGLONG)
151 uint32 id_high = (namerec->data.id >> 32) & 0xFFFFFFFF;
152 #else
153 uint32 id_high = 0;
154 #endif
156 ZERO_STRUCT(data);
158 len = (2 + 1 + (7*4)); /* "wbddddddd" */
159 len += (namerec->data.num_ips * 4);
161 data.dptr = (uint8 *)SMB_MALLOC(len);
162 if (!data.dptr) {
163 return data;
165 data.dsize = len;
167 len = tdb_pack(data.dptr, data.dsize, "wbddddddd",
168 namerec->data.nb_flags,
169 (unsigned char)namerec->data.source,
170 (uint32)namerec->data.death_time,
171 (uint32)namerec->data.refresh_time,
172 id_low,
173 id_high,
174 (uint32)namerec->data.wins_ip.s_addr,
175 (uint32)namerec->data.wins_flags,
176 (uint32)namerec->data.num_ips );
178 for (i = 0; i < namerec->data.num_ips; i++) {
179 SIVAL(data.dptr, len + (i*4), namerec->data.ip[i].s_addr);
182 return data;
185 /****************************************************************************
186 Create key. Key is UNIX codepage namestring (usually utf8 64 byte len) with 1 byte type.
187 *****************************************************************************/
189 static TDB_DATA name_to_key(const struct nmb_name *nmbname)
191 static char keydata[sizeof(unstring) + 1];
192 TDB_DATA key;
194 memset(keydata, '\0', sizeof(keydata));
196 pull_ascii_nstring(keydata, sizeof(unstring), nmbname->name);
197 strupper_m(keydata);
198 keydata[sizeof(unstring)] = nmbname->name_type;
199 key.dptr = (uint8 *)keydata;
200 key.dsize = sizeof(keydata);
202 return key;
205 /****************************************************************************
206 Lookup a given name in the wins.tdb and create a temporary malloc'ed data struct
207 on the linked list. We will free this later in XXXX().
208 *****************************************************************************/
210 struct name_record *find_name_on_wins_subnet(const struct nmb_name *nmbname, bool self_only)
212 TDB_DATA data, key;
213 struct name_record *nr = NULL;
214 struct name_record *namerec = NULL;
216 if (!wins_tdb) {
217 return NULL;
220 key = name_to_key(nmbname);
221 data = tdb_fetch(wins_tdb, key);
223 if (data.dsize == 0) {
224 return NULL;
227 namerec = wins_record_to_name_record(key, data);
229 /* done with the this */
231 SAFE_FREE( data.dptr );
233 if (!namerec) {
234 return NULL;
237 /* Self names only - these include permanent names. */
238 if( self_only && (namerec->data.source != SELF_NAME) && (namerec->data.source != PERMANENT_NAME) ) {
239 DEBUG( 9, ( "find_name_on_wins_subnet: self name %s NOT FOUND\n", nmb_namestr(nmbname) ) );
240 SAFE_FREE(namerec->data.ip);
241 SAFE_FREE(namerec);
242 return NULL;
245 /* Search for this name record on the list. Replace it if found. */
247 for( nr = wins_server_subnet->namelist; nr; nr = nr->next) {
248 if (memcmp(nmbname->name, nr->name.name, 16) == 0) {
249 /* Delete it. */
250 DLIST_REMOVE(wins_server_subnet->namelist, nr);
251 SAFE_FREE(nr->data.ip);
252 SAFE_FREE(nr);
253 break;
257 DLIST_ADD(wins_server_subnet->namelist, namerec);
258 return namerec;
261 /****************************************************************************
262 Overwrite or add a given name in the wins.tdb.
263 *****************************************************************************/
265 static bool store_or_replace_wins_namerec(const struct name_record *namerec, int tdb_flag)
267 TDB_DATA key, data;
268 int ret;
270 if (!wins_tdb) {
271 return False;
274 key = name_to_key(&namerec->name);
275 data = name_record_to_wins_record(namerec);
277 if (data.dptr == NULL) {
278 return False;
281 ret = tdb_store(wins_tdb, key, data, tdb_flag);
283 SAFE_FREE(data.dptr);
284 return (ret == 0) ? True : False;
287 /****************************************************************************
288 Overwrite a given name in the wins.tdb.
289 *****************************************************************************/
291 bool wins_store_changed_namerec(const struct name_record *namerec)
293 return store_or_replace_wins_namerec(namerec, TDB_REPLACE);
296 /****************************************************************************
297 Primary interface into creating and overwriting records in the wins.tdb.
298 *****************************************************************************/
300 bool add_name_to_wins_subnet(const struct name_record *namerec)
302 return store_or_replace_wins_namerec(namerec, TDB_INSERT);
305 /****************************************************************************
306 Delete a given name in the tdb and remove the temporary malloc'ed data struct
307 on the linked list.
308 *****************************************************************************/
310 bool remove_name_from_wins_namelist(struct name_record *namerec)
312 TDB_DATA key;
313 int ret;
315 if (!wins_tdb) {
316 return False;
319 key = name_to_key(&namerec->name);
320 ret = tdb_delete(wins_tdb, key);
322 DLIST_REMOVE(wins_server_subnet->namelist, namerec);
324 /* namerec must be freed by the caller */
326 return (ret == 0) ? True : False;
329 /****************************************************************************
330 Dump out the complete namelist.
331 *****************************************************************************/
333 static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
335 struct name_record *namerec = NULL;
336 XFILE *fp = (XFILE *)state;
338 if (kbuf.dsize != sizeof(unstring) + 1) {
339 return 0;
342 namerec = wins_record_to_name_record(kbuf, dbuf);
343 if (!namerec) {
344 return 0;
347 dump_name_record(namerec, fp);
349 SAFE_FREE(namerec->data.ip);
350 SAFE_FREE(namerec);
351 return 0;
354 void dump_wins_subnet_namelist(XFILE *fp)
356 tdb_traverse(wins_tdb, traverse_fn, (void *)fp);
359 /****************************************************************************
360 Change the wins owner address in the record.
361 *****************************************************************************/
363 static void update_wins_owner(struct name_record *namerec, struct in_addr wins_ip)
365 namerec->data.wins_ip=wins_ip;
368 /****************************************************************************
369 Create the wins flags based on the nb flags and the input value.
370 *****************************************************************************/
372 static void update_wins_flag(struct name_record *namerec, int flags)
374 namerec->data.wins_flags=0x0;
376 /* if it's a group, it can be a normal or a special one */
377 if (namerec->data.nb_flags & NB_GROUP) {
378 if (namerec->name.name_type==0x1C) {
379 namerec->data.wins_flags|=WINS_SGROUP;
380 } else {
381 if (namerec->data.num_ips>1) {
382 namerec->data.wins_flags|=WINS_SGROUP;
383 } else {
384 namerec->data.wins_flags|=WINS_NGROUP;
387 } else {
388 /* can be unique or multi-homed */
389 if (namerec->data.num_ips>1) {
390 namerec->data.wins_flags|=WINS_MHOMED;
391 } else {
392 namerec->data.wins_flags|=WINS_UNIQUE;
396 /* the node type are the same bits */
397 namerec->data.wins_flags|=namerec->data.nb_flags&NB_NODETYPEMASK;
399 /* the static bit is elsewhere */
400 if (namerec->data.death_time == PERMANENT_TTL) {
401 namerec->data.wins_flags|=WINS_STATIC;
404 /* and add the given bits */
405 namerec->data.wins_flags|=flags;
407 DEBUG(8,("update_wins_flag: nbflags: 0x%x, ttl: 0x%d, flags: 0x%x, winsflags: 0x%x\n",
408 namerec->data.nb_flags, (int)namerec->data.death_time, flags, namerec->data.wins_flags));
411 /****************************************************************************
412 Return the general ID value and increase it if requested.
413 *****************************************************************************/
415 static void get_global_id_and_update(SMB_BIG_UINT *current_id, bool update)
418 * it's kept as a static here, to prevent people from messing
419 * with the value directly
422 static SMB_BIG_UINT general_id = 1;
424 DEBUG(5,("get_global_id_and_update: updating version ID: %d\n", (int)general_id));
426 *current_id = general_id;
428 if (update) {
429 general_id++;
433 /****************************************************************************
434 Possibly call the WINS hook external program when a WINS change is made.
435 Also stores the changed record back in the wins_tdb.
436 *****************************************************************************/
438 static void wins_hook(const char *operation, struct name_record *namerec, int ttl)
440 char *command = NULL;
441 char *cmd = lp_wins_hook();
442 char *p, *namestr;
443 int i;
444 TALLOC_CTX *ctx = talloc_tos();
446 wins_store_changed_namerec(namerec);
448 if (!cmd || !*cmd) {
449 return;
452 for (p=namerec->name.name; *p; p++) {
453 if (!(isalnum((int)*p) || strchr_m("._-",*p))) {
454 DEBUG(3,("not calling wins hook for invalid name %s\n", nmb_namestr(&namerec->name)));
455 return;
459 /* Use the name without the nametype (and scope) appended */
461 namestr = nmb_namestr(&namerec->name);
462 if ((p = strchr(namestr, '<'))) {
463 *p = 0;
466 command = talloc_asprintf(ctx,
467 "%s %s %s %02x %d",
468 cmd,
469 operation,
470 namestr,
471 namerec->name.name_type,
472 ttl);
473 if (!command) {
474 return;
477 for (i=0;i<namerec->data.num_ips;i++) {
478 command = talloc_asprintf_append(command,
479 " %s",
480 inet_ntoa(namerec->data.ip[i]));
481 if (!command) {
482 return;
486 DEBUG(3,("calling wins hook for %s\n", nmb_namestr(&namerec->name)));
487 smbrun(command, NULL);
488 TALLOC_FREE(command);
491 /****************************************************************************
492 Determine if this packet should be allocated to the WINS server.
493 *****************************************************************************/
495 bool packet_is_for_wins_server(struct packet_struct *packet)
497 struct nmb_packet *nmb = &packet->packet.nmb;
499 /* Only unicast packets go to a WINS server. */
500 if((wins_server_subnet == NULL) || (nmb->header.nm_flags.bcast == True)) {
501 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #1.\n"));
502 return False;
505 /* Check for node status requests. */
506 if (nmb->question.question_type != QUESTION_TYPE_NB_QUERY) {
507 return False;
510 switch(nmb->header.opcode) {
512 * A WINS server issues WACKS, not receives them.
514 case NMB_WACK_OPCODE:
515 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #2 (WACK).\n"));
516 return False;
518 * A WINS server only processes registration and
519 * release requests, not responses.
521 case NMB_NAME_REG_OPCODE:
522 case NMB_NAME_MULTIHOMED_REG_OPCODE:
523 case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
524 case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
525 if(nmb->header.response) {
526 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #3 (response = 1).\n"));
527 return False;
529 break;
531 case NMB_NAME_RELEASE_OPCODE:
532 if(nmb->header.response) {
533 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #4 (response = 1).\n"));
534 return False;
536 break;
539 * Only process unicast name queries with rd = 1.
541 case NMB_NAME_QUERY_OPCODE:
542 if(!nmb->header.response && !nmb->header.nm_flags.recursion_desired) {
543 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #5 (response = 1).\n"));
544 return False;
546 break;
549 return True;
552 /****************************************************************************
553 Utility function to decide what ttl to give a register/refresh request.
554 *****************************************************************************/
556 static int get_ttl_from_packet(struct nmb_packet *nmb)
558 int ttl = nmb->additional->ttl;
560 if (ttl < lp_min_wins_ttl()) {
561 ttl = lp_min_wins_ttl();
564 if (ttl > lp_max_wins_ttl()) {
565 ttl = lp_max_wins_ttl();
568 return ttl;
571 /****************************************************************************
572 Load or create the WINS database.
573 *****************************************************************************/
575 bool initialise_wins(void)
577 time_t time_now = time(NULL);
578 XFILE *fp;
579 char line[1024];
581 if(!lp_we_are_a_wins_server()) {
582 return True;
585 /* Open the wins.tdb. */
586 wins_tdb = tdb_open_log(lock_path("wins.tdb"), 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST, O_CREAT|O_RDWR, 0600);
587 if (!wins_tdb) {
588 DEBUG(0,("initialise_wins: failed to open wins.tdb. Error was %s\n",
589 strerror(errno) ));
590 return False;
593 tdb_store_int32(wins_tdb, "WINSDB_VERSION", WINSDB_VERSION);
595 add_samba_names_to_subnet(wins_server_subnet);
597 if((fp = x_fopen(state_path(WINS_LIST),O_RDONLY,0)) == NULL) {
598 DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
599 WINS_LIST, strerror(errno) ));
600 return True;
603 while (!x_feof(fp)) {
604 char *name_str = NULL;
605 char *ip_str = NULL;
606 char *ttl_str = NULL, *nb_flags_str = NULL;
607 unsigned int num_ips;
608 char *name = NULL;
609 struct in_addr *ip_list = NULL;
610 int type = 0;
611 int nb_flags;
612 int ttl;
613 const char *ptr;
614 char *p = NULL;
615 bool got_token;
616 bool was_ip;
617 int i;
618 unsigned int hash;
619 int version;
620 TALLOC_CTX *frame = NULL;
622 /* Read a line from the wins.dat file. Strips whitespace
623 from the beginning and end of the line. */
624 if (!fgets_slash(line,sizeof(line),fp)) {
625 continue;
628 if (*line == '#') {
629 continue;
632 if (strncmp(line,"VERSION ", 8) == 0) {
633 if (sscanf(line,"VERSION %d %u", &version, &hash) != 2 ||
634 version != WINS_VERSION) {
635 DEBUG(0,("Discarding invalid wins.dat file [%s]\n",line));
636 x_fclose(fp);
637 return True;
639 continue;
642 ptr = line;
645 * Now we handle multiple IP addresses per name we need
646 * to iterate over the line twice. The first time to
647 * determine how many IP addresses there are, the second
648 * time to actually parse them into the ip_list array.
651 frame = talloc_stackframe();
652 if (!next_token_talloc(frame,&ptr,&name_str,NULL)) {
653 DEBUG(0,("initialise_wins: Failed to parse name when parsing line %s\n", line ));
654 TALLOC_FREE(frame);
655 continue;
658 if (!next_token_talloc(frame,&ptr,&ttl_str,NULL)) {
659 DEBUG(0,("initialise_wins: Failed to parse time to live when parsing line %s\n", line ));
660 TALLOC_FREE(frame);
661 continue;
665 * Determine the number of IP addresses per line.
667 num_ips = 0;
668 do {
669 got_token = next_token_talloc(frame,&ptr,&ip_str,NULL);
670 was_ip = False;
672 if(got_token && strchr(ip_str, '.')) {
673 num_ips++;
674 was_ip = True;
676 } while(got_token && was_ip);
678 if(num_ips == 0) {
679 DEBUG(0,("initialise_wins: Missing IP address when parsing line %s\n", line ));
680 TALLOC_FREE(frame);
681 continue;
684 if(!got_token) {
685 DEBUG(0,("initialise_wins: Missing nb_flags when parsing line %s\n", line ));
686 TALLOC_FREE(frame);
687 continue;
690 /* Allocate the space for the ip_list. */
691 if((ip_list = SMB_MALLOC_ARRAY( struct in_addr, num_ips)) == NULL) {
692 DEBUG(0,("initialise_wins: Malloc fail !\n"));
693 x_fclose(fp);
694 TALLOC_FREE(frame);
695 return False;
698 /* Reset and re-parse the line. */
699 ptr = line;
700 next_token_talloc(frame,&ptr,&name_str,NULL);
701 next_token_talloc(frame,&ptr,&ttl_str,NULL);
702 for(i = 0; i < num_ips; i++) {
703 next_token_talloc(frame,&ptr, &ip_str, NULL);
704 (void)interpret_addr2(&ip_list[i], ip_str);
706 next_token_talloc(frame,&ptr,&nb_flags_str,NULL);
709 * Deal with SELF or REGISTER name encoding. Default is REGISTER
710 * for compatibility with old nmbds.
713 if(nb_flags_str[strlen(nb_flags_str)-1] == 'S') {
714 DEBUG(5,("initialise_wins: Ignoring SELF name %s\n", line));
715 SAFE_FREE(ip_list);
716 TALLOC_FREE(frame);
717 continue;
720 if(nb_flags_str[strlen(nb_flags_str)-1] == 'R') {
721 nb_flags_str[strlen(nb_flags_str)-1] = '\0';
724 /* Netbios name. # divides the name from the type (hex): netbios#xx */
725 name = name_str;
727 if((p = strchr(name,'#')) != NULL) {
728 *p = 0;
729 sscanf(p+1,"%x",&type);
732 /* Decode the netbios flags (hex) and the time-to-live (in seconds). */
733 sscanf(nb_flags_str,"%x",&nb_flags);
734 sscanf(ttl_str,"%d",&ttl);
736 /* add all entries that have 60 seconds or more to live */
737 if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) {
738 if(ttl != PERMANENT_TTL) {
739 ttl -= time_now;
742 DEBUG( 4, ("initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
743 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
745 (void)add_name_to_subnet( wins_server_subnet, name, type, nb_flags,
746 ttl, REGISTER_NAME, num_ips, ip_list );
747 } else {
748 DEBUG(4, ("initialise_wins: not adding name (ttl problem) "
749 "%s#%02x ttl = %d first IP %s flags = %2x\n",
750 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
753 TALLOC_FREE(frame);
754 SAFE_FREE(ip_list);
757 x_fclose(fp);
758 return True;
761 /****************************************************************************
762 Send a WINS WACK (Wait ACKnowledgement) response.
763 **************************************************************************/
765 static void send_wins_wack_response(int ttl, struct packet_struct *p)
767 struct nmb_packet *nmb = &p->packet.nmb;
768 unsigned char rdata[2];
770 rdata[0] = rdata[1] = 0;
772 /* Taken from nmblib.c - we need to send back almost
773 identical bytes from the requesting packet header. */
775 rdata[0] = (nmb->header.opcode & 0xF) << 3;
776 if (nmb->header.nm_flags.authoritative && nmb->header.response) {
777 rdata[0] |= 0x4;
779 if (nmb->header.nm_flags.trunc) {
780 rdata[0] |= 0x2;
782 if (nmb->header.nm_flags.recursion_desired) {
783 rdata[0] |= 0x1;
785 if (nmb->header.nm_flags.recursion_available && nmb->header.response) {
786 rdata[1] |= 0x80;
788 if (nmb->header.nm_flags.bcast) {
789 rdata[1] |= 0x10;
792 reply_netbios_packet(p, /* Packet to reply to. */
793 0, /* Result code. */
794 NMB_WAIT_ACK, /* nmbd type code. */
795 NMB_WACK_OPCODE, /* opcode. */
796 ttl, /* ttl. */
797 (char *)rdata, /* data to send. */
798 2); /* data length. */
801 /****************************************************************************
802 Send a WINS name registration response.
803 **************************************************************************/
805 static void send_wins_name_registration_response(int rcode, int ttl, struct packet_struct *p)
807 struct nmb_packet *nmb = &p->packet.nmb;
808 char rdata[6];
810 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
812 reply_netbios_packet(p, /* Packet to reply to. */
813 rcode, /* Result code. */
814 WINS_REG, /* nmbd type code. */
815 NMB_NAME_REG_OPCODE, /* opcode. */
816 ttl, /* ttl. */
817 rdata, /* data to send. */
818 6); /* data length. */
821 /***********************************************************************
822 Deal with a name refresh request to a WINS server.
823 ************************************************************************/
825 void wins_process_name_refresh_request( struct subnet_record *subrec,
826 struct packet_struct *p )
828 struct nmb_packet *nmb = &p->packet.nmb;
829 struct nmb_name *question = &nmb->question.question_name;
830 bool bcast = nmb->header.nm_flags.bcast;
831 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
832 bool group = (nb_flags & NB_GROUP) ? True : False;
833 struct name_record *namerec = NULL;
834 int ttl = get_ttl_from_packet(nmb);
835 struct in_addr from_ip;
836 struct in_addr our_fake_ip;
838 (void)interpret_addr2(&our_fake_ip, "0.0.0.0");
839 putip( (char *)&from_ip, &nmb->additional->rdata[2] );
841 if(bcast) {
843 * We should only get unicast name refresh packets here.
844 * Anyone trying to refresh broadcast should not be going
845 * to a WINS server. Log an error here.
847 if( DEBUGLVL( 0 ) ) {
848 dbgtext( "wins_process_name_refresh_request: " );
849 dbgtext( "Broadcast name refresh request received " );
850 dbgtext( "for name %s ", nmb_namestr(question) );
851 dbgtext( "from IP %s ", inet_ntoa(from_ip) );
852 dbgtext( "on subnet %s. ", subrec->subnet_name );
853 dbgtext( "Error - Broadcasts should not be sent " );
854 dbgtext( "to a WINS server\n" );
856 return;
859 if( DEBUGLVL( 3 ) ) {
860 dbgtext( "wins_process_name_refresh_request: " );
861 dbgtext( "Name refresh for name %s IP %s\n",
862 nmb_namestr(question), inet_ntoa(from_ip) );
866 * See if the name already exists.
867 * If not, handle it as a name registration and return.
869 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
872 * If this is a refresh request and the name doesn't exist then
873 * treat it like a registration request. This allows us to recover
874 * from errors (tridge)
876 if(namerec == NULL) {
877 if( DEBUGLVL( 3 ) ) {
878 dbgtext( "wins_process_name_refresh_request: " );
879 dbgtext( "Name refresh for name %s ",
880 nmb_namestr( question ) );
881 dbgtext( "and the name does not exist. Treating " );
882 dbgtext( "as registration.\n" );
884 wins_process_name_registration_request(subrec,p);
885 return;
889 * if the name is present but not active, simply remove it
890 * and treat the refresh request as a registration & return.
892 if (namerec != NULL && !WINS_STATE_ACTIVE(namerec)) {
893 if( DEBUGLVL( 5 ) ) {
894 dbgtext( "wins_process_name_refresh_request: " );
895 dbgtext( "Name (%s) in WINS ", nmb_namestr(question) );
896 dbgtext( "was not active - removing it.\n" );
898 remove_name_from_namelist( subrec, namerec );
899 namerec = NULL;
900 wins_process_name_registration_request( subrec, p );
901 return;
905 * Check that the group bits for the refreshing name and the
906 * name in our database match. If not, refuse the refresh.
907 * [crh: Why RFS_ERR instead of ACT_ERR? Is this what MS does?]
909 if( (namerec != NULL) &&
910 ( (group && !NAME_GROUP(namerec))
911 || (!group && NAME_GROUP(namerec)) ) ) {
912 if( DEBUGLVL( 3 ) ) {
913 dbgtext( "wins_process_name_refresh_request: " );
914 dbgtext( "Name %s ", nmb_namestr(question) );
915 dbgtext( "group bit = %s does not match ",
916 group ? "True" : "False" );
917 dbgtext( "group bit in WINS for this name.\n" );
919 send_wins_name_registration_response(RFS_ERR, 0, p);
920 return;
924 * For a unique name check that the person refreshing the name is
925 * one of the registered IP addresses. If not - fail the refresh.
926 * Do the same for group names with a type of 0x1c.
927 * Just return success for unique 0x1d refreshes. For normal group
928 * names update the ttl and return success.
930 if( (!group || (group && (question->name_type == 0x1c)))
931 && find_ip_in_name_record(namerec, from_ip) ) {
933 * Update the ttl.
935 update_name_ttl(namerec, ttl);
938 * if the record is a replica:
939 * we take ownership and update the version ID.
941 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
942 update_wins_owner(namerec, our_fake_ip);
943 get_global_id_and_update(&namerec->data.id, True);
946 send_wins_name_registration_response(0, ttl, p);
947 wins_hook("refresh", namerec, ttl);
948 return;
949 } else if((group && (question->name_type == 0x1c))) {
951 * Added by crh for bug #1079.
952 * Fix from Bert Driehuis
954 if( DEBUGLVL( 3 ) ) {
955 dbgtext( "wins_process_name_refresh_request: " );
956 dbgtext( "Name refresh for name %s, ",
957 nmb_namestr(question) );
958 dbgtext( "but IP address %s ", inet_ntoa(from_ip) );
959 dbgtext( "is not yet associated with " );
960 dbgtext( "that name. Treating as registration.\n" );
962 wins_process_name_registration_request(subrec,p);
963 return;
964 } else if(group) {
966 * Normal groups are all registered with an IP address of
967 * 255.255.255.255 so we can't search for the IP address.
969 update_name_ttl(namerec, ttl);
970 wins_hook("refresh", namerec, ttl);
971 send_wins_name_registration_response(0, ttl, p);
972 return;
973 } else if(!group && (question->name_type == 0x1d)) {
975 * Special name type - just pretend the refresh succeeded.
977 send_wins_name_registration_response(0, ttl, p);
978 return;
979 } else {
981 * Fail the refresh.
983 if( DEBUGLVL( 3 ) ) {
984 dbgtext( "wins_process_name_refresh_request: " );
985 dbgtext( "Name refresh for name %s with IP %s ",
986 nmb_namestr(question), inet_ntoa(from_ip) );
987 dbgtext( "and is IP is not known to the name.\n" );
989 send_wins_name_registration_response(RFS_ERR, 0, p);
990 return;
994 /***********************************************************************
995 Deal with a name registration request query success to a client that
996 owned the name.
998 We have a locked pointer to the original packet stashed away in the
999 userdata pointer. The success here is actually a failure as it means
1000 the client we queried wants to keep the name, so we must return
1001 a registration failure to the original requestor.
1002 ************************************************************************/
1004 static void wins_register_query_success(struct subnet_record *subrec,
1005 struct userdata_struct *userdata,
1006 struct nmb_name *question_name,
1007 struct in_addr ip,
1008 struct res_rec *answers)
1010 struct packet_struct *orig_reg_packet;
1012 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1014 DEBUG(3,("wins_register_query_success: Original client at IP %s still wants the \
1015 name %s. Rejecting registration request.\n", inet_ntoa(ip), nmb_namestr(question_name) ));
1017 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1019 orig_reg_packet->locked = False;
1020 free_packet(orig_reg_packet);
1023 /***********************************************************************
1024 Deal with a name registration request query failure to a client that
1025 owned the name.
1027 We have a locked pointer to the original packet stashed away in the
1028 userdata pointer. The failure here is actually a success as it means
1029 the client we queried didn't want to keep the name, so we can remove
1030 the old name record and then successfully add the new name.
1031 ************************************************************************/
1033 static void wins_register_query_fail(struct subnet_record *subrec,
1034 struct response_record *rrec,
1035 struct nmb_name *question_name,
1036 int rcode)
1038 struct userdata_struct *userdata = rrec->userdata;
1039 struct packet_struct *orig_reg_packet;
1040 struct name_record *namerec = NULL;
1042 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1045 * We want to just add the name, as we now know the original owner
1046 * didn't want it. But we can't just do that as an arbitary
1047 * amount of time may have taken place between the name query
1048 * request and this timeout/error response. So we check that
1049 * the name still exists and is in the same state - if so
1050 * we remove it and call wins_process_name_registration_request()
1051 * as we know it will do the right thing now.
1054 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1056 if ((namerec != NULL) && (namerec->data.source == REGISTER_NAME) &&
1057 ip_equal_v4(rrec->packet->ip, *namerec->data.ip)) {
1058 remove_name_from_namelist( subrec, namerec);
1059 namerec = NULL;
1062 if(namerec == NULL) {
1063 wins_process_name_registration_request(subrec, orig_reg_packet);
1064 } else {
1065 DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between "
1066 "querying for name %s in order to replace it and this reply.\n",
1067 nmb_namestr(question_name) ));
1070 orig_reg_packet->locked = False;
1071 free_packet(orig_reg_packet);
1074 /***********************************************************************
1075 Deal with a name registration request to a WINS server.
1077 Use the following pseudocode :
1079 registering_group
1082 +--------name exists
1085 | +--- existing name is group
1086 | | |
1087 | | |
1088 | | +--- add name (return).
1091 | +--- exiting name is unique
1094 | +--- query existing owner (return).
1097 +--------name doesn't exist
1100 +--- add name (return).
1102 registering_unique
1105 +--------name exists
1108 | +--- existing name is group
1109 | | |
1110 | | |
1111 | | +--- fail add (return).
1112 | |
1114 | +--- exiting name is unique
1117 | +--- query existing owner (return).
1120 +--------name doesn't exist
1123 +--- add name (return).
1125 As can be seen from the above, the two cases may be collapsed onto each
1126 other with the exception of the case where the name already exists and
1127 is a group name. This case we handle with an if statement.
1129 ************************************************************************/
1131 void wins_process_name_registration_request(struct subnet_record *subrec,
1132 struct packet_struct *p)
1134 unstring name;
1135 struct nmb_packet *nmb = &p->packet.nmb;
1136 struct nmb_name *question = &nmb->question.question_name;
1137 bool bcast = nmb->header.nm_flags.bcast;
1138 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
1139 int ttl = get_ttl_from_packet(nmb);
1140 struct name_record *namerec = NULL;
1141 struct in_addr from_ip;
1142 bool registering_group_name = (nb_flags & NB_GROUP) ? True : False;
1143 struct in_addr our_fake_ip;
1145 (void)interpret_addr2(&our_fake_ip, "0.0.0.0");
1146 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1148 if(bcast) {
1150 * We should only get unicast name registration packets here.
1151 * Anyone trying to register broadcast should not be going to a WINS
1152 * server. Log an error here.
1155 DEBUG(0,("wins_process_name_registration_request: broadcast name registration request \
1156 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1157 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1158 return;
1161 DEBUG(3,("wins_process_name_registration_request: %s name registration for name %s \
1162 IP %s\n", registering_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
1165 * See if the name already exists.
1168 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1171 * if the record exists but NOT in active state,
1172 * consider it dead.
1174 if ( (namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1175 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1176 not active - removing it.\n", nmb_namestr(question) ));
1177 remove_name_from_namelist( subrec, namerec );
1178 namerec = NULL;
1182 * Deal with the case where the name found was a dns entry.
1183 * Remove it as we now have a NetBIOS client registering the
1184 * name.
1187 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1188 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1189 a dns lookup - removing it.\n", nmb_namestr(question) ));
1190 remove_name_from_namelist( subrec, namerec );
1191 namerec = NULL;
1195 * Reject if the name exists and is not a REGISTER_NAME.
1196 * (ie. Don't allow any static names to be overwritten.
1199 if((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) {
1200 DEBUG( 3, ( "wins_process_name_registration_request: Attempt \
1201 to register name %s. Name already exists in WINS with source type %d.\n",
1202 nmb_namestr(question), namerec->data.source ));
1203 send_wins_name_registration_response(RFS_ERR, 0, p);
1204 return;
1208 * Special policy decisions based on MS documentation.
1209 * 1). All group names (except names ending in 0x1c) are added as 255.255.255.255.
1210 * 2). All unique names ending in 0x1d are ignored, although a positive response is sent.
1214 * A group name is always added as the local broadcast address, except
1215 * for group names ending in 0x1c.
1216 * Group names with type 0x1c are registered with individual IP addresses.
1219 if(registering_group_name && (question->name_type != 0x1c)) {
1220 (void)interpret_addr2(&from_ip, "255.255.255.255");
1224 * Ignore all attempts to register a unique 0x1d name, although return success.
1227 if(!registering_group_name && (question->name_type == 0x1d)) {
1228 DEBUG(3,("wins_process_name_registration_request: Ignoring request \
1229 to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
1230 send_wins_name_registration_response(0, ttl, p);
1231 return;
1235 * Next two cases are the 'if statement' mentioned above.
1238 if((namerec != NULL) && NAME_GROUP(namerec)) {
1239 if(registering_group_name) {
1241 * If we are adding a group name, the name exists and is also a group entry just add this
1242 * IP address to it and update the ttl.
1245 DEBUG(3,("wins_process_name_registration_request: Adding IP %s to group name %s.\n",
1246 inet_ntoa(from_ip), nmb_namestr(question) ));
1249 * Check the ip address is not already in the group.
1252 if(!find_ip_in_name_record(namerec, from_ip)) {
1253 add_ip_to_name_record(namerec, from_ip);
1254 /* we need to update the record for replication */
1255 get_global_id_and_update(&namerec->data.id, True);
1258 * if the record is a replica, we must change
1259 * the wins owner to us to make the replication updates
1260 * it on the other wins servers.
1261 * And when the partner will receive this record,
1262 * it will update its own record.
1265 update_wins_owner(namerec, our_fake_ip);
1267 update_name_ttl(namerec, ttl);
1268 wins_hook("refresh", namerec, ttl);
1269 send_wins_name_registration_response(0, ttl, p);
1270 return;
1271 } else {
1274 * If we are adding a unique name, the name exists in the WINS db
1275 * and is a group name then reject the registration.
1277 * explanation: groups have a higher priority than unique names.
1280 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1281 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1282 send_wins_name_registration_response(RFS_ERR, 0, p);
1283 return;
1288 * From here on down we know that if the name exists in the WINS db it is
1289 * a unique name, not a group name.
1293 * If the name exists and is one of our names then check the
1294 * registering IP address. If it's not one of ours then automatically
1295 * reject without doing the query - we know we will reject it.
1298 if ( namerec != NULL ) {
1299 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
1300 if( is_myname(name) ) {
1301 if(!ismyip_v4(from_ip)) {
1302 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1303 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1304 send_wins_name_registration_response(RFS_ERR, 0, p);
1305 return;
1306 } else {
1308 * It's one of our names and one of our IP's - update the ttl.
1310 update_name_ttl(namerec, ttl);
1311 wins_hook("refresh", namerec, ttl);
1312 send_wins_name_registration_response(0, ttl, p);
1313 return;
1316 } else {
1317 name[0] = '\0';
1321 * If the name exists and it is a unique registration and the registering IP
1322 * is the same as the (single) already registered IP then just update the ttl.
1324 * But not if the record is an active replica. IF it's a replica, it means it can be
1325 * the same client which has moved and not yet expired. So we don't update
1326 * the ttl in this case and go beyond to do a WACK and query the old client
1329 if( !registering_group_name
1330 && (namerec != NULL)
1331 && (namerec->data.num_ips == 1)
1332 && ip_equal_v4( namerec->data.ip[0], from_ip )
1333 && ip_equal_v4(namerec->data.wins_ip, our_fake_ip) ) {
1334 update_name_ttl( namerec, ttl );
1335 wins_hook("refresh", namerec, ttl);
1336 send_wins_name_registration_response( 0, ttl, p );
1337 return;
1341 * Finally if the name exists do a query to the registering machine
1342 * to see if they still claim to have the name.
1345 if( namerec != NULL ) {
1346 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1347 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1350 * First send a WACK to the registering machine.
1353 send_wins_wack_response(60, p);
1356 * When the reply comes back we need the original packet.
1357 * Lock this so it won't be freed and then put it into
1358 * the userdata structure.
1361 p->locked = True;
1363 userdata = (struct userdata_struct *)ud;
1365 userdata->copy_fn = NULL;
1366 userdata->free_fn = NULL;
1367 userdata->userdata_len = sizeof(struct packet_struct *);
1368 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1371 * Use the new call to send a query directly to an IP address.
1372 * This sends the query directly to the IP address, and ensures
1373 * the recursion desired flag is not set (you were right Luke :-).
1374 * This function should *only* be called from the WINS server
1375 * code. JRA.
1378 pull_ascii_nstring(name, sizeof(name), question->name);
1379 query_name_from_wins_server( *namerec->data.ip,
1380 name,
1381 question->name_type,
1382 wins_register_query_success,
1383 wins_register_query_fail,
1384 userdata );
1385 return;
1389 * Name did not exist - add it.
1392 pull_ascii_nstring(name, sizeof(name), question->name);
1393 add_name_to_subnet( subrec, name, question->name_type,
1394 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1396 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1397 get_global_id_and_update(&namerec->data.id, True);
1398 update_wins_owner(namerec, our_fake_ip);
1399 update_wins_flag(namerec, WINS_ACTIVE);
1400 wins_hook("add", namerec, ttl);
1403 send_wins_name_registration_response(0, ttl, p);
1406 /***********************************************************************
1407 Deal with a mutihomed name query success to the machine that
1408 requested the multihomed name registration.
1410 We have a locked pointer to the original packet stashed away in the
1411 userdata pointer.
1412 ************************************************************************/
1414 static void wins_multihomed_register_query_success(struct subnet_record *subrec,
1415 struct userdata_struct *userdata,
1416 struct nmb_name *question_name,
1417 struct in_addr ip,
1418 struct res_rec *answers)
1420 struct packet_struct *orig_reg_packet;
1421 struct nmb_packet *nmb;
1422 struct name_record *namerec = NULL;
1423 struct in_addr from_ip;
1424 int ttl;
1425 struct in_addr our_fake_ip;
1427 (void)interpret_addr2(&our_fake_ip, "0.0.0.0");
1428 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1430 nmb = &orig_reg_packet->packet.nmb;
1432 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1433 ttl = get_ttl_from_packet(nmb);
1436 * We want to just add the new IP, as we now know the requesting
1437 * machine claims to own it. But we can't just do that as an arbitary
1438 * amount of time may have taken place between the name query
1439 * request and this response. So we check that
1440 * the name still exists and is in the same state - if so
1441 * we just add the extra IP and update the ttl.
1444 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1446 if( (namerec == NULL) || (namerec->data.source != REGISTER_NAME) || !WINS_STATE_ACTIVE(namerec) ) {
1447 DEBUG(3,("wins_multihomed_register_query_success: name %s is not in the correct state to add \
1448 a subsequent IP address.\n", nmb_namestr(question_name) ));
1449 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1451 orig_reg_packet->locked = False;
1452 free_packet(orig_reg_packet);
1454 return;
1457 if(!find_ip_in_name_record(namerec, from_ip)) {
1458 add_ip_to_name_record(namerec, from_ip);
1461 get_global_id_and_update(&namerec->data.id, True);
1462 update_wins_owner(namerec, our_fake_ip);
1463 update_wins_flag(namerec, WINS_ACTIVE);
1464 update_name_ttl(namerec, ttl);
1465 wins_hook("add", namerec, ttl);
1466 send_wins_name_registration_response(0, ttl, orig_reg_packet);
1468 orig_reg_packet->locked = False;
1469 free_packet(orig_reg_packet);
1472 /***********************************************************************
1473 Deal with a name registration request query failure to a client that
1474 owned the name.
1476 We have a locked pointer to the original packet stashed away in the
1477 userdata pointer.
1478 ************************************************************************/
1480 static void wins_multihomed_register_query_fail(struct subnet_record *subrec,
1481 struct response_record *rrec,
1482 struct nmb_name *question_name,
1483 int rcode)
1485 struct userdata_struct *userdata = rrec->userdata;
1486 struct packet_struct *orig_reg_packet;
1488 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1490 DEBUG(3,("wins_multihomed_register_query_fail: Registering machine at IP %s failed to answer \
1491 query successfully for name %s.\n", inet_ntoa(orig_reg_packet->ip), nmb_namestr(question_name) ));
1492 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1494 orig_reg_packet->locked = False;
1495 free_packet(orig_reg_packet);
1496 return;
1499 /***********************************************************************
1500 Deal with a multihomed name registration request to a WINS server.
1501 These cannot be group name registrations.
1502 ***********************************************************************/
1504 void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
1505 struct packet_struct *p)
1507 struct nmb_packet *nmb = &p->packet.nmb;
1508 struct nmb_name *question = &nmb->question.question_name;
1509 bool bcast = nmb->header.nm_flags.bcast;
1510 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
1511 int ttl = get_ttl_from_packet(nmb);
1512 struct name_record *namerec = NULL;
1513 struct in_addr from_ip;
1514 bool group = (nb_flags & NB_GROUP) ? True : False;
1515 struct in_addr our_fake_ip;
1516 unstring qname;
1518 (void)interpret_addr2(&our_fake_ip, "0.0.0.0");
1519 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1521 if(bcast) {
1523 * We should only get unicast name registration packets here.
1524 * Anyone trying to register broadcast should not be going to a WINS
1525 * server. Log an error here.
1528 DEBUG(0,("wins_process_multihomed_name_registration_request: broadcast name registration request \
1529 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1530 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1531 return;
1535 * Only unique names should be registered multihomed.
1538 if(group) {
1539 DEBUG(0,("wins_process_multihomed_name_registration_request: group name registration request \
1540 received for name %s from IP %s on subnet %s. Errror - group names should not be multihomed.\n",
1541 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1542 return;
1545 DEBUG(3,("wins_process_multihomed_name_registration_request: name registration for name %s \
1546 IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ));
1549 * Deal with policy regarding 0x1d names.
1552 if(question->name_type == 0x1d) {
1553 DEBUG(3,("wins_process_multihomed_name_registration_request: Ignoring request \
1554 to register name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
1555 send_wins_name_registration_response(0, ttl, p);
1556 return;
1560 * See if the name already exists.
1563 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1566 * if the record exists but NOT in active state,
1567 * consider it dead.
1570 if ((namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1571 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was not active - removing it.\n", nmb_namestr(question)));
1572 remove_name_from_namelist(subrec, namerec);
1573 namerec = NULL;
1577 * Deal with the case where the name found was a dns entry.
1578 * Remove it as we now have a NetBIOS client registering the
1579 * name.
1582 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1583 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was a dns lookup \
1584 - removing it.\n", nmb_namestr(question) ));
1585 remove_name_from_namelist( subrec, namerec);
1586 namerec = NULL;
1590 * Reject if the name exists and is not a REGISTER_NAME.
1591 * (ie. Don't allow any static names to be overwritten.
1594 if( (namerec != NULL) && (namerec->data.source != REGISTER_NAME) ) {
1595 DEBUG( 3, ( "wins_process_multihomed_name_registration_request: Attempt \
1596 to register name %s. Name already exists in WINS with source type %d.\n",
1597 nmb_namestr(question), namerec->data.source ));
1598 send_wins_name_registration_response(RFS_ERR, 0, p);
1599 return;
1603 * Reject if the name exists and is a GROUP name and is active.
1606 if((namerec != NULL) && NAME_GROUP(namerec) && WINS_STATE_ACTIVE(namerec)) {
1607 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1608 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1609 send_wins_name_registration_response(RFS_ERR, 0, p);
1610 return;
1614 * From here on down we know that if the name exists in the WINS db it is
1615 * a unique name, not a group name.
1619 * If the name exists and is one of our names then check the
1620 * registering IP address. If it's not one of ours then automatically
1621 * reject without doing the query - we know we will reject it.
1624 if((namerec != NULL) && (is_myname(namerec->name.name)) ) {
1625 if(!ismyip_v4(from_ip)) {
1626 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1627 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1628 send_wins_name_registration_response(RFS_ERR, 0, p);
1629 return;
1630 } else {
1632 * It's one of our names and one of our IP's. Ensure the IP is in the record and
1633 * update the ttl. Update the version ID to force replication.
1635 update_name_ttl(namerec, ttl);
1637 if(!find_ip_in_name_record(namerec, from_ip)) {
1638 get_global_id_and_update(&namerec->data.id, True);
1639 update_wins_owner(namerec, our_fake_ip);
1640 update_wins_flag(namerec, WINS_ACTIVE);
1642 add_ip_to_name_record(namerec, from_ip);
1645 wins_hook("refresh", namerec, ttl);
1646 send_wins_name_registration_response(0, ttl, p);
1647 return;
1652 * If the name exists and is active, check if the IP address is already registered
1653 * to that name. If so then update the ttl and reply success.
1656 if((namerec != NULL) && find_ip_in_name_record(namerec, from_ip) && WINS_STATE_ACTIVE(namerec)) {
1657 update_name_ttl(namerec, ttl);
1660 * If it's a replica, we need to become the wins owner
1661 * to force the replication
1663 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
1664 get_global_id_and_update(&namerec->data.id, True);
1665 update_wins_owner(namerec, our_fake_ip);
1666 update_wins_flag(namerec, WINS_ACTIVE);
1669 wins_hook("refresh", namerec, ttl);
1670 send_wins_name_registration_response(0, ttl, p);
1671 return;
1675 * If the name exists do a query to the owner
1676 * to see if they still want the name.
1679 if(namerec != NULL) {
1680 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1681 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1684 * First send a WACK to the registering machine.
1687 send_wins_wack_response(60, p);
1690 * When the reply comes back we need the original packet.
1691 * Lock this so it won't be freed and then put it into
1692 * the userdata structure.
1695 p->locked = True;
1697 userdata = (struct userdata_struct *)ud;
1699 userdata->copy_fn = NULL;
1700 userdata->free_fn = NULL;
1701 userdata->userdata_len = sizeof(struct packet_struct *);
1702 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1705 * Use the new call to send a query directly to an IP address.
1706 * This sends the query directly to the IP address, and ensures
1707 * the recursion desired flag is not set (you were right Luke :-).
1708 * This function should *only* be called from the WINS server
1709 * code. JRA.
1711 * Note that this packet is sent to the current owner of the name,
1712 * not the person who sent the packet
1715 pull_ascii_nstring( qname, sizeof(qname), question->name);
1716 query_name_from_wins_server( namerec->data.ip[0],
1717 qname,
1718 question->name_type,
1719 wins_multihomed_register_query_success,
1720 wins_multihomed_register_query_fail,
1721 userdata );
1723 return;
1727 * Name did not exist - add it.
1730 pull_ascii_nstring( qname, sizeof(qname), question->name);
1731 add_name_to_subnet( subrec, qname, question->name_type,
1732 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1734 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1735 get_global_id_and_update(&namerec->data.id, True);
1736 update_wins_owner(namerec, our_fake_ip);
1737 update_wins_flag(namerec, WINS_ACTIVE);
1738 wins_hook("add", namerec, ttl);
1741 send_wins_name_registration_response(0, ttl, p);
1744 /***********************************************************************
1745 Fetch all *<1b> names from the WINS db and store on the namelist.
1746 ***********************************************************************/
1748 static int fetch_1b_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
1750 struct name_record *namerec = NULL;
1752 if (kbuf.dsize != sizeof(unstring) + 1) {
1753 return 0;
1756 /* Filter out all non-1b names. */
1757 if (kbuf.dptr[sizeof(unstring)] != 0x1b) {
1758 return 0;
1761 namerec = wins_record_to_name_record(kbuf, dbuf);
1762 if (!namerec) {
1763 return 0;
1766 DLIST_ADD(wins_server_subnet->namelist, namerec);
1767 return 0;
1770 void fetch_all_active_wins_1b_names(void)
1772 tdb_traverse(wins_tdb, fetch_1b_traverse_fn, NULL);
1775 /***********************************************************************
1776 Deal with the special name query for *<1b>.
1777 ***********************************************************************/
1779 static void process_wins_dmb_query_request(struct subnet_record *subrec,
1780 struct packet_struct *p)
1782 struct name_record *namerec = NULL;
1783 char *prdata;
1784 int num_ips;
1787 * Go through all the ACTIVE names in the WINS db looking for those
1788 * ending in <1b>. Use this to calculate the number of IP
1789 * addresses we need to return.
1792 num_ips = 0;
1794 /* First, clear the in memory list - we're going to re-populate
1795 it with the tdb_traversal in fetch_all_active_wins_1b_names. */
1797 wins_delete_all_tmp_in_memory_records();
1799 fetch_all_active_wins_1b_names();
1801 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1802 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1803 num_ips += namerec->data.num_ips;
1807 if(num_ips == 0) {
1809 * There are no 0x1b names registered. Return name query fail.
1811 send_wins_name_query_response(NAM_ERR, p, NULL);
1812 return;
1815 if((prdata = (char *)SMB_MALLOC( num_ips * 6 )) == NULL) {
1816 DEBUG(0,("process_wins_dmb_query_request: Malloc fail !.\n"));
1817 return;
1821 * Go through all the names again in the WINS db looking for those
1822 * ending in <1b>. Add their IP addresses into the list we will
1823 * return.
1826 num_ips = 0;
1827 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1828 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1829 int i;
1830 for(i = 0; i < namerec->data.num_ips; i++) {
1831 set_nb_flags(&prdata[num_ips * 6],namerec->data.nb_flags);
1832 putip((char *)&prdata[(num_ips * 6) + 2], &namerec->data.ip[i]);
1833 num_ips++;
1839 * Send back the reply containing the IP list.
1842 reply_netbios_packet(p, /* Packet to reply to. */
1843 0, /* Result code. */
1844 WINS_QUERY, /* nmbd type code. */
1845 NMB_NAME_QUERY_OPCODE, /* opcode. */
1846 lp_min_wins_ttl(), /* ttl. */
1847 prdata, /* data to send. */
1848 num_ips*6); /* data length. */
1850 SAFE_FREE(prdata);
1853 /****************************************************************************
1854 Send a WINS name query response.
1855 **************************************************************************/
1857 void send_wins_name_query_response(int rcode, struct packet_struct *p,
1858 struct name_record *namerec)
1860 char rdata[6];
1861 char *prdata = rdata;
1862 int reply_data_len = 0;
1863 int ttl = 0;
1864 int i;
1866 memset(rdata,'\0',6);
1868 if(rcode == 0) {
1869 ttl = (namerec->data.death_time != PERMANENT_TTL) ? namerec->data.death_time - p->timestamp : lp_max_wins_ttl();
1871 /* Copy all known ip addresses into the return data. */
1872 /* Optimise for the common case of one IP address so we don't need a malloc. */
1874 if( namerec->data.num_ips == 1 ) {
1875 prdata = rdata;
1876 } else {
1877 if((prdata = (char *)SMB_MALLOC( namerec->data.num_ips * 6 )) == NULL) {
1878 DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
1879 return;
1883 for(i = 0; i < namerec->data.num_ips; i++) {
1884 set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
1885 putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
1888 sort_query_replies(prdata, i, p->ip);
1889 reply_data_len = namerec->data.num_ips * 6;
1892 reply_netbios_packet(p, /* Packet to reply to. */
1893 rcode, /* Result code. */
1894 WINS_QUERY, /* nmbd type code. */
1895 NMB_NAME_QUERY_OPCODE, /* opcode. */
1896 ttl, /* ttl. */
1897 prdata, /* data to send. */
1898 reply_data_len); /* data length. */
1900 if(prdata != rdata) {
1901 SAFE_FREE(prdata);
1905 /***********************************************************************
1906 Deal with a name query.
1907 ***********************************************************************/
1909 void wins_process_name_query_request(struct subnet_record *subrec,
1910 struct packet_struct *p)
1912 struct nmb_packet *nmb = &p->packet.nmb;
1913 struct nmb_name *question = &nmb->question.question_name;
1914 struct name_record *namerec = NULL;
1915 unstring qname;
1917 DEBUG(3,("wins_process_name_query: name query for name %s from IP %s\n",
1918 nmb_namestr(question), inet_ntoa(p->ip) ));
1921 * Special name code. If the queried name is *<1b> then search
1922 * the entire WINS database and return a list of all the IP addresses
1923 * registered to any <1b> name. This is to allow domain master browsers
1924 * to discover other domains that may not have a presence on their subnet.
1927 pull_ascii_nstring(qname, sizeof(qname), question->name);
1928 if(strequal( qname, "*") && (question->name_type == 0x1b)) {
1929 process_wins_dmb_query_request( subrec, p);
1930 return;
1933 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1935 if(namerec != NULL) {
1937 * If the name is not anymore in active state then reply not found.
1938 * it's fair even if we keep it in the cache for days.
1940 if (!WINS_STATE_ACTIVE(namerec)) {
1941 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
1942 nmb_namestr(question) ));
1943 send_wins_name_query_response(NAM_ERR, p, namerec);
1944 return;
1948 * If it's a DNSFAIL_NAME then reply name not found.
1951 if( namerec->data.source == DNSFAIL_NAME ) {
1952 DEBUG(3,("wins_process_name_query: name query for name %s returning DNS fail.\n",
1953 nmb_namestr(question) ));
1954 send_wins_name_query_response(NAM_ERR, p, namerec);
1955 return;
1959 * If the name has expired then reply name not found.
1962 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < p->timestamp) ) {
1963 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
1964 nmb_namestr(question) ));
1965 send_wins_name_query_response(NAM_ERR, p, namerec);
1966 return;
1969 DEBUG(3,("wins_process_name_query: name query for name %s returning first IP %s.\n",
1970 nmb_namestr(question), inet_ntoa(namerec->data.ip[0]) ));
1972 send_wins_name_query_response(0, p, namerec);
1973 return;
1977 * Name not found in WINS - try a dns query if it's a 0x20 name.
1980 if(lp_dns_proxy() && ((question->name_type == 0x20) || question->name_type == 0)) {
1981 DEBUG(3,("wins_process_name_query: name query for name %s not found - doing dns lookup.\n",
1982 nmb_namestr(question) ));
1984 queue_dns_query(p, question);
1985 return;
1989 * Name not found - return error.
1992 send_wins_name_query_response(NAM_ERR, p, NULL);
1995 /****************************************************************************
1996 Send a WINS name release response.
1997 **************************************************************************/
1999 static void send_wins_name_release_response(int rcode, struct packet_struct *p)
2001 struct nmb_packet *nmb = &p->packet.nmb;
2002 char rdata[6];
2004 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
2006 reply_netbios_packet(p, /* Packet to reply to. */
2007 rcode, /* Result code. */
2008 NMB_REL, /* nmbd type code. */
2009 NMB_NAME_RELEASE_OPCODE, /* opcode. */
2010 0, /* ttl. */
2011 rdata, /* data to send. */
2012 6); /* data length. */
2015 /***********************************************************************
2016 Deal with a name release.
2017 ***********************************************************************/
2019 void wins_process_name_release_request(struct subnet_record *subrec,
2020 struct packet_struct *p)
2022 struct nmb_packet *nmb = &p->packet.nmb;
2023 struct nmb_name *question = &nmb->question.question_name;
2024 bool bcast = nmb->header.nm_flags.bcast;
2025 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
2026 struct name_record *namerec = NULL;
2027 struct in_addr from_ip;
2028 bool releasing_group_name = (nb_flags & NB_GROUP) ? True : False;;
2030 putip((char *)&from_ip,&nmb->additional->rdata[2]);
2032 if(bcast) {
2034 * We should only get unicast name registration packets here.
2035 * Anyone trying to register broadcast should not be going to a WINS
2036 * server. Log an error here.
2039 DEBUG(0,("wins_process_name_release_request: broadcast name registration request \
2040 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
2041 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
2042 return;
2045 DEBUG(3,("wins_process_name_release_request: %s name release for name %s \
2046 IP %s\n", releasing_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
2049 * Deal with policy regarding 0x1d names.
2052 if(!releasing_group_name && (question->name_type == 0x1d)) {
2053 DEBUG(3,("wins_process_name_release_request: Ignoring request \
2054 to release name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
2055 send_wins_name_release_response(0, p);
2056 return;
2060 * See if the name already exists.
2063 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2065 if( (namerec == NULL) || ((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) ) {
2066 send_wins_name_release_response(NAM_ERR, p);
2067 return;
2071 * Check that the sending machine has permission to release this name.
2072 * If it's a group name not ending in 0x1c then just say yes and let
2073 * the group time out.
2076 if(releasing_group_name && (question->name_type != 0x1c)) {
2077 send_wins_name_release_response(0, p);
2078 return;
2082 * Check that the releasing node is on the list of IP addresses
2083 * for this name. Disallow the release if not.
2086 if(!find_ip_in_name_record(namerec, from_ip)) {
2087 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2088 release name %s as IP %s is not one of the known IP's for this name.\n",
2089 nmb_namestr(question), inet_ntoa(from_ip) ));
2090 send_wins_name_release_response(NAM_ERR, p);
2091 return;
2095 * Check if the record is active. IF it's already released
2096 * or tombstoned, refuse the release.
2099 if (!WINS_STATE_ACTIVE(namerec)) {
2100 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2101 release name %s as this record is not active anymore.\n", nmb_namestr(question) ));
2102 send_wins_name_release_response(NAM_ERR, p);
2103 return;
2107 * Check if the record is a 0x1c group
2108 * and has more then one ip
2109 * remove only this address.
2112 if(releasing_group_name && (question->name_type == 0x1c) && (namerec->data.num_ips > 1)) {
2113 remove_ip_from_name_record(namerec, from_ip);
2114 DEBUG(3,("wins_process_name_release_request: Remove IP %s from NAME: %s\n",
2115 inet_ntoa(from_ip),nmb_namestr(question)));
2116 wins_hook("delete", namerec, 0);
2117 send_wins_name_release_response(0, p);
2118 return;
2122 * Send a release response.
2123 * Flag the name as released and update the ttl
2126 namerec->data.wins_flags |= WINS_RELEASED;
2127 update_name_ttl(namerec, EXTINCTION_INTERVAL);
2129 wins_hook("delete", namerec, 0);
2130 send_wins_name_release_response(0, p);
2133 /*******************************************************************
2134 WINS time dependent processing.
2135 ******************************************************************/
2137 static int wins_processing_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2139 time_t t = *(time_t *)state;
2140 bool store_record = False;
2141 struct name_record *namerec = NULL;
2142 struct in_addr our_fake_ip;
2144 (void)interpret_addr2(&our_fake_ip, "0.0.0.0");
2145 if (kbuf.dsize != sizeof(unstring) + 1) {
2146 return 0;
2149 namerec = wins_record_to_name_record(kbuf, dbuf);
2150 if (!namerec) {
2151 return 0;
2154 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
2155 if( namerec->data.source == SELF_NAME ) {
2156 DEBUG( 3, ( "wins_processing_traverse_fn: Subnet %s not expiring SELF name %s\n",
2157 wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) );
2158 namerec->data.death_time += 300;
2159 store_record = True;
2160 goto done;
2161 } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) {
2162 DEBUG(3,("wins_processing_traverse_fn: deleting timed out DNS name %s\n",
2163 nmb_namestr(&namerec->name)));
2164 remove_name_from_wins_namelist(namerec );
2165 goto done;
2168 /* handle records, samba is the wins owner */
2169 if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
2170 switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2171 case WINS_ACTIVE:
2172 namerec->data.wins_flags&=~WINS_STATE_MASK;
2173 namerec->data.wins_flags|=WINS_RELEASED;
2174 namerec->data.death_time = t + EXTINCTION_INTERVAL;
2175 DEBUG(3,("wins_processing_traverse_fn: expiring %s\n",
2176 nmb_namestr(&namerec->name)));
2177 store_record = True;
2178 goto done;
2179 case WINS_RELEASED:
2180 namerec->data.wins_flags&=~WINS_STATE_MASK;
2181 namerec->data.wins_flags|=WINS_TOMBSTONED;
2182 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2183 get_global_id_and_update(&namerec->data.id, True);
2184 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2185 nmb_namestr(&namerec->name)));
2186 store_record = True;
2187 goto done;
2188 case WINS_TOMBSTONED:
2189 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2190 nmb_namestr(&namerec->name)));
2191 remove_name_from_wins_namelist(namerec );
2192 goto done;
2194 } else {
2195 switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2196 case WINS_ACTIVE:
2197 /* that's not as MS says it should be */
2198 namerec->data.wins_flags&=~WINS_STATE_MASK;
2199 namerec->data.wins_flags|=WINS_TOMBSTONED;
2200 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2201 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2202 nmb_namestr(&namerec->name)));
2203 store_record = True;
2204 goto done;
2205 case WINS_TOMBSTONED:
2206 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2207 nmb_namestr(&namerec->name)));
2208 remove_name_from_wins_namelist(namerec );
2209 goto done;
2210 case WINS_RELEASED:
2211 DEBUG(0,("wins_processing_traverse_fn: %s is in released state and\
2212 we are not the wins owner !\n", nmb_namestr(&namerec->name)));
2213 goto done;
2218 done:
2220 if (store_record) {
2221 wins_store_changed_namerec(namerec);
2224 SAFE_FREE(namerec->data.ip);
2225 SAFE_FREE(namerec);
2227 return 0;
2230 /*******************************************************************
2231 Time dependent wins processing.
2232 ******************************************************************/
2234 void initiate_wins_processing(time_t t)
2236 static time_t lasttime = 0;
2238 if (!lasttime) {
2239 lasttime = t;
2241 if (t - lasttime < 20) {
2242 return;
2245 if(!lp_we_are_a_wins_server()) {
2246 lasttime = t;
2247 return;
2250 tdb_traverse(wins_tdb, wins_processing_traverse_fn, &t);
2252 wins_delete_all_tmp_in_memory_records();
2254 wins_write_database(t, True);
2256 lasttime = t;
2259 /*******************************************************************
2260 Write out one record.
2261 ******************************************************************/
2263 void wins_write_name_record(struct name_record *namerec, XFILE *fp)
2265 int i;
2266 struct tm *tm;
2268 DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) ));
2270 if( namerec->data.death_time != PERMANENT_TTL ) {
2271 char *ts, *nl;
2273 tm = localtime(&namerec->data.death_time);
2274 if (!tm) {
2275 return;
2277 ts = asctime(tm);
2278 if (!ts) {
2279 return;
2281 nl = strrchr( ts, '\n' );
2282 if( NULL != nl ) {
2283 *nl = '\0';
2285 DEBUGADD(4,("TTL = %s ", ts ));
2286 } else {
2287 DEBUGADD(4,("TTL = PERMANENT "));
2290 for (i = 0; i < namerec->data.num_ips; i++) {
2291 DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) ));
2293 DEBUGADD(4,("%2x\n", namerec->data.nb_flags ));
2295 if( namerec->data.source == REGISTER_NAME ) {
2296 unstring name;
2297 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
2298 x_fprintf(fp, "\"%s#%02x\" %d ", name,namerec->name.name_type, /* Ignore scope. */
2299 (int)namerec->data.death_time);
2301 for (i = 0; i < namerec->data.num_ips; i++)
2302 x_fprintf( fp, "%s ", inet_ntoa( namerec->data.ip[i] ) );
2303 x_fprintf( fp, "%2xR\n", namerec->data.nb_flags );
2307 /*******************************************************************
2308 Write out the current WINS database.
2309 ******************************************************************/
2311 static int wins_writedb_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2313 struct name_record *namerec = NULL;
2314 XFILE *fp = (XFILE *)state;
2316 if (kbuf.dsize != sizeof(unstring) + 1) {
2317 return 0;
2320 namerec = wins_record_to_name_record(kbuf, dbuf);
2321 if (!namerec) {
2322 return 0;
2325 wins_write_name_record(namerec, fp);
2327 SAFE_FREE(namerec->data.ip);
2328 SAFE_FREE(namerec);
2329 return 0;
2333 void wins_write_database(time_t t, bool background)
2335 static time_t last_write_time = 0;
2336 char *fname = NULL;
2337 char *fnamenew = NULL;
2339 XFILE *fp;
2341 if (background) {
2342 if (!last_write_time) {
2343 last_write_time = t;
2345 if (t - last_write_time < 120) {
2346 return;
2351 if(!lp_we_are_a_wins_server()) {
2352 return;
2355 /* We will do the writing in a child process to ensure that the parent doesn't block while this is done */
2356 if (background) {
2357 CatchChild();
2358 if (sys_fork()) {
2359 return;
2361 if (tdb_reopen(wins_tdb)) {
2362 DEBUG(0,("wins_write_database: tdb_reopen failed. Error was %s\n",
2363 strerror(errno)));
2364 _exit(0);
2365 return;
2369 if (asprintf(&fname, "%s/%s", get_dyn_STATEDIR(), WINS_LIST) < 0) {
2370 goto err_exit;
2372 /* This is safe as the 0 length means "don't expand". */
2373 all_string_sub(fname,"//", "/", 0);
2375 if (asprintf(&fnamenew, "%s.%u", fname, (unsigned int)sys_getpid()) < 0) {
2376 goto err_exit;
2379 if((fp = x_fopen(fnamenew,O_WRONLY|O_CREAT,0644)) == NULL) {
2380 DEBUG(0,("wins_write_database: Can't open %s. Error was %s\n", fnamenew, strerror(errno)));
2381 goto err_exit;
2384 DEBUG(4,("wins_write_database: Dump of WINS name list.\n"));
2386 x_fprintf(fp,"VERSION %d %u\n", WINS_VERSION, 0);
2388 tdb_traverse(wins_tdb, wins_writedb_traverse_fn, fp);
2390 x_fclose(fp);
2391 chmod(fnamenew,0644);
2392 unlink(fname);
2393 rename(fnamenew,fname);
2395 err_exit:
2397 SAFE_FREE(fname);
2398 SAFE_FREE(fnamenew);
2400 if (background) {
2401 _exit(0);
2405 #if 0
2406 Until winsrepl is done.
2407 /****************************************************************************
2408 Process a internal Samba message receiving a wins record.
2409 ***************************************************************************/
2411 void nmbd_wins_new_entry(struct messaging_context *msg,
2412 void *private_data,
2413 uint32_t msg_type,
2414 struct server_id server_id,
2415 DATA_BLOB *data)
2417 WINS_RECORD *record;
2418 struct name_record *namerec = NULL;
2419 struct name_record *new_namerec = NULL;
2420 struct nmb_name question;
2421 bool overwrite=False;
2422 struct in_addr our_fake_ip;
2423 int i;
2425 (void)interpret_addr2(&our_fake_ip, "0.0.0.0");
2426 if (buf==NULL) {
2427 return;
2430 /* Record should use UNIX codepage. Ensure this is so in the wrepld code. JRA. */
2431 record=(WINS_RECORD *)buf;
2433 make_nmb_name(&question, record->name, record->type);
2435 namerec = find_name_on_subnet(wins_server_subnet, &question, FIND_ANY_NAME);
2437 /* record doesn't exist, add it */
2438 if (namerec == NULL) {
2439 DEBUG(3,("nmbd_wins_new_entry: adding new replicated record: %s<%02x> for wins server: %s\n",
2440 record->name, record->type, inet_ntoa(record->wins_ip)));
2442 new_namerec=add_name_to_subnet( wins_server_subnet,
2443 record->name,
2444 record->type,
2445 record->nb_flags,
2446 EXTINCTION_INTERVAL,
2447 REGISTER_NAME,
2448 record->num_ips,
2449 record->ip);
2451 if (new_namerec!=NULL) {
2452 update_wins_owner(new_namerec, record->wins_ip);
2453 update_wins_flag(new_namerec, record->wins_flags);
2454 new_namerec->data.id=record->id;
2456 wins_server_subnet->namelist_changed = True;
2460 /* check if we have a conflict */
2461 if (namerec != NULL) {
2462 /* both records are UNIQUE */
2463 if (namerec->data.wins_flags&WINS_UNIQUE && record->wins_flags&WINS_UNIQUE) {
2465 /* the database record is a replica */
2466 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
2467 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED) {
2468 if (ip_equal_v4(namerec->data.wins_ip, record->wins_ip))
2469 overwrite=True;
2470 } else
2471 overwrite=True;
2472 } else {
2473 /* we are the wins owner of the database record */
2474 /* the 2 records have the same IP address */
2475 if (ip_equal_v4(namerec->data.ip[0], record->ip[0])) {
2476 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED)
2477 get_global_id_and_update(&namerec->data.id, True);
2478 else
2479 overwrite=True;
2481 } else {
2482 /* the 2 records have different IP address */
2483 if (namerec->data.wins_flags&WINS_ACTIVE) {
2484 if (record->wins_flags&WINS_TOMBSTONED)
2485 get_global_id_and_update(&namerec->data.id, True);
2486 if (record->wins_flags&WINS_ACTIVE)
2487 /* send conflict challenge to the replica node */
2489 } else
2490 overwrite=True;
2496 /* the replica is a standard group */
2497 if (record->wins_flags&WINS_NGROUP || record->wins_flags&WINS_SGROUP) {
2498 /* if the database record is unique and active force a name release */
2499 if (namerec->data.wins_flags&WINS_UNIQUE)
2500 /* send a release name to the unique node */
2502 overwrite=True;
2506 /* the replica is a special group */
2507 if (record->wins_flags&WINS_SGROUP && namerec->data.wins_flags&WINS_SGROUP) {
2508 if (namerec->data.wins_flags&WINS_ACTIVE) {
2509 for (i=0; i<record->num_ips; i++)
2510 if(!find_ip_in_name_record(namerec, record->ip[i]))
2511 add_ip_to_name_record(namerec, record->ip[i]);
2512 } else {
2513 overwrite=True;
2517 /* the replica is a multihomed host */
2519 /* I'm giving up on multi homed. Too much complex to understand */
2521 if (record->wins_flags&WINS_MHOMED) {
2522 if (! (namerec->data.wins_flags&WINS_ACTIVE)) {
2523 if ( !(namerec->data.wins_flags&WINS_RELEASED) && !(namerec->data.wins_flags&WINS_NGROUP))
2524 overwrite=True;
2526 else {
2527 if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
2528 overwrite=True;
2530 if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip))
2531 if (namerec->data.wins_flags&WINS_UNIQUE)
2532 get_global_id_and_update(&namerec->data.id, True);
2536 if (record->wins_flags&WINS_ACTIVE && namerec->data.wins_flags&WINS_ACTIVE)
2537 if (namerec->data.wins_flags&WINS_UNIQUE ||
2538 namerec->data.wins_flags&WINS_MHOMED)
2539 if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
2540 overwrite=True;
2544 if (overwrite == False)
2545 DEBUG(3, ("nmbd_wins_new_entry: conflict in adding record: %s<%02x> from wins server: %s\n",
2546 record->name, record->type, inet_ntoa(record->wins_ip)));
2547 else {
2548 DEBUG(3, ("nmbd_wins_new_entry: replacing record: %s<%02x> from wins server: %s\n",
2549 record->name, record->type, inet_ntoa(record->wins_ip)));
2551 /* remove the old record and add a new one */
2552 remove_name_from_namelist( wins_server_subnet, namerec );
2553 new_namerec=add_name_to_subnet( wins_server_subnet, record->name, record->type, record->nb_flags,
2554 EXTINCTION_INTERVAL, REGISTER_NAME, record->num_ips, record->ip);
2555 if (new_namerec!=NULL) {
2556 update_wins_owner(new_namerec, record->wins_ip);
2557 update_wins_flag(new_namerec, record->wins_flags);
2558 new_namerec->data.id=record->id;
2560 wins_server_subnet->namelist_changed = True;
2563 wins_server_subnet->namelist_changed = True;
2568 #endif