30231c1ee3d9868f3f3539379b45a1f142350900
[metze/samba/wip.git] / librpc / rpc / pipe_handle.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    dcerpc pipe handle functions
5
6    Copyright (C) Stefan Metzmacher 2010,2013
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include <tevent.h>
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "librpc/rpc/dcerpc.h"
26 #include "rpc_common.h"
27
28 struct dcerpc_pipe_handle_connection {
29         const char *chunk_struct_name;
30         size_t chunk_struct_size;
31         struct dcerpc_pipe_handle *p;
32         bool push;
33 };
34
35 struct dcerpc_pipe_handle {
36         void *private_data;
37         const struct dcerpc_pipe_handle_ops *ops;
38         const char *location;
39         struct dcerpc_pipe_handle_connection *pc;
40         struct tevent_req *current_req;
41 };
42
43 struct dcerpc_pipe_handle_connection *dcerpc_pipe_handle_connection_create(
44                                         TALLOC_CTX *mem_ctx,
45                                         const char *chunk_struct_name,
46                                         size_t chunk_struct_size)
47 {
48         struct dcerpc_pipe_handle_connection *pc;
49
50         pc = talloc_zero(mem_ctx, struct dcerpc_pipe_handle_connection);
51         if (pc == NULL) {
52                 return NULL;
53         }
54
55         pc->chunk_struct_name = talloc_strdup(pc, chunk_struct_name);
56         if (pc->chunk_struct_name == NULL) {
57                 TALLOC_FREE(pc);
58                 return NULL;
59         }
60
61         pc->chunk_struct_size = chunk_struct_size;
62
63         return pc;
64 }
65
66 bool _dcerpc_pipe_handle_connection_connect(
67                                 struct dcerpc_pipe_handle_connection *pc,
68                                 const char *chunk_struct_name,
69                                 size_t chunk_struct_size,
70                                 struct dcerpc_pipe_handle *p,
71                                 bool push)
72 {
73         if (pc->chunk_struct_size != chunk_struct_size) {
74                 return false;
75         }
76
77         if (strcmp(pc->chunk_struct_name, chunk_struct_name) != 0) {
78                 return false;
79         }
80
81         pc->p = p;
82         p->pc = pc;
83
84         pc->push = push;
85
86         return true;
87 }
88
89 void dcerpc_pipe_handle_connection_disconnect(
90                                 struct dcerpc_pipe_handle_connection *pc)
91 {
92         if (pc == NULL) {
93                 return;
94         }
95
96         if (pc->p != NULL) {
97                 pc->p->pc = NULL;
98         }
99
100         pc->p = NULL;
101 }
102
103 static int dcerpc_pipe_handle_destructor(struct dcerpc_pipe_handle *p)
104 {
105         dcerpc_pipe_handle_connection_disconnect(p->pc);
106
107         if (p->current_req) {
108                 tevent_req_received(p->current_req);
109         }
110
111         return 0;
112 }
113
114 struct dcerpc_pipe_handle *_dcerpc_pipe_handle_create(
115                                         TALLOC_CTX *mem_ctx,
116                                         const struct dcerpc_pipe_handle_ops *ops,
117                                         void *pstate,
118                                         size_t psize,
119                                         const char *type,
120                                         const char *location)
121 {
122         struct dcerpc_pipe_handle *p;
123         void **ppstate = (void **)pstate;
124         void *state;
125
126         p = talloc_zero(mem_ctx, struct dcerpc_pipe_handle);
127         if (p == NULL) {
128                 return NULL;
129         }
130         p->ops          = ops;
131         p->location     = location;
132
133         state = talloc_zero_size(p, psize);
134         if (state == NULL) {
135                 talloc_free(p);
136                 return NULL;
137         }
138         talloc_set_name_const(state, type);
139
140         p->private_data = state;
141
142         talloc_set_destructor(p, dcerpc_pipe_handle_destructor);
143
144         *ppstate = state;
145         return p;
146 }
147
148 void *_dcerpc_pipe_handle_data(struct dcerpc_pipe_handle *p)
149 {
150         return p->private_data;
151 }
152
153 struct dcerpc_pipe_handle_push_state {
154         const struct dcerpc_pipe_handle_ops *ops;
155         struct dcerpc_pipe_handle *p;
156 };
157
158 static int dcerpc_pipe_handle_push_state_destructor(
159         struct dcerpc_pipe_handle_push_state *state)
160 {
161         if (state->p) {
162                 state->p->current_req = NULL;
163         }
164
165         return 0;
166 }
167
168 static void dcerpc_pipe_handle_push_done(struct tevent_req *subreq);
169
170 struct tevent_req *dcerpc_pipe_handle_push_send(TALLOC_CTX *mem_ctx,
171                                         struct tevent_context *ev,
172                                         struct dcerpc_pipe_handle_connection *pc,
173                                         const void *chunk_ptr)
174 {
175         struct dcerpc_pipe_handle *p = pc->p;
176         struct tevent_req *req;
177         struct dcerpc_pipe_handle_push_state *state;
178         struct tevent_req *subreq;
179
180         req = tevent_req_create(mem_ctx, &state,
181                                 struct dcerpc_pipe_handle_push_state);
182         if (req == NULL) {
183                 return NULL;
184         }
185
186         if (p == NULL) {
187                 tevent_req_nterror(req, NT_STATUS_RPC_PIPE_DISCIPLINE_ERROR);
188                 return tevent_req_post(req, ev);
189         }
190
191         if (!pc->push) {
192                 tevent_req_nterror(req, NT_STATUS_RPC_PIPE_DISCIPLINE_ERROR);
193                 return tevent_req_post(req, ev);
194         }
195
196         if (p->current_req) {
197                 tevent_req_nterror(req, NT_STATUS_RPC_PIPE_DISCIPLINE_ERROR);
198                 return tevent_req_post(req, ev);
199         }
200
201         state->ops = p->ops;
202         state->p = p;
203
204         talloc_set_destructor(state, dcerpc_pipe_handle_push_state_destructor);
205         p->current_req = req;
206
207         subreq = p->ops->chunk_push_send(state, ev, p, chunk_ptr);
208         if (tevent_req_nomem(subreq, req)) {
209                 return tevent_req_post(req, ev);
210         }
211
212         tevent_req_set_callback(subreq, dcerpc_pipe_handle_push_done, req);
213
214         return req;
215 }
216
217 static void dcerpc_pipe_handle_push_done(struct tevent_req *subreq)
218 {
219         struct tevent_req *req =
220                 tevent_req_callback_data(subreq,
221                 struct tevent_req);
222         struct dcerpc_pipe_handle_push_state *state =
223                 tevent_req_data(req,
224                 struct dcerpc_pipe_handle_push_state);
225         NTSTATUS status;
226
227         status = state->ops->chunk_push_recv(subreq);
228         TALLOC_FREE(subreq);
229         if (tevent_req_nterror(req, status)) {
230                 return;
231         }
232
233         tevent_req_done(req);
234 }
235
236 NTSTATUS dcerpc_pipe_handle_push_recv(struct tevent_req *req)
237 {
238         return tevent_req_simple_recv_ntstatus(req);
239 }
240
241 struct dcerpc_pipe_handle_pull_state {
242         const struct dcerpc_pipe_handle_ops *ops;
243         struct dcerpc_pipe_handle *p;
244 };
245
246 static int dcerpc_pipe_handle_pull_state_destructor(
247         struct dcerpc_pipe_handle_pull_state *state)
248 {
249         if (state->p) {
250                 state->p->current_req = NULL;
251         }
252
253         return 0;
254 }
255
256 static void dcerpc_pipe_handle_pull_done(struct tevent_req *subreq);
257
258 struct tevent_req *dcerpc_pipe_handle_pull_send(TALLOC_CTX *mem_ctx,
259                                         struct tevent_context *ev,
260                                         struct dcerpc_pipe_handle_connection *pc,
261                                         void *chunk_mem,
262                                         void *chunk_ptr)
263 {
264         struct dcerpc_pipe_handle *p = pc->p;
265         struct tevent_req *req;
266         struct dcerpc_pipe_handle_pull_state *state;
267         struct tevent_req *subreq;
268
269         req = tevent_req_create(mem_ctx, &state,
270                                 struct dcerpc_pipe_handle_pull_state);
271         if (req == NULL) {
272                 return NULL;
273         }
274
275         if (p == NULL) {
276                 tevent_req_nterror(req, NT_STATUS_RPC_PIPE_DISCIPLINE_ERROR);
277                 return tevent_req_post(req, ev);
278         }
279
280         if (pc->push) {
281                 tevent_req_nterror(req, NT_STATUS_RPC_PIPE_DISCIPLINE_ERROR);
282                 return tevent_req_post(req, ev);
283         }
284
285         if (p->current_req) {
286                 tevent_req_nterror(req, NT_STATUS_RPC_PIPE_DISCIPLINE_ERROR);
287                 return tevent_req_post(req, ev);
288         }
289
290         state->ops = p->ops;
291         state->p = p;
292
293         talloc_set_destructor(state, dcerpc_pipe_handle_pull_state_destructor);
294         p->current_req = req;
295
296         subreq = p->ops->chunk_pull_send(state, ev, p, chunk_mem, chunk_ptr);
297         if (tevent_req_nomem(subreq, req)) {
298                 return tevent_req_post(req, ev);
299         }
300
301         tevent_req_set_callback(subreq, dcerpc_pipe_handle_pull_done, req);
302
303         return req;
304 }
305
306 static void dcerpc_pipe_handle_pull_done(struct tevent_req *subreq)
307 {
308         struct tevent_req *req =
309                 tevent_req_callback_data(subreq,
310                 struct tevent_req);
311         struct dcerpc_pipe_handle_pull_state *state =
312                 tevent_req_data(req,
313                 struct dcerpc_pipe_handle_pull_state);
314         NTSTATUS status;
315
316         status = state->ops->chunk_pull_recv(subreq);
317         TALLOC_FREE(subreq);
318         if (tevent_req_nterror(req, status)) {
319                 return;
320         }
321
322         tevent_req_done(req);
323 }
324
325 NTSTATUS dcerpc_pipe_handle_pull_recv(struct tevent_req *req)
326 {
327         return tevent_req_simple_recv_ntstatus(req);
328 }