diff options
-rw-r--r-- | source4/include/structs.h | 3 | ||||
-rw-r--r-- | source4/librpc/idl/irpc.idl | 18 | ||||
-rw-r--r-- | source4/nbt_server/irpc.c | 16 | ||||
-rw-r--r-- | source4/nbt_server/wins/winswack.c | 367 |
4 files changed, 403 insertions, 1 deletions
diff --git a/source4/include/structs.h b/source4/include/structs.h index 34127c58ca..bc3e62cd2b 100644 --- a/source4/include/structs.h +++ b/source4/include/structs.h @@ -263,6 +263,7 @@ struct nbt_dgram_socket; struct dgram_mailslot_handler; struct messaging_context; +struct irpc_message; struct stream_connection; struct task_server; struct model_ops; @@ -271,6 +272,8 @@ struct stream_server_ops; struct nbtd_server; struct nbtd_interface; struct wins_server; +struct nbtd_proxy_wins_challenge; +struct nbtd_proxy_wins_release_demand; struct nbt_dc_name; struct wb_sid_object; diff --git a/source4/librpc/idl/irpc.idl b/source4/librpc/idl/irpc.idl index d7a727bee7..f83816f2f2 100644 --- a/source4/librpc/idl/irpc.idl +++ b/source4/librpc/idl/irpc.idl @@ -6,7 +6,7 @@ [ uuid("e770c620-0b06-4b5e-8d87-a26e20f28340"), version(1.0), pointer_default(unique), - depends(security) + depends(security,nbt) ] interface irpc { typedef bitmap { @@ -61,6 +61,22 @@ [out,unique] astring *dcname ); + typedef [noejs] struct { + ipv4address addr; + } nbtd_proxy_wins_addr; + + [noejs] void nbtd_proxy_wins_challenge( + [in] nbt_name name, + [in,out] uint32 num_addrs, + [in,out] nbtd_proxy_wins_addr addrs[num_addrs] + ); + + [noejs] void nbtd_proxy_wins_release_demand( + [in] nbt_name name, + [in] uint32 num_addrs, + [in] nbtd_proxy_wins_addr addrs[num_addrs] + ); + /****************************************************** management calls for the smb server ******************************************************/ diff --git a/source4/nbt_server/irpc.c b/source4/nbt_server/irpc.c index 0cd65453a4..2e72b8146c 100644 --- a/source4/nbt_server/irpc.c +++ b/source4/nbt_server/irpc.c @@ -190,4 +190,20 @@ void nbtd_register_irpc(struct nbtd_server *nbtsrv) "handler"); return; } + + status = IRPC_REGISTER(task->msg_ctx, irpc, NBTD_PROXY_WINS_CHALLENGE, + nbtd_proxy_wins_challenge, nbtsrv); + if (!NT_STATUS_IS_OK(status)) { + task_server_terminate(task, "nbtd failed to setup wins challenge " + "handler"); + return; + } + + status = IRPC_REGISTER(task->msg_ctx, irpc, NBTD_PROXY_WINS_RELEASE_DEMAND, + nbtd_proxy_wins_release_demand, nbtsrv); + if (!NT_STATUS_IS_OK(status)) { + task_server_terminate(task, "nbtd failed to setup wins release demand " + "handler"); + return; + } } diff --git a/source4/nbt_server/wins/winswack.c b/source4/nbt_server/wins/winswack.c index 40a4d7d76a..598c244825 100644 --- a/source4/nbt_server/wins/winswack.c +++ b/source4/nbt_server/wins/winswack.c @@ -24,6 +24,236 @@ #include "nbt_server/nbt_server.h" #include "nbt_server/wins/winsdb.h" #include "system/time.h" +#include "libcli/composite/composite.h" + +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; +}; + +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_interface(state->io->in.nbtd_server, state->query.in.dest_addr); + 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); +} + +static 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; +} + +static 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_interface(state->io->in.nbtd_server, state->query.in.dest_addr); + 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_interface(state->io->in.nbtd_server, state->release.in.dest_addr); + 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_interface(state->io->in.nbtd_server, state->release.in.dest_addr); + 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; +} struct wack_state { struct wins_server *winssrv; @@ -217,3 +447,140 @@ failed: talloc_free(state); nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR); } + +/* + 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; +} |