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