rpc_server: Init local_server_* in make_internal_rpc_pipe_socketpair
[metze/samba/wip.git] / source3 / rpc_server / srv_pipe_hnd.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Andrew Tridgell              1992-1998,
5  *  Largely re-written : 2005
6  *  Copyright (C) Jeremy Allison                1998 - 2005
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 "fake_file.h"
24 #include "rpc_dce.h"
25 #include "ntdomain.h"
26 #include "rpc_server/rpc_ncacn_np.h"
27 #include "rpc_server/srv_pipe_hnd.h"
28 #include "rpc_server/srv_pipe.h"
29 #include "rpc_server/rpc_server.h"
30 #include "rpc_server/rpc_config.h"
31 #include "../lib/tsocket/tsocket.h"
32 #include "../lib/util/tevent_ntstatus.h"
33 #include "librpc/ndr/ndr_table.h"
34
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_RPC_SRV
37
38 bool fsp_is_np(struct files_struct *fsp)
39 {
40         enum FAKE_FILE_TYPE type;
41
42         if ((fsp == NULL) || (fsp->fake_file_handle == NULL)) {
43                 return false;
44         }
45
46         type = fsp->fake_file_handle->type;
47
48         return (type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY);
49 }
50
51 NTSTATUS np_open(TALLOC_CTX *mem_ctx, const char *name,
52                  const struct tsocket_address *remote_client_address,
53                  const struct tsocket_address *local_server_address,
54                  struct auth_session_info *session_info,
55                  struct tevent_context *ev_ctx,
56                  struct messaging_context *msg_ctx,
57                  struct fake_file_handle **phandle)
58 {
59         enum rpc_service_mode_e pipe_mode;
60         const char **proxy_list;
61         struct fake_file_handle *handle;
62         struct ndr_syntax_id syntax;
63         struct npa_state *npa = NULL;
64         NTSTATUS status;
65         bool ok;
66
67         proxy_list = lp_parm_string_list(-1, "np", "proxy", NULL);
68
69         handle = talloc(mem_ctx, struct fake_file_handle);
70         if (handle == NULL) {
71                 return NT_STATUS_NO_MEMORY;
72         }
73
74         /* Check what is the server type for this pipe.
75            Defaults to "embedded" */
76         pipe_mode = rpc_service_mode(name);
77
78         /* Still support the old method for defining external servers */
79         if ((proxy_list != NULL) && str_list_check_ci(proxy_list, name)) {
80                 pipe_mode = RPC_SERVICE_MODE_EXTERNAL;
81         }
82
83         switch (pipe_mode) {
84         case RPC_SERVICE_MODE_EXTERNAL:
85                 status = make_external_rpc_pipe(handle,
86                                                 name,
87                                                 remote_client_address,
88                                                 local_server_address,
89                                                 session_info,
90                                                 &npa);
91                 if (!NT_STATUS_IS_OK(status)) {
92                         talloc_free(handle);
93                         return status;
94                 }
95
96                 handle->private_data = (void *)npa;
97                 handle->type = FAKE_FILE_TYPE_NAMED_PIPE_PROXY;
98
99                 break;
100         case RPC_SERVICE_MODE_EMBEDDED:
101                 /* Check if we handle this pipe internally */
102                 ok = is_known_pipename(name, &syntax);
103                 if (!ok) {
104                         DEBUG(2, ("'%s' is not a registered pipe!\n", name));
105                         talloc_free(handle);
106                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
107                 }
108
109                 status = make_internal_rpc_pipe_socketpair(
110                         handle,
111                         ev_ctx,
112                         msg_ctx,
113                         name,
114                         &syntax,
115                         remote_client_address,
116                         local_server_address,
117                         session_info,
118                         &npa);
119                 if (!NT_STATUS_IS_OK(status)) {
120                         talloc_free(handle);
121                         return status;
122                 }
123
124                 handle->private_data = (void *)npa;
125                 handle->type = FAKE_FILE_TYPE_NAMED_PIPE_PROXY;
126
127                 break;
128         case RPC_SERVICE_MODE_DISABLED:
129                 talloc_free(handle);
130                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
131         }
132
133         *phandle = handle;
134
135         return NT_STATUS_OK;
136 }
137
138 bool np_read_in_progress(struct fake_file_handle *handle)
139 {
140         if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
141                 struct npa_state *p =
142                         talloc_get_type_abort(handle->private_data,
143                                               struct npa_state);
144                 size_t read_count;
145
146                 read_count = tevent_queue_length(p->read_queue);
147                 if (read_count > 0) {
148                         return true;
149                 }
150
151                 return false;
152         }
153
154         return false;
155 }
156
157 struct np_write_state {
158         struct tevent_context *ev;
159         struct npa_state *p;
160         struct iovec iov;
161         ssize_t nwritten;
162 };
163
164 static void np_write_done(struct tevent_req *subreq);
165
166 struct tevent_req *np_write_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
167                                  struct fake_file_handle *handle,
168                                  const uint8_t *data, size_t len)
169 {
170         struct tevent_req *req;
171         struct np_write_state *state;
172         NTSTATUS status;
173
174         DEBUG(6, ("np_write_send: len: %d\n", (int)len));
175         dump_data(50, data, len);
176
177         req = tevent_req_create(mem_ctx, &state, struct np_write_state);
178         if (req == NULL) {
179                 return NULL;
180         }
181
182         if (len == 0) {
183                 state->nwritten = 0;
184                 status = NT_STATUS_OK;
185                 goto post_status;
186         }
187
188         if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
189                 struct npa_state *p = talloc_get_type_abort(
190                         handle->private_data, struct npa_state);
191                 struct tevent_req *subreq;
192
193                 state->ev = ev;
194                 state->p = p;
195                 state->iov.iov_base = discard_const_p(void, data);
196                 state->iov.iov_len = len;
197
198                 subreq = tstream_writev_queue_send(state, ev,
199                                                    p->stream,
200                                                    p->write_queue,
201                                                    &state->iov, 1);
202                 if (subreq == NULL) {
203                         goto fail;
204                 }
205                 tevent_req_set_callback(subreq, np_write_done, req);
206                 return req;
207         }
208
209         status = NT_STATUS_INVALID_HANDLE;
210  post_status:
211         if (NT_STATUS_IS_OK(status)) {
212                 tevent_req_done(req);
213         } else {
214                 tevent_req_nterror(req, status);
215         }
216         return tevent_req_post(req, ev);
217  fail:
218         TALLOC_FREE(req);
219         return NULL;
220 }
221
222 static void np_write_done(struct tevent_req *subreq)
223 {
224         struct tevent_req *req = tevent_req_callback_data(
225                 subreq, struct tevent_req);
226         struct np_write_state *state = tevent_req_data(
227                 req, struct np_write_state);
228         ssize_t received;
229         int err;
230
231         received = tstream_writev_queue_recv(subreq, &err);
232         if (received < 0) {
233                 tevent_req_nterror(req, map_nt_error_from_unix(err));
234                 return;
235         }
236         state->nwritten = received;
237         tevent_req_done(req);
238 }
239
240 NTSTATUS np_write_recv(struct tevent_req *req, ssize_t *pnwritten)
241 {
242         struct np_write_state *state = tevent_req_data(
243                 req, struct np_write_state);
244         NTSTATUS status;
245
246         if (tevent_req_is_nterror(req, &status)) {
247                 return status;
248         }
249         *pnwritten = state->nwritten;
250         return NT_STATUS_OK;
251 }
252
253 struct np_ipc_readv_next_vector_state {
254         uint8_t *buf;
255         size_t len;
256         off_t ofs;
257         size_t remaining;
258 };
259
260 static void np_ipc_readv_next_vector_init(struct np_ipc_readv_next_vector_state *s,
261                                           uint8_t *buf, size_t len)
262 {
263         ZERO_STRUCTP(s);
264
265         s->buf = buf;
266         s->len = MIN(len, UINT16_MAX);
267 }
268
269 static int np_ipc_readv_next_vector(struct tstream_context *stream,
270                                     void *private_data,
271                                     TALLOC_CTX *mem_ctx,
272                                     struct iovec **_vector,
273                                     size_t *count)
274 {
275         struct np_ipc_readv_next_vector_state *state =
276                 (struct np_ipc_readv_next_vector_state *)private_data;
277         struct iovec *vector;
278         ssize_t pending;
279         size_t wanted;
280
281         if (state->ofs == state->len) {
282                 *_vector = NULL;
283                 *count = 0;
284                 return 0;
285         }
286
287         pending = tstream_pending_bytes(stream);
288         if (pending == -1) {
289                 return -1;
290         }
291
292         if (pending == 0 && state->ofs != 0) {
293                 /* return a short read */
294                 *_vector = NULL;
295                 *count = 0;
296                 return 0;
297         }
298
299         if (pending == 0) {
300                 /* we want at least one byte and recheck again */
301                 wanted = 1;
302         } else {
303                 size_t missing = state->len - state->ofs;
304                 if (pending > missing) {
305                         /* there's more available */
306                         state->remaining = pending - missing;
307                         wanted = missing;
308                 } else {
309                         /* read what we can get and recheck in the next cycle */
310                         wanted = pending;
311                 }
312         }
313
314         vector = talloc_array(mem_ctx, struct iovec, 1);
315         if (!vector) {
316                 return -1;
317         }
318
319         vector[0].iov_base = state->buf + state->ofs;
320         vector[0].iov_len = wanted;
321
322         state->ofs += wanted;
323
324         *_vector = vector;
325         *count = 1;
326         return 0;
327 }
328
329 struct np_read_state {
330         struct npa_state *p;
331         struct np_ipc_readv_next_vector_state next_vector;
332
333         ssize_t nread;
334         bool is_data_outstanding;
335 };
336
337 static void np_read_done(struct tevent_req *subreq);
338
339 struct tevent_req *np_read_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
340                                 struct fake_file_handle *handle,
341                                 uint8_t *data, size_t len)
342 {
343         struct tevent_req *req;
344         struct np_read_state *state;
345         NTSTATUS status;
346
347         req = tevent_req_create(mem_ctx, &state, struct np_read_state);
348         if (req == NULL) {
349                 return NULL;
350         }
351
352         if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
353                 struct npa_state *p = talloc_get_type_abort(
354                         handle->private_data, struct npa_state);
355                 struct tevent_req *subreq;
356
357                 np_ipc_readv_next_vector_init(&state->next_vector,
358                                               data, len);
359
360                 subreq = tstream_readv_pdu_queue_send(state,
361                                                       ev,
362                                                       p->stream,
363                                                       p->read_queue,
364                                                       np_ipc_readv_next_vector,
365                                                       &state->next_vector);
366                 if (subreq == NULL) {
367                         status = NT_STATUS_NO_MEMORY;
368                         goto post_status;
369                 }
370                 tevent_req_set_callback(subreq, np_read_done, req);
371                 return req;
372         }
373
374         status = NT_STATUS_INVALID_HANDLE;
375  post_status:
376         if (NT_STATUS_IS_OK(status)) {
377                 tevent_req_done(req);
378         } else {
379                 tevent_req_nterror(req, status);
380         }
381         return tevent_req_post(req, ev);
382 }
383
384 static void np_read_done(struct tevent_req *subreq)
385 {
386         struct tevent_req *req = tevent_req_callback_data(
387                 subreq, struct tevent_req);
388         struct np_read_state *state = tevent_req_data(
389                 req, struct np_read_state);
390         ssize_t ret;
391         int err;
392
393         ret = tstream_readv_pdu_queue_recv(subreq, &err);
394         TALLOC_FREE(subreq);
395         if (ret == -1) {
396                 tevent_req_nterror(req, map_nt_error_from_unix(err));
397                 return;
398         }
399
400         state->nread = ret;
401         state->is_data_outstanding = (state->next_vector.remaining > 0);
402
403         tevent_req_done(req);
404         return;
405 }
406
407 NTSTATUS np_read_recv(struct tevent_req *req, ssize_t *nread,
408                       bool *is_data_outstanding)
409 {
410         struct np_read_state *state = tevent_req_data(
411                 req, struct np_read_state);
412         NTSTATUS status;
413
414         if (tevent_req_is_nterror(req, &status)) {
415                 return status;
416         }
417
418         DEBUG(10, ("Received %d bytes. There is %smore data outstanding\n",
419                    (int)state->nread, state->is_data_outstanding?"":"no "));
420
421         *nread = state->nread;
422         *is_data_outstanding = state->is_data_outstanding;
423         return NT_STATUS_OK;
424 }