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 "lib/util/dlinklist.h"
25 #include "nbt_server/nbt_server.h"
26 #include "nbt_server/wins/winsdb.h"
27 #include "nbt_server/wins/winsserver.h"
28 #include "librpc/gen_ndr/ndr_nbt.h"
29 #include "system/time.h"
30 #include "libcli/composite/composite.h"
31 #include "smbd/service_task.h"
32 #include "system/network.h"
33 #include "lib/socket/socket.h"
34 #include "lib/socket/netif.h"
35 #include "lib/ldb/include/ldb.h"
36 #include "param/param.h"
37 #include "libcli/resolve/resolve.h"
40 work out the ttl we will use given a client requested ttl
42 uint32_t wins_server_ttl(struct wins_server *winssrv, uint32_t ttl)
44 ttl = MIN(ttl, winssrv->config.max_renew_interval);
45 ttl = MAX(ttl, winssrv->config.min_renew_interval);
49 static enum wrepl_name_type wrepl_type(uint16_t nb_flags, struct nbt_name *name, bool mhomed)
51 /* this copes with the nasty hack that is the type 0x1c name */
52 if (name->type == NBT_NAME_LOGON) {
53 return WREPL_TYPE_SGROUP;
55 if (nb_flags & NBT_NM_GROUP) {
56 return WREPL_TYPE_GROUP;
59 return WREPL_TYPE_MHOMED;
61 return WREPL_TYPE_UNIQUE;
65 register a new name with WINS
67 static uint8_t wins_register_new(struct nbt_name_socket *nbtsock,
68 struct nbt_name_packet *packet,
69 const struct socket_address *src,
70 enum wrepl_name_type type)
72 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
73 struct nbtd_interface);
74 struct wins_server *winssrv = iface->nbtsrv->winssrv;
75 struct nbt_name *name = &packet->questions[0].name;
76 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
77 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
78 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
79 struct winsdb_record rec;
80 enum wrepl_name_node node;
82 #define WREPL_NODE_NBT_FLAGS(nb_flags) \
83 ((nb_flags & NBT_NM_OWNER_TYPE)>>13)
85 node = WREPL_NODE_NBT_FLAGS(nb_flags);
89 rec.state = WREPL_STATE_ACTIVE;
91 rec.is_static = false;
92 rec.expire_time = time(NULL) + ttl;
93 rec.version = 0; /* will be allocated later */
94 rec.wins_owner = NULL; /* will be set later */
95 rec.registered_by = src->addr;
96 rec.addresses = winsdb_addr_list_make(packet);
97 if (rec.addresses == NULL) return NBT_RCODE_SVR;
99 rec.addresses = winsdb_addr_list_add(winssrv->wins_db,
102 winssrv->wins_db->local_owner,
105 if (rec.addresses == NULL) return NBT_RCODE_SVR;
107 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
108 nbt_name_string(packet, name), rec.addresses[0]->address));
110 return winsdb_add(winssrv->wins_db, &rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
115 update the ttl on an existing record
117 static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock,
118 struct nbt_name_packet *packet,
119 struct winsdb_record *rec,
120 struct winsdb_addr *winsdb_addr,
121 const struct socket_address *src)
123 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
124 struct nbtd_interface);
125 struct wins_server *winssrv = iface->nbtsrv->winssrv;
126 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
127 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
128 uint32_t modify_flags = 0;
130 rec->expire_time = time(NULL) + ttl;
131 rec->registered_by = src->addr;
134 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
136 winsdb_addr->address,
137 winssrv->wins_db->local_owner,
140 if (rec->addresses == NULL) return NBT_RCODE_SVR;
143 if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) {
144 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
147 DEBUG(5,("WINS: refreshed registration of %s at %s\n",
148 nbt_name_string(packet, rec->name), address));
150 return winsdb_modify(winssrv->wins_db, rec, modify_flags);
156 static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
157 struct nbt_name_packet *packet,
158 struct winsdb_record *rec,
160 const struct socket_address *src)
162 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
163 struct nbtd_interface);
164 struct wins_server *winssrv = iface->nbtsrv->winssrv;
165 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
167 rec->expire_time = time(NULL) + ttl;
168 rec->registered_by = src->addr;
170 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
173 winssrv->wins_db->local_owner,
176 if (rec->addresses == NULL) return NBT_RCODE_SVR;
178 DEBUG(5,("WINS: sgroup merge of %s at %s\n",
179 nbt_name_string(packet, rec->name), address));
181 return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
184 struct nbtd_wins_wack_state {
185 struct nbtd_wins_wack_state *prev, *next;
186 struct wins_server *winssrv;
187 struct nbt_name_socket *nbtsock;
188 struct nbtd_interface *iface;
189 struct nbt_name_packet *request_packet;
190 struct winsdb_record *rec;
191 struct socket_address *src;
192 const char *reg_address;
193 enum wrepl_name_type new_type;
194 struct wins_challenge_io io;
198 static int nbtd_wins_wack_state_destructor(struct nbtd_wins_wack_state *s)
200 DLIST_REMOVE(s->iface->wack_queue, s);
204 static bool wins_check_wack_queue(struct nbtd_interface *iface,
205 struct nbt_name_packet *packet,
206 struct socket_address *src)
208 struct nbtd_wins_wack_state *s;
210 for (s= iface->wack_queue; s; s = s->next) {
211 if (packet->name_trn_id != s->request_packet->name_trn_id) {
214 if (packet->operation != s->request_packet->operation) {
217 if (src->port != s->src->port) {
220 if (strcmp(src->addr, s->src->addr) != 0) {
231 deny a registration request
233 static void wins_wack_deny(struct nbtd_wins_wack_state *s)
235 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
236 s->src, NBT_RCODE_ACT);
237 DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
238 nbt_name_string(s, s->rec->name), s->src->addr, s->src->port));
243 allow a registration request
245 static void wins_wack_allow(struct nbtd_wins_wack_state *s)
248 uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
249 struct winsdb_record *rec = s->rec, *rec2;
252 status = winsdb_lookup(s->winssrv->wins_db, rec->name, s, &rec2);
253 if (!NT_STATUS_IS_OK(status) ||
254 rec2->version != rec->version ||
255 strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
256 DEBUG(5,("WINS: record %s changed during WACK - failing registration\n",
257 nbt_name_string(s, rec->name)));
263 * if the old name owner doesn't hold the name anymore
264 * handle the request as new registration for the new name owner
266 if (!NT_STATUS_IS_OK(s->status)) {
269 winsdb_delete(s->winssrv->wins_db, rec);
270 rcode = wins_register_new(s->nbtsock, s->request_packet, s->src, s->new_type);
271 if (rcode != NBT_RCODE_OK) {
272 DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
273 nbt_name_string(s, rec->name)));
280 rec->expire_time = time(NULL) + ttl;
281 rec->registered_by = s->src->addr;
284 * now remove all addresses that're the client doesn't hold anymore
285 * and update the time stamp and owner for the ownes that are still there
287 for (i=0; rec->addresses[i]; i++) {
289 for (j=0; j < s->io.out.num_addresses; j++) {
290 if (strcmp(rec->addresses[i]->address, s->io.out.addresses[j]) != 0) continue;
296 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
299 s->winssrv->wins_db->local_owner,
302 if (rec->addresses == NULL) goto failed;
306 winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
309 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
312 s->winssrv->wins_db->local_owner,
315 if (rec->addresses == NULL) goto failed;
317 /* if we have more than one address, this becomes implicit a MHOMED record */
318 if (winsdb_addr_list_length(rec->addresses) > 1) {
319 rec->type = WREPL_TYPE_MHOMED;
322 winsdb_modify(s->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
324 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
325 nbt_name_string(s, rec->name), s->reg_address));
328 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
329 s->src, NBT_RCODE_OK);
335 called when a name query to a current owner completes
337 static void wack_wins_challenge_handler(struct composite_context *c_req)
339 struct nbtd_wins_wack_state *s = talloc_get_type(c_req->async.private_data,
340 struct nbtd_wins_wack_state);
344 s->status = wins_challenge_recv(c_req, s, &s->io);
347 * if the owner denies it holds the name, then allow
350 if (!NT_STATUS_IS_OK(s->status)) {
355 if (s->new_type == WREPL_TYPE_GROUP || s->new_type == WREPL_TYPE_SGROUP) {
356 DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
357 nbt_name_string(s, s->rec->name), s->new_type, s->rec->type));
363 * if the owner still wants the name and doesn't reply
364 * with the address trying to be registered, then deny
368 for (i=0; i < s->io.out.num_addresses; i++) {
369 if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
385 a client has asked to register a unique name that someone else owns. We
386 need to ask each of the current owners if they still want it. If they do
387 then reject the registration, otherwise allow it
389 static void wins_register_wack(struct nbt_name_socket *nbtsock,
390 struct nbt_name_packet *packet,
391 struct winsdb_record *rec,
392 struct socket_address *src,
393 enum wrepl_name_type new_type)
395 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
396 struct nbtd_interface);
397 struct wins_server *winssrv = iface->nbtsrv->winssrv;
398 struct nbtd_wins_wack_state *s;
399 struct composite_context *c_req;
402 s = talloc_zero(nbtsock, struct nbtd_wins_wack_state);
403 if (s == NULL) goto failed;
405 /* package up the state variables for this wack request */
406 s->winssrv = winssrv;
407 s->nbtsock = nbtsock;
409 s->request_packet = talloc_steal(s, packet);
410 s->rec = talloc_steal(s, rec);
411 s->reg_address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
412 s->new_type = new_type;
414 if (talloc_reference(s, src) == NULL) goto failed;
416 s->io.in.nbtd_server = iface->nbtsrv;
417 s->io.in.nbt_port = lp_nbt_port(iface->nbtsrv->task->lp_ctx);
418 s->io.in.event_ctx = iface->nbtsrv->task->event_ctx;
419 s->io.in.name = rec->name;
420 s->io.in.num_addresses = winsdb_addr_list_length(rec->addresses);
421 s->io.in.addresses = winsdb_addr_string_list(s, rec->addresses);
422 if (s->io.in.addresses == NULL) goto failed;
424 DLIST_ADD_END(iface->wack_queue, s, struct nbtd_wins_wack_state *);
426 talloc_set_destructor(s, nbtd_wins_wack_state_destructor);
429 * send a WACK to the client, specifying the maximum time it could
430 * take to check with the owner, plus some slack
432 ttl = 5 + 4 * winsdb_addr_list_length(rec->addresses);
433 nbtd_wack_reply(nbtsock, packet, src, ttl);
436 * send the challenge to the old addresses
438 c_req = wins_challenge_send(s, &s->io);
439 if (c_req == NULL) goto failed;
441 c_req->async.fn = wack_wins_challenge_handler;
442 c_req->async.private_data = s;
447 nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR);
453 static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
454 struct nbt_name_packet *packet,
455 struct socket_address *src)
458 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
459 struct nbtd_interface);
460 struct wins_server *winssrv = iface->nbtsrv->winssrv;
461 struct nbt_name *name = &packet->questions[0].name;
462 struct winsdb_record *rec;
463 uint8_t rcode = NBT_RCODE_OK;
464 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
465 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
466 bool mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
467 enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
468 struct winsdb_addr *winsdb_addr = NULL;
469 bool duplicate_packet;
472 * as a special case, the local master browser name is always accepted
473 * for registration, but never stored, but w2k3 stores it if it's registered
474 * as a group name, (but a query for the 0x1D name still returns not found!)
476 if (name->type == NBT_NAME_MASTER && !(nb_flags & NBT_NM_GROUP)) {
477 rcode = NBT_RCODE_OK;
481 /* w2k3 refuses 0x1B names with marked as group */
482 if (name->type == NBT_NAME_PDC && (nb_flags & NBT_NM_GROUP)) {
483 rcode = NBT_RCODE_RFS;
487 /* w2k3 refuses 0x1C names with out marked as group */
488 if (name->type == NBT_NAME_LOGON && !(nb_flags & NBT_NM_GROUP)) {
489 rcode = NBT_RCODE_RFS;
493 /* w2k3 refuses 0x1E names with out marked as group */
494 if (name->type == NBT_NAME_BROWSER && !(nb_flags & NBT_NM_GROUP)) {
495 rcode = NBT_RCODE_RFS;
499 duplicate_packet = wins_check_wack_queue(iface, packet, src);
500 if (duplicate_packet) {
501 /* just ignore the packet */
502 DEBUG(5,("Ignoring duplicate packet while WACK is pending from %s:%d\n",
503 src->addr, src->port));
507 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
508 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
509 rcode = wins_register_new(nbtsock, packet, src, new_type);
511 } else if (!NT_STATUS_IS_OK(status)) {
512 rcode = NBT_RCODE_SVR;
514 } else if (rec->is_static) {
515 if (rec->type == WREPL_TYPE_GROUP || rec->type == WREPL_TYPE_SGROUP) {
516 rcode = NBT_RCODE_OK;
519 rcode = NBT_RCODE_ACT;
523 if (rec->type == WREPL_TYPE_GROUP) {
524 if (new_type != WREPL_TYPE_GROUP) {
525 DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
526 " while a normal group is already there\n",
527 nbt_name_string(packet, name), new_type));
528 rcode = NBT_RCODE_ACT;
532 if (rec->state == WREPL_STATE_ACTIVE) {
533 /* TODO: is this correct? */
534 rcode = wins_update_ttl(nbtsock, packet, rec, NULL, src);
538 /* TODO: is this correct? */
539 winsdb_delete(winssrv->wins_db, rec);
540 rcode = wins_register_new(nbtsock, packet, src, new_type);
544 if (rec->state != WREPL_STATE_ACTIVE) {
545 winsdb_delete(winssrv->wins_db, rec);
546 rcode = wins_register_new(nbtsock, packet, src, new_type);
551 case WREPL_TYPE_UNIQUE:
552 case WREPL_TYPE_MHOMED:
554 * if its an active unique name, and the registration is for a group, then
555 * see if the unique name owner still wants the name
556 * TODO: is this correct?
558 if (new_type == WREPL_TYPE_GROUP || new_type == WREPL_TYPE_GROUP) {
559 wins_register_wack(nbtsock, packet, rec, src, new_type);
564 * if the registration is for an address that is currently active, then
565 * just update the expiry time of the record and the address
567 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
569 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
574 * we have to do a WACK to see if the current owner is willing
575 * to give up its claim
577 wins_register_wack(nbtsock, packet, rec, src, new_type);
580 case WREPL_TYPE_GROUP:
581 /* this should not be reached as normal groups are handled above */
582 DEBUG(0,("BUG at %s\n",__location__));
583 rcode = NBT_RCODE_ACT;
586 case WREPL_TYPE_SGROUP:
587 /* if the new record isn't also a special group, refuse the registration */
588 if (new_type != WREPL_TYPE_SGROUP) {
589 DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
590 " while a special group is already there\n",
591 nbt_name_string(packet, name), new_type));
592 rcode = NBT_RCODE_ACT;
597 * if the registration is for an address that is currently active, then
598 * just update the expiry time of the record and the address
600 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
602 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
606 rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
611 nbtd_name_registration_reply(nbtsock, packet, src, rcode);
614 static uint32_t ipv4_match_bits(struct in_addr ip1, struct in_addr ip2)
616 uint32_t i, j, match=0;
619 p1 = (uint8_t *)&ip1.s_addr;
620 p2 = (uint8_t *)&ip2.s_addr;
622 for (i=0; i<4; i++) {
623 if (p1[i] != p2[i]) break;
627 if (i==4) return match;
629 for (j=0; j<8; j++) {
630 if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j))))
638 static int nbtd_wins_randomize1Clist_sort(void *p1,/* (const char **) */
639 void *p2,/* (const char **) */
640 struct socket_address *src)
642 const char *a1 = (const char *)*(const char **)p1;
643 const char *a2 = (const char *)*(const char **)p2;
644 uint32_t match_bits1;
645 uint32_t match_bits2;
647 match_bits1 = ipv4_match_bits(interpret_addr2(a1), interpret_addr2(src->addr));
648 match_bits2 = ipv4_match_bits(interpret_addr2(a2), interpret_addr2(src->addr));
650 return match_bits2 - match_bits1;
653 static void nbtd_wins_randomize1Clist(struct loadparm_context *lp_ctx,
654 const char **addresses, struct socket_address *src)
662 for (num_addrs=0; addresses[num_addrs]; num_addrs++) { /* noop */ }
664 if (num_addrs <= 1) return; /* nothing to do */
666 /* first sort the addresses depending on the matching to the client */
667 ldb_qsort(addresses, num_addrs , sizeof(addresses[0]),
668 src, (ldb_qsort_cmp_fn_t)nbtd_wins_randomize1Clist_sort);
670 mask = lp_parm_string(lp_ctx, NULL, "nbtd", "wins_randomize1Clist_mask");
672 mask = "255.255.255.0";
676 * choose a random address to be the first in the response to the client,
677 * preferr the addresses inside the nbtd:wins_randomize1Clist_mask netmask
680 idx = sidx = r % num_addrs;
685 /* if the current one is in the same subnet, use it */
686 same = iface_same_net(addresses[idx], src->addr, mask);
692 /* we need to check for idx == 0, after checking for the same net */
695 * if we haven't found an address in the same subnet, search in ones
696 * which match the client more
700 * it's not "idx = idx % r" but "idx = r % idx"
701 * because in "a % b" b is the allowed range
702 * and b-1 is the maximum possible result, so it must be decreasing
703 * and the above idx == 0 check breaks the while(1) loop.
708 /* note sidx == 0 is also valid here ... */
710 addresses[0] = addresses[sidx];
711 addresses[sidx] = tmp;
717 static void nbtd_winsserver_query(struct loadparm_context *lp_ctx,
718 struct nbt_name_socket *nbtsock,
719 struct nbt_name_packet *packet,
720 struct socket_address *src)
723 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
724 struct nbtd_interface);
725 struct wins_server *winssrv = iface->nbtsrv->winssrv;
726 struct nbt_name *name = &packet->questions[0].name;
727 struct winsdb_record *rec;
728 struct winsdb_record *rec_1b = NULL;
729 const char **addresses;
730 const char **addresses_1b = NULL;
731 uint16_t nb_flags = 0;
733 if (name->type == NBT_NAME_MASTER) {
738 * w2k3 returns the first address of the 0x1B record as first address
741 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
743 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Prepend1BTo1CQueries
744 * Typ: Daten REG_DWORD
745 * Value: 0 = deactivated, 1 = activated
747 if (name->type == NBT_NAME_LOGON &&
748 lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_prepend1Bto1Cqueries", true)) {
749 struct nbt_name name_1b;
752 name_1b.type = NBT_NAME_PDC;
754 status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
755 if (NT_STATUS_IS_OK(status)) {
756 addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
760 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
761 if (!NT_STATUS_IS_OK(status)) {
762 if (!lp_wins_dns_proxy(lp_ctx)) {
766 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
770 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
775 * for group's we always reply with
776 * 255.255.255.255 as address, even if
777 * the record is released or tombstoned
779 if (rec->type == WREPL_TYPE_GROUP) {
780 addresses = str_list_add(NULL, "255.255.255.255");
781 talloc_steal(packet, addresses);
785 nb_flags |= NBT_NM_GROUP;
789 if (rec->state != WREPL_STATE_ACTIVE) {
793 addresses = winsdb_addr_string_list(packet, rec->addresses);
799 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
800 * first 0x1B address as first address
802 if (addresses_1b && addresses_1b[0]) {
803 const char **addresses_1c = addresses;
807 addresses = str_list_add(NULL, addresses_1b[0]);
811 talloc_steal(packet, addresses);
814 for (i=0; addresses_1c[i]; i++) {
815 if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
818 * stop when we already have 25 addresses
820 if (num_addrs >= 25) break;
823 addresses = str_list_add(addresses, addresses_1c[i]);
830 if (rec->type == WREPL_TYPE_SGROUP) {
831 nb_flags |= NBT_NM_GROUP;
833 nb_flags |= (rec->node <<13);
837 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
839 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList
840 * Typ: Daten REG_DWORD
841 * Value: 0 = deactivated, 1 = activated
843 if (name->type == NBT_NAME_LOGON &&
844 lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_randomize1Clist", false)) {
845 nbtd_wins_randomize1Clist(lp_ctx, addresses, src);
849 nbtd_name_query_reply(nbtsock, packet, src, name,
850 0, nb_flags, addresses);
854 nbtd_negative_name_query_reply(nbtsock, packet, src);
860 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
861 struct nbt_name_packet *packet,
862 struct socket_address *src)
865 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
866 struct nbtd_interface);
867 struct wins_server *winssrv = iface->nbtsrv->winssrv;
868 struct nbt_name *name = &packet->questions[0].name;
869 struct winsdb_record *rec;
870 uint32_t modify_flags = 0;
873 if (name->type == NBT_NAME_MASTER) {
877 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
878 if (!NT_STATUS_IS_OK(status)) {
882 if (rec->is_static) {
883 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
886 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
890 if (rec->state != WREPL_STATE_ACTIVE) {
895 * TODO: do we need to check if
896 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
901 * we only allow releases from an owner - other releases are
904 if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
906 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
907 DEBUGADD(4, ("Registered Addresses: \n"));
908 for (i=0; rec->addresses && rec->addresses[i]; i++) {
909 DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
914 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
917 case WREPL_TYPE_UNIQUE:
918 rec->state = WREPL_STATE_RELEASED;
921 case WREPL_TYPE_GROUP:
922 rec->state = WREPL_STATE_RELEASED;
925 case WREPL_TYPE_SGROUP:
926 winsdb_addr_list_remove(rec->addresses, src->addr);
927 /* TODO: do we need to take the ownership here? */
928 if (winsdb_addr_list_length(rec->addresses) == 0) {
929 rec->state = WREPL_STATE_RELEASED;
933 case WREPL_TYPE_MHOMED:
934 winsdb_addr_list_remove(rec->addresses, src->addr);
935 /* TODO: do we need to take the ownership here? */
936 if (winsdb_addr_list_length(rec->addresses) == 0) {
937 rec->state = WREPL_STATE_RELEASED;
942 if (rec->state == WREPL_STATE_ACTIVE) {
944 * If the record is still active, we need to update the
947 * if we're not the owner, we need to take the ownership.
949 rec->expire_time= time(NULL) + winssrv->config.max_renew_interval;
950 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) != 0) {
951 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
953 if (lp_parm_bool(iface->nbtsrv->task->lp_ctx, NULL, "wreplsrv", "propagate name releases", false)) {
955 * We have an option to propagate every name release,
956 * this is off by default to match windows servers
958 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
960 } else if (rec->state == WREPL_STATE_RELEASED) {
962 * if we're not the owner, we need to take the owner ship
963 * and make the record tombstone, but expire after
964 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
965 * like for normal tombstone records.
966 * This is to replicate the record directly to the original owner,
967 * where the record is still active
969 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
970 rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
972 rec->state = WREPL_STATE_TOMBSTONE;
973 rec->expire_time= time(NULL) +
974 winssrv->config.tombstone_interval +
975 winssrv->config.tombstone_timeout;
976 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
980 ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
981 if (ret != NBT_RCODE_OK) {
982 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
983 nbt_name_string(rec, rec->name), src->addr, ret));
986 /* we match w2k3 by always giving a positive reply to name releases. */
987 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
994 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
995 struct nbt_name_packet *packet,
996 struct socket_address *src)
998 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
999 struct nbtd_interface);
1000 struct wins_server *winssrv = iface->nbtsrv->winssrv;
1001 if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
1005 switch (packet->operation & NBT_OPCODE) {
1006 case NBT_OPCODE_QUERY:
1007 nbtd_winsserver_query(iface->nbtsrv->task->lp_ctx, nbtsock, packet, src);
1010 case NBT_OPCODE_REGISTER:
1011 case NBT_OPCODE_REFRESH:
1012 case NBT_OPCODE_REFRESH2:
1013 case NBT_OPCODE_MULTI_HOME_REG:
1014 nbtd_winsserver_register(nbtsock, packet, src);
1017 case NBT_OPCODE_RELEASE:
1018 nbtd_winsserver_release(nbtsock, packet, src);
1025 startup the WINS server, if configured
1027 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
1032 if (!lp_wins_support(nbtsrv->task->lp_ctx)) {
1033 nbtsrv->winssrv = NULL;
1034 return NT_STATUS_OK;
1037 nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
1038 NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
1040 nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl(nbtsrv->task->lp_ctx);
1041 nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl(nbtsrv->task->lp_ctx);
1042 tmp = lp_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv", "tombstone_interval", 6*24*60*60);
1043 nbtsrv->winssrv->config.tombstone_interval = tmp;
1044 tmp = lp_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv"," tombstone_timeout", 1*24*60*60);
1045 nbtsrv->winssrv->config.tombstone_timeout = tmp;
1047 owner = lp_parm_string(nbtsrv->task->lp_ctx, NULL, "winsdb", "local_owner");
1049 if (owner == NULL) {
1050 struct interface *ifaces;
1051 load_interfaces(nbtsrv->task, lp_interfaces(nbtsrv->task->lp_ctx), &ifaces);
1052 owner = iface_n_ip(ifaces, 0);
1055 nbtsrv->winssrv->wins_db = winsdb_connect(nbtsrv->winssrv, nbtsrv->task->event_ctx,
1056 nbtsrv->task->lp_ctx,
1057 owner, WINSDB_HANDLE_CALLER_NBTD);
1058 if (!nbtsrv->winssrv->wins_db) {
1059 return NT_STATUS_INTERNAL_DB_ERROR;
1062 irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");
1064 return NT_STATUS_OK;