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 "samba/service_task.h"
32 #include "system/network.h"
33 #include "lib/socket/socket.h"
34 #include "lib/socket/netif.h"
36 #include "param/param.h"
37 #include "libcli/resolve/resolve.h"
38 #include "lib/util/util_net.h"
39 #include "lib/util/tsort.h"
42 work out the ttl we will use given a client requested ttl
44 uint32_t wins_server_ttl(struct wins_server
*winssrv
, uint32_t ttl
)
46 ttl
= MIN(ttl
, winssrv
->config
.max_renew_interval
);
47 ttl
= MAX(ttl
, winssrv
->config
.min_renew_interval
);
51 static enum wrepl_name_type
wrepl_type(uint16_t nb_flags
, struct nbt_name
*name
, bool mhomed
)
53 /* this copes with the nasty hack that is the type 0x1c name */
54 if (name
->type
== NBT_NAME_LOGON
) {
55 return WREPL_TYPE_SGROUP
;
57 if (nb_flags
& NBT_NM_GROUP
) {
58 return WREPL_TYPE_GROUP
;
61 return WREPL_TYPE_MHOMED
;
63 return WREPL_TYPE_UNIQUE
;
67 register a new name with WINS
69 static uint8_t wins_register_new(struct nbt_name_socket
*nbtsock
,
70 struct nbt_name_packet
*packet
,
71 const struct socket_address
*src
,
72 enum wrepl_name_type type
)
74 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
75 struct nbtd_interface
);
76 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
77 struct nbt_name
*name
= &packet
->questions
[0].name
;
78 uint32_t ttl
= wins_server_ttl(winssrv
, packet
->additional
[0].ttl
);
79 uint16_t nb_flags
= packet
->additional
[0].rdata
.netbios
.addresses
[0].nb_flags
;
80 const char *address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
81 struct winsdb_record rec
;
82 enum wrepl_name_node node
;
84 #define WREPL_NODE_NBT_FLAGS(nb_flags) \
85 ((nb_flags & NBT_NM_OWNER_TYPE)>>13)
87 node
= WREPL_NODE_NBT_FLAGS(nb_flags
);
91 rec
.state
= WREPL_STATE_ACTIVE
;
93 rec
.is_static
= false;
94 rec
.expire_time
= time(NULL
) + ttl
;
95 rec
.version
= 0; /* will be allocated later */
96 rec
.wins_owner
= NULL
; /* will be set later */
97 rec
.registered_by
= src
->addr
;
98 rec
.addresses
= winsdb_addr_list_make(packet
);
99 if (rec
.addresses
== NULL
) return NBT_RCODE_SVR
;
101 rec
.addresses
= winsdb_addr_list_add(winssrv
->wins_db
,
104 winssrv
->wins_db
->local_owner
,
107 if (rec
.addresses
== NULL
) return NBT_RCODE_SVR
;
109 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
110 nbt_name_string(packet
, name
), rec
.addresses
[0]->address
));
112 return winsdb_add(winssrv
->wins_db
, &rec
, WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
);
117 update the ttl on an existing record
119 static uint8_t wins_update_ttl(struct nbt_name_socket
*nbtsock
,
120 struct nbt_name_packet
*packet
,
121 struct winsdb_record
*rec
,
122 struct winsdb_addr
*winsdb_addr
,
123 const struct socket_address
*src
)
125 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
126 struct nbtd_interface
);
127 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
128 uint32_t ttl
= wins_server_ttl(winssrv
, packet
->additional
[0].ttl
);
129 const char *address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
130 uint32_t modify_flags
= 0;
132 rec
->expire_time
= time(NULL
) + ttl
;
133 rec
->registered_by
= src
->addr
;
136 rec
->addresses
= winsdb_addr_list_add(winssrv
->wins_db
,
138 winsdb_addr
->address
,
139 winssrv
->wins_db
->local_owner
,
142 if (rec
->addresses
== NULL
) return NBT_RCODE_SVR
;
145 if (strcmp(winssrv
->wins_db
->local_owner
, rec
->wins_owner
) != 0) {
146 modify_flags
= WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
;
149 DEBUG(5,("WINS: refreshed registration of %s at %s\n",
150 nbt_name_string(packet
, rec
->name
), address
));
152 return winsdb_modify(winssrv
->wins_db
, rec
, modify_flags
);
158 static uint8_t wins_sgroup_merge(struct nbt_name_socket
*nbtsock
,
159 struct nbt_name_packet
*packet
,
160 struct winsdb_record
*rec
,
162 const struct socket_address
*src
)
164 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
165 struct nbtd_interface
);
166 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
167 uint32_t ttl
= wins_server_ttl(winssrv
, packet
->additional
[0].ttl
);
169 rec
->expire_time
= time(NULL
) + ttl
;
170 rec
->registered_by
= src
->addr
;
172 rec
->addresses
= winsdb_addr_list_add(winssrv
->wins_db
,
175 winssrv
->wins_db
->local_owner
,
178 if (rec
->addresses
== NULL
) return NBT_RCODE_SVR
;
180 DEBUG(5,("WINS: sgroup merge of %s at %s\n",
181 nbt_name_string(packet
, rec
->name
), address
));
183 return winsdb_modify(winssrv
->wins_db
, rec
, WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
);
186 struct nbtd_wins_wack_state
{
187 struct nbtd_wins_wack_state
*prev
, *next
;
188 struct wins_server
*winssrv
;
189 struct nbt_name_socket
*nbtsock
;
190 struct nbtd_interface
*iface
;
191 struct nbt_name_packet
*request_packet
;
192 struct winsdb_record
*rec
;
193 struct socket_address
*src
;
194 const char *reg_address
;
195 enum wrepl_name_type new_type
;
196 struct wins_challenge_io io
;
200 static int nbtd_wins_wack_state_destructor(struct nbtd_wins_wack_state
*s
)
202 DLIST_REMOVE(s
->iface
->wack_queue
, s
);
206 static bool wins_check_wack_queue(struct nbtd_interface
*iface
,
207 struct nbt_name_packet
*packet
,
208 struct socket_address
*src
)
210 struct nbtd_wins_wack_state
*s
;
212 for (s
= iface
->wack_queue
; s
; s
= s
->next
) {
213 if (packet
->name_trn_id
!= s
->request_packet
->name_trn_id
) {
216 if (packet
->operation
!= s
->request_packet
->operation
) {
219 if (src
->port
!= s
->src
->port
) {
222 if (strcmp(src
->addr
, s
->src
->addr
) != 0) {
233 deny a registration request
235 static void wins_wack_deny(struct nbtd_wins_wack_state
*s
)
237 nbtd_name_registration_reply(s
->nbtsock
, s
->request_packet
,
238 s
->src
, NBT_RCODE_ACT
);
239 DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
240 nbt_name_string(s
, s
->rec
->name
), s
->src
->addr
, s
->src
->port
));
245 allow a registration request
247 static void wins_wack_allow(struct nbtd_wins_wack_state
*s
)
250 uint32_t ttl
= wins_server_ttl(s
->winssrv
, s
->request_packet
->additional
[0].ttl
);
251 struct winsdb_record
*rec
= s
->rec
, *rec2
;
254 status
= winsdb_lookup(s
->winssrv
->wins_db
, rec
->name
, s
, &rec2
);
255 if (!NT_STATUS_IS_OK(status
) ||
256 rec2
->version
!= rec
->version
||
257 strcmp(rec2
->wins_owner
, rec
->wins_owner
) != 0) {
258 DEBUG(5,("WINS: record %s changed during WACK - failing registration\n",
259 nbt_name_string(s
, rec
->name
)));
265 * if the old name owner doesn't hold the name anymore
266 * handle the request as new registration for the new name owner
268 if (!NT_STATUS_IS_OK(s
->status
)) {
271 winsdb_delete(s
->winssrv
->wins_db
, rec
);
272 rcode
= wins_register_new(s
->nbtsock
, s
->request_packet
, s
->src
, s
->new_type
);
273 if (rcode
!= NBT_RCODE_OK
) {
274 DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
275 nbt_name_string(s
, rec
->name
)));
282 rec
->expire_time
= time(NULL
) + ttl
;
283 rec
->registered_by
= s
->src
->addr
;
286 * now remove all addresses that the client doesn't hold anymore
287 * and update the time stamp and owner for the ones that are still there
289 for (i
=0; rec
->addresses
[i
]; i
++) {
291 for (j
=0; j
< s
->io
.out
.num_addresses
; j
++) {
292 if (strcmp(rec
->addresses
[i
]->address
, s
->io
.out
.addresses
[j
]) != 0) continue;
298 rec
->addresses
= winsdb_addr_list_add(s
->winssrv
->wins_db
,
301 s
->winssrv
->wins_db
->local_owner
,
304 if (rec
->addresses
== NULL
) goto failed
;
308 winsdb_addr_list_remove(rec
->addresses
, rec
->addresses
[i
]->address
);
311 rec
->addresses
= winsdb_addr_list_add(s
->winssrv
->wins_db
,
314 s
->winssrv
->wins_db
->local_owner
,
317 if (rec
->addresses
== NULL
) goto failed
;
319 /* if we have more than one address, this becomes implicit a MHOMED record */
320 if (winsdb_addr_list_length(rec
->addresses
) > 1) {
321 rec
->type
= WREPL_TYPE_MHOMED
;
324 winsdb_modify(s
->winssrv
->wins_db
, rec
, WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
);
326 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
327 nbt_name_string(s
, rec
->name
), s
->reg_address
));
330 nbtd_name_registration_reply(s
->nbtsock
, s
->request_packet
,
331 s
->src
, NBT_RCODE_OK
);
337 called when a name query to a current owner completes
339 static void wack_wins_challenge_handler(struct composite_context
*c_req
)
341 struct nbtd_wins_wack_state
*s
= talloc_get_type(c_req
->async
.private_data
,
342 struct nbtd_wins_wack_state
);
346 s
->status
= wins_challenge_recv(c_req
, s
, &s
->io
);
349 * if the owner denies it holds the name, then allow
352 if (!NT_STATUS_IS_OK(s
->status
)) {
357 if (s
->new_type
== WREPL_TYPE_GROUP
|| s
->new_type
== WREPL_TYPE_SGROUP
) {
358 DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
359 nbt_name_string(s
, s
->rec
->name
), s
->new_type
, s
->rec
->type
));
365 * if the owner still wants the name and doesn't reply
366 * with the address trying to be registered, then deny
370 for (i
=0; i
< s
->io
.out
.num_addresses
; i
++) {
371 if (strcmp(s
->reg_address
, s
->io
.out
.addresses
[i
]) != 0) continue;
387 a client has asked to register a unique name that someone else owns. We
388 need to ask each of the current owners if they still want it. If they do
389 then reject the registration, otherwise allow it
391 static void wins_register_wack(struct nbt_name_socket
*nbtsock
,
392 struct nbt_name_packet
*packet
,
393 struct winsdb_record
*rec
,
394 struct socket_address
*src
,
395 enum wrepl_name_type new_type
)
397 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
398 struct nbtd_interface
);
399 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
400 struct nbtd_wins_wack_state
*s
;
401 struct composite_context
*c_req
;
404 s
= talloc_zero(nbtsock
, struct nbtd_wins_wack_state
);
405 if (s
== NULL
) goto failed
;
407 /* package up the state variables for this wack request */
408 s
->winssrv
= winssrv
;
409 s
->nbtsock
= nbtsock
;
411 s
->request_packet
= talloc_steal(s
, packet
);
412 s
->rec
= talloc_steal(s
, rec
);
413 s
->reg_address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
414 s
->new_type
= new_type
;
415 s
->src
= socket_address_copy(s
, src
);
416 if (s
->src
== NULL
) goto failed
;
418 s
->io
.in
.nbtd_server
= iface
->nbtsrv
;
419 s
->io
.in
.nbt_port
= lpcfg_nbt_port(iface
->nbtsrv
->task
->lp_ctx
);
420 s
->io
.in
.event_ctx
= iface
->nbtsrv
->task
->event_ctx
;
421 s
->io
.in
.name
= rec
->name
;
422 s
->io
.in
.num_addresses
= winsdb_addr_list_length(rec
->addresses
);
423 s
->io
.in
.addresses
= winsdb_addr_string_list(s
, rec
->addresses
);
424 if (s
->io
.in
.addresses
== NULL
) goto failed
;
426 DLIST_ADD_END(iface
->wack_queue
, s
);
428 talloc_set_destructor(s
, nbtd_wins_wack_state_destructor
);
431 * send a WACK to the client, specifying the maximum time it could
432 * take to check with the owner, plus some slack
434 ttl
= 5 + 4 * winsdb_addr_list_length(rec
->addresses
);
435 nbtd_wack_reply(nbtsock
, packet
, src
, ttl
);
438 * send the challenge to the old addresses
440 c_req
= wins_challenge_send(s
, &s
->io
);
441 if (c_req
== NULL
) goto failed
;
443 c_req
->async
.fn
= wack_wins_challenge_handler
;
444 c_req
->async
.private_data
= s
;
449 nbtd_name_registration_reply(nbtsock
, packet
, src
, NBT_RCODE_SVR
);
455 static void nbtd_winsserver_register(struct nbt_name_socket
*nbtsock
,
456 struct nbt_name_packet
*packet
,
457 struct socket_address
*src
)
460 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
461 struct nbtd_interface
);
462 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
463 struct nbt_name
*name
= &packet
->questions
[0].name
;
464 struct winsdb_record
*rec
;
465 uint8_t rcode
= NBT_RCODE_OK
;
466 uint16_t nb_flags
= packet
->additional
[0].rdata
.netbios
.addresses
[0].nb_flags
;
467 const char *address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
468 bool mhomed
= ((packet
->operation
& NBT_OPCODE
) == NBT_OPCODE_MULTI_HOME_REG
);
469 enum wrepl_name_type new_type
= wrepl_type(nb_flags
, name
, mhomed
);
470 struct winsdb_addr
*winsdb_addr
= NULL
;
471 bool duplicate_packet
;
474 * as a special case, the local master browser name is always accepted
475 * for registration, but never stored, but w2k3 stores it if it's registered
476 * as a group name, (but a query for the 0x1D name still returns not found!)
478 if (name
->type
== NBT_NAME_MASTER
&& !(nb_flags
& NBT_NM_GROUP
)) {
479 rcode
= NBT_RCODE_OK
;
483 /* w2k3 refuses 0x1B names with marked as group */
484 if (name
->type
== NBT_NAME_PDC
&& (nb_flags
& NBT_NM_GROUP
)) {
485 rcode
= NBT_RCODE_RFS
;
489 /* w2k3 refuses 0x1C names with out marked as group */
490 if (name
->type
== NBT_NAME_LOGON
&& !(nb_flags
& NBT_NM_GROUP
)) {
491 rcode
= NBT_RCODE_RFS
;
495 /* w2k3 refuses 0x1E names with out marked as group */
496 if (name
->type
== NBT_NAME_BROWSER
&& !(nb_flags
& NBT_NM_GROUP
)) {
497 rcode
= NBT_RCODE_RFS
;
501 if (name
->scope
&& strlen(name
->scope
) > 237) {
502 rcode
= NBT_RCODE_SVR
;
506 duplicate_packet
= wins_check_wack_queue(iface
, packet
, src
);
507 if (duplicate_packet
) {
508 /* just ignore the packet */
509 DEBUG(5,("Ignoring duplicate packet while WACK is pending from %s:%d\n",
510 src
->addr
, src
->port
));
514 status
= winsdb_lookup(winssrv
->wins_db
, name
, packet
, &rec
);
515 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND
, status
)) {
516 rcode
= wins_register_new(nbtsock
, packet
, src
, new_type
);
518 } else if (!NT_STATUS_IS_OK(status
)) {
519 rcode
= NBT_RCODE_SVR
;
521 } else if (rec
->is_static
) {
522 if (rec
->type
== WREPL_TYPE_GROUP
|| rec
->type
== WREPL_TYPE_SGROUP
) {
523 rcode
= NBT_RCODE_OK
;
526 rcode
= NBT_RCODE_ACT
;
530 if (rec
->type
== WREPL_TYPE_GROUP
) {
531 if (new_type
!= WREPL_TYPE_GROUP
) {
532 DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
533 " while a normal group is already there\n",
534 nbt_name_string(packet
, name
), new_type
));
535 rcode
= NBT_RCODE_ACT
;
539 if (rec
->state
== WREPL_STATE_ACTIVE
) {
540 /* TODO: is this correct? */
541 rcode
= wins_update_ttl(nbtsock
, packet
, rec
, NULL
, src
);
545 /* TODO: is this correct? */
546 winsdb_delete(winssrv
->wins_db
, rec
);
547 rcode
= wins_register_new(nbtsock
, packet
, src
, new_type
);
551 if (rec
->state
!= WREPL_STATE_ACTIVE
) {
552 winsdb_delete(winssrv
->wins_db
, rec
);
553 rcode
= wins_register_new(nbtsock
, packet
, src
, new_type
);
558 case WREPL_TYPE_UNIQUE
:
559 case WREPL_TYPE_MHOMED
:
561 * if its an active unique name, and the registration is for a group, then
562 * see if the unique name owner still wants the name
563 * TODO: is this correct?
565 if (new_type
== WREPL_TYPE_GROUP
|| new_type
== WREPL_TYPE_GROUP
) {
566 wins_register_wack(nbtsock
, packet
, rec
, src
, new_type
);
571 * if the registration is for an address that is currently active, then
572 * just update the expiry time of the record and the address
574 winsdb_addr
= winsdb_addr_list_check(rec
->addresses
, address
);
576 rcode
= wins_update_ttl(nbtsock
, packet
, rec
, winsdb_addr
, src
);
581 * we have to do a WACK to see if the current owner is willing
582 * to give up its claim
584 wins_register_wack(nbtsock
, packet
, rec
, src
, new_type
);
587 case WREPL_TYPE_GROUP
:
588 /* this should not be reached as normal groups are handled above */
589 DEBUG(0,("BUG at %s\n",__location__
));
590 rcode
= NBT_RCODE_ACT
;
593 case WREPL_TYPE_SGROUP
:
594 /* if the new record isn't also a special group, refuse the registration */
595 if (new_type
!= WREPL_TYPE_SGROUP
) {
596 DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
597 " while a special group is already there\n",
598 nbt_name_string(packet
, name
), new_type
));
599 rcode
= NBT_RCODE_ACT
;
604 * if the registration is for an address that is currently active, then
605 * just update the expiry time of the record and the address
607 winsdb_addr
= winsdb_addr_list_check(rec
->addresses
, address
);
609 rcode
= wins_update_ttl(nbtsock
, packet
, rec
, winsdb_addr
, src
);
613 rcode
= wins_sgroup_merge(nbtsock
, packet
, rec
, address
, src
);
618 nbtd_name_registration_reply(nbtsock
, packet
, src
, rcode
);
621 static uint32_t ipv4_match_bits(struct in_addr ip1
, struct in_addr ip2
)
623 uint32_t i
, j
, match
=0;
626 p1
= (uint8_t *)&ip1
.s_addr
;
627 p2
= (uint8_t *)&ip2
.s_addr
;
629 for (i
=0; i
<4; i
++) {
630 if (p1
[i
] != p2
[i
]) break;
634 if (i
==4) return match
;
636 for (j
=0; j
<8; j
++) {
637 if ((p1
[i
] & (1<<(7-j
))) != (p2
[i
] & (1<<(7-j
))))
645 static int nbtd_wins_randomize1Clist_sort(void *p1
,/* (const char **) */
646 void *p2
,/* (const char **) */
647 struct socket_address
*src
)
649 const char *a1
= (const char *)*(const char **)p1
;
650 const char *a2
= (const char *)*(const char **)p2
;
651 uint32_t match_bits1
;
652 uint32_t match_bits2
;
654 match_bits1
= ipv4_match_bits(interpret_addr2(a1
), interpret_addr2(src
->addr
));
655 match_bits2
= ipv4_match_bits(interpret_addr2(a2
), interpret_addr2(src
->addr
));
657 return NUMERIC_CMP(match_bits2
, match_bits1
);
660 static void nbtd_wins_randomize1Clist(struct loadparm_context
*lp_ctx
,
661 const char **addresses
, struct socket_address
*src
)
669 for (num_addrs
=0; addresses
[num_addrs
]; num_addrs
++) { /* noop */ }
671 if (num_addrs
<= 1) return; /* nothing to do */
673 /* first sort the addresses depending on the matching to the client */
674 LDB_TYPESAFE_QSORT(addresses
, num_addrs
, src
, nbtd_wins_randomize1Clist_sort
);
676 mask
= lpcfg_parm_string(lp_ctx
, NULL
, "nbtd", "wins_randomize1Clist_mask");
678 mask
= "255.255.255.0";
682 * choose a random address to be the first in the response to the client,
683 * prefer the addresses inside the nbtd:wins_randomize1Clist_mask netmask
686 idx
= sidx
= r
% num_addrs
;
691 /* if the current one is in the same subnet, use it */
692 same
= iface_list_same_net(addresses
[idx
], src
->addr
, mask
);
698 /* we need to check for idx == 0, after checking for the same net */
701 * if we haven't found an address in the same subnet, search in ones
702 * which match the client more
706 * it's not "idx = idx % r" but "idx = r % idx"
707 * because in "a % b" b is the allowed range
708 * and b-1 is the maximum possible result, so it must be decreasing
709 * and the above idx == 0 check breaks the while(1) loop.
714 /* note sidx == 0 is also valid here ... */
716 addresses
[0] = addresses
[sidx
];
717 addresses
[sidx
] = tmp
;
723 static void nbtd_winsserver_query(struct loadparm_context
*lp_ctx
,
724 struct nbt_name_socket
*nbtsock
,
725 struct nbt_name_packet
*packet
,
726 struct socket_address
*src
)
729 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
730 struct nbtd_interface
);
731 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
732 struct nbt_name
*name
= &packet
->questions
[0].name
;
733 struct winsdb_record
*rec
;
734 struct winsdb_record
*rec_1b
= NULL
;
735 const char **addresses
;
736 const char **addresses_1b
= NULL
;
737 uint16_t nb_flags
= 0;
739 if (name
->type
== NBT_NAME_MASTER
) {
744 * w2k3 returns the first address of the 0x1B record as first address
747 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
749 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Prepend1BTo1CQueries
750 * Typ: Daten REG_DWORD
751 * Value: 0 = deactivated, 1 = activated
753 if (name
->type
== NBT_NAME_LOGON
&&
754 lpcfg_parm_bool(lp_ctx
, NULL
, "nbtd", "wins_prepend1Bto1Cqueries", true)) {
755 struct nbt_name name_1b
;
758 name_1b
.type
= NBT_NAME_PDC
;
760 status
= winsdb_lookup(winssrv
->wins_db
, &name_1b
, packet
, &rec_1b
);
761 if (NT_STATUS_IS_OK(status
)) {
762 addresses_1b
= winsdb_addr_string_list(packet
, rec_1b
->addresses
);
766 status
= winsdb_lookup(winssrv
->wins_db
, name
, packet
, &rec
);
767 if (!NT_STATUS_IS_OK(status
)) {
768 if (!lpcfg_wins_dns_proxy(lp_ctx
)) {
772 if (name
->type
!= NBT_NAME_CLIENT
&& name
->type
!= NBT_NAME_SERVER
) {
776 nbtd_wins_dns_proxy_query(nbtsock
, packet
, src
);
781 * for group's we always reply with
782 * 255.255.255.255 as address, even if
783 * the record is released or tombstoned
785 if (rec
->type
== WREPL_TYPE_GROUP
) {
786 addresses
= str_list_add(NULL
, "255.255.255.255");
787 talloc_steal(packet
, addresses
);
791 nb_flags
|= NBT_NM_GROUP
;
795 if (rec
->state
!= WREPL_STATE_ACTIVE
) {
799 addresses
= winsdb_addr_string_list(packet
, rec
->addresses
);
805 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
806 * first 0x1B address as first address
808 if (addresses_1b
&& addresses_1b
[0]) {
809 const char **addresses_1c
= addresses
;
813 addresses
= str_list_add(NULL
, addresses_1b
[0]);
817 talloc_steal(packet
, addresses
);
820 for (i
=0; addresses_1c
[i
]; i
++) {
821 if (strcmp(addresses_1b
[0], addresses_1c
[i
]) == 0) continue;
824 * stop when we already have 25 addresses
826 if (num_addrs
>= 25) break;
829 addresses
= str_list_add(addresses
, addresses_1c
[i
]);
836 if (rec
->type
== WREPL_TYPE_SGROUP
) {
837 nb_flags
|= NBT_NM_GROUP
;
839 nb_flags
|= (rec
->node
<<13);
843 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
845 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList
846 * Typ: Daten REG_DWORD
847 * Value: 0 = deactivated, 1 = activated
849 if (name
->type
== NBT_NAME_LOGON
&&
850 lpcfg_parm_bool(lp_ctx
, NULL
, "nbtd", "wins_randomize1Clist", false)) {
851 nbtd_wins_randomize1Clist(lp_ctx
, addresses
, src
);
855 nbtd_name_query_reply(nbtsock
, packet
, src
, name
,
856 0, nb_flags
, addresses
);
860 nbtd_negative_name_query_reply(nbtsock
, packet
, src
);
866 static void nbtd_winsserver_release(struct nbt_name_socket
*nbtsock
,
867 struct nbt_name_packet
*packet
,
868 struct socket_address
*src
)
871 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
872 struct nbtd_interface
);
873 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
874 struct nbt_name
*name
= &packet
->questions
[0].name
;
875 struct winsdb_record
*rec
;
876 uint32_t modify_flags
= 0;
879 if (name
->type
== NBT_NAME_MASTER
) {
883 if (name
->scope
&& strlen(name
->scope
) > 237) {
887 status
= winsdb_lookup(winssrv
->wins_db
, name
, packet
, &rec
);
888 if (!NT_STATUS_IS_OK(status
)) {
892 if (rec
->is_static
) {
893 if (rec
->type
== WREPL_TYPE_UNIQUE
|| rec
->type
== WREPL_TYPE_MHOMED
) {
896 nbtd_name_release_reply(nbtsock
, packet
, src
, NBT_RCODE_ACT
);
900 if (rec
->state
!= WREPL_STATE_ACTIVE
) {
905 * TODO: do we need to check if
906 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
911 * we only allow releases from an owner - other releases are
914 if (!winsdb_addr_list_check(rec
->addresses
, src
->addr
)) {
916 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec
, rec
->name
), src
->addr
));
917 DEBUGADD(4, ("Registered Addresses: \n"));
918 for (i
=0; rec
->addresses
&& rec
->addresses
[i
]; i
++) {
919 DEBUGADD(4, ("%s\n", rec
->addresses
[i
]->address
));
924 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec
, rec
->name
), src
->addr
));
927 case WREPL_TYPE_UNIQUE
:
928 rec
->state
= WREPL_STATE_RELEASED
;
931 case WREPL_TYPE_GROUP
:
932 rec
->state
= WREPL_STATE_RELEASED
;
935 case WREPL_TYPE_SGROUP
:
936 winsdb_addr_list_remove(rec
->addresses
, src
->addr
);
937 /* TODO: do we need to take the ownership here? */
938 if (winsdb_addr_list_length(rec
->addresses
) == 0) {
939 rec
->state
= WREPL_STATE_RELEASED
;
943 case WREPL_TYPE_MHOMED
:
944 winsdb_addr_list_remove(rec
->addresses
, src
->addr
);
945 /* TODO: do we need to take the ownership here? */
946 if (winsdb_addr_list_length(rec
->addresses
) == 0) {
947 rec
->state
= WREPL_STATE_RELEASED
;
952 if (rec
->state
== WREPL_STATE_ACTIVE
) {
954 * If the record is still active, we need to update the
957 * if we're not the owner, we need to take the ownership.
959 rec
->expire_time
= time(NULL
) + winssrv
->config
.max_renew_interval
;
960 if (strcmp(rec
->wins_owner
, winssrv
->wins_db
->local_owner
) != 0) {
961 modify_flags
= WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
;
963 if (lpcfg_parm_bool(iface
->nbtsrv
->task
->lp_ctx
, NULL
, "wreplsrv", "propagate name releases", false)) {
965 * We have an option to propagate every name release,
966 * this is off by default to match windows servers
968 modify_flags
= WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
;
970 } else if (rec
->state
== WREPL_STATE_RELEASED
) {
972 * if we're not the owner, we need to take the owner ship
973 * and make the record tombstone, but expire after
974 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
975 * like for normal tombstone records.
976 * This is to replicate the record directly to the original owner,
977 * where the record is still active
979 if (strcmp(rec
->wins_owner
, winssrv
->wins_db
->local_owner
) == 0) {
980 rec
->expire_time
= time(NULL
) + winssrv
->config
.tombstone_interval
;
982 rec
->state
= WREPL_STATE_TOMBSTONE
;
983 rec
->expire_time
= time(NULL
) +
984 winssrv
->config
.tombstone_interval
+
985 winssrv
->config
.tombstone_timeout
;
986 modify_flags
= WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
;
990 ret
= winsdb_modify(winssrv
->wins_db
, rec
, modify_flags
);
991 if (ret
!= NBT_RCODE_OK
) {
992 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
993 nbt_name_string(rec
, rec
->name
), src
->addr
, ret
));
996 /* we match w2k3 by always giving a positive reply to name releases. */
997 nbtd_name_release_reply(nbtsock
, packet
, src
, NBT_RCODE_OK
);
1004 void nbtd_winsserver_request(struct nbt_name_socket
*nbtsock
,
1005 struct nbt_name_packet
*packet
,
1006 struct socket_address
*src
)
1008 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
1009 struct nbtd_interface
);
1010 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
1011 if ((packet
->operation
& NBT_FLAG_BROADCAST
) || winssrv
== NULL
) {
1015 switch (packet
->operation
& NBT_OPCODE
) {
1016 case NBT_OPCODE_QUERY
:
1017 nbtd_winsserver_query(iface
->nbtsrv
->task
->lp_ctx
, nbtsock
, packet
, src
);
1020 case NBT_OPCODE_REGISTER
:
1021 case NBT_OPCODE_REFRESH
:
1022 case NBT_OPCODE_REFRESH2
:
1023 case NBT_OPCODE_MULTI_HOME_REG
:
1024 nbtd_winsserver_register(nbtsock
, packet
, src
);
1027 case NBT_OPCODE_RELEASE
:
1028 nbtd_winsserver_release(nbtsock
, packet
, src
);
1035 startup the WINS server, if configured
1037 NTSTATUS
nbtd_winsserver_init(struct nbtd_server
*nbtsrv
)
1042 if (!lpcfg_we_are_a_wins_server(nbtsrv
->task
->lp_ctx
)) {
1043 nbtsrv
->winssrv
= NULL
;
1044 return NT_STATUS_OK
;
1047 nbtsrv
->winssrv
= talloc_zero(nbtsrv
, struct wins_server
);
1048 NT_STATUS_HAVE_NO_MEMORY(nbtsrv
->winssrv
);
1050 nbtsrv
->winssrv
->config
.max_renew_interval
= lpcfg_max_wins_ttl(nbtsrv
->task
->lp_ctx
);
1051 nbtsrv
->winssrv
->config
.min_renew_interval
= lpcfg_min_wins_ttl(nbtsrv
->task
->lp_ctx
);
1052 tmp
= lpcfg_parm_int(nbtsrv
->task
->lp_ctx
, NULL
, "wreplsrv", "tombstone_interval", 6*24*60*60);
1053 nbtsrv
->winssrv
->config
.tombstone_interval
= tmp
;
1054 tmp
= lpcfg_parm_int(nbtsrv
->task
->lp_ctx
, NULL
, "wreplsrv"," tombstone_timeout", 1*24*60*60);
1055 nbtsrv
->winssrv
->config
.tombstone_timeout
= tmp
;
1057 owner
= lpcfg_parm_string(nbtsrv
->task
->lp_ctx
, NULL
, "winsdb", "local_owner");
1059 if (owner
== NULL
) {
1060 struct interface
*ifaces
;
1061 load_interface_list(nbtsrv
->task
, nbtsrv
->task
->lp_ctx
, &ifaces
);
1062 owner
= iface_list_first_v4(ifaces
);
1065 nbtsrv
->winssrv
->wins_db
= winsdb_connect(nbtsrv
->winssrv
, nbtsrv
->task
->event_ctx
,
1066 nbtsrv
->task
->lp_ctx
,
1067 owner
, WINSDB_HANDLE_CALLER_NBTD
);
1068 if (!nbtsrv
->winssrv
->wins_db
) {
1069 return NT_STATUS_INTERNAL_DB_ERROR
;
1072 irpc_add_name(nbtsrv
->task
->msg_ctx
, "wins_server");
1074 return NT_STATUS_OK
;