s4:winsserver: reject name registrations with a scope length > 237
[Samba/fernandojvsilva.git] / source4 / nbt_server / wins / winsserver.c
blobca8daedc66f5e788efb848d4352ccdf8d0eab663
1 /*
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/>.
23 #include "includes.h"
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);
46 return ttl;
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;
58 if (mhomed) {
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);
87 rec.name = name;
88 rec.type = type;
89 rec.state = WREPL_STATE_ACTIVE;
90 rec.node = node;
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,
100 &rec, rec.addresses,
101 address,
102 winssrv->wins_db->local_owner,
103 rec.expire_time,
104 true);
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;
133 if (winsdb_addr) {
134 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
135 rec, rec->addresses,
136 winsdb_addr->address,
137 winssrv->wins_db->local_owner,
138 rec->expire_time,
139 true);
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);
154 do a sgroup merge
156 static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
157 struct nbt_name_packet *packet,
158 struct winsdb_record *rec,
159 const char *address,
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,
171 rec, rec->addresses,
172 address,
173 winssrv->wins_db->local_owner,
174 rec->expire_time,
175 true);
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;
195 NTSTATUS status;
198 static int nbtd_wins_wack_state_destructor(struct nbtd_wins_wack_state *s)
200 DLIST_REMOVE(s->iface->wack_queue, s);
201 return 0;
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) {
212 continue;
214 if (packet->operation != s->request_packet->operation) {
215 continue;
217 if (src->port != s->src->port) {
218 continue;
220 if (strcmp(src->addr, s->src->addr) != 0) {
221 continue;
224 return true;
227 return false;
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));
239 talloc_free(s);
243 allow a registration request
245 static void wins_wack_allow(struct nbtd_wins_wack_state *s)
247 NTSTATUS status;
248 uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
249 struct winsdb_record *rec = s->rec, *rec2;
250 uint32_t i,j;
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)));
258 wins_wack_deny(s);
259 return;
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)) {
267 uint8_t rcode;
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)));
274 wins_wack_deny(s);
275 return;
277 goto done;
280 rec->expire_time = time(NULL) + ttl;
281 rec->registered_by = s->src->addr;
284 * now remove all addresses that're the client doesn't hold anymore
285 * and update the time stamp and owner for the ownes that are still there
287 for (i=0; rec->addresses[i]; i++) {
288 bool found = false;
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;
292 found = true;
293 break;
295 if (found) {
296 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
297 rec, rec->addresses,
298 s->reg_address,
299 s->winssrv->wins_db->local_owner,
300 rec->expire_time,
301 true);
302 if (rec->addresses == NULL) goto failed;
303 continue;
306 winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
309 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
310 rec, rec->addresses,
311 s->reg_address,
312 s->winssrv->wins_db->local_owner,
313 rec->expire_time,
314 true);
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));
327 done:
328 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
329 s->src, NBT_RCODE_OK);
330 failed:
331 talloc_free(s);
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);
341 bool found;
342 uint32_t i;
344 s->status = wins_challenge_recv(c_req, s, &s->io);
347 * if the owner denies it holds the name, then allow
348 * the registration
350 if (!NT_STATUS_IS_OK(s->status)) {
351 wins_wack_allow(s);
352 return;
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));
358 wins_wack_deny(s);
359 return;
363 * if the owner still wants the name and doesn't reply
364 * with the address trying to be registered, then deny
365 * the registration
367 found = false;
368 for (i=0; i < s->io.out.num_addresses; i++) {
369 if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
371 found = true;
372 break;
374 if (!found) {
375 wins_wack_deny(s);
376 return;
379 wins_wack_allow(s);
380 return;
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;
400 uint32_t ttl;
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;
408 s->iface = iface;
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;
413 s->src = src;
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;
443 return;
445 failed:
446 talloc_free(s);
447 nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR);
451 register a name
453 static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
454 struct nbt_name_packet *packet,
455 struct socket_address *src)
457 NTSTATUS status;
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;
478 goto done;
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;
484 goto done;
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;
490 goto done;
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;
496 goto done;
499 if (name->scope && strlen(name->scope) > 237) {
500 rcode = NBT_RCODE_SVR;
501 goto done;
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));
509 return;
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);
515 goto done;
516 } else if (!NT_STATUS_IS_OK(status)) {
517 rcode = NBT_RCODE_SVR;
518 goto done;
519 } else if (rec->is_static) {
520 if (rec->type == WREPL_TYPE_GROUP || rec->type == WREPL_TYPE_SGROUP) {
521 rcode = NBT_RCODE_OK;
522 goto done;
524 rcode = NBT_RCODE_ACT;
525 goto done;
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;
534 goto done;
537 if (rec->state == WREPL_STATE_ACTIVE) {
538 /* TODO: is this correct? */
539 rcode = wins_update_ttl(nbtsock, packet, rec, NULL, src);
540 goto done;
543 /* TODO: is this correct? */
544 winsdb_delete(winssrv->wins_db, rec);
545 rcode = wins_register_new(nbtsock, packet, src, new_type);
546 goto done;
549 if (rec->state != WREPL_STATE_ACTIVE) {
550 winsdb_delete(winssrv->wins_db, rec);
551 rcode = wins_register_new(nbtsock, packet, src, new_type);
552 goto done;
555 switch (rec->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);
565 return;
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);
573 if (winsdb_addr) {
574 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
575 goto done;
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);
583 return;
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;
589 goto done;
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;
598 goto done;
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);
606 if (winsdb_addr) {
607 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
608 goto done;
611 rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
612 goto done;
615 done:
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;
622 uint8_t *p1, *p2;
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;
629 match += 8;
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))))
636 break;
637 match++;
640 return match;
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)
661 const char *mask;
662 const char *tmp;
663 uint32_t num_addrs;
664 uint32_t idx, sidx;
665 int r;
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_qsort(addresses, num_addrs , sizeof(addresses[0]),
673 src, (ldb_qsort_cmp_fn_t)nbtd_wins_randomize1Clist_sort);
675 mask = lp_parm_string(lp_ctx, NULL, "nbtd", "wins_randomize1Clist_mask");
676 if (!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
684 r = random();
685 idx = sidx = r % num_addrs;
687 while (1) {
688 bool same;
690 /* if the current one is in the same subnet, use it */
691 same = iface_same_net(addresses[idx], src->addr, mask);
692 if (same) {
693 sidx = idx;
694 break;
697 /* we need to check for idx == 0, after checking for the same net */
698 if (idx == 0) break;
700 * if we haven't found an address in the same subnet, search in ones
701 * which match the client more
703 * some notes:
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.
710 idx = r % idx;
713 /* note sidx == 0 is also valid here ... */
714 tmp = addresses[0];
715 addresses[0] = addresses[sidx];
716 addresses[sidx] = tmp;
720 query a name
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)
727 NTSTATUS status;
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) {
739 goto notfound;
743 * w2k3 returns the first address of the 0x1B record as first address
744 * to a 0x1C query
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 lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_prepend1Bto1Cqueries", true)) {
754 struct nbt_name name_1b;
756 name_1b = *name;
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 (!lp_wins_dns_proxy(lp_ctx)) {
768 goto notfound;
771 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
772 goto notfound;
775 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
776 return;
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);
787 if (!addresses) {
788 goto notfound;
790 nb_flags |= NBT_NM_GROUP;
791 goto found;
794 if (rec->state != WREPL_STATE_ACTIVE) {
795 goto notfound;
798 addresses = winsdb_addr_string_list(packet, rec->addresses);
799 if (!addresses) {
800 goto notfound;
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;
809 uint32_t i;
810 uint32_t num_addrs;
812 addresses = str_list_add(NULL, addresses_1b[0]);
813 if (!addresses) {
814 goto notfound;
816 talloc_steal(packet, addresses);
817 num_addrs = 1;
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;
827 num_addrs++;
828 addresses = str_list_add(addresses, addresses_1c[i]);
829 if (!addresses) {
830 goto notfound;
835 if (rec->type == WREPL_TYPE_SGROUP) {
836 nb_flags |= NBT_NM_GROUP;
837 } else {
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 lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_randomize1Clist", false)) {
850 nbtd_wins_randomize1Clist(lp_ctx, addresses, src);
853 found:
854 nbtd_name_query_reply(nbtsock, packet, src, name,
855 0, nb_flags, addresses);
856 return;
858 notfound:
859 nbtd_negative_name_query_reply(nbtsock, packet, src);
863 release a name
865 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
866 struct nbt_name_packet *packet,
867 struct socket_address *src)
869 NTSTATUS status;
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;
876 uint8_t ret;
878 if (name->type == NBT_NAME_MASTER) {
879 goto done;
882 if (name->scope && strlen(name->scope) > 237) {
883 goto done;
886 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
887 if (!NT_STATUS_IS_OK(status)) {
888 goto done;
891 if (rec->is_static) {
892 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
893 goto done;
895 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
896 return;
899 if (rec->state != WREPL_STATE_ACTIVE) {
900 goto done;
904 * TODO: do we need to check if
905 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
906 * here?
910 * we only allow releases from an owner - other releases are
911 * silently ignored
913 if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
914 int i;
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));
920 goto done;
923 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
925 switch (rec->type) {
926 case WREPL_TYPE_UNIQUE:
927 rec->state = WREPL_STATE_RELEASED;
928 break;
930 case WREPL_TYPE_GROUP:
931 rec->state = WREPL_STATE_RELEASED;
932 break;
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;
940 break;
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;
948 break;
951 if (rec->state == WREPL_STATE_ACTIVE) {
953 * If the record is still active, we need to update the
954 * expire_time.
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 (lp_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;
980 } else {
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));
994 done:
995 /* we match w2k3 by always giving a positive reply to name releases. */
996 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
1001 answer a name query
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) {
1011 return;
1014 switch (packet->operation & NBT_OPCODE) {
1015 case NBT_OPCODE_QUERY:
1016 nbtd_winsserver_query(iface->nbtsrv->task->lp_ctx, nbtsock, packet, src);
1017 break;
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);
1024 break;
1026 case NBT_OPCODE_RELEASE:
1027 nbtd_winsserver_release(nbtsock, packet, src);
1028 break;
1034 startup the WINS server, if configured
1036 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
1038 uint32_t tmp;
1039 const char *owner;
1041 if (!lp_wins_support(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 = lp_max_wins_ttl(nbtsrv->task->lp_ctx);
1050 nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl(nbtsrv->task->lp_ctx);
1051 tmp = lp_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv", "tombstone_interval", 6*24*60*60);
1052 nbtsrv->winssrv->config.tombstone_interval = tmp;
1053 tmp = lp_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv"," tombstone_timeout", 1*24*60*60);
1054 nbtsrv->winssrv->config.tombstone_timeout = tmp;
1056 owner = lp_parm_string(nbtsrv->task->lp_ctx, NULL, "winsdb", "local_owner");
1058 if (owner == NULL) {
1059 struct interface *ifaces;
1060 load_interfaces(nbtsrv->task, lp_interfaces(nbtsrv->task->lp_ctx), &ifaces);
1061 owner = iface_n_ip(ifaces, 0);
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;