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