source: vendor/3.6.0/source3/libsmb/climessage.c

Last change on this file was 740, checked in by Silvan Scherrer, 13 years ago

Samba Server: update vendor to 3.6.0

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