s3: fix crash in winbindd
[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
35         if (s->cli->fd == -1) {
36                 DEBUG(10, ("socket was closed, no need to send close request.\n"));
37                 return 0;
38         }
39         
40         ret = cli_close(s->cli, s->fnum);
41         if (!ret) {
42                 DEBUG(1, ("rpc_transport_np_state_destructor: cli_close "
43                           "failed on pipe %s. Error was %s\n", s->pipe_name,
44                           cli_errstr(s->cli)));
45         }
46         DEBUG(10, ("rpc_pipe_destructor: closed %s\n", s->pipe_name));
47         /*
48          * We can't do much on failure
49          */
50         return 0;
51 }
52
53 struct rpc_np_write_state {
54         size_t size;
55         size_t written;
56 };
57
58 static void rpc_np_write_done(struct tevent_req *subreq);
59
60 static struct tevent_req *rpc_np_write_send(TALLOC_CTX *mem_ctx,
61                                             struct event_context *ev,
62                                             const uint8_t *data, size_t size,
63                                             void *priv)
64 {
65         struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
66                 priv, struct rpc_transport_np_state);
67         struct tevent_req *req, *subreq;
68         struct rpc_np_write_state *state;
69
70         req = tevent_req_create(mem_ctx, &state, struct rpc_np_write_state);
71         if (req == NULL) {
72                 return NULL;
73         }
74         state->size = size;
75
76         subreq = cli_write_andx_send(mem_ctx, ev, np_transport->cli,
77                                      np_transport->fnum,
78                                      8, /* 8 means message mode. */
79                                      data, 0, size);
80         if (tevent_req_nomem(subreq, req)) {
81                 return tevent_req_post(req, ev);
82         }
83         tevent_req_set_callback(subreq, rpc_np_write_done, req);
84         return req;
85 }
86
87 static void rpc_np_write_done(struct tevent_req *subreq)
88 {
89         struct tevent_req *req = tevent_req_callback_data(
90                 subreq, struct tevent_req);
91         struct rpc_np_write_state *state = tevent_req_data(
92                 req, struct rpc_np_write_state);
93         NTSTATUS status;
94
95         status = cli_write_andx_recv(subreq, &state->written);
96         TALLOC_FREE(subreq);
97         if (!NT_STATUS_IS_OK(status)) {
98                 tevent_req_nterror(req, status);
99                 return;
100         }
101         tevent_req_done(req);
102 }
103
104 static NTSTATUS rpc_np_write_recv(struct tevent_req *req, ssize_t *pwritten)
105 {
106         struct rpc_np_write_state *state = tevent_req_data(
107                 req, struct rpc_np_write_state);
108         NTSTATUS status;
109
110         if (tevent_req_is_nterror(req, &status)) {
111                 return status;
112         }
113         *pwritten = state->written;
114         return NT_STATUS_OK;
115 }
116
117 struct rpc_np_read_state {
118         uint8_t *data;
119         size_t size;
120         ssize_t received;
121 };
122
123 static void rpc_np_read_done(struct tevent_req *subreq);
124
125 static struct tevent_req *rpc_np_read_send(TALLOC_CTX *mem_ctx,
126                                            struct event_context *ev,
127                                            uint8_t *data, size_t size,
128                                            void *priv)
129 {
130         struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
131                 priv, struct rpc_transport_np_state);
132         struct tevent_req *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         tevent_req_set_callback(subreq, rpc_np_read_done, req);
148         return req;
149  fail:
150         TALLOC_FREE(req);
151         return NULL;
152 }
153
154 static void rpc_np_read_done(struct tevent_req *subreq)
155 {
156         struct tevent_req *req = tevent_req_callback_data(
157                 subreq, 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 tevent_req *subreq);
207
208 static struct tevent_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 tevent_req *req, *subreq;
217         struct rpc_np_trans_state *state;
218
219         req = tevent_req_create(mem_ctx, &state, struct rpc_np_trans_state);
220         if (req == NULL) {
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         tevent_req_set_callback(subreq, rpc_np_trans_done, req);
235         return req;
236
237  fail:
238         TALLOC_FREE(req);
239         return NULL;
240 }
241
242 static void rpc_np_trans_done(struct tevent_req *subreq)
243 {
244         struct tevent_req *req = tevent_req_callback_data(
245                 subreq, struct tevent_req);
246         struct rpc_np_trans_state *state = tevent_req_data(
247                 req, 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                 tevent_req_nterror(req, status);
255                 return;
256         }
257         tevent_req_done(req);
258 }
259
260 static NTSTATUS rpc_np_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
261                                   uint8_t **prdata, uint32_t *prdata_len)
262 {
263         struct rpc_np_trans_state *state = tevent_req_data(
264                 req, struct rpc_np_trans_state);
265         NTSTATUS status;
266
267         if (tevent_req_is_nterror(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 tevent_req *subreq);
281
282 struct tevent_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 tevent_req *req, *subreq;
288         struct rpc_transport_np_init_state *state;
289
290         req = tevent_req_create(mem_ctx, &state,
291                                 struct rpc_transport_np_init_state);
292         if (req == NULL) {
293                 return NULL;
294         }
295
296         state->transport = talloc(state, struct rpc_cli_transport);
297         if (tevent_req_nomem(state->transport, req)) {
298                 return tevent_req_post(req, ev);
299         }
300         state->transport_np = talloc(state->transport,
301                                      struct rpc_transport_np_state);
302         if (tevent_req_nomem(state->transport_np, req)) {
303                 return tevent_req_post(req, ev);
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 (tevent_req_nomem(subreq, req)) {
316                 return tevent_req_post(req, ev);
317         }
318         tevent_req_set_callback(subreq, rpc_transport_np_init_pipe_open,
319                                 req);
320         return req;
321 }
322
323 static void rpc_transport_np_init_pipe_open(struct tevent_req *subreq)
324 {
325         struct tevent_req *req = tevent_req_callback_data(
326                 subreq, struct tevent_req);
327         struct rpc_transport_np_init_state *state = tevent_req_data(
328                 req, struct rpc_transport_np_init_state);
329         NTSTATUS status;
330
331         status = cli_ntcreate_recv(subreq, &state->transport_np->fnum);
332         TALLOC_FREE(subreq);
333         if (!NT_STATUS_IS_OK(status)) {
334                 tevent_req_nterror(req, status);
335                 return;
336         }
337
338         talloc_set_destructor(state->transport_np,
339                               rpc_transport_np_state_destructor);
340         tevent_req_done(req);
341 }
342
343 NTSTATUS rpc_transport_np_init_recv(struct tevent_req *req,
344                                     TALLOC_CTX *mem_ctx,
345                                     struct rpc_cli_transport **presult)
346 {
347         struct rpc_transport_np_init_state *state = tevent_req_data(
348                 req, struct rpc_transport_np_init_state);
349         NTSTATUS status;
350
351         if (tevent_req_is_nterror(req, &status)) {
352                 return status;
353         }
354
355         state->transport->write_send = rpc_np_write_send;
356         state->transport->write_recv = rpc_np_write_recv;
357         state->transport->read_send = rpc_np_read_send;
358         state->transport->read_recv = rpc_np_read_recv;
359         state->transport->trans_send = rpc_np_trans_send;
360         state->transport->trans_recv = rpc_np_trans_recv;
361
362         *presult = talloc_move(mem_ctx, &state->transport);
363         return NT_STATUS_OK;
364 }
365
366 NTSTATUS rpc_transport_np_init(TALLOC_CTX *mem_ctx, struct cli_state *cli,
367                                const struct ndr_syntax_id *abstract_syntax,
368                                struct rpc_cli_transport **presult)
369 {
370         TALLOC_CTX *frame = talloc_stackframe();
371         struct event_context *ev;
372         struct tevent_req *req;
373         NTSTATUS status = NT_STATUS_OK;
374
375         ev = event_context_init(frame);
376         if (ev == NULL) {
377                 status = NT_STATUS_NO_MEMORY;
378                 goto fail;
379         }
380
381         req = rpc_transport_np_init_send(frame, ev, cli, abstract_syntax);
382         if (req == NULL) {
383                 status = NT_STATUS_NO_MEMORY;
384                 goto fail;
385         }
386
387         if (!tevent_req_poll(req, ev)) {
388                 status = map_nt_error_from_unix(errno);
389                 goto fail;
390         }
391
392         status = rpc_transport_np_init_recv(req, mem_ctx, presult);
393  fail:
394         TALLOC_FREE(frame);
395         return status;
396 }
397
398 struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p)
399 {
400         struct rpc_transport_np_state *state = talloc_get_type(
401                 p->transport->priv, struct rpc_transport_np_state);
402
403         if (state == NULL) {
404                 return NULL;
405         }
406         return state->cli;
407 }