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"
36 #include "param/param.h"
37 #include "libcli/resolve/resolve.h"
38 #include "lib/util/util_net.h"
41 work out the ttl we will use given a client requested ttl
43 uint32_t wins_server_ttl(struct wins_server
*winssrv
, uint32_t ttl
)
45 ttl
= MIN(ttl
, winssrv
->config
.max_renew_interval
);
46 ttl
= MAX(ttl
, winssrv
->config
.min_renew_interval
);
50 static enum wrepl_name_type
wrepl_type(uint16_t nb_flags
, struct nbt_name
*name
, bool mhomed
)
52 /* this copes with the nasty hack that is the type 0x1c name */
53 if (name
->type
== NBT_NAME_LOGON
) {
54 return WREPL_TYPE_SGROUP
;
56 if (nb_flags
& NBT_NM_GROUP
) {
57 return WREPL_TYPE_GROUP
;
60 return WREPL_TYPE_MHOMED
;
62 return WREPL_TYPE_UNIQUE
;
66 register a new name with WINS
68 static uint8_t wins_register_new(struct nbt_name_socket
*nbtsock
,
69 struct nbt_name_packet
*packet
,
70 const struct socket_address
*src
,
71 enum wrepl_name_type type
)
73 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
74 struct nbtd_interface
);
75 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
76 struct nbt_name
*name
= &packet
->questions
[0].name
;
77 uint32_t ttl
= wins_server_ttl(winssrv
, packet
->additional
[0].ttl
);
78 uint16_t nb_flags
= packet
->additional
[0].rdata
.netbios
.addresses
[0].nb_flags
;
79 const char *address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
80 struct winsdb_record rec
;
81 enum wrepl_name_node node
;
83 #define WREPL_NODE_NBT_FLAGS(nb_flags) \
84 ((nb_flags & NBT_NM_OWNER_TYPE)>>13)
86 node
= WREPL_NODE_NBT_FLAGS(nb_flags
);
90 rec
.state
= WREPL_STATE_ACTIVE
;
92 rec
.is_static
= false;
93 rec
.expire_time
= time(NULL
) + ttl
;
94 rec
.version
= 0; /* will be allocated later */
95 rec
.wins_owner
= NULL
; /* will be set later */
96 rec
.registered_by
= src
->addr
;
97 rec
.addresses
= winsdb_addr_list_make(packet
);
98 if (rec
.addresses
== NULL
) return NBT_RCODE_SVR
;
100 rec
.addresses
= winsdb_addr_list_add(winssrv
->wins_db
,
103 winssrv
->wins_db
->local_owner
,
106 if (rec
.addresses
== NULL
) return NBT_RCODE_SVR
;
108 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
109 nbt_name_string(packet
, name
), rec
.addresses
[0]->address
));
111 return winsdb_add(winssrv
->wins_db
, &rec
, WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
);
116 update the ttl on an existing record
118 static uint8_t wins_update_ttl(struct nbt_name_socket
*nbtsock
,
119 struct nbt_name_packet
*packet
,
120 struct winsdb_record
*rec
,
121 struct winsdb_addr
*winsdb_addr
,
122 const struct socket_address
*src
)
124 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
125 struct nbtd_interface
);
126 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
127 uint32_t ttl
= wins_server_ttl(winssrv
, packet
->additional
[0].ttl
);
128 const char *address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
129 uint32_t modify_flags
= 0;
131 rec
->expire_time
= time(NULL
) + ttl
;
132 rec
->registered_by
= src
->addr
;
135 rec
->addresses
= winsdb_addr_list_add(winssrv
->wins_db
,
137 winsdb_addr
->address
,
138 winssrv
->wins_db
->local_owner
,
141 if (rec
->addresses
== NULL
) return NBT_RCODE_SVR
;
144 if (strcmp(winssrv
->wins_db
->local_owner
, rec
->wins_owner
) != 0) {
145 modify_flags
= WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
;
148 DEBUG(5,("WINS: refreshed registration of %s at %s\n",
149 nbt_name_string(packet
, rec
->name
), address
));
151 return winsdb_modify(winssrv
->wins_db
, rec
, modify_flags
);
157 static uint8_t wins_sgroup_merge(struct nbt_name_socket
*nbtsock
,
158 struct nbt_name_packet
*packet
,
159 struct winsdb_record
*rec
,
161 const struct socket_address
*src
)
163 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
164 struct nbtd_interface
);
165 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
166 uint32_t ttl
= wins_server_ttl(winssrv
, packet
->additional
[0].ttl
);
168 rec
->expire_time
= time(NULL
) + ttl
;
169 rec
->registered_by
= src
->addr
;
171 rec
->addresses
= winsdb_addr_list_add(winssrv
->wins_db
,
174 winssrv
->wins_db
->local_owner
,
177 if (rec
->addresses
== NULL
) return NBT_RCODE_SVR
;
179 DEBUG(5,("WINS: sgroup merge of %s at %s\n",
180 nbt_name_string(packet
, rec
->name
), address
));
182 return winsdb_modify(winssrv
->wins_db
, rec
, WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
);
185 struct nbtd_wins_wack_state
{
186 struct nbtd_wins_wack_state
*prev
, *next
;
187 struct wins_server
*winssrv
;
188 struct nbt_name_socket
*nbtsock
;
189 struct nbtd_interface
*iface
;
190 struct nbt_name_packet
*request_packet
;
191 struct winsdb_record
*rec
;
192 struct socket_address
*src
;
193 const char *reg_address
;
194 enum wrepl_name_type new_type
;
195 struct wins_challenge_io io
;
199 static int nbtd_wins_wack_state_destructor(struct nbtd_wins_wack_state
*s
)
201 DLIST_REMOVE(s
->iface
->wack_queue
, s
);
205 static bool wins_check_wack_queue(struct nbtd_interface
*iface
,
206 struct nbt_name_packet
*packet
,
207 struct socket_address
*src
)
209 struct nbtd_wins_wack_state
*s
;
211 for (s
= iface
->wack_queue
; s
; s
= s
->next
) {
212 if (packet
->name_trn_id
!= s
->request_packet
->name_trn_id
) {
215 if (packet
->operation
!= s
->request_packet
->operation
) {
218 if (src
->port
!= s
->src
->port
) {
221 if (strcmp(src
->addr
, s
->src
->addr
) != 0) {
232 deny a registration request
234 static void wins_wack_deny(struct nbtd_wins_wack_state
*s
)
236 nbtd_name_registration_reply(s
->nbtsock
, s
->request_packet
,
237 s
->src
, NBT_RCODE_ACT
);
238 DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
239 nbt_name_string(s
, s
->rec
->name
), s
->src
->addr
, s
->src
->port
));
244 allow a registration request
246 static void wins_wack_allow(struct nbtd_wins_wack_state
*s
)
249 uint32_t ttl
= wins_server_ttl(s
->winssrv
, s
->request_packet
->additional
[0].ttl
);
250 struct winsdb_record
*rec
= s
->rec
, *rec2
;
253 status
= winsdb_lookup(s
->winssrv
->wins_db
, rec
->name
, s
, &rec2
);
254 if (!NT_STATUS_IS_OK(status
) ||
255 rec2
->version
!= rec
->version
||
256 strcmp(rec2
->wins_owner
, rec
->wins_owner
) != 0) {
257 DEBUG(5,("WINS: record %s changed during WACK - failing registration\n",
258 nbt_name_string(s
, rec
->name
)));
264 * if the old name owner doesn't hold the name anymore
265 * handle the request as new registration for the new name owner
267 if (!NT_STATUS_IS_OK(s
->status
)) {
270 winsdb_delete(s
->winssrv
->wins_db
, rec
);
271 rcode
= wins_register_new(s
->nbtsock
, s
->request_packet
, s
->src
, s
->new_type
);
272 if (rcode
!= NBT_RCODE_OK
) {
273 DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
274 nbt_name_string(s
, rec
->name
)));
281 rec
->expire_time
= time(NULL
) + ttl
;
282 rec
->registered_by
= s
->src
->addr
;
285 * now remove all addresses that the client doesn't hold anymore
286 * and update the time stamp and owner for the ones that are still there
288 for (i
=0; rec
->addresses
[i
]; i
++) {
290 for (j
=0; j
< s
->io
.out
.num_addresses
; j
++) {
291 if (strcmp(rec
->addresses
[i
]->address
, s
->io
.out
.addresses
[j
]) != 0) continue;
297 rec
->addresses
= winsdb_addr_list_add(s
->winssrv
->wins_db
,
300 s
->winssrv
->wins_db
->local_owner
,
303 if (rec
->addresses
== NULL
) goto failed
;
307 winsdb_addr_list_remove(rec
->addresses
, rec
->addresses
[i
]->address
);
310 rec
->addresses
= winsdb_addr_list_add(s
->winssrv
->wins_db
,
313 s
->winssrv
->wins_db
->local_owner
,
316 if (rec
->addresses
== NULL
) goto failed
;
318 /* if we have more than one address, this becomes implicit a MHOMED record */
319 if (winsdb_addr_list_length(rec
->addresses
) > 1) {
320 rec
->type
= WREPL_TYPE_MHOMED
;
323 winsdb_modify(s
->winssrv
->wins_db
, rec
, WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
);
325 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
326 nbt_name_string(s
, rec
->name
), s
->reg_address
));
329 nbtd_name_registration_reply(s
->nbtsock
, s
->request_packet
,
330 s
->src
, NBT_RCODE_OK
);
336 called when a name query to a current owner completes
338 static void wack_wins_challenge_handler(struct composite_context
*c_req
)
340 struct nbtd_wins_wack_state
*s
= talloc_get_type(c_req
->async
.private_data
,
341 struct nbtd_wins_wack_state
);
345 s
->status
= wins_challenge_recv(c_req
, s
, &s
->io
);
348 * if the owner denies it holds the name, then allow
351 if (!NT_STATUS_IS_OK(s
->status
)) {
356 if (s
->new_type
== WREPL_TYPE_GROUP
|| s
->new_type
== WREPL_TYPE_SGROUP
) {
357 DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
358 nbt_name_string(s
, s
->rec
->name
), s
->new_type
, s
->rec
->type
));
364 * if the owner still wants the name and doesn't reply
365 * with the address trying to be registered, then deny
369 for (i
=0; i
< s
->io
.out
.num_addresses
; i
++) {
370 if (strcmp(s
->reg_address
, s
->io
.out
.addresses
[i
]) != 0) continue;
386 a client has asked to register a unique name that someone else owns. We
387 need to ask each of the current owners if they still want it. If they do
388 then reject the registration, otherwise allow it
390 static void wins_register_wack(struct nbt_name_socket
*nbtsock
,
391 struct nbt_name_packet
*packet
,
392 struct winsdb_record
*rec
,
393 struct socket_address
*src
,
394 enum wrepl_name_type new_type
)
396 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
397 struct nbtd_interface
);
398 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
399 struct nbtd_wins_wack_state
*s
;
400 struct composite_context
*c_req
;
403 s
= talloc_zero(nbtsock
, struct nbtd_wins_wack_state
);
404 if (s
== NULL
) goto failed
;
406 /* package up the state variables for this wack request */
407 s
->winssrv
= winssrv
;
408 s
->nbtsock
= nbtsock
;
410 s
->request_packet
= talloc_steal(s
, packet
);
411 s
->rec
= talloc_steal(s
, rec
);
412 s
->reg_address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
413 s
->new_type
= new_type
;
415 if (talloc_reference(s
, src
) == NULL
) goto failed
;
417 s
->io
.in
.nbtd_server
= iface
->nbtsrv
;
418 s
->io
.in
.nbt_port
= lpcfg_nbt_port(iface
->nbtsrv
->task
->lp_ctx
);
419 s
->io
.in
.event_ctx
= iface
->nbtsrv
->task
->event_ctx
;
420 s
->io
.in
.name
= rec
->name
;
421 s
->io
.in
.num_addresses
= winsdb_addr_list_length(rec
->addresses
);
422 s
->io
.in
.addresses
= winsdb_addr_string_list(s
, rec
->addresses
);
423 if (s
->io
.in
.addresses
== NULL
) goto failed
;
425 DLIST_ADD_END(iface
->wack_queue
, s
, struct nbtd_wins_wack_state
*);
427 talloc_set_destructor(s
, nbtd_wins_wack_state_destructor
);
430 * send a WACK to the client, specifying the maximum time it could
431 * take to check with the owner, plus some slack
433 ttl
= 5 + 4 * winsdb_addr_list_length(rec
->addresses
);
434 nbtd_wack_reply(nbtsock
, packet
, src
, ttl
);
437 * send the challenge to the old addresses
439 c_req
= wins_challenge_send(s
, &s
->io
);
440 if (c_req
== NULL
) goto failed
;
442 c_req
->async
.fn
= wack_wins_challenge_handler
;
443 c_req
->async
.private_data
= s
;
448 nbtd_name_registration_reply(nbtsock
, packet
, src
, NBT_RCODE_SVR
);
454 static void nbtd_winsserver_register(struct nbt_name_socket
*nbtsock
,
455 struct nbt_name_packet
*packet
,
456 struct socket_address
*src
)
459 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
460 struct nbtd_interface
);
461 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
462 struct nbt_name
*name
= &packet
->questions
[0].name
;
463 struct winsdb_record
*rec
;
464 uint8_t rcode
= NBT_RCODE_OK
;
465 uint16_t nb_flags
= packet
->additional
[0].rdata
.netbios
.addresses
[0].nb_flags
;
466 const char *address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
467 bool mhomed
= ((packet
->operation
& NBT_OPCODE
) == NBT_OPCODE_MULTI_HOME_REG
);
468 enum wrepl_name_type new_type
= wrepl_type(nb_flags
, name
, mhomed
);
469 struct winsdb_addr
*winsdb_addr
= NULL
;
470 bool duplicate_packet
;
473 * as a special case, the local master browser name is always accepted
474 * for registration, but never stored, but w2k3 stores it if it's registered
475 * as a group name, (but a query for the 0x1D name still returns not found!)
477 if (name
->type
== NBT_NAME_MASTER
&& !(nb_flags
& NBT_NM_GROUP
)) {
478 rcode
= NBT_RCODE_OK
;
482 /* w2k3 refuses 0x1B names with marked as group */
483 if (name
->type
== NBT_NAME_PDC
&& (nb_flags
& NBT_NM_GROUP
)) {
484 rcode
= NBT_RCODE_RFS
;
488 /* w2k3 refuses 0x1C names with out marked as group */
489 if (name
->type
== NBT_NAME_LOGON
&& !(nb_flags
& NBT_NM_GROUP
)) {
490 rcode
= NBT_RCODE_RFS
;
494 /* w2k3 refuses 0x1E names with out marked as group */
495 if (name
->type
== NBT_NAME_BROWSER
&& !(nb_flags
& NBT_NM_GROUP
)) {
496 rcode
= NBT_RCODE_RFS
;
500 if (name
->scope
&& strlen(name
->scope
) > 237) {
501 rcode
= NBT_RCODE_SVR
;
505 duplicate_packet
= wins_check_wack_queue(iface
, packet
, src
);
506 if (duplicate_packet
) {
507 /* just ignore the packet */
508 DEBUG(5,("Ignoring duplicate packet while WACK is pending from %s:%d\n",
509 src
->addr
, src
->port
));
513 status
= winsdb_lookup(winssrv
->wins_db
, name
, packet
, &rec
);
514 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND
, status
)) {
515 rcode
= wins_register_new(nbtsock
, packet
, src
, new_type
);
517 } else if (!NT_STATUS_IS_OK(status
)) {
518 rcode
= NBT_RCODE_SVR
;
520 } else if (rec
->is_static
) {
521 if (rec
->type
== WREPL_TYPE_GROUP
|| rec
->type
== WREPL_TYPE_SGROUP
) {
522 rcode
= NBT_RCODE_OK
;
525 rcode
= NBT_RCODE_ACT
;
529 if (rec
->type
== WREPL_TYPE_GROUP
) {
530 if (new_type
!= WREPL_TYPE_GROUP
) {
531 DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
532 " while a normal group is already there\n",
533 nbt_name_string(packet
, name
), new_type
));
534 rcode
= NBT_RCODE_ACT
;
538 if (rec
->state
== WREPL_STATE_ACTIVE
) {
539 /* TODO: is this correct? */
540 rcode
= wins_update_ttl(nbtsock
, packet
, rec
, NULL
, src
);
544 /* TODO: is this correct? */
545 winsdb_delete(winssrv
->wins_db
, rec
);
546 rcode
= wins_register_new(nbtsock
, packet
, src
, new_type
);
550 if (rec
->state
!= WREPL_STATE_ACTIVE
) {
551 winsdb_delete(winssrv
->wins_db
, rec
);
552 rcode
= wins_register_new(nbtsock
, packet
, src
, new_type
);
557 case WREPL_TYPE_UNIQUE
:
558 case WREPL_TYPE_MHOMED
:
560 * if its an active unique name, and the registration is for a group, then
561 * see if the unique name owner still wants the name
562 * TODO: is this correct?
564 if (new_type
== WREPL_TYPE_GROUP
|| new_type
== WREPL_TYPE_GROUP
) {
565 wins_register_wack(nbtsock
, packet
, rec
, src
, new_type
);
570 * if the registration is for an address that is currently active, then
571 * just update the expiry time of the record and the address
573 winsdb_addr
= winsdb_addr_list_check(rec
->addresses
, address
);
575 rcode
= wins_update_ttl(nbtsock
, packet
, rec
, winsdb_addr
, src
);
580 * we have to do a WACK to see if the current owner is willing
581 * to give up its claim
583 wins_register_wack(nbtsock
, packet
, rec
, src
, new_type
);
586 case WREPL_TYPE_GROUP
:
587 /* this should not be reached as normal groups are handled above */
588 DEBUG(0,("BUG at %s\n",__location__
));
589 rcode
= NBT_RCODE_ACT
;
592 case WREPL_TYPE_SGROUP
:
593 /* if the new record isn't also a special group, refuse the registration */
594 if (new_type
!= WREPL_TYPE_SGROUP
) {
595 DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
596 " while a special group is already there\n",
597 nbt_name_string(packet
, name
), new_type
));
598 rcode
= NBT_RCODE_ACT
;
603 * if the registration is for an address that is currently active, then
604 * just update the expiry time of the record and the address
606 winsdb_addr
= winsdb_addr_list_check(rec
->addresses
, address
);
608 rcode
= wins_update_ttl(nbtsock
, packet
, rec
, winsdb_addr
, src
);
612 rcode
= wins_sgroup_merge(nbtsock
, packet
, rec
, address
, src
);
617 nbtd_name_registration_reply(nbtsock
, packet
, src
, rcode
);
620 static uint32_t ipv4_match_bits(struct in_addr ip1
, struct in_addr ip2
)
622 uint32_t i
, j
, match
=0;
625 p1
= (uint8_t *)&ip1
.s_addr
;
626 p2
= (uint8_t *)&ip2
.s_addr
;
628 for (i
=0; i
<4; i
++) {
629 if (p1
[i
] != p2
[i
]) break;
633 if (i
==4) return match
;
635 for (j
=0; j
<8; j
++) {
636 if ((p1
[i
] & (1<<(7-j
))) != (p2
[i
] & (1<<(7-j
))))
644 static int nbtd_wins_randomize1Clist_sort(void *p1
,/* (const char **) */
645 void *p2
,/* (const char **) */
646 struct socket_address
*src
)
648 const char *a1
= (const char *)*(const char **)p1
;
649 const char *a2
= (const char *)*(const char **)p2
;
650 uint32_t match_bits1
;
651 uint32_t match_bits2
;
653 match_bits1
= ipv4_match_bits(interpret_addr2(a1
), interpret_addr2(src
->addr
));
654 match_bits2
= ipv4_match_bits(interpret_addr2(a2
), interpret_addr2(src
->addr
));
656 return match_bits2
- match_bits1
;
659 static void nbtd_wins_randomize1Clist(struct loadparm_context
*lp_ctx
,
660 const char **addresses
, struct socket_address
*src
)
668 for (num_addrs
=0; addresses
[num_addrs
]; num_addrs
++) { /* noop */ }
670 if (num_addrs
<= 1) return; /* nothing to do */
672 /* first sort the addresses depending on the matching to the client */
673 LDB_TYPESAFE_QSORT(addresses
, num_addrs
, src
, nbtd_wins_randomize1Clist_sort
);
675 mask
= lpcfg_parm_string(lp_ctx
, NULL
, "nbtd", "wins_randomize1Clist_mask");
677 mask
= "255.255.255.0";
681 * choose a random address to be the first in the response to the client,
682 * preferr the addresses inside the nbtd:wins_randomize1Clist_mask netmask
685 idx
= sidx
= r
% num_addrs
;
690 /* if the current one is in the same subnet, use it */
691 same
= iface_list_same_net(addresses
[idx
], src
->addr
, mask
);
697 /* we need to check for idx == 0, after checking for the same net */
700 * if we haven't found an address in the same subnet, search in ones
701 * which match the client more
705 * it's not "idx = idx % r" but "idx = r % idx"
706 * because in "a % b" b is the allowed range
707 * and b-1 is the maximum possible result, so it must be decreasing
708 * and the above idx == 0 check breaks the while(1) loop.
713 /* note sidx == 0 is also valid here ... */
715 addresses
[0] = addresses
[sidx
];
716 addresses
[sidx
] = tmp
;
722 static void nbtd_winsserver_query(struct loadparm_context
*lp_ctx
,
723 struct nbt_name_socket
*nbtsock
,
724 struct nbt_name_packet
*packet
,
725 struct socket_address
*src
)
728 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
729 struct nbtd_interface
);
730 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
731 struct nbt_name
*name
= &packet
->questions
[0].name
;
732 struct winsdb_record
*rec
;
733 struct winsdb_record
*rec_1b
= NULL
;
734 const char **addresses
;
735 const char **addresses_1b
= NULL
;
736 uint16_t nb_flags
= 0;
738 if (name
->type
== NBT_NAME_MASTER
) {
743 * w2k3 returns the first address of the 0x1B record as first address
746 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
748 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Prepend1BTo1CQueries
749 * Typ: Daten REG_DWORD
750 * Value: 0 = deactivated, 1 = activated
752 if (name
->type
== NBT_NAME_LOGON
&&
753 lpcfg_parm_bool(lp_ctx
, NULL
, "nbtd", "wins_prepend1Bto1Cqueries", true)) {
754 struct nbt_name name_1b
;
757 name_1b
.type
= NBT_NAME_PDC
;
759 status
= winsdb_lookup(winssrv
->wins_db
, &name_1b
, packet
, &rec_1b
);
760 if (NT_STATUS_IS_OK(status
)) {
761 addresses_1b
= winsdb_addr_string_list(packet
, rec_1b
->addresses
);
765 status
= winsdb_lookup(winssrv
->wins_db
, name
, packet
, &rec
);
766 if (!NT_STATUS_IS_OK(status
)) {
767 if (!lpcfg_wins_dns_proxy(lp_ctx
)) {
771 if (name
->type
!= NBT_NAME_CLIENT
&& name
->type
!= NBT_NAME_SERVER
) {
775 nbtd_wins_dns_proxy_query(nbtsock
, packet
, src
);
780 * for group's we always reply with
781 * 255.255.255.255 as address, even if
782 * the record is released or tombstoned
784 if (rec
->type
== WREPL_TYPE_GROUP
) {
785 addresses
= str_list_add(NULL
, "255.255.255.255");
786 talloc_steal(packet
, addresses
);
790 nb_flags
|= NBT_NM_GROUP
;
794 if (rec
->state
!= WREPL_STATE_ACTIVE
) {
798 addresses
= winsdb_addr_string_list(packet
, rec
->addresses
);
804 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
805 * first 0x1B address as first address
807 if (addresses_1b
&& addresses_1b
[0]) {
808 const char **addresses_1c
= addresses
;
812 addresses
= str_list_add(NULL
, addresses_1b
[0]);
816 talloc_steal(packet
, addresses
);
819 for (i
=0; addresses_1c
[i
]; i
++) {
820 if (strcmp(addresses_1b
[0], addresses_1c
[i
]) == 0) continue;
823 * stop when we already have 25 addresses
825 if (num_addrs
>= 25) break;
828 addresses
= str_list_add(addresses
, addresses_1c
[i
]);
835 if (rec
->type
== WREPL_TYPE_SGROUP
) {
836 nb_flags
|= NBT_NM_GROUP
;
838 nb_flags
|= (rec
->node
<<13);
842 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
844 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList
845 * Typ: Daten REG_DWORD
846 * Value: 0 = deactivated, 1 = activated
848 if (name
->type
== NBT_NAME_LOGON
&&
849 lpcfg_parm_bool(lp_ctx
, NULL
, "nbtd", "wins_randomize1Clist", false)) {
850 nbtd_wins_randomize1Clist(lp_ctx
, addresses
, src
);
854 nbtd_name_query_reply(nbtsock
, packet
, src
, name
,
855 0, nb_flags
, addresses
);
859 nbtd_negative_name_query_reply(nbtsock
, packet
, src
);
865 static void nbtd_winsserver_release(struct nbt_name_socket
*nbtsock
,
866 struct nbt_name_packet
*packet
,
867 struct socket_address
*src
)
870 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
871 struct nbtd_interface
);
872 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
873 struct nbt_name
*name
= &packet
->questions
[0].name
;
874 struct winsdb_record
*rec
;
875 uint32_t modify_flags
= 0;
878 if (name
->type
== NBT_NAME_MASTER
) {
882 if (name
->scope
&& strlen(name
->scope
) > 237) {
886 status
= winsdb_lookup(winssrv
->wins_db
, name
, packet
, &rec
);
887 if (!NT_STATUS_IS_OK(status
)) {
891 if (rec
->is_static
) {
892 if (rec
->type
== WREPL_TYPE_UNIQUE
|| rec
->type
== WREPL_TYPE_MHOMED
) {
895 nbtd_name_release_reply(nbtsock
, packet
, src
, NBT_RCODE_ACT
);
899 if (rec
->state
!= WREPL_STATE_ACTIVE
) {
904 * TODO: do we need to check if
905 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
910 * we only allow releases from an owner - other releases are
913 if (!winsdb_addr_list_check(rec
->addresses
, src
->addr
)) {
915 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec
, rec
->name
), src
->addr
));
916 DEBUGADD(4, ("Registered Addresses: \n"));
917 for (i
=0; rec
->addresses
&& rec
->addresses
[i
]; i
++) {
918 DEBUGADD(4, ("%s\n", rec
->addresses
[i
]->address
));
923 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec
, rec
->name
), src
->addr
));
926 case WREPL_TYPE_UNIQUE
:
927 rec
->state
= WREPL_STATE_RELEASED
;
930 case WREPL_TYPE_GROUP
:
931 rec
->state
= WREPL_STATE_RELEASED
;
934 case WREPL_TYPE_SGROUP
:
935 winsdb_addr_list_remove(rec
->addresses
, src
->addr
);
936 /* TODO: do we need to take the ownership here? */
937 if (winsdb_addr_list_length(rec
->addresses
) == 0) {
938 rec
->state
= WREPL_STATE_RELEASED
;
942 case WREPL_TYPE_MHOMED
:
943 winsdb_addr_list_remove(rec
->addresses
, src
->addr
);
944 /* TODO: do we need to take the ownership here? */
945 if (winsdb_addr_list_length(rec
->addresses
) == 0) {
946 rec
->state
= WREPL_STATE_RELEASED
;
951 if (rec
->state
== WREPL_STATE_ACTIVE
) {
953 * If the record is still active, we need to update the
956 * if we're not the owner, we need to take the ownership.
958 rec
->expire_time
= time(NULL
) + winssrv
->config
.max_renew_interval
;
959 if (strcmp(rec
->wins_owner
, winssrv
->wins_db
->local_owner
) != 0) {
960 modify_flags
= WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
;
962 if (lpcfg_parm_bool(iface
->nbtsrv
->task
->lp_ctx
, NULL
, "wreplsrv", "propagate name releases", false)) {
964 * We have an option to propagate every name release,
965 * this is off by default to match windows servers
967 modify_flags
= WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
;
969 } else if (rec
->state
== WREPL_STATE_RELEASED
) {
971 * if we're not the owner, we need to take the owner ship
972 * and make the record tombstone, but expire after
973 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
974 * like for normal tombstone records.
975 * This is to replicate the record directly to the original owner,
976 * where the record is still active
978 if (strcmp(rec
->wins_owner
, winssrv
->wins_db
->local_owner
) == 0) {
979 rec
->expire_time
= time(NULL
) + winssrv
->config
.tombstone_interval
;
981 rec
->state
= WREPL_STATE_TOMBSTONE
;
982 rec
->expire_time
= time(NULL
) +
983 winssrv
->config
.tombstone_interval
+
984 winssrv
->config
.tombstone_timeout
;
985 modify_flags
= WINSDB_FLAG_ALLOC_VERSION
| WINSDB_FLAG_TAKE_OWNERSHIP
;
989 ret
= winsdb_modify(winssrv
->wins_db
, rec
, modify_flags
);
990 if (ret
!= NBT_RCODE_OK
) {
991 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
992 nbt_name_string(rec
, rec
->name
), src
->addr
, ret
));
995 /* we match w2k3 by always giving a positive reply to name releases. */
996 nbtd_name_release_reply(nbtsock
, packet
, src
, NBT_RCODE_OK
);
1003 void nbtd_winsserver_request(struct nbt_name_socket
*nbtsock
,
1004 struct nbt_name_packet
*packet
,
1005 struct socket_address
*src
)
1007 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private_data
,
1008 struct nbtd_interface
);
1009 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
1010 if ((packet
->operation
& NBT_FLAG_BROADCAST
) || winssrv
== NULL
) {
1014 switch (packet
->operation
& NBT_OPCODE
) {
1015 case NBT_OPCODE_QUERY
:
1016 nbtd_winsserver_query(iface
->nbtsrv
->task
->lp_ctx
, nbtsock
, packet
, src
);
1019 case NBT_OPCODE_REGISTER
:
1020 case NBT_OPCODE_REFRESH
:
1021 case NBT_OPCODE_REFRESH2
:
1022 case NBT_OPCODE_MULTI_HOME_REG
:
1023 nbtd_winsserver_register(nbtsock
, packet
, src
);
1026 case NBT_OPCODE_RELEASE
:
1027 nbtd_winsserver_release(nbtsock
, packet
, src
);
1034 startup the WINS server, if configured
1036 NTSTATUS
nbtd_winsserver_init(struct nbtd_server
*nbtsrv
)
1041 if (!lpcfg_we_are_a_wins_server(nbtsrv
->task
->lp_ctx
)) {
1042 nbtsrv
->winssrv
= NULL
;
1043 return NT_STATUS_OK
;
1046 nbtsrv
->winssrv
= talloc_zero(nbtsrv
, struct wins_server
);
1047 NT_STATUS_HAVE_NO_MEMORY(nbtsrv
->winssrv
);
1049 nbtsrv
->winssrv
->config
.max_renew_interval
= lpcfg_max_wins_ttl(nbtsrv
->task
->lp_ctx
);
1050 nbtsrv
->winssrv
->config
.min_renew_interval
= lpcfg_min_wins_ttl(nbtsrv
->task
->lp_ctx
);
1051 tmp
= lpcfg_parm_int(nbtsrv
->task
->lp_ctx
, NULL
, "wreplsrv", "tombstone_interval", 6*24*60*60);
1052 nbtsrv
->winssrv
->config
.tombstone_interval
= tmp
;
1053 tmp
= lpcfg_parm_int(nbtsrv
->task
->lp_ctx
, NULL
, "wreplsrv"," tombstone_timeout", 1*24*60*60);
1054 nbtsrv
->winssrv
->config
.tombstone_timeout
= tmp
;
1056 owner
= lpcfg_parm_string(nbtsrv
->task
->lp_ctx
, NULL
, "winsdb", "local_owner");
1058 if (owner
== NULL
) {
1059 struct interface
*ifaces
;
1060 load_interface_list(nbtsrv
->task
, nbtsrv
->task
->lp_ctx
, &ifaces
);
1061 owner
= iface_list_first_v4(ifaces
);
1064 nbtsrv
->winssrv
->wins_db
= winsdb_connect(nbtsrv
->winssrv
, nbtsrv
->task
->event_ctx
,
1065 nbtsrv
->task
->lp_ctx
,
1066 owner
, WINSDB_HANDLE_CALLER_NBTD
);
1067 if (!nbtsrv
->winssrv
->wins_db
) {
1068 return NT_STATUS_INTERNAL_DB_ERROR
;
1071 irpc_add_name(nbtsrv
->task
->msg_ctx
, "wins_server");
1073 return NT_STATUS_OK
;