Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : smb2 lib
4 : Copyright (C) Stefan Metzmacher 2012
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "system/network.h"
22 : #include "lib/util/tevent_ntstatus.h"
23 : #include "smb_common.h"
24 : #include "smbXcli_base.h"
25 :
26 : struct smb1cli_echo_state {
27 : uint16_t vwv[1];
28 : DATA_BLOB data;
29 : uint16_t num_echos;
30 : };
31 :
32 : static void smb1cli_echo_done(struct tevent_req *subreq);
33 :
34 21 : struct tevent_req *smb1cli_echo_send(TALLOC_CTX *mem_ctx,
35 : struct tevent_context *ev,
36 : struct smbXcli_conn *conn,
37 : uint32_t timeout_msec,
38 : uint16_t num_echos,
39 : DATA_BLOB data)
40 : {
41 0 : struct tevent_req *req, *subreq;
42 0 : struct smb1cli_echo_state *state;
43 :
44 21 : req = tevent_req_create(mem_ctx, &state, struct smb1cli_echo_state);
45 21 : if (req == NULL) {
46 0 : return NULL;
47 : }
48 21 : SSVAL(state->vwv, 0, num_echos);
49 21 : state->data = data;
50 21 : state->num_echos = num_echos;
51 :
52 21 : subreq = smb1cli_req_send(state, ev, conn, SMBecho,
53 : 0, 0, /* *_flags */
54 : 0, 0, /* *_flags2 */
55 : timeout_msec,
56 : 0, /* pid */
57 : NULL, /* tcon */
58 : NULL, /* session */
59 21 : ARRAY_SIZE(state->vwv), state->vwv,
60 21 : data.length, data.data);
61 21 : if (subreq == NULL) {
62 0 : goto fail;
63 : }
64 21 : tevent_req_set_callback(subreq, smb1cli_echo_done, req);
65 21 : return req;
66 0 : fail:
67 0 : TALLOC_FREE(req);
68 0 : return NULL;
69 : }
70 :
71 21 : static void smb1cli_echo_done(struct tevent_req *subreq)
72 : {
73 21 : struct tevent_req *req = tevent_req_callback_data(
74 : subreq, struct tevent_req);
75 21 : struct smb1cli_echo_state *state = tevent_req_data(
76 : req, struct smb1cli_echo_state);
77 0 : NTSTATUS status;
78 0 : uint32_t num_bytes;
79 0 : uint8_t *bytes;
80 0 : struct iovec *recv_iov;
81 21 : struct smb1cli_req_expected_response expected[] = {
82 : {
83 : .status = NT_STATUS_OK,
84 : .wct = 1,
85 : },
86 : };
87 :
88 21 : status = smb1cli_req_recv(subreq, state,
89 : &recv_iov,
90 : NULL, /* phdr */
91 : NULL, /* pwct */
92 : NULL, /* pvwv */
93 : NULL, /* pvwv_offset */
94 : &num_bytes,
95 : &bytes,
96 : NULL, /* pbytes_offset */
97 : NULL, /* pinbuf */
98 : expected, ARRAY_SIZE(expected));
99 21 : if (!NT_STATUS_IS_OK(status)) {
100 0 : tevent_req_nterror(req, status);
101 21 : return;
102 : }
103 :
104 21 : if (num_bytes != state->data.length) {
105 0 : tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
106 0 : return;
107 : }
108 :
109 21 : if (memcmp(bytes, state->data.data, num_bytes) != 0) {
110 0 : tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
111 0 : return;
112 : }
113 :
114 : /* TODO: do we want to verify the sequence number? */
115 :
116 21 : state->num_echos -=1;
117 21 : if (state->num_echos == 0) {
118 21 : tevent_req_done(req);
119 21 : return;
120 : }
121 :
122 0 : if (!smbXcli_req_set_pending(subreq)) {
123 0 : tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
124 0 : return;
125 : }
126 : }
127 :
128 : /**
129 : * Get the result out from an echo request
130 : * @param[in] req The async_req from smb1cli_echo_send
131 : * @retval Did the server reply correctly?
132 : */
133 :
134 21 : NTSTATUS smb1cli_echo_recv(struct tevent_req *req)
135 : {
136 21 : return tevent_req_simple_recv_ntstatus(req);
137 : }
138 :
139 0 : NTSTATUS smb1cli_echo(struct smbXcli_conn *conn, uint32_t timeout_msec,
140 : uint16_t num_echos, DATA_BLOB data)
141 : {
142 0 : TALLOC_CTX *frame = talloc_stackframe();
143 0 : struct tevent_context *ev;
144 0 : struct tevent_req *req;
145 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
146 :
147 0 : if (smbXcli_conn_has_async_calls(conn)) {
148 : /*
149 : * Can't use sync call while an async call is in flight
150 : */
151 0 : status = NT_STATUS_INVALID_PARAMETER;
152 0 : goto fail;
153 : }
154 0 : ev = samba_tevent_context_init(frame);
155 0 : if (ev == NULL) {
156 0 : goto fail;
157 : }
158 0 : req = smb1cli_echo_send(frame, ev, conn, timeout_msec, num_echos, data);
159 0 : if (req == NULL) {
160 0 : goto fail;
161 : }
162 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
163 0 : goto fail;
164 : }
165 0 : status = smb1cli_echo_recv(req);
166 0 : fail:
167 0 : TALLOC_FREE(frame);
168 0 : return status;
169 : }
|