--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+ test suite for lsa rpc operations
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/cmdline.h"
+#include "torture/torture.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libcli/tstream_binding_handle/tstream_binding_handle.h"
+#include "lib/tsocket/tsocket.h"
+#include "param/param.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "libcli/resolve/resolve.h"
+#include "libcli/libcli.h"
+#include "libcli/smb/smbXcli_base.h"
+#include "librpc/gen_ndr/ndr_rawpipe.h"
+
+static NTSTATUS raw_resp_pdu_complete(struct tstream_context *stream,
+void *private_data,
+DATA_BLOB blob,
+size_t *packet_size)
+{
+ ssize_t to_read;
+
+ to_read = tstream_pending_bytes(stream);
+ if (to_read == -1) {
+ return NT_STATUS_IO_DEVICE_ERROR;
+ }
+
+ if (to_read > 0) {
+ *packet_size = blob.length + to_read;
+ return STATUS_MORE_ENTRIES;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS torture_rawpipe_connection(struct torture_context *tctx,
+ struct dcerpc_pipe **p,
+ const char* pipename)
+{
+ struct cli_credentials *credentials = samba_cmdline_get_creds();
+ struct tevent_context *ev_ctx = tctx->ev;
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+ struct loadparm_context *lp_ctx = tctx->lp_ctx;
+ bool smb2_or_greater;
+ struct smbcli_options options;
+ struct smbcli_session_options session_options;
+ struct dcerpc_pipe *pipe = NULL;
+ struct smb2_tree *tree = NULL;
+ struct smbcli_state *cli = NULL;
+ const char *target_hostname = NULL;
+ enum protocol_types protocol;
+ lpcfg_smbcli_options(lp_ctx, &options);
+ lpcfg_smbcli_session_options(lp_ctx, &session_options);
+ status = torture_rpc_binding(tctx, &binding);
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
+ }
+
+ target_hostname =
+ dcerpc_binding_get_string_option(binding, "target_hostname");
+
+ if (target_hostname == NULL) {
+ target_hostname =
+ dcerpc_binding_get_string_option(binding, "host");
+ }
+
+ smb2_or_greater =
+ (lpcfg_client_ipc_max_protocol(lp_ctx) >= PROTOCOL_SMB2_02);
+ if (smb2_or_greater) {
+ status = smb2_connect(tctx,
+ target_hostname,
+ lpcfg_smb_ports(lp_ctx),
+ "IPC$",
+ lpcfg_resolve_context(lp_ctx),
+ credentials,
+ &tree,
+ ev_ctx,
+ &options,
+ lpcfg_socket_options(lp_ctx),
+ lpcfg_gensec_settings(tctx,
+ lp_ctx)
+ );
+
+ if (NT_STATUS_IS_OK(status)) {
+ protocol =
+ smbXcli_conn_protocol(
+ tree->session->transport->conn);
+ } else {
+ return status;
+ }
+
+ } else {
+ status = smbcli_full_connection(tctx,
+ &cli,
+ target_hostname,
+ lpcfg_smb_ports(lp_ctx),
+ "IPC$", NULL,
+ lpcfg_socket_options(lp_ctx),
+ credentials,
+ lpcfg_resolve_context(lp_ctx),
+ ev_ctx, &options, &session_options,
+ lpcfg_gensec_settings(tctx,
+ lp_ctx));
+ if (NT_STATUS_IS_OK(status)) {
+ protocol =
+ smbXcli_conn_protocol(
+ cli->transport->conn);
+ } else {
+ return status;
+ }
+ }
+
+ pipe = dcerpc_pipe_init(tctx, ev_ctx);
+ if (!pipe) {
+ DBG_ERR("failed to int the pipe)\n");
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (protocol >= PROTOCOL_SMB2_02) {
+ status = dcerpc_pipe_open_smb2(pipe, tree, pipename);
+ } else {
+ status = dcerpc_pipe_open_smb(pipe, cli->tree, pipename);
+ }
+ if (NT_STATUS_IS_OK(status)) {
+ *p = pipe;
+ }
+ return status;
+}
+
+bool torture_rpc_rawpipe_echo_impl(struct torture_context *tctx,
+ const char* pipename)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ bool ret = true;
+ struct dcerpc_binding_handle *b;
+ int count;
+ const char* echoes[] = {
+ "one",
+ "two",
+ "three",
+ "four"};
+ status = torture_rawpipe_connection(tctx, &p, pipename);
+
+ torture_assert_ntstatus_ok(tctx, status, "Error connecting to server");
+
+ /* use custom rawpipe specific handle */
+ b = tstream_binding_handle_create(p,
+ NULL,
+ &p->conn->transport.stream,
+ 3,
+ raw_resp_pdu_complete,
+ tctx, 42280);
+ dcerpc_binding_handle_set_timeout(b,
+ DCERPC_REQUEST_TIMEOUT * 1000);
+ for (count=0; count < ARRAY_SIZE(echoes); count++) {
+ DATA_BLOB in = {0};
+ DATA_BLOB out = {0};
+ struct raw_request_response *request = NULL;
+ struct raw_request_response *response = NULL;
+ uint32_t outflags;
+ struct ndr_pull *ndr = NULL;
+ struct ndr_push *ndr_push = NULL;
+ enum ndr_err_code err;
+ int ndr_flags = NDR_SCALARS | NDR_BUFFERS;
+
+ request = talloc_zero(tctx, struct raw_request_response);
+ torture_assert(tctx, request != NULL, "talloc_zero failed");
+
+ response = talloc_zero(tctx, struct raw_request_response);
+ torture_assert(tctx, response != NULL, "talloc_zero failed");
+
+ request->payload = talloc_strdup(talloc_tos(), echoes[count]);
+ torture_assert(tctx,
+ request->payload != NULL,
+ "failed to allocate payload");
+
+ ndr_push = ndr_push_init_ctx(tctx);
+ torture_assert(tctx,
+ ndr_push != NULL,
+ "Failed to init push ctx");
+
+ err = ndr_push_raw_request_response(ndr_push,
+ ndr_flags,
+ request);
+
+ torture_assert(tctx, err == 0, "push payload failed");
+ in = ndr_push_blob(ndr_push);
+
+ status = dcerpc_binding_handle_raw_call(b,
+ NULL,
+ 0,
+ 0,
+ in.data,
+ in.length,
+ tctx,
+ &out.data,
+ &out.length,
+ &outflags);
+ torture_assert_ntstatus_ok(tctx,
+ status,
+ "Failed to send to rawpipe");
+ ndr = ndr_pull_init_blob(&out, tctx);
+ torture_assert(tctx, ndr != NULL, "failed to init push blob");
+ err = ndr_pull_raw_request_response(ndr, ndr_flags, response);
+
+ torture_assert(tctx, err == 0, "pull response payload failed");
+ printf("Received %s from rawd\n", response->payload);
+ }
+ return ret;
+}
+
+bool torture_rpc_rawpipe(struct torture_context *tctx)
+{
+ return torture_rpc_rawpipe_echo_impl(tctx,
+ "rawpipe");
+}