wmi-1.3.16 from opsview.com
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
wins server dns proxy
|
||||
|
||||
Copyright (C) Stefan Metzmacher 2005
|
||||
|
||||
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
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "nbt_server/nbt_server.h"
|
||||
#include "nbt_server/wins/winsdb.h"
|
||||
#include "nbt_server/wins/winsserver.h"
|
||||
#include "system/time.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "smbd/service_task.h"
|
||||
#include "libcli/resolve/resolve.h"
|
||||
|
||||
struct wins_dns_proxy_state {
|
||||
struct nbt_name_socket *nbtsock;
|
||||
struct nbt_name_packet *packet;
|
||||
struct socket_address *src;
|
||||
};
|
||||
|
||||
static void nbtd_wins_dns_proxy_handler(struct composite_context *creq)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct wins_dns_proxy_state *s = talloc_get_type(creq->async.private_data,
|
||||
struct wins_dns_proxy_state);
|
||||
struct nbt_name *name = &s->packet->questions[0].name;
|
||||
const char *address;
|
||||
const char **addresses;
|
||||
uint16_t nb_flags = 0; /* TODO: ... */
|
||||
|
||||
status = resolve_name_recv(creq, s->packet, &address);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto notfound;
|
||||
}
|
||||
|
||||
addresses = str_list_add(NULL, address);
|
||||
talloc_steal(s->packet, addresses);
|
||||
if (!addresses) goto notfound;
|
||||
|
||||
nbtd_name_query_reply(s->nbtsock, s->packet, s->src, name,
|
||||
0, nb_flags, addresses);
|
||||
return;
|
||||
notfound:
|
||||
nbtd_negative_name_query_reply(s->nbtsock, s->packet, s->src);
|
||||
}
|
||||
|
||||
/*
|
||||
dns proxy query a name
|
||||
*/
|
||||
void nbtd_wins_dns_proxy_query(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *packet,
|
||||
struct socket_address *src)
|
||||
{
|
||||
struct nbt_name *name = &packet->questions[0].name;
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
struct wins_dns_proxy_state *s;
|
||||
struct composite_context *creq;
|
||||
const char *methods[] = {
|
||||
"host",
|
||||
NULL
|
||||
};
|
||||
|
||||
s = talloc(nbtsock, struct wins_dns_proxy_state);
|
||||
if (!s) goto failed;
|
||||
s->nbtsock = nbtsock;
|
||||
s->packet = talloc_steal(s, packet);
|
||||
s->src = src;
|
||||
if (!talloc_reference(s, src)) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
creq = resolve_name_send(name, iface->nbtsrv->task->event_ctx, methods);
|
||||
if (!creq) goto failed;
|
||||
|
||||
creq->async.fn = nbtd_wins_dns_proxy_handler;
|
||||
creq->async.private_data= s;
|
||||
return;
|
||||
failed:
|
||||
nbtd_negative_name_query_reply(nbtsock, packet, src);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
wins hook feature, we run a specified script
|
||||
which can then do some custom actions
|
||||
|
||||
Copyright (C) Stefan Metzmacher 2005
|
||||
|
||||
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
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "nbt_server/nbt_server.h"
|
||||
#include "nbt_server/wins/winsdb.h"
|
||||
#include "system/filesys.h"
|
||||
|
||||
static const char *wins_hook_action_string(enum wins_hook_action action)
|
||||
{
|
||||
switch (action) {
|
||||
case WINS_HOOK_ADD: return "add";
|
||||
case WINS_HOOK_MODIFY: return "refresh";
|
||||
case WINS_HOOK_DELETE: return "delete";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
void wins_hook(struct winsdb_handle *h, const struct winsdb_record *rec, enum wins_hook_action action)
|
||||
{
|
||||
const char *script = lp_wins_hook();
|
||||
uint32_t i, length;
|
||||
int child;
|
||||
char *cmd = NULL;
|
||||
TALLOC_CTX *tmp_mem = NULL;
|
||||
|
||||
if (!script || !script[0]) return;
|
||||
|
||||
tmp_mem = talloc_new(h);
|
||||
if (!tmp_mem) goto failed;
|
||||
|
||||
length = winsdb_addr_list_length(rec->addresses);
|
||||
|
||||
if (action == WINS_HOOK_MODIFY && length < 1) {
|
||||
action = WINS_HOOK_DELETE;
|
||||
}
|
||||
|
||||
cmd = talloc_asprintf(tmp_mem,
|
||||
"%s %s %s %02x %ld",
|
||||
script,
|
||||
wins_hook_action_string(action),
|
||||
rec->name->name,
|
||||
rec->name->type,
|
||||
rec->expire_time);
|
||||
if (!cmd) goto failed;
|
||||
|
||||
for (i=0; rec->addresses[i]; i++) {
|
||||
cmd = talloc_asprintf_append(cmd, " %s", rec->addresses[i]->address);
|
||||
if (!cmd) goto failed;
|
||||
}
|
||||
|
||||
DEBUG(10,("call wins hook '%s'\n", cmd));
|
||||
|
||||
/* signal handling in posix really sucks - doing this in a library
|
||||
affects the whole app, but what else to do?? */
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
|
||||
child = fork();
|
||||
if (child == (pid_t)-1) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (child == 0) {
|
||||
/* TODO: close file handles */
|
||||
execl("/bin/sh", "sh", "-c", cmd, NULL);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
talloc_free(tmp_mem);
|
||||
return;
|
||||
failed:
|
||||
talloc_free(tmp_mem);
|
||||
DEBUG(0,("FAILED: calling wins hook '%s'\n", script));
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
ldb database module
|
||||
|
||||
Copyright (C) Stefan Metzmacher 2006
|
||||
|
||||
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
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Name: ldb
|
||||
*
|
||||
* Component: ldb winsdb module
|
||||
*
|
||||
* Description: verify winsdb records before they're written to disk
|
||||
*
|
||||
* Author: Stefan Metzmacher
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "nbt_server/nbt_server.h"
|
||||
#include "nbt_server/wins/winsdb.h"
|
||||
#include "lib/ldb/include/ldb.h"
|
||||
#include "lib/ldb/include/ldb_errors.h"
|
||||
#include "lib/ldb/include/ldb_private.h"
|
||||
#include "system/network.h"
|
||||
#include "lib/socket/netif.h"
|
||||
|
||||
static int wins_ldb_verify(struct ldb_module *module, struct ldb_request *req)
|
||||
{
|
||||
struct winsdb_handle *h = talloc_get_type(ldb_get_opaque(module->ldb, "winsdb_handle"),
|
||||
struct winsdb_handle);
|
||||
const struct ldb_message *msg;
|
||||
|
||||
switch (req->operation) {
|
||||
case LDB_ADD:
|
||||
msg = req->op.add.message;
|
||||
break;
|
||||
|
||||
case LDB_MODIFY:
|
||||
msg = req->op.mod.message;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ldb_next_request(module, req);
|
||||
}
|
||||
|
||||
/* do not manipulate our control entries */
|
||||
if (ldb_dn_is_special(msg->dn)) {
|
||||
return ldb_next_request(module, req);
|
||||
}
|
||||
|
||||
if (!h) {
|
||||
ldb_debug_set(module->ldb, LDB_DEBUG_FATAL, "%s", "WINS_LDB: INTERNAL ERROR: no winsdb_handle present!");
|
||||
return LDB_ERR_OTHER;
|
||||
}
|
||||
|
||||
switch (h->caller) {
|
||||
case WINSDB_HANDLE_CALLER_NBTD:
|
||||
case WINSDB_HANDLE_CALLER_WREPL:
|
||||
/* we trust our nbt and wrepl code ... */
|
||||
return ldb_next_request(module, req);
|
||||
|
||||
case WINSDB_HANDLE_CALLER_ADMIN:
|
||||
ldb_debug(module->ldb, LDB_DEBUG_WARNING, "%s\n", "WINS_LDB: TODO verify add/modify for WINSDB_HANDLE_CALLER_ADMIN");
|
||||
return ldb_next_request(module, req);
|
||||
}
|
||||
|
||||
return LDB_ERR_OTHER;
|
||||
}
|
||||
|
||||
static int wins_ldb_init(struct ldb_module *ctx)
|
||||
{
|
||||
struct winsdb_handle *h;
|
||||
const char *owner;
|
||||
|
||||
ctx->private_data = NULL;
|
||||
|
||||
owner = lp_parm_string(-1, "winsdb", "local_owner");
|
||||
if (!owner) {
|
||||
owner = iface_n_ip(0);
|
||||
if (!owner) {
|
||||
owner = "0.0.0.0";
|
||||
}
|
||||
}
|
||||
|
||||
h = talloc(ctx, struct winsdb_handle);
|
||||
if (!h) goto failed;
|
||||
h->ldb = ctx->ldb;
|
||||
h->caller = WINSDB_HANDLE_CALLER_ADMIN;
|
||||
h->local_owner = talloc_strdup(h, owner);
|
||||
if (!h->local_owner) goto failed;
|
||||
|
||||
return ldb_set_opaque(ctx->ldb, "winsdb_handle", h);
|
||||
|
||||
failed:
|
||||
talloc_free(h);
|
||||
return LDB_ERR_OTHER;
|
||||
}
|
||||
|
||||
static const struct ldb_module_ops wins_ldb_ops = {
|
||||
.name = "wins_ldb",
|
||||
.add = wins_ldb_verify,
|
||||
.modify = wins_ldb_verify,
|
||||
.init_context = wins_ldb_init
|
||||
};
|
||||
|
||||
|
||||
/* the init function */
|
||||
int wins_ldb_module_init(void)
|
||||
{
|
||||
return ldb_register_module(&wins_ldb_ops);
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
wins client name registration and refresh
|
||||
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
|
||||
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
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "nbt_server/nbt_server.h"
|
||||
#include "nbt_server/wins/winsserver.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "lib/events/events.h"
|
||||
#include "librpc/gen_ndr/ndr_nbt.h"
|
||||
#include "smbd/service_task.h"
|
||||
|
||||
static void nbtd_wins_refresh_handler(struct composite_context *c);
|
||||
|
||||
/* we send WINS client requests using our primary network interface
|
||||
*/
|
||||
static struct nbt_name_socket *wins_socket(struct nbtd_interface *iface)
|
||||
{
|
||||
struct nbtd_server *nbtsrv = iface->nbtsrv;
|
||||
return nbtsrv->interfaces->nbtsock;
|
||||
}
|
||||
|
||||
|
||||
static void nbtd_wins_refresh(struct event_context *ev, struct timed_event *te,
|
||||
struct timeval t, void *private_data);
|
||||
|
||||
/*
|
||||
retry a WINS name registration
|
||||
*/
|
||||
static void nbtd_wins_register_retry(struct event_context *ev, struct timed_event *te,
|
||||
struct timeval t, void *private_data)
|
||||
{
|
||||
struct nbtd_iface_name *iname = talloc_get_type(private_data, struct nbtd_iface_name);
|
||||
nbtd_winsclient_register(iname);
|
||||
}
|
||||
|
||||
/*
|
||||
start a timer to refresh this name
|
||||
*/
|
||||
static void nbtd_wins_start_refresh_timer(struct nbtd_iface_name *iname)
|
||||
{
|
||||
uint32_t refresh_time;
|
||||
uint32_t max_refresh_time = lp_parm_int(-1, "nbtd", "max_refresh_time", 7200);
|
||||
|
||||
refresh_time = MIN(max_refresh_time, iname->ttl/2);
|
||||
|
||||
event_add_timed(iname->iface->nbtsrv->task->event_ctx,
|
||||
iname,
|
||||
timeval_add(&iname->registration_time, refresh_time, 0),
|
||||
nbtd_wins_refresh, iname);
|
||||
}
|
||||
|
||||
/*
|
||||
called when a wins name refresh has completed
|
||||
*/
|
||||
static void nbtd_wins_refresh_handler(struct composite_context *c)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct nbt_name_refresh_wins io;
|
||||
struct nbtd_iface_name *iname = talloc_get_type(c->async.private_data,
|
||||
struct nbtd_iface_name);
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(iname);
|
||||
|
||||
status = nbt_name_refresh_wins_recv(c, tmp_ctx, &io);
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
|
||||
/* our WINS server is dead - start registration over
|
||||
from scratch */
|
||||
DEBUG(2,("Failed to refresh %s with WINS server %s\n",
|
||||
nbt_name_string(tmp_ctx, &iname->name), iname->wins_server));
|
||||
talloc_free(tmp_ctx);
|
||||
nbtd_winsclient_register(iname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1,("Name refresh failure with WINS for %s - %s\n",
|
||||
nbt_name_string(tmp_ctx, &iname->name), nt_errstr(status)));
|
||||
talloc_free(tmp_ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (io.out.rcode != 0) {
|
||||
DEBUG(1,("WINS server %s rejected name refresh of %s - %s\n",
|
||||
io.out.wins_server, nbt_name_string(tmp_ctx, &iname->name),
|
||||
nt_errstr(nbt_rcode_to_ntstatus(io.out.rcode))));
|
||||
iname->nb_flags |= NBT_NM_CONFLICT;
|
||||
talloc_free(tmp_ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG(4,("Refreshed name %s with WINS server %s\n",
|
||||
nbt_name_string(tmp_ctx, &iname->name), iname->wins_server));
|
||||
/* success - start a periodic name refresh */
|
||||
iname->nb_flags |= NBT_NM_ACTIVE;
|
||||
if (iname->wins_server) {
|
||||
/*
|
||||
* talloc_free() would generate a warning,
|
||||
* so steal it into the tmp context
|
||||
*/
|
||||
talloc_steal(tmp_ctx, iname->wins_server);
|
||||
}
|
||||
iname->wins_server = talloc_steal(iname, io.out.wins_server);
|
||||
|
||||
iname->registration_time = timeval_current();
|
||||
nbtd_wins_start_refresh_timer(iname);
|
||||
|
||||
talloc_free(tmp_ctx);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
refresh a WINS name registration
|
||||
*/
|
||||
static void nbtd_wins_refresh(struct event_context *ev, struct timed_event *te,
|
||||
struct timeval t, void *private_data)
|
||||
{
|
||||
struct nbtd_iface_name *iname = talloc_get_type(private_data, struct nbtd_iface_name);
|
||||
struct nbtd_interface *iface = iname->iface;
|
||||
struct nbt_name_refresh_wins io;
|
||||
struct composite_context *c;
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(iname);
|
||||
|
||||
/* setup a wins name refresh request */
|
||||
io.in.name = iname->name;
|
||||
io.in.wins_servers = str_list_make(tmp_ctx, iname->wins_server, NULL);
|
||||
io.in.addresses = nbtd_address_list(iface, tmp_ctx);
|
||||
io.in.nb_flags = iname->nb_flags;
|
||||
io.in.ttl = iname->ttl;
|
||||
|
||||
if (!io.in.addresses) {
|
||||
talloc_free(tmp_ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
c = nbt_name_refresh_wins_send(wins_socket(iface), &io);
|
||||
if (c == NULL) {
|
||||
talloc_free(tmp_ctx);
|
||||
return;
|
||||
}
|
||||
talloc_steal(c, io.in.addresses);
|
||||
|
||||
c->async.fn = nbtd_wins_refresh_handler;
|
||||
c->async.private_data = iname;
|
||||
|
||||
talloc_free(tmp_ctx);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
called when a wins name register has completed
|
||||
*/
|
||||
static void nbtd_wins_register_handler(struct composite_context *c)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct nbt_name_register_wins io;
|
||||
struct nbtd_iface_name *iname = talloc_get_type(c->async.private_data,
|
||||
struct nbtd_iface_name);
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(iname);
|
||||
|
||||
status = nbt_name_register_wins_recv(c, tmp_ctx, &io);
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
|
||||
/* none of the WINS servers responded - try again
|
||||
periodically */
|
||||
int wins_retry_time = lp_parm_int(-1, "nbtd", "wins_retry", 300);
|
||||
event_add_timed(iname->iface->nbtsrv->task->event_ctx,
|
||||
iname,
|
||||
timeval_current_ofs(wins_retry_time, 0),
|
||||
nbtd_wins_register_retry,
|
||||
iname);
|
||||
talloc_free(tmp_ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(1,("Name register failure with WINS for %s - %s\n",
|
||||
nbt_name_string(tmp_ctx, &iname->name), nt_errstr(status)));
|
||||
talloc_free(tmp_ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (io.out.rcode != 0) {
|
||||
DEBUG(1,("WINS server %s rejected name register of %s - %s\n",
|
||||
io.out.wins_server, nbt_name_string(tmp_ctx, &iname->name),
|
||||
nt_errstr(nbt_rcode_to_ntstatus(io.out.rcode))));
|
||||
iname->nb_flags |= NBT_NM_CONFLICT;
|
||||
talloc_free(tmp_ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
/* success - start a periodic name refresh */
|
||||
iname->nb_flags |= NBT_NM_ACTIVE;
|
||||
if (iname->wins_server) {
|
||||
/*
|
||||
* talloc_free() would generate a warning,
|
||||
* so steal it into the tmp context
|
||||
*/
|
||||
talloc_steal(tmp_ctx, iname->wins_server);
|
||||
}
|
||||
iname->wins_server = talloc_steal(iname, io.out.wins_server);
|
||||
|
||||
iname->registration_time = timeval_current();
|
||||
nbtd_wins_start_refresh_timer(iname);
|
||||
|
||||
DEBUG(3,("Registered %s with WINS server %s\n",
|
||||
nbt_name_string(tmp_ctx, &iname->name), iname->wins_server));
|
||||
|
||||
talloc_free(tmp_ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
register a name with our WINS servers
|
||||
*/
|
||||
void nbtd_winsclient_register(struct nbtd_iface_name *iname)
|
||||
{
|
||||
struct nbtd_interface *iface = iname->iface;
|
||||
struct nbt_name_register_wins io;
|
||||
struct composite_context *c;
|
||||
|
||||
/* setup a wins name register request */
|
||||
io.in.name = iname->name;
|
||||
io.in.wins_servers = lp_wins_server_list();
|
||||
io.in.addresses = nbtd_address_list(iface, iname);
|
||||
io.in.nb_flags = iname->nb_flags;
|
||||
io.in.ttl = iname->ttl;
|
||||
|
||||
if (!io.in.addresses) {
|
||||
return;
|
||||
}
|
||||
|
||||
c = nbt_name_register_wins_send(wins_socket(iface), &io);
|
||||
if (c == NULL) {
|
||||
talloc_free(io.in.addresses);
|
||||
return;
|
||||
}
|
||||
talloc_steal(c, io.in.addresses);
|
||||
|
||||
c->async.fn = nbtd_wins_register_handler;
|
||||
c->async.private_data = iname;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
WINS server structures
|
||||
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
|
||||
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
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
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.
|
||||
*/
|
||||
|
||||
#define WINSDB_FLAG_ALLOC_VERSION (1<<0)
|
||||
#define WINSDB_FLAG_TAKE_OWNERSHIP (1<<1)
|
||||
|
||||
struct winsdb_addr {
|
||||
const char *address;
|
||||
const char *wins_owner;
|
||||
time_t expire_time;
|
||||
};
|
||||
|
||||
/*
|
||||
each record in the database contains the following information
|
||||
*/
|
||||
struct winsdb_record {
|
||||
struct nbt_name *name;
|
||||
enum wrepl_name_type type;
|
||||
enum wrepl_name_state state;
|
||||
enum wrepl_name_node node;
|
||||
BOOL is_static;
|
||||
time_t expire_time;
|
||||
uint64_t version;
|
||||
const char *wins_owner;
|
||||
struct winsdb_addr **addresses;
|
||||
|
||||
/* only needed for debugging problems */
|
||||
const char *registered_by;
|
||||
};
|
||||
|
||||
enum winsdb_handle_caller {
|
||||
WINSDB_HANDLE_CALLER_ADMIN = 0,
|
||||
WINSDB_HANDLE_CALLER_NBTD = 1,
|
||||
WINSDB_HANDLE_CALLER_WREPL = 2
|
||||
};
|
||||
|
||||
struct winsdb_handle {
|
||||
/* wins server database handle */
|
||||
struct ldb_context *ldb;
|
||||
|
||||
/*
|
||||
* the type of the caller, as we pass this to the
|
||||
* 'wins_ldb' ldb module can decide if it needs to verify the
|
||||
* the records before they're written to disk
|
||||
*/
|
||||
enum winsdb_handle_caller caller;
|
||||
|
||||
/* local owner address */
|
||||
const char *local_owner;
|
||||
};
|
||||
|
||||
enum wins_hook_action {
|
||||
WINS_HOOK_ADD = 0,
|
||||
WINS_HOOK_MODIFY = 1,
|
||||
WINS_HOOK_DELETE = 2
|
||||
};
|
||||
|
||||
struct ldb_message;
|
||||
|
||||
#include "nbt_server/wins/winsdb_proto.h"
|
||||
@@ -0,0 +1,863 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
core wins server handling
|
||||
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
Copyright (C) Stefan Metzmacher 2005
|
||||
|
||||
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
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "nbt_server/nbt_server.h"
|
||||
#include "nbt_server/wins/winsdb.h"
|
||||
#include "nbt_server/wins/winsserver.h"
|
||||
#include "librpc/gen_ndr/ndr_nbt.h"
|
||||
#include "system/time.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
#include "smbd/service_task.h"
|
||||
#include "lib/socket/socket.h"
|
||||
#include "lib/ldb/include/ldb.h"
|
||||
|
||||
/*
|
||||
work out the ttl we will use given a client requested ttl
|
||||
*/
|
||||
uint32_t wins_server_ttl(struct wins_server *winssrv, uint32_t ttl)
|
||||
{
|
||||
ttl = MIN(ttl, winssrv->config.max_renew_interval);
|
||||
ttl = MAX(ttl, winssrv->config.min_renew_interval);
|
||||
return ttl;
|
||||
}
|
||||
|
||||
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) {
|
||||
return WREPL_TYPE_SGROUP;
|
||||
}
|
||||
if (nb_flags & NBT_NM_GROUP) {
|
||||
return WREPL_TYPE_GROUP;
|
||||
}
|
||||
if (mhomed) {
|
||||
return WREPL_TYPE_MHOMED;
|
||||
}
|
||||
return WREPL_TYPE_UNIQUE;
|
||||
}
|
||||
|
||||
/*
|
||||
register a new name with WINS
|
||||
*/
|
||||
static uint8_t wins_register_new(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *packet,
|
||||
const struct socket_address *src,
|
||||
enum wrepl_name_type type)
|
||||
{
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
struct wins_server *winssrv = iface->nbtsrv->winssrv;
|
||||
struct nbt_name *name = &packet->questions[0].name;
|
||||
uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
|
||||
uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
|
||||
const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
|
||||
struct winsdb_record rec;
|
||||
enum wrepl_name_node node;
|
||||
|
||||
#define WREPL_NODE_NBT_FLAGS(nb_flags) \
|
||||
((nb_flags & NBT_NM_OWNER_TYPE)>>13)
|
||||
|
||||
node = WREPL_NODE_NBT_FLAGS(nb_flags);
|
||||
|
||||
rec.name = name;
|
||||
rec.type = type;
|
||||
rec.state = WREPL_STATE_ACTIVE;
|
||||
rec.node = node;
|
||||
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 */
|
||||
rec.registered_by = src->addr;
|
||||
rec.addresses = winsdb_addr_list_make(packet);
|
||||
if (rec.addresses == NULL) return NBT_RCODE_SVR;
|
||||
|
||||
rec.addresses = winsdb_addr_list_add(winssrv->wins_db,
|
||||
&rec, rec.addresses,
|
||||
address,
|
||||
winssrv->wins_db->local_owner,
|
||||
rec.expire_time,
|
||||
True);
|
||||
if (rec.addresses == NULL) return NBT_RCODE_SVR;
|
||||
|
||||
DEBUG(4,("WINS: accepted registration of %s with address %s\n",
|
||||
nbt_name_string(packet, name), rec.addresses[0]->address));
|
||||
|
||||
return winsdb_add(winssrv->wins_db, &rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
update the ttl on an existing record
|
||||
*/
|
||||
static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *packet,
|
||||
struct winsdb_record *rec,
|
||||
struct winsdb_addr *winsdb_addr,
|
||||
const struct socket_address *src)
|
||||
{
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
struct wins_server *winssrv = iface->nbtsrv->winssrv;
|
||||
uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
|
||||
const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
|
||||
uint32_t modify_flags = 0;
|
||||
|
||||
rec->expire_time = time(NULL) + ttl;
|
||||
rec->registered_by = src->addr;
|
||||
|
||||
if (winsdb_addr) {
|
||||
rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
|
||||
rec, rec->addresses,
|
||||
winsdb_addr->address,
|
||||
winssrv->wins_db->local_owner,
|
||||
rec->expire_time,
|
||||
True);
|
||||
if (rec->addresses == NULL) return NBT_RCODE_SVR;
|
||||
}
|
||||
|
||||
if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) {
|
||||
modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
|
||||
}
|
||||
|
||||
DEBUG(5,("WINS: refreshed registration of %s at %s\n",
|
||||
nbt_name_string(packet, rec->name), address));
|
||||
|
||||
return winsdb_modify(winssrv->wins_db, rec, modify_flags);
|
||||
}
|
||||
|
||||
/*
|
||||
do a sgroup merge
|
||||
*/
|
||||
static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *packet,
|
||||
struct winsdb_record *rec,
|
||||
const char *address,
|
||||
const struct socket_address *src)
|
||||
{
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
struct wins_server *winssrv = iface->nbtsrv->winssrv;
|
||||
uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
|
||||
|
||||
rec->expire_time = time(NULL) + ttl;
|
||||
rec->registered_by = src->addr;
|
||||
|
||||
rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
|
||||
rec, rec->addresses,
|
||||
address,
|
||||
winssrv->wins_db->local_owner,
|
||||
rec->expire_time,
|
||||
True);
|
||||
if (rec->addresses == NULL) return NBT_RCODE_SVR;
|
||||
|
||||
DEBUG(5,("WINS: sgroup merge of %s at %s\n",
|
||||
nbt_name_string(packet, rec->name), address));
|
||||
|
||||
return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
|
||||
}
|
||||
|
||||
struct wack_state {
|
||||
struct wins_server *winssrv;
|
||||
struct nbt_name_socket *nbtsock;
|
||||
struct nbt_name_packet *request_packet;
|
||||
struct winsdb_record *rec;
|
||||
struct socket_address *src;
|
||||
const char *reg_address;
|
||||
enum wrepl_name_type new_type;
|
||||
struct wins_challenge_io io;
|
||||
NTSTATUS status;
|
||||
};
|
||||
|
||||
/*
|
||||
deny a registration request
|
||||
*/
|
||||
static void wins_wack_deny(struct wack_state *s)
|
||||
{
|
||||
nbtd_name_registration_reply(s->nbtsock, s->request_packet,
|
||||
s->src, NBT_RCODE_ACT);
|
||||
DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
|
||||
nbt_name_string(s, s->rec->name), s->src->addr, s->src->port));
|
||||
talloc_free(s);
|
||||
}
|
||||
|
||||
/*
|
||||
allow a registration request
|
||||
*/
|
||||
static void wins_wack_allow(struct wack_state *s)
|
||||
{
|
||||
NTSTATUS status;
|
||||
uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
|
||||
struct winsdb_record *rec = s->rec, *rec2;
|
||||
uint32_t i,j;
|
||||
|
||||
status = winsdb_lookup(s->winssrv->wins_db, rec->name, s, &rec2);
|
||||
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",
|
||||
nbt_name_string(s, rec->name)));
|
||||
wins_wack_deny(s);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* if the old name owner doesn't hold the name anymore
|
||||
* handle the request as new registration for the new name owner
|
||||
*/
|
||||
if (!NT_STATUS_IS_OK(s->status)) {
|
||||
uint8_t rcode;
|
||||
|
||||
winsdb_delete(s->winssrv->wins_db, rec);
|
||||
rcode = wins_register_new(s->nbtsock, s->request_packet, s->src, s->new_type);
|
||||
if (rcode != NBT_RCODE_OK) {
|
||||
DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
|
||||
nbt_name_string(s, rec->name)));
|
||||
wins_wack_deny(s);
|
||||
return;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
rec->expire_time = time(NULL) + ttl;
|
||||
rec->registered_by = s->src->addr;
|
||||
|
||||
/*
|
||||
* now remove all addresses that're the client doesn't hold anymore
|
||||
* and update the time stamp and owner for the ownes that are still there
|
||||
*/
|
||||
for (i=0; rec->addresses[i]; i++) {
|
||||
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;
|
||||
break;
|
||||
}
|
||||
if (found) {
|
||||
rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
|
||||
rec, rec->addresses,
|
||||
s->reg_address,
|
||||
s->winssrv->wins_db->local_owner,
|
||||
rec->expire_time,
|
||||
True);
|
||||
if (rec->addresses == NULL) goto failed;
|
||||
continue;
|
||||
}
|
||||
|
||||
winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
|
||||
}
|
||||
|
||||
rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
|
||||
rec, rec->addresses,
|
||||
s->reg_address,
|
||||
s->winssrv->wins_db->local_owner,
|
||||
rec->expire_time,
|
||||
True);
|
||||
if (rec->addresses == NULL) goto failed;
|
||||
|
||||
/* if we have more than one address, this becomes implicit a MHOMED record */
|
||||
if (winsdb_addr_list_length(rec->addresses) > 1) {
|
||||
rec->type = WREPL_TYPE_MHOMED;
|
||||
}
|
||||
|
||||
winsdb_modify(s->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
|
||||
|
||||
DEBUG(4,("WINS: accepted registration of %s with address %s\n",
|
||||
nbt_name_string(s, rec->name), s->reg_address));
|
||||
|
||||
done:
|
||||
nbtd_name_registration_reply(s->nbtsock, s->request_packet,
|
||||
s->src, NBT_RCODE_OK);
|
||||
failed:
|
||||
talloc_free(s);
|
||||
}
|
||||
|
||||
/*
|
||||
called when a name query to a current owner completes
|
||||
*/
|
||||
static void wack_wins_challenge_handler(struct composite_context *c_req)
|
||||
{
|
||||
struct wack_state *s = talloc_get_type(c_req->async.private_data,
|
||||
struct wack_state);
|
||||
BOOL found;
|
||||
uint32_t i;
|
||||
|
||||
s->status = wins_challenge_recv(c_req, s, &s->io);
|
||||
|
||||
/*
|
||||
* if the owner denies it holds the name, then allow
|
||||
* the registration
|
||||
*/
|
||||
if (!NT_STATUS_IS_OK(s->status)) {
|
||||
wins_wack_allow(s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->new_type == WREPL_TYPE_GROUP || s->new_type == WREPL_TYPE_SGROUP) {
|
||||
DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
|
||||
nbt_name_string(s, s->rec->name), s->new_type, s->rec->type));
|
||||
wins_wack_deny(s);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* if the owner still wants the name and doesn't reply
|
||||
* with the address trying to be registered, then deny
|
||||
* the registration
|
||||
*/
|
||||
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;
|
||||
break;
|
||||
}
|
||||
if (!found) {
|
||||
wins_wack_deny(s);
|
||||
return;
|
||||
}
|
||||
|
||||
wins_wack_allow(s);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
a client has asked to register a unique name that someone else owns. We
|
||||
need to ask each of the current owners if they still want it. If they do
|
||||
then reject the registration, otherwise allow it
|
||||
*/
|
||||
static void wins_register_wack(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *packet,
|
||||
struct winsdb_record *rec,
|
||||
struct socket_address *src,
|
||||
enum wrepl_name_type new_type)
|
||||
{
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
struct wins_server *winssrv = iface->nbtsrv->winssrv;
|
||||
struct wack_state *s;
|
||||
struct composite_context *c_req;
|
||||
uint32_t ttl;
|
||||
|
||||
s = talloc_zero(nbtsock, struct wack_state);
|
||||
if (s == NULL) goto failed;
|
||||
|
||||
/* package up the state variables for this wack request */
|
||||
s->winssrv = winssrv;
|
||||
s->nbtsock = nbtsock;
|
||||
s->request_packet = talloc_steal(s, packet);
|
||||
s->rec = talloc_steal(s, rec);
|
||||
s->reg_address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
|
||||
s->new_type = new_type;
|
||||
s->src = src;
|
||||
if (talloc_reference(s, src) == NULL) goto failed;
|
||||
|
||||
s->io.in.nbtd_server = iface->nbtsrv;
|
||||
s->io.in.event_ctx = iface->nbtsrv->task->event_ctx;
|
||||
s->io.in.name = rec->name;
|
||||
s->io.in.num_addresses = winsdb_addr_list_length(rec->addresses);
|
||||
s->io.in.addresses = winsdb_addr_string_list(s, rec->addresses);
|
||||
if (s->io.in.addresses == NULL) goto failed;
|
||||
|
||||
/*
|
||||
* send a WACK to the client, specifying the maximum time it could
|
||||
* take to check with the owner, plus some slack
|
||||
*/
|
||||
ttl = 5 + 4 * winsdb_addr_list_length(rec->addresses);
|
||||
nbtd_wack_reply(nbtsock, packet, src, ttl);
|
||||
|
||||
/*
|
||||
* send the challenge to the old addresses
|
||||
*/
|
||||
c_req = wins_challenge_send(s, &s->io);
|
||||
if (c_req == NULL) goto failed;
|
||||
|
||||
c_req->async.fn = wack_wins_challenge_handler;
|
||||
c_req->async.private_data = s;
|
||||
return;
|
||||
|
||||
failed:
|
||||
talloc_free(s);
|
||||
nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR);
|
||||
}
|
||||
|
||||
/*
|
||||
register a name
|
||||
*/
|
||||
static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *packet,
|
||||
struct socket_address *src)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
struct wins_server *winssrv = iface->nbtsrv->winssrv;
|
||||
struct nbt_name *name = &packet->questions[0].name;
|
||||
struct winsdb_record *rec;
|
||||
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);
|
||||
enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
|
||||
struct winsdb_addr *winsdb_addr = NULL;
|
||||
|
||||
/*
|
||||
* as a special case, the local master browser name is always accepted
|
||||
* for registration, but never stored, but w2k3 stores it if it's registered
|
||||
* as a group name, (but a query for the 0x1D name still returns not found!)
|
||||
*/
|
||||
if (name->type == NBT_NAME_MASTER && !(nb_flags & NBT_NM_GROUP)) {
|
||||
rcode = NBT_RCODE_OK;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* w2k3 refuses 0x1B names with marked as group */
|
||||
if (name->type == NBT_NAME_PDC && (nb_flags & NBT_NM_GROUP)) {
|
||||
rcode = NBT_RCODE_RFS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* w2k3 refuses 0x1C names with out marked as group */
|
||||
if (name->type == NBT_NAME_LOGON && !(nb_flags & NBT_NM_GROUP)) {
|
||||
rcode = NBT_RCODE_RFS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* w2k3 refuses 0x1E names with out marked as group */
|
||||
if (name->type == NBT_NAME_BROWSER && !(nb_flags & NBT_NM_GROUP)) {
|
||||
rcode = NBT_RCODE_RFS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
|
||||
if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
|
||||
rcode = wins_register_new(nbtsock, packet, src, new_type);
|
||||
goto done;
|
||||
} else if (!NT_STATUS_IS_OK(status)) {
|
||||
rcode = NBT_RCODE_SVR;
|
||||
goto done;
|
||||
} else if (rec->is_static) {
|
||||
if (rec->type == WREPL_TYPE_GROUP || rec->type == WREPL_TYPE_SGROUP) {
|
||||
rcode = NBT_RCODE_OK;
|
||||
goto done;
|
||||
}
|
||||
rcode = NBT_RCODE_ACT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (rec->type == WREPL_TYPE_GROUP) {
|
||||
if (new_type != WREPL_TYPE_GROUP) {
|
||||
DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
|
||||
" while a normal group is already there\n",
|
||||
nbt_name_string(packet, name), new_type));
|
||||
rcode = NBT_RCODE_ACT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (rec->state == WREPL_STATE_ACTIVE) {
|
||||
/* TODO: is this correct? */
|
||||
rcode = wins_update_ttl(nbtsock, packet, rec, NULL, src);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* TODO: is this correct? */
|
||||
winsdb_delete(winssrv->wins_db, rec);
|
||||
rcode = wins_register_new(nbtsock, packet, src, new_type);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (rec->state != WREPL_STATE_ACTIVE) {
|
||||
winsdb_delete(winssrv->wins_db, rec);
|
||||
rcode = wins_register_new(nbtsock, packet, src, new_type);
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (rec->type) {
|
||||
case WREPL_TYPE_UNIQUE:
|
||||
case WREPL_TYPE_MHOMED:
|
||||
/*
|
||||
* if its an active unique name, and the registration is for a group, then
|
||||
* see if the unique name owner still wants the name
|
||||
* TODO: is this correct?
|
||||
*/
|
||||
if (new_type == WREPL_TYPE_GROUP || new_type == WREPL_TYPE_GROUP) {
|
||||
wins_register_wack(nbtsock, packet, rec, src, new_type);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* if the registration is for an address that is currently active, then
|
||||
* just update the expiry time of the record and the address
|
||||
*/
|
||||
winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
|
||||
if (winsdb_addr) {
|
||||
rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* we have to do a WACK to see if the current owner is willing
|
||||
* to give up its claim
|
||||
*/
|
||||
wins_register_wack(nbtsock, packet, rec, src, new_type);
|
||||
return;
|
||||
|
||||
case WREPL_TYPE_GROUP:
|
||||
/* this should not be reached as normal groups are handled above */
|
||||
DEBUG(0,("BUG at %s\n",__location__));
|
||||
rcode = NBT_RCODE_ACT;
|
||||
goto done;
|
||||
|
||||
case WREPL_TYPE_SGROUP:
|
||||
/* if the new record isn't also a special group, refuse the registration */
|
||||
if (new_type != WREPL_TYPE_SGROUP) {
|
||||
DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
|
||||
" while a special group is already there\n",
|
||||
nbt_name_string(packet, name), new_type));
|
||||
rcode = NBT_RCODE_ACT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* if the registration is for an address that is currently active, then
|
||||
* just update the expiry time of the record and the address
|
||||
*/
|
||||
winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
|
||||
if (winsdb_addr) {
|
||||
rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
|
||||
goto done;
|
||||
}
|
||||
|
||||
rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
nbtd_name_registration_reply(nbtsock, packet, src, rcode);
|
||||
}
|
||||
|
||||
/*
|
||||
query a name
|
||||
*/
|
||||
static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *packet,
|
||||
struct socket_address *src)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
struct wins_server *winssrv = iface->nbtsrv->winssrv;
|
||||
struct nbt_name *name = &packet->questions[0].name;
|
||||
struct winsdb_record *rec;
|
||||
struct winsdb_record *rec_1b = NULL;
|
||||
const char **addresses;
|
||||
const char **addresses_1b = NULL;
|
||||
uint16_t nb_flags = 0;
|
||||
|
||||
if (name->type == NBT_NAME_MASTER) {
|
||||
goto notfound;
|
||||
}
|
||||
|
||||
/*
|
||||
* w2k3 returns the first address of the 0x1B record as first address
|
||||
* to a 0x1C query
|
||||
*/
|
||||
if (name->type == NBT_NAME_LOGON) {
|
||||
struct nbt_name name_1b;
|
||||
|
||||
name_1b = *name;
|
||||
name_1b.type = NBT_NAME_PDC;
|
||||
|
||||
status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
|
||||
}
|
||||
}
|
||||
|
||||
status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
if (!lp_wins_dns_proxy()) {
|
||||
goto notfound;
|
||||
}
|
||||
|
||||
if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
|
||||
goto notfound;
|
||||
}
|
||||
|
||||
nbtd_wins_dns_proxy_query(nbtsock, packet, src);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* for group's we always reply with
|
||||
* 255.255.255.255 as address, even if
|
||||
* the record is released or tombstoned
|
||||
*/
|
||||
if (rec->type == WREPL_TYPE_GROUP) {
|
||||
addresses = str_list_add(NULL, "255.255.255.255");
|
||||
talloc_steal(packet, addresses);
|
||||
if (!addresses) {
|
||||
goto notfound;
|
||||
}
|
||||
nb_flags |= NBT_NM_GROUP;
|
||||
goto found;
|
||||
}
|
||||
|
||||
if (rec->state != WREPL_STATE_ACTIVE) {
|
||||
goto notfound;
|
||||
}
|
||||
|
||||
addresses = winsdb_addr_string_list(packet, rec->addresses);
|
||||
if (!addresses) {
|
||||
goto notfound;
|
||||
}
|
||||
|
||||
/*
|
||||
* if addresses_1b isn't NULL, we have a 0x1C query and need to return the
|
||||
* first 0x1B address as first address
|
||||
*/
|
||||
if (addresses_1b && addresses_1b[0]) {
|
||||
const char **addresses_1c = addresses;
|
||||
uint32_t i;
|
||||
uint32_t num_addrs;
|
||||
|
||||
addresses = str_list_add(NULL, addresses_1b[0]);
|
||||
if (!addresses) {
|
||||
goto notfound;
|
||||
}
|
||||
talloc_steal(packet, addresses);
|
||||
num_addrs = 1;
|
||||
|
||||
for (i=0; addresses_1c[i]; i++) {
|
||||
if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
|
||||
|
||||
/*
|
||||
* stop when we already have 25 addresses
|
||||
*/
|
||||
if (num_addrs >= 25) break;
|
||||
|
||||
num_addrs++;
|
||||
addresses = str_list_add(addresses, addresses_1c[i]);
|
||||
if (!addresses) {
|
||||
goto notfound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rec->type == WREPL_TYPE_SGROUP) {
|
||||
nb_flags |= NBT_NM_GROUP;
|
||||
} else {
|
||||
nb_flags |= (rec->node <<13);
|
||||
}
|
||||
|
||||
found:
|
||||
nbtd_name_query_reply(nbtsock, packet, src, name,
|
||||
0, nb_flags, addresses);
|
||||
return;
|
||||
|
||||
notfound:
|
||||
nbtd_negative_name_query_reply(nbtsock, packet, src);
|
||||
}
|
||||
|
||||
/*
|
||||
release a name
|
||||
*/
|
||||
static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *packet,
|
||||
struct socket_address *src)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
struct wins_server *winssrv = iface->nbtsrv->winssrv;
|
||||
struct nbt_name *name = &packet->questions[0].name;
|
||||
struct winsdb_record *rec;
|
||||
uint32_t modify_flags = 0;
|
||||
uint8_t ret;
|
||||
|
||||
if (name->type == NBT_NAME_MASTER) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (rec->is_static) {
|
||||
if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
|
||||
goto done;
|
||||
}
|
||||
nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rec->state != WREPL_STATE_ACTIVE) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: do we need to check if
|
||||
* src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
|
||||
* here?
|
||||
*/
|
||||
|
||||
/*
|
||||
* we only allow releases from an owner - other releases are
|
||||
* silently ignored
|
||||
*/
|
||||
if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
|
||||
int i;
|
||||
DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
|
||||
DEBUGADD(4, ("Registered Addresses: \n"));
|
||||
for (i=0; rec->addresses && rec->addresses[i]; i++) {
|
||||
DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
|
||||
|
||||
switch (rec->type) {
|
||||
case WREPL_TYPE_UNIQUE:
|
||||
rec->state = WREPL_STATE_RELEASED;
|
||||
break;
|
||||
|
||||
case WREPL_TYPE_GROUP:
|
||||
rec->state = WREPL_STATE_RELEASED;
|
||||
break;
|
||||
|
||||
case WREPL_TYPE_SGROUP:
|
||||
winsdb_addr_list_remove(rec->addresses, src->addr);
|
||||
/* TODO: do we need to take the ownership here? */
|
||||
if (winsdb_addr_list_length(rec->addresses) == 0) {
|
||||
rec->state = WREPL_STATE_RELEASED;
|
||||
}
|
||||
break;
|
||||
|
||||
case WREPL_TYPE_MHOMED:
|
||||
winsdb_addr_list_remove(rec->addresses, src->addr);
|
||||
/* TODO: do we need to take the ownership here? */
|
||||
if (winsdb_addr_list_length(rec->addresses) == 0) {
|
||||
rec->state = WREPL_STATE_RELEASED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (rec->state == WREPL_STATE_RELEASED) {
|
||||
/*
|
||||
* if we're not the owner, we need to take the owner ship
|
||||
* and make the record tombstone, but expire after
|
||||
* tombstone_interval + tombstone_timeout and not only after tombstone_timeout
|
||||
* like for normal tombstone records.
|
||||
* This is to replicate the record directly to the original owner,
|
||||
* where the record is still active
|
||||
*/
|
||||
if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
|
||||
rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
|
||||
} else {
|
||||
rec->state = WREPL_STATE_TOMBSTONE;
|
||||
rec->expire_time= time(NULL) +
|
||||
winssrv->config.tombstone_interval +
|
||||
winssrv->config.tombstone_timeout;
|
||||
modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
|
||||
}
|
||||
}
|
||||
|
||||
ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
|
||||
if (ret != NBT_RCODE_OK) {
|
||||
DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
|
||||
nbt_name_string(rec, rec->name), src->addr, ret));
|
||||
}
|
||||
done:
|
||||
/* we match w2k3 by always giving a positive reply to name releases. */
|
||||
nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
answer a name query
|
||||
*/
|
||||
void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_packet *packet,
|
||||
struct socket_address *src)
|
||||
{
|
||||
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private,
|
||||
struct nbtd_interface);
|
||||
struct wins_server *winssrv = iface->nbtsrv->winssrv;
|
||||
if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (packet->operation & NBT_OPCODE) {
|
||||
case NBT_OPCODE_QUERY:
|
||||
nbtd_winsserver_query(nbtsock, packet, src);
|
||||
break;
|
||||
|
||||
case NBT_OPCODE_REGISTER:
|
||||
case NBT_OPCODE_REFRESH:
|
||||
case NBT_OPCODE_REFRESH2:
|
||||
case NBT_OPCODE_MULTI_HOME_REG:
|
||||
nbtd_winsserver_register(nbtsock, packet, src);
|
||||
break;
|
||||
|
||||
case NBT_OPCODE_RELEASE:
|
||||
nbtd_winsserver_release(nbtsock, packet, src);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
startup the WINS server, if configured
|
||||
*/
|
||||
NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
if (!lp_wins_support()) {
|
||||
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.tombstone_interval = tmp;
|
||||
tmp = lp_parm_int(-1,"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);
|
||||
if (!nbtsrv->winssrv->wins_db) {
|
||||
return NT_STATUS_INTERNAL_DB_ERROR;
|
||||
}
|
||||
|
||||
irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
wins server WACK processing
|
||||
|
||||
Copyright (C) Stefan Metzmacher 2005
|
||||
|
||||
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
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
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.
|
||||
*/
|
||||
|
||||
struct wins_server {
|
||||
/* wins server database handle */
|
||||
struct winsdb_handle *wins_db;
|
||||
|
||||
/* some configuration */
|
||||
struct {
|
||||
/*
|
||||
* the interval (in secs) till an active record will be marked as RELEASED
|
||||
*/
|
||||
uint32_t min_renew_interval;
|
||||
uint32_t max_renew_interval;
|
||||
|
||||
/*
|
||||
* the interval (in secs) a record remains in RELEASED state,
|
||||
* before it will be marked as TOMBSTONE
|
||||
* (also known as extinction interval)
|
||||
*/
|
||||
uint32_t tombstone_interval;
|
||||
|
||||
/*
|
||||
* the interval (in secs) a record remains in TOMBSTONE state,
|
||||
* before it will be removed from the database.
|
||||
* See also 'tombstone_extra_timeout'.
|
||||
* (also known as extinction timeout)
|
||||
*/
|
||||
uint32_t tombstone_timeout;
|
||||
} config;
|
||||
};
|
||||
|
||||
struct wins_challenge_io {
|
||||
struct {
|
||||
struct nbtd_server *nbtd_server;
|
||||
struct event_context *event_ctx;
|
||||
struct nbt_name *name;
|
||||
uint32_t num_addresses;
|
||||
const char **addresses;
|
||||
} in;
|
||||
struct {
|
||||
uint32_t num_addresses;
|
||||
const char **addresses;
|
||||
} out;
|
||||
};
|
||||
|
||||
#include "nbt_server/wins/winsserver_proto.h"
|
||||
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
"secure" wins server WACK processing
|
||||
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
Copyright (C) Stefan Metzmacher 2005
|
||||
|
||||
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
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "nbt_server/nbt_server.h"
|
||||
#include "nbt_server/wins/winsdb.h"
|
||||
#include "nbt_server/wins/winsserver.h"
|
||||
#include "system/time.h"
|
||||
#include "libcli/composite/composite.h"
|
||||
|
||||
struct wins_challenge_state {
|
||||
struct wins_challenge_io *io;
|
||||
uint32_t current_address;
|
||||
struct nbt_name_query query;
|
||||
};
|
||||
|
||||
static void wins_challenge_handler(struct nbt_name_request *req)
|
||||
{
|
||||
struct composite_context *ctx = talloc_get_type(req->async.private, struct composite_context);
|
||||
struct wins_challenge_state *state = talloc_get_type(ctx->private_data, struct wins_challenge_state);
|
||||
|
||||
ctx->status = nbt_name_query_recv(req, state, &state->query);
|
||||
|
||||
/* if we timed out then try the next owner address, if any */
|
||||
if (NT_STATUS_EQUAL(ctx->status, NT_STATUS_IO_TIMEOUT)) {
|
||||
state->current_address++;
|
||||
if (state->current_address < state->io->in.num_addresses) {
|
||||
struct nbtd_interface *iface;
|
||||
|
||||
state->query.in.dest_addr = state->io->in.addresses[state->current_address];
|
||||
|
||||
iface = nbtd_find_request_iface(state->io->in.nbtd_server, state->query.in.dest_addr, True);
|
||||
if (!iface) {
|
||||
composite_error(ctx, NT_STATUS_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
ZERO_STRUCT(state->query.out);
|
||||
req = nbt_name_query_send(iface->nbtsock, &state->query);
|
||||
composite_continue_nbt(ctx, req, wins_challenge_handler, ctx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
composite_done(ctx);
|
||||
}
|
||||
|
||||
NTSTATUS wins_challenge_recv(struct composite_context *ctx, TALLOC_CTX *mem_ctx, struct wins_challenge_io *io)
|
||||
{
|
||||
NTSTATUS status = ctx->status;
|
||||
struct wins_challenge_state *state = talloc_get_type(ctx->private_data, struct wins_challenge_state);
|
||||
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
io->out.num_addresses = state->query.out.num_addrs;
|
||||
io->out.addresses = state->query.out.reply_addrs;
|
||||
talloc_steal(mem_ctx, io->out.addresses);
|
||||
} else {
|
||||
ZERO_STRUCT(io->out);
|
||||
}
|
||||
|
||||
talloc_free(ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
struct composite_context *wins_challenge_send(TALLOC_CTX *mem_ctx, struct wins_challenge_io *io)
|
||||
{
|
||||
struct composite_context *result;
|
||||
struct wins_challenge_state *state;
|
||||
struct nbt_name_request *req;
|
||||
struct nbtd_interface *iface;
|
||||
|
||||
result = talloc_zero(mem_ctx, struct composite_context);
|
||||
if (result == NULL) return NULL;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->event_ctx = talloc_reference(result, io->in.event_ctx);
|
||||
|
||||
state = talloc_zero(result, struct wins_challenge_state);
|
||||
if (state == NULL) goto failed;
|
||||
result->private_data = state;
|
||||
|
||||
/* package up the state variables for this wack request */
|
||||
state->io = io;
|
||||
state->current_address = 0;
|
||||
|
||||
/* setup a name query to the first address */
|
||||
state->query.in.name = *state->io->in.name;
|
||||
state->query.in.dest_addr = state->io->in.addresses[state->current_address];
|
||||
state->query.in.broadcast = False;
|
||||
state->query.in.wins_lookup = True;
|
||||
state->query.in.timeout = 1;
|
||||
state->query.in.retries = 2;
|
||||
ZERO_STRUCT(state->query.out);
|
||||
|
||||
iface = nbtd_find_request_iface(state->io->in.nbtd_server, state->query.in.dest_addr, True);
|
||||
if (!iface) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
req = nbt_name_query_send(iface->nbtsock, &state->query);
|
||||
if (req == NULL) goto failed;
|
||||
|
||||
req->async.fn = wins_challenge_handler;
|
||||
req->async.private = result;
|
||||
|
||||
return result;
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wins_release_demand_io {
|
||||
struct {
|
||||
struct nbtd_server *nbtd_server;
|
||||
struct event_context *event_ctx;
|
||||
struct nbt_name *name;
|
||||
uint16_t nb_flags;
|
||||
uint32_t num_addresses;
|
||||
const char **addresses;
|
||||
} in;
|
||||
};
|
||||
|
||||
struct wins_release_demand_state {
|
||||
struct wins_release_demand_io *io;
|
||||
uint32_t current_address;
|
||||
uint32_t addresses_left;
|
||||
struct nbt_name_release release;
|
||||
};
|
||||
|
||||
static void wins_release_demand_handler(struct nbt_name_request *req)
|
||||
{
|
||||
struct composite_context *ctx = talloc_get_type(req->async.private, struct composite_context);
|
||||
struct wins_release_demand_state *state = talloc_get_type(ctx->private_data, struct wins_release_demand_state);
|
||||
|
||||
ctx->status = nbt_name_release_recv(req, state, &state->release);
|
||||
|
||||
/* if we timed out then try the next owner address, if any */
|
||||
if (NT_STATUS_EQUAL(ctx->status, NT_STATUS_IO_TIMEOUT)) {
|
||||
state->current_address++;
|
||||
state->addresses_left--;
|
||||
if (state->current_address < state->io->in.num_addresses) {
|
||||
struct nbtd_interface *iface;
|
||||
|
||||
state->release.in.dest_addr = state->io->in.addresses[state->current_address];
|
||||
state->release.in.address = state->release.in.dest_addr;
|
||||
state->release.in.timeout = (state->addresses_left > 1 ? 2 : 1);
|
||||
state->release.in.retries = (state->addresses_left > 1 ? 0 : 2);
|
||||
|
||||
iface = nbtd_find_request_iface(state->io->in.nbtd_server, state->release.in.dest_addr, True);
|
||||
if (!iface) {
|
||||
composite_error(ctx, NT_STATUS_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
ZERO_STRUCT(state->release.out);
|
||||
req = nbt_name_release_send(iface->nbtsock, &state->release);
|
||||
composite_continue_nbt(ctx, req, wins_release_demand_handler, ctx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
composite_done(ctx);
|
||||
}
|
||||
|
||||
static NTSTATUS wins_release_demand_recv(struct composite_context *ctx,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct wins_release_demand_io *io)
|
||||
{
|
||||
NTSTATUS status = ctx->status;
|
||||
talloc_free(ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct composite_context *wins_release_demand_send(TALLOC_CTX *mem_ctx, struct wins_release_demand_io *io)
|
||||
{
|
||||
struct composite_context *result;
|
||||
struct wins_release_demand_state *state;
|
||||
struct nbt_name_request *req;
|
||||
struct nbtd_interface *iface;
|
||||
|
||||
result = talloc_zero(mem_ctx, struct composite_context);
|
||||
if (result == NULL) return NULL;
|
||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||
result->event_ctx = talloc_reference(result, io->in.event_ctx);
|
||||
|
||||
state = talloc_zero(result, struct wins_release_demand_state);
|
||||
if (state == NULL) goto failed;
|
||||
result->private_data = state;
|
||||
|
||||
/* package up the state variables for this wack request */
|
||||
state->io = io;
|
||||
state->current_address = 0;
|
||||
state->addresses_left = state->io->in.num_addresses;
|
||||
|
||||
/*
|
||||
* setup a name query to the first address
|
||||
* - if we have more than one address try the first
|
||||
* with 2 secs timeout and no retry
|
||||
* - otherwise use 1 sec timeout (w2k3 uses 0.5 sec here)
|
||||
* with 2 retries
|
||||
*/
|
||||
state->release.in.name = *state->io->in.name;
|
||||
state->release.in.dest_addr = state->io->in.addresses[state->current_address];
|
||||
state->release.in.address = state->release.in.dest_addr;
|
||||
state->release.in.broadcast = False;
|
||||
state->release.in.timeout = (state->addresses_left > 1 ? 2 : 1);
|
||||
state->release.in.retries = (state->addresses_left > 1 ? 0 : 2);
|
||||
ZERO_STRUCT(state->release.out);
|
||||
|
||||
iface = nbtd_find_request_iface(state->io->in.nbtd_server, state->release.in.dest_addr, True);
|
||||
if (!iface) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
req = nbt_name_release_send(iface->nbtsock, &state->release);
|
||||
if (req == NULL) goto failed;
|
||||
|
||||
req->async.fn = wins_release_demand_handler;
|
||||
req->async.private = result;
|
||||
|
||||
return result;
|
||||
failed:
|
||||
talloc_free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
wrepl_server needs to be able to do a name query request, but some windows
|
||||
servers always send the reply to port 137, regardless of the request
|
||||
port. To cope with this we use a irpc request to the NBT server
|
||||
which has port 137 open, and thus can receive the replies
|
||||
*/
|
||||
struct proxy_wins_challenge_state {
|
||||
struct irpc_message *msg;
|
||||
struct nbtd_proxy_wins_challenge *req;
|
||||
struct wins_challenge_io io;
|
||||
struct composite_context *c_req;
|
||||
};
|
||||
|
||||
static void proxy_wins_challenge_handler(struct composite_context *c_req)
|
||||
{
|
||||
NTSTATUS status;
|
||||
uint32_t i;
|
||||
struct proxy_wins_challenge_state *s = talloc_get_type(c_req->async.private_data,
|
||||
struct proxy_wins_challenge_state);
|
||||
|
||||
status = wins_challenge_recv(s->c_req, s, &s->io);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
ZERO_STRUCT(s->req->out);
|
||||
irpc_send_reply(s->msg, status);
|
||||
return;
|
||||
}
|
||||
|
||||
s->req->out.num_addrs = s->io.out.num_addresses;
|
||||
/* TODO: fix pidl to handle inline ipv4address arrays */
|
||||
s->req->out.addrs = talloc_array(s->msg, struct nbtd_proxy_wins_addr,
|
||||
s->io.out.num_addresses);
|
||||
if (!s->req->out.addrs) {
|
||||
ZERO_STRUCT(s->req->out);
|
||||
irpc_send_reply(s->msg, NT_STATUS_NO_MEMORY);
|
||||
return;
|
||||
}
|
||||
for (i=0; i < s->io.out.num_addresses; i++) {
|
||||
s->req->out.addrs[i].addr = talloc_steal(s->req->out.addrs, s->io.out.addresses[i]);
|
||||
}
|
||||
|
||||
irpc_send_reply(s->msg, status);
|
||||
}
|
||||
|
||||
NTSTATUS nbtd_proxy_wins_challenge(struct irpc_message *msg,
|
||||
struct nbtd_proxy_wins_challenge *req)
|
||||
{
|
||||
struct nbtd_server *nbtd_server =
|
||||
talloc_get_type(msg->private, struct nbtd_server);
|
||||
struct proxy_wins_challenge_state *s;
|
||||
uint32_t i;
|
||||
|
||||
s = talloc(msg, struct proxy_wins_challenge_state);
|
||||
NT_STATUS_HAVE_NO_MEMORY(s);
|
||||
|
||||
s->msg = msg;
|
||||
s->req = req;
|
||||
|
||||
s->io.in.nbtd_server = nbtd_server;
|
||||
s->io.in.event_ctx = msg->ev;
|
||||
s->io.in.name = &req->in.name;
|
||||
s->io.in.num_addresses = req->in.num_addrs;
|
||||
s->io.in.addresses = talloc_array(s, const char *, req->in.num_addrs);
|
||||
NT_STATUS_HAVE_NO_MEMORY(s->io.in.addresses);
|
||||
/* TODO: fix pidl to handle inline ipv4address arrays */
|
||||
for (i=0; i < req->in.num_addrs; i++) {
|
||||
s->io.in.addresses[i] = talloc_steal(s->io.in.addresses, req->in.addrs[i].addr);
|
||||
}
|
||||
|
||||
s->c_req = wins_challenge_send(s, &s->io);
|
||||
NT_STATUS_HAVE_NO_MEMORY(s->c_req);
|
||||
|
||||
s->c_req->async.fn = proxy_wins_challenge_handler;
|
||||
s->c_req->async.private_data = s;
|
||||
|
||||
msg->defer_reply = True;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
wrepl_server needs to be able to do a name release demands, but some windows
|
||||
servers always send the reply to port 137, regardless of the request
|
||||
port. To cope with this we use a irpc request to the NBT server
|
||||
which has port 137 open, and thus can receive the replies
|
||||
*/
|
||||
struct proxy_wins_release_demand_state {
|
||||
struct irpc_message *msg;
|
||||
struct nbtd_proxy_wins_release_demand *req;
|
||||
struct wins_release_demand_io io;
|
||||
struct composite_context *c_req;
|
||||
};
|
||||
|
||||
static void proxy_wins_release_demand_handler(struct composite_context *c_req)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct proxy_wins_release_demand_state *s = talloc_get_type(c_req->async.private_data,
|
||||
struct proxy_wins_release_demand_state);
|
||||
|
||||
status = wins_release_demand_recv(s->c_req, s, &s->io);
|
||||
|
||||
irpc_send_reply(s->msg, status);
|
||||
}
|
||||
|
||||
NTSTATUS nbtd_proxy_wins_release_demand(struct irpc_message *msg,
|
||||
struct nbtd_proxy_wins_release_demand *req)
|
||||
{
|
||||
struct nbtd_server *nbtd_server =
|
||||
talloc_get_type(msg->private, struct nbtd_server);
|
||||
struct proxy_wins_release_demand_state *s;
|
||||
uint32_t i;
|
||||
|
||||
s = talloc(msg, struct proxy_wins_release_demand_state);
|
||||
NT_STATUS_HAVE_NO_MEMORY(s);
|
||||
|
||||
s->msg = msg;
|
||||
s->req = req;
|
||||
|
||||
s->io.in.nbtd_server = nbtd_server;
|
||||
s->io.in.event_ctx = msg->ev;
|
||||
s->io.in.name = &req->in.name;
|
||||
s->io.in.num_addresses = req->in.num_addrs;
|
||||
s->io.in.addresses = talloc_array(s, const char *, req->in.num_addrs);
|
||||
NT_STATUS_HAVE_NO_MEMORY(s->io.in.addresses);
|
||||
/* TODO: fix pidl to handle inline ipv4address arrays */
|
||||
for (i=0; i < req->in.num_addrs; i++) {
|
||||
s->io.in.addresses[i] = talloc_steal(s->io.in.addresses, req->in.addrs[i].addr);
|
||||
}
|
||||
|
||||
s->c_req = wins_release_demand_send(s, &s->io);
|
||||
NT_STATUS_HAVE_NO_MEMORY(s->c_req);
|
||||
|
||||
s->c_req->async.fn = proxy_wins_release_demand_handler;
|
||||
s->c_req->async.private_data = s;
|
||||
|
||||
msg->defer_reply = True;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
Reference in New Issue
Block a user