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 in_addr ip1, struct in_addr ip2)
565 uint32_t i, j, match=0;
568 p1 = (uint8_t *)&ip1.s_addr;
569 p2 = (uint8_t *)&ip2.s_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(struct loadparm_context *lp_ctx,
603 const char **addresses, struct socket_address *src)
611 for (num_addrs=0; addresses[num_addrs]; num_addrs++) { /* noop */ }
613 if (num_addrs <= 1) return; /* nothing to do */
615 /* first sort the addresses depending on the matching to the client */
616 ldb_qsort(addresses, num_addrs , sizeof(addresses[0]),
617 src, (ldb_qsort_cmp_fn_t)nbtd_wins_randomize1Clist_sort);
619 mask = lp_parm_string(lp_ctx, NULL, "nbtd", "wins_randomize1Clist_mask");
621 mask = "255.255.255.0";
625 * choose a random address to be the first in the response to the client,
626 * preferr the addresses inside the nbtd:wins_randomize1Clist_mask netmask
629 idx = sidx = r % num_addrs;
634 /* if the current one is in the same subnet, use it */
635 same = iface_same_net(addresses[idx], src->addr, mask);
641 /* we need to check for idx == 0, after checking for the same net */
644 * if we haven't found an address in the same subnet, search in ones
645 * which match the client more
649 * it's not "idx = idx % r" but "idx = r % idx"
650 * because in "a % b" b is the allowed range
651 * and b-1 is the maximum possible result, so it must be decreasing
652 * and the above idx == 0 check breaks the while(1) loop.
657 /* note sidx == 0 is also valid here ... */
659 addresses[0] = addresses[sidx];
660 addresses[sidx] = tmp;
666 static void nbtd_winsserver_query(struct loadparm_context *lp_ctx,
667 struct nbt_name_socket *nbtsock,
668 struct nbt_name_packet *packet,
669 struct socket_address *src)
672 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
673 struct nbtd_interface);
674 struct wins_server *winssrv = iface->nbtsrv->winssrv;
675 struct nbt_name *name = &packet->questions[0].name;
676 struct winsdb_record *rec;
677 struct winsdb_record *rec_1b = NULL;
678 const char **addresses;
679 const char **addresses_1b = NULL;
680 uint16_t nb_flags = 0;
682 if (name->type == NBT_NAME_MASTER) {
687 * w2k3 returns the first address of the 0x1B record as first address
690 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
692 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Prepend1BTo1CQueries
693 * Typ: Daten REG_DWORD
694 * Value: 0 = deactivated, 1 = activated
696 if (name->type == NBT_NAME_LOGON &&
697 lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_prepend1Bto1Cqueries", true)) {
698 struct nbt_name name_1b;
701 name_1b.type = NBT_NAME_PDC;
703 status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
704 if (NT_STATUS_IS_OK(status)) {
705 addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
709 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
710 if (!NT_STATUS_IS_OK(status)) {
711 if (!lp_wins_dns_proxy(lp_ctx)) {
715 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
719 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
724 * for group's we always reply with
725 * 255.255.255.255 as address, even if
726 * the record is released or tombstoned
728 if (rec->type == WREPL_TYPE_GROUP) {
729 addresses = str_list_add(NULL, "255.255.255.255");
730 talloc_steal(packet, addresses);
734 nb_flags |= NBT_NM_GROUP;
738 if (rec->state != WREPL_STATE_ACTIVE) {
742 addresses = winsdb_addr_string_list(packet, rec->addresses);
748 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
749 * first 0x1B address as first address
751 if (addresses_1b && addresses_1b[0]) {
752 const char **addresses_1c = addresses;
756 addresses = str_list_add(NULL, addresses_1b[0]);
760 talloc_steal(packet, addresses);
763 for (i=0; addresses_1c[i]; i++) {
764 if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
767 * stop when we already have 25 addresses
769 if (num_addrs >= 25) break;
772 addresses = str_list_add(addresses, addresses_1c[i]);
779 if (rec->type == WREPL_TYPE_SGROUP) {
780 nb_flags |= NBT_NM_GROUP;
782 nb_flags |= (rec->node <<13);
786 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
788 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList
789 * Typ: Daten REG_DWORD
790 * Value: 0 = deactivated, 1 = activated
792 if (name->type == NBT_NAME_LOGON &&
793 lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_randomize1Clist", false)) {
794 nbtd_wins_randomize1Clist(lp_ctx, addresses, src);
798 nbtd_name_query_reply(nbtsock, packet, src, name,
799 0, nb_flags, addresses);
803 nbtd_negative_name_query_reply(nbtsock, packet, src);
809 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
810 struct nbt_name_packet *packet,
811 struct socket_address *src)
814 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
815 struct nbtd_interface);
816 struct wins_server *winssrv = iface->nbtsrv->winssrv;
817 struct nbt_name *name = &packet->questions[0].name;
818 struct winsdb_record *rec;
819 uint32_t modify_flags = 0;
822 if (name->type == NBT_NAME_MASTER) {
826 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
827 if (!NT_STATUS_IS_OK(status)) {
831 if (rec->is_static) {
832 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
835 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
839 if (rec->state != WREPL_STATE_ACTIVE) {
844 * TODO: do we need to check if
845 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
850 * we only allow releases from an owner - other releases are
853 if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
855 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
856 DEBUGADD(4, ("Registered Addresses: \n"));
857 for (i=0; rec->addresses && rec->addresses[i]; i++) {
858 DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
863 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
866 case WREPL_TYPE_UNIQUE:
867 rec->state = WREPL_STATE_RELEASED;
870 case WREPL_TYPE_GROUP:
871 rec->state = WREPL_STATE_RELEASED;
874 case WREPL_TYPE_SGROUP:
875 winsdb_addr_list_remove(rec->addresses, src->addr);
876 /* TODO: do we need to take the ownership here? */
877 if (winsdb_addr_list_length(rec->addresses) == 0) {
878 rec->state = WREPL_STATE_RELEASED;
882 case WREPL_TYPE_MHOMED:
883 winsdb_addr_list_remove(rec->addresses, src->addr);
884 /* TODO: do we need to take the ownership here? */
885 if (winsdb_addr_list_length(rec->addresses) == 0) {
886 rec->state = WREPL_STATE_RELEASED;
891 if (rec->state == WREPL_STATE_RELEASED) {
893 * if we're not the owner, we need to take the owner ship
894 * and make the record tombstone, but expire after
895 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
896 * like for normal tombstone records.
897 * This is to replicate the record directly to the original owner,
898 * where the record is still active
900 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
901 rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
903 rec->state = WREPL_STATE_TOMBSTONE;
904 rec->expire_time= time(NULL) +
905 winssrv->config.tombstone_interval +
906 winssrv->config.tombstone_timeout;
907 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
911 ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
912 if (ret != NBT_RCODE_OK) {
913 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
914 nbt_name_string(rec, rec->name), src->addr, ret));
917 /* we match w2k3 by always giving a positive reply to name releases. */
918 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
925 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
926 struct nbt_name_packet *packet,
927 struct socket_address *src)
929 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
930 struct nbtd_interface);
931 struct wins_server *winssrv = iface->nbtsrv->winssrv;
932 if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
936 switch (packet->operation & NBT_OPCODE) {
937 case NBT_OPCODE_QUERY:
938 nbtd_winsserver_query(iface->nbtsrv->task->lp_ctx, nbtsock, packet, src);
941 case NBT_OPCODE_REGISTER:
942 case NBT_OPCODE_REFRESH:
943 case NBT_OPCODE_REFRESH2:
944 case NBT_OPCODE_MULTI_HOME_REG:
945 nbtd_winsserver_register(nbtsock, packet, src);
948 case NBT_OPCODE_RELEASE:
949 nbtd_winsserver_release(nbtsock, packet, src);
956 startup the WINS server, if configured
958 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
962 if (!lp_wins_support(nbtsrv->task->lp_ctx)) {
963 nbtsrv->winssrv = NULL;
967 nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
968 NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
970 nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl(nbtsrv->task->lp_ctx);
971 nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl(nbtsrv->task->lp_ctx);
972 tmp = lp_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv", "tombstone_interval", 6*24*60*60);
973 nbtsrv->winssrv->config.tombstone_interval = tmp;
974 tmp = lp_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv"," tombstone_timeout", 1*24*60*60);
975 nbtsrv->winssrv->config.tombstone_timeout = tmp;
977 nbtsrv->winssrv->wins_db = winsdb_connect(nbtsrv->winssrv, nbtsrv->task->lp_ctx,
978 WINSDB_HANDLE_CALLER_NBTD);
979 if (!nbtsrv->winssrv->wins_db) {
980 return NT_STATUS_INTERNAL_DB_ERROR;
983 irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");