• 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/rpc_client/
1/*
2 *  Unix SMB/CIFS implementation.
3 *  RPC client transport over named pipes
4 *  Copyright (C) Volker Lendecke 2009
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
22#undef DBGC_CLASS
23#define DBGC_CLASS DBGC_RPC_CLI
24
25struct rpc_transport_np_state {
26	struct cli_state *cli;
27	const char *pipe_name;
28	uint16_t fnum;
29};
30
31static bool rpc_np_is_connected(void *priv)
32{
33	struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
34		priv, struct rpc_transport_np_state);
35	bool ok;
36
37	if (np_transport->cli == NULL) {
38		return false;
39	}
40
41	ok = cli_state_is_connected(np_transport->cli);
42	if (!ok) {
43		np_transport->cli = NULL;
44		return false;
45	}
46
47	return true;
48}
49
50static unsigned int rpc_np_set_timeout(void *priv, unsigned int timeout)
51{
52	struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
53		priv, struct rpc_transport_np_state);
54	bool ok;
55
56	if (np_transport->cli == NULL) {
57		return false;
58	}
59
60	ok = rpc_np_is_connected(np_transport);
61	if (!ok) {
62		return 0;
63	}
64
65	return cli_set_timeout(np_transport->cli, timeout);
66}
67
68static int rpc_transport_np_state_destructor(struct rpc_transport_np_state *s)
69{
70	if (!rpc_np_is_connected(s)) {
71		DEBUG(10, ("socket was closed, no need to send close request.\n"));
72		return 0;
73	}
74
75	/* TODO: do not use a sync call with a destructor!!! */
76	if (!NT_STATUS_IS_OK(cli_close(s->cli, s->fnum))) {
77		DEBUG(1, ("rpc_transport_np_state_destructor: cli_close "
78			  "failed on pipe %s. Error was %s\n", s->pipe_name,
79			  cli_errstr(s->cli)));
80	}
81	DEBUG(10, ("rpc_pipe_destructor: closed %s\n", s->pipe_name));
82	/*
83	 * We can't do much on failure
84	 */
85	return 0;
86}
87
88struct rpc_np_write_state {
89	struct rpc_transport_np_state *np_transport;
90	size_t size;
91	size_t written;
92};
93
94static void rpc_np_write_done(struct tevent_req *subreq);
95
96static struct tevent_req *rpc_np_write_send(TALLOC_CTX *mem_ctx,
97					    struct event_context *ev,
98					    const uint8_t *data, size_t size,
99					    void *priv)
100{
101	struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
102		priv, struct rpc_transport_np_state);
103	struct tevent_req *req, *subreq;
104	struct rpc_np_write_state *state;
105	bool ok;
106
107	req = tevent_req_create(mem_ctx, &state, struct rpc_np_write_state);
108	if (req == NULL) {
109		return NULL;
110	}
111
112	ok = rpc_np_is_connected(np_transport);
113	if (!ok) {
114		tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID);
115		return tevent_req_post(req, ev);
116	}
117
118	state->np_transport = np_transport;
119	state->size = size;
120
121
122	subreq = cli_write_andx_send(mem_ctx, ev, np_transport->cli,
123				     np_transport->fnum,
124				     8, /* 8 means message mode. */
125				     data, 0, size);
126	if (tevent_req_nomem(subreq, req)) {
127		return tevent_req_post(req, ev);
128	}
129	tevent_req_set_callback(subreq, rpc_np_write_done, req);
130	return req;
131}
132
133static void rpc_np_write_done(struct tevent_req *subreq)
134{
135	struct tevent_req *req = tevent_req_callback_data(
136		subreq, struct tevent_req);
137	struct rpc_np_write_state *state = tevent_req_data(
138		req, struct rpc_np_write_state);
139	NTSTATUS status;
140
141	status = cli_write_andx_recv(subreq, &state->written);
142	TALLOC_FREE(subreq);
143	if (!NT_STATUS_IS_OK(status)) {
144		state->np_transport->cli = NULL;
145		tevent_req_nterror(req, status);
146		return;
147	}
148	tevent_req_done(req);
149}
150
151static NTSTATUS rpc_np_write_recv(struct tevent_req *req, ssize_t *pwritten)
152{
153	struct rpc_np_write_state *state = tevent_req_data(
154		req, struct rpc_np_write_state);
155	NTSTATUS status;
156
157	if (tevent_req_is_nterror(req, &status)) {
158		return status;
159	}
160	*pwritten = state->written;
161	return NT_STATUS_OK;
162}
163
164struct rpc_np_read_state {
165	struct rpc_transport_np_state *np_transport;
166	uint8_t *data;
167	size_t size;
168	ssize_t received;
169};
170
171static void rpc_np_read_done(struct tevent_req *subreq);
172
173static struct tevent_req *rpc_np_read_send(TALLOC_CTX *mem_ctx,
174					   struct event_context *ev,
175					   uint8_t *data, size_t size,
176					   void *priv)
177{
178	struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
179		priv, struct rpc_transport_np_state);
180	struct tevent_req *req, *subreq;
181	struct rpc_np_read_state *state;
182	bool ok;
183
184	req = tevent_req_create(mem_ctx, &state, struct rpc_np_read_state);
185	if (req == NULL) {
186		return NULL;
187	}
188
189	ok = rpc_np_is_connected(np_transport);
190	if (!ok) {
191		tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID);
192		return tevent_req_post(req, ev);
193	}
194
195	state->np_transport = np_transport;
196	state->data = data;
197	state->size = size;
198
199	subreq = cli_read_andx_send(mem_ctx, ev, np_transport->cli,
200				    np_transport->fnum, 0, size);
201	if (subreq == NULL) {
202		goto fail;
203	}
204	tevent_req_set_callback(subreq, rpc_np_read_done, req);
205	return req;
206 fail:
207	TALLOC_FREE(req);
208	return NULL;
209}
210
211static void rpc_np_read_done(struct tevent_req *subreq)
212{
213	struct tevent_req *req = tevent_req_callback_data(
214		subreq, struct tevent_req);
215	struct rpc_np_read_state *state = tevent_req_data(
216		req, struct rpc_np_read_state);
217	NTSTATUS status;
218	uint8_t *rcvbuf;
219
220	/* We must free subreq in this function as there is
221	   a timer event attached to it. */
222
223	status = cli_read_andx_recv(subreq, &state->received, &rcvbuf);
224	/*
225	 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
226	 * child of that.
227	 */
228	if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
229		status = NT_STATUS_OK;
230	}
231	if (!NT_STATUS_IS_OK(status)) {
232		TALLOC_FREE(subreq);
233		state->np_transport->cli = NULL;
234		tevent_req_nterror(req, status);
235		return;
236	}
237
238	if (state->received > state->size) {
239		TALLOC_FREE(subreq);
240		state->np_transport->cli = NULL;
241		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
242		return;
243	}
244
245	if (state->received == 0) {
246		TALLOC_FREE(subreq);
247		state->np_transport->cli = NULL;
248		tevent_req_nterror(req, NT_STATUS_PIPE_BROKEN);
249		return;
250	}
251
252	memcpy(state->data, rcvbuf, state->received);
253	TALLOC_FREE(subreq);
254	tevent_req_done(req);
255}
256
257static NTSTATUS rpc_np_read_recv(struct tevent_req *req, ssize_t *preceived)
258{
259	struct rpc_np_read_state *state = tevent_req_data(
260		req, struct rpc_np_read_state);
261	NTSTATUS status;
262
263	if (tevent_req_is_nterror(req, &status)) {
264		return status;
265	}
266	*preceived = state->received;
267	return NT_STATUS_OK;
268}
269
270struct rpc_np_trans_state {
271	struct rpc_transport_np_state *np_transport;
272	uint16_t setup[2];
273	uint32_t max_rdata_len;
274	uint8_t *rdata;
275	uint32_t rdata_len;
276};
277
278static void rpc_np_trans_done(struct tevent_req *subreq);
279
280static struct tevent_req *rpc_np_trans_send(TALLOC_CTX *mem_ctx,
281					    struct event_context *ev,
282					    uint8_t *data, size_t data_len,
283					    uint32_t max_rdata_len,
284					    void *priv)
285{
286	struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
287		priv, struct rpc_transport_np_state);
288	struct tevent_req *req, *subreq;
289	struct rpc_np_trans_state *state;
290	bool ok;
291
292	req = tevent_req_create(mem_ctx, &state, struct rpc_np_trans_state);
293	if (req == NULL) {
294		return NULL;
295	}
296
297	ok = rpc_np_is_connected(np_transport);
298	if (!ok) {
299		tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID);
300		return tevent_req_post(req, ev);
301	}
302
303	state->np_transport = np_transport;
304	state->max_rdata_len = max_rdata_len;
305
306	SSVAL(state->setup+0, 0, TRANSACT_DCERPCCMD);
307	SSVAL(state->setup+1, 0, np_transport->fnum);
308
309	subreq = cli_trans_send(
310		state, ev, np_transport->cli, SMBtrans,
311		"\\PIPE\\", 0, 0, 0, state->setup, 2, 0,
312		NULL, 0, 0, data, data_len, max_rdata_len);
313	if (subreq == NULL) {
314		goto fail;
315	}
316	tevent_req_set_callback(subreq, rpc_np_trans_done, req);
317	return req;
318
319 fail:
320	TALLOC_FREE(req);
321	return NULL;
322}
323
324static void rpc_np_trans_done(struct tevent_req *subreq)
325{
326	struct tevent_req *req = tevent_req_callback_data(
327		subreq, struct tevent_req);
328	struct rpc_np_trans_state *state = tevent_req_data(
329		req, struct rpc_np_trans_state);
330	NTSTATUS status;
331
332	status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL,
333				&state->rdata, &state->rdata_len);
334	TALLOC_FREE(subreq);
335	if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
336		status = NT_STATUS_OK;
337	}
338	if (!NT_STATUS_IS_OK(status)) {
339		state->np_transport->cli = NULL;
340		tevent_req_nterror(req, status);
341		return;
342	}
343
344	if (state->rdata_len > state->max_rdata_len) {
345		state->np_transport->cli = NULL;
346		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
347		return;
348	}
349
350	if (state->rdata_len == 0) {
351		state->np_transport->cli = NULL;
352		tevent_req_nterror(req, NT_STATUS_PIPE_BROKEN);
353		return;
354	}
355
356	tevent_req_done(req);
357}
358
359static NTSTATUS rpc_np_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
360				  uint8_t **prdata, uint32_t *prdata_len)
361{
362	struct rpc_np_trans_state *state = tevent_req_data(
363		req, struct rpc_np_trans_state);
364	NTSTATUS status;
365
366	if (tevent_req_is_nterror(req, &status)) {
367		return status;
368	}
369	*prdata = talloc_move(mem_ctx, &state->rdata);
370	*prdata_len = state->rdata_len;
371	return NT_STATUS_OK;
372}
373
374struct rpc_transport_np_init_state {
375	struct rpc_cli_transport *transport;
376	struct rpc_transport_np_state *transport_np;
377};
378
379static void rpc_transport_np_init_pipe_open(struct tevent_req *subreq);
380
381struct tevent_req *rpc_transport_np_init_send(TALLOC_CTX *mem_ctx,
382					      struct event_context *ev,
383					      struct cli_state *cli,
384					      const struct ndr_syntax_id *abstract_syntax)
385{
386	struct tevent_req *req, *subreq;
387	struct rpc_transport_np_init_state *state;
388	bool ok;
389
390	req = tevent_req_create(mem_ctx, &state,
391				struct rpc_transport_np_init_state);
392	if (req == NULL) {
393		return NULL;
394	}
395
396	ok = cli_state_is_connected(cli);
397	if (!ok) {
398		tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID);
399		return tevent_req_post(req, ev);
400	}
401
402	state->transport = talloc(state, struct rpc_cli_transport);
403	if (tevent_req_nomem(state->transport, req)) {
404		return tevent_req_post(req, ev);
405	}
406	state->transport_np = talloc(state->transport,
407				     struct rpc_transport_np_state);
408	if (tevent_req_nomem(state->transport_np, req)) {
409		return tevent_req_post(req, ev);
410	}
411	state->transport->priv = state->transport_np;
412
413	state->transport_np->pipe_name = get_pipe_name_from_syntax(
414		state->transport_np, abstract_syntax);
415	state->transport_np->cli = cli;
416
417	subreq = cli_ntcreate_send(
418		state, ev, cli, state->transport_np->pipe_name,	0,
419		DESIRED_ACCESS_PIPE, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
420		FILE_OPEN, 0, 0);
421	if (tevent_req_nomem(subreq, req)) {
422		return tevent_req_post(req, ev);
423	}
424	tevent_req_set_callback(subreq, rpc_transport_np_init_pipe_open,
425				req);
426	return req;
427}
428
429static void rpc_transport_np_init_pipe_open(struct tevent_req *subreq)
430{
431	struct tevent_req *req = tevent_req_callback_data(
432		subreq, struct tevent_req);
433	struct rpc_transport_np_init_state *state = tevent_req_data(
434		req, struct rpc_transport_np_init_state);
435	NTSTATUS status;
436
437	status = cli_ntcreate_recv(subreq, &state->transport_np->fnum);
438	TALLOC_FREE(subreq);
439	if (!NT_STATUS_IS_OK(status)) {
440		tevent_req_nterror(req, status);
441		return;
442	}
443
444	talloc_set_destructor(state->transport_np,
445			      rpc_transport_np_state_destructor);
446	tevent_req_done(req);
447}
448
449NTSTATUS rpc_transport_np_init_recv(struct tevent_req *req,
450				    TALLOC_CTX *mem_ctx,
451				    struct rpc_cli_transport **presult)
452{
453	struct rpc_transport_np_init_state *state = tevent_req_data(
454		req, struct rpc_transport_np_init_state);
455	NTSTATUS status;
456
457	if (tevent_req_is_nterror(req, &status)) {
458		return status;
459	}
460
461	state->transport->write_send = rpc_np_write_send;
462	state->transport->write_recv = rpc_np_write_recv;
463	state->transport->read_send = rpc_np_read_send;
464	state->transport->read_recv = rpc_np_read_recv;
465	state->transport->trans_send = rpc_np_trans_send;
466	state->transport->trans_recv = rpc_np_trans_recv;
467	state->transport->is_connected = rpc_np_is_connected;
468	state->transport->set_timeout = rpc_np_set_timeout;
469
470	*presult = talloc_move(mem_ctx, &state->transport);
471	return NT_STATUS_OK;
472}
473
474NTSTATUS rpc_transport_np_init(TALLOC_CTX *mem_ctx, struct cli_state *cli,
475			       const struct ndr_syntax_id *abstract_syntax,
476			       struct rpc_cli_transport **presult)
477{
478	TALLOC_CTX *frame = talloc_stackframe();
479	struct event_context *ev;
480	struct tevent_req *req;
481	NTSTATUS status = NT_STATUS_OK;
482
483	ev = event_context_init(frame);
484	if (ev == NULL) {
485		status = NT_STATUS_NO_MEMORY;
486		goto fail;
487	}
488
489	req = rpc_transport_np_init_send(frame, ev, cli, abstract_syntax);
490	if (req == NULL) {
491		status = NT_STATUS_NO_MEMORY;
492		goto fail;
493	}
494
495	if (!tevent_req_poll(req, ev)) {
496		status = map_nt_error_from_unix(errno);
497		goto fail;
498	}
499
500	status = rpc_transport_np_init_recv(req, mem_ctx, presult);
501 fail:
502	TALLOC_FREE(frame);
503	return status;
504}
505
506struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p)
507{
508	struct rpc_transport_np_state *state = talloc_get_type(
509		p->transport->priv, struct rpc_transport_np_state);
510
511	if (state == NULL) {
512		return NULL;
513	}
514	return state->cli;
515}
516