More spelling fixes across source4/
[Samba/gebeck_regimport.git] / source4 / nbt_server / wins / winsserver.c
blob95d22242b31cdb359105799993c4478c88ca5de2
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 the client doesn't hold anymore
285 * and update the time stamp and owner for the ones that are still there
287 for (i=0; rec->addresses[i]; i++) {
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_TYPESAFE_QSORT(addresses, num_addrs, src, nbtd_wins_randomize1Clist_sort);
674 mask = lp_parm_string(lp_ctx, NULL, "nbtd", "wins_randomize1Clist_mask");
675 if (!mask) {
676 mask = "255.255.255.0";
680 * choose a random address to be the first in the response to the client,
681 * preferr the addresses inside the nbtd:wins_randomize1Clist_mask netmask
683 r = random();
684 idx = sidx = r % num_addrs;
686 while (1) {
687 bool same;
689 /* if the current one is in the same subnet, use it */
690 same = iface_same_net(addresses[idx], src->addr, mask);
691 if (same) {
692 sidx = idx;
693 break;
696 /* we need to check for idx == 0, after checking for the same net */
697 if (idx == 0) break;
699 * if we haven't found an address in the same subnet, search in ones
700 * which match the client more
702 * some notes:
704 * it's not "idx = idx % r" but "idx = r % idx"
705 * because in "a % b" b is the allowed range
706 * and b-1 is the maximum possible result, so it must be decreasing
707 * and the above idx == 0 check breaks the while(1) loop.
709 idx = r % idx;
712 /* note sidx == 0 is also valid here ... */
713 tmp = addresses[0];
714 addresses[0] = addresses[sidx];
715 addresses[sidx] = tmp;
719 query a name
721 static void nbtd_winsserver_query(struct loadparm_context *lp_ctx,
722 struct nbt_name_socket *nbtsock,
723 struct nbt_name_packet *packet,
724 struct socket_address *src)
726 NTSTATUS status;
727 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
728 struct nbtd_interface);
729 struct wins_server *winssrv = iface->nbtsrv->winssrv;
730 struct nbt_name *name = &packet->questions[0].name;
731 struct winsdb_record *rec;
732 struct winsdb_record *rec_1b = NULL;
733 const char **addresses;
734 const char **addresses_1b = NULL;
735 uint16_t nb_flags = 0;
737 if (name->type == NBT_NAME_MASTER) {
738 goto notfound;
742 * w2k3 returns the first address of the 0x1B record as first address
743 * to a 0x1C query
745 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
747 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Prepend1BTo1CQueries
748 * Typ: Daten REG_DWORD
749 * Value: 0 = deactivated, 1 = activated
751 if (name->type == NBT_NAME_LOGON &&
752 lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_prepend1Bto1Cqueries", true)) {
753 struct nbt_name name_1b;
755 name_1b = *name;
756 name_1b.type = NBT_NAME_PDC;
758 status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
759 if (NT_STATUS_IS_OK(status)) {
760 addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
764 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
765 if (!NT_STATUS_IS_OK(status)) {
766 if (!lp_wins_dns_proxy(lp_ctx)) {
767 goto notfound;
770 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
771 goto notfound;
774 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
775 return;
779 * for group's we always reply with
780 * 255.255.255.255 as address, even if
781 * the record is released or tombstoned
783 if (rec->type == WREPL_TYPE_GROUP) {
784 addresses = str_list_add(NULL, "255.255.255.255");
785 talloc_steal(packet, addresses);
786 if (!addresses) {
787 goto notfound;
789 nb_flags |= NBT_NM_GROUP;
790 goto found;
793 if (rec->state != WREPL_STATE_ACTIVE) {
794 goto notfound;
797 addresses = winsdb_addr_string_list(packet, rec->addresses);
798 if (!addresses) {
799 goto notfound;
803 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
804 * first 0x1B address as first address
806 if (addresses_1b && addresses_1b[0]) {
807 const char **addresses_1c = addresses;
808 uint32_t i;
809 uint32_t num_addrs;
811 addresses = str_list_add(NULL, addresses_1b[0]);
812 if (!addresses) {
813 goto notfound;
815 talloc_steal(packet, addresses);
816 num_addrs = 1;
818 for (i=0; addresses_1c[i]; i++) {
819 if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
822 * stop when we already have 25 addresses
824 if (num_addrs >= 25) break;
826 num_addrs++;
827 addresses = str_list_add(addresses, addresses_1c[i]);
828 if (!addresses) {
829 goto notfound;
834 if (rec->type == WREPL_TYPE_SGROUP) {
835 nb_flags |= NBT_NM_GROUP;
836 } else {
837 nb_flags |= (rec->node <<13);
841 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
843 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList
844 * Typ: Daten REG_DWORD
845 * Value: 0 = deactivated, 1 = activated
847 if (name->type == NBT_NAME_LOGON &&
848 lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_randomize1Clist", false)) {
849 nbtd_wins_randomize1Clist(lp_ctx, addresses, src);
852 found:
853 nbtd_name_query_reply(nbtsock, packet, src, name,
854 0, nb_flags, addresses);
855 return;
857 notfound:
858 nbtd_negative_name_query_reply(nbtsock, packet, src);
862 release a name
864 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
865 struct nbt_name_packet *packet,
866 struct socket_address *src)
868 NTSTATUS status;
869 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
870 struct nbtd_interface);
871 struct wins_server *winssrv = iface->nbtsrv->winssrv;
872 struct nbt_name *name = &packet->questions[0].name;
873 struct winsdb_record *rec;
874 uint32_t modify_flags = 0;
875 uint8_t ret;
877 if (name->type == NBT_NAME_MASTER) {
878 goto done;
881 if (name->scope && strlen(name->scope) > 237) {
882 goto done;
885 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
886 if (!NT_STATUS_IS_OK(status)) {
887 goto done;
890 if (rec->is_static) {
891 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
892 goto done;
894 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
895 return;
898 if (rec->state != WREPL_STATE_ACTIVE) {
899 goto done;
903 * TODO: do we need to check if
904 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
905 * here?
909 * we only allow releases from an owner - other releases are
910 * silently ignored
912 if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
913 int i;
914 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
915 DEBUGADD(4, ("Registered Addresses: \n"));
916 for (i=0; rec->addresses && rec->addresses[i]; i++) {
917 DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
919 goto done;
922 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
924 switch (rec->type) {
925 case WREPL_TYPE_UNIQUE:
926 rec->state = WREPL_STATE_RELEASED;
927 break;
929 case WREPL_TYPE_GROUP:
930 rec->state = WREPL_STATE_RELEASED;
931 break;
933 case WREPL_TYPE_SGROUP:
934 winsdb_addr_list_remove(rec->addresses, src->addr);
935 /* TODO: do we need to take the ownership here? */
936 if (winsdb_addr_list_length(rec->addresses) == 0) {
937 rec->state = WREPL_STATE_RELEASED;
939 break;
941 case WREPL_TYPE_MHOMED:
942 winsdb_addr_list_remove(rec->addresses, src->addr);
943 /* TODO: do we need to take the ownership here? */
944 if (winsdb_addr_list_length(rec->addresses) == 0) {
945 rec->state = WREPL_STATE_RELEASED;
947 break;
950 if (rec->state == WREPL_STATE_ACTIVE) {
952 * If the record is still active, we need to update the
953 * expire_time.
955 * if we're not the owner, we need to take the ownership.
957 rec->expire_time= time(NULL) + winssrv->config.max_renew_interval;
958 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) != 0) {
959 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
961 if (lp_parm_bool(iface->nbtsrv->task->lp_ctx, NULL, "wreplsrv", "propagate name releases", false)) {
963 * We have an option to propagate every name release,
964 * this is off by default to match windows servers
966 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
968 } else if (rec->state == WREPL_STATE_RELEASED) {
970 * if we're not the owner, we need to take the owner ship
971 * and make the record tombstone, but expire after
972 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
973 * like for normal tombstone records.
974 * This is to replicate the record directly to the original owner,
975 * where the record is still active
977 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
978 rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
979 } else {
980 rec->state = WREPL_STATE_TOMBSTONE;
981 rec->expire_time= time(NULL) +
982 winssrv->config.tombstone_interval +
983 winssrv->config.tombstone_timeout;
984 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
988 ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
989 if (ret != NBT_RCODE_OK) {
990 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
991 nbt_name_string(rec, rec->name), src->addr, ret));
993 done:
994 /* we match w2k3 by always giving a positive reply to name releases. */
995 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
1000 answer a name query
1002 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
1003 struct nbt_name_packet *packet,
1004 struct socket_address *src)
1006 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
1007 struct nbtd_interface);
1008 struct wins_server *winssrv = iface->nbtsrv->winssrv;
1009 if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
1010 return;
1013 switch (packet->operation & NBT_OPCODE) {
1014 case NBT_OPCODE_QUERY:
1015 nbtd_winsserver_query(iface->nbtsrv->task->lp_ctx, nbtsock, packet, src);
1016 break;
1018 case NBT_OPCODE_REGISTER:
1019 case NBT_OPCODE_REFRESH:
1020 case NBT_OPCODE_REFRESH2:
1021 case NBT_OPCODE_MULTI_HOME_REG:
1022 nbtd_winsserver_register(nbtsock, packet, src);
1023 break;
1025 case NBT_OPCODE_RELEASE:
1026 nbtd_winsserver_release(nbtsock, packet, src);
1027 break;
1033 startup the WINS server, if configured
1035 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
1037 uint32_t tmp;
1038 const char *owner;
1040 if (!lp_wins_support(nbtsrv->task->lp_ctx)) {
1041 nbtsrv->winssrv = NULL;
1042 return NT_STATUS_OK;
1045 nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
1046 NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
1048 nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl(nbtsrv->task->lp_ctx);
1049 nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl(nbtsrv->task->lp_ctx);
1050 tmp = lp_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv", "tombstone_interval", 6*24*60*60);
1051 nbtsrv->winssrv->config.tombstone_interval = tmp;
1052 tmp = lp_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv"," tombstone_timeout", 1*24*60*60);
1053 nbtsrv->winssrv->config.tombstone_timeout = tmp;
1055 owner = lp_parm_string(nbtsrv->task->lp_ctx, NULL, "winsdb", "local_owner");
1057 if (owner == NULL) {
1058 struct interface *ifaces;
1059 load_interfaces(nbtsrv->task, lp_interfaces(nbtsrv->task->lp_ctx), &ifaces);
1060 owner = iface_n_ip(ifaces, 0);
1063 nbtsrv->winssrv->wins_db = winsdb_connect(nbtsrv->winssrv, nbtsrv->task->event_ctx,
1064 nbtsrv->task->lp_ctx,
1065 owner, WINSDB_HANDLE_CALLER_NBTD);
1066 if (!nbtsrv->winssrv->wins_db) {
1067 return NT_STATUS_INTERNAL_DB_ERROR;
1070 irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");
1072 return NT_STATUS_OK;