Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : client message handling routines
4 : Copyright (C) Andrew Tridgell 1994-1998
5 :
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.
10 :
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.
15 :
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/>.
18 : */
19 :
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"
25 :
26 : struct cli_message_start_state {
27 : uint16_t grp;
28 : };
29 :
30 : static void cli_message_start_done(struct tevent_req *subreq);
31 :
32 8 : 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)
37 : {
38 : struct tevent_req *req, *subreq;
39 : struct cli_message_start_state *state;
40 8 : char *htmp = NULL;
41 8 : char *utmp = NULL;
42 : size_t hlen, ulen;
43 : uint8_t *bytes, *p;
44 :
45 8 : req = tevent_req_create(mem_ctx, &state,
46 : struct cli_message_start_state);
47 8 : if (req == NULL) {
48 0 : return NULL;
49 : }
50 :
51 8 : if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
52 8 : username, strlen(username)+1,
53 : &utmp, &ulen)) {
54 0 : goto fail;
55 : }
56 8 : if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
57 8 : host, strlen(host)+1,
58 : &htmp, &hlen)) {
59 0 : goto fail;
60 : }
61 :
62 8 : bytes = talloc_array(state, uint8_t, ulen+hlen+2);
63 8 : if (bytes == NULL) {
64 0 : goto fail;
65 : }
66 8 : p = bytes;
67 :
68 8 : *p++ = 4;
69 8 : memcpy(p, utmp, ulen);
70 8 : p += ulen;
71 8 : *p++ = 4;
72 8 : memcpy(p, htmp, hlen);
73 8 : TALLOC_FREE(htmp);
74 8 : TALLOC_FREE(utmp);
75 :
76 8 : subreq = cli_smb_send(state, ev, cli, SMBsendstrt, 0, 0, 0, NULL,
77 8 : talloc_get_size(bytes), bytes);
78 8 : if (tevent_req_nomem(subreq, req)) {
79 0 : return tevent_req_post(req, ev);
80 : }
81 8 : tevent_req_set_callback(subreq, cli_message_start_done, req);
82 8 : return req;
83 0 : fail:
84 0 : TALLOC_FREE(htmp);
85 0 : TALLOC_FREE(utmp);
86 0 : tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
87 0 : return tevent_req_post(req, ev);
88 : }
89 :
90 8 : static void cli_message_start_done(struct tevent_req *subreq)
91 : {
92 8 : struct tevent_req *req = tevent_req_callback_data(
93 : subreq, struct tevent_req);
94 8 : 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;
99 :
100 8 : status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv,
101 : NULL, NULL);
102 8 : TALLOC_FREE(subreq);
103 8 : if (!NT_STATUS_IS_OK(status)) {
104 8 : TALLOC_FREE(subreq);
105 8 : tevent_req_nterror(req, status);
106 8 : return;
107 : }
108 0 : if (wct >= 1) {
109 0 : state->grp = SVAL(vwv+0, 0);
110 : } else {
111 0 : state->grp = 0;
112 : }
113 0 : tevent_req_done(req);
114 : }
115 :
116 8 : static NTSTATUS cli_message_start_recv(struct tevent_req *req,
117 : uint16_t *pgrp)
118 : {
119 8 : struct cli_message_start_state *state = tevent_req_data(
120 : req, struct cli_message_start_state);
121 : NTSTATUS status;
122 :
123 8 : if (tevent_req_is_nterror(req, &status)) {
124 8 : return status;
125 : }
126 0 : *pgrp = state->grp;
127 0 : return NT_STATUS_OK;
128 : }
129 :
130 : struct cli_message_text_state {
131 : uint16_t vwv;
132 : };
133 :
134 : static void cli_message_text_done(struct tevent_req *subreq);
135 :
136 0 : 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)
142 : {
143 : struct tevent_req *req, *subreq;
144 : struct cli_message_text_state *state;
145 : char *tmp;
146 : size_t tmplen;
147 : uint8_t *bytes;
148 :
149 0 : req = tevent_req_create(mem_ctx, &state,
150 : struct cli_message_text_state);
151 0 : if (req == NULL) {
152 0 : return NULL;
153 : }
154 :
155 0 : SSVAL(&state->vwv, 0, grp);
156 :
157 0 : if (convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS, msg, msglen,
158 : &tmp, &tmplen)) {
159 0 : msg = tmp;
160 0 : msglen = tmplen;
161 : } else {
162 0 : DEBUG(3, ("Conversion failed, sending message in UNIX "
163 : "charset\n"));
164 0 : tmp = NULL;
165 : }
166 :
167 0 : bytes = talloc_array(state, uint8_t, msglen+3);
168 0 : if (tevent_req_nomem(bytes, req)) {
169 0 : TALLOC_FREE(tmp);
170 0 : return tevent_req_post(req, ev);
171 : }
172 0 : SCVAL(bytes, 0, 1); /* pad */
173 0 : SSVAL(bytes+1, 0, msglen);
174 0 : memcpy(bytes+3, msg, msglen);
175 0 : TALLOC_FREE(tmp);
176 :
177 0 : subreq = cli_smb_send(state, ev, cli, SMBsendtxt, 0, 0, 1, &state->vwv,
178 0 : talloc_get_size(bytes), bytes);
179 0 : if (tevent_req_nomem(subreq, req)) {
180 0 : return tevent_req_post(req, ev);
181 : }
182 0 : tevent_req_set_callback(subreq, cli_message_text_done, req);
183 0 : return req;
184 : }
185 :
186 0 : static void cli_message_text_done(struct tevent_req *subreq)
187 : {
188 0 : struct tevent_req *req = tevent_req_callback_data(
189 : subreq, struct tevent_req);
190 : NTSTATUS status;
191 :
192 0 : status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
193 0 : TALLOC_FREE(subreq);
194 0 : if (!NT_STATUS_IS_OK(status)) {
195 0 : tevent_req_nterror(req, status);
196 0 : return;
197 : }
198 0 : tevent_req_done(req);
199 : }
200 :
201 0 : static NTSTATUS cli_message_text_recv(struct tevent_req *req)
202 : {
203 0 : return tevent_req_simple_recv_ntstatus(req);
204 : }
205 :
206 : struct cli_message_end_state {
207 : uint16_t vwv;
208 : };
209 :
210 : static void cli_message_end_done(struct tevent_req *subreq);
211 :
212 0 : 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)
216 : {
217 : struct tevent_req *req, *subreq;
218 : struct cli_message_end_state *state;
219 :
220 0 : req = tevent_req_create(mem_ctx, &state,
221 : struct cli_message_end_state);
222 0 : if (req == NULL) {
223 0 : return NULL;
224 : }
225 :
226 0 : SSVAL(&state->vwv, 0, grp);
227 :
228 0 : subreq = cli_smb_send(state, ev, cli, SMBsendend, 0, 0, 1, &state->vwv,
229 : 0, NULL);
230 0 : if (tevent_req_nomem(subreq, req)) {
231 0 : return tevent_req_post(req, ev);
232 : }
233 0 : tevent_req_set_callback(subreq, cli_message_end_done, req);
234 0 : return req;
235 : }
236 :
237 0 : static void cli_message_end_done(struct tevent_req *subreq)
238 : {
239 0 : struct tevent_req *req = tevent_req_callback_data(
240 : subreq, struct tevent_req);
241 : NTSTATUS status;
242 :
243 0 : status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
244 0 : TALLOC_FREE(subreq);
245 0 : if (!NT_STATUS_IS_OK(status)) {
246 0 : tevent_req_nterror(req, status);
247 0 : return;
248 : }
249 0 : tevent_req_done(req);
250 : }
251 :
252 0 : static NTSTATUS cli_message_end_recv(struct tevent_req *req)
253 : {
254 0 : return tevent_req_simple_recv_ntstatus(req);
255 : }
256 :
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;
263 : };
264 :
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);
268 :
269 8 : 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)
274 : {
275 : struct tevent_req *req, *subreq;
276 : struct cli_message_state *state;
277 :
278 8 : req = tevent_req_create(mem_ctx, &state, struct cli_message_state);
279 8 : if (req == NULL) {
280 0 : return NULL;
281 : }
282 8 : state->ev = ev;
283 8 : state->cli = cli;
284 8 : state->sent = 0;
285 8 : state->message = message;
286 :
287 8 : subreq = cli_message_start_send(state, ev, cli, host, username);
288 8 : if (tevent_req_nomem(subreq, req)) {
289 0 : return tevent_req_post(req, ev);
290 : }
291 8 : tevent_req_set_callback(subreq, cli_message_started, req);
292 8 : return req;
293 : }
294 :
295 8 : static void cli_message_started(struct tevent_req *subreq)
296 : {
297 8 : struct tevent_req *req = tevent_req_callback_data(
298 : subreq, struct tevent_req);
299 8 : struct cli_message_state *state = tevent_req_data(
300 : req, struct cli_message_state);
301 : NTSTATUS status;
302 : size_t thistime;
303 :
304 8 : status = cli_message_start_recv(subreq, &state->grp);
305 8 : TALLOC_FREE(subreq);
306 8 : if (!NT_STATUS_IS_OK(status)) {
307 8 : tevent_req_nterror(req, status);
308 8 : return;
309 : }
310 :
311 0 : thistime = MIN(127, strlen(state->message));
312 :
313 0 : subreq = cli_message_text_send(state, state->ev, state->cli,
314 0 : state->grp, state->message, thistime);
315 0 : if (tevent_req_nomem(subreq, req)) {
316 0 : return;
317 : }
318 0 : state->sent += thistime;
319 0 : tevent_req_set_callback(subreq, cli_message_sent, req);
320 : }
321 :
322 0 : static void cli_message_sent(struct tevent_req *subreq)
323 : {
324 0 : struct tevent_req *req = tevent_req_callback_data(
325 : subreq, struct tevent_req);
326 0 : struct cli_message_state *state = tevent_req_data(
327 : req, struct cli_message_state);
328 : NTSTATUS status;
329 : size_t left, thistime;
330 :
331 0 : status = cli_message_text_recv(subreq);
332 0 : TALLOC_FREE(subreq);
333 0 : if (!NT_STATUS_IS_OK(status)) {
334 0 : tevent_req_nterror(req, status);
335 0 : return;
336 : }
337 :
338 0 : if (state->sent >= strlen(state->message)) {
339 0 : subreq = cli_message_end_send(state, state->ev, state->cli,
340 0 : state->grp);
341 0 : if (tevent_req_nomem(subreq, req)) {
342 0 : return;
343 : }
344 0 : tevent_req_set_callback(subreq, cli_message_done, req);
345 0 : return;
346 : }
347 :
348 0 : left = strlen(state->message) - state->sent;
349 0 : thistime = MIN(127, left);
350 :
351 0 : subreq = cli_message_text_send(state, state->ev, state->cli,
352 0 : state->grp,
353 0 : state->message + state->sent,
354 : thistime);
355 0 : if (tevent_req_nomem(subreq, req)) {
356 0 : return;
357 : }
358 0 : state->sent += thistime;
359 0 : tevent_req_set_callback(subreq, cli_message_sent, req);
360 : }
361 :
362 0 : static void cli_message_done(struct tevent_req *subreq)
363 : {
364 0 : struct tevent_req *req = tevent_req_callback_data(
365 : subreq, struct tevent_req);
366 : NTSTATUS status;
367 :
368 0 : status = cli_message_end_recv(subreq);
369 0 : TALLOC_FREE(subreq);
370 0 : if (!NT_STATUS_IS_OK(status)) {
371 0 : tevent_req_nterror(req, status);
372 0 : return;
373 : }
374 0 : tevent_req_done(req);
375 : }
376 :
377 8 : NTSTATUS cli_message_recv(struct tevent_req *req)
378 : {
379 8 : return tevent_req_simple_recv_ntstatus(req);
380 : }
381 :
382 8 : NTSTATUS cli_message(struct cli_state *cli, const char *host,
383 : const char *username, const char *message)
384 : {
385 8 : TALLOC_CTX *frame = talloc_stackframe();
386 : struct tevent_context *ev;
387 : struct tevent_req *req;
388 8 : NTSTATUS status = NT_STATUS_OK;
389 :
390 8 : if (smbXcli_conn_has_async_calls(cli->conn)) {
391 : /*
392 : * Can't use sync call while an async call is in flight
393 : */
394 0 : status = NT_STATUS_INVALID_PARAMETER;
395 0 : goto fail;
396 : }
397 :
398 8 : ev = samba_tevent_context_init(frame);
399 8 : if (ev == NULL) {
400 0 : status = NT_STATUS_NO_MEMORY;
401 0 : goto fail;
402 : }
403 :
404 8 : req = cli_message_send(frame, ev, cli, host, username, message);
405 8 : if (req == NULL) {
406 0 : status = NT_STATUS_NO_MEMORY;
407 0 : goto fail;
408 : }
409 :
410 8 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
411 0 : goto fail;
412 : }
413 :
414 8 : status = cli_message_recv(req);
415 8 : fail:
416 8 : TALLOC_FREE(frame);
417 8 : return status;
418 : }
|