s3-dcerpc: add server helpers for gssapi auth
[Samba.git] / source3 / nmbd / nmbd_winsserver.c
blob5f3a9c39bf3744e653964543d66b4ec71ebbd9e6
1 /*
2 Unix SMB/CIFS implementation.
3 NBT netbios routines and daemon - version 2
5 Copyright (C) Jeremy Allison 1994-2005
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 Converted to store WINS data in a tdb. Dec 2005. JRA.
23 #include "includes.h"
24 #include "nmbd/nmbd.h"
26 #define WINS_LIST "wins.dat"
27 #define WINS_VERSION 1
28 #define WINSDB_VERSION 1
30 /****************************************************************************
31 We don't store the NetBIOS scope in the wins.tdb. We key off the (utf8) netbios
32 name (65 bytes with the last byte being the name type).
33 *****************************************************************************/
35 TDB_CONTEXT *wins_tdb;
37 /****************************************************************************
38 Delete all the temporary name records on the in-memory linked list.
39 *****************************************************************************/
41 static void wins_delete_all_tmp_in_memory_records(void)
43 struct name_record *nr = NULL;
44 struct name_record *nrnext = NULL;
46 /* Delete all temporary name records on the wins subnet linked list. */
47 for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
48 nrnext = nr->next;
49 DLIST_REMOVE(wins_server_subnet->namelist, nr);
50 SAFE_FREE(nr->data.ip);
51 SAFE_FREE(nr);
55 /****************************************************************************
56 Delete all the temporary 1b name records on the in-memory linked list.
57 *****************************************************************************/
59 static void wins_delete_all_1b_in_memory_records(void)
61 struct name_record *nr = NULL;
62 struct name_record *nrnext = NULL;
64 /* Delete all temporary 1b name records on the wins subnet linked list. */
65 for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
66 nrnext = nr->next;
67 if (nr->name.name_type == 0x1b) {
68 DLIST_REMOVE(wins_server_subnet->namelist, nr);
69 SAFE_FREE(nr->data.ip);
70 SAFE_FREE(nr);
75 /****************************************************************************
76 Convert a wins.tdb record to a struct name_record. Add in our global_scope().
77 *****************************************************************************/
79 static struct name_record *wins_record_to_name_record(TDB_DATA key, TDB_DATA data)
81 struct name_record *namerec = NULL;
82 uint16 nb_flags;
83 unsigned char nr_src;
84 uint32 death_time, refresh_time;
85 uint32 id_low, id_high;
86 uint32 saddr;
87 uint32 wins_flags;
88 uint32 num_ips;
89 size_t len;
90 int i;
92 if (data.dptr == NULL || data.dsize == 0) {
93 return NULL;
96 /* Min size is "wbddddddd" + 1 ip address (4). */
97 if (data.dsize < 2 + 1 + (7*4) + 4) {
98 return NULL;
101 len = tdb_unpack(data.dptr, data.dsize,
102 "wbddddddd",
103 &nb_flags,
104 &nr_src,
105 &death_time,
106 &refresh_time,
107 &id_low,
108 &id_high,
109 &saddr,
110 &wins_flags,
111 &num_ips );
113 namerec = SMB_MALLOC_P(struct name_record);
114 if (!namerec) {
115 return NULL;
117 ZERO_STRUCTP(namerec);
119 namerec->data.ip = SMB_MALLOC_ARRAY(struct in_addr, num_ips);
120 if (!namerec->data.ip) {
121 SAFE_FREE(namerec);
122 return NULL;
125 namerec->subnet = wins_server_subnet;
126 push_ascii_nstring(namerec->name.name, (const char *)key.dptr);
127 namerec->name.name_type = key.dptr[sizeof(unstring)];
128 /* Add the scope. */
129 push_ascii(namerec->name.scope, global_scope(), 64, STR_TERMINATE);
131 /* We're using a byte-by-byte compare, so we must be sure that
132 * unused space doesn't have garbage in it.
135 for( i = strlen( namerec->name.name ); i < sizeof( namerec->name.name ); i++ ) {
136 namerec->name.name[i] = '\0';
138 for( i = strlen( namerec->name.scope ); i < sizeof( namerec->name.scope ); i++ ) {
139 namerec->name.scope[i] = '\0';
142 namerec->data.nb_flags = nb_flags;
143 namerec->data.source = (enum name_source)nr_src;
144 namerec->data.death_time = (time_t)death_time;
145 namerec->data.refresh_time = (time_t)refresh_time;
146 namerec->data.id = id_low;
147 #if defined(HAVE_LONGLONG)
148 namerec->data.id |= ((uint64_t)id_high << 32);
149 #endif
150 namerec->data.wins_ip.s_addr = saddr;
151 namerec->data.wins_flags = wins_flags,
152 namerec->data.num_ips = num_ips;
154 for (i = 0; i < num_ips; i++) {
155 namerec->data.ip[i].s_addr = IVAL(data.dptr, len + (i*4));
158 return namerec;
161 /****************************************************************************
162 Convert a struct name_record to a wins.tdb record. Ignore the scope.
163 *****************************************************************************/
165 static TDB_DATA name_record_to_wins_record(const struct name_record *namerec)
167 TDB_DATA data;
168 size_t len = 0;
169 int i;
170 uint32 id_low = (namerec->data.id & 0xFFFFFFFF);
171 #if defined(HAVE_LONGLONG)
172 uint32 id_high = (namerec->data.id >> 32) & 0xFFFFFFFF;
173 #else
174 uint32 id_high = 0;
175 #endif
177 ZERO_STRUCT(data);
179 len = (2 + 1 + (7*4)); /* "wbddddddd" */
180 len += (namerec->data.num_ips * 4);
182 data.dptr = (uint8 *)SMB_MALLOC(len);
183 if (!data.dptr) {
184 return data;
186 data.dsize = len;
188 len = tdb_pack(data.dptr, data.dsize, "wbddddddd",
189 namerec->data.nb_flags,
190 (unsigned char)namerec->data.source,
191 (uint32)namerec->data.death_time,
192 (uint32)namerec->data.refresh_time,
193 id_low,
194 id_high,
195 (uint32)namerec->data.wins_ip.s_addr,
196 (uint32)namerec->data.wins_flags,
197 (uint32)namerec->data.num_ips );
199 for (i = 0; i < namerec->data.num_ips; i++) {
200 SIVAL(data.dptr, len + (i*4), namerec->data.ip[i].s_addr);
203 return data;
206 /****************************************************************************
207 Create key. Key is UNIX codepage namestring (usually utf8 64 byte len) with 1 byte type.
208 *****************************************************************************/
210 static TDB_DATA name_to_key(const struct nmb_name *nmbname)
212 static char keydata[sizeof(unstring) + 1];
213 TDB_DATA key;
215 memset(keydata, '\0', sizeof(keydata));
217 pull_ascii_nstring(keydata, sizeof(unstring), nmbname->name);
218 strupper_m(keydata);
219 keydata[sizeof(unstring)] = nmbname->name_type;
220 key.dptr = (uint8 *)keydata;
221 key.dsize = sizeof(keydata);
223 return key;
226 /****************************************************************************
227 Lookup a given name in the wins.tdb and create a temporary malloc'ed data struct
228 on the linked list. We will free this later in XXXX().
229 *****************************************************************************/
231 struct name_record *find_name_on_wins_subnet(const struct nmb_name *nmbname, bool self_only)
233 TDB_DATA data, key;
234 struct name_record *nr = NULL;
235 struct name_record *namerec = NULL;
237 if (!wins_tdb) {
238 return NULL;
241 key = name_to_key(nmbname);
242 data = tdb_fetch(wins_tdb, key);
244 if (data.dsize == 0) {
245 return NULL;
248 namerec = wins_record_to_name_record(key, data);
250 /* done with the this */
252 SAFE_FREE( data.dptr );
254 if (!namerec) {
255 return NULL;
258 /* Self names only - these include permanent names. */
259 if( self_only && (namerec->data.source != SELF_NAME) && (namerec->data.source != PERMANENT_NAME) ) {
260 DEBUG( 9, ( "find_name_on_wins_subnet: self name %s NOT FOUND\n", nmb_namestr(nmbname) ) );
261 SAFE_FREE(namerec->data.ip);
262 SAFE_FREE(namerec);
263 return NULL;
266 /* Search for this name record on the list. Replace it if found. */
268 for( nr = wins_server_subnet->namelist; nr; nr = nr->next) {
269 if (memcmp(nmbname->name, nr->name.name, 16) == 0) {
270 /* Delete it. */
271 DLIST_REMOVE(wins_server_subnet->namelist, nr);
272 SAFE_FREE(nr->data.ip);
273 SAFE_FREE(nr);
274 break;
278 DLIST_ADD(wins_server_subnet->namelist, namerec);
279 return namerec;
282 /****************************************************************************
283 Overwrite or add a given name in the wins.tdb.
284 *****************************************************************************/
286 static bool store_or_replace_wins_namerec(const struct name_record *namerec, int tdb_flag)
288 TDB_DATA key, data;
289 int ret;
291 if (!wins_tdb) {
292 return False;
295 key = name_to_key(&namerec->name);
296 data = name_record_to_wins_record(namerec);
298 if (data.dptr == NULL) {
299 return False;
302 ret = tdb_store(wins_tdb, key, data, tdb_flag);
304 SAFE_FREE(data.dptr);
305 return (ret == 0) ? True : False;
308 /****************************************************************************
309 Overwrite a given name in the wins.tdb.
310 *****************************************************************************/
312 bool wins_store_changed_namerec(const struct name_record *namerec)
314 return store_or_replace_wins_namerec(namerec, TDB_REPLACE);
317 /****************************************************************************
318 Primary interface into creating and overwriting records in the wins.tdb.
319 *****************************************************************************/
321 bool add_name_to_wins_subnet(const struct name_record *namerec)
323 return store_or_replace_wins_namerec(namerec, TDB_INSERT);
326 /****************************************************************************
327 Delete a given name in the tdb and remove the temporary malloc'ed data struct
328 on the linked list.
329 *****************************************************************************/
331 bool remove_name_from_wins_namelist(struct name_record *namerec)
333 TDB_DATA key;
334 int ret;
336 if (!wins_tdb) {
337 return False;
340 key = name_to_key(&namerec->name);
341 ret = tdb_delete(wins_tdb, key);
343 DLIST_REMOVE(wins_server_subnet->namelist, namerec);
345 /* namerec must be freed by the caller */
347 return (ret == 0) ? True : False;
350 /****************************************************************************
351 Dump out the complete namelist.
352 *****************************************************************************/
354 static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
356 struct name_record *namerec = NULL;
357 XFILE *fp = (XFILE *)state;
359 if (kbuf.dsize != sizeof(unstring) + 1) {
360 return 0;
363 namerec = wins_record_to_name_record(kbuf, dbuf);
364 if (!namerec) {
365 return 0;
368 dump_name_record(namerec, fp);
370 SAFE_FREE(namerec->data.ip);
371 SAFE_FREE(namerec);
372 return 0;
375 void dump_wins_subnet_namelist(XFILE *fp)
377 tdb_traverse(wins_tdb, traverse_fn, (void *)fp);
380 /****************************************************************************
381 Change the wins owner address in the record.
382 *****************************************************************************/
384 static void update_wins_owner(struct name_record *namerec, struct in_addr wins_ip)
386 namerec->data.wins_ip=wins_ip;
389 /****************************************************************************
390 Create the wins flags based on the nb flags and the input value.
391 *****************************************************************************/
393 static void update_wins_flag(struct name_record *namerec, int flags)
395 namerec->data.wins_flags=0x0;
397 /* if it's a group, it can be a normal or a special one */
398 if (namerec->data.nb_flags & NB_GROUP) {
399 if (namerec->name.name_type==0x1C) {
400 namerec->data.wins_flags|=WINS_SGROUP;
401 } else {
402 if (namerec->data.num_ips>1) {
403 namerec->data.wins_flags|=WINS_SGROUP;
404 } else {
405 namerec->data.wins_flags|=WINS_NGROUP;
408 } else {
409 /* can be unique or multi-homed */
410 if (namerec->data.num_ips>1) {
411 namerec->data.wins_flags|=WINS_MHOMED;
412 } else {
413 namerec->data.wins_flags|=WINS_UNIQUE;
417 /* the node type are the same bits */
418 namerec->data.wins_flags|=namerec->data.nb_flags&NB_NODETYPEMASK;
420 /* the static bit is elsewhere */
421 if (namerec->data.death_time == PERMANENT_TTL) {
422 namerec->data.wins_flags|=WINS_STATIC;
425 /* and add the given bits */
426 namerec->data.wins_flags|=flags;
428 DEBUG(8,("update_wins_flag: nbflags: 0x%x, ttl: %d, flags: 0x%x, winsflags: 0x%x\n",
429 namerec->data.nb_flags, (int)namerec->data.death_time, flags, namerec->data.wins_flags));
432 /****************************************************************************
433 Return the general ID value and increase it if requested.
434 *****************************************************************************/
436 static void get_global_id_and_update(uint64_t *current_id, bool update)
439 * it's kept as a static here, to prevent people from messing
440 * with the value directly
443 static uint64_t general_id = 1;
445 DEBUG(5,("get_global_id_and_update: updating version ID: %d\n", (int)general_id));
447 *current_id = general_id;
449 if (update) {
450 general_id++;
454 /****************************************************************************
455 Possibly call the WINS hook external program when a WINS change is made.
456 Also stores the changed record back in the wins_tdb.
457 *****************************************************************************/
459 static void wins_hook(const char *operation, struct name_record *namerec, int ttl)
461 char *command = NULL;
462 char *cmd = lp_wins_hook();
463 char *p, *namestr;
464 int i;
465 TALLOC_CTX *ctx = talloc_tos();
467 wins_store_changed_namerec(namerec);
469 if (!cmd || !*cmd) {
470 return;
473 for (p=namerec->name.name; *p; p++) {
474 if (!(isalnum((int)*p) || strchr_m("._-",*p))) {
475 DEBUG(3,("not calling wins hook for invalid name %s\n", nmb_namestr(&namerec->name)));
476 return;
480 /* Use the name without the nametype (and scope) appended */
482 namestr = nmb_namestr(&namerec->name);
483 if ((p = strchr(namestr, '<'))) {
484 *p = 0;
487 command = talloc_asprintf(ctx,
488 "%s %s %s %02x %d",
489 cmd,
490 operation,
491 namestr,
492 namerec->name.name_type,
493 ttl);
494 if (!command) {
495 return;
498 for (i=0;i<namerec->data.num_ips;i++) {
499 command = talloc_asprintf_append(command,
500 " %s",
501 inet_ntoa(namerec->data.ip[i]));
502 if (!command) {
503 return;
507 DEBUG(3,("calling wins hook for %s\n", nmb_namestr(&namerec->name)));
508 smbrun(command, NULL);
509 TALLOC_FREE(command);
512 /****************************************************************************
513 Determine if this packet should be allocated to the WINS server.
514 *****************************************************************************/
516 bool packet_is_for_wins_server(struct packet_struct *packet)
518 struct nmb_packet *nmb = &packet->packet.nmb;
520 /* Only unicast packets go to a WINS server. */
521 if((wins_server_subnet == NULL) || (nmb->header.nm_flags.bcast == True)) {
522 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #1.\n"));
523 return False;
526 /* Check for node status requests. */
527 if (nmb->question.question_type != QUESTION_TYPE_NB_QUERY) {
528 return False;
531 switch(nmb->header.opcode) {
533 * A WINS server issues WACKS, not receives them.
535 case NMB_WACK_OPCODE:
536 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #2 (WACK).\n"));
537 return False;
539 * A WINS server only processes registration and
540 * release requests, not responses.
542 case NMB_NAME_REG_OPCODE:
543 case NMB_NAME_MULTIHOMED_REG_OPCODE:
544 case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
545 case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
546 if(nmb->header.response) {
547 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #3 (response = 1).\n"));
548 return False;
550 break;
552 case NMB_NAME_RELEASE_OPCODE:
553 if(nmb->header.response) {
554 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #4 (response = 1).\n"));
555 return False;
557 break;
560 * Only process unicast name queries with rd = 1.
562 case NMB_NAME_QUERY_OPCODE:
563 if(!nmb->header.response && !nmb->header.nm_flags.recursion_desired) {
564 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #5 (response = 1).\n"));
565 return False;
567 break;
570 return True;
573 /****************************************************************************
574 Utility function to decide what ttl to give a register/refresh request.
575 *****************************************************************************/
577 static int get_ttl_from_packet(struct nmb_packet *nmb)
579 int ttl = nmb->additional->ttl;
581 if (ttl < lp_min_wins_ttl()) {
582 ttl = lp_min_wins_ttl();
585 if (ttl > lp_max_wins_ttl()) {
586 ttl = lp_max_wins_ttl();
589 return ttl;
592 /****************************************************************************
593 Load or create the WINS database.
594 *****************************************************************************/
596 bool initialise_wins(void)
598 time_t time_now = time(NULL);
599 XFILE *fp;
600 char line[1024];
602 if(!lp_we_are_a_wins_server()) {
603 return True;
606 /* Open the wins.tdb. */
607 wins_tdb = tdb_open_log(state_path("wins.tdb"), 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST, O_CREAT|O_RDWR, 0600);
608 if (!wins_tdb) {
609 DEBUG(0,("initialise_wins: failed to open wins.tdb. Error was %s\n",
610 strerror(errno) ));
611 return False;
614 tdb_store_int32(wins_tdb, "WINSDB_VERSION", WINSDB_VERSION);
616 add_samba_names_to_subnet(wins_server_subnet);
618 if((fp = x_fopen(state_path(WINS_LIST),O_RDONLY,0)) == NULL) {
619 DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
620 WINS_LIST, strerror(errno) ));
621 return True;
624 while (!x_feof(fp)) {
625 char *name_str = NULL;
626 char *ip_str = NULL;
627 char *ttl_str = NULL, *nb_flags_str = NULL;
628 unsigned int num_ips;
629 char *name = NULL;
630 struct in_addr *ip_list = NULL;
631 int type = 0;
632 int nb_flags;
633 int ttl;
634 const char *ptr;
635 char *p = NULL;
636 bool got_token;
637 bool was_ip;
638 int i;
639 unsigned int hash;
640 int version;
641 TALLOC_CTX *frame = NULL;
643 /* Read a line from the wins.dat file. Strips whitespace
644 from the beginning and end of the line. */
645 if (!fgets_slash(line,sizeof(line),fp)) {
646 continue;
649 if (*line == '#') {
650 continue;
653 if (strncmp(line,"VERSION ", 8) == 0) {
654 if (sscanf(line,"VERSION %d %u", &version, &hash) != 2 ||
655 version != WINS_VERSION) {
656 DEBUG(0,("Discarding invalid wins.dat file [%s]\n",line));
657 x_fclose(fp);
658 return True;
660 continue;
663 ptr = line;
666 * Now we handle multiple IP addresses per name we need
667 * to iterate over the line twice. The first time to
668 * determine how many IP addresses there are, the second
669 * time to actually parse them into the ip_list array.
672 frame = talloc_stackframe();
673 if (!next_token_talloc(frame,&ptr,&name_str,NULL)) {
674 DEBUG(0,("initialise_wins: Failed to parse name when parsing line %s\n", line ));
675 TALLOC_FREE(frame);
676 continue;
679 if (!next_token_talloc(frame,&ptr,&ttl_str,NULL)) {
680 DEBUG(0,("initialise_wins: Failed to parse time to live when parsing line %s\n", line ));
681 TALLOC_FREE(frame);
682 continue;
686 * Determine the number of IP addresses per line.
688 num_ips = 0;
689 do {
690 got_token = next_token_talloc(frame,&ptr,&ip_str,NULL);
691 was_ip = False;
693 if(got_token && strchr(ip_str, '.')) {
694 num_ips++;
695 was_ip = True;
697 } while(got_token && was_ip);
699 if(num_ips == 0) {
700 DEBUG(0,("initialise_wins: Missing IP address when parsing line %s\n", line ));
701 TALLOC_FREE(frame);
702 continue;
705 if(!got_token) {
706 DEBUG(0,("initialise_wins: Missing nb_flags when parsing line %s\n", line ));
707 TALLOC_FREE(frame);
708 continue;
711 /* Allocate the space for the ip_list. */
712 if((ip_list = SMB_MALLOC_ARRAY( struct in_addr, num_ips)) == NULL) {
713 DEBUG(0,("initialise_wins: Malloc fail !\n"));
714 x_fclose(fp);
715 TALLOC_FREE(frame);
716 return False;
719 /* Reset and re-parse the line. */
720 ptr = line;
721 next_token_talloc(frame,&ptr,&name_str,NULL);
722 next_token_talloc(frame,&ptr,&ttl_str,NULL);
723 for(i = 0; i < num_ips; i++) {
724 next_token_talloc(frame,&ptr, &ip_str, NULL);
725 ip_list[i] = interpret_addr2(ip_str);
727 next_token_talloc(frame,&ptr,&nb_flags_str,NULL);
730 * Deal with SELF or REGISTER name encoding. Default is REGISTER
731 * for compatibility with old nmbds.
734 if(nb_flags_str[strlen(nb_flags_str)-1] == 'S') {
735 DEBUG(5,("initialise_wins: Ignoring SELF name %s\n", line));
736 SAFE_FREE(ip_list);
737 TALLOC_FREE(frame);
738 continue;
741 if(nb_flags_str[strlen(nb_flags_str)-1] == 'R') {
742 nb_flags_str[strlen(nb_flags_str)-1] = '\0';
745 /* Netbios name. # divides the name from the type (hex): netbios#xx */
746 name = name_str;
748 if((p = strchr(name,'#')) != NULL) {
749 *p = 0;
750 sscanf(p+1,"%x",&type);
753 /* Decode the netbios flags (hex) and the time-to-live (in seconds). */
754 sscanf(nb_flags_str,"%x",&nb_flags);
755 sscanf(ttl_str,"%d",&ttl);
757 /* add all entries that have 60 seconds or more to live */
758 if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) {
759 if(ttl != PERMANENT_TTL) {
760 ttl -= time_now;
763 DEBUG( 4, ("initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
764 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
766 (void)add_name_to_subnet( wins_server_subnet, name, type, nb_flags,
767 ttl, REGISTER_NAME, num_ips, ip_list );
768 } else {
769 DEBUG(4, ("initialise_wins: not adding name (ttl problem) "
770 "%s#%02x ttl = %d first IP %s flags = %2x\n",
771 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
774 TALLOC_FREE(frame);
775 SAFE_FREE(ip_list);
778 x_fclose(fp);
779 return True;
782 /****************************************************************************
783 Send a WINS WACK (Wait ACKnowledgement) response.
784 **************************************************************************/
786 static void send_wins_wack_response(int ttl, struct packet_struct *p)
788 struct nmb_packet *nmb = &p->packet.nmb;
789 unsigned char rdata[2];
791 rdata[0] = rdata[1] = 0;
793 /* Taken from nmblib.c - we need to send back almost
794 identical bytes from the requesting packet header. */
796 rdata[0] = (nmb->header.opcode & 0xF) << 3;
797 if (nmb->header.nm_flags.authoritative && nmb->header.response) {
798 rdata[0] |= 0x4;
800 if (nmb->header.nm_flags.trunc) {
801 rdata[0] |= 0x2;
803 if (nmb->header.nm_flags.recursion_desired) {
804 rdata[0] |= 0x1;
806 if (nmb->header.nm_flags.recursion_available && nmb->header.response) {
807 rdata[1] |= 0x80;
809 if (nmb->header.nm_flags.bcast) {
810 rdata[1] |= 0x10;
813 reply_netbios_packet(p, /* Packet to reply to. */
814 0, /* Result code. */
815 NMB_WAIT_ACK, /* nmbd type code. */
816 NMB_WACK_OPCODE, /* opcode. */
817 ttl, /* ttl. */
818 (char *)rdata, /* data to send. */
819 2); /* data length. */
822 /****************************************************************************
823 Send a WINS name registration response.
824 **************************************************************************/
826 static void send_wins_name_registration_response(int rcode, int ttl, struct packet_struct *p)
828 struct nmb_packet *nmb = &p->packet.nmb;
829 char rdata[6];
831 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
833 reply_netbios_packet(p, /* Packet to reply to. */
834 rcode, /* Result code. */
835 WINS_REG, /* nmbd type code. */
836 NMB_NAME_REG_OPCODE, /* opcode. */
837 ttl, /* ttl. */
838 rdata, /* data to send. */
839 6); /* data length. */
842 /***********************************************************************
843 Deal with a name refresh request to a WINS server.
844 ************************************************************************/
846 void wins_process_name_refresh_request( struct subnet_record *subrec,
847 struct packet_struct *p )
849 struct nmb_packet *nmb = &p->packet.nmb;
850 struct nmb_name *question = &nmb->question.question_name;
851 bool bcast = nmb->header.nm_flags.bcast;
852 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
853 bool group = (nb_flags & NB_GROUP) ? True : False;
854 struct name_record *namerec = NULL;
855 int ttl = get_ttl_from_packet(nmb);
856 struct in_addr from_ip;
857 struct in_addr our_fake_ip;
859 our_fake_ip = interpret_addr2("0.0.0.0");
860 putip( (char *)&from_ip, &nmb->additional->rdata[2] );
862 if(bcast) {
864 * We should only get unicast name refresh packets here.
865 * Anyone trying to refresh broadcast should not be going
866 * to a WINS server. Log an error here.
868 if( DEBUGLVL( 0 ) ) {
869 dbgtext( "wins_process_name_refresh_request: " );
870 dbgtext( "Broadcast name refresh request received " );
871 dbgtext( "for name %s ", nmb_namestr(question) );
872 dbgtext( "from IP %s ", inet_ntoa(from_ip) );
873 dbgtext( "on subnet %s. ", subrec->subnet_name );
874 dbgtext( "Error - Broadcasts should not be sent " );
875 dbgtext( "to a WINS server\n" );
877 return;
880 if( DEBUGLVL( 3 ) ) {
881 dbgtext( "wins_process_name_refresh_request: " );
882 dbgtext( "Name refresh for name %s IP %s\n",
883 nmb_namestr(question), inet_ntoa(from_ip) );
887 * See if the name already exists.
888 * If not, handle it as a name registration and return.
890 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
893 * If this is a refresh request and the name doesn't exist then
894 * treat it like a registration request. This allows us to recover
895 * from errors (tridge)
897 if(namerec == NULL) {
898 if( DEBUGLVL( 3 ) ) {
899 dbgtext( "wins_process_name_refresh_request: " );
900 dbgtext( "Name refresh for name %s ",
901 nmb_namestr( question ) );
902 dbgtext( "and the name does not exist. Treating " );
903 dbgtext( "as registration.\n" );
905 wins_process_name_registration_request(subrec,p);
906 return;
910 * if the name is present but not active, simply remove it
911 * and treat the refresh request as a registration & return.
913 if (namerec != NULL && !WINS_STATE_ACTIVE(namerec)) {
914 if( DEBUGLVL( 5 ) ) {
915 dbgtext( "wins_process_name_refresh_request: " );
916 dbgtext( "Name (%s) in WINS ", nmb_namestr(question) );
917 dbgtext( "was not active - removing it.\n" );
919 remove_name_from_namelist( subrec, namerec );
920 namerec = NULL;
921 wins_process_name_registration_request( subrec, p );
922 return;
926 * Check that the group bits for the refreshing name and the
927 * name in our database match. If not, refuse the refresh.
928 * [crh: Why RFS_ERR instead of ACT_ERR? Is this what MS does?]
930 if( (namerec != NULL) &&
931 ( (group && !NAME_GROUP(namerec))
932 || (!group && NAME_GROUP(namerec)) ) ) {
933 if( DEBUGLVL( 3 ) ) {
934 dbgtext( "wins_process_name_refresh_request: " );
935 dbgtext( "Name %s ", nmb_namestr(question) );
936 dbgtext( "group bit = %s does not match ",
937 group ? "True" : "False" );
938 dbgtext( "group bit in WINS for this name.\n" );
940 send_wins_name_registration_response(RFS_ERR, 0, p);
941 return;
945 * For a unique name check that the person refreshing the name is
946 * one of the registered IP addresses. If not - fail the refresh.
947 * Do the same for group names with a type of 0x1c.
948 * Just return success for unique 0x1d refreshes. For normal group
949 * names update the ttl and return success.
951 if( (!group || (group && (question->name_type == 0x1c)))
952 && find_ip_in_name_record(namerec, from_ip) ) {
954 * Update the ttl.
956 update_name_ttl(namerec, ttl);
959 * if the record is a replica:
960 * we take ownership and update the version ID.
962 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
963 update_wins_owner(namerec, our_fake_ip);
964 get_global_id_and_update(&namerec->data.id, True);
967 send_wins_name_registration_response(0, ttl, p);
968 wins_hook("refresh", namerec, ttl);
969 return;
970 } else if((group && (question->name_type == 0x1c))) {
972 * Added by crh for bug #1079.
973 * Fix from Bert Driehuis
975 if( DEBUGLVL( 3 ) ) {
976 dbgtext( "wins_process_name_refresh_request: " );
977 dbgtext( "Name refresh for name %s, ",
978 nmb_namestr(question) );
979 dbgtext( "but IP address %s ", inet_ntoa(from_ip) );
980 dbgtext( "is not yet associated with " );
981 dbgtext( "that name. Treating as registration.\n" );
983 wins_process_name_registration_request(subrec,p);
984 return;
985 } else if(group) {
987 * Normal groups are all registered with an IP address of
988 * 255.255.255.255 so we can't search for the IP address.
990 update_name_ttl(namerec, ttl);
991 wins_hook("refresh", namerec, ttl);
992 send_wins_name_registration_response(0, ttl, p);
993 return;
994 } else if(!group && (question->name_type == 0x1d)) {
996 * Special name type - just pretend the refresh succeeded.
998 send_wins_name_registration_response(0, ttl, p);
999 return;
1000 } else {
1002 * Fail the refresh.
1004 if( DEBUGLVL( 3 ) ) {
1005 dbgtext( "wins_process_name_refresh_request: " );
1006 dbgtext( "Name refresh for name %s with IP %s ",
1007 nmb_namestr(question), inet_ntoa(from_ip) );
1008 dbgtext( "and is IP is not known to the name.\n" );
1010 send_wins_name_registration_response(RFS_ERR, 0, p);
1011 return;
1015 /***********************************************************************
1016 Deal with a name registration request query success to a client that
1017 owned the name.
1019 We have a locked pointer to the original packet stashed away in the
1020 userdata pointer. The success here is actually a failure as it means
1021 the client we queried wants to keep the name, so we must return
1022 a registration failure to the original requestor.
1023 ************************************************************************/
1025 static void wins_register_query_success(struct subnet_record *subrec,
1026 struct userdata_struct *userdata,
1027 struct nmb_name *question_name,
1028 struct in_addr ip,
1029 struct res_rec *answers)
1031 struct packet_struct *orig_reg_packet;
1033 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1035 DEBUG(3,("wins_register_query_success: Original client at IP %s still wants the \
1036 name %s. Rejecting registration request.\n", inet_ntoa(ip), nmb_namestr(question_name) ));
1038 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1040 orig_reg_packet->locked = False;
1041 free_packet(orig_reg_packet);
1044 /***********************************************************************
1045 Deal with a name registration request query failure to a client that
1046 owned the name.
1048 We have a locked pointer to the original packet stashed away in the
1049 userdata pointer. The failure here is actually a success as it means
1050 the client we queried didn't want to keep the name, so we can remove
1051 the old name record and then successfully add the new name.
1052 ************************************************************************/
1054 static void wins_register_query_fail(struct subnet_record *subrec,
1055 struct response_record *rrec,
1056 struct nmb_name *question_name,
1057 int rcode)
1059 struct userdata_struct *userdata = rrec->userdata;
1060 struct packet_struct *orig_reg_packet;
1061 struct name_record *namerec = NULL;
1063 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1066 * We want to just add the name, as we now know the original owner
1067 * didn't want it. But we can't just do that as an arbitary
1068 * amount of time may have taken place between the name query
1069 * request and this timeout/error response. So we check that
1070 * the name still exists and is in the same state - if so
1071 * we remove it and call wins_process_name_registration_request()
1072 * as we know it will do the right thing now.
1075 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1077 if ((namerec != NULL) && (namerec->data.source == REGISTER_NAME) &&
1078 ip_equal_v4(rrec->packet->ip, *namerec->data.ip)) {
1079 remove_name_from_namelist( subrec, namerec);
1080 namerec = NULL;
1083 if(namerec == NULL) {
1084 wins_process_name_registration_request(subrec, orig_reg_packet);
1085 } else {
1086 DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between "
1087 "querying for name %s in order to replace it and this reply.\n",
1088 nmb_namestr(question_name) ));
1091 orig_reg_packet->locked = False;
1092 free_packet(orig_reg_packet);
1095 /***********************************************************************
1096 Deal with a name registration request to a WINS server.
1098 Use the following pseudocode :
1100 registering_group
1103 +--------name exists
1106 | +--- existing name is group
1107 | | |
1108 | | |
1109 | | +--- add name (return).
1112 | +--- exiting name is unique
1115 | +--- query existing owner (return).
1118 +--------name doesn't exist
1121 +--- add name (return).
1123 registering_unique
1126 +--------name exists
1129 | +--- existing name is group
1130 | | |
1131 | | |
1132 | | +--- fail add (return).
1133 | |
1135 | +--- exiting name is unique
1138 | +--- query existing owner (return).
1141 +--------name doesn't exist
1144 +--- add name (return).
1146 As can be seen from the above, the two cases may be collapsed onto each
1147 other with the exception of the case where the name already exists and
1148 is a group name. This case we handle with an if statement.
1150 ************************************************************************/
1152 void wins_process_name_registration_request(struct subnet_record *subrec,
1153 struct packet_struct *p)
1155 unstring name;
1156 struct nmb_packet *nmb = &p->packet.nmb;
1157 struct nmb_name *question = &nmb->question.question_name;
1158 bool bcast = nmb->header.nm_flags.bcast;
1159 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
1160 int ttl = get_ttl_from_packet(nmb);
1161 struct name_record *namerec = NULL;
1162 struct in_addr from_ip;
1163 bool registering_group_name = (nb_flags & NB_GROUP) ? True : False;
1164 struct in_addr our_fake_ip;
1166 our_fake_ip = interpret_addr2("0.0.0.0");
1167 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1169 if(bcast) {
1171 * We should only get unicast name registration packets here.
1172 * Anyone trying to register broadcast should not be going to a WINS
1173 * server. Log an error here.
1176 DEBUG(0,("wins_process_name_registration_request: broadcast name registration request \
1177 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1178 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1179 return;
1182 DEBUG(3,("wins_process_name_registration_request: %s name registration for name %s \
1183 IP %s\n", registering_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
1186 * See if the name already exists.
1189 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1192 * if the record exists but NOT in active state,
1193 * consider it dead.
1195 if ( (namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1196 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1197 not active - removing it.\n", nmb_namestr(question) ));
1198 remove_name_from_namelist( subrec, namerec );
1199 namerec = NULL;
1203 * Deal with the case where the name found was a dns entry.
1204 * Remove it as we now have a NetBIOS client registering the
1205 * name.
1208 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1209 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1210 a dns lookup - removing it.\n", nmb_namestr(question) ));
1211 remove_name_from_namelist( subrec, namerec );
1212 namerec = NULL;
1216 * Reject if the name exists and is not a REGISTER_NAME.
1217 * (ie. Don't allow any static names to be overwritten.
1220 if((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) {
1221 DEBUG( 3, ( "wins_process_name_registration_request: Attempt \
1222 to register name %s. Name already exists in WINS with source type %d.\n",
1223 nmb_namestr(question), namerec->data.source ));
1224 send_wins_name_registration_response(RFS_ERR, 0, p);
1225 return;
1229 * Special policy decisions based on MS documentation.
1230 * 1). All group names (except names ending in 0x1c) are added as 255.255.255.255.
1231 * 2). All unique names ending in 0x1d are ignored, although a positive response is sent.
1235 * A group name is always added as the local broadcast address, except
1236 * for group names ending in 0x1c.
1237 * Group names with type 0x1c are registered with individual IP addresses.
1240 if(registering_group_name && (question->name_type != 0x1c)) {
1241 from_ip = interpret_addr2("255.255.255.255");
1245 * Ignore all attempts to register a unique 0x1d name, although return success.
1248 if(!registering_group_name && (question->name_type == 0x1d)) {
1249 DEBUG(3,("wins_process_name_registration_request: Ignoring request \
1250 to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
1251 send_wins_name_registration_response(0, ttl, p);
1252 return;
1256 * Next two cases are the 'if statement' mentioned above.
1259 if((namerec != NULL) && NAME_GROUP(namerec)) {
1260 if(registering_group_name) {
1262 * If we are adding a group name, the name exists and is also a group entry just add this
1263 * IP address to it and update the ttl.
1266 DEBUG(3,("wins_process_name_registration_request: Adding IP %s to group name %s.\n",
1267 inet_ntoa(from_ip), nmb_namestr(question) ));
1270 * Check the ip address is not already in the group.
1273 if(!find_ip_in_name_record(namerec, from_ip)) {
1275 * Need to emulate the behaviour of Windows, as
1276 * described in:
1277 * http://lists.samba.org/archive/samba-technical/2001-October/016236.html
1278 * (is there an MS reference for this
1279 * somewhere?) because if the 1c list gets over
1280 * 86 entries, the reply packet is too big
1281 * (rdata>576 bytes) so no reply is sent.
1283 * Keep only the "latest" 25 records, while
1284 * ensuring that the PDC (0x1b) is never removed
1285 * We do this by removing the first entry that
1286 * isn't the 1b entry for the same name,
1287 * on the grounds that insertion is at the end
1288 * of the list, so the oldest entries are at
1289 * the start.
1292 while(namerec->data.num_ips>=25) {
1293 struct name_record *name1brec = NULL;
1295 /* We only do this for 1c types. */
1296 if (namerec->name.name_type != 0x1c) {
1297 break;
1299 DEBUG(3,("wins_process_name_registration_request: "
1300 "More than 25 IPs already in "
1301 "the list. Looking for a 1b "
1302 "record\n"));
1304 /* Ensure we have all the active 1b
1305 * names on the list. */
1306 wins_delete_all_1b_in_memory_records();
1307 fetch_all_active_wins_1b_names();
1309 /* Per the above, find the 1b record,
1310 and then remove the first IP that isn't the same */
1311 for(name1brec = subrec->namelist;
1312 name1brec;
1313 name1brec = name1brec->next ) {
1314 if( WINS_STATE_ACTIVE(name1brec) &&
1315 name1brec->name.name_type == 0x1b) {
1316 DEBUG(3,("wins_process_name_registration_request: "
1317 "Found the #1b record "
1318 "with ip %s\n",
1319 inet_ntoa(name1brec->data.ip[0])));
1320 break;
1323 if(!name1brec) {
1324 DEBUG(3,("wins_process_name_registration_request: "
1325 "Didn't find a #1b name record. "
1326 "Removing the first available "
1327 "entry %s\n",
1328 inet_ntoa(namerec->data.ip[0])));
1329 remove_ip_from_name_record(namerec, namerec->data.ip[0]);
1330 wins_hook("delete", namerec, 0);
1331 } else {
1332 int i;
1333 for(i=0; i<namerec->data.num_ips; i++) {
1334 /* The name1brec should only have
1335 * the single IP address in it,
1336 * so we only check against the first one*/
1337 if(!ip_equal_v4( namerec->data.ip[i], name1brec->data.ip[0])) {
1338 /* The i'th entry isn't the 1b address; delete it */
1339 DEBUG(3,("wins_process_name_registration_request: "
1340 "Entry at %d is not the #1b address. "
1341 "About to remove it\n",
1342 i));
1343 remove_ip_from_name_record(namerec, namerec->data.ip[i]);
1344 wins_hook("delete", namerec, 0);
1345 break;
1350 /* The list is guaranteed to be < 25 entries now
1351 * - safe to add a new one */
1352 add_ip_to_name_record(namerec, from_ip);
1353 /* we need to update the record for replication */
1354 get_global_id_and_update(&namerec->data.id, True);
1357 * if the record is a replica, we must change
1358 * the wins owner to us to make the replication updates
1359 * it on the other wins servers.
1360 * And when the partner will receive this record,
1361 * it will update its own record.
1364 update_wins_owner(namerec, our_fake_ip);
1366 update_name_ttl(namerec, ttl);
1367 wins_hook("refresh", namerec, ttl);
1368 send_wins_name_registration_response(0, ttl, p);
1369 return;
1370 } else {
1373 * If we are adding a unique name, the name exists in the WINS db
1374 * and is a group name then reject the registration.
1376 * explanation: groups have a higher priority than unique names.
1379 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1380 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1381 send_wins_name_registration_response(RFS_ERR, 0, p);
1382 return;
1387 * From here on down we know that if the name exists in the WINS db it is
1388 * a unique name, not a group name.
1392 * If the name exists and is one of our names then check the
1393 * registering IP address. If it's not one of ours then automatically
1394 * reject without doing the query - we know we will reject it.
1397 if ( namerec != NULL ) {
1398 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
1399 if( is_myname(name) ) {
1400 if(!ismyip_v4(from_ip)) {
1401 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1402 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1403 send_wins_name_registration_response(RFS_ERR, 0, p);
1404 return;
1405 } else {
1407 * It's one of our names and one of our IP's - update the ttl.
1409 update_name_ttl(namerec, ttl);
1410 wins_hook("refresh", namerec, ttl);
1411 send_wins_name_registration_response(0, ttl, p);
1412 return;
1415 } else {
1416 name[0] = '\0';
1420 * If the name exists and it is a unique registration and the registering IP
1421 * is the same as the (single) already registered IP then just update the ttl.
1423 * But not if the record is an active replica. IF it's a replica, it means it can be
1424 * the same client which has moved and not yet expired. So we don't update
1425 * the ttl in this case and go beyond to do a WACK and query the old client
1428 if( !registering_group_name
1429 && (namerec != NULL)
1430 && (namerec->data.num_ips == 1)
1431 && ip_equal_v4( namerec->data.ip[0], from_ip )
1432 && ip_equal_v4(namerec->data.wins_ip, our_fake_ip) ) {
1433 update_name_ttl( namerec, ttl );
1434 wins_hook("refresh", namerec, ttl);
1435 send_wins_name_registration_response( 0, ttl, p );
1436 return;
1440 * Finally if the name exists do a query to the registering machine
1441 * to see if they still claim to have the name.
1444 if( namerec != NULL ) {
1445 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1446 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1449 * First send a WACK to the registering machine.
1452 send_wins_wack_response(60, p);
1455 * When the reply comes back we need the original packet.
1456 * Lock this so it won't be freed and then put it into
1457 * the userdata structure.
1460 p->locked = True;
1462 userdata = (struct userdata_struct *)ud;
1464 userdata->copy_fn = NULL;
1465 userdata->free_fn = NULL;
1466 userdata->userdata_len = sizeof(struct packet_struct *);
1467 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1470 * Use the new call to send a query directly to an IP address.
1471 * This sends the query directly to the IP address, and ensures
1472 * the recursion desired flag is not set (you were right Luke :-).
1473 * This function should *only* be called from the WINS server
1474 * code. JRA.
1477 pull_ascii_nstring(name, sizeof(name), question->name);
1478 query_name_from_wins_server( *namerec->data.ip,
1479 name,
1480 question->name_type,
1481 wins_register_query_success,
1482 wins_register_query_fail,
1483 userdata );
1484 return;
1488 * Name did not exist - add it.
1491 pull_ascii_nstring(name, sizeof(name), question->name);
1492 add_name_to_subnet( subrec, name, question->name_type,
1493 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1495 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1496 get_global_id_and_update(&namerec->data.id, True);
1497 update_wins_owner(namerec, our_fake_ip);
1498 update_wins_flag(namerec, WINS_ACTIVE);
1499 wins_hook("add", namerec, ttl);
1502 send_wins_name_registration_response(0, ttl, p);
1505 /***********************************************************************
1506 Deal with a mutihomed name query success to the machine that
1507 requested the multihomed name registration.
1509 We have a locked pointer to the original packet stashed away in the
1510 userdata pointer.
1511 ************************************************************************/
1513 static void wins_multihomed_register_query_success(struct subnet_record *subrec,
1514 struct userdata_struct *userdata,
1515 struct nmb_name *question_name,
1516 struct in_addr ip,
1517 struct res_rec *answers)
1519 struct packet_struct *orig_reg_packet;
1520 struct nmb_packet *nmb;
1521 struct name_record *namerec = NULL;
1522 struct in_addr from_ip;
1523 int ttl;
1524 struct in_addr our_fake_ip;
1526 our_fake_ip = interpret_addr2("0.0.0.0");
1527 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1529 nmb = &orig_reg_packet->packet.nmb;
1531 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1532 ttl = get_ttl_from_packet(nmb);
1535 * We want to just add the new IP, as we now know the requesting
1536 * machine claims to own it. But we can't just do that as an arbitary
1537 * amount of time may have taken place between the name query
1538 * request and this response. So we check that
1539 * the name still exists and is in the same state - if so
1540 * we just add the extra IP and update the ttl.
1543 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1545 if( (namerec == NULL) || (namerec->data.source != REGISTER_NAME) || !WINS_STATE_ACTIVE(namerec) ) {
1546 DEBUG(3,("wins_multihomed_register_query_success: name %s is not in the correct state to add \
1547 a subsequent IP address.\n", nmb_namestr(question_name) ));
1548 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1550 orig_reg_packet->locked = False;
1551 free_packet(orig_reg_packet);
1553 return;
1556 if(!find_ip_in_name_record(namerec, from_ip)) {
1557 add_ip_to_name_record(namerec, from_ip);
1560 get_global_id_and_update(&namerec->data.id, True);
1561 update_wins_owner(namerec, our_fake_ip);
1562 update_wins_flag(namerec, WINS_ACTIVE);
1563 update_name_ttl(namerec, ttl);
1564 wins_hook("add", namerec, ttl);
1565 send_wins_name_registration_response(0, ttl, orig_reg_packet);
1567 orig_reg_packet->locked = False;
1568 free_packet(orig_reg_packet);
1571 /***********************************************************************
1572 Deal with a name registration request query failure to a client that
1573 owned the name.
1575 We have a locked pointer to the original packet stashed away in the
1576 userdata pointer.
1577 ************************************************************************/
1579 static void wins_multihomed_register_query_fail(struct subnet_record *subrec,
1580 struct response_record *rrec,
1581 struct nmb_name *question_name,
1582 int rcode)
1584 struct userdata_struct *userdata = rrec->userdata;
1585 struct packet_struct *orig_reg_packet;
1587 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1589 DEBUG(3,("wins_multihomed_register_query_fail: Registering machine at IP %s failed to answer \
1590 query successfully for name %s.\n", inet_ntoa(orig_reg_packet->ip), nmb_namestr(question_name) ));
1591 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1593 orig_reg_packet->locked = False;
1594 free_packet(orig_reg_packet);
1595 return;
1598 /***********************************************************************
1599 Deal with a multihomed name registration request to a WINS server.
1600 These cannot be group name registrations.
1601 ***********************************************************************/
1603 void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
1604 struct packet_struct *p)
1606 struct nmb_packet *nmb = &p->packet.nmb;
1607 struct nmb_name *question = &nmb->question.question_name;
1608 bool bcast = nmb->header.nm_flags.bcast;
1609 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
1610 int ttl = get_ttl_from_packet(nmb);
1611 struct name_record *namerec = NULL;
1612 struct in_addr from_ip;
1613 bool group = (nb_flags & NB_GROUP) ? True : False;
1614 struct in_addr our_fake_ip;
1615 unstring qname;
1617 our_fake_ip = interpret_addr2("0.0.0.0");
1618 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1620 if(bcast) {
1622 * We should only get unicast name registration packets here.
1623 * Anyone trying to register broadcast should not be going to a WINS
1624 * server. Log an error here.
1627 DEBUG(0,("wins_process_multihomed_name_registration_request: broadcast name registration request \
1628 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1629 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1630 return;
1634 * Only unique names should be registered multihomed.
1637 if(group) {
1638 DEBUG(0,("wins_process_multihomed_name_registration_request: group name registration request \
1639 received for name %s from IP %s on subnet %s. Errror - group names should not be multihomed.\n",
1640 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1641 return;
1644 DEBUG(3,("wins_process_multihomed_name_registration_request: name registration for name %s \
1645 IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ));
1648 * Deal with policy regarding 0x1d names.
1651 if(question->name_type == 0x1d) {
1652 DEBUG(3,("wins_process_multihomed_name_registration_request: Ignoring request \
1653 to register name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
1654 send_wins_name_registration_response(0, ttl, p);
1655 return;
1659 * See if the name already exists.
1662 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1665 * if the record exists but NOT in active state,
1666 * consider it dead.
1669 if ((namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1670 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was not active - removing it.\n", nmb_namestr(question)));
1671 remove_name_from_namelist(subrec, namerec);
1672 namerec = NULL;
1676 * Deal with the case where the name found was a dns entry.
1677 * Remove it as we now have a NetBIOS client registering the
1678 * name.
1681 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1682 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was a dns lookup \
1683 - removing it.\n", nmb_namestr(question) ));
1684 remove_name_from_namelist( subrec, namerec);
1685 namerec = NULL;
1689 * Reject if the name exists and is not a REGISTER_NAME.
1690 * (ie. Don't allow any static names to be overwritten.
1693 if( (namerec != NULL) && (namerec->data.source != REGISTER_NAME) ) {
1694 DEBUG( 3, ( "wins_process_multihomed_name_registration_request: Attempt \
1695 to register name %s. Name already exists in WINS with source type %d.\n",
1696 nmb_namestr(question), namerec->data.source ));
1697 send_wins_name_registration_response(RFS_ERR, 0, p);
1698 return;
1702 * Reject if the name exists and is a GROUP name and is active.
1705 if((namerec != NULL) && NAME_GROUP(namerec) && WINS_STATE_ACTIVE(namerec)) {
1706 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1707 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1708 send_wins_name_registration_response(RFS_ERR, 0, p);
1709 return;
1713 * From here on down we know that if the name exists in the WINS db it is
1714 * a unique name, not a group name.
1718 * If the name exists and is one of our names then check the
1719 * registering IP address. If it's not one of ours then automatically
1720 * reject without doing the query - we know we will reject it.
1723 if((namerec != NULL) && (is_myname(namerec->name.name)) ) {
1724 if(!ismyip_v4(from_ip)) {
1725 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1726 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1727 send_wins_name_registration_response(RFS_ERR, 0, p);
1728 return;
1729 } else {
1731 * It's one of our names and one of our IP's. Ensure the IP is in the record and
1732 * update the ttl. Update the version ID to force replication.
1734 update_name_ttl(namerec, ttl);
1736 if(!find_ip_in_name_record(namerec, from_ip)) {
1737 get_global_id_and_update(&namerec->data.id, True);
1738 update_wins_owner(namerec, our_fake_ip);
1739 update_wins_flag(namerec, WINS_ACTIVE);
1741 add_ip_to_name_record(namerec, from_ip);
1744 wins_hook("refresh", namerec, ttl);
1745 send_wins_name_registration_response(0, ttl, p);
1746 return;
1751 * If the name exists and is active, check if the IP address is already registered
1752 * to that name. If so then update the ttl and reply success.
1755 if((namerec != NULL) && find_ip_in_name_record(namerec, from_ip) && WINS_STATE_ACTIVE(namerec)) {
1756 update_name_ttl(namerec, ttl);
1759 * If it's a replica, we need to become the wins owner
1760 * to force the replication
1762 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
1763 get_global_id_and_update(&namerec->data.id, True);
1764 update_wins_owner(namerec, our_fake_ip);
1765 update_wins_flag(namerec, WINS_ACTIVE);
1768 wins_hook("refresh", namerec, ttl);
1769 send_wins_name_registration_response(0, ttl, p);
1770 return;
1774 * If the name exists do a query to the owner
1775 * to see if they still want the name.
1778 if(namerec != NULL) {
1779 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1780 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1783 * First send a WACK to the registering machine.
1786 send_wins_wack_response(60, p);
1789 * When the reply comes back we need the original packet.
1790 * Lock this so it won't be freed and then put it into
1791 * the userdata structure.
1794 p->locked = True;
1796 userdata = (struct userdata_struct *)ud;
1798 userdata->copy_fn = NULL;
1799 userdata->free_fn = NULL;
1800 userdata->userdata_len = sizeof(struct packet_struct *);
1801 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1804 * Use the new call to send a query directly to an IP address.
1805 * This sends the query directly to the IP address, and ensures
1806 * the recursion desired flag is not set (you were right Luke :-).
1807 * This function should *only* be called from the WINS server
1808 * code. JRA.
1810 * Note that this packet is sent to the current owner of the name,
1811 * not the person who sent the packet
1814 pull_ascii_nstring( qname, sizeof(qname), question->name);
1815 query_name_from_wins_server( namerec->data.ip[0],
1816 qname,
1817 question->name_type,
1818 wins_multihomed_register_query_success,
1819 wins_multihomed_register_query_fail,
1820 userdata );
1822 return;
1826 * Name did not exist - add it.
1829 pull_ascii_nstring( qname, sizeof(qname), question->name);
1830 add_name_to_subnet( subrec, qname, question->name_type,
1831 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1833 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1834 get_global_id_and_update(&namerec->data.id, True);
1835 update_wins_owner(namerec, our_fake_ip);
1836 update_wins_flag(namerec, WINS_ACTIVE);
1837 wins_hook("add", namerec, ttl);
1840 send_wins_name_registration_response(0, ttl, p);
1843 /***********************************************************************
1844 Fetch all *<1b> names from the WINS db and store on the namelist.
1845 ***********************************************************************/
1847 static int fetch_1b_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
1849 struct name_record *namerec = NULL;
1851 if (kbuf.dsize != sizeof(unstring) + 1) {
1852 return 0;
1855 /* Filter out all non-1b names. */
1856 if (kbuf.dptr[sizeof(unstring)] != 0x1b) {
1857 return 0;
1860 namerec = wins_record_to_name_record(kbuf, dbuf);
1861 if (!namerec) {
1862 return 0;
1865 DLIST_ADD(wins_server_subnet->namelist, namerec);
1866 return 0;
1869 void fetch_all_active_wins_1b_names(void)
1871 tdb_traverse(wins_tdb, fetch_1b_traverse_fn, NULL);
1874 /***********************************************************************
1875 Deal with the special name query for *<1b>.
1876 ***********************************************************************/
1878 static void process_wins_dmb_query_request(struct subnet_record *subrec,
1879 struct packet_struct *p)
1881 struct name_record *namerec = NULL;
1882 char *prdata;
1883 int num_ips;
1886 * Go through all the ACTIVE names in the WINS db looking for those
1887 * ending in <1b>. Use this to calculate the number of IP
1888 * addresses we need to return.
1891 num_ips = 0;
1893 /* First, clear the in memory list - we're going to re-populate
1894 it with the tdb_traversal in fetch_all_active_wins_1b_names. */
1896 wins_delete_all_tmp_in_memory_records();
1898 fetch_all_active_wins_1b_names();
1900 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1901 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1902 num_ips += namerec->data.num_ips;
1906 if(num_ips == 0) {
1908 * There are no 0x1b names registered. Return name query fail.
1910 send_wins_name_query_response(NAM_ERR, p, NULL);
1911 return;
1914 if((prdata = (char *)SMB_MALLOC( num_ips * 6 )) == NULL) {
1915 DEBUG(0,("process_wins_dmb_query_request: Malloc fail !.\n"));
1916 return;
1920 * Go through all the names again in the WINS db looking for those
1921 * ending in <1b>. Add their IP addresses into the list we will
1922 * return.
1925 num_ips = 0;
1926 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1927 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1928 int i;
1929 for(i = 0; i < namerec->data.num_ips; i++) {
1930 set_nb_flags(&prdata[num_ips * 6],namerec->data.nb_flags);
1931 putip((char *)&prdata[(num_ips * 6) + 2], &namerec->data.ip[i]);
1932 num_ips++;
1938 * Send back the reply containing the IP list.
1941 reply_netbios_packet(p, /* Packet to reply to. */
1942 0, /* Result code. */
1943 WINS_QUERY, /* nmbd type code. */
1944 NMB_NAME_QUERY_OPCODE, /* opcode. */
1945 lp_min_wins_ttl(), /* ttl. */
1946 prdata, /* data to send. */
1947 num_ips*6); /* data length. */
1949 SAFE_FREE(prdata);
1952 /****************************************************************************
1953 Send a WINS name query response.
1954 **************************************************************************/
1956 void send_wins_name_query_response(int rcode, struct packet_struct *p,
1957 struct name_record *namerec)
1959 char rdata[6];
1960 char *prdata = rdata;
1961 int reply_data_len = 0;
1962 int ttl = 0;
1963 int i;
1965 memset(rdata,'\0',6);
1967 if(rcode == 0) {
1969 int ip_count;
1971 ttl = (namerec->data.death_time != PERMANENT_TTL) ? namerec->data.death_time - p->timestamp : lp_max_wins_ttl();
1973 /* The netbios reply packet data section is limited to 576 bytes. In theory
1974 * this should give us space for 96 addresses, but in practice, 86 appears
1975 * to be the max (don't know why). If we send any more than that,
1976 * reply_netbios_packet will fail to send a reply to avoid a memcpy buffer
1977 * overflow. Keep the count to 85 and it will be ok */
1978 ip_count=namerec->data.num_ips;
1979 if(ip_count>85) {
1980 ip_count=85;
1983 /* Copy all known ip addresses into the return data. */
1984 /* Optimise for the common case of one IP address so we don't need a malloc. */
1986 if( ip_count == 1 ) {
1987 prdata = rdata;
1988 } else {
1989 if((prdata = (char *)SMB_MALLOC( ip_count * 6 )) == NULL) {
1990 DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
1991 return;
1995 for(i = 0; i < ip_count; i++) {
1996 set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
1997 putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
2000 sort_query_replies(prdata, i, p->ip);
2001 reply_data_len = ip_count * 6;
2004 reply_netbios_packet(p, /* Packet to reply to. */
2005 rcode, /* Result code. */
2006 WINS_QUERY, /* nmbd type code. */
2007 NMB_NAME_QUERY_OPCODE, /* opcode. */
2008 ttl, /* ttl. */
2009 prdata, /* data to send. */
2010 reply_data_len); /* data length. */
2012 if(prdata != rdata) {
2013 SAFE_FREE(prdata);
2017 /***********************************************************************
2018 Deal with a name query.
2019 ***********************************************************************/
2021 void wins_process_name_query_request(struct subnet_record *subrec,
2022 struct packet_struct *p)
2024 struct nmb_packet *nmb = &p->packet.nmb;
2025 struct nmb_name *question = &nmb->question.question_name;
2026 struct name_record *namerec = NULL;
2027 unstring qname;
2029 DEBUG(3,("wins_process_name_query: name query for name %s from IP %s\n",
2030 nmb_namestr(question), inet_ntoa(p->ip) ));
2033 * Special name code. If the queried name is *<1b> then search
2034 * the entire WINS database and return a list of all the IP addresses
2035 * registered to any <1b> name. This is to allow domain master browsers
2036 * to discover other domains that may not have a presence on their subnet.
2039 pull_ascii_nstring(qname, sizeof(qname), question->name);
2040 if(strequal( qname, "*") && (question->name_type == 0x1b)) {
2041 process_wins_dmb_query_request( subrec, p);
2042 return;
2045 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2047 if(namerec != NULL) {
2049 * If the name is not anymore in active state then reply not found.
2050 * it's fair even if we keep it in the cache for days.
2052 if (!WINS_STATE_ACTIVE(namerec)) {
2053 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
2054 nmb_namestr(question) ));
2055 send_wins_name_query_response(NAM_ERR, p, namerec);
2056 return;
2060 * If it's a DNSFAIL_NAME then reply name not found.
2063 if( namerec->data.source == DNSFAIL_NAME ) {
2064 DEBUG(3,("wins_process_name_query: name query for name %s returning DNS fail.\n",
2065 nmb_namestr(question) ));
2066 send_wins_name_query_response(NAM_ERR, p, namerec);
2067 return;
2071 * If the name has expired then reply name not found.
2074 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < p->timestamp) ) {
2075 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
2076 nmb_namestr(question) ));
2077 send_wins_name_query_response(NAM_ERR, p, namerec);
2078 return;
2081 DEBUG(3,("wins_process_name_query: name query for name %s returning first IP %s.\n",
2082 nmb_namestr(question), inet_ntoa(namerec->data.ip[0]) ));
2084 send_wins_name_query_response(0, p, namerec);
2085 return;
2089 * Name not found in WINS - try a dns query if it's a 0x20 name.
2092 if(lp_dns_proxy() && ((question->name_type == 0x20) || question->name_type == 0)) {
2093 DEBUG(3,("wins_process_name_query: name query for name %s not found - doing dns lookup.\n",
2094 nmb_namestr(question) ));
2096 queue_dns_query(p, question);
2097 return;
2101 * Name not found - return error.
2104 send_wins_name_query_response(NAM_ERR, p, NULL);
2107 /****************************************************************************
2108 Send a WINS name release response.
2109 **************************************************************************/
2111 static void send_wins_name_release_response(int rcode, struct packet_struct *p)
2113 struct nmb_packet *nmb = &p->packet.nmb;
2114 char rdata[6];
2116 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
2118 reply_netbios_packet(p, /* Packet to reply to. */
2119 rcode, /* Result code. */
2120 NMB_REL, /* nmbd type code. */
2121 NMB_NAME_RELEASE_OPCODE, /* opcode. */
2122 0, /* ttl. */
2123 rdata, /* data to send. */
2124 6); /* data length. */
2127 /***********************************************************************
2128 Deal with a name release.
2129 ***********************************************************************/
2131 void wins_process_name_release_request(struct subnet_record *subrec,
2132 struct packet_struct *p)
2134 struct nmb_packet *nmb = &p->packet.nmb;
2135 struct nmb_name *question = &nmb->question.question_name;
2136 bool bcast = nmb->header.nm_flags.bcast;
2137 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
2138 struct name_record *namerec = NULL;
2139 struct in_addr from_ip;
2140 bool releasing_group_name = (nb_flags & NB_GROUP) ? True : False;;
2142 putip((char *)&from_ip,&nmb->additional->rdata[2]);
2144 if(bcast) {
2146 * We should only get unicast name registration packets here.
2147 * Anyone trying to register broadcast should not be going to a WINS
2148 * server. Log an error here.
2151 DEBUG(0,("wins_process_name_release_request: broadcast name registration request \
2152 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
2153 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
2154 return;
2157 DEBUG(3,("wins_process_name_release_request: %s name release for name %s \
2158 IP %s\n", releasing_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
2161 * Deal with policy regarding 0x1d names.
2164 if(!releasing_group_name && (question->name_type == 0x1d)) {
2165 DEBUG(3,("wins_process_name_release_request: Ignoring request \
2166 to release name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
2167 send_wins_name_release_response(0, p);
2168 return;
2172 * See if the name already exists.
2175 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2177 if( (namerec == NULL) || ((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) ) {
2178 send_wins_name_release_response(NAM_ERR, p);
2179 return;
2183 * Check that the sending machine has permission to release this name.
2184 * If it's a group name not ending in 0x1c then just say yes and let
2185 * the group time out.
2188 if(releasing_group_name && (question->name_type != 0x1c)) {
2189 send_wins_name_release_response(0, p);
2190 return;
2194 * Check that the releasing node is on the list of IP addresses
2195 * for this name. Disallow the release if not.
2198 if(!find_ip_in_name_record(namerec, from_ip)) {
2199 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2200 release name %s as IP %s is not one of the known IP's for this name.\n",
2201 nmb_namestr(question), inet_ntoa(from_ip) ));
2202 send_wins_name_release_response(NAM_ERR, p);
2203 return;
2207 * Check if the record is active. IF it's already released
2208 * or tombstoned, refuse the release.
2211 if (!WINS_STATE_ACTIVE(namerec)) {
2212 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2213 release name %s as this record is not active anymore.\n", nmb_namestr(question) ));
2214 send_wins_name_release_response(NAM_ERR, p);
2215 return;
2219 * Check if the record is a 0x1c group
2220 * and has more then one ip
2221 * remove only this address.
2224 if(releasing_group_name && (question->name_type == 0x1c) && (namerec->data.num_ips > 1)) {
2225 remove_ip_from_name_record(namerec, from_ip);
2226 DEBUG(3,("wins_process_name_release_request: Remove IP %s from NAME: %s\n",
2227 inet_ntoa(from_ip),nmb_namestr(question)));
2228 wins_hook("delete", namerec, 0);
2229 send_wins_name_release_response(0, p);
2230 return;
2234 * Send a release response.
2235 * Flag the name as released and update the ttl
2238 namerec->data.wins_flags |= WINS_RELEASED;
2239 update_name_ttl(namerec, EXTINCTION_INTERVAL);
2241 wins_hook("delete", namerec, 0);
2242 send_wins_name_release_response(0, p);
2245 /*******************************************************************
2246 WINS time dependent processing.
2247 ******************************************************************/
2249 static int wins_processing_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2251 time_t t = *(time_t *)state;
2252 bool store_record = False;
2253 struct name_record *namerec = NULL;
2254 struct in_addr our_fake_ip;
2256 our_fake_ip = interpret_addr2("0.0.0.0");
2257 if (kbuf.dsize != sizeof(unstring) + 1) {
2258 return 0;
2261 namerec = wins_record_to_name_record(kbuf, dbuf);
2262 if (!namerec) {
2263 return 0;
2266 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
2267 if( namerec->data.source == SELF_NAME ) {
2268 DEBUG( 3, ( "wins_processing_traverse_fn: Subnet %s not expiring SELF name %s\n",
2269 wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) );
2270 namerec->data.death_time += 300;
2271 store_record = True;
2272 goto done;
2273 } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) {
2274 DEBUG(3,("wins_processing_traverse_fn: deleting timed out DNS name %s\n",
2275 nmb_namestr(&namerec->name)));
2276 remove_name_from_wins_namelist(namerec );
2277 goto done;
2280 /* handle records, samba is the wins owner */
2281 if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
2282 switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2283 case WINS_ACTIVE:
2284 namerec->data.wins_flags&=~WINS_STATE_MASK;
2285 namerec->data.wins_flags|=WINS_RELEASED;
2286 namerec->data.death_time = t + EXTINCTION_INTERVAL;
2287 DEBUG(3,("wins_processing_traverse_fn: expiring %s\n",
2288 nmb_namestr(&namerec->name)));
2289 store_record = True;
2290 goto done;
2291 case WINS_RELEASED:
2292 namerec->data.wins_flags&=~WINS_STATE_MASK;
2293 namerec->data.wins_flags|=WINS_TOMBSTONED;
2294 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2295 get_global_id_and_update(&namerec->data.id, True);
2296 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2297 nmb_namestr(&namerec->name)));
2298 store_record = True;
2299 goto done;
2300 case WINS_TOMBSTONED:
2301 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2302 nmb_namestr(&namerec->name)));
2303 remove_name_from_wins_namelist(namerec );
2304 goto done;
2306 } else {
2307 switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2308 case WINS_ACTIVE:
2309 /* that's not as MS says it should be */
2310 namerec->data.wins_flags&=~WINS_STATE_MASK;
2311 namerec->data.wins_flags|=WINS_TOMBSTONED;
2312 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2313 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2314 nmb_namestr(&namerec->name)));
2315 store_record = True;
2316 goto done;
2317 case WINS_TOMBSTONED:
2318 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2319 nmb_namestr(&namerec->name)));
2320 remove_name_from_wins_namelist(namerec );
2321 goto done;
2322 case WINS_RELEASED:
2323 DEBUG(0,("wins_processing_traverse_fn: %s is in released state and\
2324 we are not the wins owner !\n", nmb_namestr(&namerec->name)));
2325 goto done;
2330 done:
2332 if (store_record) {
2333 wins_store_changed_namerec(namerec);
2336 SAFE_FREE(namerec->data.ip);
2337 SAFE_FREE(namerec);
2339 return 0;
2342 /*******************************************************************
2343 Time dependent wins processing.
2344 ******************************************************************/
2346 void initiate_wins_processing(time_t t)
2348 static time_t lasttime = 0;
2350 if (!lasttime) {
2351 lasttime = t;
2353 if (t - lasttime < 20) {
2354 return;
2357 if(!lp_we_are_a_wins_server()) {
2358 lasttime = t;
2359 return;
2362 tdb_traverse(wins_tdb, wins_processing_traverse_fn, &t);
2364 wins_delete_all_tmp_in_memory_records();
2366 wins_write_database(t, True);
2368 lasttime = t;
2371 /*******************************************************************
2372 Write out one record.
2373 ******************************************************************/
2375 void wins_write_name_record(struct name_record *namerec, XFILE *fp)
2377 int i;
2378 struct tm *tm;
2380 DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) ));
2382 if( namerec->data.death_time != PERMANENT_TTL ) {
2383 char *ts, *nl;
2385 tm = localtime(&namerec->data.death_time);
2386 if (!tm) {
2387 return;
2389 ts = asctime(tm);
2390 if (!ts) {
2391 return;
2393 nl = strrchr( ts, '\n' );
2394 if( NULL != nl ) {
2395 *nl = '\0';
2397 DEBUGADD(4,("TTL = %s ", ts ));
2398 } else {
2399 DEBUGADD(4,("TTL = PERMANENT "));
2402 for (i = 0; i < namerec->data.num_ips; i++) {
2403 DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) ));
2405 DEBUGADD(4,("%2x\n", namerec->data.nb_flags ));
2407 if( namerec->data.source == REGISTER_NAME ) {
2408 unstring name;
2409 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
2410 x_fprintf(fp, "\"%s#%02x\" %d ", name,namerec->name.name_type, /* Ignore scope. */
2411 (int)namerec->data.death_time);
2413 for (i = 0; i < namerec->data.num_ips; i++)
2414 x_fprintf( fp, "%s ", inet_ntoa( namerec->data.ip[i] ) );
2415 x_fprintf( fp, "%2xR\n", namerec->data.nb_flags );
2419 /*******************************************************************
2420 Write out the current WINS database.
2421 ******************************************************************/
2423 static int wins_writedb_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2425 struct name_record *namerec = NULL;
2426 XFILE *fp = (XFILE *)state;
2428 if (kbuf.dsize != sizeof(unstring) + 1) {
2429 return 0;
2432 namerec = wins_record_to_name_record(kbuf, dbuf);
2433 if (!namerec) {
2434 return 0;
2437 wins_write_name_record(namerec, fp);
2439 SAFE_FREE(namerec->data.ip);
2440 SAFE_FREE(namerec);
2441 return 0;
2445 void wins_write_database(time_t t, bool background)
2447 static time_t last_write_time = 0;
2448 char *fname = NULL;
2449 char *fnamenew = NULL;
2451 XFILE *fp;
2453 if (background) {
2454 if (!last_write_time) {
2455 last_write_time = t;
2457 if (t - last_write_time < 120) {
2458 return;
2463 if(!lp_we_are_a_wins_server()) {
2464 return;
2467 /* We will do the writing in a child process to ensure that the parent doesn't block while this is done */
2468 if (background) {
2469 CatchChild();
2470 if (sys_fork()) {
2471 return;
2473 if (tdb_reopen(wins_tdb)) {
2474 DEBUG(0,("wins_write_database: tdb_reopen failed. Error was %s\n",
2475 strerror(errno)));
2476 _exit(0);
2477 return;
2481 if (!(fname = state_path(WINS_LIST))) {
2482 goto err_exit;
2484 /* This is safe as the 0 length means "don't expand". */
2485 all_string_sub(fname,"//", "/", 0);
2487 if (asprintf(&fnamenew, "%s.%u", fname, (unsigned int)sys_getpid()) < 0) {
2488 goto err_exit;
2491 if((fp = x_fopen(fnamenew,O_WRONLY|O_CREAT,0644)) == NULL) {
2492 DEBUG(0,("wins_write_database: Can't open %s. Error was %s\n", fnamenew, strerror(errno)));
2493 goto err_exit;
2496 DEBUG(4,("wins_write_database: Dump of WINS name list.\n"));
2498 x_fprintf(fp,"VERSION %d %u\n", WINS_VERSION, 0);
2500 tdb_traverse(wins_tdb, wins_writedb_traverse_fn, fp);
2502 x_fclose(fp);
2503 chmod(fnamenew,0644);
2504 unlink(fname);
2505 rename(fnamenew,fname);
2507 err_exit:
2509 SAFE_FREE(fnamenew);
2510 TALLOC_FREE(fname);
2512 if (background) {
2513 _exit(0);
2517 #if 0
2518 Until winsrepl is done.
2519 /****************************************************************************
2520 Process a internal Samba message receiving a wins record.
2521 ***************************************************************************/
2523 void nmbd_wins_new_entry(struct messaging_context *msg,
2524 void *private_data,
2525 uint32_t msg_type,
2526 struct server_id server_id,
2527 DATA_BLOB *data)
2529 WINS_RECORD *record;
2530 struct name_record *namerec = NULL;
2531 struct name_record *new_namerec = NULL;
2532 struct nmb_name question;
2533 bool overwrite=False;
2534 struct in_addr our_fake_ip;
2535 int i;
2537 our_fake_ip = interpret_addr2("0.0.0.0");
2538 if (buf==NULL) {
2539 return;
2542 /* Record should use UNIX codepage. Ensure this is so in the wrepld code. JRA. */
2543 record=(WINS_RECORD *)buf;
2545 make_nmb_name(&question, record->name, record->type);
2547 namerec = find_name_on_subnet(wins_server_subnet, &question, FIND_ANY_NAME);
2549 /* record doesn't exist, add it */
2550 if (namerec == NULL) {
2551 DEBUG(3,("nmbd_wins_new_entry: adding new replicated record: %s<%02x> for wins server: %s\n",
2552 record->name, record->type, inet_ntoa(record->wins_ip)));
2554 new_namerec=add_name_to_subnet( wins_server_subnet,
2555 record->name,
2556 record->type,
2557 record->nb_flags,
2558 EXTINCTION_INTERVAL,
2559 REGISTER_NAME,
2560 record->num_ips,
2561 record->ip);
2563 if (new_namerec!=NULL) {
2564 update_wins_owner(new_namerec, record->wins_ip);
2565 update_wins_flag(new_namerec, record->wins_flags);
2566 new_namerec->data.id=record->id;
2568 wins_server_subnet->namelist_changed = True;
2572 /* check if we have a conflict */
2573 if (namerec != NULL) {
2574 /* both records are UNIQUE */
2575 if (namerec->data.wins_flags&WINS_UNIQUE && record->wins_flags&WINS_UNIQUE) {
2577 /* the database record is a replica */
2578 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
2579 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED) {
2580 if (ip_equal_v4(namerec->data.wins_ip, record->wins_ip))
2581 overwrite=True;
2582 } else
2583 overwrite=True;
2584 } else {
2585 /* we are the wins owner of the database record */
2586 /* the 2 records have the same IP address */
2587 if (ip_equal_v4(namerec->data.ip[0], record->ip[0])) {
2588 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED)
2589 get_global_id_and_update(&namerec->data.id, True);
2590 else
2591 overwrite=True;
2593 } else {
2594 /* the 2 records have different IP address */
2595 if (namerec->data.wins_flags&WINS_ACTIVE) {
2596 if (record->wins_flags&WINS_TOMBSTONED)
2597 get_global_id_and_update(&namerec->data.id, True);
2598 if (record->wins_flags&WINS_ACTIVE)
2599 /* send conflict challenge to the replica node */
2601 } else
2602 overwrite=True;
2608 /* the replica is a standard group */
2609 if (record->wins_flags&WINS_NGROUP || record->wins_flags&WINS_SGROUP) {
2610 /* if the database record is unique and active force a name release */
2611 if (namerec->data.wins_flags&WINS_UNIQUE)
2612 /* send a release name to the unique node */
2614 overwrite=True;
2618 /* the replica is a special group */
2619 if (record->wins_flags&WINS_SGROUP && namerec->data.wins_flags&WINS_SGROUP) {
2620 if (namerec->data.wins_flags&WINS_ACTIVE) {
2621 for (i=0; i<record->num_ips; i++)
2622 if(!find_ip_in_name_record(namerec, record->ip[i]))
2623 add_ip_to_name_record(namerec, record->ip[i]);
2624 } else {
2625 overwrite=True;
2629 /* the replica is a multihomed host */
2631 /* I'm giving up on multi homed. Too much complex to understand */
2633 if (record->wins_flags&WINS_MHOMED) {
2634 if (! (namerec->data.wins_flags&WINS_ACTIVE)) {
2635 if ( !(namerec->data.wins_flags&WINS_RELEASED) && !(namerec->data.wins_flags&WINS_NGROUP))
2636 overwrite=True;
2638 else {
2639 if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
2640 overwrite=True;
2642 if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip))
2643 if (namerec->data.wins_flags&WINS_UNIQUE)
2644 get_global_id_and_update(&namerec->data.id, True);
2648 if (record->wins_flags&WINS_ACTIVE && namerec->data.wins_flags&WINS_ACTIVE)
2649 if (namerec->data.wins_flags&WINS_UNIQUE ||
2650 namerec->data.wins_flags&WINS_MHOMED)
2651 if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
2652 overwrite=True;
2656 if (overwrite == False)
2657 DEBUG(3, ("nmbd_wins_new_entry: conflict in adding record: %s<%02x> from wins server: %s\n",
2658 record->name, record->type, inet_ntoa(record->wins_ip)));
2659 else {
2660 DEBUG(3, ("nmbd_wins_new_entry: replacing record: %s<%02x> from wins server: %s\n",
2661 record->name, record->type, inet_ntoa(record->wins_ip)));
2663 /* remove the old record and add a new one */
2664 remove_name_from_namelist( wins_server_subnet, namerec );
2665 new_namerec=add_name_to_subnet( wins_server_subnet, record->name, record->type, record->nb_flags,
2666 EXTINCTION_INTERVAL, REGISTER_NAME, record->num_ips, record->ip);
2667 if (new_namerec!=NULL) {
2668 update_wins_owner(new_namerec, record->wins_ip);
2669 update_wins_flag(new_namerec, record->wins_flags);
2670 new_namerec->data.id=record->id;
2672 wins_server_subnet->namelist_changed = True;
2675 wins_server_subnet->namelist_changed = True;
2680 #endif