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"
36 #include "libcli/resolve/resolve.h"
39 work out the ttl we will use given a client requested ttl
41 uint32_t wins_server_ttl(struct wins_server *winssrv, uint32_t ttl)
43 ttl = MIN(ttl, winssrv->config.max_renew_interval);
44 ttl = MAX(ttl, winssrv->config.min_renew_interval);
48 static enum wrepl_name_type wrepl_type(uint16_t nb_flags, struct nbt_name *name, bool mhomed)
50 /* this copes with the nasty hack that is the type 0x1c name */
51 if (name->type == NBT_NAME_LOGON) {
52 return WREPL_TYPE_SGROUP;
54 if (nb_flags & NBT_NM_GROUP) {
55 return WREPL_TYPE_GROUP;
58 return WREPL_TYPE_MHOMED;
60 return WREPL_TYPE_UNIQUE;
64 register a new name with WINS
66 static uint8_t wins_register_new(struct nbt_name_socket *nbtsock,
67 struct nbt_name_packet *packet,
68 const struct socket_address *src,
69 enum wrepl_name_type type)
71 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
72 struct nbtd_interface);
73 struct wins_server *winssrv = iface->nbtsrv->winssrv;
74 struct nbt_name *name = &packet->questions[0].name;
75 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
76 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
77 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
78 struct winsdb_record rec;
79 enum wrepl_name_node node;
81 #define WREPL_NODE_NBT_FLAGS(nb_flags) \
82 ((nb_flags & NBT_NM_OWNER_TYPE)>>13)
84 node = WREPL_NODE_NBT_FLAGS(nb_flags);
88 rec.state = WREPL_STATE_ACTIVE;
90 rec.is_static = false;
91 rec.expire_time = time(NULL) + ttl;
92 rec.version = 0; /* will be allocated later */
93 rec.wins_owner = NULL; /* will be set later */
94 rec.registered_by = src->addr;
95 rec.addresses = winsdb_addr_list_make(packet);
96 if (rec.addresses == NULL) return NBT_RCODE_SVR;
98 rec.addresses = winsdb_addr_list_add(winssrv->wins_db,
101 winssrv->wins_db->local_owner,
104 if (rec.addresses == NULL) return NBT_RCODE_SVR;
106 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
107 nbt_name_string(packet, name), rec.addresses[0]->address));
109 return winsdb_add(winssrv->wins_db, &rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
114 update the ttl on an existing record
116 static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock,
117 struct nbt_name_packet *packet,
118 struct winsdb_record *rec,
119 struct winsdb_addr *winsdb_addr,
120 const struct socket_address *src)
122 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
123 struct nbtd_interface);
124 struct wins_server *winssrv = iface->nbtsrv->winssrv;
125 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
126 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
127 uint32_t modify_flags = 0;
129 rec->expire_time = time(NULL) + ttl;
130 rec->registered_by = src->addr;
133 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
135 winsdb_addr->address,
136 winssrv->wins_db->local_owner,
139 if (rec->addresses == NULL) return NBT_RCODE_SVR;
142 if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) {
143 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
146 DEBUG(5,("WINS: refreshed registration of %s at %s\n",
147 nbt_name_string(packet, rec->name), address));
149 return winsdb_modify(winssrv->wins_db, rec, modify_flags);
155 static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
156 struct nbt_name_packet *packet,
157 struct winsdb_record *rec,
159 const struct socket_address *src)
161 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
162 struct nbtd_interface);
163 struct wins_server *winssrv = iface->nbtsrv->winssrv;
164 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
166 rec->expire_time = time(NULL) + ttl;
167 rec->registered_by = src->addr;
169 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
172 winssrv->wins_db->local_owner,
175 if (rec->addresses == NULL) return NBT_RCODE_SVR;
177 DEBUG(5,("WINS: sgroup merge of %s at %s\n",
178 nbt_name_string(packet, rec->name), address));
180 return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
184 struct wins_server *winssrv;
185 struct nbt_name_socket *nbtsock;
186 struct nbt_name_packet *request_packet;
187 struct winsdb_record *rec;
188 struct socket_address *src;
189 const char *reg_address;
190 enum wrepl_name_type new_type;
191 struct wins_challenge_io io;
196 deny a registration request
198 static void wins_wack_deny(struct wack_state *s)
200 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
201 s->src, NBT_RCODE_ACT);
202 DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
203 nbt_name_string(s, s->rec->name), s->src->addr, s->src->port));
208 allow a registration request
210 static void wins_wack_allow(struct wack_state *s)
213 uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
214 struct winsdb_record *rec = s->rec, *rec2;
217 status = winsdb_lookup(s->winssrv->wins_db, rec->name, s, &rec2);
218 if (!NT_STATUS_IS_OK(status) ||
219 rec2->version != rec->version ||
220 strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
221 DEBUG(5,("WINS: record %s changed during WACK - failing registration\n",
222 nbt_name_string(s, rec->name)));
228 * if the old name owner doesn't hold the name anymore
229 * handle the request as new registration for the new name owner
231 if (!NT_STATUS_IS_OK(s->status)) {
234 winsdb_delete(s->winssrv->wins_db, rec);
235 rcode = wins_register_new(s->nbtsock, s->request_packet, s->src, s->new_type);
236 if (rcode != NBT_RCODE_OK) {
237 DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
238 nbt_name_string(s, rec->name)));
245 rec->expire_time = time(NULL) + ttl;
246 rec->registered_by = s->src->addr;
249 * now remove all addresses that're the client doesn't hold anymore
250 * and update the time stamp and owner for the ownes that are still there
252 for (i=0; rec->addresses[i]; i++) {
254 for (j=0; j < s->io.out.num_addresses; j++) {
255 if (strcmp(rec->addresses[i]->address, s->io.out.addresses[j]) != 0) continue;
261 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
264 s->winssrv->wins_db->local_owner,
267 if (rec->addresses == NULL) goto failed;
271 winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
274 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
277 s->winssrv->wins_db->local_owner,
280 if (rec->addresses == NULL) goto failed;
282 /* if we have more than one address, this becomes implicit a MHOMED record */
283 if (winsdb_addr_list_length(rec->addresses) > 1) {
284 rec->type = WREPL_TYPE_MHOMED;
287 winsdb_modify(s->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
289 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
290 nbt_name_string(s, rec->name), s->reg_address));
293 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
294 s->src, NBT_RCODE_OK);
300 called when a name query to a current owner completes
302 static void wack_wins_challenge_handler(struct composite_context *c_req)
304 struct wack_state *s = talloc_get_type(c_req->async.private_data,
309 s->status = wins_challenge_recv(c_req, s, &s->io);
312 * if the owner denies it holds the name, then allow
315 if (!NT_STATUS_IS_OK(s->status)) {
320 if (s->new_type == WREPL_TYPE_GROUP || s->new_type == WREPL_TYPE_SGROUP) {
321 DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
322 nbt_name_string(s, s->rec->name), s->new_type, s->rec->type));
328 * if the owner still wants the name and doesn't reply
329 * with the address trying to be registered, then deny
333 for (i=0; i < s->io.out.num_addresses; i++) {
334 if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
350 a client has asked to register a unique name that someone else owns. We
351 need to ask each of the current owners if they still want it. If they do
352 then reject the registration, otherwise allow it
354 static void wins_register_wack(struct nbt_name_socket *nbtsock,
355 struct nbt_name_packet *packet,
356 struct winsdb_record *rec,
357 struct socket_address *src,
358 enum wrepl_name_type new_type)
360 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
361 struct nbtd_interface);
362 struct wins_server *winssrv = iface->nbtsrv->winssrv;
363 struct wack_state *s;
364 struct composite_context *c_req;
367 s = talloc_zero(nbtsock, struct wack_state);
368 if (s == NULL) goto failed;
370 /* package up the state variables for this wack request */
371 s->winssrv = winssrv;
372 s->nbtsock = nbtsock;
373 s->request_packet = talloc_steal(s, packet);
374 s->rec = talloc_steal(s, rec);
375 s->reg_address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
376 s->new_type = new_type;
378 if (talloc_reference(s, src) == NULL) goto failed;
380 s->io.in.nbtd_server = iface->nbtsrv;
381 s->io.in.nbt_port = lp_nbt_port(iface->nbtsrv->task->lp_ctx);
382 s->io.in.event_ctx = iface->nbtsrv->task->event_ctx;
383 s->io.in.name = rec->name;
384 s->io.in.num_addresses = winsdb_addr_list_length(rec->addresses);
385 s->io.in.addresses = winsdb_addr_string_list(s, rec->addresses);
386 if (s->io.in.addresses == NULL) goto failed;
389 * send a WACK to the client, specifying the maximum time it could
390 * take to check with the owner, plus some slack
392 ttl = 5 + 4 * winsdb_addr_list_length(rec->addresses);
393 nbtd_wack_reply(nbtsock, packet, src, ttl);
396 * send the challenge to the old addresses
398 c_req = wins_challenge_send(s, &s->io);
399 if (c_req == NULL) goto failed;
401 c_req->async.fn = wack_wins_challenge_handler;
402 c_req->async.private_data = s;
407 nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR);
413 static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
414 struct nbt_name_packet *packet,
415 struct socket_address *src)
418 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
419 struct nbtd_interface);
420 struct wins_server *winssrv = iface->nbtsrv->winssrv;
421 struct nbt_name *name = &packet->questions[0].name;
422 struct winsdb_record *rec;
423 uint8_t rcode = NBT_RCODE_OK;
424 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
425 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
426 bool mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
427 enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
428 struct winsdb_addr *winsdb_addr = NULL;
431 * as a special case, the local master browser name is always accepted
432 * for registration, but never stored, but w2k3 stores it if it's registered
433 * as a group name, (but a query for the 0x1D name still returns not found!)
435 if (name->type == NBT_NAME_MASTER && !(nb_flags & NBT_NM_GROUP)) {
436 rcode = NBT_RCODE_OK;
440 /* w2k3 refuses 0x1B names with marked as group */
441 if (name->type == NBT_NAME_PDC && (nb_flags & NBT_NM_GROUP)) {
442 rcode = NBT_RCODE_RFS;
446 /* w2k3 refuses 0x1C names with out marked as group */
447 if (name->type == NBT_NAME_LOGON && !(nb_flags & NBT_NM_GROUP)) {
448 rcode = NBT_RCODE_RFS;
452 /* w2k3 refuses 0x1E names with out marked as group */
453 if (name->type == NBT_NAME_BROWSER && !(nb_flags & NBT_NM_GROUP)) {
454 rcode = NBT_RCODE_RFS;
458 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
459 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
460 rcode = wins_register_new(nbtsock, packet, src, new_type);
462 } else if (!NT_STATUS_IS_OK(status)) {
463 rcode = NBT_RCODE_SVR;
465 } else if (rec->is_static) {
466 if (rec->type == WREPL_TYPE_GROUP || rec->type == WREPL_TYPE_SGROUP) {
467 rcode = NBT_RCODE_OK;
470 rcode = NBT_RCODE_ACT;
474 if (rec->type == WREPL_TYPE_GROUP) {
475 if (new_type != WREPL_TYPE_GROUP) {
476 DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
477 " while a normal group is already there\n",
478 nbt_name_string(packet, name), new_type));
479 rcode = NBT_RCODE_ACT;
483 if (rec->state == WREPL_STATE_ACTIVE) {
484 /* TODO: is this correct? */
485 rcode = wins_update_ttl(nbtsock, packet, rec, NULL, src);
489 /* TODO: is this correct? */
490 winsdb_delete(winssrv->wins_db, rec);
491 rcode = wins_register_new(nbtsock, packet, src, new_type);
495 if (rec->state != WREPL_STATE_ACTIVE) {
496 winsdb_delete(winssrv->wins_db, rec);
497 rcode = wins_register_new(nbtsock, packet, src, new_type);
502 case WREPL_TYPE_UNIQUE:
503 case WREPL_TYPE_MHOMED:
505 * if its an active unique name, and the registration is for a group, then
506 * see if the unique name owner still wants the name
507 * TODO: is this correct?
509 if (new_type == WREPL_TYPE_GROUP || new_type == WREPL_TYPE_GROUP) {
510 wins_register_wack(nbtsock, packet, rec, src, new_type);
515 * if the registration is for an address that is currently active, then
516 * just update the expiry time of the record and the address
518 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
520 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
525 * we have to do a WACK to see if the current owner is willing
526 * to give up its claim
528 wins_register_wack(nbtsock, packet, rec, src, new_type);
531 case WREPL_TYPE_GROUP:
532 /* this should not be reached as normal groups are handled above */
533 DEBUG(0,("BUG at %s\n",__location__));
534 rcode = NBT_RCODE_ACT;
537 case WREPL_TYPE_SGROUP:
538 /* if the new record isn't also a special group, refuse the registration */
539 if (new_type != WREPL_TYPE_SGROUP) {
540 DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
541 " while a special group is already there\n",
542 nbt_name_string(packet, name), new_type));
543 rcode = NBT_RCODE_ACT;
548 * if the registration is for an address that is currently active, then
549 * just update the expiry time of the record and the address
551 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
553 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
557 rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
562 nbtd_name_registration_reply(nbtsock, packet, src, rcode);
565 static uint32_t ipv4_match_bits(struct in_addr ip1, struct in_addr ip2)
567 uint32_t i, j, match=0;
570 p1 = (uint8_t *)&ip1.s_addr;
571 p2 = (uint8_t *)&ip2.s_addr;
573 for (i=0; i<4; i++) {
574 if (p1[i] != p2[i]) break;
578 if (i==4) return match;
580 for (j=0; j<8; j++) {
581 if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j))))
589 static int nbtd_wins_randomize1Clist_sort(void *p1,/* (const char **) */
590 void *p2,/* (const char **) */
591 struct socket_address *src)
593 const char *a1 = (const char *)*(const char **)p1;
594 const char *a2 = (const char *)*(const char **)p2;
595 uint32_t match_bits1;
596 uint32_t match_bits2;
598 match_bits1 = ipv4_match_bits(interpret_addr2(a1), interpret_addr2(src->addr));
599 match_bits2 = ipv4_match_bits(interpret_addr2(a2), interpret_addr2(src->addr));
601 return match_bits2 - match_bits1;
604 static void nbtd_wins_randomize1Clist(struct loadparm_context *lp_ctx,
605 const char **addresses, struct socket_address *src)
613 for (num_addrs=0; addresses[num_addrs]; num_addrs++) { /* noop */ }
615 if (num_addrs <= 1) return; /* nothing to do */
617 /* first sort the addresses depending on the matching to the client */
618 ldb_qsort(addresses, num_addrs , sizeof(addresses[0]),
619 src, (ldb_qsort_cmp_fn_t)nbtd_wins_randomize1Clist_sort);
621 mask = lp_parm_string(lp_ctx, NULL, "nbtd", "wins_randomize1Clist_mask");
623 mask = "255.255.255.0";
627 * choose a random address to be the first in the response to the client,
628 * preferr the addresses inside the nbtd:wins_randomize1Clist_mask netmask
631 idx = sidx = r % num_addrs;
636 /* if the current one is in the same subnet, use it */
637 same = iface_same_net(addresses[idx], src->addr, mask);
643 /* we need to check for idx == 0, after checking for the same net */
646 * if we haven't found an address in the same subnet, search in ones
647 * which match the client more
651 * it's not "idx = idx % r" but "idx = r % idx"
652 * because in "a % b" b is the allowed range
653 * and b-1 is the maximum possible result, so it must be decreasing
654 * and the above idx == 0 check breaks the while(1) loop.
659 /* note sidx == 0 is also valid here ... */
661 addresses[0] = addresses[sidx];
662 addresses[sidx] = tmp;
668 static void nbtd_winsserver_query(struct loadparm_context *lp_ctx,
669 struct nbt_name_socket *nbtsock,
670 struct nbt_name_packet *packet,
671 struct socket_address *src)
674 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
675 struct nbtd_interface);
676 struct wins_server *winssrv = iface->nbtsrv->winssrv;
677 struct nbt_name *name = &packet->questions[0].name;
678 struct winsdb_record *rec;
679 struct winsdb_record *rec_1b = NULL;
680 const char **addresses;
681 const char **addresses_1b = NULL;
682 uint16_t nb_flags = 0;
684 if (name->type == NBT_NAME_MASTER) {
689 * w2k3 returns the first address of the 0x1B record as first address
692 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
694 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Prepend1BTo1CQueries
695 * Typ: Daten REG_DWORD
696 * Value: 0 = deactivated, 1 = activated
698 if (name->type == NBT_NAME_LOGON &&
699 lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_prepend1Bto1Cqueries", true)) {
700 struct nbt_name name_1b;
703 name_1b.type = NBT_NAME_PDC;
705 status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
706 if (NT_STATUS_IS_OK(status)) {
707 addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
711 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
712 if (!NT_STATUS_IS_OK(status)) {
713 if (!lp_wins_dns_proxy(lp_ctx)) {
717 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
721 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
726 * for group's we always reply with
727 * 255.255.255.255 as address, even if
728 * the record is released or tombstoned
730 if (rec->type == WREPL_TYPE_GROUP) {
731 addresses = str_list_add(NULL, "255.255.255.255");
732 talloc_steal(packet, addresses);
736 nb_flags |= NBT_NM_GROUP;
740 if (rec->state != WREPL_STATE_ACTIVE) {
744 addresses = winsdb_addr_string_list(packet, rec->addresses);
750 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
751 * first 0x1B address as first address
753 if (addresses_1b && addresses_1b[0]) {
754 const char **addresses_1c = addresses;
758 addresses = str_list_add(NULL, addresses_1b[0]);
762 talloc_steal(packet, addresses);
765 for (i=0; addresses_1c[i]; i++) {
766 if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
769 * stop when we already have 25 addresses
771 if (num_addrs >= 25) break;
774 addresses = str_list_add(addresses, addresses_1c[i]);
781 if (rec->type == WREPL_TYPE_SGROUP) {
782 nb_flags |= NBT_NM_GROUP;
784 nb_flags |= (rec->node <<13);
788 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
790 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList
791 * Typ: Daten REG_DWORD
792 * Value: 0 = deactivated, 1 = activated
794 if (name->type == NBT_NAME_LOGON &&
795 lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_randomize1Clist", false)) {
796 nbtd_wins_randomize1Clist(lp_ctx, addresses, src);
800 nbtd_name_query_reply(nbtsock, packet, src, name,
801 0, nb_flags, addresses);
805 nbtd_negative_name_query_reply(nbtsock, packet, src);
811 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
812 struct nbt_name_packet *packet,
813 struct socket_address *src)
816 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
817 struct nbtd_interface);
818 struct wins_server *winssrv = iface->nbtsrv->winssrv;
819 struct nbt_name *name = &packet->questions[0].name;
820 struct winsdb_record *rec;
821 uint32_t modify_flags = 0;
824 if (name->type == NBT_NAME_MASTER) {
828 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
829 if (!NT_STATUS_IS_OK(status)) {
833 if (rec->is_static) {
834 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
837 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
841 if (rec->state != WREPL_STATE_ACTIVE) {
846 * TODO: do we need to check if
847 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
852 * we only allow releases from an owner - other releases are
855 if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
857 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
858 DEBUGADD(4, ("Registered Addresses: \n"));
859 for (i=0; rec->addresses && rec->addresses[i]; i++) {
860 DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
865 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
868 case WREPL_TYPE_UNIQUE:
869 rec->state = WREPL_STATE_RELEASED;
872 case WREPL_TYPE_GROUP:
873 rec->state = WREPL_STATE_RELEASED;
876 case WREPL_TYPE_SGROUP:
877 winsdb_addr_list_remove(rec->addresses, src->addr);
878 /* TODO: do we need to take the ownership here? */
879 if (winsdb_addr_list_length(rec->addresses) == 0) {
880 rec->state = WREPL_STATE_RELEASED;
884 case WREPL_TYPE_MHOMED:
885 winsdb_addr_list_remove(rec->addresses, src->addr);
886 /* TODO: do we need to take the ownership here? */
887 if (winsdb_addr_list_length(rec->addresses) == 0) {
888 rec->state = WREPL_STATE_RELEASED;
893 if (rec->state == WREPL_STATE_RELEASED) {
895 * if we're not the owner, we need to take the owner ship
896 * and make the record tombstone, but expire after
897 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
898 * like for normal tombstone records.
899 * This is to replicate the record directly to the original owner,
900 * where the record is still active
902 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
903 rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
905 rec->state = WREPL_STATE_TOMBSTONE;
906 rec->expire_time= time(NULL) +
907 winssrv->config.tombstone_interval +
908 winssrv->config.tombstone_timeout;
909 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
913 ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
914 if (ret != NBT_RCODE_OK) {
915 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
916 nbt_name_string(rec, rec->name), src->addr, ret));
919 /* we match w2k3 by always giving a positive reply to name releases. */
920 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
927 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
928 struct nbt_name_packet *packet,
929 struct socket_address *src)
931 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
932 struct nbtd_interface);
933 struct wins_server *winssrv = iface->nbtsrv->winssrv;
934 if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
938 switch (packet->operation & NBT_OPCODE) {
939 case NBT_OPCODE_QUERY:
940 nbtd_winsserver_query(iface->nbtsrv->task->lp_ctx, nbtsock, packet, src);
943 case NBT_OPCODE_REGISTER:
944 case NBT_OPCODE_REFRESH:
945 case NBT_OPCODE_REFRESH2:
946 case NBT_OPCODE_MULTI_HOME_REG:
947 nbtd_winsserver_register(nbtsock, packet, src);
950 case NBT_OPCODE_RELEASE:
951 nbtd_winsserver_release(nbtsock, packet, src);
958 startup the WINS server, if configured
960 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
965 if (!lp_wins_support(nbtsrv->task->lp_ctx)) {
966 nbtsrv->winssrv = NULL;
970 nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
971 NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
973 nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl(nbtsrv->task->lp_ctx);
974 nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl(nbtsrv->task->lp_ctx);
975 tmp = lp_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv", "tombstone_interval", 6*24*60*60);
976 nbtsrv->winssrv->config.tombstone_interval = tmp;
977 tmp = lp_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv"," tombstone_timeout", 1*24*60*60);
978 nbtsrv->winssrv->config.tombstone_timeout = tmp;
980 owner = lp_parm_string(nbtsrv->task->lp_ctx, NULL, "winsdb", "local_owner");
983 struct interface *ifaces;
984 load_interfaces(nbtsrv->task, lp_interfaces(nbtsrv->task->lp_ctx), &ifaces);
985 owner = iface_n_ip(ifaces, 0);
988 nbtsrv->winssrv->wins_db = winsdb_connect(nbtsrv->winssrv, nbtsrv->task->lp_ctx,
989 owner, WINSDB_HANDLE_CALLER_NBTD);
990 if (!nbtsrv->winssrv->wins_db) {
991 return NT_STATUS_INTERNAL_DB_ERROR;
994 irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");