• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source3/libsmb/
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}
416