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/>.
22 struct cli_message_start_state
{
26 static void cli_message_start_done(struct tevent_req
*subreq
);
28 static struct tevent_req
*cli_message_start_send(TALLOC_CTX
*mem_ctx
,
29 struct tevent_context
*ev
,
30 struct cli_state
*cli
,
34 struct tevent_req
*req
, *subreq
;
35 struct cli_message_start_state
*state
;
41 req
= tevent_req_create(mem_ctx
, &state
,
42 struct cli_message_start_state
);
47 if (!convert_string_talloc(talloc_tos(), CH_UNIX
, CH_DOS
,
48 username
, strlen(username
)+1,
49 &utmp
, &ulen
, true)) {
52 if (!convert_string_talloc(talloc_tos(), CH_UNIX
, CH_DOS
,
54 &htmp
, &hlen
, true)) {
58 bytes
= talloc_array(state
, uint8_t, ulen
+hlen
+2);
65 memcpy(p
, utmp
, ulen
);
67 memcpy(p
, htmp
, hlen
);
71 subreq
= cli_smb_send(state
, ev
, cli
, SMBsendstrt
, 0, 0, NULL
,
72 talloc_get_size(bytes
), bytes
);
73 if (tevent_req_nomem(subreq
, req
)) {
74 return tevent_req_post(req
, ev
);
76 tevent_req_set_callback(subreq
, cli_message_start_done
, req
);
81 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
82 return tevent_req_post(req
, ev
);
85 static void cli_message_start_done(struct tevent_req
*subreq
)
87 struct tevent_req
*req
= tevent_req_callback_data(
88 subreq
, struct tevent_req
);
89 struct cli_message_start_state
*state
= tevent_req_data(
90 req
, struct cli_message_start_state
);
95 status
= cli_smb_recv(subreq
, 0, &wct
, &vwv
, NULL
, NULL
);
96 if (!NT_STATUS_IS_OK(status
)) {
98 tevent_req_nterror(req
, status
);
102 state
->grp
= SVAL(vwv
+0, 0);
107 tevent_req_done(req
);
110 static NTSTATUS
cli_message_start_recv(struct tevent_req
*req
,
113 struct cli_message_start_state
*state
= tevent_req_data(
114 req
, struct cli_message_start_state
);
117 if (tevent_req_is_nterror(req
, &status
)) {
124 struct cli_message_text_state
{
128 static void cli_message_text_done(struct tevent_req
*subreq
);
130 static struct tevent_req
*cli_message_text_send(TALLOC_CTX
*mem_ctx
,
131 struct tevent_context
*ev
,
132 struct cli_state
*cli
,
137 struct tevent_req
*req
, *subreq
;
138 struct cli_message_text_state
*state
;
143 req
= tevent_req_create(mem_ctx
, &state
,
144 struct cli_message_text_state
);
149 SSVAL(&state
->vwv
, 0, grp
);
151 if (convert_string_talloc(talloc_tos(), CH_UNIX
, CH_DOS
, msg
, msglen
,
152 &tmp
, &tmplen
, true)) {
156 DEBUG(3, ("Conversion failed, sending message in UNIX "
161 bytes
= talloc_array(state
, uint8_t, msglen
+3);
162 if (tevent_req_nomem(bytes
, req
)) {
164 return tevent_req_post(req
, ev
);
166 SCVAL(bytes
, 0, 0); /* pad */
167 SSVAL(bytes
, 1, msglen
);
168 memcpy(bytes
+3, msg
, msglen
);
171 subreq
= cli_smb_send(state
, ev
, cli
, SMBsendtxt
, 0, 1, &state
->vwv
,
172 talloc_get_size(bytes
), bytes
);
173 if (tevent_req_nomem(subreq
, req
)) {
174 return tevent_req_post(req
, ev
);
176 tevent_req_set_callback(subreq
, cli_message_text_done
, req
);
180 static void cli_message_text_done(struct tevent_req
*subreq
)
182 struct tevent_req
*req
= tevent_req_callback_data(
183 subreq
, struct tevent_req
);
186 status
= cli_smb_recv(subreq
, 0, NULL
, NULL
, NULL
, NULL
);
188 if (!NT_STATUS_IS_OK(status
)) {
189 tevent_req_nterror(req
, status
);
192 tevent_req_done(req
);
195 static NTSTATUS
cli_message_text_recv(struct tevent_req
*req
)
197 return tevent_req_simple_recv_ntstatus(req
);
200 struct cli_message_end_state
{
204 static void cli_message_end_done(struct tevent_req
*subreq
);
206 static struct tevent_req
*cli_message_end_send(TALLOC_CTX
*mem_ctx
,
207 struct tevent_context
*ev
,
208 struct cli_state
*cli
,
211 struct tevent_req
*req
, *subreq
;
212 struct cli_message_end_state
*state
;
214 req
= tevent_req_create(mem_ctx
, &state
,
215 struct cli_message_end_state
);
220 SSVAL(&state
->vwv
, 0, grp
);
222 subreq
= cli_smb_send(state
, ev
, cli
, SMBsendend
, 0, 1, &state
->vwv
,
224 if (tevent_req_nomem(subreq
, req
)) {
225 return tevent_req_post(req
, ev
);
227 tevent_req_set_callback(subreq
, cli_message_end_done
, req
);
231 static void cli_message_end_done(struct tevent_req
*subreq
)
233 struct tevent_req
*req
= tevent_req_callback_data(
234 subreq
, struct tevent_req
);
237 status
= cli_smb_recv(subreq
, 0, NULL
, NULL
, NULL
, NULL
);
239 if (!NT_STATUS_IS_OK(status
)) {
240 tevent_req_nterror(req
, status
);
243 tevent_req_done(req
);
246 static NTSTATUS
cli_message_end_recv(struct tevent_req
*req
)
248 return tevent_req_simple_recv_ntstatus(req
);
251 struct cli_message_state
{
252 struct tevent_context
*ev
;
253 struct cli_state
*cli
;
259 static void cli_message_started(struct tevent_req
*subreq
);
260 static void cli_message_sent(struct tevent_req
*subreq
);
261 static void cli_message_done(struct tevent_req
*subreq
);
263 struct tevent_req
*cli_message_send(TALLOC_CTX
*mem_ctx
,
264 struct tevent_context
*ev
,
265 struct cli_state
*cli
,
266 const char *host
, const char *username
,
269 struct tevent_req
*req
, *subreq
;
270 struct cli_message_state
*state
;
272 req
= tevent_req_create(mem_ctx
, &state
, struct cli_message_state
);
279 state
->message
= message
;
281 subreq
= cli_message_start_send(state
, ev
, cli
, host
, username
);
282 if (tevent_req_nomem(subreq
, req
)) {
283 return tevent_req_post(req
, ev
);
285 tevent_req_set_callback(subreq
, cli_message_started
, req
);
289 static void cli_message_started(struct tevent_req
*subreq
)
291 struct tevent_req
*req
= tevent_req_callback_data(
292 subreq
, struct tevent_req
);
293 struct cli_message_state
*state
= tevent_req_data(
294 req
, struct cli_message_state
);
298 status
= cli_message_start_recv(subreq
, &state
->grp
);
300 if (!NT_STATUS_IS_OK(status
)) {
301 tevent_req_nterror(req
, status
);
305 thistime
= MIN(127, strlen(state
->message
));
307 subreq
= cli_message_text_send(state
, state
->ev
, state
->cli
,
308 state
->grp
, state
->message
, thistime
);
309 if (tevent_req_nomem(subreq
, req
)) {
312 state
->sent
+= thistime
;
313 tevent_req_set_callback(subreq
, cli_message_sent
, req
);
316 static void cli_message_sent(struct tevent_req
*subreq
)
318 struct tevent_req
*req
= tevent_req_callback_data(
319 subreq
, struct tevent_req
);
320 struct cli_message_state
*state
= tevent_req_data(
321 req
, struct cli_message_state
);
323 size_t left
, thistime
;
325 status
= cli_message_text_recv(subreq
);
327 if (!NT_STATUS_IS_OK(status
)) {
328 tevent_req_nterror(req
, status
);
332 if (state
->sent
>= strlen(state
->message
)) {
333 subreq
= cli_message_end_send(state
, state
->ev
, state
->cli
,
335 if (tevent_req_nomem(subreq
, req
)) {
338 tevent_req_set_callback(subreq
, cli_message_done
, req
);
342 left
= strlen(state
->message
) - state
->sent
;
343 thistime
= MIN(127, left
);
345 subreq
= cli_message_text_send(state
, state
->ev
, state
->cli
,
347 state
->message
+ state
->sent
,
349 if (tevent_req_nomem(subreq
, req
)) {
352 state
->sent
+= thistime
;
353 tevent_req_set_callback(subreq
, cli_message_sent
, req
);
356 static void cli_message_done(struct tevent_req
*subreq
)
358 struct tevent_req
*req
= tevent_req_callback_data(
359 subreq
, struct tevent_req
);
362 status
= cli_message_end_recv(subreq
);
364 if (!NT_STATUS_IS_OK(status
)) {
365 tevent_req_nterror(req
, status
);
368 tevent_req_done(req
);
371 NTSTATUS
cli_message_recv(struct tevent_req
*req
)
373 return tevent_req_simple_recv_ntstatus(req
);
376 NTSTATUS
cli_message(struct cli_state
*cli
, const char *host
,
377 const char *username
, const char *message
)
379 TALLOC_CTX
*frame
= talloc_stackframe();
380 struct event_context
*ev
;
381 struct tevent_req
*req
;
382 NTSTATUS status
= NT_STATUS_OK
;
384 if (cli_has_async_calls(cli
)) {
386 * Can't use sync call while an async call is in flight
388 status
= NT_STATUS_INVALID_PARAMETER
;
392 ev
= event_context_init(frame
);
394 status
= NT_STATUS_NO_MEMORY
;
398 req
= cli_message_send(frame
, ev
, cli
, host
, username
, message
);
400 status
= NT_STATUS_NO_MEMORY
;
404 if (!tevent_req_poll(req
, ev
)) {
405 status
= map_nt_error_from_unix(errno
);
409 status
= cli_message_recv(req
);