talloc: Bump version number after pytalloc changes.
[Samba.git] / source3 / libsmb / climessage.c
blob4c730c4b76e9127e1a13e504c0f45edaa40f38a9
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"
21 #include "async_smb.h"
23 struct cli_message_start_state {
24 uint16_t grp;
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,
32 const char *host,
33 const char *username)
35 struct tevent_req *req, *subreq;
36 struct cli_message_start_state *state;
37 char *htmp = NULL;
38 char *utmp = NULL;
39 size_t hlen, ulen;
40 uint8_t *bytes, *p;
42 req = tevent_req_create(mem_ctx, &state,
43 struct cli_message_start_state);
44 if (req == NULL) {
45 return NULL;
48 if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
49 username, strlen(username)+1,
50 &utmp, &ulen, true)) {
51 goto fail;
53 if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
54 host, strlen(host)+1,
55 &htmp, &hlen, true)) {
56 goto fail;
59 bytes = talloc_array(state, uint8_t, ulen+hlen+2);
60 if (bytes == NULL) {
61 goto fail;
63 p = bytes;
65 *p++ = 4;
66 memcpy(p, utmp, ulen);
67 p += ulen;
68 *p++ = 4;
69 memcpy(p, htmp, hlen);
70 p += hlen;
71 TALLOC_FREE(htmp);
72 TALLOC_FREE(utmp);
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);
80 return req;
81 fail:
82 TALLOC_FREE(htmp);
83 TALLOC_FREE(utmp);
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);
94 NTSTATUS status;
95 uint8_t wct;
96 uint16_t *vwv;
97 uint8_t *inbuf;
99 status = cli_smb_recv(subreq, state, &inbuf, 0, &wct, &vwv,
100 NULL, NULL);
101 TALLOC_FREE(subreq);
102 if (!NT_STATUS_IS_OK(status)) {
103 TALLOC_FREE(subreq);
104 tevent_req_nterror(req, status);
105 return;
107 if (wct >= 1) {
108 state->grp = SVAL(vwv+0, 0);
109 } else {
110 state->grp = 0;
112 tevent_req_done(req);
115 static NTSTATUS cli_message_start_recv(struct tevent_req *req,
116 uint16_t *pgrp)
118 struct cli_message_start_state *state = tevent_req_data(
119 req, struct cli_message_start_state);
120 NTSTATUS status;
122 if (tevent_req_is_nterror(req, &status)) {
123 return status;
125 *pgrp = state->grp;
126 return NT_STATUS_OK;
129 struct cli_message_text_state {
130 uint16_t vwv;
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,
138 uint16_t grp,
139 const char *msg,
140 int msglen)
142 struct tevent_req *req, *subreq;
143 struct cli_message_text_state *state;
144 char *tmp;
145 size_t tmplen;
146 uint8_t *bytes;
148 req = tevent_req_create(mem_ctx, &state,
149 struct cli_message_text_state);
150 if (req == NULL) {
151 return NULL;
154 SSVAL(&state->vwv, 0, grp);
156 if (convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS, msg, msglen,
157 &tmp, &tmplen, true)) {
158 msg = tmp;
159 msglen = tmplen;
160 } else {
161 DEBUG(3, ("Conversion failed, sending message in UNIX "
162 "charset\n"));
163 tmp = NULL;
166 bytes = talloc_array(state, uint8_t, msglen+3);
167 if (tevent_req_nomem(bytes, req)) {
168 TALLOC_FREE(tmp);
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);
174 TALLOC_FREE(tmp);
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);
182 return 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);
189 NTSTATUS status;
191 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
192 TALLOC_FREE(subreq);
193 if (!NT_STATUS_IS_OK(status)) {
194 tevent_req_nterror(req, status);
195 return;
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 {
206 uint16_t vwv;
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,
214 uint16_t grp)
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);
221 if (req == NULL) {
222 return NULL;
225 SSVAL(&state->vwv, 0, grp);
227 subreq = cli_smb_send(state, ev, cli, SMBsendend, 0, 1, &state->vwv,
228 0, NULL);
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);
233 return 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);
240 NTSTATUS status;
242 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
243 TALLOC_FREE(subreq);
244 if (!NT_STATUS_IS_OK(status)) {
245 tevent_req_nterror(req, status);
246 return;
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;
259 size_t sent;
260 const char *message;
261 uint16_t grp;
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,
272 const char *message)
274 struct tevent_req *req, *subreq;
275 struct cli_message_state *state;
277 req = tevent_req_create(mem_ctx, &state, struct cli_message_state);
278 if (req == NULL) {
279 return NULL;
281 state->ev = ev;
282 state->cli = cli;
283 state->sent = 0;
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);
291 return 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);
300 NTSTATUS status;
301 size_t thistime;
303 status = cli_message_start_recv(subreq, &state->grp);
304 TALLOC_FREE(subreq);
305 if (!NT_STATUS_IS_OK(status)) {
306 tevent_req_nterror(req, status);
307 return;
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)) {
315 return;
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);
327 NTSTATUS status;
328 size_t left, thistime;
330 status = cli_message_text_recv(subreq);
331 TALLOC_FREE(subreq);
332 if (!NT_STATUS_IS_OK(status)) {
333 tevent_req_nterror(req, status);
334 return;
337 if (state->sent >= strlen(state->message)) {
338 subreq = cli_message_end_send(state, state->ev, state->cli,
339 state->grp);
340 if (tevent_req_nomem(subreq, req)) {
341 return;
343 tevent_req_set_callback(subreq, cli_message_done, req);
344 return;
347 left = strlen(state->message) - state->sent;
348 thistime = MIN(127, left);
350 subreq = cli_message_text_send(state, state->ev, state->cli,
351 state->grp,
352 state->message + state->sent,
353 thistime);
354 if (tevent_req_nomem(subreq, req)) {
355 return;
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);
365 NTSTATUS status;
367 status = cli_message_end_recv(subreq);
368 TALLOC_FREE(subreq);
369 if (!NT_STATUS_IS_OK(status)) {
370 tevent_req_nterror(req, status);
371 return;
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;
394 goto fail;
397 ev = event_context_init(frame);
398 if (ev == NULL) {
399 status = NT_STATUS_NO_MEMORY;
400 goto fail;
403 req = cli_message_send(frame, ev, cli, host, username, message);
404 if (req == NULL) {
405 status = NT_STATUS_NO_MEMORY;
406 goto fail;
409 if (!tevent_req_poll(req, ev)) {
410 status = map_nt_error_from_unix(errno);
411 goto fail;
414 status = cli_message_recv(req);
415 fail:
416 TALLOC_FREE(frame);
417 return status;