This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "system/time.h"
#include "libcli/composite/composite.h"
#include "smbd/service_task.h"
+#include "system/network.h"
#include "lib/socket/socket.h"
+#include "lib/socket/netif.h"
#include "lib/ldb/include/ldb.h"
+#include "param/param.h"
/*
work out the ttl we will use given a client requested ttl
return ttl;
}
-static enum wrepl_name_type wrepl_type(uint16_t nb_flags, struct nbt_name *name, BOOL mhomed)
+static enum wrepl_name_type wrepl_type(uint16_t nb_flags, struct nbt_name *name, bool mhomed)
{
/* this copes with the nasty hack that is the type 0x1c name */
if (name->type == NBT_NAME_LOGON) {
rec.type = type;
rec.state = WREPL_STATE_ACTIVE;
rec.node = node;
- rec.is_static = False;
+ rec.is_static = false;
rec.expire_time = time(NULL) + ttl;
rec.version = 0; /* will be allocated later */
rec.wins_owner = NULL; /* will be set later */
address,
winssrv->wins_db->local_owner,
rec.expire_time,
- True);
+ true);
if (rec.addresses == NULL) return NBT_RCODE_SVR;
DEBUG(4,("WINS: accepted registration of %s with address %s\n",
winsdb_addr->address,
winssrv->wins_db->local_owner,
rec->expire_time,
- True);
+ true);
if (rec->addresses == NULL) return NBT_RCODE_SVR;
}
address,
winssrv->wins_db->local_owner,
rec->expire_time,
- True);
+ true);
if (rec->addresses == NULL) return NBT_RCODE_SVR;
DEBUG(5,("WINS: sgroup merge of %s at %s\n",
if (!NT_STATUS_IS_OK(status) ||
rec2->version != rec->version ||
strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
- DEBUG(1,("WINS: record %s changed during WACK - failing registration\n",
+ DEBUG(5,("WINS: record %s changed during WACK - failing registration\n",
nbt_name_string(s, rec->name)));
wins_wack_deny(s);
return;
* and update the time stamp and owner for the ownes that are still there
*/
for (i=0; rec->addresses[i]; i++) {
- BOOL found = False;
+ bool found = false;
for (j=0; j < s->io.out.num_addresses; j++) {
if (strcmp(rec->addresses[i]->address, s->io.out.addresses[j]) != 0) continue;
- found = True;
+ found = true;
break;
}
if (found) {
s->reg_address,
s->winssrv->wins_db->local_owner,
rec->expire_time,
- True);
+ true);
if (rec->addresses == NULL) goto failed;
continue;
}
s->reg_address,
s->winssrv->wins_db->local_owner,
rec->expire_time,
- True);
+ true);
if (rec->addresses == NULL) goto failed;
/* if we have more than one address, this becomes implicit a MHOMED record */
{
struct wack_state *s = talloc_get_type(c_req->async.private_data,
struct wack_state);
- BOOL found;
+ bool found;
uint32_t i;
s->status = wins_challenge_recv(c_req, s, &s->io);
* with the address trying to be registered, then deny
* the registration
*/
- found = False;
+ found = false;
for (i=0; i < s->io.out.num_addresses; i++) {
if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
- found = True;
+ found = true;
break;
}
if (!found) {
uint8_t rcode = NBT_RCODE_OK;
uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
- BOOL mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
+ bool mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
struct winsdb_addr *winsdb_addr = NULL;
nbtd_name_registration_reply(nbtsock, packet, src, rcode);
}
+static uint32_t ipv4_match_bits(struct in_addr ip1, struct in_addr ip2)
+{
+ uint32_t i, j, match=0;
+ uint8_t *p1, *p2;
+
+ p1 = (uint8_t *)&ip1.s_addr;
+ p2 = (uint8_t *)&ip2.s_addr;
+
+ for (i=0; i<4; i++) {
+ if (p1[i] != p2[i]) break;
+ match += 8;
+ }
+
+ if (i==4) return match;
+
+ for (j=0; j<8; j++) {
+ if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j))))
+ break;
+ match++;
+ }
+
+ return match;
+}
+
+static int nbtd_wins_randomize1Clist_sort(void *p1,/* (const char **) */
+ void *p2,/* (const char **) */
+ struct socket_address *src)
+{
+ const char *a1 = (const char *)*(const char **)p1;
+ const char *a2 = (const char *)*(const char **)p2;
+ uint32_t match_bits1;
+ uint32_t match_bits2;
+
+ match_bits1 = ipv4_match_bits(interpret_addr2(a1), interpret_addr2(src->addr));
+ match_bits2 = ipv4_match_bits(interpret_addr2(a2), interpret_addr2(src->addr));
+
+ return match_bits2 - match_bits1;
+}
+
+static void nbtd_wins_randomize1Clist(const char **addresses, struct socket_address *src)
+{
+ const char *mask;
+ const char *tmp;
+ uint32_t num_addrs;
+ uint32_t idx, sidx;
+ int r;
+
+ for (num_addrs=0; addresses[num_addrs]; num_addrs++) { /* noop */ }
+
+ if (num_addrs <= 1) return; /* nothing to do */
+
+ /* first sort the addresses depending on the matching to the client */
+ ldb_qsort(addresses, num_addrs , sizeof(addresses[0]),
+ src, (ldb_qsort_cmp_fn_t)nbtd_wins_randomize1Clist_sort);
+
+ mask = lp_parm_string(global_loadparm, NULL, "nbtd", "wins_randomize1Clist_mask");
+ if (!mask) {
+ mask = "255.255.255.0";
+ }
+
+ /*
+ * choose a random address to be the first in the response to the client,
+ * preferr the addresses inside the nbtd:wins_randomize1Clist_mask netmask
+ */
+ r = random();
+ idx = sidx = r % num_addrs;
+
+ while (1) {
+ bool same;
+
+ /* if the current one is in the same subnet, use it */
+ same = iface_same_net(addresses[idx], src->addr, mask);
+ if (same) {
+ sidx = idx;
+ break;
+ }
+
+ /* we need to check for idx == 0, after checking for the same net */
+ if (idx == 0) break;
+ /*
+ * if we haven't found an address in the same subnet, search in ones
+ * which match the client more
+ *
+ * some notes:
+ *
+ * it's not "idx = idx % r" but "idx = r % idx"
+ * because in "a % b" b is the allowed range
+ * and b-1 is the maximum possible result, so it must be decreasing
+ * and the above idx == 0 check breaks the while(1) loop.
+ */
+ idx = r % idx;
+ }
+
+ /* note sidx == 0 is also valid here ... */
+ tmp = addresses[0];
+ addresses[0] = addresses[sidx];
+ addresses[sidx] = tmp;
+}
+
/*
query a name
*/
* Typ: Daten REG_DWORD
* Value: 0 = deactivated, 1 = activated
*/
- if (name->type == NBT_NAME_LOGON && lp_parm_bool(-1, "nbtd", "wins_prepend1Bto1Cqueries", True)) {
+ if (name->type == NBT_NAME_LOGON &&
+ lp_parm_bool(global_loadparm, NULL, "nbtd", "wins_prepend1Bto1Cqueries", true)) {
struct nbt_name name_1b;
name_1b = *name;
status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
if (!NT_STATUS_IS_OK(status)) {
- if (!lp_wins_dns_proxy()) {
+ if (!lp_wins_dns_proxy(global_loadparm)) {
goto notfound;
}
nb_flags |= (rec->node <<13);
}
+ /*
+ * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
+ *
+ * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList
+ * Typ: Daten REG_DWORD
+ * Value: 0 = deactivated, 1 = activated
+ */
+ if (name->type == NBT_NAME_LOGON &&
+ lp_parm_bool(global_loadparm, NULL, "nbtd", "wins_randomize1Clist", false)) {
+ nbtd_wins_randomize1Clist(addresses, src);
+ }
+
found:
nbtd_name_query_reply(nbtsock, packet, src, name,
0, nb_flags, addresses);
{
uint32_t tmp;
- if (!lp_wins_support()) {
+ if (!lp_wins_support(global_loadparm)) {
nbtsrv->winssrv = NULL;
return NT_STATUS_OK;
}
nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
- nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl();
- nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl();
- tmp = lp_parm_int(-1,"wreplsrv","tombstone_interval", 6*24*60*60);
+ nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl(global_loadparm);
+ nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl(global_loadparm);
+ tmp = lp_parm_int(global_loadparm, NULL, "wreplsrv", "tombstone_interval", 6*24*60*60);
nbtsrv->winssrv->config.tombstone_interval = tmp;
- tmp = lp_parm_int(-1,"wreplsrv","tombstone_timeout", 1*24*60*60);
+ tmp = lp_parm_int(global_loadparm, NULL, "wreplsrv"," tombstone_timeout", 1*24*60*60);
nbtsrv->winssrv->config.tombstone_timeout = tmp;
nbtsrv->winssrv->wins_db = winsdb_connect(nbtsrv->winssrv, WINSDB_HANDLE_CALLER_NBTD);