a11e0e0f22ff5203f31d96a3a33788d0725789b4
[tprouty/samba.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_error(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_error(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 async_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 async_req *result, *subreq;
131         struct rpc_np_read_state *state;
132
133         if (!async_req_setup(mem_ctx, &result, &state,
134                              struct rpc_np_read_state)) {
135                 return NULL;
136         }
137         state->data = data;
138         state->size = size;
139
140         subreq = cli_read_andx_send(mem_ctx, ev, np_transport->cli,
141                                     np_transport->fnum, 0, size);
142         if (subreq == NULL) {
143                 goto fail;
144         }
145         subreq->async.fn = rpc_np_read_done;
146         subreq->async.priv = result;
147         return result;
148  fail:
149         TALLOC_FREE(result);
150         return NULL;
151 }
152
153 static void rpc_np_read_done(struct async_req *subreq)
154 {
155         struct async_req *req = talloc_get_type_abort(
156                 subreq->async.priv, struct async_req);
157         struct rpc_np_read_state *state = talloc_get_type_abort(
158                 req->private_data, struct rpc_np_read_state);
159         NTSTATUS status;
160         uint8_t *rcvbuf;
161
162         status = cli_read_andx_recv(subreq, &state->received, &rcvbuf);
163         /*
164          * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
165          * child of that.
166          */
167         if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
168                 status = NT_STATUS_OK;
169         }
170         if (!NT_STATUS_IS_OK(status)) {
171                 TALLOC_FREE(subreq);
172                 async_req_error(req, status);
173                 return;
174         }
175
176         if (state->received > state->size) {
177                 TALLOC_FREE(subreq);
178                 async_req_error(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
179                 return;
180         }
181
182         memcpy(state->data, rcvbuf, state->received);
183         async_req_done(req);
184 }
185
186 static NTSTATUS rpc_np_read_recv(struct async_req *req, ssize_t *preceived)
187 {
188         struct rpc_np_read_state *state = talloc_get_type_abort(
189                 req->private_data, struct rpc_np_read_state);
190         NTSTATUS status;
191
192         if (async_req_is_error(req, &status)) {
193                 return status;
194         }
195         *preceived = state->received;
196         return NT_STATUS_OK;
197 }
198
199 struct rpc_np_trans_state {
200         uint16_t setup[2];
201         uint8_t *rdata;
202         uint32_t rdata_len;
203 };
204
205 static void rpc_np_trans_done(struct async_req *subreq);
206
207 static struct async_req *rpc_np_trans_send(TALLOC_CTX *mem_ctx,
208                                            struct event_context *ev,
209                                            uint8_t *data, size_t data_len,
210                                            uint32_t max_rdata_len,
211                                            void *priv)
212 {
213         struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
214                 priv, struct rpc_transport_np_state);
215         struct async_req *result, *subreq;
216         struct rpc_np_trans_state *state;
217
218         if (!async_req_setup(mem_ctx, &result, &state,
219                              struct rpc_np_trans_state)) {
220                 return NULL;
221         }
222
223         SSVAL(state->setup+0, 0, TRANSACT_DCERPCCMD);
224         SSVAL(state->setup+1, 0, np_transport->fnum);
225
226         subreq = cli_trans_send(
227                 state, ev, np_transport->cli, SMBtrans,
228                 "\\PIPE\\", 0, 0, 0, state->setup, 2, 0,
229                 NULL, 0, 0, data, data_len, max_rdata_len);
230         if (subreq == NULL) {
231                 goto fail;
232         }
233         subreq->async.fn = rpc_np_trans_done;
234         subreq->async.priv = result;
235         return result;
236
237  fail:
238         TALLOC_FREE(result);
239         return NULL;
240 }
241
242 static void rpc_np_trans_done(struct async_req *subreq)
243 {
244         struct async_req *req = talloc_get_type_abort(
245                 subreq->async.priv, struct async_req);
246         struct rpc_np_trans_state *state = talloc_get_type_abort(
247                 req->private_data, struct rpc_np_trans_state);
248         NTSTATUS status;
249
250         status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL,
251                                 &state->rdata, &state->rdata_len);
252         TALLOC_FREE(subreq);
253         if (!NT_STATUS_IS_OK(status)) {
254                 async_req_error(req, status);
255                 return;
256         }
257         async_req_done(req);
258 }
259
260 static NTSTATUS rpc_np_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
261                                   uint8_t **prdata, uint32_t *prdata_len)
262 {
263         struct rpc_np_trans_state *state = talloc_get_type_abort(
264                 req->private_data, struct rpc_np_trans_state);
265         NTSTATUS status;
266
267         if (async_req_is_error(req, &status)) {
268                 return status;
269         }
270         *prdata = talloc_move(mem_ctx, &state->rdata);
271         *prdata_len = state->rdata_len;
272         return NT_STATUS_OK;
273 }
274
275 struct rpc_transport_np_init_state {
276         struct rpc_cli_transport *transport;
277         struct rpc_transport_np_state *transport_np;
278 };
279
280 static void rpc_transport_np_init_pipe_open(struct async_req *subreq);
281
282 struct async_req *rpc_transport_np_init_send(TALLOC_CTX *mem_ctx,
283                                              struct event_context *ev,
284                                              struct cli_state *cli,
285                                              const struct ndr_syntax_id *abstract_syntax)
286 {
287         struct async_req *result, *subreq;
288         struct rpc_transport_np_init_state *state;
289
290         if (!async_req_setup(mem_ctx, &result, &state,
291                              struct rpc_transport_np_init_state)) {
292                 return NULL;
293         }
294
295         state->transport = talloc(state, struct rpc_cli_transport);
296         if (state->transport == NULL) {
297                 goto fail;
298         }
299         state->transport_np = talloc(state->transport,
300                                      struct rpc_transport_np_state);
301         if (state->transport_np == NULL) {
302                 goto fail;
303         }
304         state->transport->priv = state->transport_np;
305
306         state->transport_np->pipe_name = get_pipe_name_from_iface(
307                 abstract_syntax);
308         state->transport_np->cli = cli;
309
310         subreq = cli_ntcreate_send(
311                 state, ev, cli, state->transport_np->pipe_name, 0,
312                 DESIRED_ACCESS_PIPE, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
313                 FILE_OPEN, 0, 0);
314         if (subreq == NULL) {
315                 goto fail;
316         }
317         subreq->async.fn = rpc_transport_np_init_pipe_open;
318         subreq->async.priv = result;
319         return result;
320
321  fail:
322         TALLOC_FREE(result);
323         return NULL;
324 }
325
326 static void rpc_transport_np_init_pipe_open(struct async_req *subreq)
327 {
328         struct async_req *req = talloc_get_type_abort(
329                 subreq->async.priv, struct async_req);
330         struct rpc_transport_np_init_state *state = talloc_get_type_abort(
331                 req->private_data, struct rpc_transport_np_init_state);
332         NTSTATUS status;
333
334         status = cli_ntcreate_recv(subreq, &state->transport_np->fnum);
335         TALLOC_FREE(subreq);
336         if (!NT_STATUS_IS_OK(status)) {
337                 async_req_error(req, status);
338                 return;
339         }
340
341         talloc_set_destructor(state->transport_np,
342                               rpc_transport_np_state_destructor);
343         async_req_done(req);
344 }
345
346 NTSTATUS rpc_transport_np_init_recv(struct async_req *req,
347                                     TALLOC_CTX *mem_ctx,
348                                     struct rpc_cli_transport **presult)
349 {
350         struct rpc_transport_np_init_state *state = talloc_get_type_abort(
351                 req->private_data, struct rpc_transport_np_init_state);
352         NTSTATUS status;
353
354         if (async_req_is_error(req, &status)) {
355                 return status;
356         }
357
358         state->transport->write_send = rpc_np_write_send;
359         state->transport->write_recv = rpc_np_write_recv;
360         state->transport->read_send = rpc_np_read_send;
361         state->transport->read_recv = rpc_np_read_recv;
362         state->transport->trans_send = rpc_np_trans_send;
363         state->transport->trans_recv = rpc_np_trans_recv;
364
365         *presult = talloc_move(mem_ctx, &state->transport);
366         return NT_STATUS_OK;
367 }
368
369 NTSTATUS rpc_transport_np_init(TALLOC_CTX *mem_ctx, struct cli_state *cli,
370                                const struct ndr_syntax_id *abstract_syntax,
371                                struct rpc_cli_transport **presult)
372 {
373         TALLOC_CTX *frame = talloc_stackframe();
374         struct event_context *ev;
375         struct async_req *req;
376         NTSTATUS status;
377
378         ev = event_context_init(frame);
379         if (ev == NULL) {
380                 status = NT_STATUS_NO_MEMORY;
381                 goto fail;
382         }
383
384         req = rpc_transport_np_init_send(frame, ev, cli, abstract_syntax);
385         if (req == NULL) {
386                 status = NT_STATUS_NO_MEMORY;
387                 goto fail;
388         }
389
390         while (req->state < ASYNC_REQ_DONE) {
391                 event_loop_once(ev);
392         }
393
394         status = rpc_transport_np_init_recv(req, mem_ctx, presult);
395  fail:
396         TALLOC_FREE(frame);
397         return status;
398 }
399
400 struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p)
401 {
402         struct rpc_transport_np_state *state = talloc_get_type(
403                 p->transport->priv, struct rpc_transport_np_state);
404
405         if (state == NULL) {
406                 return NULL;
407         }
408         return state->cli;
409 }