ctdb-scripts: Support storing statd-callout state in cluster filesystem
[samba4-gss.git] / source4 / nbt_server / wins / winsserver.c
blob6679961dc035d187a8fe2014fafd4c921c6fc0cc
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 "samba/service_task.h"
32 #include "system/network.h"
33 #include "lib/socket/socket.h"
34 #include "lib/socket/netif.h"
35 #include <ldb.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);
48 return ttl;
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;
60 if (mhomed) {
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);
89 rec.name = name;
90 rec.type = type;
91 rec.state = WREPL_STATE_ACTIVE;
92 rec.node = node;
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,
102 &rec, rec.addresses,
103 address,
104 winssrv->wins_db->local_owner,
105 rec.expire_time,
106 true);
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;
135 if (winsdb_addr) {
136 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
137 rec, rec->addresses,
138 winsdb_addr->address,
139 winssrv->wins_db->local_owner,
140 rec->expire_time,
141 true);
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);
156 do a sgroup merge
158 static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
159 struct nbt_name_packet *packet,
160 struct winsdb_record *rec,
161 const char *address,
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,
173 rec, rec->addresses,
174 address,
175 winssrv->wins_db->local_owner,
176 rec->expire_time,
177 true);
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;
197 NTSTATUS status;
200 static int nbtd_wins_wack_state_destructor(struct nbtd_wins_wack_state *s)
202 DLIST_REMOVE(s->iface->wack_queue, s);
203 return 0;
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) {
214 continue;
216 if (packet->operation != s->request_packet->operation) {
217 continue;
219 if (src->port != s->src->port) {
220 continue;
222 if (strcmp(src->addr, s->src->addr) != 0) {
223 continue;
226 return true;
229 return false;
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));
241 talloc_free(s);
245 allow a registration request
247 static void wins_wack_allow(struct nbtd_wins_wack_state *s)
249 NTSTATUS status;
250 uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
251 struct winsdb_record *rec = s->rec, *rec2;
252 uint32_t i,j;
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)));
260 wins_wack_deny(s);
261 return;
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)) {
269 uint8_t rcode;
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)));
276 wins_wack_deny(s);
277 return;
279 goto done;
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++) {
290 bool found = false;
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;
294 found = true;
295 break;
297 if (found) {
298 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
299 rec, rec->addresses,
300 s->reg_address,
301 s->winssrv->wins_db->local_owner,
302 rec->expire_time,
303 true);
304 if (rec->addresses == NULL) goto failed;
305 continue;
308 winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
311 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
312 rec, rec->addresses,
313 s->reg_address,
314 s->winssrv->wins_db->local_owner,
315 rec->expire_time,
316 true);
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));
329 done:
330 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
331 s->src, NBT_RCODE_OK);
332 failed:
333 talloc_free(s);
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);
343 bool found;
344 uint32_t i;
346 s->status = wins_challenge_recv(c_req, s, &s->io);
349 * if the owner denies it holds the name, then allow
350 * the registration
352 if (!NT_STATUS_IS_OK(s->status)) {
353 wins_wack_allow(s);
354 return;
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));
360 wins_wack_deny(s);
361 return;
365 * if the owner still wants the name and doesn't reply
366 * with the address trying to be registered, then deny
367 * the registration
369 found = false;
370 for (i=0; i < s->io.out.num_addresses; i++) {
371 if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
373 found = true;
374 break;
376 if (!found) {
377 wins_wack_deny(s);
378 return;
381 wins_wack_allow(s);
382 return;
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;
402 uint32_t ttl;
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;
410 s->iface = iface;
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;
445 return;
447 failed:
448 talloc_free(s);
449 nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR);
453 register a name
455 static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
456 struct nbt_name_packet *packet,
457 struct socket_address *src)
459 NTSTATUS status;
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;
480 goto done;
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;
486 goto done;
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;
492 goto done;
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;
498 goto done;
501 if (name->scope && strlen(name->scope) > 237) {
502 rcode = NBT_RCODE_SVR;
503 goto done;
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));
511 return;
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);
517 goto done;
518 } else if (!NT_STATUS_IS_OK(status)) {
519 rcode = NBT_RCODE_SVR;
520 goto done;
521 } else if (rec->is_static) {
522 if (rec->type == WREPL_TYPE_GROUP || rec->type == WREPL_TYPE_SGROUP) {
523 rcode = NBT_RCODE_OK;
524 goto done;
526 rcode = NBT_RCODE_ACT;
527 goto done;
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;
536 goto done;
539 if (rec->state == WREPL_STATE_ACTIVE) {
540 /* TODO: is this correct? */
541 rcode = wins_update_ttl(nbtsock, packet, rec, NULL, src);
542 goto done;
545 /* TODO: is this correct? */
546 winsdb_delete(winssrv->wins_db, rec);
547 rcode = wins_register_new(nbtsock, packet, src, new_type);
548 goto done;
551 if (rec->state != WREPL_STATE_ACTIVE) {
552 winsdb_delete(winssrv->wins_db, rec);
553 rcode = wins_register_new(nbtsock, packet, src, new_type);
554 goto done;
557 switch (rec->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);
567 return;
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);
575 if (winsdb_addr) {
576 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
577 goto done;
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);
585 return;
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;
591 goto done;
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;
600 goto done;
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);
608 if (winsdb_addr) {
609 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
610 goto done;
613 rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
614 goto done;
617 done:
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;
624 uint8_t *p1, *p2;
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;
631 match += 8;
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))))
638 break;
639 match++;
642 return match;
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)
663 const char *mask;
664 const char *tmp;
665 uint32_t num_addrs;
666 uint32_t idx, sidx;
667 int r;
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");
677 if (!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
685 r = random();
686 idx = sidx = r % num_addrs;
688 while (1) {
689 bool same;
691 /* if the current one is in the same subnet, use it */
692 same = iface_list_same_net(addresses[idx], src->addr, mask);
693 if (same) {
694 sidx = idx;
695 break;
698 /* we need to check for idx == 0, after checking for the same net */
699 if (idx == 0) break;
701 * if we haven't found an address in the same subnet, search in ones
702 * which match the client more
704 * some notes:
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.
711 idx = r % idx;
714 /* note sidx == 0 is also valid here ... */
715 tmp = addresses[0];
716 addresses[0] = addresses[sidx];
717 addresses[sidx] = tmp;
721 query a name
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)
728 NTSTATUS status;
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) {
740 goto notfound;
744 * w2k3 returns the first address of the 0x1B record as first address
745 * to a 0x1C query
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;
757 name_1b = *name;
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)) {
769 goto notfound;
772 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
773 goto notfound;
776 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
777 return;
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);
788 if (!addresses) {
789 goto notfound;
791 nb_flags |= NBT_NM_GROUP;
792 goto found;
795 if (rec->state != WREPL_STATE_ACTIVE) {
796 goto notfound;
799 addresses = winsdb_addr_string_list(packet, rec->addresses);
800 if (!addresses) {
801 goto notfound;
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;
810 uint32_t i;
811 uint32_t num_addrs;
813 addresses = str_list_add(NULL, addresses_1b[0]);
814 if (!addresses) {
815 goto notfound;
817 talloc_steal(packet, addresses);
818 num_addrs = 1;
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;
828 num_addrs++;
829 addresses = str_list_add(addresses, addresses_1c[i]);
830 if (!addresses) {
831 goto notfound;
836 if (rec->type == WREPL_TYPE_SGROUP) {
837 nb_flags |= NBT_NM_GROUP;
838 } else {
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);
854 found:
855 nbtd_name_query_reply(nbtsock, packet, src, name,
856 0, nb_flags, addresses);
857 return;
859 notfound:
860 nbtd_negative_name_query_reply(nbtsock, packet, src);
864 release a name
866 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
867 struct nbt_name_packet *packet,
868 struct socket_address *src)
870 NTSTATUS status;
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;
877 uint8_t ret;
879 if (name->type == NBT_NAME_MASTER) {
880 goto done;
883 if (name->scope && strlen(name->scope) > 237) {
884 goto done;
887 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
888 if (!NT_STATUS_IS_OK(status)) {
889 goto done;
892 if (rec->is_static) {
893 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
894 goto done;
896 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
897 return;
900 if (rec->state != WREPL_STATE_ACTIVE) {
901 goto done;
905 * TODO: do we need to check if
906 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
907 * here?
911 * we only allow releases from an owner - other releases are
912 * silently ignored
914 if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
915 int i;
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));
921 goto done;
924 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
926 switch (rec->type) {
927 case WREPL_TYPE_UNIQUE:
928 rec->state = WREPL_STATE_RELEASED;
929 break;
931 case WREPL_TYPE_GROUP:
932 rec->state = WREPL_STATE_RELEASED;
933 break;
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;
941 break;
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;
949 break;
952 if (rec->state == WREPL_STATE_ACTIVE) {
954 * If the record is still active, we need to update the
955 * expire_time.
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;
981 } else {
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));
995 done:
996 /* we match w2k3 by always giving a positive reply to name releases. */
997 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
1002 answer a name query
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) {
1012 return;
1015 switch (packet->operation & NBT_OPCODE) {
1016 case NBT_OPCODE_QUERY:
1017 nbtd_winsserver_query(iface->nbtsrv->task->lp_ctx, nbtsock, packet, src);
1018 break;
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);
1025 break;
1027 case NBT_OPCODE_RELEASE:
1028 nbtd_winsserver_release(nbtsock, packet, src);
1029 break;
1035 startup the WINS server, if configured
1037 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
1039 uint32_t tmp;
1040 const char *owner;
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;