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 0 : struct tevent_req *req, *subreq;
39 0 : struct cli_message_start_state *state;
40 28 : char *htmp = NULL;
41 28 : char *utmp = NULL;
42 0 : size_t hlen, ulen;
43 0 : 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 0 : NTSTATUS status;
97 0 : uint8_t wct;
98 0 : 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 (tevent_req_nterror(req, status)) {
104 22 : return;
105 : }
106 6 : if (wct >= 1) {
107 0 : state->grp = SVAL(vwv+0, 0);
108 : } else {
109 6 : state->grp = 0;
110 : }
111 6 : tevent_req_done(req);
112 : }
113 :
114 28 : static NTSTATUS cli_message_start_recv(struct tevent_req *req,
115 : uint16_t *pgrp)
116 : {
117 28 : struct cli_message_start_state *state = tevent_req_data(
118 : req, struct cli_message_start_state);
119 0 : NTSTATUS status;
120 :
121 28 : if (tevent_req_is_nterror(req, &status)) {
122 22 : return status;
123 : }
124 6 : *pgrp = state->grp;
125 6 : return NT_STATUS_OK;
126 : }
127 :
128 : struct cli_message_text_state {
129 : uint16_t vwv;
130 : };
131 :
132 : static void cli_message_text_done(struct tevent_req *subreq);
133 :
134 6 : 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)
140 : {
141 0 : struct tevent_req *req, *subreq;
142 0 : struct cli_message_text_state *state;
143 0 : char *tmp;
144 0 : size_t tmplen;
145 0 : uint8_t *bytes;
146 :
147 6 : req = tevent_req_create(mem_ctx, &state,
148 : struct cli_message_text_state);
149 6 : if (req == NULL) {
150 0 : return NULL;
151 : }
152 :
153 6 : SSVAL(&state->vwv, 0, grp);
154 :
155 6 : if (convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS, msg, msglen,
156 : &tmp, &tmplen)) {
157 6 : msg = tmp;
158 6 : msglen = tmplen;
159 : } else {
160 0 : DEBUG(3, ("Conversion failed, sending message in UNIX "
161 : "charset\n"));
162 0 : tmp = NULL;
163 : }
164 :
165 6 : bytes = talloc_array(state, uint8_t, msglen+3);
166 6 : if (tevent_req_nomem(bytes, req)) {
167 0 : TALLOC_FREE(tmp);
168 0 : return tevent_req_post(req, ev);
169 : }
170 6 : SCVAL(bytes, 0, 1); /* pad */
171 6 : SSVAL(bytes+1, 0, msglen);
172 6 : memcpy(bytes+3, msg, msglen);
173 6 : TALLOC_FREE(tmp);
174 :
175 6 : subreq = cli_smb_send(state, ev, cli, SMBsendtxt, 0, 0, 1, &state->vwv,
176 6 : talloc_get_size(bytes), bytes);
177 6 : if (tevent_req_nomem(subreq, req)) {
178 0 : return tevent_req_post(req, ev);
179 : }
180 6 : tevent_req_set_callback(subreq, cli_message_text_done, req);
181 6 : return req;
182 : }
183 :
184 6 : static void cli_message_text_done(struct tevent_req *subreq)
185 : {
186 6 : struct tevent_req *req = tevent_req_callback_data(
187 : subreq, struct tevent_req);
188 0 : NTSTATUS status;
189 :
190 6 : status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
191 6 : TALLOC_FREE(subreq);
192 6 : if (tevent_req_nterror(req, status)) {
193 0 : return;
194 : }
195 6 : tevent_req_done(req);
196 : }
197 :
198 6 : static NTSTATUS cli_message_text_recv(struct tevent_req *req)
199 : {
200 6 : return tevent_req_simple_recv_ntstatus(req);
201 : }
202 :
203 : struct cli_message_end_state {
204 : uint16_t vwv;
205 : };
206 :
207 : static void cli_message_end_done(struct tevent_req *subreq);
208 :
209 6 : 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)
213 : {
214 0 : struct tevent_req *req, *subreq;
215 0 : struct cli_message_end_state *state;
216 :
217 6 : req = tevent_req_create(mem_ctx, &state,
218 : struct cli_message_end_state);
219 6 : if (req == NULL) {
220 0 : return NULL;
221 : }
222 :
223 6 : SSVAL(&state->vwv, 0, grp);
224 :
225 6 : subreq = cli_smb_send(state, ev, cli, SMBsendend, 0, 0, 1, &state->vwv,
226 : 0, NULL);
227 6 : if (tevent_req_nomem(subreq, req)) {
228 0 : return tevent_req_post(req, ev);
229 : }
230 6 : tevent_req_set_callback(subreq, cli_message_end_done, req);
231 6 : return req;
232 : }
233 :
234 6 : static void cli_message_end_done(struct tevent_req *subreq)
235 : {
236 6 : struct tevent_req *req = tevent_req_callback_data(
237 : subreq, struct tevent_req);
238 0 : NTSTATUS status;
239 :
240 6 : status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
241 6 : TALLOC_FREE(subreq);
242 6 : if (tevent_req_nterror(req, status)) {
243 0 : return;
244 : }
245 6 : tevent_req_done(req);
246 : }
247 :
248 6 : static NTSTATUS cli_message_end_recv(struct tevent_req *req)
249 : {
250 6 : return tevent_req_simple_recv_ntstatus(req);
251 : }
252 :
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;
259 : };
260 :
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);
264 :
265 28 : 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)
270 : {
271 0 : struct tevent_req *req, *subreq;
272 0 : struct cli_message_state *state;
273 :
274 28 : req = tevent_req_create(mem_ctx, &state, struct cli_message_state);
275 28 : if (req == NULL) {
276 0 : return NULL;
277 : }
278 28 : state->ev = ev;
279 28 : state->cli = cli;
280 28 : state->sent = 0;
281 28 : state->message = message;
282 :
283 28 : subreq = cli_message_start_send(state, ev, cli, host, username);
284 28 : if (tevent_req_nomem(subreq, req)) {
285 0 : return tevent_req_post(req, ev);
286 : }
287 28 : tevent_req_set_callback(subreq, cli_message_started, req);
288 28 : return req;
289 : }
290 :
291 28 : static void cli_message_started(struct tevent_req *subreq)
292 : {
293 28 : struct tevent_req *req = tevent_req_callback_data(
294 : subreq, struct tevent_req);
295 28 : struct cli_message_state *state = tevent_req_data(
296 : req, struct cli_message_state);
297 0 : NTSTATUS status;
298 0 : size_t thistime;
299 :
300 28 : status = cli_message_start_recv(subreq, &state->grp);
301 28 : TALLOC_FREE(subreq);
302 28 : if (tevent_req_nterror(req, status)) {
303 22 : return;
304 : }
305 :
306 6 : thistime = MIN(127, strlen(state->message));
307 :
308 6 : subreq = cli_message_text_send(state, state->ev, state->cli,
309 6 : state->grp, state->message, thistime);
310 6 : if (tevent_req_nomem(subreq, req)) {
311 0 : return;
312 : }
313 6 : state->sent += thistime;
314 6 : tevent_req_set_callback(subreq, cli_message_sent, req);
315 : }
316 :
317 6 : static void cli_message_sent(struct tevent_req *subreq)
318 : {
319 6 : struct tevent_req *req = tevent_req_callback_data(
320 : subreq, struct tevent_req);
321 6 : struct cli_message_state *state = tevent_req_data(
322 : req, struct cli_message_state);
323 0 : NTSTATUS status;
324 0 : size_t left, thistime;
325 :
326 6 : status = cli_message_text_recv(subreq);
327 6 : TALLOC_FREE(subreq);
328 6 : if (tevent_req_nterror(req, status)) {
329 6 : return;
330 : }
331 :
332 6 : if (state->sent >= strlen(state->message)) {
333 6 : subreq = cli_message_end_send(state, state->ev, state->cli,
334 6 : state->grp);
335 6 : if (tevent_req_nomem(subreq, req)) {
336 0 : return;
337 : }
338 6 : tevent_req_set_callback(subreq, cli_message_done, req);
339 6 : return;
340 : }
341 :
342 0 : left = strlen(state->message) - state->sent;
343 0 : thistime = MIN(127, left);
344 :
345 0 : subreq = cli_message_text_send(state, state->ev, state->cli,
346 0 : state->grp,
347 0 : state->message + state->sent,
348 : thistime);
349 0 : if (tevent_req_nomem(subreq, req)) {
350 0 : return;
351 : }
352 0 : state->sent += thistime;
353 0 : tevent_req_set_callback(subreq, cli_message_sent, req);
354 : }
355 :
356 6 : static void cli_message_done(struct tevent_req *subreq)
357 : {
358 6 : struct tevent_req *req = tevent_req_callback_data(
359 : subreq, struct tevent_req);
360 0 : NTSTATUS status;
361 :
362 6 : status = cli_message_end_recv(subreq);
363 6 : TALLOC_FREE(subreq);
364 6 : if (tevent_req_nterror(req, status)) {
365 0 : return;
366 : }
367 6 : tevent_req_done(req);
368 : }
369 :
370 28 : NTSTATUS cli_message_recv(struct tevent_req *req)
371 : {
372 28 : return tevent_req_simple_recv_ntstatus(req);
373 : }
374 :
375 28 : NTSTATUS cli_message(struct cli_state *cli, const char *host,
376 : const char *username, const char *message)
377 : {
378 28 : TALLOC_CTX *frame = talloc_stackframe();
379 0 : struct tevent_context *ev;
380 0 : struct tevent_req *req;
381 28 : NTSTATUS status = NT_STATUS_OK;
382 :
383 28 : if (smbXcli_conn_has_async_calls(cli->conn)) {
384 : /*
385 : * Can't use sync call while an async call is in flight
386 : */
387 0 : status = NT_STATUS_INVALID_PARAMETER;
388 0 : goto fail;
389 : }
390 :
391 28 : ev = samba_tevent_context_init(frame);
392 28 : if (ev == NULL) {
393 0 : status = NT_STATUS_NO_MEMORY;
394 0 : goto fail;
395 : }
396 :
397 28 : req = cli_message_send(frame, ev, cli, host, username, message);
398 28 : if (req == NULL) {
399 0 : status = NT_STATUS_NO_MEMORY;
400 0 : goto fail;
401 : }
402 :
403 28 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
404 0 : goto fail;
405 : }
406 :
407 28 : status = cli_message_recv(req);
408 28 : fail:
409 28 : TALLOC_FREE(frame);
410 28 : return status;
411 : }
|