[GLUE] Rsync SAMBA_3_0 SVN r25598 in order to create the v3-0-test branch.
[Samba.git] / source / nmbd / nmbd_winsserver.c
blob9b9f7401675deca30de63ed155b6ab7f281dc820
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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 Converted to store WINS data in a tdb. Dec 2005. JRA.
24 #include "includes.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 Convert a wins.tdb record to a struct name_record. Add in our global_scope().
57 *****************************************************************************/
59 static struct name_record *wins_record_to_name_record(TDB_DATA key, TDB_DATA data)
61 struct name_record *namerec = NULL;
62 uint16 nb_flags;
63 unsigned char nr_src;
64 uint32 death_time, refresh_time;
65 uint32 id_low, id_high;
66 uint32 saddr;
67 uint32 wins_flags;
68 uint32 num_ips;
69 size_t len;
70 int i;
72 if (data.dptr == NULL || data.dsize == 0) {
73 return NULL;
76 /* Min size is "wbddddddd" + 1 ip address (4). */
77 if (data.dsize < 2 + 1 + (7*4) + 4) {
78 return NULL;
81 len = tdb_unpack(data.dptr, data.dsize,
82 "wbddddddd",
83 &nb_flags,
84 &nr_src,
85 &death_time,
86 &refresh_time,
87 &id_low,
88 &id_high,
89 &saddr,
90 &wins_flags,
91 &num_ips );
93 namerec = SMB_MALLOC_P(struct name_record);
94 if (!namerec) {
95 return NULL;
97 ZERO_STRUCTP(namerec);
99 namerec->data.ip = SMB_MALLOC_ARRAY(struct in_addr, num_ips);
100 if (!namerec->data.ip) {
101 SAFE_FREE(namerec);
102 return NULL;
105 namerec->subnet = wins_server_subnet;
106 push_ascii_nstring(namerec->name.name, key.dptr);
107 namerec->name.name_type = key.dptr[sizeof(unstring)];
108 /* Add the scope. */
109 push_ascii(namerec->name.scope, global_scope(), 64, STR_TERMINATE);
111 /* We're using a byte-by-byte compare, so we must be sure that
112 * unused space doesn't have garbage in it.
115 for( i = strlen( namerec->name.name ); i < sizeof( namerec->name.name ); i++ ) {
116 namerec->name.name[i] = '\0';
118 for( i = strlen( namerec->name.scope ); i < sizeof( namerec->name.scope ); i++ ) {
119 namerec->name.scope[i] = '\0';
122 namerec->data.nb_flags = nb_flags;
123 namerec->data.source = (enum name_source)nr_src;
124 namerec->data.death_time = (time_t)death_time;
125 namerec->data.refresh_time = (time_t)refresh_time;
126 namerec->data.id = id_low;
127 #if defined(HAVE_LONGLONG)
128 namerec->data.id |= ((SMB_BIG_UINT)id_high << 32);
129 #endif
130 namerec->data.wins_ip.s_addr = saddr;
131 namerec->data.wins_flags = wins_flags,
132 namerec->data.num_ips = num_ips;
134 for (i = 0; i < num_ips; i++) {
135 namerec->data.ip[i].s_addr = IVAL(data.dptr, len + (i*4));
138 return namerec;
141 /****************************************************************************
142 Convert a struct name_record to a wins.tdb record. Ignore the scope.
143 *****************************************************************************/
145 static TDB_DATA name_record_to_wins_record(const struct name_record *namerec)
147 TDB_DATA data;
148 size_t len = 0;
149 int i;
150 uint32 id_low = (namerec->data.id & 0xFFFFFFFF);
151 #if defined(HAVE_LONGLONG)
152 uint32 id_high = (namerec->data.id >> 32) & 0xFFFFFFFF;
153 #else
154 uint32 id_high = 0;
155 #endif
157 ZERO_STRUCT(data);
159 len = (2 + 1 + (7*4)); /* "wbddddddd" */
160 len += (namerec->data.num_ips * 4);
162 data.dptr = (char *)SMB_MALLOC(len);
163 if (!data.dptr) {
164 return data;
166 data.dsize = len;
168 len = tdb_pack(data.dptr, data.dsize, "wbddddddd",
169 namerec->data.nb_flags,
170 (unsigned char)namerec->data.source,
171 (uint32)namerec->data.death_time,
172 (uint32)namerec->data.refresh_time,
173 id_low,
174 id_high,
175 (uint32)namerec->data.wins_ip.s_addr,
176 (uint32)namerec->data.wins_flags,
177 (uint32)namerec->data.num_ips );
179 for (i = 0; i < namerec->data.num_ips; i++) {
180 SIVAL(data.dptr, len + (i*4), namerec->data.ip[i].s_addr);
183 return data;
186 /****************************************************************************
187 Create key. Key is UNIX codepage namestring (usually utf8 64 byte len) with 1 byte type.
188 *****************************************************************************/
190 static TDB_DATA name_to_key(const struct nmb_name *nmbname)
192 static char keydata[sizeof(unstring) + 1];
193 TDB_DATA key;
195 memset(keydata, '\0', sizeof(keydata));
197 pull_ascii_nstring(keydata, sizeof(unstring), nmbname->name);
198 strupper_m(keydata);
199 keydata[sizeof(unstring)] = nmbname->name_type;
200 key.dptr = keydata;
201 key.dsize = sizeof(keydata);
203 return key;
206 /****************************************************************************
207 Lookup a given name in the wins.tdb and create a temporary malloc'ed data struct
208 on the linked list. We will free this later in XXXX().
209 *****************************************************************************/
211 struct name_record *find_name_on_wins_subnet(const struct nmb_name *nmbname, BOOL self_only)
213 TDB_DATA data, key;
214 struct name_record *nr = NULL;
215 struct name_record *namerec = NULL;
217 if (!wins_tdb) {
218 return NULL;
221 key = name_to_key(nmbname);
222 data = tdb_fetch(wins_tdb, key);
224 if (data.dsize == 0) {
225 return NULL;
228 namerec = wins_record_to_name_record(key, data);
230 /* done with the this */
232 SAFE_FREE( data.dptr );
234 if (!namerec) {
235 return NULL;
238 /* Self names only - these include permanent names. */
239 if( self_only && (namerec->data.source != SELF_NAME) && (namerec->data.source != PERMANENT_NAME) ) {
240 DEBUG( 9, ( "find_name_on_wins_subnet: self name %s NOT FOUND\n", nmb_namestr(nmbname) ) );
241 SAFE_FREE(namerec->data.ip);
242 SAFE_FREE(namerec);
243 return NULL;
246 /* Search for this name record on the list. Replace it if found. */
248 for( nr = wins_server_subnet->namelist; nr; nr = nr->next) {
249 if (memcmp(nmbname->name, nr->name.name, 16) == 0) {
250 /* Delete it. */
251 DLIST_REMOVE(wins_server_subnet->namelist, nr);
252 SAFE_FREE(nr->data.ip);
253 SAFE_FREE(nr);
254 break;
258 DLIST_ADD(wins_server_subnet->namelist, namerec);
259 return namerec;
262 /****************************************************************************
263 Overwrite or add a given name in the wins.tdb.
264 *****************************************************************************/
266 static BOOL store_or_replace_wins_namerec(const struct name_record *namerec, int tdb_flag)
268 TDB_DATA key, data;
269 int ret;
271 if (!wins_tdb) {
272 return False;
275 key = name_to_key(&namerec->name);
276 data = name_record_to_wins_record(namerec);
278 if (data.dptr == NULL) {
279 return False;
282 ret = tdb_store(wins_tdb, key, data, tdb_flag);
284 SAFE_FREE(data.dptr);
285 return (ret == 0) ? True : False;
288 /****************************************************************************
289 Overwrite a given name in the wins.tdb.
290 *****************************************************************************/
292 BOOL wins_store_changed_namerec(const struct name_record *namerec)
294 return store_or_replace_wins_namerec(namerec, TDB_REPLACE);
297 /****************************************************************************
298 Primary interface into creating and overwriting records in the wins.tdb.
299 *****************************************************************************/
301 BOOL add_name_to_wins_subnet(const struct name_record *namerec)
303 return store_or_replace_wins_namerec(namerec, TDB_INSERT);
306 /****************************************************************************
307 Delete a given name in the tdb and remove the temporary malloc'ed data struct
308 on the linked list.
309 *****************************************************************************/
311 BOOL remove_name_from_wins_namelist(struct name_record *namerec)
313 TDB_DATA key;
314 int ret;
316 if (!wins_tdb) {
317 return False;
320 key = name_to_key(&namerec->name);
321 ret = tdb_delete(wins_tdb, key);
323 DLIST_REMOVE(wins_server_subnet->namelist, namerec);
325 /* namerec must be freed by the caller */
327 return (ret == 0) ? True : False;
330 /****************************************************************************
331 Dump out the complete namelist.
332 *****************************************************************************/
334 static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
336 struct name_record *namerec = NULL;
337 XFILE *fp = (XFILE *)state;
339 if (kbuf.dsize != sizeof(unstring) + 1) {
340 return 0;
343 namerec = wins_record_to_name_record(kbuf, dbuf);
344 if (!namerec) {
345 return 0;
348 dump_name_record(namerec, fp);
350 SAFE_FREE(namerec->data.ip);
351 SAFE_FREE(namerec);
352 return 0;
355 void dump_wins_subnet_namelist(XFILE *fp)
357 tdb_traverse(wins_tdb, traverse_fn, (void *)fp);
360 /****************************************************************************
361 Change the wins owner address in the record.
362 *****************************************************************************/
364 static void update_wins_owner(struct name_record *namerec, struct in_addr wins_ip)
366 namerec->data.wins_ip=wins_ip;
369 /****************************************************************************
370 Create the wins flags based on the nb flags and the input value.
371 *****************************************************************************/
373 static void update_wins_flag(struct name_record *namerec, int flags)
375 namerec->data.wins_flags=0x0;
377 /* if it's a group, it can be a normal or a special one */
378 if (namerec->data.nb_flags & NB_GROUP) {
379 if (namerec->name.name_type==0x1C) {
380 namerec->data.wins_flags|=WINS_SGROUP;
381 } else {
382 if (namerec->data.num_ips>1) {
383 namerec->data.wins_flags|=WINS_SGROUP;
384 } else {
385 namerec->data.wins_flags|=WINS_NGROUP;
388 } else {
389 /* can be unique or multi-homed */
390 if (namerec->data.num_ips>1) {
391 namerec->data.wins_flags|=WINS_MHOMED;
392 } else {
393 namerec->data.wins_flags|=WINS_UNIQUE;
397 /* the node type are the same bits */
398 namerec->data.wins_flags|=namerec->data.nb_flags&NB_NODETYPEMASK;
400 /* the static bit is elsewhere */
401 if (namerec->data.death_time == PERMANENT_TTL) {
402 namerec->data.wins_flags|=WINS_STATIC;
405 /* and add the given bits */
406 namerec->data.wins_flags|=flags;
408 DEBUG(8,("update_wins_flag: nbflags: 0x%x, ttl: 0x%d, flags: 0x%x, winsflags: 0x%x\n",
409 namerec->data.nb_flags, (int)namerec->data.death_time, flags, namerec->data.wins_flags));
412 /****************************************************************************
413 Return the general ID value and increase it if requested.
414 *****************************************************************************/
416 static void get_global_id_and_update(SMB_BIG_UINT *current_id, BOOL update)
419 * it's kept as a static here, to prevent people from messing
420 * with the value directly
423 static SMB_BIG_UINT general_id = 1;
425 DEBUG(5,("get_global_id_and_update: updating version ID: %d\n", (int)general_id));
427 *current_id = general_id;
429 if (update) {
430 general_id++;
434 /****************************************************************************
435 Possibly call the WINS hook external program when a WINS change is made.
436 Also stores the changed record back in the wins_tdb.
437 *****************************************************************************/
439 static void wins_hook(const char *operation, struct name_record *namerec, int ttl)
441 pstring command;
442 char *cmd = lp_wins_hook();
443 char *p, *namestr;
444 int i;
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 p = command;
467 p += slprintf(p, sizeof(command)-1, "%s %s %s %02x %d",
468 cmd,
469 operation,
470 namestr,
471 namerec->name.name_type,
472 ttl);
474 for (i=0;i<namerec->data.num_ips;i++) {
475 p += slprintf(p, sizeof(command) - (p-command) -1, " %s", inet_ntoa(namerec->data.ip[i]));
478 DEBUG(3,("calling wins hook for %s\n", nmb_namestr(&namerec->name)));
479 smbrun(command, NULL);
482 /****************************************************************************
483 Determine if this packet should be allocated to the WINS server.
484 *****************************************************************************/
486 BOOL packet_is_for_wins_server(struct packet_struct *packet)
488 struct nmb_packet *nmb = &packet->packet.nmb;
490 /* Only unicast packets go to a WINS server. */
491 if((wins_server_subnet == NULL) || (nmb->header.nm_flags.bcast == True)) {
492 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #1.\n"));
493 return False;
496 /* Check for node status requests. */
497 if (nmb->question.question_type != QUESTION_TYPE_NB_QUERY) {
498 return False;
501 switch(nmb->header.opcode) {
503 * A WINS server issues WACKS, not receives them.
505 case NMB_WACK_OPCODE:
506 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #2 (WACK).\n"));
507 return False;
509 * A WINS server only processes registration and
510 * release requests, not responses.
512 case NMB_NAME_REG_OPCODE:
513 case NMB_NAME_MULTIHOMED_REG_OPCODE:
514 case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
515 case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
516 if(nmb->header.response) {
517 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #3 (response = 1).\n"));
518 return False;
520 break;
522 case NMB_NAME_RELEASE_OPCODE:
523 if(nmb->header.response) {
524 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #4 (response = 1).\n"));
525 return False;
527 break;
530 * Only process unicast name queries with rd = 1.
532 case NMB_NAME_QUERY_OPCODE:
533 if(!nmb->header.response && !nmb->header.nm_flags.recursion_desired) {
534 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #5 (response = 1).\n"));
535 return False;
537 break;
540 return True;
543 /****************************************************************************
544 Utility function to decide what ttl to give a register/refresh request.
545 *****************************************************************************/
547 static int get_ttl_from_packet(struct nmb_packet *nmb)
549 int ttl = nmb->additional->ttl;
551 if (ttl < lp_min_wins_ttl()) {
552 ttl = lp_min_wins_ttl();
555 if (ttl > lp_max_wins_ttl()) {
556 ttl = lp_max_wins_ttl();
559 return ttl;
562 /****************************************************************************
563 Load or create the WINS database.
564 *****************************************************************************/
566 BOOL initialise_wins(void)
568 time_t time_now = time(NULL);
569 XFILE *fp;
570 pstring line;
572 if(!lp_we_are_a_wins_server()) {
573 return True;
576 /* Open the wins.tdb. */
577 wins_tdb = tdb_open_log(lock_path("wins.tdb"), 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST, O_CREAT|O_RDWR, 0600);
578 if (!wins_tdb) {
579 DEBUG(0,("initialise_wins: failed to open wins.tdb. Error was %s\n",
580 strerror(errno) ));
581 return False;
584 tdb_store_int32(wins_tdb, "WINSDB_VERSION", WINSDB_VERSION);
586 add_samba_names_to_subnet(wins_server_subnet);
588 if((fp = x_fopen(lock_path(WINS_LIST),O_RDONLY,0)) == NULL) {
589 DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
590 WINS_LIST, strerror(errno) ));
591 return True;
594 while (!x_feof(fp)) {
595 pstring name_str, ip_str, ttl_str, nb_flags_str;
596 unsigned int num_ips;
597 pstring name;
598 struct in_addr *ip_list;
599 int type = 0;
600 int nb_flags;
601 int ttl;
602 const char *ptr;
603 char *p;
604 BOOL got_token;
605 BOOL was_ip;
606 int i;
607 unsigned int hash;
608 int version;
610 /* Read a line from the wins.dat file. Strips whitespace
611 from the beginning and end of the line. */
612 if (!fgets_slash(line,sizeof(pstring),fp))
613 continue;
615 if (*line == '#')
616 continue;
618 if (strncmp(line,"VERSION ", 8) == 0) {
619 if (sscanf(line,"VERSION %d %u", &version, &hash) != 2 ||
620 version != WINS_VERSION) {
621 DEBUG(0,("Discarding invalid wins.dat file [%s]\n",line));
622 x_fclose(fp);
623 return True;
625 continue;
628 ptr = line;
631 * Now we handle multiple IP addresses per name we need
632 * to iterate over the line twice. The first time to
633 * determine how many IP addresses there are, the second
634 * time to actually parse them into the ip_list array.
637 if (!next_token(&ptr,name_str,NULL,sizeof(name_str))) {
638 DEBUG(0,("initialise_wins: Failed to parse name when parsing line %s\n", line ));
639 continue;
642 if (!next_token(&ptr,ttl_str,NULL,sizeof(ttl_str))) {
643 DEBUG(0,("initialise_wins: Failed to parse time to live when parsing line %s\n", line ));
644 continue;
648 * Determine the number of IP addresses per line.
650 num_ips = 0;
651 do {
652 got_token = next_token(&ptr,ip_str,NULL,sizeof(ip_str));
653 was_ip = False;
655 if(got_token && strchr(ip_str, '.')) {
656 num_ips++;
657 was_ip = True;
659 } while( got_token && was_ip);
661 if(num_ips == 0) {
662 DEBUG(0,("initialise_wins: Missing IP address when parsing line %s\n", line ));
663 continue;
666 if(!got_token) {
667 DEBUG(0,("initialise_wins: Missing nb_flags when parsing line %s\n", line ));
668 continue;
671 /* Allocate the space for the ip_list. */
672 if((ip_list = SMB_MALLOC_ARRAY( struct in_addr, num_ips)) == NULL) {
673 DEBUG(0,("initialise_wins: Malloc fail !\n"));
674 x_fclose(fp);
675 return False;
678 /* Reset and re-parse the line. */
679 ptr = line;
680 next_token(&ptr,name_str,NULL,sizeof(name_str));
681 next_token(&ptr,ttl_str,NULL,sizeof(ttl_str));
682 for(i = 0; i < num_ips; i++) {
683 next_token(&ptr, ip_str, NULL, sizeof(ip_str));
684 ip_list[i] = *interpret_addr2(ip_str);
686 next_token(&ptr,nb_flags_str,NULL, sizeof(nb_flags_str));
689 * Deal with SELF or REGISTER name encoding. Default is REGISTER
690 * for compatibility with old nmbds.
693 if(nb_flags_str[strlen(nb_flags_str)-1] == 'S') {
694 DEBUG(5,("initialise_wins: Ignoring SELF name %s\n", line));
695 SAFE_FREE(ip_list);
696 continue;
699 if(nb_flags_str[strlen(nb_flags_str)-1] == 'R') {
700 nb_flags_str[strlen(nb_flags_str)-1] = '\0';
703 /* Netbios name. # divides the name from the type (hex): netbios#xx */
704 pstrcpy(name,name_str);
706 if((p = strchr(name,'#')) != NULL) {
707 *p = 0;
708 sscanf(p+1,"%x",&type);
711 /* Decode the netbios flags (hex) and the time-to-live (in seconds). */
712 sscanf(nb_flags_str,"%x",&nb_flags);
713 sscanf(ttl_str,"%d",&ttl);
715 /* add all entries that have 60 seconds or more to live */
716 if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) {
717 if(ttl != PERMANENT_TTL) {
718 ttl -= time_now;
721 DEBUG( 4, ("initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
722 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
724 (void)add_name_to_subnet( wins_server_subnet, name, type, nb_flags,
725 ttl, REGISTER_NAME, num_ips, ip_list );
726 } else {
727 DEBUG(4, ("initialise_wins: not adding name (ttl problem) "
728 "%s#%02x ttl = %d first IP %s flags = %2x\n",
729 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
732 SAFE_FREE(ip_list);
735 x_fclose(fp);
736 return True;
739 /****************************************************************************
740 Send a WINS WACK (Wait ACKnowledgement) response.
741 **************************************************************************/
743 static void send_wins_wack_response(int ttl, struct packet_struct *p)
745 struct nmb_packet *nmb = &p->packet.nmb;
746 unsigned char rdata[2];
748 rdata[0] = rdata[1] = 0;
750 /* Taken from nmblib.c - we need to send back almost
751 identical bytes from the requesting packet header. */
753 rdata[0] = (nmb->header.opcode & 0xF) << 3;
754 if (nmb->header.nm_flags.authoritative && nmb->header.response) {
755 rdata[0] |= 0x4;
757 if (nmb->header.nm_flags.trunc) {
758 rdata[0] |= 0x2;
760 if (nmb->header.nm_flags.recursion_desired) {
761 rdata[0] |= 0x1;
763 if (nmb->header.nm_flags.recursion_available && nmb->header.response) {
764 rdata[1] |= 0x80;
766 if (nmb->header.nm_flags.bcast) {
767 rdata[1] |= 0x10;
770 reply_netbios_packet(p, /* Packet to reply to. */
771 0, /* Result code. */
772 NMB_WAIT_ACK, /* nmbd type code. */
773 NMB_WACK_OPCODE, /* opcode. */
774 ttl, /* ttl. */
775 (char *)rdata, /* data to send. */
776 2); /* data length. */
779 /****************************************************************************
780 Send a WINS name registration response.
781 **************************************************************************/
783 static void send_wins_name_registration_response(int rcode, int ttl, struct packet_struct *p)
785 struct nmb_packet *nmb = &p->packet.nmb;
786 char rdata[6];
788 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
790 reply_netbios_packet(p, /* Packet to reply to. */
791 rcode, /* Result code. */
792 WINS_REG, /* nmbd type code. */
793 NMB_NAME_REG_OPCODE, /* opcode. */
794 ttl, /* ttl. */
795 rdata, /* data to send. */
796 6); /* data length. */
799 /***********************************************************************
800 Deal with a name refresh request to a WINS server.
801 ************************************************************************/
803 void wins_process_name_refresh_request( struct subnet_record *subrec,
804 struct packet_struct *p )
806 struct nmb_packet *nmb = &p->packet.nmb;
807 struct nmb_name *question = &nmb->question.question_name;
808 BOOL bcast = nmb->header.nm_flags.bcast;
809 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
810 BOOL group = (nb_flags & NB_GROUP) ? True : False;
811 struct name_record *namerec = NULL;
812 int ttl = get_ttl_from_packet(nmb);
813 struct in_addr from_ip;
814 struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
816 putip( (char *)&from_ip, &nmb->additional->rdata[2] );
818 if(bcast) {
820 * We should only get unicast name refresh packets here.
821 * Anyone trying to refresh broadcast should not be going
822 * to a WINS server. Log an error here.
824 if( DEBUGLVL( 0 ) ) {
825 dbgtext( "wins_process_name_refresh_request: " );
826 dbgtext( "Broadcast name refresh request received " );
827 dbgtext( "for name %s ", nmb_namestr(question) );
828 dbgtext( "from IP %s ", inet_ntoa(from_ip) );
829 dbgtext( "on subnet %s. ", subrec->subnet_name );
830 dbgtext( "Error - Broadcasts should not be sent " );
831 dbgtext( "to a WINS server\n" );
833 return;
836 if( DEBUGLVL( 3 ) ) {
837 dbgtext( "wins_process_name_refresh_request: " );
838 dbgtext( "Name refresh for name %s IP %s\n",
839 nmb_namestr(question), inet_ntoa(from_ip) );
843 * See if the name already exists.
844 * If not, handle it as a name registration and return.
846 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
849 * If this is a refresh request and the name doesn't exist then
850 * treat it like a registration request. This allows us to recover
851 * from errors (tridge)
853 if(namerec == NULL) {
854 if( DEBUGLVL( 3 ) ) {
855 dbgtext( "wins_process_name_refresh_request: " );
856 dbgtext( "Name refresh for name %s ",
857 nmb_namestr( question ) );
858 dbgtext( "and the name does not exist. Treating " );
859 dbgtext( "as registration.\n" );
861 wins_process_name_registration_request(subrec,p);
862 return;
866 * if the name is present but not active, simply remove it
867 * and treat the refresh request as a registration & return.
869 if (namerec != NULL && !WINS_STATE_ACTIVE(namerec)) {
870 if( DEBUGLVL( 5 ) ) {
871 dbgtext( "wins_process_name_refresh_request: " );
872 dbgtext( "Name (%s) in WINS ", nmb_namestr(question) );
873 dbgtext( "was not active - removing it.\n" );
875 remove_name_from_namelist( subrec, namerec );
876 namerec = NULL;
877 wins_process_name_registration_request( subrec, p );
878 return;
882 * Check that the group bits for the refreshing name and the
883 * name in our database match. If not, refuse the refresh.
884 * [crh: Why RFS_ERR instead of ACT_ERR? Is this what MS does?]
886 if( (namerec != NULL) &&
887 ( (group && !NAME_GROUP(namerec))
888 || (!group && NAME_GROUP(namerec)) ) ) {
889 if( DEBUGLVL( 3 ) ) {
890 dbgtext( "wins_process_name_refresh_request: " );
891 dbgtext( "Name %s ", nmb_namestr(question) );
892 dbgtext( "group bit = %s does not match ",
893 group ? "True" : "False" );
894 dbgtext( "group bit in WINS for this name.\n" );
896 send_wins_name_registration_response(RFS_ERR, 0, p);
897 return;
901 * For a unique name check that the person refreshing the name is
902 * one of the registered IP addresses. If not - fail the refresh.
903 * Do the same for group names with a type of 0x1c.
904 * Just return success for unique 0x1d refreshes. For normal group
905 * names update the ttl and return success.
907 if( (!group || (group && (question->name_type == 0x1c)))
908 && find_ip_in_name_record(namerec, from_ip) ) {
910 * Update the ttl.
912 update_name_ttl(namerec, ttl);
915 * if the record is a replica:
916 * we take ownership and update the version ID.
918 if (!ip_equal(namerec->data.wins_ip, our_fake_ip)) {
919 update_wins_owner(namerec, our_fake_ip);
920 get_global_id_and_update(&namerec->data.id, True);
923 send_wins_name_registration_response(0, ttl, p);
924 wins_hook("refresh", namerec, ttl);
925 return;
926 } else if((group && (question->name_type == 0x1c))) {
928 * Added by crh for bug #1079.
929 * Fix from Bert Driehuis
931 if( DEBUGLVL( 3 ) ) {
932 dbgtext( "wins_process_name_refresh_request: " );
933 dbgtext( "Name refresh for name %s, ",
934 nmb_namestr(question) );
935 dbgtext( "but IP address %s ", inet_ntoa(from_ip) );
936 dbgtext( "is not yet associated with " );
937 dbgtext( "that name. Treating as registration.\n" );
939 wins_process_name_registration_request(subrec,p);
940 return;
941 } else if(group) {
943 * Normal groups are all registered with an IP address of
944 * 255.255.255.255 so we can't search for the IP address.
946 update_name_ttl(namerec, ttl);
947 wins_hook("refresh", namerec, ttl);
948 send_wins_name_registration_response(0, ttl, p);
949 return;
950 } else if(!group && (question->name_type == 0x1d)) {
952 * Special name type - just pretend the refresh succeeded.
954 send_wins_name_registration_response(0, ttl, p);
955 return;
956 } else {
958 * Fail the refresh.
960 if( DEBUGLVL( 3 ) ) {
961 dbgtext( "wins_process_name_refresh_request: " );
962 dbgtext( "Name refresh for name %s with IP %s ",
963 nmb_namestr(question), inet_ntoa(from_ip) );
964 dbgtext( "and is IP is not known to the name.\n" );
966 send_wins_name_registration_response(RFS_ERR, 0, p);
967 return;
971 /***********************************************************************
972 Deal with a name registration request query success to a client that
973 owned the name.
975 We have a locked pointer to the original packet stashed away in the
976 userdata pointer. The success here is actually a failure as it means
977 the client we queried wants to keep the name, so we must return
978 a registration failure to the original requestor.
979 ************************************************************************/
981 static void wins_register_query_success(struct subnet_record *subrec,
982 struct userdata_struct *userdata,
983 struct nmb_name *question_name,
984 struct in_addr ip,
985 struct res_rec *answers)
987 struct packet_struct *orig_reg_packet;
989 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
991 DEBUG(3,("wins_register_query_success: Original client at IP %s still wants the \
992 name %s. Rejecting registration request.\n", inet_ntoa(ip), nmb_namestr(question_name) ));
994 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
996 orig_reg_packet->locked = False;
997 free_packet(orig_reg_packet);
1000 /***********************************************************************
1001 Deal with a name registration request query failure to a client that
1002 owned the name.
1004 We have a locked pointer to the original packet stashed away in the
1005 userdata pointer. The failure here is actually a success as it means
1006 the client we queried didn't want to keep the name, so we can remove
1007 the old name record and then successfully add the new name.
1008 ************************************************************************/
1010 static void wins_register_query_fail(struct subnet_record *subrec,
1011 struct response_record *rrec,
1012 struct nmb_name *question_name,
1013 int rcode)
1015 struct userdata_struct *userdata = rrec->userdata;
1016 struct packet_struct *orig_reg_packet;
1017 struct name_record *namerec = NULL;
1019 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1022 * We want to just add the name, as we now know the original owner
1023 * didn't want it. But we can't just do that as an arbitary
1024 * amount of time may have taken place between the name query
1025 * request and this timeout/error response. So we check that
1026 * the name still exists and is in the same state - if so
1027 * we remove it and call wins_process_name_registration_request()
1028 * as we know it will do the right thing now.
1031 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1033 if ((namerec != NULL) && (namerec->data.source == REGISTER_NAME) &&
1034 ip_equal(rrec->packet->ip, *namerec->data.ip)) {
1035 remove_name_from_namelist( subrec, namerec);
1036 namerec = NULL;
1039 if(namerec == NULL) {
1040 wins_process_name_registration_request(subrec, orig_reg_packet);
1041 } else {
1042 DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between "
1043 "querying for name %s in order to replace it and this reply.\n",
1044 nmb_namestr(question_name) ));
1047 orig_reg_packet->locked = False;
1048 free_packet(orig_reg_packet);
1051 /***********************************************************************
1052 Deal with a name registration request to a WINS server.
1054 Use the following pseudocode :
1056 registering_group
1059 +--------name exists
1062 | +--- existing name is group
1063 | | |
1064 | | |
1065 | | +--- add name (return).
1068 | +--- exiting name is unique
1071 | +--- query existing owner (return).
1074 +--------name doesn't exist
1077 +--- add name (return).
1079 registering_unique
1082 +--------name exists
1085 | +--- existing name is group
1086 | | |
1087 | | |
1088 | | +--- fail add (return).
1089 | |
1091 | +--- exiting name is unique
1094 | +--- query existing owner (return).
1097 +--------name doesn't exist
1100 +--- add name (return).
1102 As can be seen from the above, the two cases may be collapsed onto each
1103 other with the exception of the case where the name already exists and
1104 is a group name. This case we handle with an if statement.
1106 ************************************************************************/
1108 void wins_process_name_registration_request(struct subnet_record *subrec,
1109 struct packet_struct *p)
1111 unstring name;
1112 struct nmb_packet *nmb = &p->packet.nmb;
1113 struct nmb_name *question = &nmb->question.question_name;
1114 BOOL bcast = nmb->header.nm_flags.bcast;
1115 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
1116 int ttl = get_ttl_from_packet(nmb);
1117 struct name_record *namerec = NULL;
1118 struct in_addr from_ip;
1119 BOOL registering_group_name = (nb_flags & NB_GROUP) ? True : False;
1120 struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
1122 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1124 if(bcast) {
1126 * We should only get unicast name registration packets here.
1127 * Anyone trying to register broadcast should not be going to a WINS
1128 * server. Log an error here.
1131 DEBUG(0,("wins_process_name_registration_request: broadcast name registration request \
1132 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1133 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1134 return;
1137 DEBUG(3,("wins_process_name_registration_request: %s name registration for name %s \
1138 IP %s\n", registering_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
1141 * See if the name already exists.
1144 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1147 * if the record exists but NOT in active state,
1148 * consider it dead.
1150 if ( (namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1151 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1152 not active - removing it.\n", nmb_namestr(question) ));
1153 remove_name_from_namelist( subrec, namerec );
1154 namerec = NULL;
1158 * Deal with the case where the name found was a dns entry.
1159 * Remove it as we now have a NetBIOS client registering the
1160 * name.
1163 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1164 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
1165 a dns lookup - removing it.\n", nmb_namestr(question) ));
1166 remove_name_from_namelist( subrec, namerec );
1167 namerec = NULL;
1171 * Reject if the name exists and is not a REGISTER_NAME.
1172 * (ie. Don't allow any static names to be overwritten.
1175 if((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) {
1176 DEBUG( 3, ( "wins_process_name_registration_request: Attempt \
1177 to register name %s. Name already exists in WINS with source type %d.\n",
1178 nmb_namestr(question), namerec->data.source ));
1179 send_wins_name_registration_response(RFS_ERR, 0, p);
1180 return;
1184 * Special policy decisions based on MS documentation.
1185 * 1). All group names (except names ending in 0x1c) are added as 255.255.255.255.
1186 * 2). All unique names ending in 0x1d are ignored, although a positive response is sent.
1190 * A group name is always added as the local broadcast address, except
1191 * for group names ending in 0x1c.
1192 * Group names with type 0x1c are registered with individual IP addresses.
1195 if(registering_group_name && (question->name_type != 0x1c)) {
1196 from_ip = *interpret_addr2("255.255.255.255");
1200 * Ignore all attempts to register a unique 0x1d name, although return success.
1203 if(!registering_group_name && (question->name_type == 0x1d)) {
1204 DEBUG(3,("wins_process_name_registration_request: Ignoring request \
1205 to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
1206 send_wins_name_registration_response(0, ttl, p);
1207 return;
1211 * Next two cases are the 'if statement' mentioned above.
1214 if((namerec != NULL) && NAME_GROUP(namerec)) {
1215 if(registering_group_name) {
1217 * If we are adding a group name, the name exists and is also a group entry just add this
1218 * IP address to it and update the ttl.
1221 DEBUG(3,("wins_process_name_registration_request: Adding IP %s to group name %s.\n",
1222 inet_ntoa(from_ip), nmb_namestr(question) ));
1225 * Check the ip address is not already in the group.
1228 if(!find_ip_in_name_record(namerec, from_ip)) {
1229 add_ip_to_name_record(namerec, from_ip);
1230 /* we need to update the record for replication */
1231 get_global_id_and_update(&namerec->data.id, True);
1234 * if the record is a replica, we must change
1235 * the wins owner to us to make the replication updates
1236 * it on the other wins servers.
1237 * And when the partner will receive this record,
1238 * it will update its own record.
1241 update_wins_owner(namerec, our_fake_ip);
1243 update_name_ttl(namerec, ttl);
1244 wins_hook("refresh", namerec, ttl);
1245 send_wins_name_registration_response(0, ttl, p);
1246 return;
1247 } else {
1250 * If we are adding a unique name, the name exists in the WINS db
1251 * and is a group name then reject the registration.
1253 * explanation: groups have a higher priority than unique names.
1256 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1257 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1258 send_wins_name_registration_response(RFS_ERR, 0, p);
1259 return;
1264 * From here on down we know that if the name exists in the WINS db it is
1265 * a unique name, not a group name.
1269 * If the name exists and is one of our names then check the
1270 * registering IP address. If it's not one of ours then automatically
1271 * reject without doing the query - we know we will reject it.
1274 if ( namerec != NULL ) {
1275 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
1276 if( is_myname(name) ) {
1277 if(!ismyip(from_ip)) {
1278 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
1279 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1280 send_wins_name_registration_response(RFS_ERR, 0, p);
1281 return;
1282 } else {
1284 * It's one of our names and one of our IP's - update the ttl.
1286 update_name_ttl(namerec, ttl);
1287 wins_hook("refresh", namerec, ttl);
1288 send_wins_name_registration_response(0, ttl, p);
1289 return;
1292 } else {
1293 name[0] = '\0';
1297 * If the name exists and it is a unique registration and the registering IP
1298 * is the same as the (single) already registered IP then just update the ttl.
1300 * But not if the record is an active replica. IF it's a replica, it means it can be
1301 * the same client which has moved and not yet expired. So we don't update
1302 * the ttl in this case and go beyond to do a WACK and query the old client
1305 if( !registering_group_name
1306 && (namerec != NULL)
1307 && (namerec->data.num_ips == 1)
1308 && ip_equal( namerec->data.ip[0], from_ip )
1309 && ip_equal(namerec->data.wins_ip, our_fake_ip) ) {
1310 update_name_ttl( namerec, ttl );
1311 wins_hook("refresh", namerec, ttl);
1312 send_wins_name_registration_response( 0, ttl, p );
1313 return;
1317 * Finally if the name exists do a query to the registering machine
1318 * to see if they still claim to have the name.
1321 if( namerec != NULL ) {
1322 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1323 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1326 * First send a WACK to the registering machine.
1329 send_wins_wack_response(60, p);
1332 * When the reply comes back we need the original packet.
1333 * Lock this so it won't be freed and then put it into
1334 * the userdata structure.
1337 p->locked = True;
1339 userdata = (struct userdata_struct *)ud;
1341 userdata->copy_fn = NULL;
1342 userdata->free_fn = NULL;
1343 userdata->userdata_len = sizeof(struct packet_struct *);
1344 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1347 * Use the new call to send a query directly to an IP address.
1348 * This sends the query directly to the IP address, and ensures
1349 * the recursion desired flag is not set (you were right Luke :-).
1350 * This function should *only* be called from the WINS server
1351 * code. JRA.
1354 pull_ascii_nstring(name, sizeof(name), question->name);
1355 query_name_from_wins_server( *namerec->data.ip,
1356 name,
1357 question->name_type,
1358 wins_register_query_success,
1359 wins_register_query_fail,
1360 userdata );
1361 return;
1365 * Name did not exist - add it.
1368 pull_ascii_nstring(name, sizeof(name), question->name);
1369 add_name_to_subnet( subrec, name, question->name_type,
1370 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1372 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1373 get_global_id_and_update(&namerec->data.id, True);
1374 update_wins_owner(namerec, our_fake_ip);
1375 update_wins_flag(namerec, WINS_ACTIVE);
1376 wins_hook("add", namerec, ttl);
1379 send_wins_name_registration_response(0, ttl, p);
1382 /***********************************************************************
1383 Deal with a mutihomed name query success to the machine that
1384 requested the multihomed name registration.
1386 We have a locked pointer to the original packet stashed away in the
1387 userdata pointer.
1388 ************************************************************************/
1390 static void wins_multihomed_register_query_success(struct subnet_record *subrec,
1391 struct userdata_struct *userdata,
1392 struct nmb_name *question_name,
1393 struct in_addr ip,
1394 struct res_rec *answers)
1396 struct packet_struct *orig_reg_packet;
1397 struct nmb_packet *nmb;
1398 struct name_record *namerec = NULL;
1399 struct in_addr from_ip;
1400 int ttl;
1401 struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
1403 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1405 nmb = &orig_reg_packet->packet.nmb;
1407 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1408 ttl = get_ttl_from_packet(nmb);
1411 * We want to just add the new IP, as we now know the requesting
1412 * machine claims to own it. But we can't just do that as an arbitary
1413 * amount of time may have taken place between the name query
1414 * request and this response. So we check that
1415 * the name still exists and is in the same state - if so
1416 * we just add the extra IP and update the ttl.
1419 namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
1421 if( (namerec == NULL) || (namerec->data.source != REGISTER_NAME) || !WINS_STATE_ACTIVE(namerec) ) {
1422 DEBUG(3,("wins_multihomed_register_query_success: name %s is not in the correct state to add \
1423 a subsequent IP address.\n", nmb_namestr(question_name) ));
1424 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1426 orig_reg_packet->locked = False;
1427 free_packet(orig_reg_packet);
1429 return;
1432 if(!find_ip_in_name_record(namerec, from_ip)) {
1433 add_ip_to_name_record(namerec, from_ip);
1436 get_global_id_and_update(&namerec->data.id, True);
1437 update_wins_owner(namerec, our_fake_ip);
1438 update_wins_flag(namerec, WINS_ACTIVE);
1439 update_name_ttl(namerec, ttl);
1440 wins_hook("add", namerec, ttl);
1441 send_wins_name_registration_response(0, ttl, orig_reg_packet);
1443 orig_reg_packet->locked = False;
1444 free_packet(orig_reg_packet);
1447 /***********************************************************************
1448 Deal with a name registration request query failure to a client that
1449 owned the name.
1451 We have a locked pointer to the original packet stashed away in the
1452 userdata pointer.
1453 ************************************************************************/
1455 static void wins_multihomed_register_query_fail(struct subnet_record *subrec,
1456 struct response_record *rrec,
1457 struct nmb_name *question_name,
1458 int rcode)
1460 struct userdata_struct *userdata = rrec->userdata;
1461 struct packet_struct *orig_reg_packet;
1463 memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
1465 DEBUG(3,("wins_multihomed_register_query_fail: Registering machine at IP %s failed to answer \
1466 query successfully for name %s.\n", inet_ntoa(orig_reg_packet->ip), nmb_namestr(question_name) ));
1467 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
1469 orig_reg_packet->locked = False;
1470 free_packet(orig_reg_packet);
1471 return;
1474 /***********************************************************************
1475 Deal with a multihomed name registration request to a WINS server.
1476 These cannot be group name registrations.
1477 ***********************************************************************/
1479 void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
1480 struct packet_struct *p)
1482 struct nmb_packet *nmb = &p->packet.nmb;
1483 struct nmb_name *question = &nmb->question.question_name;
1484 BOOL bcast = nmb->header.nm_flags.bcast;
1485 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
1486 int ttl = get_ttl_from_packet(nmb);
1487 struct name_record *namerec = NULL;
1488 struct in_addr from_ip;
1489 BOOL group = (nb_flags & NB_GROUP) ? True : False;
1490 struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
1491 unstring qname;
1493 putip((char *)&from_ip,&nmb->additional->rdata[2]);
1495 if(bcast) {
1497 * We should only get unicast name registration packets here.
1498 * Anyone trying to register broadcast should not be going to a WINS
1499 * server. Log an error here.
1502 DEBUG(0,("wins_process_multihomed_name_registration_request: broadcast name registration request \
1503 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
1504 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1505 return;
1509 * Only unique names should be registered multihomed.
1512 if(group) {
1513 DEBUG(0,("wins_process_multihomed_name_registration_request: group name registration request \
1514 received for name %s from IP %s on subnet %s. Errror - group names should not be multihomed.\n",
1515 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1516 return;
1519 DEBUG(3,("wins_process_multihomed_name_registration_request: name registration for name %s \
1520 IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ));
1523 * Deal with policy regarding 0x1d names.
1526 if(question->name_type == 0x1d) {
1527 DEBUG(3,("wins_process_multihomed_name_registration_request: Ignoring request \
1528 to register name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
1529 send_wins_name_registration_response(0, ttl, p);
1530 return;
1534 * See if the name already exists.
1537 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1540 * if the record exists but NOT in active state,
1541 * consider it dead.
1544 if ((namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
1545 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was not active - removing it.\n", nmb_namestr(question)));
1546 remove_name_from_namelist(subrec, namerec);
1547 namerec = NULL;
1551 * Deal with the case where the name found was a dns entry.
1552 * Remove it as we now have a NetBIOS client registering the
1553 * name.
1556 if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
1557 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was a dns lookup \
1558 - removing it.\n", nmb_namestr(question) ));
1559 remove_name_from_namelist( subrec, namerec);
1560 namerec = NULL;
1564 * Reject if the name exists and is not a REGISTER_NAME.
1565 * (ie. Don't allow any static names to be overwritten.
1568 if( (namerec != NULL) && (namerec->data.source != REGISTER_NAME) ) {
1569 DEBUG( 3, ( "wins_process_multihomed_name_registration_request: Attempt \
1570 to register name %s. Name already exists in WINS with source type %d.\n",
1571 nmb_namestr(question), namerec->data.source ));
1572 send_wins_name_registration_response(RFS_ERR, 0, p);
1573 return;
1577 * Reject if the name exists and is a GROUP name and is active.
1580 if((namerec != NULL) && NAME_GROUP(namerec) && WINS_STATE_ACTIVE(namerec)) {
1581 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1582 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
1583 send_wins_name_registration_response(RFS_ERR, 0, p);
1584 return;
1588 * From here on down we know that if the name exists in the WINS db it is
1589 * a unique name, not a group name.
1593 * If the name exists and is one of our names then check the
1594 * registering IP address. If it's not one of ours then automatically
1595 * reject without doing the query - we know we will reject it.
1598 if((namerec != NULL) && (is_myname(namerec->name.name)) ) {
1599 if(!ismyip(from_ip)) {
1600 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1601 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
1602 send_wins_name_registration_response(RFS_ERR, 0, p);
1603 return;
1604 } else {
1606 * It's one of our names and one of our IP's. Ensure the IP is in the record and
1607 * update the ttl. Update the version ID to force replication.
1609 update_name_ttl(namerec, ttl);
1611 if(!find_ip_in_name_record(namerec, from_ip)) {
1612 get_global_id_and_update(&namerec->data.id, True);
1613 update_wins_owner(namerec, our_fake_ip);
1614 update_wins_flag(namerec, WINS_ACTIVE);
1616 add_ip_to_name_record(namerec, from_ip);
1619 wins_hook("refresh", namerec, ttl);
1620 send_wins_name_registration_response(0, ttl, p);
1621 return;
1626 * If the name exists and is active, check if the IP address is already registered
1627 * to that name. If so then update the ttl and reply success.
1630 if((namerec != NULL) && find_ip_in_name_record(namerec, from_ip) && WINS_STATE_ACTIVE(namerec)) {
1631 update_name_ttl(namerec, ttl);
1634 * If it's a replica, we need to become the wins owner
1635 * to force the replication
1637 if (!ip_equal(namerec->data.wins_ip, our_fake_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);
1643 wins_hook("refresh", namerec, ttl);
1644 send_wins_name_registration_response(0, ttl, p);
1645 return;
1649 * If the name exists do a query to the owner
1650 * to see if they still want the name.
1653 if(namerec != NULL) {
1654 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
1655 struct userdata_struct *userdata = (struct userdata_struct *)ud;
1658 * First send a WACK to the registering machine.
1661 send_wins_wack_response(60, p);
1664 * When the reply comes back we need the original packet.
1665 * Lock this so it won't be freed and then put it into
1666 * the userdata structure.
1669 p->locked = True;
1671 userdata = (struct userdata_struct *)ud;
1673 userdata->copy_fn = NULL;
1674 userdata->free_fn = NULL;
1675 userdata->userdata_len = sizeof(struct packet_struct *);
1676 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
1679 * Use the new call to send a query directly to an IP address.
1680 * This sends the query directly to the IP address, and ensures
1681 * the recursion desired flag is not set (you were right Luke :-).
1682 * This function should *only* be called from the WINS server
1683 * code. JRA.
1685 * Note that this packet is sent to the current owner of the name,
1686 * not the person who sent the packet
1689 pull_ascii_nstring( qname, sizeof(qname), question->name);
1690 query_name_from_wins_server( namerec->data.ip[0],
1691 qname,
1692 question->name_type,
1693 wins_multihomed_register_query_success,
1694 wins_multihomed_register_query_fail,
1695 userdata );
1697 return;
1701 * Name did not exist - add it.
1704 pull_ascii_nstring( qname, sizeof(qname), question->name);
1705 add_name_to_subnet( subrec, qname, question->name_type,
1706 nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
1708 if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
1709 get_global_id_and_update(&namerec->data.id, True);
1710 update_wins_owner(namerec, our_fake_ip);
1711 update_wins_flag(namerec, WINS_ACTIVE);
1712 wins_hook("add", namerec, ttl);
1715 send_wins_name_registration_response(0, ttl, p);
1718 /***********************************************************************
1719 Fetch all *<1b> names from the WINS db and store on the namelist.
1720 ***********************************************************************/
1722 static int fetch_1b_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
1724 struct name_record *namerec = NULL;
1726 if (kbuf.dsize != sizeof(unstring) + 1) {
1727 return 0;
1730 /* Filter out all non-1b names. */
1731 if (kbuf.dptr[sizeof(unstring)] != 0x1b) {
1732 return 0;
1735 namerec = wins_record_to_name_record(kbuf, dbuf);
1736 if (!namerec) {
1737 return 0;
1740 DLIST_ADD(wins_server_subnet->namelist, namerec);
1741 return 0;
1744 void fetch_all_active_wins_1b_names(void)
1746 tdb_traverse(wins_tdb, fetch_1b_traverse_fn, NULL);
1749 /***********************************************************************
1750 Deal with the special name query for *<1b>.
1751 ***********************************************************************/
1753 static void process_wins_dmb_query_request(struct subnet_record *subrec,
1754 struct packet_struct *p)
1756 struct name_record *namerec = NULL;
1757 char *prdata;
1758 int num_ips;
1761 * Go through all the ACTIVE names in the WINS db looking for those
1762 * ending in <1b>. Use this to calculate the number of IP
1763 * addresses we need to return.
1766 num_ips = 0;
1768 /* First, clear the in memory list - we're going to re-populate
1769 it with the tdb_traversal in fetch_all_active_wins_1b_names. */
1771 wins_delete_all_tmp_in_memory_records();
1773 fetch_all_active_wins_1b_names();
1775 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1776 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1777 num_ips += namerec->data.num_ips;
1781 if(num_ips == 0) {
1783 * There are no 0x1b names registered. Return name query fail.
1785 send_wins_name_query_response(NAM_ERR, p, NULL);
1786 return;
1789 if((prdata = (char *)SMB_MALLOC( num_ips * 6 )) == NULL) {
1790 DEBUG(0,("process_wins_dmb_query_request: Malloc fail !.\n"));
1791 return;
1795 * Go through all the names again in the WINS db looking for those
1796 * ending in <1b>. Add their IP addresses into the list we will
1797 * return.
1800 num_ips = 0;
1801 for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
1802 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
1803 int i;
1804 for(i = 0; i < namerec->data.num_ips; i++) {
1805 set_nb_flags(&prdata[num_ips * 6],namerec->data.nb_flags);
1806 putip((char *)&prdata[(num_ips * 6) + 2], &namerec->data.ip[i]);
1807 num_ips++;
1813 * Send back the reply containing the IP list.
1816 reply_netbios_packet(p, /* Packet to reply to. */
1817 0, /* Result code. */
1818 WINS_QUERY, /* nmbd type code. */
1819 NMB_NAME_QUERY_OPCODE, /* opcode. */
1820 lp_min_wins_ttl(), /* ttl. */
1821 prdata, /* data to send. */
1822 num_ips*6); /* data length. */
1824 SAFE_FREE(prdata);
1827 /****************************************************************************
1828 Send a WINS name query response.
1829 **************************************************************************/
1831 void send_wins_name_query_response(int rcode, struct packet_struct *p,
1832 struct name_record *namerec)
1834 char rdata[6];
1835 char *prdata = rdata;
1836 int reply_data_len = 0;
1837 int ttl = 0;
1838 int i;
1840 memset(rdata,'\0',6);
1842 if(rcode == 0) {
1843 ttl = (namerec->data.death_time != PERMANENT_TTL) ? namerec->data.death_time - p->timestamp : lp_max_wins_ttl();
1845 /* Copy all known ip addresses into the return data. */
1846 /* Optimise for the common case of one IP address so we don't need a malloc. */
1848 if( namerec->data.num_ips == 1 ) {
1849 prdata = rdata;
1850 } else {
1851 if((prdata = (char *)SMB_MALLOC( namerec->data.num_ips * 6 )) == NULL) {
1852 DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
1853 return;
1857 for(i = 0; i < namerec->data.num_ips; i++) {
1858 set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
1859 putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
1862 sort_query_replies(prdata, i, p->ip);
1863 reply_data_len = namerec->data.num_ips * 6;
1866 reply_netbios_packet(p, /* Packet to reply to. */
1867 rcode, /* Result code. */
1868 WINS_QUERY, /* nmbd type code. */
1869 NMB_NAME_QUERY_OPCODE, /* opcode. */
1870 ttl, /* ttl. */
1871 prdata, /* data to send. */
1872 reply_data_len); /* data length. */
1874 if(prdata != rdata) {
1875 SAFE_FREE(prdata);
1879 /***********************************************************************
1880 Deal with a name query.
1881 ***********************************************************************/
1883 void wins_process_name_query_request(struct subnet_record *subrec,
1884 struct packet_struct *p)
1886 struct nmb_packet *nmb = &p->packet.nmb;
1887 struct nmb_name *question = &nmb->question.question_name;
1888 struct name_record *namerec = NULL;
1889 unstring qname;
1891 DEBUG(3,("wins_process_name_query: name query for name %s from IP %s\n",
1892 nmb_namestr(question), inet_ntoa(p->ip) ));
1895 * Special name code. If the queried name is *<1b> then search
1896 * the entire WINS database and return a list of all the IP addresses
1897 * registered to any <1b> name. This is to allow domain master browsers
1898 * to discover other domains that may not have a presence on their subnet.
1901 pull_ascii_nstring(qname, sizeof(qname), question->name);
1902 if(strequal( qname, "*") && (question->name_type == 0x1b)) {
1903 process_wins_dmb_query_request( subrec, p);
1904 return;
1907 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
1909 if(namerec != NULL) {
1911 * If the name is not anymore in active state then reply not found.
1912 * it's fair even if we keep it in the cache for days.
1914 if (!WINS_STATE_ACTIVE(namerec)) {
1915 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
1916 nmb_namestr(question) ));
1917 send_wins_name_query_response(NAM_ERR, p, namerec);
1918 return;
1922 * If it's a DNSFAIL_NAME then reply name not found.
1925 if( namerec->data.source == DNSFAIL_NAME ) {
1926 DEBUG(3,("wins_process_name_query: name query for name %s returning DNS fail.\n",
1927 nmb_namestr(question) ));
1928 send_wins_name_query_response(NAM_ERR, p, namerec);
1929 return;
1933 * If the name has expired then reply name not found.
1936 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < p->timestamp) ) {
1937 DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
1938 nmb_namestr(question) ));
1939 send_wins_name_query_response(NAM_ERR, p, namerec);
1940 return;
1943 DEBUG(3,("wins_process_name_query: name query for name %s returning first IP %s.\n",
1944 nmb_namestr(question), inet_ntoa(namerec->data.ip[0]) ));
1946 send_wins_name_query_response(0, p, namerec);
1947 return;
1951 * Name not found in WINS - try a dns query if it's a 0x20 name.
1954 if(lp_dns_proxy() && ((question->name_type == 0x20) || question->name_type == 0)) {
1955 DEBUG(3,("wins_process_name_query: name query for name %s not found - doing dns lookup.\n",
1956 nmb_namestr(question) ));
1958 queue_dns_query(p, question);
1959 return;
1963 * Name not found - return error.
1966 send_wins_name_query_response(NAM_ERR, p, NULL);
1969 /****************************************************************************
1970 Send a WINS name release response.
1971 **************************************************************************/
1973 static void send_wins_name_release_response(int rcode, struct packet_struct *p)
1975 struct nmb_packet *nmb = &p->packet.nmb;
1976 char rdata[6];
1978 memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
1980 reply_netbios_packet(p, /* Packet to reply to. */
1981 rcode, /* Result code. */
1982 NMB_REL, /* nmbd type code. */
1983 NMB_NAME_RELEASE_OPCODE, /* opcode. */
1984 0, /* ttl. */
1985 rdata, /* data to send. */
1986 6); /* data length. */
1989 /***********************************************************************
1990 Deal with a name release.
1991 ***********************************************************************/
1993 void wins_process_name_release_request(struct subnet_record *subrec,
1994 struct packet_struct *p)
1996 struct nmb_packet *nmb = &p->packet.nmb;
1997 struct nmb_name *question = &nmb->question.question_name;
1998 BOOL bcast = nmb->header.nm_flags.bcast;
1999 uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
2000 struct name_record *namerec = NULL;
2001 struct in_addr from_ip;
2002 BOOL releasing_group_name = (nb_flags & NB_GROUP) ? True : False;;
2004 putip((char *)&from_ip,&nmb->additional->rdata[2]);
2006 if(bcast) {
2008 * We should only get unicast name registration packets here.
2009 * Anyone trying to register broadcast should not be going to a WINS
2010 * server. Log an error here.
2013 DEBUG(0,("wins_process_name_release_request: broadcast name registration request \
2014 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
2015 nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
2016 return;
2019 DEBUG(3,("wins_process_name_release_request: %s name release for name %s \
2020 IP %s\n", releasing_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
2023 * Deal with policy regarding 0x1d names.
2026 if(!releasing_group_name && (question->name_type == 0x1d)) {
2027 DEBUG(3,("wins_process_name_release_request: Ignoring request \
2028 to release name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
2029 send_wins_name_release_response(0, p);
2030 return;
2034 * See if the name already exists.
2037 namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
2039 if( (namerec == NULL) || ((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) ) {
2040 send_wins_name_release_response(NAM_ERR, p);
2041 return;
2045 * Check that the sending machine has permission to release this name.
2046 * If it's a group name not ending in 0x1c then just say yes and let
2047 * the group time out.
2050 if(releasing_group_name && (question->name_type != 0x1c)) {
2051 send_wins_name_release_response(0, p);
2052 return;
2056 * Check that the releasing node is on the list of IP addresses
2057 * for this name. Disallow the release if not.
2060 if(!find_ip_in_name_record(namerec, from_ip)) {
2061 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2062 release name %s as IP %s is not one of the known IP's for this name.\n",
2063 nmb_namestr(question), inet_ntoa(from_ip) ));
2064 send_wins_name_release_response(NAM_ERR, p);
2065 return;
2069 * Check if the record is active. IF it's already released
2070 * or tombstoned, refuse the release.
2073 if (!WINS_STATE_ACTIVE(namerec)) {
2074 DEBUG(3,("wins_process_name_release_request: Refusing request to \
2075 release name %s as this record is not active anymore.\n", nmb_namestr(question) ));
2076 send_wins_name_release_response(NAM_ERR, p);
2077 return;
2081 * Check if the record is a 0x1c group
2082 * and has more then one ip
2083 * remove only this address.
2086 if(releasing_group_name && (question->name_type == 0x1c) && (namerec->data.num_ips > 1)) {
2087 remove_ip_from_name_record(namerec, from_ip);
2088 DEBUG(3,("wins_process_name_release_request: Remove IP %s from NAME: %s\n",
2089 inet_ntoa(from_ip),nmb_namestr(question)));
2090 wins_hook("delete", namerec, 0);
2091 send_wins_name_release_response(0, p);
2092 return;
2096 * Send a release response.
2097 * Flag the name as released and update the ttl
2100 namerec->data.wins_flags |= WINS_RELEASED;
2101 update_name_ttl(namerec, EXTINCTION_INTERVAL);
2103 wins_hook("delete", namerec, 0);
2104 send_wins_name_release_response(0, p);
2107 /*******************************************************************
2108 WINS time dependent processing.
2109 ******************************************************************/
2111 static int wins_processing_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2113 time_t t = *(time_t *)state;
2114 BOOL store_record = False;
2115 struct name_record *namerec = NULL;
2116 struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
2118 if (kbuf.dsize != sizeof(unstring) + 1) {
2119 return 0;
2122 namerec = wins_record_to_name_record(kbuf, dbuf);
2123 if (!namerec) {
2124 return 0;
2127 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
2128 if( namerec->data.source == SELF_NAME ) {
2129 DEBUG( 3, ( "wins_processing_traverse_fn: Subnet %s not expiring SELF name %s\n",
2130 wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) );
2131 namerec->data.death_time += 300;
2132 store_record = True;
2133 goto done;
2134 } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) {
2135 DEBUG(3,("wins_processing_traverse_fn: deleting timed out DNS name %s\n",
2136 nmb_namestr(&namerec->name)));
2137 remove_name_from_wins_namelist(namerec );
2138 goto done;
2141 /* handle records, samba is the wins owner */
2142 if (ip_equal(namerec->data.wins_ip, our_fake_ip)) {
2143 switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2144 case WINS_ACTIVE:
2145 namerec->data.wins_flags&=~WINS_STATE_MASK;
2146 namerec->data.wins_flags|=WINS_RELEASED;
2147 namerec->data.death_time = t + EXTINCTION_INTERVAL;
2148 DEBUG(3,("wins_processing_traverse_fn: expiring %s\n",
2149 nmb_namestr(&namerec->name)));
2150 store_record = True;
2151 goto done;
2152 case WINS_RELEASED:
2153 namerec->data.wins_flags&=~WINS_STATE_MASK;
2154 namerec->data.wins_flags|=WINS_TOMBSTONED;
2155 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2156 get_global_id_and_update(&namerec->data.id, True);
2157 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2158 nmb_namestr(&namerec->name)));
2159 store_record = True;
2160 goto done;
2161 case WINS_TOMBSTONED:
2162 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2163 nmb_namestr(&namerec->name)));
2164 remove_name_from_wins_namelist(namerec );
2165 goto done;
2167 } else {
2168 switch (namerec->data.wins_flags & WINS_STATE_MASK) {
2169 case WINS_ACTIVE:
2170 /* that's not as MS says it should be */
2171 namerec->data.wins_flags&=~WINS_STATE_MASK;
2172 namerec->data.wins_flags|=WINS_TOMBSTONED;
2173 namerec->data.death_time = t + EXTINCTION_TIMEOUT;
2174 DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
2175 nmb_namestr(&namerec->name)));
2176 store_record = True;
2177 goto done;
2178 case WINS_TOMBSTONED:
2179 DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
2180 nmb_namestr(&namerec->name)));
2181 remove_name_from_wins_namelist(namerec );
2182 goto done;
2183 case WINS_RELEASED:
2184 DEBUG(0,("wins_processing_traverse_fn: %s is in released state and\
2185 we are not the wins owner !\n", nmb_namestr(&namerec->name)));
2186 goto done;
2191 done:
2193 if (store_record) {
2194 wins_store_changed_namerec(namerec);
2197 SAFE_FREE(namerec->data.ip);
2198 SAFE_FREE(namerec);
2200 return 0;
2203 /*******************************************************************
2204 Time dependent wins processing.
2205 ******************************************************************/
2207 void initiate_wins_processing(time_t t)
2209 static time_t lasttime = 0;
2211 if (!lasttime) {
2212 lasttime = t;
2214 if (t - lasttime < 20) {
2215 return;
2218 if(!lp_we_are_a_wins_server()) {
2219 lasttime = t;
2220 return;
2223 tdb_traverse(wins_tdb, wins_processing_traverse_fn, &t);
2225 wins_delete_all_tmp_in_memory_records();
2227 wins_write_database(t, True);
2229 lasttime = t;
2232 /*******************************************************************
2233 Write out one record.
2234 ******************************************************************/
2236 void wins_write_name_record(struct name_record *namerec, XFILE *fp)
2238 int i;
2239 struct tm *tm;
2241 DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) ));
2243 if( namerec->data.death_time != PERMANENT_TTL ) {
2244 char *ts, *nl;
2246 tm = localtime(&namerec->data.death_time);
2247 if (!tm) {
2248 return;
2250 ts = asctime(tm);
2251 if (!ts) {
2252 return;
2254 nl = strrchr( ts, '\n' );
2255 if( NULL != nl ) {
2256 *nl = '\0';
2258 DEBUGADD(4,("TTL = %s ", ts ));
2259 } else {
2260 DEBUGADD(4,("TTL = PERMANENT "));
2263 for (i = 0; i < namerec->data.num_ips; i++) {
2264 DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) ));
2266 DEBUGADD(4,("%2x\n", namerec->data.nb_flags ));
2268 if( namerec->data.source == REGISTER_NAME ) {
2269 unstring name;
2270 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
2271 x_fprintf(fp, "\"%s#%02x\" %d ", name,namerec->name.name_type, /* Ignore scope. */
2272 (int)namerec->data.death_time);
2274 for (i = 0; i < namerec->data.num_ips; i++)
2275 x_fprintf( fp, "%s ", inet_ntoa( namerec->data.ip[i] ) );
2276 x_fprintf( fp, "%2xR\n", namerec->data.nb_flags );
2280 /*******************************************************************
2281 Write out the current WINS database.
2282 ******************************************************************/
2284 static int wins_writedb_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
2286 struct name_record *namerec = NULL;
2287 XFILE *fp = (XFILE *)state;
2289 if (kbuf.dsize != sizeof(unstring) + 1) {
2290 return 0;
2293 namerec = wins_record_to_name_record(kbuf, dbuf);
2294 if (!namerec) {
2295 return 0;
2298 wins_write_name_record(namerec, fp);
2300 SAFE_FREE(namerec->data.ip);
2301 SAFE_FREE(namerec);
2302 return 0;
2306 void wins_write_database(time_t t, BOOL background)
2308 static time_t last_write_time = 0;
2309 pstring fname, fnamenew;
2311 XFILE *fp;
2313 if (background) {
2314 if (!last_write_time) {
2315 last_write_time = t;
2317 if (t - last_write_time < 120) {
2318 return;
2323 if(!lp_we_are_a_wins_server()) {
2324 return;
2327 /* We will do the writing in a child process to ensure that the parent doesn't block while this is done */
2328 if (background) {
2329 CatchChild();
2330 if (sys_fork()) {
2331 return;
2333 if (tdb_reopen(wins_tdb)) {
2334 DEBUG(0,("wins_write_database: tdb_reopen failed. Error was %s\n",
2335 strerror(errno)));
2336 _exit(0);
2337 return;
2341 slprintf(fname,sizeof(fname)-1,"%s/%s", lp_lockdir(), WINS_LIST);
2342 all_string_sub(fname,"//", "/", 0);
2343 slprintf(fnamenew,sizeof(fnamenew)-1,"%s.%u", fname, (unsigned int)sys_getpid());
2345 if((fp = x_fopen(fnamenew,O_WRONLY|O_CREAT,0644)) == NULL) {
2346 DEBUG(0,("wins_write_database: Can't open %s. Error was %s\n", fnamenew, strerror(errno)));
2347 if (background) {
2348 _exit(0);
2350 return;
2353 DEBUG(4,("wins_write_database: Dump of WINS name list.\n"));
2355 x_fprintf(fp,"VERSION %d %u\n", WINS_VERSION, 0);
2357 tdb_traverse(wins_tdb, wins_writedb_traverse_fn, fp);
2359 x_fclose(fp);
2360 chmod(fnamenew,0644);
2361 unlink(fname);
2362 rename(fnamenew,fname);
2363 if (background) {
2364 _exit(0);
2368 #if 0
2369 Until winsrepl is done.
2370 /****************************************************************************
2371 Process a internal Samba message receiving a wins record.
2372 ***************************************************************************/
2374 void nmbd_wins_new_entry(int msg_type, struct process_id src,
2375 void *buf, size_t len, void *private_data)
2377 WINS_RECORD *record;
2378 struct name_record *namerec = NULL;
2379 struct name_record *new_namerec = NULL;
2380 struct nmb_name question;
2381 BOOL overwrite=False;
2382 struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
2383 int i;
2385 if (buf==NULL) {
2386 return;
2389 /* Record should use UNIX codepage. Ensure this is so in the wrepld code. JRA. */
2390 record=(WINS_RECORD *)buf;
2392 make_nmb_name(&question, record->name, record->type);
2394 namerec = find_name_on_subnet(wins_server_subnet, &question, FIND_ANY_NAME);
2396 /* record doesn't exist, add it */
2397 if (namerec == NULL) {
2398 DEBUG(3,("nmbd_wins_new_entry: adding new replicated record: %s<%02x> for wins server: %s\n",
2399 record->name, record->type, inet_ntoa(record->wins_ip)));
2401 new_namerec=add_name_to_subnet( wins_server_subnet,
2402 record->name,
2403 record->type,
2404 record->nb_flags,
2405 EXTINCTION_INTERVAL,
2406 REGISTER_NAME,
2407 record->num_ips,
2408 record->ip);
2410 if (new_namerec!=NULL) {
2411 update_wins_owner(new_namerec, record->wins_ip);
2412 update_wins_flag(new_namerec, record->wins_flags);
2413 new_namerec->data.id=record->id;
2415 wins_server_subnet->namelist_changed = True;
2419 /* check if we have a conflict */
2420 if (namerec != NULL) {
2421 /* both records are UNIQUE */
2422 if (namerec->data.wins_flags&WINS_UNIQUE && record->wins_flags&WINS_UNIQUE) {
2424 /* the database record is a replica */
2425 if (!ip_equal(namerec->data.wins_ip, our_fake_ip)) {
2426 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED) {
2427 if (ip_equal(namerec->data.wins_ip, record->wins_ip))
2428 overwrite=True;
2429 } else
2430 overwrite=True;
2431 } else {
2432 /* we are the wins owner of the database record */
2433 /* the 2 records have the same IP address */
2434 if (ip_equal(namerec->data.ip[0], record->ip[0])) {
2435 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED)
2436 get_global_id_and_update(&namerec->data.id, True);
2437 else
2438 overwrite=True;
2440 } else {
2441 /* the 2 records have different IP address */
2442 if (namerec->data.wins_flags&WINS_ACTIVE) {
2443 if (record->wins_flags&WINS_TOMBSTONED)
2444 get_global_id_and_update(&namerec->data.id, True);
2445 if (record->wins_flags&WINS_ACTIVE)
2446 /* send conflict challenge to the replica node */
2448 } else
2449 overwrite=True;
2455 /* the replica is a standard group */
2456 if (record->wins_flags&WINS_NGROUP || record->wins_flags&WINS_SGROUP) {
2457 /* if the database record is unique and active force a name release */
2458 if (namerec->data.wins_flags&WINS_UNIQUE)
2459 /* send a release name to the unique node */
2461 overwrite=True;
2465 /* the replica is a special group */
2466 if (record->wins_flags&WINS_SGROUP && namerec->data.wins_flags&WINS_SGROUP) {
2467 if (namerec->data.wins_flags&WINS_ACTIVE) {
2468 for (i=0; i<record->num_ips; i++)
2469 if(!find_ip_in_name_record(namerec, record->ip[i]))
2470 add_ip_to_name_record(namerec, record->ip[i]);
2471 } else {
2472 overwrite=True;
2476 /* the replica is a multihomed host */
2478 /* I'm giving up on multi homed. Too much complex to understand */
2480 if (record->wins_flags&WINS_MHOMED) {
2481 if (! (namerec->data.wins_flags&WINS_ACTIVE)) {
2482 if ( !(namerec->data.wins_flags&WINS_RELEASED) && !(namerec->data.wins_flags&WINS_NGROUP))
2483 overwrite=True;
2485 else {
2486 if (ip_equal(record->wins_ip, namerec->data.wins_ip))
2487 overwrite=True;
2489 if (ip_equal(namerec->data.wins_ip, our_fake_ip))
2490 if (namerec->data.wins_flags&WINS_UNIQUE)
2491 get_global_id_and_update(&namerec->data.id, True);
2495 if (record->wins_flags&WINS_ACTIVE && namerec->data.wins_flags&WINS_ACTIVE)
2496 if (namerec->data.wins_flags&WINS_UNIQUE ||
2497 namerec->data.wins_flags&WINS_MHOMED)
2498 if (ip_equal(record->wins_ip, namerec->data.wins_ip))
2499 overwrite=True;
2503 if (overwrite == False)
2504 DEBUG(3, ("nmbd_wins_new_entry: conflict in adding record: %s<%02x> from wins server: %s\n",
2505 record->name, record->type, inet_ntoa(record->wins_ip)));
2506 else {
2507 DEBUG(3, ("nmbd_wins_new_entry: replacing record: %s<%02x> from wins server: %s\n",
2508 record->name, record->type, inet_ntoa(record->wins_ip)));
2510 /* remove the old record and add a new one */
2511 remove_name_from_namelist( wins_server_subnet, namerec );
2512 new_namerec=add_name_to_subnet( wins_server_subnet, record->name, record->type, record->nb_flags,
2513 EXTINCTION_INTERVAL, REGISTER_NAME, record->num_ips, record->ip);
2514 if (new_namerec!=NULL) {
2515 update_wins_owner(new_namerec, record->wins_ip);
2516 update_wins_flag(new_namerec, record->wins_flags);
2517 new_namerec->data.id=record->id;
2519 wins_server_subnet->namelist_changed = True;
2522 wins_server_subnet->namelist_changed = True;
2527 #endif