ctdb-scripts: Move connection tracking to 10.interface
[samba4-gss.git] / source3 / libsmb / climessage.c
blob856361589f5098e5daad3b162ada91476a3ff78e
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"
23 #include "libsmb/libsmb.h"
24 #include "../libcli/smb/smbXcli_base.h"
26 struct cli_message_start_state {
27 uint16_t grp;
30 static void cli_message_start_done(struct tevent_req *subreq);
32 static struct tevent_req *cli_message_start_send(TALLOC_CTX *mem_ctx,
33 struct tevent_context *ev,
34 struct cli_state *cli,
35 const char *host,
36 const char *username)
38 struct tevent_req *req, *subreq;
39 struct cli_message_start_state *state;
40 char *htmp = NULL;
41 char *utmp = NULL;
42 size_t hlen, ulen;
43 uint8_t *bytes, *p;
45 req = tevent_req_create(mem_ctx, &state,
46 struct cli_message_start_state);
47 if (req == NULL) {
48 return NULL;
51 if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
52 username, strlen(username)+1,
53 &utmp, &ulen)) {
54 goto fail;
56 if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
57 host, strlen(host)+1,
58 &htmp, &hlen)) {
59 goto fail;
62 bytes = talloc_array(state, uint8_t, ulen+hlen+2);
63 if (bytes == NULL) {
64 goto fail;
66 p = bytes;
68 *p++ = 4;
69 memcpy(p, utmp, ulen);
70 p += ulen;
71 *p++ = 4;
72 memcpy(p, htmp, hlen);
73 TALLOC_FREE(htmp);
74 TALLOC_FREE(utmp);
76 subreq = cli_smb_send(state, ev, cli, SMBsendstrt, 0, 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);
82 return req;
83 fail:
84 TALLOC_FREE(htmp);
85 TALLOC_FREE(utmp);
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);
96 NTSTATUS status;
97 uint8_t wct;
98 uint16_t *vwv;
100 status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv,
101 NULL, NULL);
102 TALLOC_FREE(subreq);
103 if (tevent_req_nterror(req, status)) {
104 return;
106 if (wct >= 1) {
107 state->grp = SVAL(vwv+0, 0);
108 } else {
109 state->grp = 0;
111 tevent_req_done(req);
114 static NTSTATUS cli_message_start_recv(struct tevent_req *req,
115 uint16_t *pgrp)
117 struct cli_message_start_state *state = tevent_req_data(
118 req, struct cli_message_start_state);
119 NTSTATUS status;
121 if (tevent_req_is_nterror(req, &status)) {
122 return status;
124 *pgrp = state->grp;
125 return NT_STATUS_OK;
128 struct cli_message_text_state {
129 uint16_t vwv;
132 static void cli_message_text_done(struct tevent_req *subreq);
134 static struct tevent_req *cli_message_text_send(TALLOC_CTX *mem_ctx,
135 struct tevent_context *ev,
136 struct cli_state *cli,
137 uint16_t grp,
138 const char *msg,
139 int msglen)
141 struct tevent_req *req, *subreq;
142 struct cli_message_text_state *state;
143 char *tmp;
144 size_t tmplen;
145 uint8_t *bytes;
147 req = tevent_req_create(mem_ctx, &state,
148 struct cli_message_text_state);
149 if (req == NULL) {
150 return NULL;
153 SSVAL(&state->vwv, 0, grp);
155 if (convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS, msg, msglen,
156 &tmp, &tmplen)) {
157 msg = tmp;
158 msglen = tmplen;
159 } else {
160 DEBUG(3, ("Conversion failed, sending message in UNIX "
161 "charset\n"));
162 tmp = NULL;
165 bytes = talloc_array(state, uint8_t, msglen+3);
166 if (tevent_req_nomem(bytes, req)) {
167 TALLOC_FREE(tmp);
168 return tevent_req_post(req, ev);
170 SCVAL(bytes, 0, 1); /* pad */
171 SSVAL(bytes+1, 0, msglen);
172 memcpy(bytes+3, msg, msglen);
173 TALLOC_FREE(tmp);
175 subreq = cli_smb_send(state, ev, cli, SMBsendtxt, 0, 0, 1, &state->vwv,
176 talloc_get_size(bytes), bytes);
177 if (tevent_req_nomem(subreq, req)) {
178 return tevent_req_post(req, ev);
180 tevent_req_set_callback(subreq, cli_message_text_done, req);
181 return req;
184 static void cli_message_text_done(struct tevent_req *subreq)
186 struct tevent_req *req = tevent_req_callback_data(
187 subreq, struct tevent_req);
188 NTSTATUS status;
190 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
191 TALLOC_FREE(subreq);
192 if (tevent_req_nterror(req, status)) {
193 return;
195 tevent_req_done(req);
198 static NTSTATUS cli_message_text_recv(struct tevent_req *req)
200 return tevent_req_simple_recv_ntstatus(req);
203 struct cli_message_end_state {
204 uint16_t vwv;
207 static void cli_message_end_done(struct tevent_req *subreq);
209 static struct tevent_req *cli_message_end_send(TALLOC_CTX *mem_ctx,
210 struct tevent_context *ev,
211 struct cli_state *cli,
212 uint16_t grp)
214 struct tevent_req *req, *subreq;
215 struct cli_message_end_state *state;
217 req = tevent_req_create(mem_ctx, &state,
218 struct cli_message_end_state);
219 if (req == NULL) {
220 return NULL;
223 SSVAL(&state->vwv, 0, grp);
225 subreq = cli_smb_send(state, ev, cli, SMBsendend, 0, 0, 1, &state->vwv,
226 0, NULL);
227 if (tevent_req_nomem(subreq, req)) {
228 return tevent_req_post(req, ev);
230 tevent_req_set_callback(subreq, cli_message_end_done, req);
231 return req;
234 static void cli_message_end_done(struct tevent_req *subreq)
236 struct tevent_req *req = tevent_req_callback_data(
237 subreq, struct tevent_req);
238 NTSTATUS status;
240 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
241 TALLOC_FREE(subreq);
242 if (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 (tevent_req_nterror(req, status)) {
303 return;
306 thistime = MIN(127, strlen(state->message));
308 subreq = cli_message_text_send(state, state->ev, state->cli,
309 state->grp, state->message, thistime);
310 if (tevent_req_nomem(subreq, req)) {
311 return;
313 state->sent += thistime;
314 tevent_req_set_callback(subreq, cli_message_sent, req);
317 static void cli_message_sent(struct tevent_req *subreq)
319 struct tevent_req *req = tevent_req_callback_data(
320 subreq, struct tevent_req);
321 struct cli_message_state *state = tevent_req_data(
322 req, struct cli_message_state);
323 NTSTATUS status;
324 size_t left, thistime;
326 status = cli_message_text_recv(subreq);
327 TALLOC_FREE(subreq);
328 if (tevent_req_nterror(req, status)) {
329 return;
332 if (state->sent >= strlen(state->message)) {
333 subreq = cli_message_end_send(state, state->ev, state->cli,
334 state->grp);
335 if (tevent_req_nomem(subreq, req)) {
336 return;
338 tevent_req_set_callback(subreq, cli_message_done, req);
339 return;
342 left = strlen(state->message) - state->sent;
343 thistime = MIN(127, left);
345 subreq = cli_message_text_send(state, state->ev, state->cli,
346 state->grp,
347 state->message + state->sent,
348 thistime);
349 if (tevent_req_nomem(subreq, req)) {
350 return;
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);
360 NTSTATUS status;
362 status = cli_message_end_recv(subreq);
363 TALLOC_FREE(subreq);
364 if (tevent_req_nterror(req, status)) {
365 return;
367 tevent_req_done(req);
370 NTSTATUS cli_message_recv(struct tevent_req *req)
372 return tevent_req_simple_recv_ntstatus(req);
375 NTSTATUS cli_message(struct cli_state *cli, const char *host,
376 const char *username, const char *message)
378 TALLOC_CTX *frame = talloc_stackframe();
379 struct tevent_context *ev;
380 struct tevent_req *req;
381 NTSTATUS status = NT_STATUS_OK;
383 if (smbXcli_conn_has_async_calls(cli->conn)) {
385 * Can't use sync call while an async call is in flight
387 status = NT_STATUS_INVALID_PARAMETER;
388 goto fail;
391 ev = samba_tevent_context_init(frame);
392 if (ev == NULL) {
393 status = NT_STATUS_NO_MEMORY;
394 goto fail;
397 req = cli_message_send(frame, ev, cli, host, username, message);
398 if (req == NULL) {
399 status = NT_STATUS_NO_MEMORY;
400 goto fail;
403 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
404 goto fail;
407 status = cli_message_recv(req);
408 fail:
409 TALLOC_FREE(frame);
410 return status;