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 28 : 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 28 : char *htmp = NULL;
41 28 : char *utmp = NULL;
42 : size_t hlen, ulen;
43 : uint8_t *bytes, *p;
44 :
45 28 : req = tevent_req_create(mem_ctx, &state,
46 : struct cli_message_start_state);
47 28 : if (req == NULL) {
48 0 : return NULL;
49 : }
50 :
51 28 : if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
52 28 : username, strlen(username)+1,
53 : &utmp, &ulen)) {
54 0 : goto fail;
55 : }
56 28 : if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS,
57 28 : host, strlen(host)+1,
58 : &htmp, &hlen)) {
59 0 : goto fail;
60 : }
61 :
62 28 : bytes = talloc_array(state, uint8_t, ulen+hlen+2);
63 28 : if (bytes == NULL) {
64 0 : goto fail;
65 : }
66 28 : p = bytes;
67 :
68 28 : *p++ = 4;
69 28 : memcpy(p, utmp, ulen);
70 28 : p += ulen;
71 28 : *p++ = 4;
72 28 : memcpy(p, htmp, hlen);
73 28 : TALLOC_FREE(htmp);
74 28 : TALLOC_FREE(utmp);
75 :
76 28 : subreq = cli_smb_send(state, ev, cli, SMBsendstrt, 0, 0, 0, NULL,
77 28 : talloc_get_size(bytes), bytes);
78 28 : if (tevent_req_nomem(subreq, req)) {
79 0 : return tevent_req_post(req, ev);
80 : }
81 28 : tevent_req_set_callback(subreq, cli_message_start_done, req);
82 28 : 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 28 : static void cli_message_start_done(struct tevent_req *subreq)
91 : {
92 28 : struct tevent_req *req = tevent_req_callback_data(
93 : subreq, struct tevent_req);
94 28 : 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 28 : status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv,
101 : NULL, NULL);
102 28 : TALLOC_FREE(subreq);
103 28 : if (!NT_STATUS_IS_OK(status)) {
104 0 : TALLOC_FREE(subreq);
105 0 : tevent_req_nterror(req, status);
106 0 : return;
107 : }
108 28 : if (wct >= 1) {
109 0 : state->grp = SVAL(vwv+0, 0);
110 : } else {
111 28 : state->grp = 0;
112 : }
113 28 : tevent_req_done(req);
114 : }
115 :
116 28 : static NTSTATUS cli_message_start_recv(struct tevent_req *req,
117 : uint16_t *pgrp)
118 : {
119 28 : struct cli_message_start_state *state = tevent_req_data(
120 : req, struct cli_message_start_state);
121 : NTSTATUS status;
122 :
123 28 : if (tevent_req_is_nterror(req, &status)) {
124 0 : return status;
125 : }
126 28 : *pgrp = state->grp;
127 28 : 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 28 : 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 28 : req = tevent_req_create(mem_ctx, &state,
150 : struct cli_message_text_state);
151 28 : if (req == NULL) {
152 0 : return NULL;
153 : }
154 :
155 28 : SSVAL(&state->vwv, 0, grp);
156 :
157 28 : if (convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS, msg, msglen,
158 : &tmp, &tmplen)) {
159 28 : msg = tmp;
160 28 : msglen = tmplen;
161 : } else {
162 0 : DEBUG(3, ("Conversion failed, sending message in UNIX "
163 : "charset\n"));
164 0 : tmp = NULL;
165 : }
166 :
167 28 : bytes = talloc_array(state, uint8_t, msglen+3);
168 28 : if (tevent_req_nomem(bytes, req)) {
169 0 : TALLOC_FREE(tmp);
170 0 : return tevent_req_post(req, ev);
171 : }
172 28 : SCVAL(bytes, 0, 1); /* pad */
173 28 : SSVAL(bytes+1, 0, msglen);
174 28 : memcpy(bytes+3, msg, msglen);
175 28 : TALLOC_FREE(tmp);
176 :
177 28 : subreq = cli_smb_send(state, ev, cli, SMBsendtxt, 0, 0, 1, &state->vwv,
178 28 : talloc_get_size(bytes), bytes);
179 28 : if (tevent_req_nomem(subreq, req)) {
180 0 : return tevent_req_post(req, ev);
181 : }
182 28 : tevent_req_set_callback(subreq, cli_message_text_done, req);
183 28 : return req;
184 : }
185 :
186 28 : static void cli_message_text_done(struct tevent_req *subreq)
187 : {
188 28 : struct tevent_req *req = tevent_req_callback_data(
189 : subreq, struct tevent_req);
190 : NTSTATUS status;
191 :
192 28 : status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
193 28 : TALLOC_FREE(subreq);
194 28 : if (!NT_STATUS_IS_OK(status)) {
195 0 : tevent_req_nterror(req, status);
196 0 : return;
197 : }
198 28 : tevent_req_done(req);
199 : }
200 :
201 28 : static NTSTATUS cli_message_text_recv(struct tevent_req *req)
202 : {
203 28 : 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 28 : 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 28 : req = tevent_req_create(mem_ctx, &state,
221 : struct cli_message_end_state);
222 28 : if (req == NULL) {
223 0 : return NULL;
224 : }
225 :
226 28 : SSVAL(&state->vwv, 0, grp);
227 :
228 28 : subreq = cli_smb_send(state, ev, cli, SMBsendend, 0, 0, 1, &state->vwv,
229 : 0, NULL);
230 28 : if (tevent_req_nomem(subreq, req)) {
231 0 : return tevent_req_post(req, ev);
232 : }
233 28 : tevent_req_set_callback(subreq, cli_message_end_done, req);
234 28 : return req;
235 : }
236 :
237 28 : static void cli_message_end_done(struct tevent_req *subreq)
238 : {
239 28 : struct tevent_req *req = tevent_req_callback_data(
240 : subreq, struct tevent_req);
241 : NTSTATUS status;
242 :
243 28 : status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
244 28 : TALLOC_FREE(subreq);
245 28 : if (!NT_STATUS_IS_OK(status)) {
246 0 : tevent_req_nterror(req, status);
247 0 : return;
248 : }
249 28 : tevent_req_done(req);
250 : }
251 :
252 28 : static NTSTATUS cli_message_end_recv(struct tevent_req *req)
253 : {
254 28 : 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 28 : 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 28 : req = tevent_req_create(mem_ctx, &state, struct cli_message_state);
279 28 : if (req == NULL) {
280 0 : return NULL;
281 : }
282 28 : state->ev = ev;
283 28 : state->cli = cli;
284 28 : state->sent = 0;
285 28 : state->message = message;
286 :
287 28 : subreq = cli_message_start_send(state, ev, cli, host, username);
288 28 : if (tevent_req_nomem(subreq, req)) {
289 0 : return tevent_req_post(req, ev);
290 : }
291 28 : tevent_req_set_callback(subreq, cli_message_started, req);
292 28 : return req;
293 : }
294 :
295 28 : static void cli_message_started(struct tevent_req *subreq)
296 : {
297 28 : struct tevent_req *req = tevent_req_callback_data(
298 : subreq, struct tevent_req);
299 28 : struct cli_message_state *state = tevent_req_data(
300 : req, struct cli_message_state);
301 : NTSTATUS status;
302 : size_t thistime;
303 :
304 28 : status = cli_message_start_recv(subreq, &state->grp);
305 28 : TALLOC_FREE(subreq);
306 28 : if (!NT_STATUS_IS_OK(status)) {
307 0 : tevent_req_nterror(req, status);
308 0 : return;
309 : }
310 :
311 28 : thistime = MIN(127, strlen(state->message));
312 :
313 52 : subreq = cli_message_text_send(state, state->ev, state->cli,
314 28 : state->grp, state->message, thistime);
315 28 : if (tevent_req_nomem(subreq, req)) {
316 0 : return;
317 : }
318 28 : state->sent += thistime;
319 28 : tevent_req_set_callback(subreq, cli_message_sent, req);
320 : }
321 :
322 28 : static void cli_message_sent(struct tevent_req *subreq)
323 : {
324 28 : struct tevent_req *req = tevent_req_callback_data(
325 : subreq, struct tevent_req);
326 28 : struct cli_message_state *state = tevent_req_data(
327 : req, struct cli_message_state);
328 : NTSTATUS status;
329 : size_t left, thistime;
330 :
331 28 : status = cli_message_text_recv(subreq);
332 28 : TALLOC_FREE(subreq);
333 28 : if (!NT_STATUS_IS_OK(status)) {
334 0 : tevent_req_nterror(req, status);
335 4 : return;
336 : }
337 :
338 28 : if (state->sent >= strlen(state->message)) {
339 28 : subreq = cli_message_end_send(state, state->ev, state->cli,
340 28 : state->grp);
341 28 : if (tevent_req_nomem(subreq, req)) {
342 0 : return;
343 : }
344 28 : tevent_req_set_callback(subreq, cli_message_done, req);
345 28 : 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 28 : static void cli_message_done(struct tevent_req *subreq)
363 : {
364 28 : struct tevent_req *req = tevent_req_callback_data(
365 : subreq, struct tevent_req);
366 : NTSTATUS status;
367 :
368 28 : status = cli_message_end_recv(subreq);
369 28 : TALLOC_FREE(subreq);
370 28 : if (!NT_STATUS_IS_OK(status)) {
371 0 : tevent_req_nterror(req, status);
372 0 : return;
373 : }
374 28 : tevent_req_done(req);
375 : }
376 :
377 28 : NTSTATUS cli_message_recv(struct tevent_req *req)
378 : {
379 28 : return tevent_req_simple_recv_ntstatus(req);
380 : }
381 :
382 28 : NTSTATUS cli_message(struct cli_state *cli, const char *host,
383 : const char *username, const char *message)
384 : {
385 28 : TALLOC_CTX *frame = talloc_stackframe();
386 : struct tevent_context *ev;
387 : struct tevent_req *req;
388 28 : NTSTATUS status = NT_STATUS_OK;
389 :
390 28 : 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 28 : ev = samba_tevent_context_init(frame);
399 28 : if (ev == NULL) {
400 0 : status = NT_STATUS_NO_MEMORY;
401 0 : goto fail;
402 : }
403 :
404 28 : req = cli_message_send(frame, ev, cli, host, username, message);
405 28 : if (req == NULL) {
406 0 : status = NT_STATUS_NO_MEMORY;
407 0 : goto fail;
408 : }
409 :
410 28 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
411 0 : goto fail;
412 : }
413 :
414 28 : status = cli_message_recv(req);
415 28 : fail:
416 28 : TALLOC_FREE(frame);
417 28 : return status;
418 : }
|