s3: Paranoia in smbsock_connect_state_destructor
[Samba.git] / source3 / libsmb / climessage.c
blobc1542ee22ce443fb2adc936218140d22169bbda7
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 "../lib/util/tevent_ntstatus.h"
22 #include "async_smb.h"
24 struct cli_message_start_state {
25 uint16_t grp;
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,
33 const char *host,
34 const char *username)
36 struct tevent_req *req, *subreq;
37 struct cli_message_start_state *state;
38 char *htmp = NULL;
39 char *utmp = NULL;
40 size_t hlen, ulen;
41 uint8_t *bytes, *p;
43 req = tevent_req_create(mem_ctx, &state,
44 struct cli_message_start_state);
45 if (req == NULL) {
46 return NULL;
49 if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
50 username, strlen(username)+1,
51 &utmp, &ulen, true)) {
52 goto fail;
54 if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
55 host, strlen(host)+1,
56 &htmp, &hlen, true)) {
57 goto fail;
60 bytes = talloc_array(state, uint8_t, ulen+hlen+2);
61 if (bytes == NULL) {
62 goto fail;
64 p = bytes;
66 *p++ = 4;
67 memcpy(p, utmp, ulen);
68 p += ulen;
69 *p++ = 4;
70 memcpy(p, htmp, hlen);
71 p += hlen;
72 TALLOC_FREE(htmp);
73 TALLOC_FREE(utmp);
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);
81 return req;
82 fail:
83 TALLOC_FREE(htmp);
84 TALLOC_FREE(utmp);
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);
95 NTSTATUS status;
96 uint8_t wct;
97 uint16_t *vwv;
98 uint8_t *inbuf;
100 status = cli_smb_recv(subreq, state, &inbuf, 0, &wct, &vwv,
101 NULL, NULL);
102 TALLOC_FREE(subreq);
103 if (!NT_STATUS_IS_OK(status)) {
104 TALLOC_FREE(subreq);
105 tevent_req_nterror(req, status);
106 return;
108 if (wct >= 1) {
109 state->grp = SVAL(vwv+0, 0);
110 } else {
111 state->grp = 0;
113 tevent_req_done(req);
116 static NTSTATUS cli_message_start_recv(struct tevent_req *req,
117 uint16_t *pgrp)
119 struct cli_message_start_state *state = tevent_req_data(
120 req, struct cli_message_start_state);
121 NTSTATUS status;
123 if (tevent_req_is_nterror(req, &status)) {
124 return status;
126 *pgrp = state->grp;
127 return NT_STATUS_OK;
130 struct cli_message_text_state {
131 uint16_t vwv;
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,
139 uint16_t grp,
140 const char *msg,
141 int msglen)
143 struct tevent_req *req, *subreq;
144 struct cli_message_text_state *state;
145 char *tmp;
146 size_t tmplen;
147 uint8_t *bytes;
149 req = tevent_req_create(mem_ctx, &state,
150 struct cli_message_text_state);
151 if (req == NULL) {
152 return NULL;
155 SSVAL(&state->vwv, 0, grp);
157 if (convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS, msg, msglen,
158 &tmp, &tmplen, true)) {
159 msg = tmp;
160 msglen = tmplen;
161 } else {
162 DEBUG(3, ("Conversion failed, sending message in UNIX "
163 "charset\n"));
164 tmp = NULL;
167 bytes = talloc_array(state, uint8_t, msglen+3);
168 if (tevent_req_nomem(bytes, req)) {
169 TALLOC_FREE(tmp);
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);
175 TALLOC_FREE(tmp);
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);
183 return 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);
190 NTSTATUS status;
192 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
193 TALLOC_FREE(subreq);
194 if (!NT_STATUS_IS_OK(status)) {
195 tevent_req_nterror(req, status);
196 return;
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 {
207 uint16_t vwv;
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,
215 uint16_t grp)
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);
222 if (req == NULL) {
223 return NULL;
226 SSVAL(&state->vwv, 0, grp);
228 subreq = cli_smb_send(state, ev, cli, SMBsendend, 0, 1, &state->vwv,
229 0, NULL);
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);
234 return 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);
241 NTSTATUS status;
243 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
244 TALLOC_FREE(subreq);
245 if (!NT_STATUS_IS_OK(status)) {
246 tevent_req_nterror(req, status);
247 return;
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;
260 size_t sent;
261 const char *message;
262 uint16_t grp;
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,
273 const char *message)
275 struct tevent_req *req, *subreq;
276 struct cli_message_state *state;
278 req = tevent_req_create(mem_ctx, &state, struct cli_message_state);
279 if (req == NULL) {
280 return NULL;
282 state->ev = ev;
283 state->cli = cli;
284 state->sent = 0;
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);
292 return 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);
301 NTSTATUS status;
302 size_t thistime;
304 status = cli_message_start_recv(subreq, &state->grp);
305 TALLOC_FREE(subreq);
306 if (!NT_STATUS_IS_OK(status)) {
307 tevent_req_nterror(req, status);
308 return;
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)) {
316 return;
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);
328 NTSTATUS status;
329 size_t left, thistime;
331 status = cli_message_text_recv(subreq);
332 TALLOC_FREE(subreq);
333 if (!NT_STATUS_IS_OK(status)) {
334 tevent_req_nterror(req, status);
335 return;
338 if (state->sent >= strlen(state->message)) {
339 subreq = cli_message_end_send(state, state->ev, state->cli,
340 state->grp);
341 if (tevent_req_nomem(subreq, req)) {
342 return;
344 tevent_req_set_callback(subreq, cli_message_done, req);
345 return;
348 left = strlen(state->message) - state->sent;
349 thistime = MIN(127, left);
351 subreq = cli_message_text_send(state, state->ev, state->cli,
352 state->grp,
353 state->message + state->sent,
354 thistime);
355 if (tevent_req_nomem(subreq, req)) {
356 return;
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);
366 NTSTATUS status;
368 status = cli_message_end_recv(subreq);
369 TALLOC_FREE(subreq);
370 if (!NT_STATUS_IS_OK(status)) {
371 tevent_req_nterror(req, status);
372 return;
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;
395 goto fail;
398 ev = event_context_init(frame);
399 if (ev == NULL) {
400 status = NT_STATUS_NO_MEMORY;
401 goto fail;
404 req = cli_message_send(frame, ev, cli, host, username, message);
405 if (req == NULL) {
406 status = NT_STATUS_NO_MEMORY;
407 goto fail;
410 if (!tevent_req_poll(req, ev)) {
411 status = map_nt_error_from_unix(errno);
412 goto fail;
415 status = cli_message_recv(req);
416 fail:
417 TALLOC_FREE(frame);
418 return status;