lib: Make genrand independent
[Samba.git] / source3 / rpc_server / srv_pipe_hnd.c
blob63a5fcdfa9230838faf37fd724d509e9e63c7dd6
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
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.
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.
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/>.
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"
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_RPC_SRV
38 bool fsp_is_np(struct files_struct *fsp)
40 enum FAKE_FILE_TYPE type;
42 if ((fsp == NULL) || (fsp->fake_file_handle == NULL)) {
43 return false;
46 type = fsp->fake_file_handle->type;
48 return (type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY);
51 NTSTATUS np_open(TALLOC_CTX *mem_ctx, const char *name,
52 const struct tsocket_address *local_address,
53 const struct tsocket_address *remote_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)
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;
67 proxy_list = lp_parm_string_list(-1, "np", "proxy", NULL);
69 handle = talloc(mem_ctx, struct fake_file_handle);
70 if (handle == NULL) {
71 return NT_STATUS_NO_MEMORY;
74 /* Check what is the server type for this pipe.
75 Defaults to "embedded" */
76 pipe_mode = rpc_service_mode(name);
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;
83 switch (pipe_mode) {
84 case RPC_SERVICE_MODE_EXTERNAL:
85 status = make_external_rpc_pipe(handle,
86 name,
87 local_address,
88 remote_address,
89 session_info,
90 &npa);
91 if (!NT_STATUS_IS_OK(status)) {
92 talloc_free(handle);
93 return status;
96 handle->private_data = (void *)npa;
97 handle->type = FAKE_FILE_TYPE_NAMED_PIPE_PROXY;
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;
109 status = make_internal_rpc_pipe_socketpair(handle,
110 ev_ctx,
111 msg_ctx,
112 name,
113 &syntax,
114 remote_address,
115 session_info,
116 &npa);
117 if (!NT_STATUS_IS_OK(status)) {
118 talloc_free(handle);
119 return status;
122 handle->private_data = (void *)npa;
123 handle->type = FAKE_FILE_TYPE_NAMED_PIPE_PROXY;
125 break;
126 case RPC_SERVICE_MODE_DISABLED:
127 talloc_free(handle);
128 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
131 *phandle = handle;
133 return NT_STATUS_OK;
136 bool np_read_in_progress(struct fake_file_handle *handle)
138 if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
139 struct npa_state *p =
140 talloc_get_type_abort(handle->private_data,
141 struct npa_state);
142 size_t read_count;
144 read_count = tevent_queue_length(p->read_queue);
145 if (read_count > 0) {
146 return true;
149 return false;
152 return false;
155 struct np_write_state {
156 struct tevent_context *ev;
157 struct npa_state *p;
158 struct iovec iov;
159 ssize_t nwritten;
162 static void np_write_done(struct tevent_req *subreq);
164 struct tevent_req *np_write_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
165 struct fake_file_handle *handle,
166 const uint8_t *data, size_t len)
168 struct tevent_req *req;
169 struct np_write_state *state;
170 NTSTATUS status;
172 DEBUG(6, ("np_write_send: len: %d\n", (int)len));
173 dump_data(50, data, len);
175 req = tevent_req_create(mem_ctx, &state, struct np_write_state);
176 if (req == NULL) {
177 return NULL;
180 if (len == 0) {
181 state->nwritten = 0;
182 status = NT_STATUS_OK;
183 goto post_status;
186 if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
187 struct npa_state *p = talloc_get_type_abort(
188 handle->private_data, struct npa_state);
189 struct tevent_req *subreq;
191 state->ev = ev;
192 state->p = p;
193 state->iov.iov_base = discard_const_p(void, data);
194 state->iov.iov_len = len;
196 subreq = tstream_writev_queue_send(state, ev,
197 p->stream,
198 p->write_queue,
199 &state->iov, 1);
200 if (subreq == NULL) {
201 goto fail;
203 tevent_req_set_callback(subreq, np_write_done, req);
204 return req;
207 status = NT_STATUS_INVALID_HANDLE;
208 post_status:
209 if (NT_STATUS_IS_OK(status)) {
210 tevent_req_done(req);
211 } else {
212 tevent_req_nterror(req, status);
214 return tevent_req_post(req, ev);
215 fail:
216 TALLOC_FREE(req);
217 return NULL;
220 static void np_write_done(struct tevent_req *subreq)
222 struct tevent_req *req = tevent_req_callback_data(
223 subreq, struct tevent_req);
224 struct np_write_state *state = tevent_req_data(
225 req, struct np_write_state);
226 ssize_t received;
227 int err;
229 received = tstream_writev_queue_recv(subreq, &err);
230 if (received < 0) {
231 tevent_req_nterror(req, map_nt_error_from_unix(err));
232 return;
234 state->nwritten = received;
235 tevent_req_done(req);
238 NTSTATUS np_write_recv(struct tevent_req *req, ssize_t *pnwritten)
240 struct np_write_state *state = tevent_req_data(
241 req, struct np_write_state);
242 NTSTATUS status;
244 if (tevent_req_is_nterror(req, &status)) {
245 return status;
247 *pnwritten = state->nwritten;
248 return NT_STATUS_OK;
251 struct np_ipc_readv_next_vector_state {
252 uint8_t *buf;
253 size_t len;
254 off_t ofs;
255 size_t remaining;
258 static void np_ipc_readv_next_vector_init(struct np_ipc_readv_next_vector_state *s,
259 uint8_t *buf, size_t len)
261 ZERO_STRUCTP(s);
263 s->buf = buf;
264 s->len = MIN(len, UINT16_MAX);
267 static int np_ipc_readv_next_vector(struct tstream_context *stream,
268 void *private_data,
269 TALLOC_CTX *mem_ctx,
270 struct iovec **_vector,
271 size_t *count)
273 struct np_ipc_readv_next_vector_state *state =
274 (struct np_ipc_readv_next_vector_state *)private_data;
275 struct iovec *vector;
276 ssize_t pending;
277 size_t wanted;
279 if (state->ofs == state->len) {
280 *_vector = NULL;
281 *count = 0;
282 return 0;
285 pending = tstream_pending_bytes(stream);
286 if (pending == -1) {
287 return -1;
290 if (pending == 0 && state->ofs != 0) {
291 /* return a short read */
292 *_vector = NULL;
293 *count = 0;
294 return 0;
297 if (pending == 0) {
298 /* we want at least one byte and recheck again */
299 wanted = 1;
300 } else {
301 size_t missing = state->len - state->ofs;
302 if (pending > missing) {
303 /* there's more available */
304 state->remaining = pending - missing;
305 wanted = missing;
306 } else {
307 /* read what we can get and recheck in the next cycle */
308 wanted = pending;
312 vector = talloc_array(mem_ctx, struct iovec, 1);
313 if (!vector) {
314 return -1;
317 vector[0].iov_base = state->buf + state->ofs;
318 vector[0].iov_len = wanted;
320 state->ofs += wanted;
322 *_vector = vector;
323 *count = 1;
324 return 0;
327 struct np_read_state {
328 struct npa_state *p;
329 struct np_ipc_readv_next_vector_state next_vector;
331 ssize_t nread;
332 bool is_data_outstanding;
335 static void np_read_done(struct tevent_req *subreq);
337 struct tevent_req *np_read_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
338 struct fake_file_handle *handle,
339 uint8_t *data, size_t len)
341 struct tevent_req *req;
342 struct np_read_state *state;
343 NTSTATUS status;
345 req = tevent_req_create(mem_ctx, &state, struct np_read_state);
346 if (req == NULL) {
347 return NULL;
350 if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
351 struct npa_state *p = talloc_get_type_abort(
352 handle->private_data, struct npa_state);
353 struct tevent_req *subreq;
355 np_ipc_readv_next_vector_init(&state->next_vector,
356 data, len);
358 subreq = tstream_readv_pdu_queue_send(state,
360 p->stream,
361 p->read_queue,
362 np_ipc_readv_next_vector,
363 &state->next_vector);
364 if (subreq == NULL) {
365 status = NT_STATUS_NO_MEMORY;
366 goto post_status;
368 tevent_req_set_callback(subreq, np_read_done, req);
369 return req;
372 status = NT_STATUS_INVALID_HANDLE;
373 post_status:
374 if (NT_STATUS_IS_OK(status)) {
375 tevent_req_done(req);
376 } else {
377 tevent_req_nterror(req, status);
379 return tevent_req_post(req, ev);
382 static void np_read_done(struct tevent_req *subreq)
384 struct tevent_req *req = tevent_req_callback_data(
385 subreq, struct tevent_req);
386 struct np_read_state *state = tevent_req_data(
387 req, struct np_read_state);
388 ssize_t ret;
389 int err;
391 ret = tstream_readv_pdu_queue_recv(subreq, &err);
392 TALLOC_FREE(subreq);
393 if (ret == -1) {
394 tevent_req_nterror(req, map_nt_error_from_unix(err));
395 return;
398 state->nread = ret;
399 state->is_data_outstanding = (state->next_vector.remaining > 0);
401 tevent_req_done(req);
402 return;
405 NTSTATUS np_read_recv(struct tevent_req *req, ssize_t *nread,
406 bool *is_data_outstanding)
408 struct np_read_state *state = tevent_req_data(
409 req, struct np_read_state);
410 NTSTATUS status;
412 if (tevent_req_is_nterror(req, &status)) {
413 return status;
416 DEBUG(10, ("Received %d bytes. There is %smore data outstanding\n",
417 (int)state->nread, state->is_data_outstanding?"":"no "));
419 *nread = state->nread;
420 *is_data_outstanding = state->is_data_outstanding;
421 return NT_STATUS_OK;