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 "lib/util/dlinklist.h"
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 "system/network.h"
33 #include "lib/socket/socket.h"
34 #include "lib/socket/netif.h"
35 #include "lib/ldb/include/ldb.h"
36 #include "param/param.h"
37 #include "libcli/resolve/resolve.h"
40 work out the ttl we will use given a client requested ttl
42 uint32_t wins_server_ttl(struct wins_server
*winssrv
, uint32_t ttl
)
44 ttl
= MIN(ttl
, winssrv
->config
.max_renew_interval
);
45 ttl
= MAX(ttl
, winssrv
->config
.min_renew_interval
);
49 static enum wrepl_name_type
wrepl_type(uint16_t nb_flags
, struct nbt_name
*name
, bool mhomed
)
51 /* this copes with the nasty hack that is the type 0x1c name */
52 if (name
->type
== NBT_NAME_LOGON
) {
53 return WREPL_TYPE_SGROUP
;
55 if (nb_flags
& NBT_NM_GROUP
) {
56 return WREPL_TYPE_GROUP
;
59 return WREPL_TYPE_MHOMED
;
61 return WREPL_TYPE_UNIQUE
;
65 register a new name with WINS
67 static uint8_t wins_register_new(struct nbt_name_socket
*nbtsock
,
68 struct nbt_name_packet
*packet
,
69 const struct socket_address
*src
,
70 enum wrepl_name_type type
)
72 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
73 struct nbtd_interface
);
74 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
75 struct nbt_name
*name
= &packet
->questions
[0].name
;
76 uint32_t ttl
= wins_server_ttl(winssrv
, packet
->additional
[0].ttl
);
77 uint16_t nb_flags
= packet
->additional
[0].rdata
.netbios
.addresses
[0].nb_flags
;
78 const char *address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
79 struct winsdb_record rec
;
80 enum wrepl_name_node node
;
82 #define WREPL_NODE_NBT_FLAGS(nb_flags) \
83 ((nb_flags & NBT_NM_OWNER_TYPE)>>13)
85 node
= WREPL_NODE_NBT_FLAGS(nb_flags
);
89 rec
.state
= WREPL_STATE_ACTIVE
;
91 rec
.is_static
= false;
92 rec
.expire_time
= time(NULL
) + ttl
;
93 rec
.version
= 0; /* will be allocated later */
94 rec
.wins_owner
= NULL
; /* will be set later */
95 rec
.registered_by
= src
->addr
;
96 rec
.addresses
= winsdb_addr_list_make(packet
);
97 if (rec
.addresses
== NULL
) return NBT_RCODE_SVR
;
99 rec
.addresses
= winsdb_addr_list_add(winssrv
->wins_db
,
102 winssrv
->wins_db
->local_owner
,
105 if (rec
.addresses
== NULL
) return NBT_RCODE_SVR
;
107 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
108 nbt_name_string(packet
, name
), rec
.addresses
[0]->address
));
110 return winsdb_add(winssrv
->wins_db
, &rec
, WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
);
115 update the ttl on an existing record
117 static uint8_t wins_update_ttl(struct nbt_name_socket
*nbtsock
,
118 struct nbt_name_packet
*packet
,
119 struct winsdb_record
*rec
,
120 struct winsdb_addr
*winsdb_addr
,
121 const struct socket_address
*src
)
123 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
124 struct nbtd_interface
);
125 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
126 uint32_t ttl
= wins_server_ttl(winssrv
, packet
->additional
[0].ttl
);
127 const char *address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
128 uint32_t modify_flags
= 0;
130 rec
->expire_time
= time(NULL
) + ttl
;
131 rec
->registered_by
= src
->addr
;
134 rec
->addresses
= winsdb_addr_list_add(winssrv
->wins_db
,
136 winsdb_addr
->address
,
137 winssrv
->wins_db
->local_owner
,
140 if (rec
->addresses
== NULL
) return NBT_RCODE_SVR
;
143 if (strcmp(winssrv
->wins_db
->local_owner
, rec
->wins_owner
) != 0) {
144 modify_flags
= WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
;
147 DEBUG(5,("WINS: refreshed registration of %s at %s\n",
148 nbt_name_string(packet
, rec
->name
), address
));
150 return winsdb_modify(winssrv
->wins_db
, rec
, modify_flags
);
156 static uint8_t wins_sgroup_merge(struct nbt_name_socket
*nbtsock
,
157 struct nbt_name_packet
*packet
,
158 struct winsdb_record
*rec
,
160 const struct socket_address
*src
)
162 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
163 struct nbtd_interface
);
164 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
165 uint32_t ttl
= wins_server_ttl(winssrv
, packet
->additional
[0].ttl
);
167 rec
->expire_time
= time(NULL
) + ttl
;
168 rec
->registered_by
= src
->addr
;
170 rec
->addresses
= winsdb_addr_list_add(winssrv
->wins_db
,
173 winssrv
->wins_db
->local_owner
,
176 if (rec
->addresses
== NULL
) return NBT_RCODE_SVR
;
178 DEBUG(5,("WINS: sgroup merge of %s at %s\n",
179 nbt_name_string(packet
, rec
->name
), address
));
181 return winsdb_modify(winssrv
->wins_db
, rec
, WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
);
184 struct nbtd_wins_wack_state
{
185 struct nbtd_wins_wack_state
*prev
, *next
;
186 struct wins_server
*winssrv
;
187 struct nbt_name_socket
*nbtsock
;
188 struct nbtd_interface
*iface
;
189 struct nbt_name_packet
*request_packet
;
190 struct winsdb_record
*rec
;
191 struct socket_address
*src
;
192 const char *reg_address
;
193 enum wrepl_name_type new_type
;
194 struct wins_challenge_io io
;
198 static int nbtd_wins_wack_state_destructor(struct nbtd_wins_wack_state
*s
)
200 DLIST_REMOVE(s
->iface
->wack_queue
, s
);
204 static bool wins_check_wack_queue(struct nbtd_interface
*iface
,
205 struct nbt_name_packet
*packet
,
206 struct socket_address
*src
)
208 struct nbtd_wins_wack_state
*s
;
210 for (s
= iface
->wack_queue
; s
; s
= s
->next
) {
211 if (packet
->name_trn_id
!= s
->request_packet
->name_trn_id
) {
214 if (packet
->operation
!= s
->request_packet
->operation
) {
217 if (src
->port
!= s
->src
->port
) {
220 if (strcmp(src
->addr
, s
->src
->addr
) != 0) {
231 deny a registration request
233 static void wins_wack_deny(struct nbtd_wins_wack_state
*s
)
235 nbtd_name_registration_reply(s
->nbtsock
, s
->request_packet
,
236 s
->src
, NBT_RCODE_ACT
);
237 DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
238 nbt_name_string(s
, s
->rec
->name
), s
->src
->addr
, s
->src
->port
));
243 allow a registration request
245 static void wins_wack_allow(struct nbtd_wins_wack_state
*s
)
248 uint32_t ttl
= wins_server_ttl(s
->winssrv
, s
->request_packet
->additional
[0].ttl
);
249 struct winsdb_record
*rec
= s
->rec
, *rec2
;
252 status
= winsdb_lookup(s
->winssrv
->wins_db
, rec
->name
, s
, &rec2
);
253 if (!NT_STATUS_IS_OK(status
) ||
254 rec2
->version
!= rec
->version
||
255 strcmp(rec2
->wins_owner
, rec
->wins_owner
) != 0) {
256 DEBUG(5,("WINS: record %s changed during WACK - failing registration\n",
257 nbt_name_string(s
, rec
->name
)));
263 * if the old name owner doesn't hold the name anymore
264 * handle the request as new registration for the new name owner
266 if (!NT_STATUS_IS_OK(s
->status
)) {
269 winsdb_delete(s
->winssrv
->wins_db
, rec
);
270 rcode
= wins_register_new(s
->nbtsock
, s
->request_packet
, s
->src
, s
->new_type
);
271 if (rcode
!= NBT_RCODE_OK
) {
272 DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
273 nbt_name_string(s
, rec
->name
)));
280 rec
->expire_time
= time(NULL
) + ttl
;
281 rec
->registered_by
= s
->src
->addr
;
284 * now remove all addresses that the client doesn't hold anymore
285 * and update the time stamp and owner for the ones that are still there
287 for (i
=0; rec
->addresses
[i
]; i
++) {
289 for (j
=0; j
< s
->io
.out
.num_addresses
; j
++) {
290 if (strcmp(rec
->addresses
[i
]->address
, s
->io
.out
.addresses
[j
]) != 0) continue;
296 rec
->addresses
= winsdb_addr_list_add(s
->winssrv
->wins_db
,
299 s
->winssrv
->wins_db
->local_owner
,
302 if (rec
->addresses
== NULL
) goto failed
;
306 winsdb_addr_list_remove(rec
->addresses
, rec
->addresses
[i
]->address
);
309 rec
->addresses
= winsdb_addr_list_add(s
->winssrv
->wins_db
,
312 s
->winssrv
->wins_db
->local_owner
,
315 if (rec
->addresses
== NULL
) goto failed
;
317 /* if we have more than one address, this becomes implicit a MHOMED record */
318 if (winsdb_addr_list_length(rec
->addresses
) > 1) {
319 rec
->type
= WREPL_TYPE_MHOMED
;
322 winsdb_modify(s
->winssrv
->wins_db
, rec
, WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
);
324 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
325 nbt_name_string(s
, rec
->name
), s
->reg_address
));
328 nbtd_name_registration_reply(s
->nbtsock
, s
->request_packet
,
329 s
->src
, NBT_RCODE_OK
);
335 called when a name query to a current owner completes
337 static void wack_wins_challenge_handler(struct composite_context
*c_req
)
339 struct nbtd_wins_wack_state
*s
= talloc_get_type(c_req
->async
.private_data
,
340 struct nbtd_wins_wack_state
);
344 s
->status
= wins_challenge_recv(c_req
, s
, &s
->io
);
347 * if the owner denies it holds the name, then allow
350 if (!NT_STATUS_IS_OK(s
->status
)) {
355 if (s
->new_type
== WREPL_TYPE_GROUP
|| s
->new_type
== WREPL_TYPE_SGROUP
) {
356 DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
357 nbt_name_string(s
, s
->rec
->name
), s
->new_type
, s
->rec
->type
));
363 * if the owner still wants the name and doesn't reply
364 * with the address trying to be registered, then deny
368 for (i
=0; i
< s
->io
.out
.num_addresses
; i
++) {
369 if (strcmp(s
->reg_address
, s
->io
.out
.addresses
[i
]) != 0) continue;
385 a client has asked to register a unique name that someone else owns. We
386 need to ask each of the current owners if they still want it. If they do
387 then reject the registration, otherwise allow it
389 static void wins_register_wack(struct nbt_name_socket
*nbtsock
,
390 struct nbt_name_packet
*packet
,
391 struct winsdb_record
*rec
,
392 struct socket_address
*src
,
393 enum wrepl_name_type new_type
)
395 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
396 struct nbtd_interface
);
397 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
398 struct nbtd_wins_wack_state
*s
;
399 struct composite_context
*c_req
;
402 s
= talloc_zero(nbtsock
, struct nbtd_wins_wack_state
);
403 if (s
== NULL
) goto failed
;
405 /* package up the state variables for this wack request */
406 s
->winssrv
= winssrv
;
407 s
->nbtsock
= nbtsock
;
409 s
->request_packet
= talloc_steal(s
, packet
);
410 s
->rec
= talloc_steal(s
, rec
);
411 s
->reg_address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
412 s
->new_type
= new_type
;
414 if (talloc_reference(s
, src
) == NULL
) goto failed
;
416 s
->io
.in
.nbtd_server
= iface
->nbtsrv
;
417 s
->io
.in
.nbt_port
= lp_nbt_port(iface
->nbtsrv
->task
->lp_ctx
);
418 s
->io
.in
.event_ctx
= iface
->nbtsrv
->task
->event_ctx
;
419 s
->io
.in
.name
= rec
->name
;
420 s
->io
.in
.num_addresses
= winsdb_addr_list_length(rec
->addresses
);
421 s
->io
.in
.addresses
= winsdb_addr_string_list(s
, rec
->addresses
);
422 if (s
->io
.in
.addresses
== NULL
) goto failed
;
424 DLIST_ADD_END(iface
->wack_queue
, s
, struct nbtd_wins_wack_state
*);
426 talloc_set_destructor(s
, nbtd_wins_wack_state_destructor
);
429 * send a WACK to the client, specifying the maximum time it could
430 * take to check with the owner, plus some slack
432 ttl
= 5 + 4 * winsdb_addr_list_length(rec
->addresses
);
433 nbtd_wack_reply(nbtsock
, packet
, src
, ttl
);
436 * send the challenge to the old addresses
438 c_req
= wins_challenge_send(s
, &s
->io
);
439 if (c_req
== NULL
) goto failed
;
441 c_req
->async
.fn
= wack_wins_challenge_handler
;
442 c_req
->async
.private_data
= s
;
447 nbtd_name_registration_reply(nbtsock
, packet
, src
, NBT_RCODE_SVR
);
453 static void nbtd_winsserver_register(struct nbt_name_socket
*nbtsock
,
454 struct nbt_name_packet
*packet
,
455 struct socket_address
*src
)
458 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
459 struct nbtd_interface
);
460 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
461 struct nbt_name
*name
= &packet
->questions
[0].name
;
462 struct winsdb_record
*rec
;
463 uint8_t rcode
= NBT_RCODE_OK
;
464 uint16_t nb_flags
= packet
->additional
[0].rdata
.netbios
.addresses
[0].nb_flags
;
465 const char *address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
466 bool mhomed
= ((packet
->operation
& NBT_OPCODE
) == NBT_OPCODE_MULTI_HOME_REG
);
467 enum wrepl_name_type new_type
= wrepl_type(nb_flags
, name
, mhomed
);
468 struct winsdb_addr
*winsdb_addr
= NULL
;
469 bool duplicate_packet
;
472 * as a special case, the local master browser name is always accepted
473 * for registration, but never stored, but w2k3 stores it if it's registered
474 * as a group name, (but a query for the 0x1D name still returns not found!)
476 if (name
->type
== NBT_NAME_MASTER
&& !(nb_flags
& NBT_NM_GROUP
)) {
477 rcode
= NBT_RCODE_OK
;
481 /* w2k3 refuses 0x1B names with marked as group */
482 if (name
->type
== NBT_NAME_PDC
&& (nb_flags
& NBT_NM_GROUP
)) {
483 rcode
= NBT_RCODE_RFS
;
487 /* w2k3 refuses 0x1C names with out marked as group */
488 if (name
->type
== NBT_NAME_LOGON
&& !(nb_flags
& NBT_NM_GROUP
)) {
489 rcode
= NBT_RCODE_RFS
;
493 /* w2k3 refuses 0x1E names with out marked as group */
494 if (name
->type
== NBT_NAME_BROWSER
&& !(nb_flags
& NBT_NM_GROUP
)) {
495 rcode
= NBT_RCODE_RFS
;
499 if (name
->scope
&& strlen(name
->scope
) > 237) {
500 rcode
= NBT_RCODE_SVR
;
504 duplicate_packet
= wins_check_wack_queue(iface
, packet
, src
);
505 if (duplicate_packet
) {
506 /* just ignore the packet */
507 DEBUG(5,("Ignoring duplicate packet while WACK is pending from %s:%d\n",
508 src
->addr
, src
->port
));
512 status
= winsdb_lookup(winssrv
->wins_db
, name
, packet
, &rec
);
513 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND
, status
)) {
514 rcode
= wins_register_new(nbtsock
, packet
, src
, new_type
);
516 } else if (!NT_STATUS_IS_OK(status
)) {
517 rcode
= NBT_RCODE_SVR
;
519 } else if (rec
->is_static
) {
520 if (rec
->type
== WREPL_TYPE_GROUP
|| rec
->type
== WREPL_TYPE_SGROUP
) {
521 rcode
= NBT_RCODE_OK
;
524 rcode
= NBT_RCODE_ACT
;
528 if (rec
->type
== WREPL_TYPE_GROUP
) {
529 if (new_type
!= WREPL_TYPE_GROUP
) {
530 DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
531 " while a normal group is already there\n",
532 nbt_name_string(packet
, name
), new_type
));
533 rcode
= NBT_RCODE_ACT
;
537 if (rec
->state
== WREPL_STATE_ACTIVE
) {
538 /* TODO: is this correct? */
539 rcode
= wins_update_ttl(nbtsock
, packet
, rec
, NULL
, src
);
543 /* TODO: is this correct? */
544 winsdb_delete(winssrv
->wins_db
, rec
);
545 rcode
= wins_register_new(nbtsock
, packet
, src
, new_type
);
549 if (rec
->state
!= WREPL_STATE_ACTIVE
) {
550 winsdb_delete(winssrv
->wins_db
, rec
);
551 rcode
= wins_register_new(nbtsock
, packet
, src
, new_type
);
556 case WREPL_TYPE_UNIQUE
:
557 case WREPL_TYPE_MHOMED
:
559 * if its an active unique name, and the registration is for a group, then
560 * see if the unique name owner still wants the name
561 * TODO: is this correct?
563 if (new_type
== WREPL_TYPE_GROUP
|| new_type
== WREPL_TYPE_GROUP
) {
564 wins_register_wack(nbtsock
, packet
, rec
, src
, new_type
);
569 * if the registration is for an address that is currently active, then
570 * just update the expiry time of the record and the address
572 winsdb_addr
= winsdb_addr_list_check(rec
->addresses
, address
);
574 rcode
= wins_update_ttl(nbtsock
, packet
, rec
, winsdb_addr
, src
);
579 * we have to do a WACK to see if the current owner is willing
580 * to give up its claim
582 wins_register_wack(nbtsock
, packet
, rec
, src
, new_type
);
585 case WREPL_TYPE_GROUP
:
586 /* this should not be reached as normal groups are handled above */
587 DEBUG(0,("BUG at %s\n",__location__
));
588 rcode
= NBT_RCODE_ACT
;
591 case WREPL_TYPE_SGROUP
:
592 /* if the new record isn't also a special group, refuse the registration */
593 if (new_type
!= WREPL_TYPE_SGROUP
) {
594 DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
595 " while a special group is already there\n",
596 nbt_name_string(packet
, name
), new_type
));
597 rcode
= NBT_RCODE_ACT
;
602 * if the registration is for an address that is currently active, then
603 * just update the expiry time of the record and the address
605 winsdb_addr
= winsdb_addr_list_check(rec
->addresses
, address
);
607 rcode
= wins_update_ttl(nbtsock
, packet
, rec
, winsdb_addr
, src
);
611 rcode
= wins_sgroup_merge(nbtsock
, packet
, rec
, address
, src
);
616 nbtd_name_registration_reply(nbtsock
, packet
, src
, rcode
);
619 static uint32_t ipv4_match_bits(struct in_addr ip1
, struct in_addr ip2
)
621 uint32_t i
, j
, match
=0;
624 p1
= (uint8_t *)&ip1
.s_addr
;
625 p2
= (uint8_t *)&ip2
.s_addr
;
627 for (i
=0; i
<4; i
++) {
628 if (p1
[i
] != p2
[i
]) break;
632 if (i
==4) return match
;
634 for (j
=0; j
<8; j
++) {
635 if ((p1
[i
] & (1<<(7-j
))) != (p2
[i
] & (1<<(7-j
))))
643 static int nbtd_wins_randomize1Clist_sort(void *p1
,/* (const char **) */
644 void *p2
,/* (const char **) */
645 struct socket_address
*src
)
647 const char *a1
= (const char *)*(const char **)p1
;
648 const char *a2
= (const char *)*(const char **)p2
;
649 uint32_t match_bits1
;
650 uint32_t match_bits2
;
652 match_bits1
= ipv4_match_bits(interpret_addr2(a1
), interpret_addr2(src
->addr
));
653 match_bits2
= ipv4_match_bits(interpret_addr2(a2
), interpret_addr2(src
->addr
));
655 return match_bits2
- match_bits1
;
658 static void nbtd_wins_randomize1Clist(struct loadparm_context
*lp_ctx
,
659 const char **addresses
, struct socket_address
*src
)
667 for (num_addrs
=0; addresses
[num_addrs
]; num_addrs
++) { /* noop */ }
669 if (num_addrs
<= 1) return; /* nothing to do */
671 /* first sort the addresses depending on the matching to the client */
672 LDB_TYPESAFE_QSORT(addresses
, num_addrs
, src
, nbtd_wins_randomize1Clist_sort
);
674 mask
= lp_parm_string(lp_ctx
, NULL
, "nbtd", "wins_randomize1Clist_mask");
676 mask
= "255.255.255.0";
680 * choose a random address to be the first in the response to the client,
681 * preferr the addresses inside the nbtd:wins_randomize1Clist_mask netmask
684 idx
= sidx
= r
% num_addrs
;
689 /* if the current one is in the same subnet, use it */
690 same
= iface_same_net(addresses
[idx
], src
->addr
, mask
);
696 /* we need to check for idx == 0, after checking for the same net */
699 * if we haven't found an address in the same subnet, search in ones
700 * which match the client more
704 * it's not "idx = idx % r" but "idx = r % idx"
705 * because in "a % b" b is the allowed range
706 * and b-1 is the maximum possible result, so it must be decreasing
707 * and the above idx == 0 check breaks the while(1) loop.
712 /* note sidx == 0 is also valid here ... */
714 addresses
[0] = addresses
[sidx
];
715 addresses
[sidx
] = tmp
;
721 static void nbtd_winsserver_query(struct loadparm_context
*lp_ctx
,
722 struct nbt_name_socket
*nbtsock
,
723 struct nbt_name_packet
*packet
,
724 struct socket_address
*src
)
727 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
728 struct nbtd_interface
);
729 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
730 struct nbt_name
*name
= &packet
->questions
[0].name
;
731 struct winsdb_record
*rec
;
732 struct winsdb_record
*rec_1b
= NULL
;
733 const char **addresses
;
734 const char **addresses_1b
= NULL
;
735 uint16_t nb_flags
= 0;
737 if (name
->type
== NBT_NAME_MASTER
) {
742 * w2k3 returns the first address of the 0x1B record as first address
745 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
747 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Prepend1BTo1CQueries
748 * Typ: Daten REG_DWORD
749 * Value: 0 = deactivated, 1 = activated
751 if (name
->type
== NBT_NAME_LOGON
&&
752 lp_parm_bool(lp_ctx
, NULL
, "nbtd", "wins_prepend1Bto1Cqueries", true)) {
753 struct nbt_name name_1b
;
756 name_1b
.type
= NBT_NAME_PDC
;
758 status
= winsdb_lookup(winssrv
->wins_db
, &name_1b
, packet
, &rec_1b
);
759 if (NT_STATUS_IS_OK(status
)) {
760 addresses_1b
= winsdb_addr_string_list(packet
, rec_1b
->addresses
);
764 status
= winsdb_lookup(winssrv
->wins_db
, name
, packet
, &rec
);
765 if (!NT_STATUS_IS_OK(status
)) {
766 if (!lp_wins_dns_proxy(lp_ctx
)) {
770 if (name
->type
!= NBT_NAME_CLIENT
&& name
->type
!= NBT_NAME_SERVER
) {
774 nbtd_wins_dns_proxy_query(nbtsock
, packet
, src
);
779 * for group's we always reply with
780 * 255.255.255.255 as address, even if
781 * the record is released or tombstoned
783 if (rec
->type
== WREPL_TYPE_GROUP
) {
784 addresses
= str_list_add(NULL
, "255.255.255.255");
785 talloc_steal(packet
, addresses
);
789 nb_flags
|= NBT_NM_GROUP
;
793 if (rec
->state
!= WREPL_STATE_ACTIVE
) {
797 addresses
= winsdb_addr_string_list(packet
, rec
->addresses
);
803 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
804 * first 0x1B address as first address
806 if (addresses_1b
&& addresses_1b
[0]) {
807 const char **addresses_1c
= addresses
;
811 addresses
= str_list_add(NULL
, addresses_1b
[0]);
815 talloc_steal(packet
, addresses
);
818 for (i
=0; addresses_1c
[i
]; i
++) {
819 if (strcmp(addresses_1b
[0], addresses_1c
[i
]) == 0) continue;
822 * stop when we already have 25 addresses
824 if (num_addrs
>= 25) break;
827 addresses
= str_list_add(addresses
, addresses_1c
[i
]);
834 if (rec
->type
== WREPL_TYPE_SGROUP
) {
835 nb_flags
|= NBT_NM_GROUP
;
837 nb_flags
|= (rec
->node
<<13);
841 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
843 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList
844 * Typ: Daten REG_DWORD
845 * Value: 0 = deactivated, 1 = activated
847 if (name
->type
== NBT_NAME_LOGON
&&
848 lp_parm_bool(lp_ctx
, NULL
, "nbtd", "wins_randomize1Clist", false)) {
849 nbtd_wins_randomize1Clist(lp_ctx
, addresses
, src
);
853 nbtd_name_query_reply(nbtsock
, packet
, src
, name
,
854 0, nb_flags
, addresses
);
858 nbtd_negative_name_query_reply(nbtsock
, packet
, src
);
864 static void nbtd_winsserver_release(struct nbt_name_socket
*nbtsock
,
865 struct nbt_name_packet
*packet
,
866 struct socket_address
*src
)
869 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
870 struct nbtd_interface
);
871 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
872 struct nbt_name
*name
= &packet
->questions
[0].name
;
873 struct winsdb_record
*rec
;
874 uint32_t modify_flags
= 0;
877 if (name
->type
== NBT_NAME_MASTER
) {
881 if (name
->scope
&& strlen(name
->scope
) > 237) {
885 status
= winsdb_lookup(winssrv
->wins_db
, name
, packet
, &rec
);
886 if (!NT_STATUS_IS_OK(status
)) {
890 if (rec
->is_static
) {
891 if (rec
->type
== WREPL_TYPE_UNIQUE
|| rec
->type
== WREPL_TYPE_MHOMED
) {
894 nbtd_name_release_reply(nbtsock
, packet
, src
, NBT_RCODE_ACT
);
898 if (rec
->state
!= WREPL_STATE_ACTIVE
) {
903 * TODO: do we need to check if
904 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
909 * we only allow releases from an owner - other releases are
912 if (!winsdb_addr_list_check(rec
->addresses
, src
->addr
)) {
914 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec
, rec
->name
), src
->addr
));
915 DEBUGADD(4, ("Registered Addresses: \n"));
916 for (i
=0; rec
->addresses
&& rec
->addresses
[i
]; i
++) {
917 DEBUGADD(4, ("%s\n", rec
->addresses
[i
]->address
));
922 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec
, rec
->name
), src
->addr
));
925 case WREPL_TYPE_UNIQUE
:
926 rec
->state
= WREPL_STATE_RELEASED
;
929 case WREPL_TYPE_GROUP
:
930 rec
->state
= WREPL_STATE_RELEASED
;
933 case WREPL_TYPE_SGROUP
:
934 winsdb_addr_list_remove(rec
->addresses
, src
->addr
);
935 /* TODO: do we need to take the ownership here? */
936 if (winsdb_addr_list_length(rec
->addresses
) == 0) {
937 rec
->state
= WREPL_STATE_RELEASED
;
941 case WREPL_TYPE_MHOMED
:
942 winsdb_addr_list_remove(rec
->addresses
, src
->addr
);
943 /* TODO: do we need to take the ownership here? */
944 if (winsdb_addr_list_length(rec
->addresses
) == 0) {
945 rec
->state
= WREPL_STATE_RELEASED
;
950 if (rec
->state
== WREPL_STATE_ACTIVE
) {
952 * If the record is still active, we need to update the
955 * if we're not the owner, we need to take the ownership.
957 rec
->expire_time
= time(NULL
) + winssrv
->config
.max_renew_interval
;
958 if (strcmp(rec
->wins_owner
, winssrv
->wins_db
->local_owner
) != 0) {
959 modify_flags
= WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
;
961 if (lp_parm_bool(iface
->nbtsrv
->task
->lp_ctx
, NULL
, "wreplsrv", "propagate name releases", false)) {
963 * We have an option to propagate every name release,
964 * this is off by default to match windows servers
966 modify_flags
= WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
;
968 } else if (rec
->state
== WREPL_STATE_RELEASED
) {
970 * if we're not the owner, we need to take the owner ship
971 * and make the record tombstone, but expire after
972 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
973 * like for normal tombstone records.
974 * This is to replicate the record directly to the original owner,
975 * where the record is still active
977 if (strcmp(rec
->wins_owner
, winssrv
->wins_db
->local_owner
) == 0) {
978 rec
->expire_time
= time(NULL
) + winssrv
->config
.tombstone_interval
;
980 rec
->state
= WREPL_STATE_TOMBSTONE
;
981 rec
->expire_time
= time(NULL
) +
982 winssrv
->config
.tombstone_interval
+
983 winssrv
->config
.tombstone_timeout
;
984 modify_flags
= WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
;
988 ret
= winsdb_modify(winssrv
->wins_db
, rec
, modify_flags
);
989 if (ret
!= NBT_RCODE_OK
) {
990 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
991 nbt_name_string(rec
, rec
->name
), src
->addr
, ret
));
994 /* we match w2k3 by always giving a positive reply to name releases. */
995 nbtd_name_release_reply(nbtsock
, packet
, src
, NBT_RCODE_OK
);
1002 void nbtd_winsserver_request(struct nbt_name_socket
*nbtsock
,
1003 struct nbt_name_packet
*packet
,
1004 struct socket_address
*src
)
1006 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
1007 struct nbtd_interface
);
1008 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
1009 if ((packet
->operation
& NBT_FLAG_BROADCAST
) || winssrv
== NULL
) {
1013 switch (packet
->operation
& NBT_OPCODE
) {
1014 case NBT_OPCODE_QUERY
:
1015 nbtd_winsserver_query(iface
->nbtsrv
->task
->lp_ctx
, nbtsock
, packet
, src
);
1018 case NBT_OPCODE_REGISTER
:
1019 case NBT_OPCODE_REFRESH
:
1020 case NBT_OPCODE_REFRESH2
:
1021 case NBT_OPCODE_MULTI_HOME_REG
:
1022 nbtd_winsserver_register(nbtsock
, packet
, src
);
1025 case NBT_OPCODE_RELEASE
:
1026 nbtd_winsserver_release(nbtsock
, packet
, src
);
1033 startup the WINS server, if configured
1035 NTSTATUS
nbtd_winsserver_init(struct nbtd_server
*nbtsrv
)
1040 if (!lp_wins_support(nbtsrv
->task
->lp_ctx
)) {
1041 nbtsrv
->winssrv
= NULL
;
1042 return NT_STATUS_OK
;
1045 nbtsrv
->winssrv
= talloc_zero(nbtsrv
, struct wins_server
);
1046 NT_STATUS_HAVE_NO_MEMORY(nbtsrv
->winssrv
);
1048 nbtsrv
->winssrv
->config
.max_renew_interval
= lp_max_wins_ttl(nbtsrv
->task
->lp_ctx
);
1049 nbtsrv
->winssrv
->config
.min_renew_interval
= lp_min_wins_ttl(nbtsrv
->task
->lp_ctx
);
1050 tmp
= lp_parm_int(nbtsrv
->task
->lp_ctx
, NULL
, "wreplsrv", "tombstone_interval", 6*24*60*60);
1051 nbtsrv
->winssrv
->config
.tombstone_interval
= tmp
;
1052 tmp
= lp_parm_int(nbtsrv
->task
->lp_ctx
, NULL
, "wreplsrv"," tombstone_timeout", 1*24*60*60);
1053 nbtsrv
->winssrv
->config
.tombstone_timeout
= tmp
;
1055 owner
= lp_parm_string(nbtsrv
->task
->lp_ctx
, NULL
, "winsdb", "local_owner");
1057 if (owner
== NULL
) {
1058 struct interface
*ifaces
;
1059 load_interfaces(nbtsrv
->task
, lp_interfaces(nbtsrv
->task
->lp_ctx
), &ifaces
);
1060 owner
= iface_n_ip(ifaces
, 0);
1063 nbtsrv
->winssrv
->wins_db
= winsdb_connect(nbtsrv
->winssrv
, nbtsrv
->task
->event_ctx
,
1064 nbtsrv
->task
->lp_ctx
,
1065 owner
, WINSDB_HANDLE_CALLER_NBTD
);
1066 if (!nbtsrv
->winssrv
->wins_db
) {
1067 return NT_STATUS_INTERNAL_DB_ERROR
;
1070 irpc_add_name(nbtsrv
->task
->msg_ctx
, "wins_server");
1072 return NT_STATUS_OK
;