s3-build: only include "fake_file.h" where needed.
[kai/samba-autobuild/.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 "../librpc/gen_ndr/srv_spoolss.h"
24 #include "librpc/gen_ndr/ndr_named_pipe_auth.h"
25 #include "../libcli/named_pipe_auth/npa_tstream.h"
26 #include "rpc_server.h"
27 #include "smbd/globals.h"
28 #include "fake_file.h"
29
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_RPC_SRV
32
33 /****************************************************************************
34  Ensures we have at least RPC_HEADER_LEN amount of data in the incoming buffer.
35 ****************************************************************************/
36
37 static ssize_t fill_rpc_header(struct pipes_struct *p, char *data, size_t data_to_copy)
38 {
39         size_t len_needed_to_complete_hdr =
40                 MIN(data_to_copy, RPC_HEADER_LEN - p->in_data.pdu.length);
41
42         DEBUG(10, ("fill_rpc_header: data_to_copy = %u, "
43                    "len_needed_to_complete_hdr = %u, "
44                    "receive_len = %u\n",
45                    (unsigned int)data_to_copy,
46                    (unsigned int)len_needed_to_complete_hdr,
47                    (unsigned int)p->in_data.pdu.length ));
48
49         if (p->in_data.pdu.data == NULL) {
50                 p->in_data.pdu.data = talloc_array(p, uint8_t, RPC_HEADER_LEN);
51         }
52         if (p->in_data.pdu.data == NULL) {
53                 DEBUG(0, ("talloc failed\n"));
54                 return -1;
55         }
56
57         memcpy((char *)&p->in_data.pdu.data[p->in_data.pdu.length],
58                 data, len_needed_to_complete_hdr);
59         p->in_data.pdu.length += len_needed_to_complete_hdr;
60
61         return (ssize_t)len_needed_to_complete_hdr;
62 }
63
64 static bool get_pdu_size(struct pipes_struct *p)
65 {
66         uint16_t frag_len;
67         /* the fill_rpc_header() call insures we copy only
68          * RPC_HEADER_LEN bytes. If this doesn't match then
69          * somethign is very wrong and we can only abort */
70         if (p->in_data.pdu.length != RPC_HEADER_LEN) {
71                 DEBUG(0, ("Unexpected RPC Header size! "
72                           "got %d, expected %d)\n",
73                           (int)p->in_data.pdu.length,
74                           RPC_HEADER_LEN));
75                 set_incoming_fault(p);
76                 return false;
77         }
78
79         frag_len = dcerpc_get_frag_length(&p->in_data.pdu);
80
81         /* verify it is a reasonable value */
82         if ((frag_len < RPC_HEADER_LEN) ||
83             (frag_len > RPC_MAX_PDU_FRAG_LEN)) {
84                 DEBUG(0, ("Unexpected RPC Fragment size! (%d)\n",
85                           frag_len));
86                 set_incoming_fault(p);
87                 return false;
88         }
89
90         p->in_data.pdu_needed_len = frag_len - RPC_HEADER_LEN;
91
92         /* allocate the space needed to fill the pdu */
93         p->in_data.pdu.data = talloc_realloc(p, p->in_data.pdu.data,
94                                                 uint8_t, frag_len);
95         if (p->in_data.pdu.data == NULL) {
96                 DEBUG(0, ("talloc_realloc failed\n"));
97                 set_incoming_fault(p);
98                 return false;
99         }
100
101         return true;
102 }
103
104 /****************************************************************************
105   Call this to free any talloc'ed memory. Do this after processing
106   a complete incoming and outgoing request (multiple incoming/outgoing
107   PDU's).
108 ****************************************************************************/
109
110 static void free_pipe_context(struct pipes_struct *p)
111 {
112         data_blob_free(&p->out_data.frag);
113         data_blob_free(&p->out_data.rdata);
114         data_blob_free(&p->in_data.data);
115
116         DEBUG(3, ("free_pipe_context: "
117                 "destroying talloc pool of size %lu\n",
118                 (unsigned long)talloc_total_size(p->mem_ctx)));
119         talloc_free_children(p->mem_ctx);
120 }
121
122 /****************************************************************************
123  Accepts incoming data on an rpc pipe. Processes the data in pdu sized units.
124 ****************************************************************************/
125
126 static ssize_t process_incoming_data(struct pipes_struct *p, char *data, size_t n)
127 {
128         size_t data_to_copy = MIN(n, RPC_MAX_PDU_FRAG_LEN
129                                         - p->in_data.pdu.length);
130
131         DEBUG(10, ("process_incoming_data: Start: pdu.length = %u, "
132                    "pdu_needed_len = %u, incoming data = %u\n",
133                    (unsigned int)p->in_data.pdu.length,
134                    (unsigned int)p->in_data.pdu_needed_len,
135                    (unsigned int)n ));
136
137         if(data_to_copy == 0) {
138                 /*
139                  * This is an error - data is being received and there is no
140                  * space in the PDU. Free the received data and go into the
141                  * fault state.
142                  */
143                 DEBUG(0, ("process_incoming_data: "
144                           "No space in incoming pdu buffer. "
145                           "Current size = %u incoming data size = %u\n",
146                           (unsigned int)p->in_data.pdu.length,
147                           (unsigned int)n));
148                 set_incoming_fault(p);
149                 return -1;
150         }
151
152         /*
153          * If we have no data already, wait until we get at least
154          * a RPC_HEADER_LEN * number of bytes before we can do anything.
155          */
156
157         if ((p->in_data.pdu_needed_len == 0) &&
158             (p->in_data.pdu.length < RPC_HEADER_LEN)) {
159                 /*
160                  * Always return here. If we have more data then the RPC_HEADER
161                  * will be processed the next time around the loop.
162                  */
163                 return fill_rpc_header(p, data, data_to_copy);
164         }
165
166         /*
167          * At this point we know we have at least an RPC_HEADER_LEN amount of
168          * data stored in p->in_data.pdu.
169          */
170
171         /*
172          * If pdu_needed_len is zero this is a new pdu.
173          * Check how much more data we need, then loop again.
174          */
175         if (p->in_data.pdu_needed_len == 0) {
176
177                 bool ok = get_pdu_size(p);
178                 if (!ok) {
179                         return -1;
180                 }
181                 if (p->in_data.pdu_needed_len > 0) {
182                         return 0;
183                 }
184
185                 /* If rret == 0 and pdu_needed_len == 0 here we have a PDU
186                  * that consists of an RPC_HEADER only. This is a
187                  * DCERPC_PKT_SHUTDOWN, DCERPC_PKT_CO_CANCEL or
188                  * DCERPC_PKT_ORPHANED pdu type.
189                  * Deal with this in process_complete_pdu(). */
190         }
191
192         /*
193          * Ok - at this point we have a valid RPC_HEADER.
194          * Keep reading until we have a full pdu.
195          */
196
197         data_to_copy = MIN(data_to_copy, p->in_data.pdu_needed_len);
198
199         /*
200          * Copy as much of the data as we need into the p->in_data.pdu buffer.
201          * pdu_needed_len becomes zero when we have a complete pdu.
202          */
203
204         memcpy((char *)&p->in_data.pdu.data[p->in_data.pdu.length],
205                 data, data_to_copy);
206         p->in_data.pdu.length += data_to_copy;
207         p->in_data.pdu_needed_len -= data_to_copy;
208
209         /*
210          * Do we have a complete PDU ?
211          * (return the number of bytes handled in the call)
212          */
213
214         if(p->in_data.pdu_needed_len == 0) {
215                 process_complete_pdu(p);
216                 return data_to_copy;
217         }
218
219         DEBUG(10, ("process_incoming_data: not a complete PDU yet. "
220                    "pdu.length = %u, pdu_needed_len = %u\n",
221                    (unsigned int)p->in_data.pdu.length,
222                    (unsigned int)p->in_data.pdu_needed_len));
223
224         return (ssize_t)data_to_copy;
225 }
226
227 /****************************************************************************
228  Accepts incoming data on an internal rpc pipe.
229 ****************************************************************************/
230
231 static ssize_t write_to_internal_pipe(struct pipes_struct *p, char *data, size_t n)
232 {
233         size_t data_left = n;
234
235         while(data_left) {
236                 ssize_t data_used;
237
238                 DEBUG(10, ("write_to_pipe: data_left = %u\n",
239                           (unsigned int)data_left));
240
241                 data_used = process_incoming_data(p, data, data_left);
242
243                 DEBUG(10, ("write_to_pipe: data_used = %d\n",
244                            (int)data_used));
245
246                 if(data_used < 0) {
247                         return -1;
248                 }
249
250                 data_left -= data_used;
251                 data += data_used;
252         }
253
254         return n;
255 }
256
257 /****************************************************************************
258  Replies to a request to read data from a pipe.
259
260  Headers are interspersed with the data at PDU intervals. By the time
261  this function is called, the start of the data could possibly have been
262  read by an SMBtrans (file_offset != 0).
263
264  Calling create_rpc_reply() here is a hack. The data should already
265  have been prepared into arrays of headers + data stream sections.
266 ****************************************************************************/
267
268 static ssize_t read_from_internal_pipe(struct pipes_struct *p, char *data,
269                                        size_t n, bool *is_data_outstanding)
270 {
271         uint32 pdu_remaining = 0;
272         ssize_t data_returned = 0;
273
274         if (!p) {
275                 DEBUG(0,("read_from_pipe: pipe not open\n"));
276                 return -1;
277         }
278
279         DEBUG(6,(" name: %s len: %u\n",
280                  get_pipe_name_from_syntax(talloc_tos(), &p->syntax),
281                  (unsigned int)n));
282
283         /*
284          * We cannot return more than one PDU length per
285          * read request.
286          */
287
288         /*
289          * This condition should result in the connection being closed.
290          * Netapp filers seem to set it to 0xffff which results in domain
291          * authentications failing.  Just ignore it so things work.
292          */
293
294         if(n > RPC_MAX_PDU_FRAG_LEN) {
295                 DEBUG(5,("read_from_pipe: too large read (%u) requested on "
296                          "pipe %s. We can only service %d sized reads.\n",
297                          (unsigned int)n,
298                          get_pipe_name_from_syntax(talloc_tos(), &p->syntax),
299                          RPC_MAX_PDU_FRAG_LEN ));
300                 n = RPC_MAX_PDU_FRAG_LEN;
301         }
302
303         /*
304          * Determine if there is still data to send in the
305          * pipe PDU buffer. Always send this first. Never
306          * send more than is left in the current PDU. The
307          * client should send a new read request for a new
308          * PDU.
309          */
310
311         pdu_remaining = p->out_data.frag.length
312                 - p->out_data.current_pdu_sent;
313
314         if (pdu_remaining > 0) {
315                 data_returned = (ssize_t)MIN(n, pdu_remaining);
316
317                 DEBUG(10,("read_from_pipe: %s: current_pdu_len = %u, "
318                           "current_pdu_sent = %u returning %d bytes.\n",
319                           get_pipe_name_from_syntax(talloc_tos(), &p->syntax),
320                           (unsigned int)p->out_data.frag.length,
321                           (unsigned int)p->out_data.current_pdu_sent,
322                           (int)data_returned));
323
324                 memcpy(data,
325                        p->out_data.frag.data
326                        + p->out_data.current_pdu_sent,
327                        data_returned);
328
329                 p->out_data.current_pdu_sent += (uint32)data_returned;
330                 goto out;
331         }
332
333         /*
334          * At this point p->current_pdu_len == p->current_pdu_sent (which
335          * may of course be zero if this is the first return fragment.
336          */
337
338         DEBUG(10,("read_from_pipe: %s: fault_state = %d : data_sent_length "
339                   "= %u, p->out_data.rdata.length = %u.\n",
340                   get_pipe_name_from_syntax(talloc_tos(), &p->syntax),
341                   (int)p->fault_state,
342                   (unsigned int)p->out_data.data_sent_length,
343                   (unsigned int)p->out_data.rdata.length));
344
345         if (p->out_data.data_sent_length >= p->out_data.rdata.length) {
346                 /*
347                  * We have sent all possible data, return 0.
348                  */
349                 data_returned = 0;
350                 goto out;
351         }
352
353         /*
354          * We need to create a new PDU from the data left in p->rdata.
355          * Create the header/data/footers. This also sets up the fields
356          * p->current_pdu_len, p->current_pdu_sent, p->data_sent_length
357          * and stores the outgoing PDU in p->current_pdu.
358          */
359
360         if(!create_next_pdu(p)) {
361                 DEBUG(0,("read_from_pipe: %s: create_next_pdu failed.\n",
362                          get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
363                 return -1;
364         }
365
366         data_returned = MIN(n, p->out_data.frag.length);
367
368         memcpy(data, p->out_data.frag.data, (size_t)data_returned);
369         p->out_data.current_pdu_sent += (uint32)data_returned;
370
371   out:
372         (*is_data_outstanding) = p->out_data.frag.length > n;
373
374         if (p->out_data.current_pdu_sent == p->out_data.frag.length) {
375                 /* We've returned everything in the out_data.frag
376                  * so we're done with this pdu. Free it and reset
377                  * current_pdu_sent. */
378                 p->out_data.current_pdu_sent = 0;
379                 data_blob_free(&p->out_data.frag);
380
381                 if (p->out_data.data_sent_length >= p->out_data.rdata.length) {
382                         /*
383                          * We're completely finished with both outgoing and
384                          * incoming data streams. It's safe to free all
385                          * temporary data from this request.
386                          */
387                         free_pipe_context(p);
388                 }
389         }
390
391         return data_returned;
392 }
393
394 bool fsp_is_np(struct files_struct *fsp)
395 {
396         enum FAKE_FILE_TYPE type;
397
398         if ((fsp == NULL) || (fsp->fake_file_handle == NULL)) {
399                 return false;
400         }
401
402         type = fsp->fake_file_handle->type;
403
404         return ((type == FAKE_FILE_TYPE_NAMED_PIPE)
405                 || (type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY));
406 }
407
408 struct np_proxy_state {
409         uint16_t file_type;
410         uint16_t device_state;
411         uint64_t allocation_size;
412         struct tstream_context *npipe;
413         struct tevent_queue *read_queue;
414         struct tevent_queue *write_queue;
415 };
416
417 static struct np_proxy_state *make_external_rpc_pipe_p(TALLOC_CTX *mem_ctx,
418                                 const char *pipe_name,
419                                 const struct tsocket_address *local_address,
420                                 const struct tsocket_address *remote_address,
421                                 struct auth_serversupplied_info *server_info)
422 {
423         struct np_proxy_state *result;
424         char *socket_np_dir;
425         const char *socket_dir;
426         struct tevent_context *ev;
427         struct tevent_req *subreq;
428         struct netr_SamInfo3 *info3;
429         NTSTATUS status;
430         bool ok;
431         int ret;
432         int sys_errno;
433
434         result = talloc(mem_ctx, struct np_proxy_state);
435         if (result == NULL) {
436                 DEBUG(0, ("talloc failed\n"));
437                 return NULL;
438         }
439
440         result->read_queue = tevent_queue_create(result, "np_read");
441         if (result->read_queue == NULL) {
442                 DEBUG(0, ("tevent_queue_create failed\n"));
443                 goto fail;
444         }
445
446         result->write_queue = tevent_queue_create(result, "np_write");
447         if (result->write_queue == NULL) {
448                 DEBUG(0, ("tevent_queue_create failed\n"));
449                 goto fail;
450         }
451
452         ev = s3_tevent_context_init(talloc_tos());
453         if (ev == NULL) {
454                 DEBUG(0, ("s3_tevent_context_init failed\n"));
455                 goto fail;
456         }
457
458         socket_dir = lp_parm_const_string(
459                 GLOBAL_SECTION_SNUM, "external_rpc_pipe", "socket_dir",
460                 get_dyn_NCALRPCDIR());
461         if (socket_dir == NULL) {
462                 DEBUG(0, ("externan_rpc_pipe:socket_dir not set\n"));
463                 goto fail;
464         }
465         socket_np_dir = talloc_asprintf(talloc_tos(), "%s/np", socket_dir);
466         if (socket_np_dir == NULL) {
467                 DEBUG(0, ("talloc_asprintf failed\n"));
468                 goto fail;
469         }
470
471         info3 = talloc_zero(talloc_tos(), struct netr_SamInfo3);
472         if (info3 == NULL) {
473                 DEBUG(0, ("talloc failed\n"));
474                 goto fail;
475         }
476
477         status = serverinfo_to_SamInfo3(server_info, NULL, 0, info3);
478         if (!NT_STATUS_IS_OK(status)) {
479                 TALLOC_FREE(info3);
480                 DEBUG(0, ("serverinfo_to_SamInfo3 failed: %s\n",
481                           nt_errstr(status)));
482                 goto fail;
483         }
484
485         become_root();
486         subreq = tstream_npa_connect_send(talloc_tos(), ev,
487                                           socket_np_dir,
488                                           pipe_name,
489                                           remote_address, /* client_addr */
490                                           NULL, /* client_name */
491                                           local_address, /* server_addr */
492                                           NULL, /* server_name */
493                                           info3,
494                                           server_info->user_session_key,
495                                           data_blob_null /* delegated_creds */);
496         if (subreq == NULL) {
497                 unbecome_root();
498                 DEBUG(0, ("tstream_npa_connect_send to %s for pipe %s and "
499                           "user %s\\%s failed\n",
500                           socket_np_dir, pipe_name, info3->base.domain.string,
501                           info3->base.account_name.string));
502                 goto fail;
503         }
504         ok = tevent_req_poll(subreq, ev);
505         unbecome_root();
506         if (!ok) {
507                 DEBUG(0, ("tevent_req_poll to %s for pipe %s and user %s\\%s "
508                           "failed for tstream_npa_connect: %s\n",
509                           socket_np_dir, pipe_name, info3->base.domain.string,
510                           info3->base.account_name.string,
511                           strerror(errno)));
512                 goto fail;
513
514         }
515         ret = tstream_npa_connect_recv(subreq, &sys_errno,
516                                        result,
517                                        &result->npipe,
518                                        &result->file_type,
519                                        &result->device_state,
520                                        &result->allocation_size);
521         TALLOC_FREE(subreq);
522         if (ret != 0) {
523                 DEBUG(0, ("tstream_npa_connect_recv  to %s for pipe %s and "
524                           "user %s\\%s failed: %s\n",
525                           socket_np_dir, pipe_name, info3->base.domain.string,
526                           info3->base.account_name.string,
527                           strerror(sys_errno)));
528                 goto fail;
529         }
530
531         return result;
532
533  fail:
534         TALLOC_FREE(result);
535         return NULL;
536 }
537
538 NTSTATUS np_open(TALLOC_CTX *mem_ctx, const char *name,
539                  const struct tsocket_address *local_address,
540                  const struct tsocket_address *remote_address,
541                  struct client_address *client_id,
542                  struct auth_serversupplied_info *server_info,
543                  struct messaging_context *msg_ctx,
544                  struct fake_file_handle **phandle)
545 {
546         const char **proxy_list;
547         struct fake_file_handle *handle;
548
549         proxy_list = lp_parm_string_list(-1, "np", "proxy", NULL);
550
551         handle = talloc(mem_ctx, struct fake_file_handle);
552         if (handle == NULL) {
553                 return NT_STATUS_NO_MEMORY;
554         }
555
556         if ((proxy_list != NULL) && str_list_check_ci(proxy_list, name)) {
557                 struct np_proxy_state *p;
558
559                 p = make_external_rpc_pipe_p(handle, name,
560                                              local_address,
561                                              remote_address,
562                                              server_info);
563
564                 handle->type = FAKE_FILE_TYPE_NAMED_PIPE_PROXY;
565                 handle->private_data = p;
566         } else {
567                 struct pipes_struct *p;
568                 struct ndr_syntax_id syntax;
569
570                 if (!is_known_pipename(name, &syntax)) {
571                         TALLOC_FREE(handle);
572                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
573                 }
574
575                 p = make_internal_rpc_pipe_p(handle, &syntax, client_id,
576                                              server_info, msg_ctx);
577
578                 handle->type = FAKE_FILE_TYPE_NAMED_PIPE;
579                 handle->private_data = p;
580         }
581
582         if (handle->private_data == NULL) {
583                 TALLOC_FREE(handle);
584                 return NT_STATUS_PIPE_NOT_AVAILABLE;
585         }
586
587         *phandle = handle;
588
589         return NT_STATUS_OK;
590 }
591
592 bool np_read_in_progress(struct fake_file_handle *handle)
593 {
594         if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE) {
595                 return false;
596         }
597
598         if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
599                 struct np_proxy_state *p = talloc_get_type_abort(
600                         handle->private_data, struct np_proxy_state);
601                 size_t read_count;
602
603                 read_count = tevent_queue_length(p->read_queue);
604                 if (read_count > 0) {
605                         return true;
606                 }
607
608                 return false;
609         }
610
611         return false;
612 }
613
614 struct np_write_state {
615         struct event_context *ev;
616         struct np_proxy_state *p;
617         struct iovec iov;
618         ssize_t nwritten;
619 };
620
621 static void np_write_done(struct tevent_req *subreq);
622
623 struct tevent_req *np_write_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
624                                  struct fake_file_handle *handle,
625                                  const uint8_t *data, size_t len)
626 {
627         struct tevent_req *req;
628         struct np_write_state *state;
629         NTSTATUS status;
630
631         DEBUG(6, ("np_write_send: len: %d\n", (int)len));
632         dump_data(50, data, len);
633
634         req = tevent_req_create(mem_ctx, &state, struct np_write_state);
635         if (req == NULL) {
636                 return NULL;
637         }
638
639         if (len == 0) {
640                 state->nwritten = 0;
641                 status = NT_STATUS_OK;
642                 goto post_status;
643         }
644
645         if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE) {
646                 struct pipes_struct *p = talloc_get_type_abort(
647                         handle->private_data, struct pipes_struct);
648
649                 state->nwritten = write_to_internal_pipe(p, (char *)data, len);
650
651                 status = (state->nwritten >= 0)
652                         ? NT_STATUS_OK : NT_STATUS_UNEXPECTED_IO_ERROR;
653                 goto post_status;
654         }
655
656         if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
657                 struct np_proxy_state *p = talloc_get_type_abort(
658                         handle->private_data, struct np_proxy_state);
659                 struct tevent_req *subreq;
660
661                 state->ev = ev;
662                 state->p = p;
663                 state->iov.iov_base = CONST_DISCARD(void *, data);
664                 state->iov.iov_len = len;
665
666                 subreq = tstream_writev_queue_send(state, ev,
667                                                    p->npipe,
668                                                    p->write_queue,
669                                                    &state->iov, 1);
670                 if (subreq == NULL) {
671                         goto fail;
672                 }
673                 tevent_req_set_callback(subreq, np_write_done, req);
674                 return req;
675         }
676
677         status = NT_STATUS_INVALID_HANDLE;
678  post_status:
679         if (NT_STATUS_IS_OK(status)) {
680                 tevent_req_done(req);
681         } else {
682                 tevent_req_nterror(req, status);
683         }
684         return tevent_req_post(req, ev);
685  fail:
686         TALLOC_FREE(req);
687         return NULL;
688 }
689
690 static void np_write_done(struct tevent_req *subreq)
691 {
692         struct tevent_req *req = tevent_req_callback_data(
693                 subreq, struct tevent_req);
694         struct np_write_state *state = tevent_req_data(
695                 req, struct np_write_state);
696         ssize_t received;
697         int err;
698
699         received = tstream_writev_queue_recv(subreq, &err);
700         if (received < 0) {
701                 tevent_req_nterror(req, map_nt_error_from_unix(err));
702                 return;
703         }
704         state->nwritten = received;
705         tevent_req_done(req);
706 }
707
708 NTSTATUS np_write_recv(struct tevent_req *req, ssize_t *pnwritten)
709 {
710         struct np_write_state *state = tevent_req_data(
711                 req, struct np_write_state);
712         NTSTATUS status;
713
714         if (tevent_req_is_nterror(req, &status)) {
715                 return status;
716         }
717         *pnwritten = state->nwritten;
718         return NT_STATUS_OK;
719 }
720
721 struct np_ipc_readv_next_vector_state {
722         uint8_t *buf;
723         size_t len;
724         off_t ofs;
725         size_t remaining;
726 };
727
728 static void np_ipc_readv_next_vector_init(struct np_ipc_readv_next_vector_state *s,
729                                           uint8_t *buf, size_t len)
730 {
731         ZERO_STRUCTP(s);
732
733         s->buf = buf;
734         s->len = MIN(len, UINT16_MAX);
735 }
736
737 static int np_ipc_readv_next_vector(struct tstream_context *stream,
738                                     void *private_data,
739                                     TALLOC_CTX *mem_ctx,
740                                     struct iovec **_vector,
741                                     size_t *count)
742 {
743         struct np_ipc_readv_next_vector_state *state =
744                 (struct np_ipc_readv_next_vector_state *)private_data;
745         struct iovec *vector;
746         ssize_t pending;
747         size_t wanted;
748
749         if (state->ofs == state->len) {
750                 *_vector = NULL;
751                 *count = 0;
752                 return 0;
753         }
754
755         pending = tstream_pending_bytes(stream);
756         if (pending == -1) {
757                 return -1;
758         }
759
760         if (pending == 0 && state->ofs != 0) {
761                 /* return a short read */
762                 *_vector = NULL;
763                 *count = 0;
764                 return 0;
765         }
766
767         if (pending == 0) {
768                 /* we want at least one byte and recheck again */
769                 wanted = 1;
770         } else {
771                 size_t missing = state->len - state->ofs;
772                 if (pending > missing) {
773                         /* there's more available */
774                         state->remaining = pending - missing;
775                         wanted = missing;
776                 } else {
777                         /* read what we can get and recheck in the next cycle */
778                         wanted = pending;
779                 }
780         }
781
782         vector = talloc_array(mem_ctx, struct iovec, 1);
783         if (!vector) {
784                 return -1;
785         }
786
787         vector[0].iov_base = state->buf + state->ofs;
788         vector[0].iov_len = wanted;
789
790         state->ofs += wanted;
791
792         *_vector = vector;
793         *count = 1;
794         return 0;
795 }
796
797 struct np_read_state {
798         struct np_proxy_state *p;
799         struct np_ipc_readv_next_vector_state next_vector;
800
801         size_t nread;
802         bool is_data_outstanding;
803 };
804
805 static void np_read_done(struct tevent_req *subreq);
806
807 struct tevent_req *np_read_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
808                                 struct fake_file_handle *handle,
809                                 uint8_t *data, size_t len)
810 {
811         struct tevent_req *req;
812         struct np_read_state *state;
813         NTSTATUS status;
814
815         req = tevent_req_create(mem_ctx, &state, struct np_read_state);
816         if (req == NULL) {
817                 return NULL;
818         }
819
820         if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE) {
821                 struct pipes_struct *p = talloc_get_type_abort(
822                         handle->private_data, struct pipes_struct);
823
824                 state->nread = read_from_internal_pipe(
825                         p, (char *)data, len, &state->is_data_outstanding);
826
827                 status = (state->nread >= 0)
828                         ? NT_STATUS_OK : NT_STATUS_UNEXPECTED_IO_ERROR;
829                 goto post_status;
830         }
831
832         if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
833                 struct np_proxy_state *p = talloc_get_type_abort(
834                         handle->private_data, struct np_proxy_state);
835                 struct tevent_req *subreq;
836
837                 np_ipc_readv_next_vector_init(&state->next_vector,
838                                               data, len);
839
840                 subreq = tstream_readv_pdu_queue_send(state,
841                                                       ev,
842                                                       p->npipe,
843                                                       p->read_queue,
844                                                       np_ipc_readv_next_vector,
845                                                       &state->next_vector);
846                 if (subreq == NULL) {
847
848                 }
849                 tevent_req_set_callback(subreq, np_read_done, req);
850                 return req;
851         }
852
853         status = NT_STATUS_INVALID_HANDLE;
854  post_status:
855         if (NT_STATUS_IS_OK(status)) {
856                 tevent_req_done(req);
857         } else {
858                 tevent_req_nterror(req, status);
859         }
860         return tevent_req_post(req, ev);
861 }
862
863 static void np_read_done(struct tevent_req *subreq)
864 {
865         struct tevent_req *req = tevent_req_callback_data(
866                 subreq, struct tevent_req);
867         struct np_read_state *state = tevent_req_data(
868                 req, struct np_read_state);
869         ssize_t ret;
870         int err;
871
872         ret = tstream_readv_pdu_queue_recv(subreq, &err);
873         TALLOC_FREE(subreq);
874         if (ret == -1) {
875                 tevent_req_nterror(req, map_nt_error_from_unix(err));
876                 return;
877         }
878
879         state->nread = ret;
880         state->is_data_outstanding = (state->next_vector.remaining > 0);
881
882         tevent_req_done(req);
883         return;
884 }
885
886 NTSTATUS np_read_recv(struct tevent_req *req, ssize_t *nread,
887                       bool *is_data_outstanding)
888 {
889         struct np_read_state *state = tevent_req_data(
890                 req, struct np_read_state);
891         NTSTATUS status;
892
893         if (tevent_req_is_nterror(req, &status)) {
894                 return status;
895         }
896         *nread = state->nread;
897         *is_data_outstanding = state->is_data_outstanding;
898         return NT_STATUS_OK;
899 }
900
901 /**
902  * @brief Create a new RPC client context which uses a local dispatch function.
903  *
904  * @param[in]  conn  The connection struct that will hold the pipe
905  *
906  * @param[out] spoolss_pipe  A pointer to the connected rpc client pipe.
907  *
908  * @return              NT_STATUS_OK on success, a corresponding NT status if an
909  *                      error occured.
910  */
911 NTSTATUS rpc_connect_spoolss_pipe(connection_struct *conn,
912                                   struct rpc_pipe_client **spoolss_pipe)
913 {
914         NTSTATUS status;
915
916         /* TODO: check and handle disconnections */
917
918         if (!conn->spoolss_pipe) {
919                 status = rpc_pipe_open_internal(conn,
920                                                 &ndr_table_spoolss.syntax_id,
921                                                 conn->server_info,
922                                                 &conn->sconn->client_id,
923                                                 conn->sconn->msg_ctx,
924                                                 &conn->spoolss_pipe);
925                 if (!NT_STATUS_IS_OK(status)) {
926                         return status;
927                 }
928         }
929
930         *spoolss_pipe = conn->spoolss_pipe;
931         return NT_STATUS_OK;
932 }