diff options
-rw-r--r-- | source4/libcli/config.mk | 7 | ||||
-rw-r--r-- | source4/libcli/finddcs.c | 245 | ||||
-rw-r--r-- | source4/libcli/libcli.h | 4 | ||||
-rw-r--r-- | source4/libcli/security/dom_sid.c | 5 | ||||
-rw-r--r-- | source4/libnet/config.mk | 2 | ||||
-rw-r--r-- | source4/libnet/libnet_join.c | 22 | ||||
-rw-r--r-- | source4/libnet/libnet_lookup.c | 48 | ||||
-rw-r--r-- | source4/libnet/libnet_lookup.h | 12 | ||||
-rw-r--r-- | source4/libnet/libnet_passwd.c | 8 | ||||
-rw-r--r-- | source4/libnet/libnet_rpc.c | 45 | ||||
-rw-r--r-- | source4/libnet/libnet_rpc.h | 4 | ||||
-rw-r--r-- | source4/libnet/libnet_share.c | 56 | ||||
-rw-r--r-- | source4/libnet/libnet_time.c | 8 | ||||
-rw-r--r-- | source4/libnet/libnet_user.c | 18 | ||||
-rw-r--r-- | source4/libnet/libnet_vampire.c | 2 | ||||
-rwxr-xr-x | source4/script/tests/test_nbt.sh | 2 | ||||
-rwxr-xr-x | source4/script/tests/test_rpc.sh | 6 | ||||
-rw-r--r-- | source4/torture/libnet/libnet_lookup.c | 26 | ||||
-rw-r--r-- | source4/torture/libnet/libnet_rpc.c | 85 | ||||
-rw-r--r-- | source4/torture/libnet/libnet_share.c | 2 |
20 files changed, 451 insertions, 156 deletions
diff --git a/source4/libcli/config.mk b/source4/libcli/config.mk index 20219be0f4..0040339fd2 100644 --- a/source4/libcli/config.mk +++ b/source4/libcli/config.mk @@ -87,6 +87,11 @@ OBJ_FILES = \ resolve/host.o REQUIRED_SUBSYSTEMS = LIBCLI_NBT +[SUBSYSTEM::LIBCLI_FINDDCS] +OBJ_FILES = \ + finddcs.o +REQUIRED_SUBSYSTEMS = LIBCLI_NBT MESSAGING + [LIBRARY::LIBCLI] MAJOR_VERSION = 0 MINOR_VERSION = 0 @@ -94,7 +99,7 @@ RELEASE_VERSION = 1 DESCRIPTION = SMB/CIFS client library REQUIRED_SUBSYSTEMS = LIBCLI_RAW LIBCLI_UTILS LIBCLI_AUTH \ LIBCLI_SMB_COMPOSITE LIBCLI_NBT LIB_SECURITY LIBCLI_RESOLVE \ - LIBCLI_DGRAM LIBCLI_SMB2 + LIBCLI_DGRAM LIBCLI_SMB2 LIBCLI_FINDDCS [SUBSYSTEM::LIBSMB] REQUIRED_SUBSYSTEMS = LIBCLI SOCKET diff --git a/source4/libcli/finddcs.c b/source4/libcli/finddcs.c new file mode 100644 index 0000000000..ff4b255a13 --- /dev/null +++ b/source4/libcli/finddcs.c @@ -0,0 +1,245 @@ +/* + Unix SMB/CIFS implementation. + + a composite API for finding a DC and its name + + Copyright (C) Volker Lendecke 2005 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 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. +*/ + +#include "include/includes.h" +#include "lib/messaging/irpc.h" +#include "librpc/gen_ndr/ndr_irpc.h" +#include "librpc/gen_ndr/ndr_samr.h" +#include "libcli/composite/composite.h" +#include "libcli/libcli.h" + +struct finddcs_state { + struct composite_context *ctx; + struct messaging_context *msg_ctx; + + const char *domain_name; + struct dom_sid *domain_sid; + + struct nbtd_getdcname r; + struct nbt_name_status node_status; + + int num_dcs; + struct nbt_dc_name *dcs; +}; + +static void finddcs_name_resolved(struct composite_context *ctx); +static void finddcs_getdc_replied(struct irpc_request *ireq); +static void fallback_node_status(struct finddcs_state *state); +static void fallback_node_status_replied(struct nbt_name_request *name_req); + +/* + * Setup and send off the a normal name resolution for the target name. + * + * The domain_sid parameter is optional, and is used in the subsequent getdc request. + * + * This will try a GetDC request, but this may not work. It will try + * a node status as a fallback, then return no name (but still include + * the IP) + */ + +struct composite_context *finddcs_send(TALLOC_CTX *mem_ctx, + const char *domain_name, + int name_type, + struct dom_sid *domain_sid, + const char **methods, + struct event_context *event_ctx, + struct messaging_context *msg_ctx) +{ + struct composite_context *result, *ctx; + struct finddcs_state *state; + struct nbt_name name; + + result = talloc(mem_ctx, struct composite_context); + if (result == NULL) goto failed; + result->state = COMPOSITE_STATE_IN_PROGRESS; + result->async.fn = NULL; + result->event_ctx = event_ctx; + + state = talloc(result, struct finddcs_state); + if (state == NULL) goto failed; + state->ctx = result; + result->private_data = state; + + state->domain_name = talloc_strdup(state, domain_name); + if (state->domain_name == NULL) goto failed; + state->domain_sid = domain_sid; + if (domain_sid != NULL) { + if (talloc_reference(state, domain_sid) == NULL) { + goto failed; + } + } + state->msg_ctx = msg_ctx; + + make_nbt_name(&name, state->domain_name, name_type); + ctx = resolve_name_send(&name, result->event_ctx, + methods); + + if (ctx == NULL) goto failed; + ctx->async.fn = finddcs_name_resolved; + ctx->async.private_data = state; + + return result; + +failed: + talloc_free(result); + return NULL; +} + +/* Having got an name query answer, fire off a GetDC request, so we + * can find the target's all-important name. (Kerberos and some + * netlogon operations are quite picky about names) + * + * The name is a courtasy, if we don't find it, don't compleatly fail. + * + * However, if the nbt server is down, fall back to a node status + * request + */ +static void finddcs_name_resolved(struct composite_context *ctx) +{ + struct finddcs_state *state = + talloc_get_type(ctx->async.private_data, struct finddcs_state); + struct irpc_request *ireq; + uint32_t *nbt_servers; + const char *address; + + state->ctx->status = resolve_name_recv(ctx, state, &address); + if (!composite_is_ok(state->ctx)) return; + + state->num_dcs = 1; + state->dcs = talloc_array(state, struct nbt_dc_name, state->num_dcs); + if (composite_nomem(state->dcs, state->ctx)) return; + + state->dcs[0].address = talloc_steal(state->dcs, address); + + /* Try and find the nbt server. We are not going to fail if + * we can't get the name, it will just be a disapointment. + * The nbt server just might not be running */ + nbt_servers = irpc_servers_byname(state->msg_ctx, "nbt_server"); + if ((nbt_servers == NULL) || (nbt_servers[0] == 0)) { + fallback_node_status(state); + return; + } + + state->r.in.domainname = state->domain_name; + state->r.in.ip_address = state->dcs[0].address; + state->r.in.my_computername = lp_netbios_name(); + state->r.in.my_accountname = talloc_asprintf(state, "%s$", + lp_netbios_name()); + if (composite_nomem(state->r.in.my_accountname, state->ctx)) return; + state->r.in.account_control = ACB_WSTRUST; + state->r.in.domain_sid = state->domain_sid; + + ireq = irpc_call_send(state->msg_ctx, nbt_servers[0], + &dcerpc_table_irpc, DCERPC_NBTD_GETDCNAME, + &state->r, state); + if (!ireq) { + fallback_node_status(state); + return; + } + + composite_continue_irpc(state->ctx, ireq, finddcs_getdc_replied, state); +} + +/* Called when the GetDC request returns */ +static void finddcs_getdc_replied(struct irpc_request *ireq) +{ + struct finddcs_state *state = + talloc_get_type(ireq->async.private, struct finddcs_state); + + state->ctx->status = irpc_call_recv(ireq); + if (!composite_is_ok(state->ctx)) return; + + state->dcs[0].name = talloc_steal(state->dcs, state->r.out.dcname); + composite_done(state->ctx); +} + +/* The GetDC request might not be availible (such as occours when the + * NBT server is down). Fallback to a node status. It is the best + * hope we have... */ +static void fallback_node_status(struct finddcs_state *state) +{ + struct nbt_name_socket *nbtsock; + struct nbt_name_request *name_req; + + state->node_status.in.name.name = "*"; + state->node_status.in.name.type = NBT_NAME_CLIENT; + state->node_status.in.name.scope = NULL; + state->node_status.in.dest_addr = state->dcs[0].address; + state->node_status.in.timeout = 1; + state->node_status.in.retries = 2; + + nbtsock = nbt_name_socket_init(state, state->ctx->event_ctx); + if (composite_nomem(nbtsock, state->ctx)) return; + + name_req = nbt_name_status_send(nbtsock, &state->node_status); + if (composite_nomem(name_req, state->ctx)) return; + + composite_continue_nbt(state->ctx, + name_req, + fallback_node_status_replied, + state); +} + +/* We have a node status reply (or perhaps a timeout) */ +static void fallback_node_status_replied(struct nbt_name_request *name_req) +{ + struct finddcs_state *state = talloc_get_type(name_req->async.private, struct finddcs_state); + state->ctx->status = nbt_name_status_recv(name_req, state, &state->node_status); + if (!composite_is_ok(state->ctx)) return; + + if (state->node_status.out.status.num_names > 0) { + state->dcs[0].name = talloc_steal(state->dcs, state->node_status.out.status.names[0].name); + composite_done(state->ctx); + return; + } + composite_error(state->ctx, NT_STATUS_NO_LOGON_SERVERS); +} + +NTSTATUS finddcs_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, + int *num_dcs, struct nbt_dc_name **dcs) +{ + NTSTATUS status = composite_wait(c); + if (NT_STATUS_IS_OK(status)) { + struct finddcs_state *state = + talloc_get_type(c->private_data, struct finddcs_state); + *num_dcs = state->num_dcs; + *dcs = talloc_steal(mem_ctx, state->dcs); + } + talloc_free(c); + return status; +} + +NTSTATUS finddcs(TALLOC_CTX *mem_ctx, + const char *domain_name, int name_type, + struct dom_sid *domain_sid, + const char **methods, + struct event_context *event_ctx, + struct messaging_context *msg_ctx, + int *num_dcs, struct nbt_dc_name **dcs) +{ + struct composite_context *c = finddcs_send(mem_ctx, + domain_name, name_type, + domain_sid, methods, + event_ctx, msg_ctx); + return finddcs_recv(c, mem_ctx, num_dcs, dcs); +} diff --git a/source4/libcli/libcli.h b/source4/libcli/libcli.h index 917ab27519..76fa13525e 100644 --- a/source4/libcli/libcli.h +++ b/source4/libcli/libcli.h @@ -41,5 +41,9 @@ struct clilist_file_info { const char *short_name; }; +struct nbt_dc_name { + const char *address; + const char *name; +}; #include "libcli/libcli_proto.h" diff --git a/source4/libcli/security/dom_sid.c b/source4/libcli/security/dom_sid.c index 646a513df5..b5ced9fcc2 100644 --- a/source4/libcli/security/dom_sid.c +++ b/source4/libcli/security/dom_sid.c @@ -157,6 +157,11 @@ struct dom_sid *dom_sid_dup(TALLOC_CTX *mem_ctx, const struct dom_sid *dom_sid) { struct dom_sid *ret; int i; + + if (!dom_sid) { + return NULL; + } + ret = talloc(mem_ctx, struct dom_sid); if (!ret) { return NULL; diff --git a/source4/libnet/config.mk b/source4/libnet/config.mk index b76fe0c7e5..baf81e36e6 100644 --- a/source4/libnet/config.mk +++ b/source4/libnet/config.mk @@ -25,6 +25,6 @@ OBJ_FILES = \ userinfo.o \ userman.o \ domain.o -REQUIRED_SUBSYSTEMS = RPC_NDR_SAMR RPC_NDR_LSA RPC_NDR_SRVSVC RPC_NDR_DRSUAPI LIBCLI_COMPOSITE LIBCLI_RESOLVE LIBSAMBA3 LIBCLI_CLDAP gensec_schannel +REQUIRED_SUBSYSTEMS = RPC_NDR_SAMR RPC_NDR_LSA RPC_NDR_SRVSVC RPC_NDR_DRSUAPI LIBCLI_COMPOSITE LIBCLI_RESOLVE LIBCLI_FINDDCS LIBSAMBA3 LIBCLI_CLDAP LIBCLI_FINDDCS gensec_schannel # End SUBSYSTEM LIBNET ################################# diff --git a/source4/libnet/libnet_join.c b/source4/libnet/libnet_join.c index 4f566a36a8..616c80b1a4 100644 --- a/source4/libnet/libnet_join.c +++ b/source4/libnet/libnet_join.c @@ -272,7 +272,7 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J status = dcerpc_pipe_connect_b(tmp_ctx, &drsuapi_pipe, drsuapi_binding, - &dcerpc_table_drsuapi, + &dcerpc_table_drsuapi, ctx->cred, ctx->event_ctx); if (!NT_STATUS_IS_OK(status)) { @@ -635,8 +635,8 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru /* prepare connect to the LSA pipe of PDC */ if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) { - c->level = LIBNET_RPC_CONNECT_PDC; - c->in.domain_name = r->in.domain_name; + c->level = LIBNET_RPC_CONNECT_PDC; + c->in.name = r->in.domain_name; } else { c->level = LIBNET_RPC_CONNECT_BINDING; c->in.binding = r->in.binding; @@ -998,7 +998,9 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru /* We created a new user, but they didn't come out the right type?!? */ r->out.error_string = talloc_asprintf(mem_ctx, - "We asked to create a new machine account (%s) of type %s, but we got an account of type %s. This is unexpected. Perhaps delete the account and try again.\n", + "We asked to create a new machine account (%s) of type %s, " + "but we got an account of type %s. This is unexpected. " + "Perhaps delete the account and try again.\n", r->in.account_name, new_account_type, old_account_type); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; @@ -1008,7 +1010,9 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru /* TODO: We should allow a --force option to override, and redo this from the top setting r.in.recreate_account */ r->out.error_string = talloc_asprintf(mem_ctx, - "The machine account (%s) already exists in the domain %s, but is a %s. You asked to join as a %s. Please delete the account and try again.\n", + "The machine account (%s) already exists in the domain %s, " + "but is a %s. You asked to join as a %s. Please delete " + "the account and try again.\n", r->in.account_name, domain_name, old_account_type, new_account_type); talloc_free(tmp_ctx); return NT_STATUS_USER_EXISTS; @@ -1045,7 +1049,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru } /* reset flags (if required) */ - if (acct_flags != qui.out.info->info16.acct_flags) { + if (acct_flags != qui.out.info->info16.acct_flags) { ZERO_STRUCT(u_info); u_info.info16.acct_flags = acct_flags; @@ -1160,7 +1164,7 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx, if ((r->in.netbios_name != NULL) && (r->in.level != LIBNET_JOIN_AUTOMATIC)) { netbios_name = r->in.netbios_name; } else { - netbios_name = talloc_asprintf(tmp_mem, "%s", lp_netbios_name()); + netbios_name = talloc_reference(tmp_mem, lp_netbios_name()); if (!netbios_name) { r->out.error_string = NULL; talloc_free(tmp_mem); @@ -1437,8 +1441,8 @@ NTSTATUS libnet_Join(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct lib } r->out.error_string = talloc_asprintf(mem_ctx, - "Invalid secure channel type specified (%08X) attempting to join domain %s", - r->in.secure_channel_type, r->in.domain_name); + "Invalid secure channel type specified (%08X) attempting to join domain %s", + r->in.secure_channel_type, r->in.domain_name); return NT_STATUS_INVALID_PARAMETER; } diff --git a/source4/libnet/libnet_lookup.c b/source4/libnet/libnet_lookup.c index e64ab6a291..1c1604f407 100644 --- a/source4/libnet/libnet_lookup.c +++ b/source4/libnet/libnet_lookup.c @@ -26,7 +26,8 @@ #include "lib/events/events.h" #include "libnet/libnet.h" #include "libcli/composite/composite.h" - +#include "lib/messaging/messaging.h" +#include "lib/messaging/irpc.h" struct lookup_state { struct composite_context *resolve_ctx; @@ -162,20 +163,49 @@ NTSTATUS libnet_LookupHost(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, /** * Sends asynchronous LookupPdc request */ -struct composite_context* libnet_LookupPdc_send(struct libnet_context *ctx, - struct libnet_Lookup *io) +struct composite_context* libnet_LookupDCs_send(struct libnet_context *ctx, + TALLOC_CTX *mem_ctx, + struct libnet_LookupDCs *io) { - io->in.type = NBT_NAME_PDC; - return libnet_Lookup_send(ctx, io); + struct messaging_context *msg_ctx = messaging_init(mem_ctx, random() % 0x10000000, ctx->event_ctx); + struct composite_context *c; + if (!msg_ctx) { + return NULL; + } + c = finddcs_send(mem_ctx, + io->in.domain_name, + NBT_NAME_PDC, + NULL, ctx->name_res_methods, + ctx->event_ctx, msg_ctx); + return c; } +/** + * Waits for and receives results of asynchronous Lookup call + * + * @param c composite context returned by asynchronous Lookup call + * @param mem_ctx memory context of the call + * @param io pointer to results (and arguments) of the call + * @return nt status code of execution + */ + +NTSTATUS libnet_LookupDCs_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, + struct libnet_LookupDCs *io) +{ + NTSTATUS status; + status = finddcs_recv(c, mem_ctx, &io->out.num_dcs, &io->out.dcs); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + return status; +} /** * Synchronous version of LookupPdc */ -NTSTATUS libnet_LookupPdc(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, - struct libnet_Lookup *io) +NTSTATUS libnet_LookupDCs(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, + struct libnet_LookupDCs *io) { - struct composite_context *c = libnet_LookupPdc_send(ctx, io); - return libnet_Lookup_recv(c, mem_ctx, io); + struct composite_context *c = libnet_LookupDCs_send(ctx, mem_ctx, io); + return libnet_LookupDCs_recv(c, mem_ctx, io); } diff --git a/source4/libnet/libnet_lookup.h b/source4/libnet/libnet_lookup.h index e5b2d58fd3..c786eb0a43 100644 --- a/source4/libnet/libnet_lookup.h +++ b/source4/libnet/libnet_lookup.h @@ -29,3 +29,15 @@ struct libnet_Lookup { const char **address; } out; }; + +struct libnet_LookupDCs { + struct { + const char *domain_name; + int name_type; + } in; + struct { + int num_dcs; + struct nbt_dc_name *dcs; + } out; +}; + diff --git a/source4/libnet/libnet_passwd.c b/source4/libnet/libnet_passwd.c index bd09e306ce..fe5239f4b6 100644 --- a/source4/libnet/libnet_passwd.c +++ b/source4/libnet/libnet_passwd.c @@ -53,7 +53,7 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT /* prepare connect to the SAMR pipe of the users domain PDC */ c.level = LIBNET_RPC_CONNECT_PDC; - c.in.domain_name = r->samr.in.domain_name; + c.in.name = r->samr.in.domain_name; c.in.dcerpc_iface = &dcerpc_table_samr; /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */ @@ -513,9 +513,9 @@ static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX * union libnet_SetPassword r2; /* prepare connect to the SAMR pipe of users domain PDC */ - c.level = LIBNET_RPC_CONNECT_PDC; - c.in.domain_name = r->samr.in.domain_name; - c.in.dcerpc_iface = &dcerpc_table_samr; + c.level = LIBNET_RPC_CONNECT_PDC; + c.in.name = r->samr.in.domain_name; + c.in.dcerpc_iface = &dcerpc_table_samr; /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */ status = libnet_RpcConnect(ctx, mem_ctx, &c); diff --git a/source4/libnet/libnet_rpc.c b/source4/libnet/libnet_rpc.c index 6b94734f9b..ffed674f1f 100644 --- a/source4/libnet/libnet_rpc.c +++ b/source4/libnet/libnet_rpc.c @@ -21,7 +21,7 @@ #include "includes.h" #include "libnet/libnet.h" - +#include "libcli/libcli.h" /** * Connects rpc pipe on remote server @@ -39,9 +39,10 @@ static NTSTATUS libnet_RpcConnectSrv(struct libnet_context *ctx, TALLOC_CTX *mem /* prepare binding string */ switch (r->level) { + case LIBNET_RPC_CONNECT_DC: case LIBNET_RPC_CONNECT_PDC: case LIBNET_RPC_CONNECT_SERVER: - binding = talloc_asprintf(mem_ctx, "ncacn_np:%s", r->in.domain_name); + binding = talloc_asprintf(mem_ctx, "ncacn_np:%s", r->in.name); break; case LIBNET_RPC_CONNECT_BINDING: @@ -81,24 +82,45 @@ static NTSTATUS libnet_RpcConnectPdc(struct libnet_context *ctx, TALLOC_CTX *mem { NTSTATUS status; struct libnet_RpcConnect r2; - struct libnet_Lookup f; + struct libnet_LookupDCs f; + const char *connect_name; - f.in.hostname = r->in.domain_name; - f.in.methods = NULL; - f.out.address = NULL; + f.in.domain_name = r->in.name; + switch (r->level) { + case LIBNET_RPC_CONNECT_PDC: + f.in.name_type = NBT_NAME_PDC; + break; + case LIBNET_RPC_CONNECT_DC: + f.in.name_type = NBT_NAME_LOGON; + break; + default: + break; + } + f.out.num_dcs = 0; + f.out.dcs = NULL; /* find the domain pdc first */ - status = libnet_LookupPdc(ctx, mem_ctx, &f); + status = libnet_LookupDCs(ctx, mem_ctx, &f); if (!NT_STATUS_IS_OK(status)) { - r->out.error_string = talloc_asprintf(mem_ctx, "libnet_LookupPdc failed: %s", + r->out.error_string = talloc_asprintf(mem_ctx, "libnet_LookupDCs failed: %s", nt_errstr(status)); return status; } + /* we might not have got back a name. Fall back to the IP */ + if (f.out.dcs[0].name) { + connect_name = f.out.dcs[0].name; + } else { + connect_name = f.out.dcs[0].address; + } + /* ok, pdc has been found so do attempt to rpc connect */ - r2.level = LIBNET_RPC_CONNECT_SERVER; - r2.in.domain_name = talloc_strdup(mem_ctx, f.out.address[0]); - r2.in.dcerpc_iface = r->in.dcerpc_iface; + r2.level = LIBNET_RPC_CONNECT_SERVER; + + /* This will cause yet another name resolution, but at least + * we pass the right name down the stack now */ + r2.in.name = talloc_strdup(mem_ctx, connect_name); + r2.in.dcerpc_iface = r->in.dcerpc_iface; status = libnet_RpcConnect(ctx, mem_ctx, &r2); @@ -130,6 +152,7 @@ NTSTATUS libnet_RpcConnect(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru return libnet_RpcConnectSrv(ctx, mem_ctx, r); case LIBNET_RPC_CONNECT_PDC: + case LIBNET_RPC_CONNECT_DC: return libnet_RpcConnectPdc(ctx, mem_ctx, r); } diff --git a/source4/libnet/libnet_rpc.h b/source4/libnet/libnet_rpc.h index d2a83bf642..5505e69a09 100644 --- a/source4/libnet/libnet_rpc.h +++ b/source4/libnet/libnet_rpc.h @@ -27,6 +27,8 @@ enum libnet_RpcConnect_level { LIBNET_RPC_CONNECT_SERVER, /* connect to a standalone rpc server */ LIBNET_RPC_CONNECT_PDC, /* connect to a domain pdc (resolves domain name to a pdc address before connecting) */ + LIBNET_RPC_CONNECT_DC, /* connect to any DC (resolves domain + name to a DC address before connecting) */ LIBNET_RPC_CONNECT_BINDING /* specified binding string */ }; @@ -34,7 +36,7 @@ struct libnet_RpcConnect { enum libnet_RpcConnect_level level; struct { - const char *domain_name; + const char *name; const char *binding; const struct dcerpc_interface_table *dcerpc_iface; } in; diff --git a/source4/libnet/libnet_share.c b/source4/libnet/libnet_share.c index 9422cdd306..0f5a3aeb52 100644 --- a/source4/libnet/libnet_share.c +++ b/source4/libnet/libnet_share.c @@ -30,10 +30,16 @@ NTSTATUS libnet_ListShares(struct libnet_context *ctx, struct srvsvc_NetShareEnumAll s; uint32_t resume_handle; struct srvsvc_NetShareCtr0 ctr0; + struct srvsvc_NetShareCtr1 ctr1; + struct srvsvc_NetShareCtr2 ctr2; + struct srvsvc_NetShareCtr501 ctr501; + struct srvsvc_NetShareCtr502 ctr502; - c.level = LIBNET_RPC_CONNECT_SERVER; - c.in.domain_name = r->in.server_name; - c.in.dcerpc_iface = &dcerpc_table_srvsvc; + c.level = LIBNET_RPC_CONNECT_SERVER; + c.in.name = r->in.server_name; + c.in.dcerpc_iface = &dcerpc_table_srvsvc; + + s.in.server_unc = talloc_asprintf(mem_ctx, "\\\\%s", c.in.name); status = libnet_RpcConnect(ctx, mem_ctx, &c); if (!NT_STATUS_IS_OK(status)) { @@ -46,11 +52,36 @@ NTSTATUS libnet_ListShares(struct libnet_context *ctx, } s.in.level = r->in.level; - s.in.ctr.ctr0 = &ctr0; + switch (s.in.level) { + case 0: + s.in.ctr.ctr0 = &ctr0; + ZERO_STRUCT(ctr0); + break; + case 1: + s.in.ctr.ctr1 = &ctr1; + ZERO_STRUCT(ctr1); + break; + case 2: + s.in.ctr.ctr2 = &ctr2; + ZERO_STRUCT(ctr2); + break; + case 501: + s.in.ctr.ctr501 = &ctr501; + ZERO_STRUCT(ctr501); + break; + case 502: + s.in.ctr.ctr502 = &ctr502; + ZERO_STRUCT(ctr502); + break; + default: + r->out.error_string = talloc_asprintf(mem_ctx, + "libnet_ListShares: Invalid info level requested: %d\n", + s.in.level); + return NT_STATUS_INVALID_PARAMETER; + } s.in.max_buffer = ~0; s.in.resume_handle = &resume_handle; - ZERO_STRUCT(ctr0); status = dcerpc_srvsvc_NetShareEnumAll(c.out.dcerpc_pipe, mem_ctx, &s); @@ -63,6 +94,9 @@ NTSTATUS libnet_ListShares(struct libnet_context *ctx, } if (!W_ERROR_IS_OK(s.out.result) && !W_ERROR_EQUAL(s.out.result, WERR_MORE_DATA)) { + r->out.error_string = talloc_asprintf(mem_ctx, + "srvsvc_NetShareEnumAll on server '%s' failed: %s", + r->in.server_name, win_errstr(s.out.result)); goto disconnect; } @@ -82,9 +116,9 @@ NTSTATUS libnet_AddShare(struct libnet_context *ctx, struct libnet_RpcConnect c; struct srvsvc_NetShareAdd s; - c.level = LIBNET_RPC_CONNECT_SERVER; - c.in.domain_name = r->in.server_name; - c.in.dcerpc_iface = &dcerpc_table_srvsvc; + c.level = LIBNET_RPC_CONNECT_SERVER; + c.in.name = r->in.server_name; + c.in.dcerpc_iface = &dcerpc_table_srvsvc; status = libnet_RpcConnect(ctx, mem_ctx, &c); if (!NT_STATUS_IS_OK(status)) { @@ -121,9 +155,9 @@ NTSTATUS libnet_DelShare(struct libnet_context *ctx, struct libnet_RpcConnect c; struct srvsvc_NetShareDel s; - c.level = LIBNET_RPC_CONNECT_SERVER; - c.in.domain_name = r->in.server_name; - c.in.dcerpc_iface = &dcerpc_table_srvsvc; + c.level = LIBNET_RPC_CONNECT_SERVER; + c.in.name = r->in.server_name; + c.in.dcerpc_iface = &dcerpc_table_srvsvc; status = libnet_RpcConnect(ctx, mem_ctx, &c); if (!NT_STATUS_IS_OK(status)) { diff --git a/source4/libnet/libnet_time.c b/source4/libnet/libnet_time.c index 7d480a5348..c7f8c79db5 100644 --- a/source4/libnet/libnet_time.c +++ b/source4/libnet/libnet_time.c @@ -33,9 +33,9 @@ static NTSTATUS libnet_RemoteTOD_srvsvc(struct libnet_context *ctx, TALLOC_CTX * struct tm tm; /* prepare connect to the SRVSVC pipe of a timeserver */ - c.level = LIBNET_RPC_CONNECT_SERVER; - c.in.domain_name = r->srvsvc.in.server_name; - c.in.dcerpc_iface = &dcerpc_table_srvsvc; + c.level = LIBNET_RPC_CONNECT_SERVER; + c.in.name = r->srvsvc.in.server_name; + c.in.dcerpc_iface = &dcerpc_table_srvsvc; /* 1. connect to the SRVSVC pipe of a timeserver */ status = libnet_RpcConnect(ctx, mem_ctx, &c); @@ -47,7 +47,7 @@ static NTSTATUS libnet_RemoteTOD_srvsvc(struct libnet_context *ctx, TALLOC_CTX * } /* prepare srvsvc_NetrRemoteTOD */ - tod.in.server_unc = talloc_asprintf(mem_ctx, "\\%s", c.in.domain_name); + tod.in.server_unc = talloc_asprintf(mem_ctx, "\\%s", c.in.name); /* 2. try srvsvc_NetRemoteTOD */ status = dcerpc_srvsvc_NetRemoteTOD(c.out.dcerpc_pipe, mem_ctx, &tod); diff --git a/source4/libnet/libnet_user.c b/source4/libnet/libnet_user.c index 629fbf8e05..50cb14d290 100644 --- a/source4/libnet/libnet_user.c +++ b/source4/libnet/libnet_user.c @@ -27,23 +27,13 @@ NTSTATUS libnet_CreateUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru { NTSTATUS status; struct libnet_RpcConnect cn; - struct libnet_Lookup fp; struct libnet_rpc_domain_open dom_io; struct libnet_rpc_useradd user_io; - const char *address; - /* find domain pdc */ - fp.in.hostname = r->in.domain_name; - fp.in.methods = NULL; - fp.out.address = &address; - - status = libnet_LookupPdc(ctx, mem_ctx, &fp); - if (!NT_STATUS_IS_OK(status)) return status; - - /* connect rpc service of remote server */ - cn.level = LIBNET_RPC_CONNECT_SERVER; - cn.in.domain_name = talloc_strdup(mem_ctx, *fp.out.address); - cn.in.dcerpc_iface = &dcerpc_table_samr; + /* connect rpc service of remote DC */ + cn.level = LIBNET_RPC_CONNECT_PDC; + cn.in.name = talloc_strdup(mem_ctx, r->in.domain_name); + cn.in.dcerpc_iface = &dcerpc_table_samr; status = libnet_RpcConnect(ctx, mem_ctx, &cn); if (!NT_STATUS_IS_OK(status)) { diff --git a/source4/libnet/libnet_vampire.c b/source4/libnet/libnet_vampire.c index d9c25d053e..dc271ba577 100644 --- a/source4/libnet/libnet_vampire.c +++ b/source4/libnet/libnet_vampire.c @@ -210,7 +210,7 @@ NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx /* Setup schannel */ nt_status = dcerpc_pipe_connect_b(samsync_ctx, &p, b, - &dcerpc_table_netlogon, + &dcerpc_table_netlogon, machine_account, ctx->event_ctx); if (!NT_STATUS_IS_OK(nt_status)) { diff --git a/source4/script/tests/test_nbt.sh b/source4/script/tests/test_nbt.sh index c230547db5..3aa558c589 100755 --- a/source4/script/tests/test_nbt.sh +++ b/source4/script/tests/test_nbt.sh @@ -21,7 +21,7 @@ export PATH testit "nmblookup -U $SERVER $SERVER" bin/nmblookup $TORTURE_OPTIONS -U $SERVER $SERVER || failed=`expr $failed + 1` testit "nmblookup $SERVER" bin/nmblookup $TORTURE_OPTIONS $SERVER || failed=`expr $failed + 1` -for f in NBT-REGISTER NBT-WINS NBT-WINSREPLICATION; do +for f in NBT-REGISTER NBT-WINS NBT-WINSREPLICATION NET-API-LOOKUP NET-API-LOOKUPHOST NET-API-LOOKUPPDC; do testit "$f" bin/smbtorture $TORTURE_OPTIONS //$SERVER/_none_ $f || failed=`expr $failed + 1` done diff --git a/source4/script/tests/test_rpc.sh b/source4/script/tests/test_rpc.sh index 7056300e28..21bd31bd24 100755 --- a/source4/script/tests/test_rpc.sh +++ b/source4/script/tests/test_rpc.sh @@ -2,9 +2,9 @@ # add tests to this list as they start passing, so we test # that they stay passing -ncacn_np_tests="RPC-SPOOLSS RPC-JOIN RPC-SCHANNEL RPC-ECHO RPC-DSSETUP RPC-ALTERCONTEXT RPC-MULTIBIND" -ncalrpc_tests="RPC-SCHANNEL RPC-JOIN RPC-ECHO RPC-DSSETUP RPC-ALTERCONTEXT RPC-MULTIBIND" -ncacn_ip_tcp_tests="RPC-SCHANNEL RPC-JOIN RPC-ECHO RPC-DSSETUP RPC-ALTERCONTEXT RPC-MULTIBIND" +ncacn_np_tests="RPC-SPOOLSS RPC-JOIN RPC-SCHANNEL RPC-ECHO RPC-DSSETUP RPC-ALTERCONTEXT RPC-MULTIBIND NET-API-RPCCONNECT NET-API-LISTSHARES NET-API-CREATEUSER" +ncalrpc_tests="RPC-SCHANNEL RPC-JOIN RPC-ECHO RPC-DSSETUP RPC-ALTERCONTEXT RPC-MULTIBIND NET-API-RPCCONNECT NET-API-LISTSHARES NET-API-CREATEUSER" +ncacn_ip_tcp_tests="RPC-SCHANNEL RPC-JOIN RPC-ECHO RPC-DSSETUP RPC-ALTERCONTEXT RPC-MULTIBIND NET-API-RPCCONNECT NET-API-LISTSHARES NET-API-CREATEUSER" slow_ncacn_np_tests="RPC-SAMLOGON" slow_ncalrpc_tests="RPC-SAMLOGON" slow_ncacn_ip_tcp_tests="RPC-SAMLOGON" diff --git a/source4/torture/libnet/libnet_lookup.c b/source4/torture/libnet/libnet_lookup.c index b6f23fd58c..c95ee58e49 100644 --- a/source4/torture/libnet/libnet_lookup.c +++ b/source4/torture/libnet/libnet_lookup.c @@ -40,8 +40,7 @@ BOOL torture_lookup(void) address = talloc_array(ctx, const char, 16); - lookup.in.hostname = lp_netbios_name(); - lookup.in.methods = lp_name_resolve_order(); + lookup.in.hostname = lp_parm_string(-1, "torture", "host"); lookup.in.type = NBT_NAME_CLIENT; lookup.out.address = &address; @@ -77,8 +76,7 @@ BOOL torture_lookup_host(void) address = talloc_array(mem_ctx, const char, 16); - lookup.in.hostname = lp_netbios_name(); - lookup.in.methods = lp_name_resolve_order(); + lookup.in.hostname = lp_parm_string(-1, "torture", "host"); lookup.out.address = &address; status = libnet_LookupHost(ctx, mem_ctx, &lookup); @@ -103,24 +101,28 @@ BOOL torture_lookup_pdc(void) NTSTATUS status; TALLOC_CTX *mem_ctx; struct libnet_context *ctx; - struct libnet_Lookup lookup; - const char *address; + struct libnet_LookupDCs *lookup; mem_ctx = talloc_init("test_lookup_pdc"); ctx = libnet_context_init(NULL); ctx->cred = cmdline_credentials; - address = talloc_array(mem_ctx, const char, 16); + talloc_steal(ctx, mem_ctx); - lookup.in.hostname = lp_workgroup(); - lookup.in.methods = lp_name_resolve_order(); - lookup.out.address = &address; + lookup = talloc(mem_ctx, struct libnet_LookupDCs); + if (!lookup) { + ret = False; + goto done; + } + + lookup->in.domain_name = lp_workgroup(); + lookup->in.name_type = NBT_NAME_PDC; - status = libnet_LookupPdc(ctx, mem_ctx, &lookup); + status = libnet_LookupDCs(ctx, mem_ctx, lookup); if (!NT_STATUS_IS_OK(status)) { - printf("Couldn't lookup pdc %s: %s\n", lookup.in.hostname, nt_errstr(status)); + printf("Couldn't lookup pdc %s: %s\n", lookup->in.domain_name, nt_errstr(status)); ret = False; goto done; } diff --git a/source4/torture/libnet/libnet_rpc.c b/source4/torture/libnet/libnet_rpc.c index 99055fac0d..418f579728 100644 --- a/source4/torture/libnet/libnet_rpc.c +++ b/source4/torture/libnet/libnet_rpc.c @@ -24,20 +24,19 @@ #include "libnet/libnet.h" -BOOL test_lsa_np_connect(struct libnet_context *ctx) +static BOOL test_lsa_connect(struct libnet_context *ctx) { NTSTATUS status; struct libnet_RpcConnect connect; connect.level = LIBNET_RPC_CONNECT_BINDING; - connect.in.domain_name = lp_workgroup(); - connect.in.binding = talloc_asprintf(ctx, "ncacn_np:%s", lp_workgroup()); + connect.in.binding = lp_parm_string(-1, "torture", "binding"); connect.in.dcerpc_iface = &dcerpc_table_lsarpc; status = libnet_RpcConnect(ctx, ctx, &connect); if (!NT_STATUS_IS_OK(status)) { printf("Couldn't connect to rpc service %s on %s: %s\n", - connect.in.dcerpc_iface->name, connect.in.domain_name, + connect.in.dcerpc_iface->name, connect.in.binding, nt_errstr(status)); return False; @@ -47,20 +46,19 @@ BOOL test_lsa_np_connect(struct libnet_context *ctx) } -BOOL test_samr_np_connect(struct libnet_context *ctx) +static BOOL test_samr_connect(struct libnet_context *ctx) { NTSTATUS status; struct libnet_RpcConnect connect; connect.level = LIBNET_RPC_CONNECT_BINDING; - connect.in.domain_name = lp_workgroup(); - connect.in.binding = talloc_asprintf(ctx, "ncacn_np:%s", lp_workgroup()); + connect.in.binding = lp_parm_string(-1, "torture", "binding"); connect.in.dcerpc_iface = &dcerpc_table_samr; status = libnet_RpcConnect(ctx, ctx, &connect); if (!NT_STATUS_IS_OK(status)) { printf("Couldn't connect to rpc service %s on %s: %s\n", - connect.in.dcerpc_iface->name, connect.in.domain_name, + connect.in.dcerpc_iface->name, connect.in.binding, nt_errstr(status)); return False; @@ -69,53 +67,6 @@ BOOL test_samr_np_connect(struct libnet_context *ctx) return True; } - -BOOL test_lsa_tcpip_connect(struct libnet_context *ctx) -{ - NTSTATUS status; - struct libnet_RpcConnect connect; - connect.level = LIBNET_RPC_CONNECT_BINDING; - connect.in.domain_name = lp_workgroup(); - connect.in.binding = talloc_asprintf(ctx, "ncacn_ip_tcp:%s", lp_netbios_name()); - connect.in.dcerpc_iface = &dcerpc_table_lsarpc; - - status = libnet_RpcConnect(ctx, ctx, &connect); - - if (!NT_STATUS_IS_OK(status)) { - printf("Couldn't connect to rpc service %s on %s: %s\n", - connect.in.dcerpc_iface->name, connect.in.domain_name, - nt_errstr(status)); - - return False; - } - - return True; -} - - -BOOL test_samr_tcpip_connect(struct libnet_context *ctx) -{ - NTSTATUS status; - struct libnet_RpcConnect connect; - connect.level = LIBNET_RPC_CONNECT_BINDING; - connect.in.domain_name = lp_workgroup(); - connect.in.binding = talloc_asprintf(ctx, "ncacn_ip_tcp:%s", lp_netbios_name()); - connect.in.dcerpc_iface = &dcerpc_table_samr; - - status = libnet_RpcConnect(ctx, ctx, &connect); - - if (!NT_STATUS_IS_OK(status)) { - printf("Couldn't connect to rpc service %s on %s: %s\n", - connect.in.dcerpc_iface->name, connect.in.domain_name, - nt_errstr(status)); - - return False; - } - - return True; -} - - BOOL torture_rpc_connect(void) { struct libnet_context *ctx; @@ -123,27 +74,15 @@ BOOL torture_rpc_connect(void) ctx = libnet_context_init(NULL); ctx->cred = cmdline_credentials; - printf("Testing connection to lsarpc interface via named pipe\n"); - if (!test_lsa_np_connect(ctx)) { - printf("failed to connect lsarpc interface via named pipe\n"); - return False; - } - - printf("Testing connection to SAMR service via named pipe\n"); - if (!test_samr_np_connect(ctx)) { - printf("failed to connect samr interface via named pipe\n"); - return False; - } - - printf("Testing connection to LSA service via tcp/ip\n"); - if (!test_lsa_tcpip_connect(ctx)) { - printf("failed to connect lsarpc interface via tcp/ip\n"); + printf("Testing connection to lsarpc interface\n"); + if (!test_lsa_connect(ctx)) { + printf("failed to connect lsarpc interface\n"); return False; } - printf("Testing connection to SAMR service via tcp/ip\n"); - if (!test_samr_tcpip_connect(ctx)) { - printf("failed to connect samr interface via tcp/ip\n"); + printf("Testing connection to SAMR service\n"); + if (!test_samr_connect(ctx)) { + printf("failed to connect samr interface\n"); return False; } diff --git a/source4/torture/libnet/libnet_share.c b/source4/torture/libnet/libnet_share.c index 5489f42ac8..93919a4129 100644 --- a/source4/torture/libnet/libnet_share.c +++ b/source4/torture/libnet/libnet_share.c @@ -148,7 +148,7 @@ BOOL torture_listshares(void) status = libnet_ListShares(libnetctx, mem_ctx, &share); if (!NT_STATUS_IS_OK(status)) { - printf("libnet_ListShare level %u failed - %s\n", share.in.level, nt_errstr(status)); + printf("libnet_ListShare level %u failed - %s\n", share.in.level, share.out.error_string); ret = False; goto done; } |