selftest: Fix typo in comment.
[Samba.git] / source3 / libsmb / climessage.c
blobbdf2977af9c4cff744d397b402dec5bcbe7ca7fb
1 /*
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/>.
20 #include "includes.h"
22 struct cli_message_start_state {
23 uint16_t grp;
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,
31 const char *host,
32 const char *username)
34 struct tevent_req *req, *subreq;
35 struct cli_message_start_state *state;
36 char *htmp = NULL;
37 char *utmp = NULL;
38 size_t hlen, ulen;
39 uint8_t *bytes, *p;
41 req = tevent_req_create(mem_ctx, &state,
42 struct cli_message_start_state);
43 if (req == NULL) {
44 return NULL;
47 if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
48 username, strlen(username)+1,
49 &utmp, &ulen, true)) {
50 goto fail;
52 if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
53 host, strlen(host)+1,
54 &htmp, &hlen, true)) {
55 goto fail;
58 bytes = talloc_array(state, uint8_t, ulen+hlen+2);
59 if (bytes == NULL) {
60 goto fail;
62 p = bytes;
64 *p++ = 4;
65 memcpy(p, utmp, ulen);
66 *p++ = 4;
67 memcpy(p, htmp, hlen);
68 TALLOC_FREE(htmp);
69 TALLOC_FREE(utmp);
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);
77 return req;
78 fail:
79 TALLOC_FREE(htmp);
80 TALLOC_FREE(utmp);
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);
91 NTSTATUS status;
92 uint8_t wct;
93 uint16_t *vwv;
94 uint8_t *inbuf;
96 status = cli_smb_recv(subreq, state, &inbuf, 0, &wct, &vwv,
97 NULL, NULL);
98 TALLOC_FREE(subreq);
99 if (!NT_STATUS_IS_OK(status)) {
100 TALLOC_FREE(subreq);
101 tevent_req_nterror(req, status);
102 return;
104 if (wct >= 1) {
105 state->grp = SVAL(vwv+0, 0);
106 } else {
107 state->grp = 0;
109 tevent_req_done(req);
112 static NTSTATUS cli_message_start_recv(struct tevent_req *req,
113 uint16_t *pgrp)
115 struct cli_message_start_state *state = tevent_req_data(
116 req, struct cli_message_start_state);
117 NTSTATUS status;
119 if (tevent_req_is_nterror(req, &status)) {
120 return status;
122 *pgrp = state->grp;
123 return NT_STATUS_OK;
126 struct cli_message_text_state {
127 uint16_t vwv;
130 static void cli_message_text_done(struct tevent_req *subreq);
132 static struct tevent_req *cli_message_text_send(TALLOC_CTX *mem_ctx,
133 struct tevent_context *ev,
134 struct cli_state *cli,
135 uint16_t grp,
136 const char *msg,
137 int msglen)
139 struct tevent_req *req, *subreq;
140 struct cli_message_text_state *state;
141 char *tmp;
142 size_t tmplen;
143 uint8_t *bytes;
145 req = tevent_req_create(mem_ctx, &state,
146 struct cli_message_text_state);
147 if (req == NULL) {
148 return NULL;
151 SSVAL(&state->vwv, 0, grp);
153 if (convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS, msg, msglen,
154 &tmp, &tmplen, true)) {
155 msg = tmp;
156 msglen = tmplen;
157 } else {
158 DEBUG(3, ("Conversion failed, sending message in UNIX "
159 "charset\n"));
160 tmp = NULL;
163 bytes = talloc_array(state, uint8_t, msglen+3);
164 if (tevent_req_nomem(bytes, req)) {
165 TALLOC_FREE(tmp);
166 return tevent_req_post(req, ev);
168 SCVAL(bytes, 0, 0); /* pad */
169 SSVAL(bytes, 1, msglen);
170 memcpy(bytes+3, msg, msglen);
171 TALLOC_FREE(tmp);
173 subreq = cli_smb_send(state, ev, cli, SMBsendtxt, 0, 1, &state->vwv,
174 talloc_get_size(bytes), bytes);
175 if (tevent_req_nomem(subreq, req)) {
176 return tevent_req_post(req, ev);
178 tevent_req_set_callback(subreq, cli_message_text_done, req);
179 return req;
182 static void cli_message_text_done(struct tevent_req *subreq)
184 struct tevent_req *req = tevent_req_callback_data(
185 subreq, struct tevent_req);
186 NTSTATUS status;
188 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
189 TALLOC_FREE(subreq);
190 if (!NT_STATUS_IS_OK(status)) {
191 tevent_req_nterror(req, status);
192 return;
194 tevent_req_done(req);
197 static NTSTATUS cli_message_text_recv(struct tevent_req *req)
199 return tevent_req_simple_recv_ntstatus(req);
202 struct cli_message_end_state {
203 uint16_t vwv;
206 static void cli_message_end_done(struct tevent_req *subreq);
208 static struct tevent_req *cli_message_end_send(TALLOC_CTX *mem_ctx,
209 struct tevent_context *ev,
210 struct cli_state *cli,
211 uint16_t grp)
213 struct tevent_req *req, *subreq;
214 struct cli_message_end_state *state;
216 req = tevent_req_create(mem_ctx, &state,
217 struct cli_message_end_state);
218 if (req == NULL) {
219 return NULL;
222 SSVAL(&state->vwv, 0, grp);
224 subreq = cli_smb_send(state, ev, cli, SMBsendend, 0, 1, &state->vwv,
225 0, NULL);
226 if (tevent_req_nomem(subreq, req)) {
227 return tevent_req_post(req, ev);
229 tevent_req_set_callback(subreq, cli_message_end_done, req);
230 return req;
233 static void cli_message_end_done(struct tevent_req *subreq)
235 struct tevent_req *req = tevent_req_callback_data(
236 subreq, struct tevent_req);
237 NTSTATUS status;
239 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
240 TALLOC_FREE(subreq);
241 if (!NT_STATUS_IS_OK(status)) {
242 tevent_req_nterror(req, status);
243 return;
245 tevent_req_done(req);
248 static NTSTATUS cli_message_end_recv(struct tevent_req *req)
250 return tevent_req_simple_recv_ntstatus(req);
253 struct cli_message_state {
254 struct tevent_context *ev;
255 struct cli_state *cli;
256 size_t sent;
257 const char *message;
258 uint16_t grp;
261 static void cli_message_started(struct tevent_req *subreq);
262 static void cli_message_sent(struct tevent_req *subreq);
263 static void cli_message_done(struct tevent_req *subreq);
265 struct tevent_req *cli_message_send(TALLOC_CTX *mem_ctx,
266 struct tevent_context *ev,
267 struct cli_state *cli,
268 const char *host, const char *username,
269 const char *message)
271 struct tevent_req *req, *subreq;
272 struct cli_message_state *state;
274 req = tevent_req_create(mem_ctx, &state, struct cli_message_state);
275 if (req == NULL) {
276 return NULL;
278 state->ev = ev;
279 state->cli = cli;
280 state->sent = 0;
281 state->message = message;
283 subreq = cli_message_start_send(state, ev, cli, host, username);
284 if (tevent_req_nomem(subreq, req)) {
285 return tevent_req_post(req, ev);
287 tevent_req_set_callback(subreq, cli_message_started, req);
288 return req;
291 static void cli_message_started(struct tevent_req *subreq)
293 struct tevent_req *req = tevent_req_callback_data(
294 subreq, struct tevent_req);
295 struct cli_message_state *state = tevent_req_data(
296 req, struct cli_message_state);
297 NTSTATUS status;
298 size_t thistime;
300 status = cli_message_start_recv(subreq, &state->grp);
301 TALLOC_FREE(subreq);
302 if (!NT_STATUS_IS_OK(status)) {
303 tevent_req_nterror(req, status);
304 return;
307 thistime = MIN(127, strlen(state->message));
309 subreq = cli_message_text_send(state, state->ev, state->cli,
310 state->grp, state->message, thistime);
311 if (tevent_req_nomem(subreq, req)) {
312 return;
314 state->sent += thistime;
315 tevent_req_set_callback(subreq, cli_message_sent, req);
318 static void cli_message_sent(struct tevent_req *subreq)
320 struct tevent_req *req = tevent_req_callback_data(
321 subreq, struct tevent_req);
322 struct cli_message_state *state = tevent_req_data(
323 req, struct cli_message_state);
324 NTSTATUS status;
325 size_t left, thistime;
327 status = cli_message_text_recv(subreq);
328 TALLOC_FREE(subreq);
329 if (!NT_STATUS_IS_OK(status)) {
330 tevent_req_nterror(req, status);
331 return;
334 if (state->sent >= strlen(state->message)) {
335 subreq = cli_message_end_send(state, state->ev, state->cli,
336 state->grp);
337 if (tevent_req_nomem(subreq, req)) {
338 return;
340 tevent_req_set_callback(subreq, cli_message_done, req);
341 return;
344 left = strlen(state->message) - state->sent;
345 thistime = MIN(127, left);
347 subreq = cli_message_text_send(state, state->ev, state->cli,
348 state->grp,
349 state->message + state->sent,
350 thistime);
351 if (tevent_req_nomem(subreq, req)) {
352 return;
354 state->sent += thistime;
355 tevent_req_set_callback(subreq, cli_message_sent, req);
358 static void cli_message_done(struct tevent_req *subreq)
360 struct tevent_req *req = tevent_req_callback_data(
361 subreq, struct tevent_req);
362 NTSTATUS status;
364 status = cli_message_end_recv(subreq);
365 TALLOC_FREE(subreq);
366 if (!NT_STATUS_IS_OK(status)) {
367 tevent_req_nterror(req, status);
368 return;
370 tevent_req_done(req);
373 NTSTATUS cli_message_recv(struct tevent_req *req)
375 return tevent_req_simple_recv_ntstatus(req);
378 NTSTATUS cli_message(struct cli_state *cli, const char *host,
379 const char *username, const char *message)
381 TALLOC_CTX *frame = talloc_stackframe();
382 struct event_context *ev;
383 struct tevent_req *req;
384 NTSTATUS status = NT_STATUS_OK;
386 if (cli_has_async_calls(cli)) {
388 * Can't use sync call while an async call is in flight
390 status = NT_STATUS_INVALID_PARAMETER;
391 goto fail;
394 ev = event_context_init(frame);
395 if (ev == NULL) {
396 status = NT_STATUS_NO_MEMORY;
397 goto fail;
400 req = cli_message_send(frame, ev, cli, host, username, message);
401 if (req == NULL) {
402 status = NT_STATUS_NO_MEMORY;
403 goto fail;
406 if (!tevent_req_poll(req, ev)) {
407 status = map_nt_error_from_unix(errno);
408 goto fail;
411 status = cli_message_recv(req);
412 fail:
413 TALLOC_FREE(frame);
414 return status;