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"
24 struct cli_message_start_state
{
28 static void cli_message_start_done(struct tevent_req
*subreq
);
30 static struct tevent_req
*cli_message_start_send(TALLOC_CTX
*mem_ctx
,
31 struct tevent_context
*ev
,
32 struct cli_state
*cli
,
36 struct tevent_req
*req
, *subreq
;
37 struct cli_message_start_state
*state
;
43 req
= tevent_req_create(mem_ctx
, &state
,
44 struct cli_message_start_state
);
49 if (!convert_string_talloc(talloc_tos(), CH_UNIX
, CH_DOS
,
50 username
, strlen(username
)+1,
51 &utmp
, &ulen
, true)) {
54 if (!convert_string_talloc(talloc_tos(), CH_UNIX
, CH_DOS
,
56 &htmp
, &hlen
, true)) {
60 bytes
= talloc_array(state
, uint8_t, ulen
+hlen
+2);
67 memcpy(p
, utmp
, ulen
);
70 memcpy(p
, htmp
, hlen
);
75 subreq
= cli_smb_send(state
, ev
, cli
, SMBsendstrt
, 0, 0, NULL
,
76 talloc_get_size(bytes
), bytes
);
77 if (tevent_req_nomem(subreq
, req
)) {
78 return tevent_req_post(req
, ev
);
80 tevent_req_set_callback(subreq
, cli_message_start_done
, req
);
85 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
86 return tevent_req_post(req
, ev
);
89 static void cli_message_start_done(struct tevent_req
*subreq
)
91 struct tevent_req
*req
= tevent_req_callback_data(
92 subreq
, struct tevent_req
);
93 struct cli_message_start_state
*state
= tevent_req_data(
94 req
, struct cli_message_start_state
);
100 status
= cli_smb_recv(subreq
, state
, &inbuf
, 0, &wct
, &vwv
,
103 if (!NT_STATUS_IS_OK(status
)) {
105 tevent_req_nterror(req
, status
);
109 state
->grp
= SVAL(vwv
+0, 0);
113 tevent_req_done(req
);
116 static NTSTATUS
cli_message_start_recv(struct tevent_req
*req
,
119 struct cli_message_start_state
*state
= tevent_req_data(
120 req
, struct cli_message_start_state
);
123 if (tevent_req_is_nterror(req
, &status
)) {
130 struct cli_message_text_state
{
134 static void cli_message_text_done(struct tevent_req
*subreq
);
136 static struct tevent_req
*cli_message_text_send(TALLOC_CTX
*mem_ctx
,
137 struct tevent_context
*ev
,
138 struct cli_state
*cli
,
143 struct tevent_req
*req
, *subreq
;
144 struct cli_message_text_state
*state
;
149 req
= tevent_req_create(mem_ctx
, &state
,
150 struct cli_message_text_state
);
155 SSVAL(&state
->vwv
, 0, grp
);
157 if (convert_string_talloc(talloc_tos(), CH_UNIX
, CH_DOS
, msg
, msglen
,
158 &tmp
, &tmplen
, true)) {
162 DEBUG(3, ("Conversion failed, sending message in UNIX "
167 bytes
= talloc_array(state
, uint8_t, msglen
+3);
168 if (tevent_req_nomem(bytes
, req
)) {
170 return tevent_req_post(req
, ev
);
172 SCVAL(bytes
, 0, 1); /* pad */
173 SSVAL(bytes
+1, 0, msglen
);
174 memcpy(bytes
+3, msg
, msglen
);
177 subreq
= cli_smb_send(state
, ev
, cli
, SMBsendtxt
, 0, 1, &state
->vwv
,
178 talloc_get_size(bytes
), bytes
);
179 if (tevent_req_nomem(subreq
, req
)) {
180 return tevent_req_post(req
, ev
);
182 tevent_req_set_callback(subreq
, cli_message_text_done
, req
);
186 static void cli_message_text_done(struct tevent_req
*subreq
)
188 struct tevent_req
*req
= tevent_req_callback_data(
189 subreq
, struct tevent_req
);
192 status
= cli_smb_recv(subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
194 if (!NT_STATUS_IS_OK(status
)) {
195 tevent_req_nterror(req
, status
);
198 tevent_req_done(req
);
201 static NTSTATUS
cli_message_text_recv(struct tevent_req
*req
)
203 return tevent_req_simple_recv_ntstatus(req
);
206 struct cli_message_end_state
{
210 static void cli_message_end_done(struct tevent_req
*subreq
);
212 static struct tevent_req
*cli_message_end_send(TALLOC_CTX
*mem_ctx
,
213 struct tevent_context
*ev
,
214 struct cli_state
*cli
,
217 struct tevent_req
*req
, *subreq
;
218 struct cli_message_end_state
*state
;
220 req
= tevent_req_create(mem_ctx
, &state
,
221 struct cli_message_end_state
);
226 SSVAL(&state
->vwv
, 0, grp
);
228 subreq
= cli_smb_send(state
, ev
, cli
, SMBsendend
, 0, 1, &state
->vwv
,
230 if (tevent_req_nomem(subreq
, req
)) {
231 return tevent_req_post(req
, ev
);
233 tevent_req_set_callback(subreq
, cli_message_end_done
, req
);
237 static void cli_message_end_done(struct tevent_req
*subreq
)
239 struct tevent_req
*req
= tevent_req_callback_data(
240 subreq
, struct tevent_req
);
243 status
= cli_smb_recv(subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
245 if (!NT_STATUS_IS_OK(status
)) {
246 tevent_req_nterror(req
, status
);
249 tevent_req_done(req
);
252 static NTSTATUS
cli_message_end_recv(struct tevent_req
*req
)
254 return tevent_req_simple_recv_ntstatus(req
);
257 struct cli_message_state
{
258 struct tevent_context
*ev
;
259 struct cli_state
*cli
;
265 static void cli_message_started(struct tevent_req
*subreq
);
266 static void cli_message_sent(struct tevent_req
*subreq
);
267 static void cli_message_done(struct tevent_req
*subreq
);
269 struct tevent_req
*cli_message_send(TALLOC_CTX
*mem_ctx
,
270 struct tevent_context
*ev
,
271 struct cli_state
*cli
,
272 const char *host
, const char *username
,
275 struct tevent_req
*req
, *subreq
;
276 struct cli_message_state
*state
;
278 req
= tevent_req_create(mem_ctx
, &state
, struct cli_message_state
);
285 state
->message
= message
;
287 subreq
= cli_message_start_send(state
, ev
, cli
, host
, username
);
288 if (tevent_req_nomem(subreq
, req
)) {
289 return tevent_req_post(req
, ev
);
291 tevent_req_set_callback(subreq
, cli_message_started
, req
);
295 static void cli_message_started(struct tevent_req
*subreq
)
297 struct tevent_req
*req
= tevent_req_callback_data(
298 subreq
, struct tevent_req
);
299 struct cli_message_state
*state
= tevent_req_data(
300 req
, struct cli_message_state
);
304 status
= cli_message_start_recv(subreq
, &state
->grp
);
306 if (!NT_STATUS_IS_OK(status
)) {
307 tevent_req_nterror(req
, status
);
311 thistime
= MIN(127, strlen(state
->message
));
313 subreq
= cli_message_text_send(state
, state
->ev
, state
->cli
,
314 state
->grp
, state
->message
, thistime
);
315 if (tevent_req_nomem(subreq
, req
)) {
318 state
->sent
+= thistime
;
319 tevent_req_set_callback(subreq
, cli_message_sent
, req
);
322 static void cli_message_sent(struct tevent_req
*subreq
)
324 struct tevent_req
*req
= tevent_req_callback_data(
325 subreq
, struct tevent_req
);
326 struct cli_message_state
*state
= tevent_req_data(
327 req
, struct cli_message_state
);
329 size_t left
, thistime
;
331 status
= cli_message_text_recv(subreq
);
333 if (!NT_STATUS_IS_OK(status
)) {
334 tevent_req_nterror(req
, status
);
338 if (state
->sent
>= strlen(state
->message
)) {
339 subreq
= cli_message_end_send(state
, state
->ev
, state
->cli
,
341 if (tevent_req_nomem(subreq
, req
)) {
344 tevent_req_set_callback(subreq
, cli_message_done
, req
);
348 left
= strlen(state
->message
) - state
->sent
;
349 thistime
= MIN(127, left
);
351 subreq
= cli_message_text_send(state
, state
->ev
, state
->cli
,
353 state
->message
+ state
->sent
,
355 if (tevent_req_nomem(subreq
, req
)) {
358 state
->sent
+= thistime
;
359 tevent_req_set_callback(subreq
, cli_message_sent
, req
);
362 static void cli_message_done(struct tevent_req
*subreq
)
364 struct tevent_req
*req
= tevent_req_callback_data(
365 subreq
, struct tevent_req
);
368 status
= cli_message_end_recv(subreq
);
370 if (!NT_STATUS_IS_OK(status
)) {
371 tevent_req_nterror(req
, status
);
374 tevent_req_done(req
);
377 NTSTATUS
cli_message_recv(struct tevent_req
*req
)
379 return tevent_req_simple_recv_ntstatus(req
);
382 NTSTATUS
cli_message(struct cli_state
*cli
, const char *host
,
383 const char *username
, const char *message
)
385 TALLOC_CTX
*frame
= talloc_stackframe();
386 struct event_context
*ev
;
387 struct tevent_req
*req
;
388 NTSTATUS status
= NT_STATUS_OK
;
390 if (cli_has_async_calls(cli
)) {
392 * Can't use sync call while an async call is in flight
394 status
= NT_STATUS_INVALID_PARAMETER
;
398 ev
= event_context_init(frame
);
400 status
= NT_STATUS_NO_MEMORY
;
404 req
= cli_message_send(frame
, ev
, cli
, host
, username
, message
);
406 status
= NT_STATUS_NO_MEMORY
;
410 if (!tevent_req_poll(req
, ev
)) {
411 status
= map_nt_error_from_unix(errno
);
415 status
= cli_message_recv(req
);