2 Unix SMB/CIFS implementation.
3 client message handling routines
4 Copyright (C) Andrew Tridgell 1994-1998
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.
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.
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/>.
21 #include "../lib/util/tevent_ntstatus.h"
22 #include "async_smb.h"
23 #include "libsmb/libsmb.h"
24 #include "../libcli/smb/smbXcli_base.h"
26 struct cli_message_start_state
{
30 static void cli_message_start_done(struct tevent_req
*subreq
);
32 static struct tevent_req
*cli_message_start_send(TALLOC_CTX
*mem_ctx
,
33 struct tevent_context
*ev
,
34 struct cli_state
*cli
,
38 struct tevent_req
*req
, *subreq
;
39 struct cli_message_start_state
*state
;
45 req
= tevent_req_create(mem_ctx
, &state
,
46 struct cli_message_start_state
);
51 if (!convert_string_talloc(talloc_tos(), CH_UNIX
, CH_DOS
,
52 username
, strlen(username
)+1,
56 if (!convert_string_talloc(talloc_tos(), CH_UNIX
, CH_DOS
,
62 bytes
= talloc_array(state
, uint8_t, ulen
+hlen
+2);
69 memcpy(p
, utmp
, ulen
);
72 memcpy(p
, htmp
, hlen
);
77 subreq
= cli_smb_send(state
, ev
, cli
, SMBsendstrt
, 0, 0, NULL
,
78 talloc_get_size(bytes
), bytes
);
79 if (tevent_req_nomem(subreq
, req
)) {
80 return tevent_req_post(req
, ev
);
82 tevent_req_set_callback(subreq
, cli_message_start_done
, req
);
87 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
88 return tevent_req_post(req
, ev
);
91 static void cli_message_start_done(struct tevent_req
*subreq
)
93 struct tevent_req
*req
= tevent_req_callback_data(
94 subreq
, struct tevent_req
);
95 struct cli_message_start_state
*state
= tevent_req_data(
96 req
, struct cli_message_start_state
);
101 status
= cli_smb_recv(subreq
, state
, NULL
, 0, &wct
, &vwv
,
104 if (!NT_STATUS_IS_OK(status
)) {
106 tevent_req_nterror(req
, status
);
110 state
->grp
= SVAL(vwv
+0, 0);
114 tevent_req_done(req
);
117 static NTSTATUS
cli_message_start_recv(struct tevent_req
*req
,
120 struct cli_message_start_state
*state
= tevent_req_data(
121 req
, struct cli_message_start_state
);
124 if (tevent_req_is_nterror(req
, &status
)) {
131 struct cli_message_text_state
{
135 static void cli_message_text_done(struct tevent_req
*subreq
);
137 static struct tevent_req
*cli_message_text_send(TALLOC_CTX
*mem_ctx
,
138 struct tevent_context
*ev
,
139 struct cli_state
*cli
,
144 struct tevent_req
*req
, *subreq
;
145 struct cli_message_text_state
*state
;
150 req
= tevent_req_create(mem_ctx
, &state
,
151 struct cli_message_text_state
);
156 SSVAL(&state
->vwv
, 0, grp
);
158 if (convert_string_talloc(talloc_tos(), CH_UNIX
, CH_DOS
, msg
, msglen
,
163 DEBUG(3, ("Conversion failed, sending message in UNIX "
168 bytes
= talloc_array(state
, uint8_t, msglen
+3);
169 if (tevent_req_nomem(bytes
, req
)) {
171 return tevent_req_post(req
, ev
);
173 SCVAL(bytes
, 0, 1); /* pad */
174 SSVAL(bytes
+1, 0, msglen
);
175 memcpy(bytes
+3, msg
, msglen
);
178 subreq
= cli_smb_send(state
, ev
, cli
, SMBsendtxt
, 0, 1, &state
->vwv
,
179 talloc_get_size(bytes
), bytes
);
180 if (tevent_req_nomem(subreq
, req
)) {
181 return tevent_req_post(req
, ev
);
183 tevent_req_set_callback(subreq
, cli_message_text_done
, req
);
187 static void cli_message_text_done(struct tevent_req
*subreq
)
189 struct tevent_req
*req
= tevent_req_callback_data(
190 subreq
, struct tevent_req
);
193 status
= cli_smb_recv(subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
195 if (!NT_STATUS_IS_OK(status
)) {
196 tevent_req_nterror(req
, status
);
199 tevent_req_done(req
);
202 static NTSTATUS
cli_message_text_recv(struct tevent_req
*req
)
204 return tevent_req_simple_recv_ntstatus(req
);
207 struct cli_message_end_state
{
211 static void cli_message_end_done(struct tevent_req
*subreq
);
213 static struct tevent_req
*cli_message_end_send(TALLOC_CTX
*mem_ctx
,
214 struct tevent_context
*ev
,
215 struct cli_state
*cli
,
218 struct tevent_req
*req
, *subreq
;
219 struct cli_message_end_state
*state
;
221 req
= tevent_req_create(mem_ctx
, &state
,
222 struct cli_message_end_state
);
227 SSVAL(&state
->vwv
, 0, grp
);
229 subreq
= cli_smb_send(state
, ev
, cli
, SMBsendend
, 0, 1, &state
->vwv
,
231 if (tevent_req_nomem(subreq
, req
)) {
232 return tevent_req_post(req
, ev
);
234 tevent_req_set_callback(subreq
, cli_message_end_done
, req
);
238 static void cli_message_end_done(struct tevent_req
*subreq
)
240 struct tevent_req
*req
= tevent_req_callback_data(
241 subreq
, struct tevent_req
);
244 status
= cli_smb_recv(subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
246 if (!NT_STATUS_IS_OK(status
)) {
247 tevent_req_nterror(req
, status
);
250 tevent_req_done(req
);
253 static NTSTATUS
cli_message_end_recv(struct tevent_req
*req
)
255 return tevent_req_simple_recv_ntstatus(req
);
258 struct cli_message_state
{
259 struct tevent_context
*ev
;
260 struct cli_state
*cli
;
266 static void cli_message_started(struct tevent_req
*subreq
);
267 static void cli_message_sent(struct tevent_req
*subreq
);
268 static void cli_message_done(struct tevent_req
*subreq
);
270 struct tevent_req
*cli_message_send(TALLOC_CTX
*mem_ctx
,
271 struct tevent_context
*ev
,
272 struct cli_state
*cli
,
273 const char *host
, const char *username
,
276 struct tevent_req
*req
, *subreq
;
277 struct cli_message_state
*state
;
279 req
= tevent_req_create(mem_ctx
, &state
, struct cli_message_state
);
286 state
->message
= message
;
288 subreq
= cli_message_start_send(state
, ev
, cli
, host
, username
);
289 if (tevent_req_nomem(subreq
, req
)) {
290 return tevent_req_post(req
, ev
);
292 tevent_req_set_callback(subreq
, cli_message_started
, req
);
296 static void cli_message_started(struct tevent_req
*subreq
)
298 struct tevent_req
*req
= tevent_req_callback_data(
299 subreq
, struct tevent_req
);
300 struct cli_message_state
*state
= tevent_req_data(
301 req
, struct cli_message_state
);
305 status
= cli_message_start_recv(subreq
, &state
->grp
);
307 if (!NT_STATUS_IS_OK(status
)) {
308 tevent_req_nterror(req
, status
);
312 thistime
= MIN(127, strlen(state
->message
));
314 subreq
= cli_message_text_send(state
, state
->ev
, state
->cli
,
315 state
->grp
, state
->message
, thistime
);
316 if (tevent_req_nomem(subreq
, req
)) {
319 state
->sent
+= thistime
;
320 tevent_req_set_callback(subreq
, cli_message_sent
, req
);
323 static void cli_message_sent(struct tevent_req
*subreq
)
325 struct tevent_req
*req
= tevent_req_callback_data(
326 subreq
, struct tevent_req
);
327 struct cli_message_state
*state
= tevent_req_data(
328 req
, struct cli_message_state
);
330 size_t left
, thistime
;
332 status
= cli_message_text_recv(subreq
);
334 if (!NT_STATUS_IS_OK(status
)) {
335 tevent_req_nterror(req
, status
);
339 if (state
->sent
>= strlen(state
->message
)) {
340 subreq
= cli_message_end_send(state
, state
->ev
, state
->cli
,
342 if (tevent_req_nomem(subreq
, req
)) {
345 tevent_req_set_callback(subreq
, cli_message_done
, req
);
349 left
= strlen(state
->message
) - state
->sent
;
350 thistime
= MIN(127, left
);
352 subreq
= cli_message_text_send(state
, state
->ev
, state
->cli
,
354 state
->message
+ state
->sent
,
356 if (tevent_req_nomem(subreq
, req
)) {
359 state
->sent
+= thistime
;
360 tevent_req_set_callback(subreq
, cli_message_sent
, req
);
363 static void cli_message_done(struct tevent_req
*subreq
)
365 struct tevent_req
*req
= tevent_req_callback_data(
366 subreq
, struct tevent_req
);
369 status
= cli_message_end_recv(subreq
);
371 if (!NT_STATUS_IS_OK(status
)) {
372 tevent_req_nterror(req
, status
);
375 tevent_req_done(req
);
378 NTSTATUS
cli_message_recv(struct tevent_req
*req
)
380 return tevent_req_simple_recv_ntstatus(req
);
383 NTSTATUS
cli_message(struct cli_state
*cli
, const char *host
,
384 const char *username
, const char *message
)
386 TALLOC_CTX
*frame
= talloc_stackframe();
387 struct tevent_context
*ev
;
388 struct tevent_req
*req
;
389 NTSTATUS status
= NT_STATUS_OK
;
391 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
393 * Can't use sync call while an async call is in flight
395 status
= NT_STATUS_INVALID_PARAMETER
;
399 ev
= samba_tevent_context_init(frame
);
401 status
= NT_STATUS_NO_MEMORY
;
405 req
= cli_message_send(frame
, ev
, cli
, host
, username
, message
);
407 status
= NT_STATUS_NO_MEMORY
;
411 if (!tevent_req_poll(req
, ev
)) {
412 status
= map_nt_error_from_unix(errno
);
416 status
= cli_message_recv(req
);