source: branches/samba-3.5.x/source3/libsmb/climessage.c@ 742

Last change on this file since 742 was 590, checked in by Herwig Bauernfeind, 14 years ago

Samba 3.5: Update trunk to 3.5.6

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