s4:torture: test setting EOF of a stream to 0 with enabled AAPL extensions
[Samba.git] / source3 / rpc_server / srv_pipe_hnd.c
blobbaa4ce96334d5cc826f2079a8da14f684d26a18d
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 *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)
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 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;
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(
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;
124 handle->private_data = (void *)npa;
125 handle->type = FAKE_FILE_TYPE_NAMED_PIPE_PROXY;
127 break;
128 case RPC_SERVICE_MODE_DISABLED:
129 talloc_free(handle);
130 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
133 *phandle = handle;
135 return NT_STATUS_OK;
138 bool np_read_in_progress(struct fake_file_handle *handle)
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;
146 read_count = tevent_queue_length(p->read_queue);
147 if (read_count > 0) {
148 return true;
151 return false;
154 return false;
157 struct np_write_state {
158 struct tevent_context *ev;
159 struct npa_state *p;
160 struct iovec iov;
161 ssize_t nwritten;
164 static void np_write_done(struct tevent_req *subreq);
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)
170 struct tevent_req *req;
171 struct np_write_state *state;
172 NTSTATUS status;
174 DEBUG(6, ("np_write_send: len: %d\n", (int)len));
175 dump_data(50, data, len);
177 req = tevent_req_create(mem_ctx, &state, struct np_write_state);
178 if (req == NULL) {
179 return NULL;
182 if (len == 0) {
183 state->nwritten = 0;
184 status = NT_STATUS_OK;
185 goto post_status;
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;
193 state->ev = ev;
194 state->p = p;
195 state->iov.iov_base = discard_const_p(void, data);
196 state->iov.iov_len = len;
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;
205 tevent_req_set_callback(subreq, np_write_done, req);
206 return req;
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);
216 return tevent_req_post(req, ev);
217 fail:
218 TALLOC_FREE(req);
219 return NULL;
222 static void np_write_done(struct tevent_req *subreq)
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;
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;
236 state->nwritten = received;
237 tevent_req_done(req);
240 NTSTATUS np_write_recv(struct tevent_req *req, ssize_t *pnwritten)
242 struct np_write_state *state = tevent_req_data(
243 req, struct np_write_state);
244 NTSTATUS status;
246 if (tevent_req_is_nterror(req, &status)) {
247 return status;
249 *pnwritten = state->nwritten;
250 return NT_STATUS_OK;
253 struct np_ipc_readv_next_vector_state {
254 uint8_t *buf;
255 size_t len;
256 off_t ofs;
257 size_t remaining;
260 static void np_ipc_readv_next_vector_init(struct np_ipc_readv_next_vector_state *s,
261 uint8_t *buf, size_t len)
263 ZERO_STRUCTP(s);
265 s->buf = buf;
266 s->len = MIN(len, UINT16_MAX);
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)
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;
281 if (state->ofs == state->len) {
282 *_vector = NULL;
283 *count = 0;
284 return 0;
287 pending = tstream_pending_bytes(stream);
288 if (pending == -1) {
289 return -1;
292 if (pending == 0 && state->ofs != 0) {
293 /* return a short read */
294 *_vector = NULL;
295 *count = 0;
296 return 0;
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;
314 vector = talloc_array(mem_ctx, struct iovec, 1);
315 if (!vector) {
316 return -1;
319 vector[0].iov_base = state->buf + state->ofs;
320 vector[0].iov_len = wanted;
322 state->ofs += wanted;
324 *_vector = vector;
325 *count = 1;
326 return 0;
329 struct np_read_state {
330 struct npa_state *p;
331 struct np_ipc_readv_next_vector_state next_vector;
333 ssize_t nread;
334 bool is_data_outstanding;
337 static void np_read_done(struct tevent_req *subreq);
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)
343 struct tevent_req *req;
344 struct np_read_state *state;
345 NTSTATUS status;
347 req = tevent_req_create(mem_ctx, &state, struct np_read_state);
348 if (req == NULL) {
349 return NULL;
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;
357 np_ipc_readv_next_vector_init(&state->next_vector,
358 data, len);
360 subreq = tstream_readv_pdu_queue_send(state,
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;
370 tevent_req_set_callback(subreq, np_read_done, req);
371 return req;
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);
381 return tevent_req_post(req, ev);
384 static void np_read_done(struct tevent_req *subreq)
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;
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;
400 state->nread = ret;
401 state->is_data_outstanding = (state->next_vector.remaining > 0);
403 tevent_req_done(req);
404 return;
407 NTSTATUS np_read_recv(struct tevent_req *req, ssize_t *nread,
408 bool *is_data_outstanding)
410 struct np_read_state *state = tevent_req_data(
411 req, struct np_read_state);
412 NTSTATUS status;
414 if (tevent_req_is_nterror(req, &status)) {
415 return status;
418 DEBUG(10, ("Received %d bytes. There is %smore data outstanding\n",
419 (int)state->nread, state->is_data_outstanding?"":"no "));
421 *nread = state->nread;
422 *is_data_outstanding = state->is_data_outstanding;
423 return NT_STATUS_OK;