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"
37 work out the ttl we will use given a client requested ttl
39 uint32_t wins_server_ttl(struct wins_server *winssrv, uint32_t ttl)
41 ttl = MIN(ttl, winssrv->config.max_renew_interval);
42 ttl = MAX(ttl, winssrv->config.min_renew_interval);
46 static enum wrepl_name_type wrepl_type(uint16_t nb_flags, struct nbt_name *name, BOOL mhomed)
48 /* this copes with the nasty hack that is the type 0x1c name */
49 if (name->type == NBT_NAME_LOGON) {
50 return WREPL_TYPE_SGROUP;
52 if (nb_flags & NBT_NM_GROUP) {
53 return WREPL_TYPE_GROUP;
56 return WREPL_TYPE_MHOMED;
58 return WREPL_TYPE_UNIQUE;
62 register a new name with WINS
64 static uint8_t wins_register_new(struct nbt_name_socket *nbtsock,
65 struct nbt_name_packet *packet,
66 const struct socket_address *src,
67 enum wrepl_name_type type)
69 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
70 struct nbtd_interface);
71 struct wins_server *winssrv = iface->nbtsrv->winssrv;
72 struct nbt_name *name = &packet->questions[0].name;
73 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
74 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
75 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
76 struct winsdb_record rec;
77 enum wrepl_name_node node;
79 #define WREPL_NODE_NBT_FLAGS(nb_flags) \
80 ((nb_flags & NBT_NM_OWNER_TYPE)>>13)
82 node = WREPL_NODE_NBT_FLAGS(nb_flags);
86 rec.state = WREPL_STATE_ACTIVE;
88 rec.is_static = False;
89 rec.expire_time = time(NULL) + ttl;
90 rec.version = 0; /* will be allocated later */
91 rec.wins_owner = NULL; /* will be set later */
92 rec.registered_by = src->addr;
93 rec.addresses = winsdb_addr_list_make(packet);
94 if (rec.addresses == NULL) return NBT_RCODE_SVR;
96 rec.addresses = winsdb_addr_list_add(winssrv->wins_db,
99 winssrv->wins_db->local_owner,
102 if (rec.addresses == NULL) return NBT_RCODE_SVR;
104 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
105 nbt_name_string(packet, name), rec.addresses[0]->address));
107 return winsdb_add(winssrv->wins_db, &rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
112 update the ttl on an existing record
114 static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock,
115 struct nbt_name_packet *packet,
116 struct winsdb_record *rec,
117 struct winsdb_addr *winsdb_addr,
118 const struct socket_address *src)
120 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
121 struct nbtd_interface);
122 struct wins_server *winssrv = iface->nbtsrv->winssrv;
123 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
124 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
125 uint32_t modify_flags = 0;
127 rec->expire_time = time(NULL) + ttl;
128 rec->registered_by = src->addr;
131 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
133 winsdb_addr->address,
134 winssrv->wins_db->local_owner,
137 if (rec->addresses == NULL) return NBT_RCODE_SVR;
140 if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) {
141 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
144 DEBUG(5,("WINS: refreshed registration of %s at %s\n",
145 nbt_name_string(packet, rec->name), address));
147 return winsdb_modify(winssrv->wins_db, rec, modify_flags);
153 static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
154 struct nbt_name_packet *packet,
155 struct winsdb_record *rec,
157 const struct socket_address *src)
159 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
160 struct nbtd_interface);
161 struct wins_server *winssrv = iface->nbtsrv->winssrv;
162 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
164 rec->expire_time = time(NULL) + ttl;
165 rec->registered_by = src->addr;
167 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
170 winssrv->wins_db->local_owner,
173 if (rec->addresses == NULL) return NBT_RCODE_SVR;
175 DEBUG(5,("WINS: sgroup merge of %s at %s\n",
176 nbt_name_string(packet, rec->name), address));
178 return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
182 struct wins_server *winssrv;
183 struct nbt_name_socket *nbtsock;
184 struct nbt_name_packet *request_packet;
185 struct winsdb_record *rec;
186 struct socket_address *src;
187 const char *reg_address;
188 enum wrepl_name_type new_type;
189 struct wins_challenge_io io;
194 deny a registration request
196 static void wins_wack_deny(struct wack_state *s)
198 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
199 s->src, NBT_RCODE_ACT);
200 DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
201 nbt_name_string(s, s->rec->name), s->src->addr, s->src->port));
206 allow a registration request
208 static void wins_wack_allow(struct wack_state *s)
211 uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
212 struct winsdb_record *rec = s->rec, *rec2;
215 status = winsdb_lookup(s->winssrv->wins_db, rec->name, s, &rec2);
216 if (!NT_STATUS_IS_OK(status) ||
217 rec2->version != rec->version ||
218 strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
219 DEBUG(5,("WINS: record %s changed during WACK - failing registration\n",
220 nbt_name_string(s, rec->name)));
226 * if the old name owner doesn't hold the name anymore
227 * handle the request as new registration for the new name owner
229 if (!NT_STATUS_IS_OK(s->status)) {
232 winsdb_delete(s->winssrv->wins_db, rec);
233 rcode = wins_register_new(s->nbtsock, s->request_packet, s->src, s->new_type);
234 if (rcode != NBT_RCODE_OK) {
235 DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
236 nbt_name_string(s, rec->name)));
243 rec->expire_time = time(NULL) + ttl;
244 rec->registered_by = s->src->addr;
247 * now remove all addresses that're the client doesn't hold anymore
248 * and update the time stamp and owner for the ownes that are still there
250 for (i=0; rec->addresses[i]; i++) {
252 for (j=0; j < s->io.out.num_addresses; j++) {
253 if (strcmp(rec->addresses[i]->address, s->io.out.addresses[j]) != 0) continue;
259 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
262 s->winssrv->wins_db->local_owner,
265 if (rec->addresses == NULL) goto failed;
269 winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
272 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
275 s->winssrv->wins_db->local_owner,
278 if (rec->addresses == NULL) goto failed;
280 /* if we have more than one address, this becomes implicit a MHOMED record */
281 if (winsdb_addr_list_length(rec->addresses) > 1) {
282 rec->type = WREPL_TYPE_MHOMED;
285 winsdb_modify(s->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
287 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
288 nbt_name_string(s, rec->name), s->reg_address));
291 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
292 s->src, NBT_RCODE_OK);
298 called when a name query to a current owner completes
300 static void wack_wins_challenge_handler(struct composite_context *c_req)
302 struct wack_state *s = talloc_get_type(c_req->async.private_data,
307 s->status = wins_challenge_recv(c_req, s, &s->io);
310 * if the owner denies it holds the name, then allow
313 if (!NT_STATUS_IS_OK(s->status)) {
318 if (s->new_type == WREPL_TYPE_GROUP || s->new_type == WREPL_TYPE_SGROUP) {
319 DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
320 nbt_name_string(s, s->rec->name), s->new_type, s->rec->type));
326 * if the owner still wants the name and doesn't reply
327 * with the address trying to be registered, then deny
331 for (i=0; i < s->io.out.num_addresses; i++) {
332 if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
348 a client has asked to register a unique name that someone else owns. We
349 need to ask each of the current owners if they still want it. If they do
350 then reject the registration, otherwise allow it
352 static void wins_register_wack(struct nbt_name_socket *nbtsock,
353 struct nbt_name_packet *packet,
354 struct winsdb_record *rec,
355 struct socket_address *src,
356 enum wrepl_name_type new_type)
358 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
359 struct nbtd_interface);
360 struct wins_server *winssrv = iface->nbtsrv->winssrv;
361 struct wack_state *s;
362 struct composite_context *c_req;
365 s = talloc_zero(nbtsock, struct wack_state);
366 if (s == NULL) goto failed;
368 /* package up the state variables for this wack request */
369 s->winssrv = winssrv;
370 s->nbtsock = nbtsock;
371 s->request_packet = talloc_steal(s, packet);
372 s->rec = talloc_steal(s, rec);
373 s->reg_address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
374 s->new_type = new_type;
376 if (talloc_reference(s, src) == NULL) goto failed;
378 s->io.in.nbtd_server = iface->nbtsrv;
379 s->io.in.event_ctx = iface->nbtsrv->task->event_ctx;
380 s->io.in.name = rec->name;
381 s->io.in.num_addresses = winsdb_addr_list_length(rec->addresses);
382 s->io.in.addresses = winsdb_addr_string_list(s, rec->addresses);
383 if (s->io.in.addresses == NULL) goto failed;
386 * send a WACK to the client, specifying the maximum time it could
387 * take to check with the owner, plus some slack
389 ttl = 5 + 4 * winsdb_addr_list_length(rec->addresses);
390 nbtd_wack_reply(nbtsock, packet, src, ttl);
393 * send the challenge to the old addresses
395 c_req = wins_challenge_send(s, &s->io);
396 if (c_req == NULL) goto failed;
398 c_req->async.fn = wack_wins_challenge_handler;
399 c_req->async.private_data = s;
404 nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR);
410 static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
411 struct nbt_name_packet *packet,
412 struct socket_address *src)
415 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
416 struct nbtd_interface);
417 struct wins_server *winssrv = iface->nbtsrv->winssrv;
418 struct nbt_name *name = &packet->questions[0].name;
419 struct winsdb_record *rec;
420 uint8_t rcode = NBT_RCODE_OK;
421 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
422 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
423 BOOL mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
424 enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
425 struct winsdb_addr *winsdb_addr = NULL;
428 * as a special case, the local master browser name is always accepted
429 * for registration, but never stored, but w2k3 stores it if it's registered
430 * as a group name, (but a query for the 0x1D name still returns not found!)
432 if (name->type == NBT_NAME_MASTER && !(nb_flags & NBT_NM_GROUP)) {
433 rcode = NBT_RCODE_OK;
437 /* w2k3 refuses 0x1B names with marked as group */
438 if (name->type == NBT_NAME_PDC && (nb_flags & NBT_NM_GROUP)) {
439 rcode = NBT_RCODE_RFS;
443 /* w2k3 refuses 0x1C names with out marked as group */
444 if (name->type == NBT_NAME_LOGON && !(nb_flags & NBT_NM_GROUP)) {
445 rcode = NBT_RCODE_RFS;
449 /* w2k3 refuses 0x1E names with out marked as group */
450 if (name->type == NBT_NAME_BROWSER && !(nb_flags & NBT_NM_GROUP)) {
451 rcode = NBT_RCODE_RFS;
455 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
456 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
457 rcode = wins_register_new(nbtsock, packet, src, new_type);
459 } else if (!NT_STATUS_IS_OK(status)) {
460 rcode = NBT_RCODE_SVR;
462 } else if (rec->is_static) {
463 if (rec->type == WREPL_TYPE_GROUP || rec->type == WREPL_TYPE_SGROUP) {
464 rcode = NBT_RCODE_OK;
467 rcode = NBT_RCODE_ACT;
471 if (rec->type == WREPL_TYPE_GROUP) {
472 if (new_type != WREPL_TYPE_GROUP) {
473 DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
474 " while a normal group is already there\n",
475 nbt_name_string(packet, name), new_type));
476 rcode = NBT_RCODE_ACT;
480 if (rec->state == WREPL_STATE_ACTIVE) {
481 /* TODO: is this correct? */
482 rcode = wins_update_ttl(nbtsock, packet, rec, NULL, src);
486 /* TODO: is this correct? */
487 winsdb_delete(winssrv->wins_db, rec);
488 rcode = wins_register_new(nbtsock, packet, src, new_type);
492 if (rec->state != WREPL_STATE_ACTIVE) {
493 winsdb_delete(winssrv->wins_db, rec);
494 rcode = wins_register_new(nbtsock, packet, src, new_type);
499 case WREPL_TYPE_UNIQUE:
500 case WREPL_TYPE_MHOMED:
502 * if its an active unique name, and the registration is for a group, then
503 * see if the unique name owner still wants the name
504 * TODO: is this correct?
506 if (new_type == WREPL_TYPE_GROUP || new_type == WREPL_TYPE_GROUP) {
507 wins_register_wack(nbtsock, packet, rec, src, new_type);
512 * if the registration is for an address that is currently active, then
513 * just update the expiry time of the record and the address
515 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
517 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
522 * we have to do a WACK to see if the current owner is willing
523 * to give up its claim
525 wins_register_wack(nbtsock, packet, rec, src, new_type);
528 case WREPL_TYPE_GROUP:
529 /* this should not be reached as normal groups are handled above */
530 DEBUG(0,("BUG at %s\n",__location__));
531 rcode = NBT_RCODE_ACT;
534 case WREPL_TYPE_SGROUP:
535 /* if the new record isn't also a special group, refuse the registration */
536 if (new_type != WREPL_TYPE_SGROUP) {
537 DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
538 " while a special group is already there\n",
539 nbt_name_string(packet, name), new_type));
540 rcode = NBT_RCODE_ACT;
545 * if the registration is for an address that is currently active, then
546 * just update the expiry time of the record and the address
548 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
550 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
554 rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
559 nbtd_name_registration_reply(nbtsock, packet, src, rcode);
562 static uint32_t ipv4_match_bits(struct ipv4_addr ip1,struct ipv4_addr ip2)
564 uint32_t i, j, match=0;
567 p1 = (uint8_t *)&ip1.addr;
568 p2 = (uint8_t *)&ip2.addr;
570 for (i=0; i<4; i++) {
571 if (p1[i] != p2[i]) break;
575 if (i==4) return match;
577 for (j=0; j<8; j++) {
578 if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j))))
586 static int nbtd_wins_randomize1Clist_sort(void *p1,/* (const char **) */
587 void *p2,/* (const char **) */
588 struct socket_address *src)
590 const char *a1 = (const char *)*(const char **)p1;
591 const char *a2 = (const char *)*(const char **)p2;
592 uint32_t match_bits1;
593 uint32_t match_bits2;
595 match_bits1 = ipv4_match_bits(interpret_addr2(a1), interpret_addr2(src->addr));
596 match_bits2 = ipv4_match_bits(interpret_addr2(a2), interpret_addr2(src->addr));
598 return match_bits2 - match_bits1;
601 static void nbtd_wins_randomize1Clist(const char **addresses, struct socket_address *src)
609 for (num_addrs=0; addresses[num_addrs]; num_addrs++) { /* noop */ }
611 if (num_addrs <= 1) return; /* nothing to do */
613 /* first sort the addresses depending on the matching to the client */
614 ldb_qsort(addresses, num_addrs , sizeof(addresses[0]),
615 src, (ldb_qsort_cmp_fn_t)nbtd_wins_randomize1Clist_sort);
617 mask = lp_parm_string(-1, "nbtd", "wins_randomize1Clist_mask");
619 mask = "255.255.255.0";
623 * choose a random address to be the first in the response to the client,
624 * preferr the addresses inside the nbtd:wins_randomize1Clist_mask netmask
627 idx = sidx = r % num_addrs;
632 /* if the current one is in the same subnet, use it */
633 same = iface_same_net(addresses[idx], src->addr, mask);
639 /* we need to check for idx == 0, after checking for the same net */
642 * if we haven't found an address in the same subnet, search in ones
643 * which match the client more
647 * it's not "idx = idx % r" but "idx = r % idx"
648 * because in "a % b" b is the allowed range
649 * and b-1 is the maximum possible result, so it must be decreasing
650 * and the above idx == 0 check breaks the while(1) loop.
655 /* note sidx == 0 is also valid here ... */
657 addresses[0] = addresses[sidx];
658 addresses[sidx] = tmp;
664 static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock,
665 struct nbt_name_packet *packet,
666 struct socket_address *src)
669 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
670 struct nbtd_interface);
671 struct wins_server *winssrv = iface->nbtsrv->winssrv;
672 struct nbt_name *name = &packet->questions[0].name;
673 struct winsdb_record *rec;
674 struct winsdb_record *rec_1b = NULL;
675 const char **addresses;
676 const char **addresses_1b = NULL;
677 uint16_t nb_flags = 0;
679 if (name->type == NBT_NAME_MASTER) {
684 * w2k3 returns the first address of the 0x1B record as first address
687 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
689 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Prepend1BTo1CQueries
690 * Typ: Daten REG_DWORD
691 * Value: 0 = deactivated, 1 = activated
693 if (name->type == NBT_NAME_LOGON && lp_parm_bool(-1, "nbtd", "wins_prepend1Bto1Cqueries", True)) {
694 struct nbt_name name_1b;
697 name_1b.type = NBT_NAME_PDC;
699 status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
700 if (NT_STATUS_IS_OK(status)) {
701 addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
705 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
706 if (!NT_STATUS_IS_OK(status)) {
707 if (!lp_wins_dns_proxy()) {
711 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
715 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
720 * for group's we always reply with
721 * 255.255.255.255 as address, even if
722 * the record is released or tombstoned
724 if (rec->type == WREPL_TYPE_GROUP) {
725 addresses = str_list_add(NULL, "255.255.255.255");
726 talloc_steal(packet, addresses);
730 nb_flags |= NBT_NM_GROUP;
734 if (rec->state != WREPL_STATE_ACTIVE) {
738 addresses = winsdb_addr_string_list(packet, rec->addresses);
744 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
745 * first 0x1B address as first address
747 if (addresses_1b && addresses_1b[0]) {
748 const char **addresses_1c = addresses;
752 addresses = str_list_add(NULL, addresses_1b[0]);
756 talloc_steal(packet, addresses);
759 for (i=0; addresses_1c[i]; i++) {
760 if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
763 * stop when we already have 25 addresses
765 if (num_addrs >= 25) break;
768 addresses = str_list_add(addresses, addresses_1c[i]);
775 if (rec->type == WREPL_TYPE_SGROUP) {
776 nb_flags |= NBT_NM_GROUP;
778 nb_flags |= (rec->node <<13);
782 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
784 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList
785 * Typ: Daten REG_DWORD
786 * Value: 0 = deactivated, 1 = activated
788 if (name->type == NBT_NAME_LOGON && lp_parm_bool(-1, "nbtd", "wins_randomize1Clist", False)) {
789 nbtd_wins_randomize1Clist(addresses, src);
793 nbtd_name_query_reply(nbtsock, packet, src, name,
794 0, nb_flags, addresses);
798 nbtd_negative_name_query_reply(nbtsock, packet, src);
804 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
805 struct nbt_name_packet *packet,
806 struct socket_address *src)
809 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
810 struct nbtd_interface);
811 struct wins_server *winssrv = iface->nbtsrv->winssrv;
812 struct nbt_name *name = &packet->questions[0].name;
813 struct winsdb_record *rec;
814 uint32_t modify_flags = 0;
817 if (name->type == NBT_NAME_MASTER) {
821 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
822 if (!NT_STATUS_IS_OK(status)) {
826 if (rec->is_static) {
827 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
830 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
834 if (rec->state != WREPL_STATE_ACTIVE) {
839 * TODO: do we need to check if
840 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
845 * we only allow releases from an owner - other releases are
848 if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
850 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
851 DEBUGADD(4, ("Registered Addresses: \n"));
852 for (i=0; rec->addresses && rec->addresses[i]; i++) {
853 DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
858 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
861 case WREPL_TYPE_UNIQUE:
862 rec->state = WREPL_STATE_RELEASED;
865 case WREPL_TYPE_GROUP:
866 rec->state = WREPL_STATE_RELEASED;
869 case WREPL_TYPE_SGROUP:
870 winsdb_addr_list_remove(rec->addresses, src->addr);
871 /* TODO: do we need to take the ownership here? */
872 if (winsdb_addr_list_length(rec->addresses) == 0) {
873 rec->state = WREPL_STATE_RELEASED;
877 case WREPL_TYPE_MHOMED:
878 winsdb_addr_list_remove(rec->addresses, src->addr);
879 /* TODO: do we need to take the ownership here? */
880 if (winsdb_addr_list_length(rec->addresses) == 0) {
881 rec->state = WREPL_STATE_RELEASED;
886 if (rec->state == WREPL_STATE_RELEASED) {
888 * if we're not the owner, we need to take the owner ship
889 * and make the record tombstone, but expire after
890 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
891 * like for normal tombstone records.
892 * This is to replicate the record directly to the original owner,
893 * where the record is still active
895 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
896 rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
898 rec->state = WREPL_STATE_TOMBSTONE;
899 rec->expire_time= time(NULL) +
900 winssrv->config.tombstone_interval +
901 winssrv->config.tombstone_timeout;
902 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
906 ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
907 if (ret != NBT_RCODE_OK) {
908 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
909 nbt_name_string(rec, rec->name), src->addr, ret));
912 /* we match w2k3 by always giving a positive reply to name releases. */
913 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
920 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
921 struct nbt_name_packet *packet,
922 struct socket_address *src)
924 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
925 struct nbtd_interface);
926 struct wins_server *winssrv = iface->nbtsrv->winssrv;
927 if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
931 switch (packet->operation & NBT_OPCODE) {
932 case NBT_OPCODE_QUERY:
933 nbtd_winsserver_query(nbtsock, packet, src);
936 case NBT_OPCODE_REGISTER:
937 case NBT_OPCODE_REFRESH:
938 case NBT_OPCODE_REFRESH2:
939 case NBT_OPCODE_MULTI_HOME_REG:
940 nbtd_winsserver_register(nbtsock, packet, src);
943 case NBT_OPCODE_RELEASE:
944 nbtd_winsserver_release(nbtsock, packet, src);
951 startup the WINS server, if configured
953 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
957 if (!lp_wins_support()) {
958 nbtsrv->winssrv = NULL;
962 nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
963 NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
965 nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl();
966 nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl();
967 tmp = lp_parm_int(-1,"wreplsrv","tombstone_interval", 6*24*60*60);
968 nbtsrv->winssrv->config.tombstone_interval = tmp;
969 tmp = lp_parm_int(-1,"wreplsrv","tombstone_timeout", 1*24*60*60);
970 nbtsrv->winssrv->config.tombstone_timeout = tmp;
972 nbtsrv->winssrv->wins_db = winsdb_connect(nbtsrv->winssrv, WINSDB_HANDLE_CALLER_NBTD);
973 if (!nbtsrv->winssrv->wins_db) {
974 return NT_STATUS_INTERNAL_DB_ERROR;
977 irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");