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(global_loadparm, NULL, "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 &&
695 lp_parm_bool(global_loadparm, NULL, "nbtd", "wins_prepend1Bto1Cqueries", true)) {
696 struct nbt_name name_1b;
699 name_1b.type = NBT_NAME_PDC;
701 status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
702 if (NT_STATUS_IS_OK(status)) {
703 addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
707 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
708 if (!NT_STATUS_IS_OK(status)) {
709 if (!lp_wins_dns_proxy(global_loadparm)) {
713 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
717 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
722 * for group's we always reply with
723 * 255.255.255.255 as address, even if
724 * the record is released or tombstoned
726 if (rec->type == WREPL_TYPE_GROUP) {
727 addresses = str_list_add(NULL, "255.255.255.255");
728 talloc_steal(packet, addresses);
732 nb_flags |= NBT_NM_GROUP;
736 if (rec->state != WREPL_STATE_ACTIVE) {
740 addresses = winsdb_addr_string_list(packet, rec->addresses);
746 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
747 * first 0x1B address as first address
749 if (addresses_1b && addresses_1b[0]) {
750 const char **addresses_1c = addresses;
754 addresses = str_list_add(NULL, addresses_1b[0]);
758 talloc_steal(packet, addresses);
761 for (i=0; addresses_1c[i]; i++) {
762 if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
765 * stop when we already have 25 addresses
767 if (num_addrs >= 25) break;
770 addresses = str_list_add(addresses, addresses_1c[i]);
777 if (rec->type == WREPL_TYPE_SGROUP) {
778 nb_flags |= NBT_NM_GROUP;
780 nb_flags |= (rec->node <<13);
784 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
786 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList
787 * Typ: Daten REG_DWORD
788 * Value: 0 = deactivated, 1 = activated
790 if (name->type == NBT_NAME_LOGON &&
791 lp_parm_bool(global_loadparm, NULL, "nbtd", "wins_randomize1Clist", false)) {
792 nbtd_wins_randomize1Clist(addresses, src);
796 nbtd_name_query_reply(nbtsock, packet, src, name,
797 0, nb_flags, addresses);
801 nbtd_negative_name_query_reply(nbtsock, packet, src);
807 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
808 struct nbt_name_packet *packet,
809 struct socket_address *src)
812 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
813 struct nbtd_interface);
814 struct wins_server *winssrv = iface->nbtsrv->winssrv;
815 struct nbt_name *name = &packet->questions[0].name;
816 struct winsdb_record *rec;
817 uint32_t modify_flags = 0;
820 if (name->type == NBT_NAME_MASTER) {
824 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
825 if (!NT_STATUS_IS_OK(status)) {
829 if (rec->is_static) {
830 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
833 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
837 if (rec->state != WREPL_STATE_ACTIVE) {
842 * TODO: do we need to check if
843 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
848 * we only allow releases from an owner - other releases are
851 if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
853 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
854 DEBUGADD(4, ("Registered Addresses: \n"));
855 for (i=0; rec->addresses && rec->addresses[i]; i++) {
856 DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
861 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
864 case WREPL_TYPE_UNIQUE:
865 rec->state = WREPL_STATE_RELEASED;
868 case WREPL_TYPE_GROUP:
869 rec->state = WREPL_STATE_RELEASED;
872 case WREPL_TYPE_SGROUP:
873 winsdb_addr_list_remove(rec->addresses, src->addr);
874 /* TODO: do we need to take the ownership here? */
875 if (winsdb_addr_list_length(rec->addresses) == 0) {
876 rec->state = WREPL_STATE_RELEASED;
880 case WREPL_TYPE_MHOMED:
881 winsdb_addr_list_remove(rec->addresses, src->addr);
882 /* TODO: do we need to take the ownership here? */
883 if (winsdb_addr_list_length(rec->addresses) == 0) {
884 rec->state = WREPL_STATE_RELEASED;
889 if (rec->state == WREPL_STATE_RELEASED) {
891 * if we're not the owner, we need to take the owner ship
892 * and make the record tombstone, but expire after
893 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
894 * like for normal tombstone records.
895 * This is to replicate the record directly to the original owner,
896 * where the record is still active
898 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
899 rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
901 rec->state = WREPL_STATE_TOMBSTONE;
902 rec->expire_time= time(NULL) +
903 winssrv->config.tombstone_interval +
904 winssrv->config.tombstone_timeout;
905 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
909 ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
910 if (ret != NBT_RCODE_OK) {
911 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
912 nbt_name_string(rec, rec->name), src->addr, ret));
915 /* we match w2k3 by always giving a positive reply to name releases. */
916 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
923 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
924 struct nbt_name_packet *packet,
925 struct socket_address *src)
927 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
928 struct nbtd_interface);
929 struct wins_server *winssrv = iface->nbtsrv->winssrv;
930 if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
934 switch (packet->operation & NBT_OPCODE) {
935 case NBT_OPCODE_QUERY:
936 nbtd_winsserver_query(nbtsock, packet, src);
939 case NBT_OPCODE_REGISTER:
940 case NBT_OPCODE_REFRESH:
941 case NBT_OPCODE_REFRESH2:
942 case NBT_OPCODE_MULTI_HOME_REG:
943 nbtd_winsserver_register(nbtsock, packet, src);
946 case NBT_OPCODE_RELEASE:
947 nbtd_winsserver_release(nbtsock, packet, src);
954 startup the WINS server, if configured
956 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
960 if (!lp_wins_support(global_loadparm)) {
961 nbtsrv->winssrv = NULL;
965 nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
966 NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
968 nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl(global_loadparm);
969 nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl(global_loadparm);
970 tmp = lp_parm_int(global_loadparm, NULL, "wreplsrv", "tombstone_interval", 6*24*60*60);
971 nbtsrv->winssrv->config.tombstone_interval = tmp;
972 tmp = lp_parm_int(global_loadparm, NULL, "wreplsrv"," tombstone_timeout", 1*24*60*60);
973 nbtsrv->winssrv->config.tombstone_timeout = tmp;
975 nbtsrv->winssrv->wins_db = winsdb_connect(nbtsrv->winssrv, WINSDB_HANDLE_CALLER_NBTD);
976 if (!nbtsrv->winssrv->wins_db) {
977 return NT_STATUS_INTERNAL_DB_ERROR;
980 irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");