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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 "lib/socket/socket.h"
33 #include "lib/ldb/include/ldb.h"
36 work out the ttl we will use given a client requested ttl
38 uint32_t wins_server_ttl(struct wins_server *winssrv, uint32_t ttl)
40 ttl = MIN(ttl, winssrv->config.max_renew_interval);
41 ttl = MAX(ttl, winssrv->config.min_renew_interval);
45 static enum wrepl_name_type wrepl_type(uint16_t nb_flags, struct nbt_name *name, BOOL mhomed)
47 /* this copes with the nasty hack that is the type 0x1c name */
48 if (name->type == NBT_NAME_LOGON) {
49 return WREPL_TYPE_SGROUP;
51 if (nb_flags & NBT_NM_GROUP) {
52 return WREPL_TYPE_GROUP;
55 return WREPL_TYPE_MHOMED;
57 return WREPL_TYPE_UNIQUE;
61 register a new name with WINS
63 static uint8_t wins_register_new(struct nbt_name_socket *nbtsock,
64 struct nbt_name_packet *packet,
65 const struct socket_address *src,
66 enum wrepl_name_type type)
68 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
69 struct nbtd_interface);
70 struct wins_server *winssrv = iface->nbtsrv->winssrv;
71 struct nbt_name *name = &packet->questions[0].name;
72 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
73 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
74 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
75 struct winsdb_record rec;
76 enum wrepl_name_node node;
78 #define WREPL_NODE_NBT_FLAGS(nb_flags) \
79 ((nb_flags & NBT_NM_OWNER_TYPE)>>13)
81 node = WREPL_NODE_NBT_FLAGS(nb_flags);
85 rec.state = WREPL_STATE_ACTIVE;
87 rec.is_static = False;
88 rec.expire_time = time(NULL) + ttl;
89 rec.version = 0; /* will be allocated later */
90 rec.wins_owner = NULL; /* will be set later */
91 rec.registered_by = src->addr;
92 rec.addresses = winsdb_addr_list_make(packet);
93 if (rec.addresses == NULL) return NBT_RCODE_SVR;
95 rec.addresses = winsdb_addr_list_add(winssrv->wins_db,
98 winssrv->wins_db->local_owner,
101 if (rec.addresses == NULL) return NBT_RCODE_SVR;
103 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
104 nbt_name_string(packet, name), rec.addresses[0]->address));
106 return winsdb_add(winssrv->wins_db, &rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
111 update the ttl on an existing record
113 static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock,
114 struct nbt_name_packet *packet,
115 struct winsdb_record *rec,
116 struct winsdb_addr *winsdb_addr,
117 const struct socket_address *src)
119 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
120 struct nbtd_interface);
121 struct wins_server *winssrv = iface->nbtsrv->winssrv;
122 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
123 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
124 uint32_t modify_flags = 0;
126 rec->expire_time = time(NULL) + ttl;
127 rec->registered_by = src->addr;
130 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
132 winsdb_addr->address,
133 winssrv->wins_db->local_owner,
136 if (rec->addresses == NULL) return NBT_RCODE_SVR;
139 if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) {
140 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
143 DEBUG(5,("WINS: refreshed registration of %s at %s\n",
144 nbt_name_string(packet, rec->name), address));
146 return winsdb_modify(winssrv->wins_db, rec, modify_flags);
152 static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
153 struct nbt_name_packet *packet,
154 struct winsdb_record *rec,
156 const struct socket_address *src)
158 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
159 struct nbtd_interface);
160 struct wins_server *winssrv = iface->nbtsrv->winssrv;
161 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
163 rec->expire_time = time(NULL) + ttl;
164 rec->registered_by = src->addr;
166 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
169 winssrv->wins_db->local_owner,
172 if (rec->addresses == NULL) return NBT_RCODE_SVR;
174 DEBUG(5,("WINS: sgroup merge of %s at %s\n",
175 nbt_name_string(packet, rec->name), address));
177 return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
181 struct wins_server *winssrv;
182 struct nbt_name_socket *nbtsock;
183 struct nbt_name_packet *request_packet;
184 struct winsdb_record *rec;
185 struct socket_address *src;
186 const char *reg_address;
187 enum wrepl_name_type new_type;
188 struct wins_challenge_io io;
193 deny a registration request
195 static void wins_wack_deny(struct wack_state *s)
197 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
198 s->src, NBT_RCODE_ACT);
199 DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
200 nbt_name_string(s, s->rec->name), s->src->addr, s->src->port));
205 allow a registration request
207 static void wins_wack_allow(struct wack_state *s)
210 uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
211 struct winsdb_record *rec = s->rec, *rec2;
214 status = winsdb_lookup(s->winssrv->wins_db, rec->name, s, &rec2);
215 if (!NT_STATUS_IS_OK(status) ||
216 rec2->version != rec->version ||
217 strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
218 DEBUG(1,("WINS: record %s changed during WACK - failing registration\n",
219 nbt_name_string(s, rec->name)));
225 * if the old name owner doesn't hold the name anymore
226 * handle the request as new registration for the new name owner
228 if (!NT_STATUS_IS_OK(s->status)) {
231 winsdb_delete(s->winssrv->wins_db, rec);
232 rcode = wins_register_new(s->nbtsock, s->request_packet, s->src, s->new_type);
233 if (rcode != NBT_RCODE_OK) {
234 DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
235 nbt_name_string(s, rec->name)));
242 rec->expire_time = time(NULL) + ttl;
243 rec->registered_by = s->src->addr;
246 * now remove all addresses that're the client doesn't hold anymore
247 * and update the time stamp and owner for the ownes that are still there
249 for (i=0; rec->addresses[i]; i++) {
251 for (j=0; j < s->io.out.num_addresses; j++) {
252 if (strcmp(rec->addresses[i]->address, s->io.out.addresses[j]) != 0) continue;
258 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
261 s->winssrv->wins_db->local_owner,
264 if (rec->addresses == NULL) goto failed;
268 winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
271 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
274 s->winssrv->wins_db->local_owner,
277 if (rec->addresses == NULL) goto failed;
279 /* if we have more than one address, this becomes implicit a MHOMED record */
280 if (winsdb_addr_list_length(rec->addresses) > 1) {
281 rec->type = WREPL_TYPE_MHOMED;
284 winsdb_modify(s->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
286 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
287 nbt_name_string(s, rec->name), s->reg_address));
290 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
291 s->src, NBT_RCODE_OK);
297 called when a name query to a current owner completes
299 static void wack_wins_challenge_handler(struct composite_context *c_req)
301 struct wack_state *s = talloc_get_type(c_req->async.private_data,
306 s->status = wins_challenge_recv(c_req, s, &s->io);
309 * if the owner denies it holds the name, then allow
312 if (!NT_STATUS_IS_OK(s->status)) {
317 if (s->new_type == WREPL_TYPE_GROUP || s->new_type == WREPL_TYPE_SGROUP) {
318 DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
319 nbt_name_string(s, s->rec->name), s->new_type, s->rec->type));
325 * if the owner still wants the name and doesn't reply
326 * with the address trying to be registered, then deny
330 for (i=0; i < s->io.out.num_addresses; i++) {
331 if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
347 a client has asked to register a unique name that someone else owns. We
348 need to ask each of the current owners if they still want it. If they do
349 then reject the registration, otherwise allow it
351 static void wins_register_wack(struct nbt_name_socket *nbtsock,
352 struct nbt_name_packet *packet,
353 struct winsdb_record *rec,
354 struct socket_address *src,
355 enum wrepl_name_type new_type)
357 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
358 struct nbtd_interface);
359 struct wins_server *winssrv = iface->nbtsrv->winssrv;
360 struct wack_state *s;
361 struct composite_context *c_req;
364 s = talloc_zero(nbtsock, struct wack_state);
365 if (s == NULL) goto failed;
367 /* package up the state variables for this wack request */
368 s->winssrv = winssrv;
369 s->nbtsock = nbtsock;
370 s->request_packet = talloc_steal(s, packet);
371 s->rec = talloc_steal(s, rec);
372 s->reg_address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
373 s->new_type = new_type;
375 if (talloc_reference(s, src) == NULL) goto failed;
377 s->io.in.nbtd_server = iface->nbtsrv;
378 s->io.in.event_ctx = iface->nbtsrv->task->event_ctx;
379 s->io.in.name = rec->name;
380 s->io.in.num_addresses = winsdb_addr_list_length(rec->addresses);
381 s->io.in.addresses = winsdb_addr_string_list(s, rec->addresses);
382 if (s->io.in.addresses == NULL) goto failed;
385 * send a WACK to the client, specifying the maximum time it could
386 * take to check with the owner, plus some slack
388 ttl = 5 + 4 * winsdb_addr_list_length(rec->addresses);
389 nbtd_wack_reply(nbtsock, packet, src, ttl);
392 * send the challenge to the old addresses
394 c_req = wins_challenge_send(s, &s->io);
395 if (c_req == NULL) goto failed;
397 c_req->async.fn = wack_wins_challenge_handler;
398 c_req->async.private_data = s;
403 nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR);
409 static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
410 struct nbt_name_packet *packet,
411 struct socket_address *src)
414 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
415 struct nbtd_interface);
416 struct wins_server *winssrv = iface->nbtsrv->winssrv;
417 struct nbt_name *name = &packet->questions[0].name;
418 struct winsdb_record *rec;
419 uint8_t rcode = NBT_RCODE_OK;
420 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
421 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
422 BOOL mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
423 enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
424 struct winsdb_addr *winsdb_addr = NULL;
427 * as a special case, the local master browser name is always accepted
428 * for registration, but never stored, but w2k3 stores it if it's registered
429 * as a group name, (but a query for the 0x1D name still returns not found!)
431 if (name->type == NBT_NAME_MASTER && !(nb_flags & NBT_NM_GROUP)) {
432 rcode = NBT_RCODE_OK;
436 /* w2k3 refuses 0x1B names with marked as group */
437 if (name->type == NBT_NAME_PDC && (nb_flags & NBT_NM_GROUP)) {
438 rcode = NBT_RCODE_RFS;
442 /* w2k3 refuses 0x1C names with out marked as group */
443 if (name->type == NBT_NAME_LOGON && !(nb_flags & NBT_NM_GROUP)) {
444 rcode = NBT_RCODE_RFS;
448 /* w2k3 refuses 0x1E names with out marked as group */
449 if (name->type == NBT_NAME_BROWSER && !(nb_flags & NBT_NM_GROUP)) {
450 rcode = NBT_RCODE_RFS;
454 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
455 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
456 rcode = wins_register_new(nbtsock, packet, src, new_type);
458 } else if (!NT_STATUS_IS_OK(status)) {
459 rcode = NBT_RCODE_SVR;
461 } else if (rec->is_static) {
462 if (rec->type == WREPL_TYPE_GROUP || rec->type == WREPL_TYPE_SGROUP) {
463 rcode = NBT_RCODE_OK;
466 rcode = NBT_RCODE_ACT;
470 if (rec->type == WREPL_TYPE_GROUP) {
471 if (new_type != WREPL_TYPE_GROUP) {
472 DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
473 " while a normal group is already there\n",
474 nbt_name_string(packet, name), new_type));
475 rcode = NBT_RCODE_ACT;
479 if (rec->state == WREPL_STATE_ACTIVE) {
480 /* TODO: is this correct? */
481 rcode = wins_update_ttl(nbtsock, packet, rec, NULL, src);
485 /* TODO: is this correct? */
486 winsdb_delete(winssrv->wins_db, rec);
487 rcode = wins_register_new(nbtsock, packet, src, new_type);
491 if (rec->state != WREPL_STATE_ACTIVE) {
492 winsdb_delete(winssrv->wins_db, rec);
493 rcode = wins_register_new(nbtsock, packet, src, new_type);
498 case WREPL_TYPE_UNIQUE:
499 case WREPL_TYPE_MHOMED:
501 * if its an active unique name, and the registration is for a group, then
502 * see if the unique name owner still wants the name
503 * TODO: is this correct?
505 if (new_type == WREPL_TYPE_GROUP || new_type == WREPL_TYPE_GROUP) {
506 wins_register_wack(nbtsock, packet, rec, src, new_type);
511 * if the registration is for an address that is currently active, then
512 * just update the expiry time of the record and the address
514 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
516 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
521 * we have to do a WACK to see if the current owner is willing
522 * to give up its claim
524 wins_register_wack(nbtsock, packet, rec, src, new_type);
527 case WREPL_TYPE_GROUP:
528 /* this should not be reached as normal groups are handled above */
529 DEBUG(0,("BUG at %s\n",__location__));
530 rcode = NBT_RCODE_ACT;
533 case WREPL_TYPE_SGROUP:
534 /* if the new record isn't also a special group, refuse the registration */
535 if (new_type != WREPL_TYPE_SGROUP) {
536 DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
537 " while a special group is already there\n",
538 nbt_name_string(packet, name), new_type));
539 rcode = NBT_RCODE_ACT;
544 * if the registration is for an address that is currently active, then
545 * just update the expiry time of the record and the address
547 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
549 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
553 rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
558 nbtd_name_registration_reply(nbtsock, packet, src, rcode);
564 static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock,
565 struct nbt_name_packet *packet,
566 struct socket_address *src)
569 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
570 struct nbtd_interface);
571 struct wins_server *winssrv = iface->nbtsrv->winssrv;
572 struct nbt_name *name = &packet->questions[0].name;
573 struct winsdb_record *rec;
574 struct winsdb_record *rec_1b = NULL;
575 const char **addresses;
576 const char **addresses_1b = NULL;
577 uint16_t nb_flags = 0;
579 if (name->type == NBT_NAME_MASTER) {
584 * w2k3 returns the first address of the 0x1B record as first address
587 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
589 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Prepend1BTo1CQueries
590 * Typ: Daten REG_DWORD
591 * Value: 0 = deactivated, 1 = activated
593 if (name->type == NBT_NAME_LOGON && lp_parm_bool(-1, "nbtd", "wins_prepend1Bto1Cqueries", True)) {
594 struct nbt_name name_1b;
597 name_1b.type = NBT_NAME_PDC;
599 status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
600 if (NT_STATUS_IS_OK(status)) {
601 addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
605 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
606 if (!NT_STATUS_IS_OK(status)) {
607 if (!lp_wins_dns_proxy()) {
611 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
615 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
620 * for group's we always reply with
621 * 255.255.255.255 as address, even if
622 * the record is released or tombstoned
624 if (rec->type == WREPL_TYPE_GROUP) {
625 addresses = str_list_add(NULL, "255.255.255.255");
626 talloc_steal(packet, addresses);
630 nb_flags |= NBT_NM_GROUP;
634 if (rec->state != WREPL_STATE_ACTIVE) {
638 addresses = winsdb_addr_string_list(packet, rec->addresses);
644 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
645 * first 0x1B address as first address
647 if (addresses_1b && addresses_1b[0]) {
648 const char **addresses_1c = addresses;
652 addresses = str_list_add(NULL, addresses_1b[0]);
656 talloc_steal(packet, addresses);
659 for (i=0; addresses_1c[i]; i++) {
660 if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
663 * stop when we already have 25 addresses
665 if (num_addrs >= 25) break;
668 addresses = str_list_add(addresses, addresses_1c[i]);
675 if (rec->type == WREPL_TYPE_SGROUP) {
676 nb_flags |= NBT_NM_GROUP;
678 nb_flags |= (rec->node <<13);
682 nbtd_name_query_reply(nbtsock, packet, src, name,
683 0, nb_flags, addresses);
687 nbtd_negative_name_query_reply(nbtsock, packet, src);
693 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
694 struct nbt_name_packet *packet,
695 struct socket_address *src)
698 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
699 struct nbtd_interface);
700 struct wins_server *winssrv = iface->nbtsrv->winssrv;
701 struct nbt_name *name = &packet->questions[0].name;
702 struct winsdb_record *rec;
703 uint32_t modify_flags = 0;
706 if (name->type == NBT_NAME_MASTER) {
710 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
711 if (!NT_STATUS_IS_OK(status)) {
715 if (rec->is_static) {
716 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
719 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
723 if (rec->state != WREPL_STATE_ACTIVE) {
728 * TODO: do we need to check if
729 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
734 * we only allow releases from an owner - other releases are
737 if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
739 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
740 DEBUGADD(4, ("Registered Addresses: \n"));
741 for (i=0; rec->addresses && rec->addresses[i]; i++) {
742 DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
747 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
750 case WREPL_TYPE_UNIQUE:
751 rec->state = WREPL_STATE_RELEASED;
754 case WREPL_TYPE_GROUP:
755 rec->state = WREPL_STATE_RELEASED;
758 case WREPL_TYPE_SGROUP:
759 winsdb_addr_list_remove(rec->addresses, src->addr);
760 /* TODO: do we need to take the ownership here? */
761 if (winsdb_addr_list_length(rec->addresses) == 0) {
762 rec->state = WREPL_STATE_RELEASED;
766 case WREPL_TYPE_MHOMED:
767 winsdb_addr_list_remove(rec->addresses, src->addr);
768 /* TODO: do we need to take the ownership here? */
769 if (winsdb_addr_list_length(rec->addresses) == 0) {
770 rec->state = WREPL_STATE_RELEASED;
775 if (rec->state == WREPL_STATE_RELEASED) {
777 * if we're not the owner, we need to take the owner ship
778 * and make the record tombstone, but expire after
779 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
780 * like for normal tombstone records.
781 * This is to replicate the record directly to the original owner,
782 * where the record is still active
784 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
785 rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
787 rec->state = WREPL_STATE_TOMBSTONE;
788 rec->expire_time= time(NULL) +
789 winssrv->config.tombstone_interval +
790 winssrv->config.tombstone_timeout;
791 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
795 ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
796 if (ret != NBT_RCODE_OK) {
797 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
798 nbt_name_string(rec, rec->name), src->addr, ret));
801 /* we match w2k3 by always giving a positive reply to name releases. */
802 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
809 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
810 struct nbt_name_packet *packet,
811 struct socket_address *src)
813 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
814 struct nbtd_interface);
815 struct wins_server *winssrv = iface->nbtsrv->winssrv;
816 if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
820 switch (packet->operation & NBT_OPCODE) {
821 case NBT_OPCODE_QUERY:
822 nbtd_winsserver_query(nbtsock, packet, src);
825 case NBT_OPCODE_REGISTER:
826 case NBT_OPCODE_REFRESH:
827 case NBT_OPCODE_REFRESH2:
828 case NBT_OPCODE_MULTI_HOME_REG:
829 nbtd_winsserver_register(nbtsock, packet, src);
832 case NBT_OPCODE_RELEASE:
833 nbtd_winsserver_release(nbtsock, packet, src);
840 startup the WINS server, if configured
842 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
846 if (!lp_wins_support()) {
847 nbtsrv->winssrv = NULL;
851 nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
852 NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
854 nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl();
855 nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl();
856 tmp = lp_parm_int(-1,"wreplsrv","tombstone_interval", 6*24*60*60);
857 nbtsrv->winssrv->config.tombstone_interval = tmp;
858 tmp = lp_parm_int(-1,"wreplsrv","tombstone_timeout", 1*24*60*60);
859 nbtsrv->winssrv->config.tombstone_timeout = tmp;
861 nbtsrv->winssrv->wins_db = winsdb_connect(nbtsrv->winssrv, WINSDB_HANDLE_CALLER_NBTD);
862 if (!nbtsrv->winssrv->wins_db) {
863 return NT_STATUS_INTERNAL_DB_ERROR;
866 irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");