summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/client/client.c10
-rw-r--r--source3/include/async_smb.h4
-rw-r--r--source3/include/proto.h7
-rw-r--r--source3/libsmb/clientgen.c166
-rw-r--r--source3/torture/torture.c33
5 files changed, 187 insertions, 33 deletions
diff --git a/source3/client/client.c b/source3/client/client.c
index 18b286324b..1c0dff92c1 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -943,6 +943,7 @@ static int cmd_echo(void)
TALLOC_CTX *ctx = talloc_tos();
char *num;
char *data;
+ NTSTATUS status;
if (!next_token_talloc(ctx, &cmd_ptr, &num, NULL)
|| !next_token_talloc(ctx, &cmd_ptr, &data, NULL)) {
@@ -950,9 +951,10 @@ static int cmd_echo(void)
return 1;
}
- if (!cli_echo(cli, atoi(num), (uint8 *)data, strlen(data))) {
- d_printf("echo failed: %s\n",
- nt_errstr(cli_get_nt_error(cli)));
+ status = cli_echo(cli, atoi(num), data_blob_const(data, strlen(data)));
+
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("echo failed: %s\n", nt_errstr(status));
return 1;
}
@@ -4417,7 +4419,7 @@ static void readline_callback(void)
{
unsigned char garbage[16];
memset(garbage, 0xf0, sizeof(garbage));
- cli_echo(cli, 1, garbage, sizeof(garbage));
+ cli_echo(cli, 1, data_blob_const(garbage, sizeof(garbage)));
}
}
diff --git a/source3/include/async_smb.h b/source3/include/async_smb.h
index 6a09bb6001..ed42baef0d 100644
--- a/source3/include/async_smb.h
+++ b/source3/include/async_smb.h
@@ -90,6 +90,10 @@ struct cli_request {
ssize_t received;
uint8_t *rcvbuf;
} read;
+ struct {
+ DATA_BLOB data;
+ uint16_t num_echos;
+ } echo;
} data;
/**
diff --git a/source3/include/proto.h b/source3/include/proto.h
index f21cc2b17f..abfc79024a 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -4338,8 +4338,11 @@ void cli_sockopt(struct cli_state *cli, const char *options);
uint16 cli_setpid(struct cli_state *cli, uint16 pid);
bool cli_set_case_sensitive(struct cli_state *cli, bool case_sensitive);
bool cli_send_keepalive(struct cli_state *cli);
-bool cli_echo(struct cli_state *cli, uint16 num_echos,
- unsigned char *data, size_t length);
+struct async_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ struct cli_state *cli, uint16_t num_echos,
+ DATA_BLOB data);
+NTSTATUS cli_echo_recv(struct async_req *req);
+NTSTATUS cli_echo(struct cli_state *cli, uint16_t num_echos, DATA_BLOB data);
/* The following definitions come from libsmb/clierror.c */
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c
index 2c0950de03..239ba470a9 100644
--- a/source3/libsmb/clientgen.c
+++ b/source3/libsmb/clientgen.c
@@ -637,41 +637,153 @@ bool cli_send_keepalive(struct cli_state *cli)
return true;
}
-/****************************************************************************
- Send/receive a SMBecho command: ping the server
-****************************************************************************/
+/**
+ * @brief: Collect a echo reply
+ * @param[in] req The corresponding async request
+ *
+ * There might be more than one echo reply. This helper pulls the reply out of
+ * the data stream. If all expected replies have arrived, declare the
+ * async_req done.
+ */
+
+static void cli_echo_recv_helper(struct async_req *req)
+{
+ struct cli_request *cli_req;
+ uint8_t wct;
+ uint16_t *vwv;
+ uint16_t num_bytes;
+ uint8_t *bytes;
+ NTSTATUS status;
+
+ status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
+ if (!NT_STATUS_IS_OK(status)) {
+ async_req_error(req, status);
+ return;
+ }
+
+ cli_req = cli_request_get(req);
+
+ if ((num_bytes != cli_req->data.echo.data.length)
+ || (memcmp(cli_req->data.echo.data.data, bytes,
+ num_bytes) != 0)) {
+ async_req_error(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ cli_req->data.echo.num_echos -= 1;
-bool cli_echo(struct cli_state *cli, uint16 num_echos,
- unsigned char *data, size_t length)
+ if (cli_req->data.echo.num_echos == 0) {
+ client_set_trans_sign_state_off(cli_req->cli, cli_req->mid);
+ async_req_done(req);
+ return;
+ }
+
+ return;
+}
+
+/**
+ * @brief Send SMBEcho requests
+ * @param[in] mem_ctx The memory context to put the async_req on
+ * @param[in] ev The event context that will call us back
+ * @param[in] cli The connection to send the echo to
+ * @param[in] num_echos How many times do we want to get the reply?
+ * @param[in] data The data we want to get back
+ * @retval The async request
+ */
+
+struct async_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
+ struct cli_state *cli, uint16_t num_echos,
+ DATA_BLOB data)
{
- char *p;
- int i;
+ uint16_t vwv[1];
+ uint8_t *data_copy;
+ struct async_req *result;
+ struct cli_request *req;
- SMB_ASSERT(length < 1024);
+ SSVAL(vwv, 0, num_echos);
- memset(cli->outbuf,'\0',smb_size);
- cli_set_message(cli->outbuf,1,length,true);
- SCVAL(cli->outbuf,smb_com,SMBecho);
- SSVAL(cli->outbuf,smb_tid,65535);
- SSVAL(cli->outbuf,smb_vwv0,num_echos);
- cli_setup_packet(cli);
- p = smb_buf(cli->outbuf);
- memcpy(p, data, length);
- p += length;
+ data_copy = (uint8_t *)talloc_memdup(mem_ctx, data.data, data.length);
+ if (data_copy == NULL) {
+ return NULL;
+ }
- cli_setup_bcc(cli, p);
+ result = cli_request_send(mem_ctx, ev, cli, SMBecho, 0, 1, vwv,
+ data.length, data.data);
+ if (result == NULL) {
+ TALLOC_FREE(data_copy);
+ return NULL;
+ }
+ req = cli_request_get(result);
- cli_send_smb(cli);
+ client_set_trans_sign_state_on(cli, req->mid);
- for (i=0; i<num_echos; i++) {
- if (!cli_receive_smb(cli)) {
- return false;
- }
+ req->data.echo.num_echos = num_echos;
+ req->data.echo.data.data = talloc_move(req, &data_copy);
+ req->data.echo.data.length = data.length;
- if (cli_is_error(cli)) {
- return false;
- }
+ req->recv_helper.fn = cli_echo_recv_helper;
+
+ return result;
+}
+
+/**
+ * Get the result out from an echo request
+ * @param[in] req The async_req from cli_echo_send
+ * @retval Did the server reply correctly?
+ */
+
+NTSTATUS cli_echo_recv(struct async_req *req)
+{
+ SMB_ASSERT(req->state >= ASYNC_REQ_DONE);
+ if (req->state == ASYNC_REQ_ERROR) {
+ return req->status;
}
- return true;
+ return NT_STATUS_OK;
+}
+
+/**
+ * @brief Send/Receive SMBEcho requests
+ * @param[in] mem_ctx The memory context to put the async_req on
+ * @param[in] ev The event context that will call us back
+ * @param[in] cli The connection to send the echo to
+ * @param[in] num_echos How many times do we want to get the reply?
+ * @param[in] data The data we want to get back
+ * @retval Did the server reply correctly?
+ */
+
+NTSTATUS cli_echo(struct cli_state *cli, uint16_t num_echos, DATA_BLOB data)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct async_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (cli->fd_event != NULL) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ cli_set_error(cli, NT_STATUS_INVALID_PARAMETER);
+ goto fail;
+ }
+
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+
+ req = cli_echo_send(frame, ev, cli, num_echos, data);
+ if (req == NULL) {
+ goto fail;
+ }
+
+ while (req->state < ASYNC_REQ_DONE) {
+ event_loop_once(ev);
+ }
+
+ status = cli_echo_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ return status;
}
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index d159ffbac3..d8942e42b9 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -4976,6 +4976,38 @@ static bool run_chain1(int dummy)
return True;
}
+static bool run_cli_echo(int dummy)
+{
+ struct cli_state *cli;
+ struct event_context *ev = event_context_init(NULL);
+ struct async_req *req;
+ NTSTATUS status;
+
+ printf("starting chain1 test\n");
+ if (!torture_open_connection(&cli, 0)) {
+ return false;
+ }
+ cli_sockopt(cli, sockops);
+
+ req = cli_echo_send(ev, ev, cli, 5, data_blob_const("hello", 5));
+ if (req == NULL) {
+ d_printf("cli_echo_send failed\n");
+ return false;
+ }
+
+ while (req->state < ASYNC_REQ_DONE) {
+ event_loop_once(ev);
+ }
+
+ status = cli_echo_recv(req);
+ d_printf("cli_echo returned %s\n", nt_errstr(status));
+
+ TALLOC_FREE(req);
+
+ torture_close_connection(cli);
+ return NT_STATUS_IS_OK(status);
+}
+
static bool run_local_substitute(int dummy)
{
bool ok = true;
@@ -5474,6 +5506,7 @@ static struct {
{ "EATEST", run_eatest, 0},
{ "SESSSETUP_BENCH", run_sesssetup_bench, 0},
{ "CHAIN1", run_chain1, 0},
+ { "CLI_ECHO", run_cli_echo, 0},
{ "LOCAL-SUBSTITUTE", run_local_substitute, 0},
{ "LOCAL-GENCACHE", run_local_gencache, 0},
{ "LOCAL-RBTREE", run_local_rbtree, 0},