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"
25 struct cli_message_start_state {
29 static void cli_message_start_done(struct tevent_req *subreq);
31 static struct tevent_req *cli_message_start_send(TALLOC_CTX *mem_ctx,
32 struct tevent_context *ev,
33 struct cli_state *cli,
37 struct tevent_req *req, *subreq;
38 struct cli_message_start_state *state;
44 req = tevent_req_create(mem_ctx, &state,
45 struct cli_message_start_state);
50 if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
51 username, strlen(username)+1,
55 if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
61 bytes = talloc_array(state, uint8_t, ulen+hlen+2);
68 memcpy(p, utmp, ulen);
71 memcpy(p, htmp, hlen);
76 subreq = cli_smb_send(state, ev, cli, SMBsendstrt, 0, 0, NULL,
77 talloc_get_size(bytes), bytes);
78 if (tevent_req_nomem(subreq, req)) {
79 return tevent_req_post(req, ev);
81 tevent_req_set_callback(subreq, cli_message_start_done, req);
86 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
87 return tevent_req_post(req, ev);
90 static void cli_message_start_done(struct tevent_req *subreq)
92 struct tevent_req *req = tevent_req_callback_data(
93 subreq, struct tevent_req);
94 struct cli_message_start_state *state = tevent_req_data(
95 req, struct cli_message_start_state);
101 status = cli_smb_recv(subreq, state, &inbuf, 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 event_context *ev;
388 struct tevent_req *req;
389 NTSTATUS status = NT_STATUS_OK;
391 if (cli_has_async_calls(cli)) {
393 * Can't use sync call while an async call is in flight
395 status = NT_STATUS_INVALID_PARAMETER;
399 ev = event_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);