Add the named pipe rpc client transport
[metze/samba/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_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 NTSTATUS rpc_transport_np_init(TALLOC_CTX *mem_ctx, struct cli_state *cli,
276                                const struct ndr_syntax_id *abstract_syntax,
277                                struct rpc_cli_transport **presult)
278 {
279         struct rpc_cli_transport *result;
280         struct rpc_transport_np_state *state;
281         int fnum;
282
283         result = talloc(mem_ctx, struct rpc_cli_transport);
284         if (result == NULL) {
285                 return NT_STATUS_NO_MEMORY;
286         }
287         state = talloc(result, struct rpc_transport_np_state);
288         if (state == NULL) {
289                 TALLOC_FREE(result);
290                 return NT_STATUS_NO_MEMORY;
291         }
292         result->priv = state;
293
294         state->cli = cli;
295         state->pipe_name = cli_get_pipe_name_from_iface(
296                 state, abstract_syntax);
297
298         fnum = cli_nt_create(cli, state->pipe_name, DESIRED_ACCESS_PIPE);
299         if (fnum == -1) {
300                 DEBUG(3,("rpc_pipe_open_np: cli_nt_create failed on pipe %s "
301                          "to machine %s.  Error was %s\n", state->pipe_name,
302                          cli->desthost, cli_errstr(cli)));
303                 TALLOC_FREE(result);
304                 return cli_get_nt_error(cli);
305         }
306         state->fnum = fnum;
307         talloc_set_destructor(state, rpc_transport_np_state_destructor);
308
309         result->write_send = rpc_np_write_send;
310         result->write_recv = rpc_np_write_recv;
311         result->read_send = rpc_np_read_send;
312         result->read_recv = rpc_np_read_recv;
313         result->trans_send = rpc_np_trans_send;
314         result->trans_recv = rpc_np_trans_recv;
315
316         *presult = result;
317         return NT_STATUS_OK;
318 }
319
320 struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p)
321 {
322         struct rpc_transport_np_state *state = talloc_get_type(
323                 p->transport->priv, struct rpc_transport_np_state);
324
325         if (state == NULL) {
326                 return NULL;
327         }
328         return state->cli;
329 }