2 Unix SMB/CIFS implementation.
4 core wins server handling
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Stefan Metzmacher 2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "nbt_server/nbt_server.h"
25 #include "nbt_server/wins/winsdb.h"
26 #include "nbt_server/wins/winsserver.h"
27 #include "librpc/gen_ndr/ndr_nbt.h"
28 #include "system/time.h"
29 #include "libcli/composite/composite.h"
30 #include "smbd/service_task.h"
31 #include "system/network.h"
32 #include "lib/socket/socket.h"
33 #include "lib/socket/netif.h"
34 #include "lib/ldb/include/ldb.h"
35 #include "param/param.h"
38 work out the ttl we will use given a client requested ttl
40 uint32_t wins_server_ttl(struct wins_server *winssrv, uint32_t ttl)
42 ttl = MIN(ttl, winssrv->config.max_renew_interval);
43 ttl = MAX(ttl, winssrv->config.min_renew_interval);
47 static enum wrepl_name_type wrepl_type(uint16_t nb_flags, struct nbt_name *name, BOOL mhomed)
49 /* this copes with the nasty hack that is the type 0x1c name */
50 if (name->type == NBT_NAME_LOGON) {
51 return WREPL_TYPE_SGROUP;
53 if (nb_flags & NBT_NM_GROUP) {
54 return WREPL_TYPE_GROUP;
57 return WREPL_TYPE_MHOMED;
59 return WREPL_TYPE_UNIQUE;
63 register a new name with WINS
65 static uint8_t wins_register_new(struct nbt_name_socket *nbtsock,
66 struct nbt_name_packet *packet,
67 const struct socket_address *src,
68 enum wrepl_name_type type)
70 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
71 struct nbtd_interface);
72 struct wins_server *winssrv = iface->nbtsrv->winssrv;
73 struct nbt_name *name = &packet->questions[0].name;
74 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
75 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
76 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
77 struct winsdb_record rec;
78 enum wrepl_name_node node;
80 #define WREPL_NODE_NBT_FLAGS(nb_flags) \
81 ((nb_flags & NBT_NM_OWNER_TYPE)>>13)
83 node = WREPL_NODE_NBT_FLAGS(nb_flags);
87 rec.state = WREPL_STATE_ACTIVE;
89 rec.is_static = False;
90 rec.expire_time = time(NULL) + ttl;
91 rec.version = 0; /* will be allocated later */
92 rec.wins_owner = NULL; /* will be set later */
93 rec.registered_by = src->addr;
94 rec.addresses = winsdb_addr_list_make(packet);
95 if (rec.addresses == NULL) return NBT_RCODE_SVR;
97 rec.addresses = winsdb_addr_list_add(winssrv->wins_db,
100 winssrv->wins_db->local_owner,
103 if (rec.addresses == NULL) return NBT_RCODE_SVR;
105 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
106 nbt_name_string(packet, name), rec.addresses[0]->address));
108 return winsdb_add(winssrv->wins_db, &rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
113 update the ttl on an existing record
115 static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock,
116 struct nbt_name_packet *packet,
117 struct winsdb_record *rec,
118 struct winsdb_addr *winsdb_addr,
119 const struct socket_address *src)
121 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
122 struct nbtd_interface);
123 struct wins_server *winssrv = iface->nbtsrv->winssrv;
124 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
125 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
126 uint32_t modify_flags = 0;
128 rec->expire_time = time(NULL) + ttl;
129 rec->registered_by = src->addr;
132 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
134 winsdb_addr->address,
135 winssrv->wins_db->local_owner,
138 if (rec->addresses == NULL) return NBT_RCODE_SVR;
141 if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) {
142 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
145 DEBUG(5,("WINS: refreshed registration of %s at %s\n",
146 nbt_name_string(packet, rec->name), address));
148 return winsdb_modify(winssrv->wins_db, rec, modify_flags);
154 static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
155 struct nbt_name_packet *packet,
156 struct winsdb_record *rec,
158 const struct socket_address *src)
160 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
161 struct nbtd_interface);
162 struct wins_server *winssrv = iface->nbtsrv->winssrv;
163 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
165 rec->expire_time = time(NULL) + ttl;
166 rec->registered_by = src->addr;
168 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
171 winssrv->wins_db->local_owner,
174 if (rec->addresses == NULL) return NBT_RCODE_SVR;
176 DEBUG(5,("WINS: sgroup merge of %s at %s\n",
177 nbt_name_string(packet, rec->name), address));
179 return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
183 struct wins_server *winssrv;
184 struct nbt_name_socket *nbtsock;
185 struct nbt_name_packet *request_packet;
186 struct winsdb_record *rec;
187 struct socket_address *src;
188 const char *reg_address;
189 enum wrepl_name_type new_type;
190 struct wins_challenge_io io;
195 deny a registration request
197 static void wins_wack_deny(struct wack_state *s)
199 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
200 s->src, NBT_RCODE_ACT);
201 DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
202 nbt_name_string(s, s->rec->name), s->src->addr, s->src->port));
207 allow a registration request
209 static void wins_wack_allow(struct wack_state *s)
212 uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
213 struct winsdb_record *rec = s->rec, *rec2;
216 status = winsdb_lookup(s->winssrv->wins_db, rec->name, s, &rec2);
217 if (!NT_STATUS_IS_OK(status) ||
218 rec2->version != rec->version ||
219 strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
220 DEBUG(5,("WINS: record %s changed during WACK - failing registration\n",
221 nbt_name_string(s, rec->name)));
227 * if the old name owner doesn't hold the name anymore
228 * handle the request as new registration for the new name owner
230 if (!NT_STATUS_IS_OK(s->status)) {
233 winsdb_delete(s->winssrv->wins_db, rec);
234 rcode = wins_register_new(s->nbtsock, s->request_packet, s->src, s->new_type);
235 if (rcode != NBT_RCODE_OK) {
236 DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
237 nbt_name_string(s, rec->name)));
244 rec->expire_time = time(NULL) + ttl;
245 rec->registered_by = s->src->addr;
248 * now remove all addresses that're the client doesn't hold anymore
249 * and update the time stamp and owner for the ownes that are still there
251 for (i=0; rec->addresses[i]; i++) {
253 for (j=0; j < s->io.out.num_addresses; j++) {
254 if (strcmp(rec->addresses[i]->address, s->io.out.addresses[j]) != 0) continue;
260 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
263 s->winssrv->wins_db->local_owner,
266 if (rec->addresses == NULL) goto failed;
270 winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
273 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
276 s->winssrv->wins_db->local_owner,
279 if (rec->addresses == NULL) goto failed;
281 /* if we have more than one address, this becomes implicit a MHOMED record */
282 if (winsdb_addr_list_length(rec->addresses) > 1) {
283 rec->type = WREPL_TYPE_MHOMED;
286 winsdb_modify(s->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
288 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
289 nbt_name_string(s, rec->name), s->reg_address));
292 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
293 s->src, NBT_RCODE_OK);
299 called when a name query to a current owner completes
301 static void wack_wins_challenge_handler(struct composite_context *c_req)
303 struct wack_state *s = talloc_get_type(c_req->async.private_data,
308 s->status = wins_challenge_recv(c_req, s, &s->io);
311 * if the owner denies it holds the name, then allow
314 if (!NT_STATUS_IS_OK(s->status)) {
319 if (s->new_type == WREPL_TYPE_GROUP || s->new_type == WREPL_TYPE_SGROUP) {
320 DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
321 nbt_name_string(s, s->rec->name), s->new_type, s->rec->type));
327 * if the owner still wants the name and doesn't reply
328 * with the address trying to be registered, then deny
332 for (i=0; i < s->io.out.num_addresses; i++) {
333 if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
349 a client has asked to register a unique name that someone else owns. We
350 need to ask each of the current owners if they still want it. If they do
351 then reject the registration, otherwise allow it
353 static void wins_register_wack(struct nbt_name_socket *nbtsock,
354 struct nbt_name_packet *packet,
355 struct winsdb_record *rec,
356 struct socket_address *src,
357 enum wrepl_name_type new_type)
359 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
360 struct nbtd_interface);
361 struct wins_server *winssrv = iface->nbtsrv->winssrv;
362 struct wack_state *s;
363 struct composite_context *c_req;
366 s = talloc_zero(nbtsock, struct wack_state);
367 if (s == NULL) goto failed;
369 /* package up the state variables for this wack request */
370 s->winssrv = winssrv;
371 s->nbtsock = nbtsock;
372 s->request_packet = talloc_steal(s, packet);
373 s->rec = talloc_steal(s, rec);
374 s->reg_address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
375 s->new_type = new_type;
377 if (talloc_reference(s, src) == NULL) goto failed;
379 s->io.in.nbtd_server = iface->nbtsrv;
380 s->io.in.event_ctx = iface->nbtsrv->task->event_ctx;
381 s->io.in.name = rec->name;
382 s->io.in.num_addresses = winsdb_addr_list_length(rec->addresses);
383 s->io.in.addresses = winsdb_addr_string_list(s, rec->addresses);
384 if (s->io.in.addresses == NULL) goto failed;
387 * send a WACK to the client, specifying the maximum time it could
388 * take to check with the owner, plus some slack
390 ttl = 5 + 4 * winsdb_addr_list_length(rec->addresses);
391 nbtd_wack_reply(nbtsock, packet, src, ttl);
394 * send the challenge to the old addresses
396 c_req = wins_challenge_send(s, &s->io);
397 if (c_req == NULL) goto failed;
399 c_req->async.fn = wack_wins_challenge_handler;
400 c_req->async.private_data = s;
405 nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR);
411 static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
412 struct nbt_name_packet *packet,
413 struct socket_address *src)
416 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
417 struct nbtd_interface);
418 struct wins_server *winssrv = iface->nbtsrv->winssrv;
419 struct nbt_name *name = &packet->questions[0].name;
420 struct winsdb_record *rec;
421 uint8_t rcode = NBT_RCODE_OK;
422 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
423 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
424 BOOL mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
425 enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
426 struct winsdb_addr *winsdb_addr = NULL;
429 * as a special case, the local master browser name is always accepted
430 * for registration, but never stored, but w2k3 stores it if it's registered
431 * as a group name, (but a query for the 0x1D name still returns not found!)
433 if (name->type == NBT_NAME_MASTER && !(nb_flags & NBT_NM_GROUP)) {
434 rcode = NBT_RCODE_OK;
438 /* w2k3 refuses 0x1B names with marked as group */
439 if (name->type == NBT_NAME_PDC && (nb_flags & NBT_NM_GROUP)) {
440 rcode = NBT_RCODE_RFS;
444 /* w2k3 refuses 0x1C names with out marked as group */
445 if (name->type == NBT_NAME_LOGON && !(nb_flags & NBT_NM_GROUP)) {
446 rcode = NBT_RCODE_RFS;
450 /* w2k3 refuses 0x1E names with out marked as group */
451 if (name->type == NBT_NAME_BROWSER && !(nb_flags & NBT_NM_GROUP)) {
452 rcode = NBT_RCODE_RFS;
456 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
457 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
458 rcode = wins_register_new(nbtsock, packet, src, new_type);
460 } else if (!NT_STATUS_IS_OK(status)) {
461 rcode = NBT_RCODE_SVR;
463 } else if (rec->is_static) {
464 if (rec->type == WREPL_TYPE_GROUP || rec->type == WREPL_TYPE_SGROUP) {
465 rcode = NBT_RCODE_OK;
468 rcode = NBT_RCODE_ACT;
472 if (rec->type == WREPL_TYPE_GROUP) {
473 if (new_type != WREPL_TYPE_GROUP) {
474 DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
475 " while a normal group is already there\n",
476 nbt_name_string(packet, name), new_type));
477 rcode = NBT_RCODE_ACT;
481 if (rec->state == WREPL_STATE_ACTIVE) {
482 /* TODO: is this correct? */
483 rcode = wins_update_ttl(nbtsock, packet, rec, NULL, src);
487 /* TODO: is this correct? */
488 winsdb_delete(winssrv->wins_db, rec);
489 rcode = wins_register_new(nbtsock, packet, src, new_type);
493 if (rec->state != WREPL_STATE_ACTIVE) {
494 winsdb_delete(winssrv->wins_db, rec);
495 rcode = wins_register_new(nbtsock, packet, src, new_type);
500 case WREPL_TYPE_UNIQUE:
501 case WREPL_TYPE_MHOMED:
503 * if its an active unique name, and the registration is for a group, then
504 * see if the unique name owner still wants the name
505 * TODO: is this correct?
507 if (new_type == WREPL_TYPE_GROUP || new_type == WREPL_TYPE_GROUP) {
508 wins_register_wack(nbtsock, packet, rec, src, new_type);
513 * if the registration is for an address that is currently active, then
514 * just update the expiry time of the record and the address
516 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
518 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
523 * we have to do a WACK to see if the current owner is willing
524 * to give up its claim
526 wins_register_wack(nbtsock, packet, rec, src, new_type);
529 case WREPL_TYPE_GROUP:
530 /* this should not be reached as normal groups are handled above */
531 DEBUG(0,("BUG at %s\n",__location__));
532 rcode = NBT_RCODE_ACT;
535 case WREPL_TYPE_SGROUP:
536 /* if the new record isn't also a special group, refuse the registration */
537 if (new_type != WREPL_TYPE_SGROUP) {
538 DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
539 " while a special group is already there\n",
540 nbt_name_string(packet, name), new_type));
541 rcode = NBT_RCODE_ACT;
546 * if the registration is for an address that is currently active, then
547 * just update the expiry time of the record and the address
549 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
551 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
555 rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
560 nbtd_name_registration_reply(nbtsock, packet, src, rcode);
563 static uint32_t ipv4_match_bits(struct ipv4_addr ip1,struct ipv4_addr ip2)
565 uint32_t i, j, match=0;
568 p1 = (uint8_t *)&ip1.addr;
569 p2 = (uint8_t *)&ip2.addr;
571 for (i=0; i<4; i++) {
572 if (p1[i] != p2[i]) break;
576 if (i==4) return match;
578 for (j=0; j<8; j++) {
579 if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j))))
587 static int nbtd_wins_randomize1Clist_sort(void *p1,/* (const char **) */
588 void *p2,/* (const char **) */
589 struct socket_address *src)
591 const char *a1 = (const char *)*(const char **)p1;
592 const char *a2 = (const char *)*(const char **)p2;
593 uint32_t match_bits1;
594 uint32_t match_bits2;
596 match_bits1 = ipv4_match_bits(interpret_addr2(a1), interpret_addr2(src->addr));
597 match_bits2 = ipv4_match_bits(interpret_addr2(a2), interpret_addr2(src->addr));
599 return match_bits2 - match_bits1;
602 static void nbtd_wins_randomize1Clist(const char **addresses, struct socket_address *src)
610 for (num_addrs=0; addresses[num_addrs]; num_addrs++) { /* noop */ }
612 if (num_addrs <= 1) return; /* nothing to do */
614 /* first sort the addresses depending on the matching to the client */
615 ldb_qsort(addresses, num_addrs , sizeof(addresses[0]),
616 src, (ldb_qsort_cmp_fn_t)nbtd_wins_randomize1Clist_sort);
618 mask = lp_parm_string(-1, "nbtd", "wins_randomize1Clist_mask");
620 mask = "255.255.255.0";
624 * choose a random address to be the first in the response to the client,
625 * preferr the addresses inside the nbtd:wins_randomize1Clist_mask netmask
628 idx = sidx = r % num_addrs;
633 /* if the current one is in the same subnet, use it */
634 same = iface_same_net(addresses[idx], src->addr, mask);
640 /* we need to check for idx == 0, after checking for the same net */
643 * if we haven't found an address in the same subnet, search in ones
644 * which match the client more
648 * it's not "idx = idx % r" but "idx = r % idx"
649 * because in "a % b" b is the allowed range
650 * and b-1 is the maximum possible result, so it must be decreasing
651 * and the above idx == 0 check breaks the while(1) loop.
656 /* note sidx == 0 is also valid here ... */
658 addresses[0] = addresses[sidx];
659 addresses[sidx] = tmp;
665 static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock,
666 struct nbt_name_packet *packet,
667 struct socket_address *src)
670 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
671 struct nbtd_interface);
672 struct wins_server *winssrv = iface->nbtsrv->winssrv;
673 struct nbt_name *name = &packet->questions[0].name;
674 struct winsdb_record *rec;
675 struct winsdb_record *rec_1b = NULL;
676 const char **addresses;
677 const char **addresses_1b = NULL;
678 uint16_t nb_flags = 0;
680 if (name->type == NBT_NAME_MASTER) {
685 * w2k3 returns the first address of the 0x1B record as first address
688 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
690 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Prepend1BTo1CQueries
691 * Typ: Daten REG_DWORD
692 * Value: 0 = deactivated, 1 = activated
694 if (name->type == NBT_NAME_LOGON && lp_parm_bool(-1, "nbtd", "wins_prepend1Bto1Cqueries", True)) {
695 struct nbt_name name_1b;
698 name_1b.type = NBT_NAME_PDC;
700 status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
701 if (NT_STATUS_IS_OK(status)) {
702 addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
706 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
707 if (!NT_STATUS_IS_OK(status)) {
708 if (!lp_wins_dns_proxy()) {
712 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
716 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
721 * for group's we always reply with
722 * 255.255.255.255 as address, even if
723 * the record is released or tombstoned
725 if (rec->type == WREPL_TYPE_GROUP) {
726 addresses = str_list_add(NULL, "255.255.255.255");
727 talloc_steal(packet, addresses);
731 nb_flags |= NBT_NM_GROUP;
735 if (rec->state != WREPL_STATE_ACTIVE) {
739 addresses = winsdb_addr_string_list(packet, rec->addresses);
745 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
746 * first 0x1B address as first address
748 if (addresses_1b && addresses_1b[0]) {
749 const char **addresses_1c = addresses;
753 addresses = str_list_add(NULL, addresses_1b[0]);
757 talloc_steal(packet, addresses);
760 for (i=0; addresses_1c[i]; i++) {
761 if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
764 * stop when we already have 25 addresses
766 if (num_addrs >= 25) break;
769 addresses = str_list_add(addresses, addresses_1c[i]);
776 if (rec->type == WREPL_TYPE_SGROUP) {
777 nb_flags |= NBT_NM_GROUP;
779 nb_flags |= (rec->node <<13);
783 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
785 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList
786 * Typ: Daten REG_DWORD
787 * Value: 0 = deactivated, 1 = activated
789 if (name->type == NBT_NAME_LOGON && lp_parm_bool(-1, "nbtd", "wins_randomize1Clist", False)) {
790 nbtd_wins_randomize1Clist(addresses, src);
794 nbtd_name_query_reply(nbtsock, packet, src, name,
795 0, nb_flags, addresses);
799 nbtd_negative_name_query_reply(nbtsock, packet, src);
805 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
806 struct nbt_name_packet *packet,
807 struct socket_address *src)
810 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
811 struct nbtd_interface);
812 struct wins_server *winssrv = iface->nbtsrv->winssrv;
813 struct nbt_name *name = &packet->questions[0].name;
814 struct winsdb_record *rec;
815 uint32_t modify_flags = 0;
818 if (name->type == NBT_NAME_MASTER) {
822 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
823 if (!NT_STATUS_IS_OK(status)) {
827 if (rec->is_static) {
828 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
831 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
835 if (rec->state != WREPL_STATE_ACTIVE) {
840 * TODO: do we need to check if
841 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
846 * we only allow releases from an owner - other releases are
849 if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
851 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
852 DEBUGADD(4, ("Registered Addresses: \n"));
853 for (i=0; rec->addresses && rec->addresses[i]; i++) {
854 DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
859 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
862 case WREPL_TYPE_UNIQUE:
863 rec->state = WREPL_STATE_RELEASED;
866 case WREPL_TYPE_GROUP:
867 rec->state = WREPL_STATE_RELEASED;
870 case WREPL_TYPE_SGROUP:
871 winsdb_addr_list_remove(rec->addresses, src->addr);
872 /* TODO: do we need to take the ownership here? */
873 if (winsdb_addr_list_length(rec->addresses) == 0) {
874 rec->state = WREPL_STATE_RELEASED;
878 case WREPL_TYPE_MHOMED:
879 winsdb_addr_list_remove(rec->addresses, src->addr);
880 /* TODO: do we need to take the ownership here? */
881 if (winsdb_addr_list_length(rec->addresses) == 0) {
882 rec->state = WREPL_STATE_RELEASED;
887 if (rec->state == WREPL_STATE_RELEASED) {
889 * if we're not the owner, we need to take the owner ship
890 * and make the record tombstone, but expire after
891 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
892 * like for normal tombstone records.
893 * This is to replicate the record directly to the original owner,
894 * where the record is still active
896 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
897 rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
899 rec->state = WREPL_STATE_TOMBSTONE;
900 rec->expire_time= time(NULL) +
901 winssrv->config.tombstone_interval +
902 winssrv->config.tombstone_timeout;
903 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
907 ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
908 if (ret != NBT_RCODE_OK) {
909 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
910 nbt_name_string(rec, rec->name), src->addr, ret));
913 /* we match w2k3 by always giving a positive reply to name releases. */
914 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
921 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
922 struct nbt_name_packet *packet,
923 struct socket_address *src)
925 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
926 struct nbtd_interface);
927 struct wins_server *winssrv = iface->nbtsrv->winssrv;
928 if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
932 switch (packet->operation & NBT_OPCODE) {
933 case NBT_OPCODE_QUERY:
934 nbtd_winsserver_query(nbtsock, packet, src);
937 case NBT_OPCODE_REGISTER:
938 case NBT_OPCODE_REFRESH:
939 case NBT_OPCODE_REFRESH2:
940 case NBT_OPCODE_MULTI_HOME_REG:
941 nbtd_winsserver_register(nbtsock, packet, src);
944 case NBT_OPCODE_RELEASE:
945 nbtd_winsserver_release(nbtsock, packet, src);
952 startup the WINS server, if configured
954 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
958 if (!lp_wins_support()) {
959 nbtsrv->winssrv = NULL;
963 nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
964 NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
966 nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl();
967 nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl();
968 tmp = lp_parm_int(-1,"wreplsrv","tombstone_interval", 6*24*60*60);
969 nbtsrv->winssrv->config.tombstone_interval = tmp;
970 tmp = lp_parm_int(-1,"wreplsrv","tombstone_timeout", 1*24*60*60);
971 nbtsrv->winssrv->config.tombstone_timeout = tmp;
973 nbtsrv->winssrv->wins_db = winsdb_connect(nbtsrv->winssrv, WINSDB_HANDLE_CALLER_NBTD);
974 if (!nbtsrv->winssrv->wins_db) {
975 return NT_STATUS_INTERNAL_DB_ERROR;
978 irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");