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 "async_smb.h"
23 struct cli_message_start_state
{
27 static void cli_message_start_done(struct tevent_req
*subreq
);
29 static struct tevent_req
*cli_message_start_send(TALLOC_CTX
*mem_ctx
,
30 struct tevent_context
*ev
,
31 struct cli_state
*cli
,
35 struct tevent_req
*req
, *subreq
;
36 struct cli_message_start_state
*state
;
42 req
= tevent_req_create(mem_ctx
, &state
,
43 struct cli_message_start_state
);
48 if (!convert_string_talloc(talloc_tos(), CH_UNIX
, CH_DOS
,
49 username
, strlen(username
)+1,
50 &utmp
, &ulen
, true)) {
53 if (!convert_string_talloc(talloc_tos(), CH_UNIX
, CH_DOS
,
55 &htmp
, &hlen
, true)) {
59 bytes
= talloc_array(state
, uint8_t, ulen
+hlen
+2);
66 memcpy(p
, utmp
, ulen
);
69 memcpy(p
, htmp
, hlen
);
74 subreq
= cli_smb_send(state
, ev
, cli
, SMBsendstrt
, 0, 0, NULL
,
75 talloc_get_size(bytes
), bytes
);
76 if (tevent_req_nomem(subreq
, req
)) {
77 return tevent_req_post(req
, ev
);
79 tevent_req_set_callback(subreq
, cli_message_start_done
, req
);
84 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
85 return tevent_req_post(req
, ev
);
88 static void cli_message_start_done(struct tevent_req
*subreq
)
90 struct tevent_req
*req
= tevent_req_callback_data(
91 subreq
, struct tevent_req
);
92 struct cli_message_start_state
*state
= tevent_req_data(
93 req
, struct cli_message_start_state
);
99 status
= cli_smb_recv(subreq
, state
, &inbuf
, 0, &wct
, &vwv
,
102 if (!NT_STATUS_IS_OK(status
)) {
104 tevent_req_nterror(req
, status
);
108 state
->grp
= SVAL(vwv
+0, 0);
112 tevent_req_done(req
);
115 static NTSTATUS
cli_message_start_recv(struct tevent_req
*req
,
118 struct cli_message_start_state
*state
= tevent_req_data(
119 req
, struct cli_message_start_state
);
122 if (tevent_req_is_nterror(req
, &status
)) {
129 struct cli_message_text_state
{
133 static void cli_message_text_done(struct tevent_req
*subreq
);
135 static struct tevent_req
*cli_message_text_send(TALLOC_CTX
*mem_ctx
,
136 struct tevent_context
*ev
,
137 struct cli_state
*cli
,
142 struct tevent_req
*req
, *subreq
;
143 struct cli_message_text_state
*state
;
148 req
= tevent_req_create(mem_ctx
, &state
,
149 struct cli_message_text_state
);
154 SSVAL(&state
->vwv
, 0, grp
);
156 if (convert_string_talloc(talloc_tos(), CH_UNIX
, CH_DOS
, msg
, msglen
,
157 &tmp
, &tmplen
, true)) {
161 DEBUG(3, ("Conversion failed, sending message in UNIX "
166 bytes
= talloc_array(state
, uint8_t, msglen
+3);
167 if (tevent_req_nomem(bytes
, req
)) {
169 return tevent_req_post(req
, ev
);
171 SCVAL(bytes
, 0, 1); /* pad */
172 SSVAL(bytes
+1, 0, msglen
);
173 memcpy(bytes
+3, msg
, msglen
);
176 subreq
= cli_smb_send(state
, ev
, cli
, SMBsendtxt
, 0, 1, &state
->vwv
,
177 talloc_get_size(bytes
), bytes
);
178 if (tevent_req_nomem(subreq
, req
)) {
179 return tevent_req_post(req
, ev
);
181 tevent_req_set_callback(subreq
, cli_message_text_done
, req
);
185 static void cli_message_text_done(struct tevent_req
*subreq
)
187 struct tevent_req
*req
= tevent_req_callback_data(
188 subreq
, struct tevent_req
);
191 status
= cli_smb_recv(subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
193 if (!NT_STATUS_IS_OK(status
)) {
194 tevent_req_nterror(req
, status
);
197 tevent_req_done(req
);
200 static NTSTATUS
cli_message_text_recv(struct tevent_req
*req
)
202 return tevent_req_simple_recv_ntstatus(req
);
205 struct cli_message_end_state
{
209 static void cli_message_end_done(struct tevent_req
*subreq
);
211 static struct tevent_req
*cli_message_end_send(TALLOC_CTX
*mem_ctx
,
212 struct tevent_context
*ev
,
213 struct cli_state
*cli
,
216 struct tevent_req
*req
, *subreq
;
217 struct cli_message_end_state
*state
;
219 req
= tevent_req_create(mem_ctx
, &state
,
220 struct cli_message_end_state
);
225 SSVAL(&state
->vwv
, 0, grp
);
227 subreq
= cli_smb_send(state
, ev
, cli
, SMBsendend
, 0, 1, &state
->vwv
,
229 if (tevent_req_nomem(subreq
, req
)) {
230 return tevent_req_post(req
, ev
);
232 tevent_req_set_callback(subreq
, cli_message_end_done
, req
);
236 static void cli_message_end_done(struct tevent_req
*subreq
)
238 struct tevent_req
*req
= tevent_req_callback_data(
239 subreq
, struct tevent_req
);
242 status
= cli_smb_recv(subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
244 if (!NT_STATUS_IS_OK(status
)) {
245 tevent_req_nterror(req
, status
);
248 tevent_req_done(req
);
251 static NTSTATUS
cli_message_end_recv(struct tevent_req
*req
)
253 return tevent_req_simple_recv_ntstatus(req
);
256 struct cli_message_state
{
257 struct tevent_context
*ev
;
258 struct cli_state
*cli
;
264 static void cli_message_started(struct tevent_req
*subreq
);
265 static void cli_message_sent(struct tevent_req
*subreq
);
266 static void cli_message_done(struct tevent_req
*subreq
);
268 struct tevent_req
*cli_message_send(TALLOC_CTX
*mem_ctx
,
269 struct tevent_context
*ev
,
270 struct cli_state
*cli
,
271 const char *host
, const char *username
,
274 struct tevent_req
*req
, *subreq
;
275 struct cli_message_state
*state
;
277 req
= tevent_req_create(mem_ctx
, &state
, struct cli_message_state
);
284 state
->message
= message
;
286 subreq
= cli_message_start_send(state
, ev
, cli
, host
, username
);
287 if (tevent_req_nomem(subreq
, req
)) {
288 return tevent_req_post(req
, ev
);
290 tevent_req_set_callback(subreq
, cli_message_started
, req
);
294 static void cli_message_started(struct tevent_req
*subreq
)
296 struct tevent_req
*req
= tevent_req_callback_data(
297 subreq
, struct tevent_req
);
298 struct cli_message_state
*state
= tevent_req_data(
299 req
, struct cli_message_state
);
303 status
= cli_message_start_recv(subreq
, &state
->grp
);
305 if (!NT_STATUS_IS_OK(status
)) {
306 tevent_req_nterror(req
, status
);
310 thistime
= MIN(127, strlen(state
->message
));
312 subreq
= cli_message_text_send(state
, state
->ev
, state
->cli
,
313 state
->grp
, state
->message
, thistime
);
314 if (tevent_req_nomem(subreq
, req
)) {
317 state
->sent
+= thistime
;
318 tevent_req_set_callback(subreq
, cli_message_sent
, req
);
321 static void cli_message_sent(struct tevent_req
*subreq
)
323 struct tevent_req
*req
= tevent_req_callback_data(
324 subreq
, struct tevent_req
);
325 struct cli_message_state
*state
= tevent_req_data(
326 req
, struct cli_message_state
);
328 size_t left
, thistime
;
330 status
= cli_message_text_recv(subreq
);
332 if (!NT_STATUS_IS_OK(status
)) {
333 tevent_req_nterror(req
, status
);
337 if (state
->sent
>= strlen(state
->message
)) {
338 subreq
= cli_message_end_send(state
, state
->ev
, state
->cli
,
340 if (tevent_req_nomem(subreq
, req
)) {
343 tevent_req_set_callback(subreq
, cli_message_done
, req
);
347 left
= strlen(state
->message
) - state
->sent
;
348 thistime
= MIN(127, left
);
350 subreq
= cli_message_text_send(state
, state
->ev
, state
->cli
,
352 state
->message
+ state
->sent
,
354 if (tevent_req_nomem(subreq
, req
)) {
357 state
->sent
+= thistime
;
358 tevent_req_set_callback(subreq
, cli_message_sent
, req
);
361 static void cli_message_done(struct tevent_req
*subreq
)
363 struct tevent_req
*req
= tevent_req_callback_data(
364 subreq
, struct tevent_req
);
367 status
= cli_message_end_recv(subreq
);
369 if (!NT_STATUS_IS_OK(status
)) {
370 tevent_req_nterror(req
, status
);
373 tevent_req_done(req
);
376 NTSTATUS
cli_message_recv(struct tevent_req
*req
)
378 return tevent_req_simple_recv_ntstatus(req
);
381 NTSTATUS
cli_message(struct cli_state
*cli
, const char *host
,
382 const char *username
, const char *message
)
384 TALLOC_CTX
*frame
= talloc_stackframe();
385 struct event_context
*ev
;
386 struct tevent_req
*req
;
387 NTSTATUS status
= NT_STATUS_OK
;
389 if (cli_has_async_calls(cli
)) {
391 * Can't use sync call while an async call is in flight
393 status
= NT_STATUS_INVALID_PARAMETER
;
397 ev
= event_context_init(frame
);
399 status
= NT_STATUS_NO_MEMORY
;
403 req
= cli_message_send(frame
, ev
, cli
, host
, username
, message
);
405 status
= NT_STATUS_NO_MEMORY
;
409 if (!tevent_req_poll(req
, ev
)) {
410 status
= map_nt_error_from_unix(errno
);
414 status
= cli_message_recv(req
);