examples: fix build on AIX6
[Samba/gebeck_regimport.git] / source4 / nbt_server / wins / winsserver.c
blobe9598bab8c4ed91fd0439f6837b3b234c8f3413e
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 <ldb.h>
36 #include "param/param.h"
37 #include "libcli/resolve/resolve.h"
38 #include "lib/util/util_net.h"
41 work out the ttl we will use given a client requested ttl
43 uint32_t wins_server_ttl(struct wins_server *winssrv, uint32_t ttl)
45 ttl = MIN(ttl, winssrv->config.max_renew_interval);
46 ttl = MAX(ttl, winssrv->config.min_renew_interval);
47 return ttl;
50 static enum wrepl_name_type wrepl_type(uint16_t nb_flags, struct nbt_name *name, bool mhomed)
52 /* this copes with the nasty hack that is the type 0x1c name */
53 if (name->type == NBT_NAME_LOGON) {
54 return WREPL_TYPE_SGROUP;
56 if (nb_flags & NBT_NM_GROUP) {
57 return WREPL_TYPE_GROUP;
59 if (mhomed) {
60 return WREPL_TYPE_MHOMED;
62 return WREPL_TYPE_UNIQUE;
66 register a new name with WINS
68 static uint8_t wins_register_new(struct nbt_name_socket *nbtsock,
69 struct nbt_name_packet *packet,
70 const struct socket_address *src,
71 enum wrepl_name_type type)
73 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
74 struct nbtd_interface);
75 struct wins_server *winssrv = iface->nbtsrv->winssrv;
76 struct nbt_name *name = &packet->questions[0].name;
77 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
78 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
79 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
80 struct winsdb_record rec;
81 enum wrepl_name_node node;
83 #define WREPL_NODE_NBT_FLAGS(nb_flags) \
84 ((nb_flags & NBT_NM_OWNER_TYPE)>>13)
86 node = WREPL_NODE_NBT_FLAGS(nb_flags);
88 rec.name = name;
89 rec.type = type;
90 rec.state = WREPL_STATE_ACTIVE;
91 rec.node = node;
92 rec.is_static = false;
93 rec.expire_time = time(NULL) + ttl;
94 rec.version = 0; /* will be allocated later */
95 rec.wins_owner = NULL; /* will be set later */
96 rec.registered_by = src->addr;
97 rec.addresses = winsdb_addr_list_make(packet);
98 if (rec.addresses == NULL) return NBT_RCODE_SVR;
100 rec.addresses = winsdb_addr_list_add(winssrv->wins_db,
101 &rec, rec.addresses,
102 address,
103 winssrv->wins_db->local_owner,
104 rec.expire_time,
105 true);
106 if (rec.addresses == NULL) return NBT_RCODE_SVR;
108 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
109 nbt_name_string(packet, name), rec.addresses[0]->address));
111 return winsdb_add(winssrv->wins_db, &rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
116 update the ttl on an existing record
118 static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock,
119 struct nbt_name_packet *packet,
120 struct winsdb_record *rec,
121 struct winsdb_addr *winsdb_addr,
122 const struct socket_address *src)
124 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
125 struct nbtd_interface);
126 struct wins_server *winssrv = iface->nbtsrv->winssrv;
127 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
128 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
129 uint32_t modify_flags = 0;
131 rec->expire_time = time(NULL) + ttl;
132 rec->registered_by = src->addr;
134 if (winsdb_addr) {
135 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
136 rec, rec->addresses,
137 winsdb_addr->address,
138 winssrv->wins_db->local_owner,
139 rec->expire_time,
140 true);
141 if (rec->addresses == NULL) return NBT_RCODE_SVR;
144 if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) {
145 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
148 DEBUG(5,("WINS: refreshed registration of %s at %s\n",
149 nbt_name_string(packet, rec->name), address));
151 return winsdb_modify(winssrv->wins_db, rec, modify_flags);
155 do a sgroup merge
157 static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
158 struct nbt_name_packet *packet,
159 struct winsdb_record *rec,
160 const char *address,
161 const struct socket_address *src)
163 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
164 struct nbtd_interface);
165 struct wins_server *winssrv = iface->nbtsrv->winssrv;
166 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
168 rec->expire_time = time(NULL) + ttl;
169 rec->registered_by = src->addr;
171 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
172 rec, rec->addresses,
173 address,
174 winssrv->wins_db->local_owner,
175 rec->expire_time,
176 true);
177 if (rec->addresses == NULL) return NBT_RCODE_SVR;
179 DEBUG(5,("WINS: sgroup merge of %s at %s\n",
180 nbt_name_string(packet, rec->name), address));
182 return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
185 struct nbtd_wins_wack_state {
186 struct nbtd_wins_wack_state *prev, *next;
187 struct wins_server *winssrv;
188 struct nbt_name_socket *nbtsock;
189 struct nbtd_interface *iface;
190 struct nbt_name_packet *request_packet;
191 struct winsdb_record *rec;
192 struct socket_address *src;
193 const char *reg_address;
194 enum wrepl_name_type new_type;
195 struct wins_challenge_io io;
196 NTSTATUS status;
199 static int nbtd_wins_wack_state_destructor(struct nbtd_wins_wack_state *s)
201 DLIST_REMOVE(s->iface->wack_queue, s);
202 return 0;
205 static bool wins_check_wack_queue(struct nbtd_interface *iface,
206 struct nbt_name_packet *packet,
207 struct socket_address *src)
209 struct nbtd_wins_wack_state *s;
211 for (s= iface->wack_queue; s; s = s->next) {
212 if (packet->name_trn_id != s->request_packet->name_trn_id) {
213 continue;
215 if (packet->operation != s->request_packet->operation) {
216 continue;
218 if (src->port != s->src->port) {
219 continue;
221 if (strcmp(src->addr, s->src->addr) != 0) {
222 continue;
225 return true;
228 return false;
232 deny a registration request
234 static void wins_wack_deny(struct nbtd_wins_wack_state *s)
236 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
237 s->src, NBT_RCODE_ACT);
238 DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
239 nbt_name_string(s, s->rec->name), s->src->addr, s->src->port));
240 talloc_free(s);
244 allow a registration request
246 static void wins_wack_allow(struct nbtd_wins_wack_state *s)
248 NTSTATUS status;
249 uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
250 struct winsdb_record *rec = s->rec, *rec2;
251 uint32_t i,j;
253 status = winsdb_lookup(s->winssrv->wins_db, rec->name, s, &rec2);
254 if (!NT_STATUS_IS_OK(status) ||
255 rec2->version != rec->version ||
256 strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
257 DEBUG(5,("WINS: record %s changed during WACK - failing registration\n",
258 nbt_name_string(s, rec->name)));
259 wins_wack_deny(s);
260 return;
264 * if the old name owner doesn't hold the name anymore
265 * handle the request as new registration for the new name owner
267 if (!NT_STATUS_IS_OK(s->status)) {
268 uint8_t rcode;
270 winsdb_delete(s->winssrv->wins_db, rec);
271 rcode = wins_register_new(s->nbtsock, s->request_packet, s->src, s->new_type);
272 if (rcode != NBT_RCODE_OK) {
273 DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
274 nbt_name_string(s, rec->name)));
275 wins_wack_deny(s);
276 return;
278 goto done;
281 rec->expire_time = time(NULL) + ttl;
282 rec->registered_by = s->src->addr;
285 * now remove all addresses that the client doesn't hold anymore
286 * and update the time stamp and owner for the ones that are still there
288 for (i=0; rec->addresses[i]; i++) {
289 bool found = false;
290 for (j=0; j < s->io.out.num_addresses; j++) {
291 if (strcmp(rec->addresses[i]->address, s->io.out.addresses[j]) != 0) continue;
293 found = true;
294 break;
296 if (found) {
297 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
298 rec, rec->addresses,
299 s->reg_address,
300 s->winssrv->wins_db->local_owner,
301 rec->expire_time,
302 true);
303 if (rec->addresses == NULL) goto failed;
304 continue;
307 winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
310 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
311 rec, rec->addresses,
312 s->reg_address,
313 s->winssrv->wins_db->local_owner,
314 rec->expire_time,
315 true);
316 if (rec->addresses == NULL) goto failed;
318 /* if we have more than one address, this becomes implicit a MHOMED record */
319 if (winsdb_addr_list_length(rec->addresses) > 1) {
320 rec->type = WREPL_TYPE_MHOMED;
323 winsdb_modify(s->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
325 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
326 nbt_name_string(s, rec->name), s->reg_address));
328 done:
329 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
330 s->src, NBT_RCODE_OK);
331 failed:
332 talloc_free(s);
336 called when a name query to a current owner completes
338 static void wack_wins_challenge_handler(struct composite_context *c_req)
340 struct nbtd_wins_wack_state *s = talloc_get_type(c_req->async.private_data,
341 struct nbtd_wins_wack_state);
342 bool found;
343 uint32_t i;
345 s->status = wins_challenge_recv(c_req, s, &s->io);
348 * if the owner denies it holds the name, then allow
349 * the registration
351 if (!NT_STATUS_IS_OK(s->status)) {
352 wins_wack_allow(s);
353 return;
356 if (s->new_type == WREPL_TYPE_GROUP || s->new_type == WREPL_TYPE_SGROUP) {
357 DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
358 nbt_name_string(s, s->rec->name), s->new_type, s->rec->type));
359 wins_wack_deny(s);
360 return;
364 * if the owner still wants the name and doesn't reply
365 * with the address trying to be registered, then deny
366 * the registration
368 found = false;
369 for (i=0; i < s->io.out.num_addresses; i++) {
370 if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
372 found = true;
373 break;
375 if (!found) {
376 wins_wack_deny(s);
377 return;
380 wins_wack_allow(s);
381 return;
386 a client has asked to register a unique name that someone else owns. We
387 need to ask each of the current owners if they still want it. If they do
388 then reject the registration, otherwise allow it
390 static void wins_register_wack(struct nbt_name_socket *nbtsock,
391 struct nbt_name_packet *packet,
392 struct winsdb_record *rec,
393 struct socket_address *src,
394 enum wrepl_name_type new_type)
396 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
397 struct nbtd_interface);
398 struct wins_server *winssrv = iface->nbtsrv->winssrv;
399 struct nbtd_wins_wack_state *s;
400 struct composite_context *c_req;
401 uint32_t ttl;
403 s = talloc_zero(nbtsock, struct nbtd_wins_wack_state);
404 if (s == NULL) goto failed;
406 /* package up the state variables for this wack request */
407 s->winssrv = winssrv;
408 s->nbtsock = nbtsock;
409 s->iface = iface;
410 s->request_packet = talloc_steal(s, packet);
411 s->rec = talloc_steal(s, rec);
412 s->reg_address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
413 s->new_type = new_type;
414 s->src = src;
415 if (talloc_reference(s, src) == NULL) goto failed;
417 s->io.in.nbtd_server = iface->nbtsrv;
418 s->io.in.nbt_port = lpcfg_nbt_port(iface->nbtsrv->task->lp_ctx);
419 s->io.in.event_ctx = iface->nbtsrv->task->event_ctx;
420 s->io.in.name = rec->name;
421 s->io.in.num_addresses = winsdb_addr_list_length(rec->addresses);
422 s->io.in.addresses = winsdb_addr_string_list(s, rec->addresses);
423 if (s->io.in.addresses == NULL) goto failed;
425 DLIST_ADD_END(iface->wack_queue, s, struct nbtd_wins_wack_state *);
427 talloc_set_destructor(s, nbtd_wins_wack_state_destructor);
430 * send a WACK to the client, specifying the maximum time it could
431 * take to check with the owner, plus some slack
433 ttl = 5 + 4 * winsdb_addr_list_length(rec->addresses);
434 nbtd_wack_reply(nbtsock, packet, src, ttl);
437 * send the challenge to the old addresses
439 c_req = wins_challenge_send(s, &s->io);
440 if (c_req == NULL) goto failed;
442 c_req->async.fn = wack_wins_challenge_handler;
443 c_req->async.private_data = s;
444 return;
446 failed:
447 talloc_free(s);
448 nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR);
452 register a name
454 static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
455 struct nbt_name_packet *packet,
456 struct socket_address *src)
458 NTSTATUS status;
459 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
460 struct nbtd_interface);
461 struct wins_server *winssrv = iface->nbtsrv->winssrv;
462 struct nbt_name *name = &packet->questions[0].name;
463 struct winsdb_record *rec;
464 uint8_t rcode = NBT_RCODE_OK;
465 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
466 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
467 bool mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
468 enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
469 struct winsdb_addr *winsdb_addr = NULL;
470 bool duplicate_packet;
473 * as a special case, the local master browser name is always accepted
474 * for registration, but never stored, but w2k3 stores it if it's registered
475 * as a group name, (but a query for the 0x1D name still returns not found!)
477 if (name->type == NBT_NAME_MASTER && !(nb_flags & NBT_NM_GROUP)) {
478 rcode = NBT_RCODE_OK;
479 goto done;
482 /* w2k3 refuses 0x1B names with marked as group */
483 if (name->type == NBT_NAME_PDC && (nb_flags & NBT_NM_GROUP)) {
484 rcode = NBT_RCODE_RFS;
485 goto done;
488 /* w2k3 refuses 0x1C names with out marked as group */
489 if (name->type == NBT_NAME_LOGON && !(nb_flags & NBT_NM_GROUP)) {
490 rcode = NBT_RCODE_RFS;
491 goto done;
494 /* w2k3 refuses 0x1E names with out marked as group */
495 if (name->type == NBT_NAME_BROWSER && !(nb_flags & NBT_NM_GROUP)) {
496 rcode = NBT_RCODE_RFS;
497 goto done;
500 if (name->scope && strlen(name->scope) > 237) {
501 rcode = NBT_RCODE_SVR;
502 goto done;
505 duplicate_packet = wins_check_wack_queue(iface, packet, src);
506 if (duplicate_packet) {
507 /* just ignore the packet */
508 DEBUG(5,("Ignoring duplicate packet while WACK is pending from %s:%d\n",
509 src->addr, src->port));
510 return;
513 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
514 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
515 rcode = wins_register_new(nbtsock, packet, src, new_type);
516 goto done;
517 } else if (!NT_STATUS_IS_OK(status)) {
518 rcode = NBT_RCODE_SVR;
519 goto done;
520 } else if (rec->is_static) {
521 if (rec->type == WREPL_TYPE_GROUP || rec->type == WREPL_TYPE_SGROUP) {
522 rcode = NBT_RCODE_OK;
523 goto done;
525 rcode = NBT_RCODE_ACT;
526 goto done;
529 if (rec->type == WREPL_TYPE_GROUP) {
530 if (new_type != WREPL_TYPE_GROUP) {
531 DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
532 " while a normal group is already there\n",
533 nbt_name_string(packet, name), new_type));
534 rcode = NBT_RCODE_ACT;
535 goto done;
538 if (rec->state == WREPL_STATE_ACTIVE) {
539 /* TODO: is this correct? */
540 rcode = wins_update_ttl(nbtsock, packet, rec, NULL, src);
541 goto done;
544 /* TODO: is this correct? */
545 winsdb_delete(winssrv->wins_db, rec);
546 rcode = wins_register_new(nbtsock, packet, src, new_type);
547 goto done;
550 if (rec->state != WREPL_STATE_ACTIVE) {
551 winsdb_delete(winssrv->wins_db, rec);
552 rcode = wins_register_new(nbtsock, packet, src, new_type);
553 goto done;
556 switch (rec->type) {
557 case WREPL_TYPE_UNIQUE:
558 case WREPL_TYPE_MHOMED:
560 * if its an active unique name, and the registration is for a group, then
561 * see if the unique name owner still wants the name
562 * TODO: is this correct?
564 if (new_type == WREPL_TYPE_GROUP || new_type == WREPL_TYPE_GROUP) {
565 wins_register_wack(nbtsock, packet, rec, src, new_type);
566 return;
570 * if the registration is for an address that is currently active, then
571 * just update the expiry time of the record and the address
573 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
574 if (winsdb_addr) {
575 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
576 goto done;
580 * we have to do a WACK to see if the current owner is willing
581 * to give up its claim
583 wins_register_wack(nbtsock, packet, rec, src, new_type);
584 return;
586 case WREPL_TYPE_GROUP:
587 /* this should not be reached as normal groups are handled above */
588 DEBUG(0,("BUG at %s\n",__location__));
589 rcode = NBT_RCODE_ACT;
590 goto done;
592 case WREPL_TYPE_SGROUP:
593 /* if the new record isn't also a special group, refuse the registration */
594 if (new_type != WREPL_TYPE_SGROUP) {
595 DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
596 " while a special group is already there\n",
597 nbt_name_string(packet, name), new_type));
598 rcode = NBT_RCODE_ACT;
599 goto done;
603 * if the registration is for an address that is currently active, then
604 * just update the expiry time of the record and the address
606 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
607 if (winsdb_addr) {
608 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
609 goto done;
612 rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
613 goto done;
616 done:
617 nbtd_name_registration_reply(nbtsock, packet, src, rcode);
620 static uint32_t ipv4_match_bits(struct in_addr ip1, struct in_addr ip2)
622 uint32_t i, j, match=0;
623 uint8_t *p1, *p2;
625 p1 = (uint8_t *)&ip1.s_addr;
626 p2 = (uint8_t *)&ip2.s_addr;
628 for (i=0; i<4; i++) {
629 if (p1[i] != p2[i]) break;
630 match += 8;
633 if (i==4) return match;
635 for (j=0; j<8; j++) {
636 if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j))))
637 break;
638 match++;
641 return match;
644 static int nbtd_wins_randomize1Clist_sort(void *p1,/* (const char **) */
645 void *p2,/* (const char **) */
646 struct socket_address *src)
648 const char *a1 = (const char *)*(const char **)p1;
649 const char *a2 = (const char *)*(const char **)p2;
650 uint32_t match_bits1;
651 uint32_t match_bits2;
653 match_bits1 = ipv4_match_bits(interpret_addr2(a1), interpret_addr2(src->addr));
654 match_bits2 = ipv4_match_bits(interpret_addr2(a2), interpret_addr2(src->addr));
656 return match_bits2 - match_bits1;
659 static void nbtd_wins_randomize1Clist(struct loadparm_context *lp_ctx,
660 const char **addresses, struct socket_address *src)
662 const char *mask;
663 const char *tmp;
664 uint32_t num_addrs;
665 uint32_t idx, sidx;
666 int r;
668 for (num_addrs=0; addresses[num_addrs]; num_addrs++) { /* noop */ }
670 if (num_addrs <= 1) return; /* nothing to do */
672 /* first sort the addresses depending on the matching to the client */
673 LDB_TYPESAFE_QSORT(addresses, num_addrs, src, nbtd_wins_randomize1Clist_sort);
675 mask = lpcfg_parm_string(lp_ctx, NULL, "nbtd", "wins_randomize1Clist_mask");
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_list_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 lpcfg_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 (!lpcfg_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 lpcfg_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 (lpcfg_parm_bool(iface->nbtsrv->task->lp_ctx, NULL, "wreplsrv", "propagate name releases", false)) {
964 * We have an option to propagate every name release,
965 * this is off by default to match windows servers
967 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
969 } else if (rec->state == WREPL_STATE_RELEASED) {
971 * if we're not the owner, we need to take the owner ship
972 * and make the record tombstone, but expire after
973 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
974 * like for normal tombstone records.
975 * This is to replicate the record directly to the original owner,
976 * where the record is still active
978 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
979 rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
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 (!lpcfg_we_are_a_wins_server(nbtsrv->task->lp_ctx)) {
1042 nbtsrv->winssrv = NULL;
1043 return NT_STATUS_OK;
1046 nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
1047 NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
1049 nbtsrv->winssrv->config.max_renew_interval = lpcfg_max_wins_ttl(nbtsrv->task->lp_ctx);
1050 nbtsrv->winssrv->config.min_renew_interval = lpcfg_min_wins_ttl(nbtsrv->task->lp_ctx);
1051 tmp = lpcfg_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv", "tombstone_interval", 6*24*60*60);
1052 nbtsrv->winssrv->config.tombstone_interval = tmp;
1053 tmp = lpcfg_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv"," tombstone_timeout", 1*24*60*60);
1054 nbtsrv->winssrv->config.tombstone_timeout = tmp;
1056 owner = lpcfg_parm_string(nbtsrv->task->lp_ctx, NULL, "winsdb", "local_owner");
1058 if (owner == NULL) {
1059 struct interface *ifaces;
1060 load_interface_list(nbtsrv->task, nbtsrv->task->lp_ctx, &ifaces);
1061 owner = iface_list_first_v4(ifaces);
1064 nbtsrv->winssrv->wins_db = winsdb_connect(nbtsrv->winssrv, nbtsrv->task->event_ctx,
1065 nbtsrv->task->lp_ctx,
1066 owner, WINSDB_HANDLE_CALLER_NBTD);
1067 if (!nbtsrv->winssrv->wins_db) {
1068 return NT_STATUS_INTERNAL_DB_ERROR;
1071 irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");
1073 return NT_STATUS_OK;