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 "system/time.h"
29 #include "libcli/composite/composite.h"
30 #include "smbd/service_task.h"
31 #include "lib/socket/socket.h"
34 work out the ttl we will use given a client requested ttl
36 uint32_t wins_server_ttl(struct wins_server *winssrv, uint32_t ttl)
38 ttl = MIN(ttl, winssrv->config.max_renew_interval);
39 ttl = MAX(ttl, winssrv->config.min_renew_interval);
43 static enum wrepl_name_type wrepl_type(uint16_t nb_flags, struct nbt_name *name, BOOL mhomed)
45 /* this copes with the nasty hack that is the type 0x1c name */
46 if (name->type == NBT_NAME_LOGON) {
47 return WREPL_TYPE_SGROUP;
49 if (nb_flags & NBT_NM_GROUP) {
50 return WREPL_TYPE_GROUP;
53 return WREPL_TYPE_MHOMED;
55 return WREPL_TYPE_UNIQUE;
59 register a new name with WINS
61 static uint8_t wins_register_new(struct nbt_name_socket *nbtsock,
62 struct nbt_name_packet *packet,
63 const struct socket_address *src,
64 enum wrepl_name_type type)
66 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
67 struct nbtd_interface);
68 struct wins_server *winssrv = iface->nbtsrv->winssrv;
69 struct nbt_name *name = &packet->questions[0].name;
70 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
71 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
72 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
73 struct winsdb_record rec;
74 enum wrepl_name_node node;
76 #define WREPL_NODE_NBT_FLAGS(nb_flags) \
77 ((nb_flags & NBT_NM_OWNER_TYPE)>>13)
79 node = WREPL_NODE_NBT_FLAGS(nb_flags);
83 rec.state = WREPL_STATE_ACTIVE;
85 rec.is_static = False;
86 rec.expire_time = time(NULL) + ttl;
87 rec.version = 0; /* will be allocated later */
88 rec.wins_owner = NULL; /* will be set later */
89 rec.registered_by = src->addr;
90 rec.addresses = winsdb_addr_list_make(packet);
91 if (rec.addresses == NULL) return NBT_RCODE_SVR;
93 rec.addresses = winsdb_addr_list_add(rec.addresses,
95 winssrv->wins_db->local_owner,
97 if (rec.addresses == NULL) return NBT_RCODE_SVR;
99 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
100 nbt_name_string(packet, name), rec.addresses[0]->address));
102 return winsdb_add(winssrv->wins_db, &rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
107 update the ttl on an existing record
109 static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock,
110 struct nbt_name_packet *packet,
111 struct winsdb_record *rec,
112 struct winsdb_addr *winsdb_addr,
113 const struct socket_address *src)
115 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
116 struct nbtd_interface);
117 struct wins_server *winssrv = iface->nbtsrv->winssrv;
118 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
119 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
120 uint32_t modify_flags = 0;
122 rec->expire_time = time(NULL) + ttl;
123 rec->registered_by = src->addr;
126 winsdb_addr->wins_owner = winssrv->wins_db->local_owner;
127 winsdb_addr->expire_time = rec->expire_time;
130 if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) {
131 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
134 DEBUG(5,("WINS: refreshed registration of %s at %s\n",
135 nbt_name_string(packet, rec->name), address));
137 return winsdb_modify(winssrv->wins_db, rec, modify_flags);
143 static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
144 struct nbt_name_packet *packet,
145 struct winsdb_record *rec,
147 const struct socket_address *src)
149 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
150 struct nbtd_interface);
151 struct wins_server *winssrv = iface->nbtsrv->winssrv;
152 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
154 rec->expire_time = time(NULL) + ttl;
155 rec->registered_by = src->addr;
157 rec->addresses = winsdb_addr_list_add(rec->addresses,
159 winssrv->wins_db->local_owner,
161 if (rec->addresses == NULL) return NBT_RCODE_SVR;
163 DEBUG(5,("WINS: sgroup merge of %s at %s\n",
164 nbt_name_string(packet, rec->name), address));
166 return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
170 struct wins_server *winssrv;
171 struct nbt_name_socket *nbtsock;
172 struct nbt_name_packet *request_packet;
173 struct winsdb_record *rec;
174 struct socket_address *src;
175 const char *reg_address;
176 enum wrepl_name_type new_type;
177 struct wins_challenge_io io;
182 deny a registration request
184 static void wins_wack_deny(struct wack_state *s)
186 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
187 s->src, NBT_RCODE_ACT);
188 DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
189 nbt_name_string(s, s->rec->name), s->src->addr, s->src->port));
194 allow a registration request
196 static void wins_wack_allow(struct wack_state *s)
199 uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
200 struct winsdb_record *rec = s->rec, *rec2;
203 status = winsdb_lookup(s->winssrv->wins_db, rec->name, s, &rec2);
204 if (!NT_STATUS_IS_OK(status) ||
205 rec2->version != rec->version ||
206 strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
207 DEBUG(1,("WINS: record %s changed during WACK - failing registration\n",
208 nbt_name_string(s, rec->name)));
214 * if the old name owner doesn't hold the name anymore
215 * handle the request as new registration for the new name owner
217 if (!NT_STATUS_IS_OK(s->status)) {
220 winsdb_delete(s->winssrv->wins_db, rec);
221 rcode = wins_register_new(s->nbtsock, s->request_packet, s->src, s->new_type);
222 if (rcode != NBT_RCODE_OK) {
223 DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
224 nbt_name_string(s, rec->name)));
231 rec->expire_time = time(NULL) + ttl;
232 rec->registered_by = s->src->addr;
235 * now remove all addresses that're the client doesn't hold anymore
236 * and update the time stamp and owner for the ownes that are still there
238 for (i=0; rec->addresses[i]; i++) {
240 for (j=0; j < s->io.out.num_addresses; j++) {
241 if (strcmp(rec->addresses[i]->address, s->io.out.addresses[j]) != 0) continue;
247 rec->addresses[i]->wins_owner = s->winssrv->wins_db->local_owner;
248 rec->addresses[i]->expire_time = rec->expire_time;
252 winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
255 rec->addresses = winsdb_addr_list_add(rec->addresses,
257 s->winssrv->wins_db->local_owner,
259 if (rec->addresses == NULL) goto failed;
261 /* if we have more than one address, this becomes implicit a MHOMED record */
262 if (winsdb_addr_list_length(rec->addresses) > 1) {
263 rec->type = WREPL_TYPE_MHOMED;
266 winsdb_modify(s->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
268 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
269 nbt_name_string(s, rec->name), s->reg_address));
272 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
273 s->src, NBT_RCODE_OK);
279 called when a name query to a current owner completes
281 static void wack_wins_challenge_handler(struct composite_context *c_req)
283 struct wack_state *s = talloc_get_type(c_req->async.private_data,
288 s->status = wins_challenge_recv(c_req, s, &s->io);
291 * if the owner denies it holds the name, then allow
294 if (!NT_STATUS_IS_OK(s->status)) {
299 if (s->new_type == WREPL_TYPE_GROUP || s->new_type == WREPL_TYPE_SGROUP) {
300 DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
301 nbt_name_string(s, s->rec->name), s->new_type, s->rec->type));
307 * if the owner still wants the name and doesn't reply
308 * with the address trying to be registered, then deny
312 for (i=0; i < s->io.out.num_addresses; i++) {
313 if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
329 a client has asked to register a unique name that someone else owns. We
330 need to ask each of the current owners if they still want it. If they do
331 then reject the registration, otherwise allow it
333 static void wins_register_wack(struct nbt_name_socket *nbtsock,
334 struct nbt_name_packet *packet,
335 struct winsdb_record *rec,
336 struct socket_address *src,
337 enum wrepl_name_type new_type)
339 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
340 struct nbtd_interface);
341 struct wins_server *winssrv = iface->nbtsrv->winssrv;
342 struct wack_state *s;
343 struct composite_context *c_req;
346 s = talloc_zero(nbtsock, struct wack_state);
347 if (s == NULL) goto failed;
349 /* package up the state variables for this wack request */
350 s->winssrv = winssrv;
351 s->nbtsock = nbtsock;
352 s->request_packet = talloc_steal(s, packet);
353 s->rec = talloc_steal(s, rec);
354 s->reg_address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
355 s->new_type = new_type;
357 if (talloc_reference(s, src) == NULL) goto failed;
359 s->io.in.nbtd_server = iface->nbtsrv;
360 s->io.in.event_ctx = iface->nbtsrv->task->event_ctx;
361 s->io.in.name = rec->name;
362 s->io.in.num_addresses = winsdb_addr_list_length(rec->addresses);
363 s->io.in.addresses = winsdb_addr_string_list(s, rec->addresses);
364 if (s->io.in.addresses == NULL) goto failed;
367 * send a WACK to the client, specifying the maximum time it could
368 * take to check with the owner, plus some slack
370 ttl = 5 + 4 * winsdb_addr_list_length(rec->addresses);
371 nbtd_wack_reply(nbtsock, packet, src, ttl);
374 * send the challenge to the old addresses
376 c_req = wins_challenge_send(s, &s->io);
377 if (c_req == NULL) goto failed;
379 c_req->async.fn = wack_wins_challenge_handler;
380 c_req->async.private_data = s;
385 nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR);
391 static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
392 struct nbt_name_packet *packet,
393 struct socket_address *src)
396 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
397 struct nbtd_interface);
398 struct wins_server *winssrv = iface->nbtsrv->winssrv;
399 struct nbt_name *name = &packet->questions[0].name;
400 struct winsdb_record *rec;
401 uint8_t rcode = NBT_RCODE_OK;
402 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
403 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
404 BOOL mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
405 enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
406 struct winsdb_addr *winsdb_addr = NULL;
409 * as a special case, the local master browser name is always accepted
410 * for registration, but never stored, but w2k3 stores it if it's registered
411 * as a group name, (but a query for the 0x1D name still returns not found!)
413 if (name->type == NBT_NAME_MASTER && !(nb_flags & NBT_NM_GROUP)) {
414 rcode = NBT_RCODE_OK;
418 /* w2k3 refuses 0x1B names with marked as group */
419 if (name->type == NBT_NAME_PDC && (nb_flags & NBT_NM_GROUP)) {
420 rcode = NBT_RCODE_RFS;
424 /* w2k3 refuses 0x1C names with out marked as group */
425 if (name->type == NBT_NAME_LOGON && !(nb_flags & NBT_NM_GROUP)) {
426 rcode = NBT_RCODE_RFS;
430 /* w2k3 refuses 0x1E names with out marked as group */
431 if (name->type == NBT_NAME_BROWSER && !(nb_flags & NBT_NM_GROUP)) {
432 rcode = NBT_RCODE_RFS;
436 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
437 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
438 rcode = wins_register_new(nbtsock, packet, src, new_type);
440 } else if (!NT_STATUS_IS_OK(status)) {
441 rcode = NBT_RCODE_SVR;
443 } else if (rec->is_static) {
444 if (rec->type == WREPL_TYPE_GROUP || rec->type == WREPL_TYPE_SGROUP) {
445 rcode = NBT_RCODE_OK;
448 rcode = NBT_RCODE_ACT;
452 if (rec->type == WREPL_TYPE_GROUP) {
453 if (new_type != WREPL_TYPE_GROUP) {
454 DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
455 " while a normal group is already there\n",
456 nbt_name_string(packet, name), new_type));
457 rcode = NBT_RCODE_ACT;
461 if (rec->state == WREPL_STATE_ACTIVE) {
462 /* TODO: is this correct? */
463 rcode = wins_update_ttl(nbtsock, packet, rec, NULL, src);
467 /* TODO: is this correct? */
468 winsdb_delete(winssrv->wins_db, rec);
469 rcode = wins_register_new(nbtsock, packet, src, new_type);
473 if (rec->state != WREPL_STATE_ACTIVE) {
474 winsdb_delete(winssrv->wins_db, rec);
475 rcode = wins_register_new(nbtsock, packet, src, new_type);
480 case WREPL_TYPE_UNIQUE:
481 case WREPL_TYPE_MHOMED:
483 * if its an active unique name, and the registration is for a group, then
484 * see if the unique name owner still wants the name
485 * TODO: is this correct?
487 if (new_type == WREPL_TYPE_GROUP || new_type == WREPL_TYPE_GROUP) {
488 wins_register_wack(nbtsock, packet, rec, src, new_type);
493 * if the registration is for an address that is currently active, then
494 * just update the expiry time of the record and the address
496 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
498 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
503 * we have to do a WACK to see if the current owner is willing
504 * to give up its claim
506 wins_register_wack(nbtsock, packet, rec, src, new_type);
509 case WREPL_TYPE_GROUP:
510 /* this should not be reached as normal groups are handled above */
511 DEBUG(0,("BUG at %s\n",__location__));
512 rcode = NBT_RCODE_ACT;
515 case WREPL_TYPE_SGROUP:
516 /* if the new record isn't also a special group, refuse the registration */
517 if (new_type != WREPL_TYPE_SGROUP) {
518 DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
519 " while a special group is already there\n",
520 nbt_name_string(packet, name), new_type));
521 rcode = NBT_RCODE_ACT;
526 * if the registration is for an address that is currently active, then
527 * just update the expiry time of the record and the address
529 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
531 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
535 rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
540 nbtd_name_registration_reply(nbtsock, packet, src, rcode);
546 static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock,
547 struct nbt_name_packet *packet,
548 struct socket_address *src)
551 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
552 struct nbtd_interface);
553 struct wins_server *winssrv = iface->nbtsrv->winssrv;
554 struct nbt_name *name = &packet->questions[0].name;
555 struct winsdb_record *rec;
556 struct winsdb_record *rec_1b = NULL;
557 const char **addresses;
558 const char **addresses_1b = NULL;
559 uint16_t nb_flags = 0;
561 if (name->type == NBT_NAME_MASTER) {
566 * w2k3 returns the first address of the 0x1B record as first address
569 if (name->type == NBT_NAME_LOGON) {
570 struct nbt_name name_1b;
573 name_1b.type = NBT_NAME_PDC;
575 status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
576 if (NT_STATUS_IS_OK(status)) {
577 addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
581 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
582 if (!NT_STATUS_IS_OK(status)) {
583 if (!lp_wins_dns_proxy()) {
587 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
591 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
596 * for group's we always reply with
597 * 255.255.255.255 as address, even if
598 * the record is released or tombstoned
600 if (rec->type == WREPL_TYPE_GROUP) {
601 addresses = str_list_add(NULL, "255.255.255.255");
602 talloc_steal(packet, addresses);
606 nb_flags |= NBT_NM_GROUP;
610 if (rec->state != WREPL_STATE_ACTIVE) {
614 addresses = winsdb_addr_string_list(packet, rec->addresses);
620 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
621 * first 0x1B address as first address
623 if (addresses_1b && addresses_1b[0]) {
624 const char **addresses_1c = addresses;
627 addresses = str_list_add(NULL, addresses_1b[0]);
631 talloc_steal(packet, addresses);
633 for (i=0; addresses_1c[i]; i++) {
634 if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
636 addresses = str_list_add(addresses, addresses_1c[i]);
643 if (rec->type == WREPL_TYPE_SGROUP) {
644 nb_flags |= NBT_NM_GROUP;
646 nb_flags |= (rec->node <<13);
650 nbtd_name_query_reply(nbtsock, packet, src, name,
651 0, nb_flags, addresses);
655 nbtd_negative_name_query_reply(nbtsock, packet, src);
661 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
662 struct nbt_name_packet *packet,
663 struct socket_address *src)
666 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
667 struct nbtd_interface);
668 struct wins_server *winssrv = iface->nbtsrv->winssrv;
669 struct nbt_name *name = &packet->questions[0].name;
670 struct winsdb_record *rec;
671 uint32_t modify_flags = 0;
674 if (name->type == NBT_NAME_MASTER) {
678 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
679 if (!NT_STATUS_IS_OK(status)) {
683 if (rec->is_static) {
684 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
687 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
691 if (rec->state != WREPL_STATE_ACTIVE) {
696 * TODO: do we need to check if
697 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
702 * we only allow releases from an owner - other releases are
705 if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
707 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
708 DEBUGADD(4, ("Registered Addressss: \n"));
709 for (i=0; rec->addresses && rec->addresses[i]; i++) {
710 DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
715 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
718 case WREPL_TYPE_UNIQUE:
719 rec->state = WREPL_STATE_RELEASED;
722 case WREPL_TYPE_GROUP:
723 rec->state = WREPL_STATE_RELEASED;
726 case WREPL_TYPE_SGROUP:
727 winsdb_addr_list_remove(rec->addresses, src->addr);
728 /* TODO: do we need to take the ownership here? */
729 if (winsdb_addr_list_length(rec->addresses) == 0) {
730 rec->state = WREPL_STATE_RELEASED;
734 case WREPL_TYPE_MHOMED:
735 winsdb_addr_list_remove(rec->addresses, src->addr);
736 /* TODO: do we need to take the ownership here? */
737 if (winsdb_addr_list_length(rec->addresses) == 0) {
738 rec->state = WREPL_STATE_RELEASED;
743 if (rec->state == WREPL_STATE_RELEASED) {
745 * if we're not the owner, we need to take the owner ship
746 * and make the record tombstone, but expire after
747 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
748 * like for normal tombstone records.
749 * This is to replicate the record directly to the original owner,
750 * where the record is still active
752 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
753 rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
755 rec->state = WREPL_STATE_TOMBSTONE;
756 rec->expire_time= time(NULL) +
757 winssrv->config.tombstone_interval +
758 winssrv->config.tombstone_timeout;
759 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
763 ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
764 if (ret != NBT_RCODE_OK) {
765 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
766 nbt_name_string(rec, rec->name), src->addr, ret));
769 /* we match w2k3 by always giving a positive reply to name releases. */
770 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
777 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
778 struct nbt_name_packet *packet,
779 struct socket_address *src)
781 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
782 struct nbtd_interface);
783 struct wins_server *winssrv = iface->nbtsrv->winssrv;
784 if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
788 switch (packet->operation & NBT_OPCODE) {
789 case NBT_OPCODE_QUERY:
790 nbtd_winsserver_query(nbtsock, packet, src);
793 case NBT_OPCODE_REGISTER:
794 case NBT_OPCODE_REFRESH:
795 case NBT_OPCODE_REFRESH2:
796 case NBT_OPCODE_MULTI_HOME_REG:
797 nbtd_winsserver_register(nbtsock, packet, src);
800 case NBT_OPCODE_RELEASE:
801 nbtd_winsserver_release(nbtsock, packet, src);
808 startup the WINS server, if configured
810 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
814 if (!lp_wins_support()) {
815 nbtsrv->winssrv = NULL;
819 nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
820 NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
822 nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl();
823 nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl();
824 tmp = lp_parm_int(-1,"wreplsrv","tombstone_interval", 6*24*60*60);
825 nbtsrv->winssrv->config.tombstone_interval = tmp;
826 tmp = lp_parm_int(-1,"wreplsrv","tombstone_timeout", 1*24*60*60);
827 nbtsrv->winssrv->config.tombstone_timeout = tmp;
829 nbtsrv->winssrv->wins_db = winsdb_connect(nbtsrv->winssrv, WINSDB_HANDLE_CALLER_NBTD);
830 if (!nbtsrv->winssrv->wins_db) {
831 return NT_STATUS_INTERNAL_DB_ERROR;
834 irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");