source: trunk/server/source3/libsmb/climessage.c@ 480

Last change on this file since 480 was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

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