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"
33 work out the ttl we will use given a client requested ttl
35 uint32_t wins_server_ttl(struct wins_server *winssrv, uint32_t ttl)
37 ttl = MIN(ttl, winssrv->config.max_renew_interval);
38 ttl = MAX(ttl, winssrv->config.min_renew_interval);
42 static enum wrepl_name_type wrepl_type(uint16_t nb_flags, struct nbt_name *name, BOOL mhomed)
44 /* this copes with the nasty hack that is the type 0x1c name */
45 if (name->type == NBT_NAME_LOGON) {
46 return WREPL_TYPE_SGROUP;
48 if (nb_flags & NBT_NM_GROUP) {
49 return WREPL_TYPE_GROUP;
52 return WREPL_TYPE_MHOMED;
54 return WREPL_TYPE_UNIQUE;
58 register a new name with WINS
60 static uint8_t wins_register_new(struct nbt_name_socket *nbtsock,
61 struct nbt_name_packet *packet,
62 const struct nbt_peer_socket *src,
63 enum wrepl_name_type type)
65 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
66 struct nbtd_interface);
67 struct wins_server *winssrv = iface->nbtsrv->winssrv;
68 struct nbt_name *name = &packet->questions[0].name;
69 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
70 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
71 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
72 struct winsdb_record rec;
73 enum wrepl_name_node node;
75 #define WREPL_NODE_NBT_FLAGS(nb_flags) \
76 ((nb_flags & NBT_NM_OWNER_TYPE)>>13)
78 node = WREPL_NODE_NBT_FLAGS(nb_flags);
82 rec.state = WREPL_STATE_ACTIVE;
84 rec.is_static = False;
85 rec.expire_time = time(NULL) + ttl;
86 rec.version = 0; /* will be allocated later */
87 rec.wins_owner = NULL; /* will be set later */
88 rec.registered_by = src->addr;
89 rec.addresses = winsdb_addr_list_make(packet);
90 if (rec.addresses == NULL) return NBT_RCODE_SVR;
92 rec.addresses = winsdb_addr_list_add(rec.addresses,
94 winssrv->wins_db->local_owner,
96 if (rec.addresses == NULL) return NBT_RCODE_SVR;
98 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
99 nbt_name_string(packet, name), rec.addresses[0]->address));
101 return winsdb_add(winssrv->wins_db, &rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
106 update the ttl on an existing record
108 static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock,
109 struct nbt_name_packet *packet,
110 struct winsdb_record *rec,
111 struct winsdb_addr *winsdb_addr,
112 const struct nbt_peer_socket *src)
114 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
115 struct nbtd_interface);
116 struct wins_server *winssrv = iface->nbtsrv->winssrv;
117 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
118 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
119 uint32_t modify_flags = 0;
121 rec->expire_time = time(NULL) + ttl;
122 rec->registered_by = src->addr;
125 winsdb_addr->wins_owner = winssrv->wins_db->local_owner;
126 winsdb_addr->expire_time = rec->expire_time;
129 if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) {
130 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
133 DEBUG(5,("WINS: refreshed registration of %s at %s\n",
134 nbt_name_string(packet, rec->name), address));
136 return winsdb_modify(winssrv->wins_db, rec, modify_flags);
142 static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
143 struct nbt_name_packet *packet,
144 struct winsdb_record *rec,
146 const struct nbt_peer_socket *src)
148 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
149 struct nbtd_interface);
150 struct wins_server *winssrv = iface->nbtsrv->winssrv;
151 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
153 rec->expire_time = time(NULL) + ttl;
154 rec->registered_by = src->addr;
156 rec->addresses = winsdb_addr_list_add(rec->addresses,
158 winssrv->wins_db->local_owner,
160 if (rec->addresses == NULL) return NBT_RCODE_SVR;
162 DEBUG(5,("WINS: sgroup merge of %s at %s\n",
163 nbt_name_string(packet, rec->name), address));
165 return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
169 struct wins_server *winssrv;
170 struct nbt_name_socket *nbtsock;
171 struct nbt_name_packet *request_packet;
172 struct winsdb_record *rec;
173 struct nbt_peer_socket src;
174 const char *reg_address;
175 enum wrepl_name_type new_type;
176 struct wins_challenge_io io;
181 deny a registration request
183 static void wins_wack_deny(struct wack_state *s)
185 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
186 &s->src, NBT_RCODE_ACT);
187 DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
188 nbt_name_string(s, s->rec->name), s->src.addr, s->src.port));
193 allow a registration request
195 static void wins_wack_allow(struct wack_state *s)
198 uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
199 struct winsdb_record *rec = s->rec, *rec2;
202 status = winsdb_lookup(s->winssrv->wins_db, rec->name, s, &rec2);
203 if (!NT_STATUS_IS_OK(status) ||
204 rec2->version != rec->version ||
205 strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
206 DEBUG(1,("WINS: record %s changed during WACK - failing registration\n",
207 nbt_name_string(s, rec->name)));
213 * if the old name owner doesn't hold the name anymore
214 * handle the request as new registration for the new name owner
216 if (!NT_STATUS_IS_OK(s->status)) {
219 winsdb_delete(s->winssrv->wins_db, rec);
220 rcode = wins_register_new(s->nbtsock, s->request_packet, &s->src, s->new_type);
221 if (rcode != NBT_RCODE_OK) {
222 DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
223 nbt_name_string(s, rec->name)));
230 rec->expire_time = time(NULL) + ttl;
231 rec->registered_by = s->src.addr;
234 * now remove all addresses that're the client doesn't hold anymore
235 * and update the time stamp and owner for the ownes that are still there
237 for (i=0; rec->addresses[i]; i++) {
239 for (j=0; j < s->io.out.num_addresses; j++) {
240 if (strcmp(rec->addresses[i]->address, s->io.out.addresses[j]) != 0) continue;
246 rec->addresses[i]->wins_owner = s->winssrv->wins_db->local_owner;
247 rec->addresses[i]->expire_time = rec->expire_time;
251 winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
254 rec->addresses = winsdb_addr_list_add(rec->addresses,
256 s->winssrv->wins_db->local_owner,
258 if (rec->addresses == NULL) goto failed;
260 /* if we have more than one address, this becomes implicit a MHOMED record */
261 if (winsdb_addr_list_length(rec->addresses) > 1) {
262 rec->type = WREPL_TYPE_MHOMED;
265 winsdb_modify(s->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
267 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
268 nbt_name_string(s, rec->name), s->reg_address));
271 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
272 &s->src, NBT_RCODE_OK);
278 called when a name query to a current owner completes
280 static void wack_wins_challenge_handler(struct composite_context *c_req)
282 struct wack_state *s = talloc_get_type(c_req->async.private_data,
287 s->status = wins_challenge_recv(c_req, s, &s->io);
290 * if the owner denies it holds the name, then allow
293 if (!NT_STATUS_IS_OK(s->status)) {
298 if (s->new_type == WREPL_TYPE_GROUP || s->new_type == WREPL_TYPE_SGROUP) {
299 DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
300 nbt_name_string(s, s->rec->name), s->new_type, s->rec->type));
306 * if the owner still wants the name and doesn't reply
307 * with the address trying to be registered, then deny
311 for (i=0; i < s->io.out.num_addresses; i++) {
312 if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
328 a client has asked to register a unique name that someone else owns. We
329 need to ask each of the current owners if they still want it. If they do
330 then reject the registration, otherwise allow it
332 static void wins_register_wack(struct nbt_name_socket *nbtsock,
333 struct nbt_name_packet *packet,
334 struct winsdb_record *rec,
335 const struct nbt_peer_socket *src,
336 enum wrepl_name_type new_type)
338 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
339 struct nbtd_interface);
340 struct wins_server *winssrv = iface->nbtsrv->winssrv;
341 struct wack_state *s;
342 struct composite_context *c_req;
345 s = talloc_zero(nbtsock, struct wack_state);
346 if (s == NULL) goto failed;
348 /* package up the state variables for this wack request */
349 s->winssrv = winssrv;
350 s->nbtsock = nbtsock;
351 s->request_packet = talloc_steal(s, packet);
352 s->rec = talloc_steal(s, rec);
353 s->reg_address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
354 s->new_type = new_type;
355 s->src.port = src->port;
356 s->src.addr = talloc_strdup(s, src->addr);
357 if (s->src.addr == 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 const struct nbt_peer_socket *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 const struct nbt_peer_socket *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; /* TODO: ... */
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)) {
590 * for group's we always reply with
591 * 255.255.255.255 as address, even if
592 * the record is released or tombstoned
594 if (rec->type == WREPL_TYPE_GROUP) {
595 addresses = talloc_array(packet, const char *, 2);
596 if (addresses == NULL) {
597 nbtd_negative_name_query_reply(nbtsock, packet, src);
600 addresses[0] = "255.255.255.255";
605 if (rec->state != WREPL_STATE_ACTIVE) {
609 addresses = winsdb_addr_string_list(packet, rec->addresses);
615 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
616 * first 0x1B address as first address
618 if (addresses_1b && addresses_1b[0]) {
619 const char **addresses_1c = addresses;
622 addresses = str_list_add(NULL, addresses_1b[0]);
626 talloc_steal(packet, addresses);
628 for (i=0; addresses_1c[i]; i++) {
629 if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
631 addresses = str_list_add(addresses, addresses_1c[i]);
639 nbtd_name_query_reply(nbtsock, packet, src, name,
640 0, nb_flags, addresses);
644 nbtd_negative_name_query_reply(nbtsock, packet, src);
650 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
651 struct nbt_name_packet *packet,
652 const struct nbt_peer_socket *src)
655 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
656 struct nbtd_interface);
657 struct wins_server *winssrv = iface->nbtsrv->winssrv;
658 struct nbt_name *name = &packet->questions[0].name;
659 struct winsdb_record *rec;
660 uint32_t modify_flags = 0;
663 if (name->type == NBT_NAME_MASTER) {
667 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
668 if (!NT_STATUS_IS_OK(status)) {
672 if (rec->is_static) {
673 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
676 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
680 if (rec->state != WREPL_STATE_ACTIVE) {
685 * TODO: do we need to check if
686 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
691 * we only allow releases from an owner - other releases are
694 if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
698 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
701 case WREPL_TYPE_UNIQUE:
702 rec->state = WREPL_STATE_RELEASED;
705 case WREPL_TYPE_GROUP:
706 rec->state = WREPL_STATE_RELEASED;
709 case WREPL_TYPE_SGROUP:
710 winsdb_addr_list_remove(rec->addresses, src->addr);
711 /* TODO: do we need to take the ownership here? */
712 if (winsdb_addr_list_length(rec->addresses) == 0) {
713 rec->state = WREPL_STATE_RELEASED;
717 case WREPL_TYPE_MHOMED:
718 winsdb_addr_list_remove(rec->addresses, src->addr);
719 /* TODO: do we need to take the ownership here? */
720 if (winsdb_addr_list_length(rec->addresses) == 0) {
721 rec->state = WREPL_STATE_RELEASED;
726 if (rec->state == WREPL_STATE_RELEASED) {
727 rec->expire_time = time(NULL) + winssrv->config.tombstone_interval;
730 ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
731 if (ret != NBT_RCODE_OK) {
732 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
733 nbt_name_string(rec, rec->name), src->addr, ret));
736 /* we match w2k3 by always giving a positive reply to name releases. */
737 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
744 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
745 struct nbt_name_packet *packet,
746 const struct nbt_peer_socket *src)
748 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
749 struct nbtd_interface);
750 struct wins_server *winssrv = iface->nbtsrv->winssrv;
751 if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
755 switch (packet->operation & NBT_OPCODE) {
756 case NBT_OPCODE_QUERY:
757 nbtd_winsserver_query(nbtsock, packet, src);
760 case NBT_OPCODE_REGISTER:
761 case NBT_OPCODE_REFRESH:
762 case NBT_OPCODE_REFRESH2:
763 case NBT_OPCODE_MULTI_HOME_REG:
764 nbtd_winsserver_register(nbtsock, packet, src);
767 case NBT_OPCODE_RELEASE:
768 nbtd_winsserver_release(nbtsock, packet, src);
775 startup the WINS server, if configured
777 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
779 uint32_t tombstone_interval;
781 if (!lp_wins_support()) {
782 nbtsrv->winssrv = NULL;
786 nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
787 NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
789 nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl();
790 nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl();
791 tombstone_interval = lp_parm_int(-1,"wreplsrv","tombstone_interval", 6*24*60*60);
792 nbtsrv->winssrv->config.tombstone_interval = tombstone_interval;
794 nbtsrv->winssrv->wins_db = winsdb_connect(nbtsrv->winssrv);
795 if (!nbtsrv->winssrv->wins_db) {
796 return NT_STATUS_INTERNAL_DB_ERROR;
799 irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");