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
495 * TODO: is this correct?
497 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
499 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
504 * we have to do a WACK to see if the current owner is willing
505 * to give up its claim
507 wins_register_wack(nbtsock, packet, rec, src, new_type);
510 case WREPL_TYPE_GROUP:
511 /* this should not be reached as normal groups are handled above */
512 DEBUG(0,("BUG at %s\n",__location__));
513 rcode = NBT_RCODE_ACT;
516 case WREPL_TYPE_SGROUP:
517 /* if the new record isn't also a special group, refuse the registration */
518 if (new_type != WREPL_TYPE_SGROUP) {
519 DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
520 " while a special group is already there\n",
521 nbt_name_string(packet, name), new_type));
522 rcode = NBT_RCODE_ACT;
527 * if the registration is for an address that is currently active, then
528 * just update the expiry time
529 * just update the expiry time of the record and the address
530 * TODO: is this correct?
532 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
534 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
538 rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
543 nbtd_name_registration_reply(nbtsock, packet, src, rcode);
549 static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock,
550 struct nbt_name_packet *packet,
551 struct socket_address *src)
554 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
555 struct nbtd_interface);
556 struct wins_server *winssrv = iface->nbtsrv->winssrv;
557 struct nbt_name *name = &packet->questions[0].name;
558 struct winsdb_record *rec;
559 struct winsdb_record *rec_1b = NULL;
560 const char **addresses;
561 const char **addresses_1b = NULL;
562 uint16_t nb_flags = 0;
564 if (name->type == NBT_NAME_MASTER) {
569 * w2k3 returns the first address of the 0x1B record as first address
572 if (name->type == NBT_NAME_LOGON) {
573 struct nbt_name name_1b;
576 name_1b.type = NBT_NAME_PDC;
578 status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
579 if (NT_STATUS_IS_OK(status)) {
580 addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
584 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
585 if (!NT_STATUS_IS_OK(status)) {
586 if (!lp_wins_dns_proxy()) {
590 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
594 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
599 * for group's we always reply with
600 * 255.255.255.255 as address, even if
601 * the record is released or tombstoned
603 if (rec->type == WREPL_TYPE_GROUP) {
604 addresses = str_list_add(NULL, "255.255.255.255");
605 talloc_steal(packet, addresses);
609 nb_flags |= NBT_NM_GROUP;
613 if (rec->state != WREPL_STATE_ACTIVE) {
617 addresses = winsdb_addr_string_list(packet, rec->addresses);
623 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
624 * first 0x1B address as first address
626 if (addresses_1b && addresses_1b[0]) {
627 const char **addresses_1c = addresses;
630 addresses = str_list_add(NULL, addresses_1b[0]);
634 talloc_steal(packet, addresses);
636 for (i=0; addresses_1c[i]; i++) {
637 if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
639 addresses = str_list_add(addresses, addresses_1c[i]);
646 if (rec->type == WREPL_TYPE_SGROUP) {
647 nb_flags |= NBT_NM_GROUP;
649 nb_flags |= (rec->node <<13);
653 nbtd_name_query_reply(nbtsock, packet, src, name,
654 0, nb_flags, addresses);
658 nbtd_negative_name_query_reply(nbtsock, packet, src);
664 static void nbtd_winsserver_release(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 uint32_t modify_flags = 0;
677 if (name->type == NBT_NAME_MASTER) {
681 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
682 if (!NT_STATUS_IS_OK(status)) {
686 if (rec->is_static) {
687 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
690 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
694 if (rec->state != WREPL_STATE_ACTIVE) {
699 * TODO: do we need to check if
700 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
705 * we only allow releases from an owner - other releases are
708 if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
710 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
711 DEBUGADD(4, ("Registered Addressss: \n"));
712 for (i=0; rec->addresses && rec->addresses[i]; i++) {
713 DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
718 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
721 case WREPL_TYPE_UNIQUE:
722 rec->state = WREPL_STATE_RELEASED;
725 case WREPL_TYPE_GROUP:
726 rec->state = WREPL_STATE_RELEASED;
729 case WREPL_TYPE_SGROUP:
730 winsdb_addr_list_remove(rec->addresses, src->addr);
731 /* TODO: do we need to take the ownership here? */
732 if (winsdb_addr_list_length(rec->addresses) == 0) {
733 rec->state = WREPL_STATE_RELEASED;
737 case WREPL_TYPE_MHOMED:
738 winsdb_addr_list_remove(rec->addresses, src->addr);
739 /* TODO: do we need to take the ownership here? */
740 if (winsdb_addr_list_length(rec->addresses) == 0) {
741 rec->state = WREPL_STATE_RELEASED;
746 if (rec->state == WREPL_STATE_RELEASED) {
748 * if we're not the owner, we need to take the owner ship
749 * and make the record tombstone, but expire after
750 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
751 * like for normal tombstone records.
752 * This is to replicate the record directly to the original owner,
753 * where the record is still active
755 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
756 rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
758 rec->state = WREPL_STATE_TOMBSTONE;
759 rec->expire_time= time(NULL) +
760 winssrv->config.tombstone_interval +
761 winssrv->config.tombstone_timeout;
762 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
766 ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
767 if (ret != NBT_RCODE_OK) {
768 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
769 nbt_name_string(rec, rec->name), src->addr, ret));
772 /* we match w2k3 by always giving a positive reply to name releases. */
773 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
780 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
781 struct nbt_name_packet *packet,
782 struct socket_address *src)
784 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
785 struct nbtd_interface);
786 struct wins_server *winssrv = iface->nbtsrv->winssrv;
787 if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
791 switch (packet->operation & NBT_OPCODE) {
792 case NBT_OPCODE_QUERY:
793 nbtd_winsserver_query(nbtsock, packet, src);
796 case NBT_OPCODE_REGISTER:
797 case NBT_OPCODE_REFRESH:
798 case NBT_OPCODE_REFRESH2:
799 case NBT_OPCODE_MULTI_HOME_REG:
800 nbtd_winsserver_register(nbtsock, packet, src);
803 case NBT_OPCODE_RELEASE:
804 nbtd_winsserver_release(nbtsock, packet, src);
811 startup the WINS server, if configured
813 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
817 if (!lp_wins_support()) {
818 nbtsrv->winssrv = NULL;
822 nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
823 NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
825 nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl();
826 nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl();
827 tmp = lp_parm_int(-1,"wreplsrv","tombstone_interval", 6*24*60*60);
828 nbtsrv->winssrv->config.tombstone_interval = tmp;
829 tmp = lp_parm_int(-1,"wreplsrv","tombstone_timeout", 1*24*60*60);
830 nbtsrv->winssrv->config.tombstone_timeout = tmp;
832 nbtsrv->winssrv->wins_db = winsdb_connect(nbtsrv->winssrv, WINSDB_HANDLE_CALLER_NBTD);
833 if (!nbtsrv->winssrv->wins_db) {
834 return NT_STATUS_INTERNAL_DB_ERROR;
837 irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");