e6de8396a88d1d1b620365dd95a4894ae93b86c3
[ira/wip.git] / source3 / rpc_client / rpc_transport_np.c
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
25 struct rpc_transport_np_state {
26         struct cli_state *cli;
27         const char *pipe_name;
28         uint16_t fnum;
29 };
30
31 static int rpc_transport_np_state_destructor(struct rpc_transport_np_state *s)
32 {
33         bool ret;
34         ret = cli_close(s->cli, s->fnum);
35         if (!ret) {
36                 DEBUG(1, ("rpc_transport_np_state_destructor: cli_close "
37                           "failed on pipe %s. Error was %s\n", s->pipe_name,
38                           cli_errstr(s->cli)));
39         }
40         DEBUG(10, ("rpc_pipe_destructor: closed %s\n", s->pipe_name));
41         /*
42          * We can't do much on failure
43          */
44         return 0;
45 }
46
47 struct rpc_np_write_state {
48         size_t size;
49         size_t written;
50 };
51
52 static void rpc_np_write_done(struct async_req *subreq);
53
54 static struct tevent_req *rpc_np_write_send(TALLOC_CTX *mem_ctx,
55                                             struct event_context *ev,
56                                             const uint8_t *data, size_t size,
57                                             void *priv)
58 {
59         struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
60                 priv, struct rpc_transport_np_state);
61         struct tevent_req *req;
62         struct async_req *subreq;
63         struct rpc_np_write_state *state;
64
65         req = tevent_req_create(mem_ctx, &state, struct rpc_np_write_state);
66         if (req == NULL) {
67                 return NULL;
68         }
69         state->size = size;
70
71         subreq = cli_write_andx_send(mem_ctx, ev, np_transport->cli,
72                                      np_transport->fnum,
73                                      8, /* 8 means message mode. */
74                                      data, 0, size);
75         if (subreq == NULL) {
76                 goto fail;
77         }
78         subreq->async.fn = rpc_np_write_done;
79         subreq->async.priv = req;
80         return req;
81  fail:
82         TALLOC_FREE(req);
83         return NULL;
84 }
85
86 static void rpc_np_write_done(struct async_req *subreq)
87 {
88         struct tevent_req *req = talloc_get_type_abort(
89                 subreq->async.priv, struct tevent_req);
90         struct rpc_np_write_state *state = tevent_req_data(
91                 req, struct rpc_np_write_state);
92         NTSTATUS status;
93
94         status = cli_write_andx_recv(subreq, &state->written);
95         TALLOC_FREE(subreq);
96         if (!NT_STATUS_IS_OK(status)) {
97                 tevent_req_nterror(req, status);
98                 return;
99         }
100         tevent_req_done(req);
101 }
102
103 static NTSTATUS rpc_np_write_recv(struct tevent_req *req, ssize_t *pwritten)
104 {
105         struct rpc_np_write_state *state = tevent_req_data(
106                 req, struct rpc_np_write_state);
107         NTSTATUS status;
108
109         if (tevent_req_is_nterror(req, &status)) {
110                 return status;
111         }
112         *pwritten = state->written;
113         return NT_STATUS_OK;
114 }
115
116 struct rpc_np_read_state {
117         uint8_t *data;
118         size_t size;
119         ssize_t received;
120 };
121
122 static void rpc_np_read_done(struct async_req *subreq);
123
124 static struct tevent_req *rpc_np_read_send(TALLOC_CTX *mem_ctx,
125                                            struct event_context *ev,
126                                            uint8_t *data, size_t size,
127                                            void *priv)
128 {
129         struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
130                 priv, struct rpc_transport_np_state);
131         struct tevent_req *req;
132         struct async_req *subreq;
133         struct rpc_np_read_state *state;
134
135         req = tevent_req_create(mem_ctx, &state, struct rpc_np_read_state);
136         if (req == NULL) {
137                 return NULL;
138         }
139         state->data = data;
140         state->size = size;
141
142         subreq = cli_read_andx_send(mem_ctx, ev, np_transport->cli,
143                                     np_transport->fnum, 0, size);
144         if (subreq == NULL) {
145                 goto fail;
146         }
147         subreq->async.fn = rpc_np_read_done;
148         subreq->async.priv = req;
149         return req;
150  fail:
151         TALLOC_FREE(req);
152         return NULL;
153 }
154
155 static void rpc_np_read_done(struct async_req *subreq)
156 {
157         struct tevent_req *req = talloc_get_type_abort(
158                 subreq->async.priv, struct tevent_req);
159         struct rpc_np_read_state *state = tevent_req_data(
160                 req, struct rpc_np_read_state);
161         NTSTATUS status;
162         uint8_t *rcvbuf;
163
164         status = cli_read_andx_recv(subreq, &state->received, &rcvbuf);
165         /*
166          * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
167          * child of that.
168          */
169         if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
170                 status = NT_STATUS_OK;
171         }
172         if (!NT_STATUS_IS_OK(status)) {
173                 TALLOC_FREE(subreq);
174                 tevent_req_nterror(req, status);
175                 return;
176         }
177
178         if (state->received > state->size) {
179                 TALLOC_FREE(subreq);
180                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
181                 return;
182         }
183
184         memcpy(state->data, rcvbuf, state->received);
185         tevent_req_done(req);
186 }
187
188 static NTSTATUS rpc_np_read_recv(struct tevent_req *req, ssize_t *preceived)
189 {
190         struct rpc_np_read_state *state = tevent_req_data(
191                 req, struct rpc_np_read_state);
192         NTSTATUS status;
193
194         if (tevent_req_is_nterror(req, &status)) {
195                 return status;
196         }
197         *preceived = state->received;
198         return NT_STATUS_OK;
199 }
200
201 struct rpc_np_trans_state {
202         uint16_t setup[2];
203         uint8_t *rdata;
204         uint32_t rdata_len;
205 };
206
207 static void rpc_np_trans_done(struct tevent_req *subreq);
208
209 static struct tevent_req *rpc_np_trans_send(TALLOC_CTX *mem_ctx,
210                                             struct event_context *ev,
211                                             uint8_t *data, size_t data_len,
212                                             uint32_t max_rdata_len,
213                                             void *priv)
214 {
215         struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
216                 priv, struct rpc_transport_np_state);
217         struct tevent_req *req, *subreq;
218         struct rpc_np_trans_state *state;
219
220         req = tevent_req_create(mem_ctx, &state, struct rpc_np_trans_state);
221         if (req == NULL) {
222                 return NULL;
223         }
224
225         SSVAL(state->setup+0, 0, TRANSACT_DCERPCCMD);
226         SSVAL(state->setup+1, 0, np_transport->fnum);
227
228         subreq = cli_trans_send(
229                 state, ev, np_transport->cli, SMBtrans,
230                 "\\PIPE\\", 0, 0, 0, state->setup, 2, 0,
231                 NULL, 0, 0, data, data_len, max_rdata_len);
232         if (subreq == NULL) {
233                 goto fail;
234         }
235         tevent_req_set_callback(subreq, rpc_np_trans_done, req);
236         return req;
237
238  fail:
239         TALLOC_FREE(req);
240         return NULL;
241 }
242
243 static void rpc_np_trans_done(struct tevent_req *subreq)
244 {
245         struct tevent_req *req = tevent_req_callback_data(
246                 subreq, struct tevent_req);
247         struct rpc_np_trans_state *state = tevent_req_data(
248                 req, struct rpc_np_trans_state);
249         NTSTATUS status;
250
251         status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL,
252                                 &state->rdata, &state->rdata_len);
253         TALLOC_FREE(subreq);
254         if (!NT_STATUS_IS_OK(status)) {
255                 tevent_req_nterror(req, status);
256                 return;
257         }
258         tevent_req_done(req);
259 }
260
261 static NTSTATUS rpc_np_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
262                                   uint8_t **prdata, uint32_t *prdata_len)
263 {
264         struct rpc_np_trans_state *state = tevent_req_data(
265                 req, struct rpc_np_trans_state);
266         NTSTATUS status;
267
268         if (tevent_req_is_nterror(req, &status)) {
269                 return status;
270         }
271         *prdata = talloc_move(mem_ctx, &state->rdata);
272         *prdata_len = state->rdata_len;
273         return NT_STATUS_OK;
274 }
275
276 struct rpc_transport_np_init_state {
277         struct rpc_cli_transport *transport;
278         struct rpc_transport_np_state *transport_np;
279 };
280
281 static void rpc_transport_np_init_pipe_open(struct tevent_req *subreq);
282
283 struct async_req *rpc_transport_np_init_send(TALLOC_CTX *mem_ctx,
284                                              struct event_context *ev,
285                                              struct cli_state *cli,
286                                              const struct ndr_syntax_id *abstract_syntax)
287 {
288         struct async_req *result;
289         struct tevent_req *subreq;
290         struct rpc_transport_np_init_state *state;
291
292         if (!async_req_setup(mem_ctx, &result, &state,
293                              struct rpc_transport_np_init_state)) {
294                 return NULL;
295         }
296
297         state->transport = talloc(state, struct rpc_cli_transport);
298         if (state->transport == NULL) {
299                 goto fail;
300         }
301         state->transport_np = talloc(state->transport,
302                                      struct rpc_transport_np_state);
303         if (state->transport_np == NULL) {
304                 goto fail;
305         }
306         state->transport->priv = state->transport_np;
307
308         state->transport_np->pipe_name = get_pipe_name_from_iface(
309                 abstract_syntax);
310         state->transport_np->cli = cli;
311
312         subreq = cli_ntcreate_send(
313                 state, ev, cli, state->transport_np->pipe_name, 0,
314                 DESIRED_ACCESS_PIPE, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
315                 FILE_OPEN, 0, 0);
316         if (subreq == NULL) {
317                 goto fail;
318         }
319         tevent_req_set_callback(subreq, rpc_transport_np_init_pipe_open,
320                                 result);
321         return result;
322
323  fail:
324         TALLOC_FREE(result);
325         return NULL;
326 }
327
328 static void rpc_transport_np_init_pipe_open(struct tevent_req *subreq)
329 {
330         struct async_req *req = tevent_req_callback_data(
331                 subreq, struct async_req);
332         struct rpc_transport_np_init_state *state = talloc_get_type_abort(
333                 req->private_data, struct rpc_transport_np_init_state);
334         NTSTATUS status;
335
336         status = cli_ntcreate_recv(subreq, &state->transport_np->fnum);
337         TALLOC_FREE(subreq);
338         if (!NT_STATUS_IS_OK(status)) {
339                 async_req_nterror(req, status);
340                 return;
341         }
342
343         talloc_set_destructor(state->transport_np,
344                               rpc_transport_np_state_destructor);
345         async_req_done(req);
346 }
347
348 NTSTATUS rpc_transport_np_init_recv(struct async_req *req,
349                                     TALLOC_CTX *mem_ctx,
350                                     struct rpc_cli_transport **presult)
351 {
352         struct rpc_transport_np_init_state *state = talloc_get_type_abort(
353                 req->private_data, struct rpc_transport_np_init_state);
354         NTSTATUS status;
355
356         if (async_req_is_nterror(req, &status)) {
357                 return status;
358         }
359
360         state->transport->write_send = rpc_np_write_send;
361         state->transport->write_recv = rpc_np_write_recv;
362         state->transport->read_send = rpc_np_read_send;
363         state->transport->read_recv = rpc_np_read_recv;
364         state->transport->trans_send = rpc_np_trans_send;
365         state->transport->trans_recv = rpc_np_trans_recv;
366
367         *presult = talloc_move(mem_ctx, &state->transport);
368         return NT_STATUS_OK;
369 }
370
371 NTSTATUS rpc_transport_np_init(TALLOC_CTX *mem_ctx, struct cli_state *cli,
372                                const struct ndr_syntax_id *abstract_syntax,
373                                struct rpc_cli_transport **presult)
374 {
375         TALLOC_CTX *frame = talloc_stackframe();
376         struct event_context *ev;
377         struct async_req *req;
378         NTSTATUS status;
379
380         ev = event_context_init(frame);
381         if (ev == NULL) {
382                 status = NT_STATUS_NO_MEMORY;
383                 goto fail;
384         }
385
386         req = rpc_transport_np_init_send(frame, ev, cli, abstract_syntax);
387         if (req == NULL) {
388                 status = NT_STATUS_NO_MEMORY;
389                 goto fail;
390         }
391
392         while (req->state < ASYNC_REQ_DONE) {
393                 event_loop_once(ev);
394         }
395
396         status = rpc_transport_np_init_recv(req, mem_ctx, presult);
397  fail:
398         TALLOC_FREE(frame);
399         return status;
400 }
401
402 struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p)
403 {
404         struct rpc_transport_np_state *state = talloc_get_type(
405                 p->transport->priv, struct rpc_transport_np_state);
406
407         if (state == NULL) {
408                 return NULL;
409         }
410         return state->cli;
411 }