example_coro...
[metze/samba/wip.git] / source4 / ntvfs / ipc / vfs_ipc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    default IPC$ NTVFS backend
4
5    Copyright (C) Andrew Tridgell 2003
6    Copyright (C) Stefan (metze) Metzmacher 2004-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   this implements the IPC$ backend, called by the NTVFS subsystem to
23   handle requests on IPC$ shares
24 */
25
26
27 #include "includes.h"
28 #include "../lib/util/dlinklist.h"
29 #include "ntvfs/ntvfs.h"
30 #include "libcli/rap/rap.h"
31 #include "ntvfs/ipc/proto.h"
32 #include "libcli/raw/ioctl.h"
33 #include "param/param.h"
34 #include "../lib/tsocket/tsocket.h"
35 #include "../libcli/named_pipe_auth/npa_tstream.h"
36 #include "auth/auth.h"
37 #include "auth/auth_sam_reply.h"
38 #include "lib/socket/socket.h"
39 #include "../lib/util/tevent_unix.h"
40 #include "../lib/util/tevent_coroutine.h"
41
42 /* this is the private structure used to keep the state of an open
43    ipc$ connection. It needs to keep information about all open
44    pipes */
45 struct ipc_private {
46         struct ntvfs_module_context *ntvfs;
47
48         /* a list of open pipes */
49         struct pipe_state {
50                 struct pipe_state *next, *prev;
51                 struct ipc_private *ipriv;
52                 const char *pipe_name;
53                 struct ntvfs_handle *handle;
54                 struct tstream_context *npipe;
55                 uint16_t file_type;
56                 uint16_t device_state;
57                 uint64_t allocation_size;
58                 struct tevent_queue *write_queue;
59                 struct tevent_queue *read_queue;
60         } *pipe_list;
61 };
62
63
64 /*
65   find a open pipe give a file handle
66 */
67 static struct pipe_state *pipe_state_find(struct ipc_private *ipriv, struct ntvfs_handle *handle)
68 {
69         struct pipe_state *s;
70         void *p;
71
72         p = ntvfs_handle_get_backend_data(handle, ipriv->ntvfs);
73         if (!p) return NULL;
74
75         s = talloc_get_type(p, struct pipe_state);
76         if (!s) return NULL;
77
78         return s;
79 }
80
81 /*
82   find a open pipe give a wire fnum
83 */
84 static struct pipe_state *pipe_state_find_key(struct ipc_private *ipriv, struct ntvfs_request *req, const DATA_BLOB *key)
85 {
86         struct ntvfs_handle *h;
87
88         h = ntvfs_handle_search_by_wire_key(ipriv->ntvfs, req, key);
89         if (!h) return NULL;
90
91         return pipe_state_find(ipriv, h);
92 }
93
94
95 /*
96   connect to a share - always works 
97 */
98 static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
99                             struct ntvfs_request *req, const char *sharename)
100 {
101         struct ipc_private *ipriv;
102
103         ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "IPC");
104         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
105
106         ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "IPC");
107         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
108
109         /* prepare the private state for this connection */
110         ipriv = talloc(ntvfs, struct ipc_private);
111         NT_STATUS_HAVE_NO_MEMORY(ipriv);
112
113         ntvfs->private_data = ipriv;
114
115         ipriv->ntvfs = ntvfs;
116         ipriv->pipe_list = NULL;
117
118         return NT_STATUS_OK;
119 }
120
121 /*
122   disconnect from a share
123 */
124 static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs)
125 {
126         return NT_STATUS_OK;
127 }
128
129 /*
130   delete a file
131 */
132 static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
133                            struct ntvfs_request *req,
134                            union smb_unlink *unl)
135 {
136         return NT_STATUS_ACCESS_DENIED;
137 }
138
139 /*
140   check if a directory exists
141 */
142 static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
143                             struct ntvfs_request *req,
144                             union smb_chkpath *cp)
145 {
146         return NT_STATUS_ACCESS_DENIED;
147 }
148
149 /*
150   return info on a pathname
151 */
152 static NTSTATUS ipc_qpathinfo(struct ntvfs_module_context *ntvfs,
153                               struct ntvfs_request *req, union smb_fileinfo *info)
154 {
155         switch (info->generic.level) {
156         case  RAW_FILEINFO_GENERIC:
157                 return NT_STATUS_INVALID_DEVICE_REQUEST;
158         case RAW_FILEINFO_GETATTR:
159                 return NT_STATUS_ACCESS_DENIED;
160         default:
161                 return ntvfs_map_qpathinfo(ntvfs, req, info);
162         }
163 }
164
165 /*
166   set info on a pathname
167 */
168 static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
169                                 struct ntvfs_request *req, union smb_setfileinfo *st)
170 {
171         return NT_STATUS_ACCESS_DENIED;
172 }
173
174
175 /*
176   destroy a open pipe structure
177 */
178 static int ipc_fd_destructor(struct pipe_state *p)
179 {
180         DLIST_REMOVE(p->ipriv->pipe_list, p);
181         ntvfs_handle_remove_backend_data(p->handle, p->ipriv->ntvfs);
182         return 0;
183 }
184
185 struct ipc_open_state {
186         struct ipc_private *ipriv;
187         struct pipe_state *p;
188         struct ntvfs_request *req;
189         union smb_open *oi;
190         struct netr_SamInfo3 *info3;
191 };
192
193 static void ipc_open_done(struct tevent_req *subreq);
194
195 /*
196   open a file - used for MSRPC pipes
197 */
198 static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
199                          struct ntvfs_request *req, union smb_open *oi)
200 {
201         NTSTATUS status;
202         struct pipe_state *p;
203         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
204                                     struct ipc_private);
205         struct smb_iconv_convenience *smb_ic
206                 = lp_iconv_convenience(ipriv->ntvfs->ctx->lp_ctx);
207         struct ntvfs_handle *h;
208         struct ipc_open_state *state;
209         struct tevent_req *subreq;
210         const char *fname;
211         const char *directory;
212         struct socket_address *client_sa;
213         struct tsocket_address *client_addr;
214         struct socket_address *server_sa;
215         struct tsocket_address *server_addr;
216         int ret;
217
218         switch (oi->generic.level) {
219         case RAW_OPEN_NTCREATEX:
220                 fname = oi->ntcreatex.in.fname;
221                 break;
222         case RAW_OPEN_OPENX:
223                 fname = oi->openx.in.fname;
224                 break;
225         case RAW_OPEN_SMB2:
226                 fname = oi->smb2.in.fname;
227                 break;
228         default:
229                 status = NT_STATUS_NOT_SUPPORTED;
230                 break;
231         }
232
233         directory = talloc_asprintf(req, "%s/np",
234                                     lp_ncalrpc_dir(ipriv->ntvfs->ctx->lp_ctx));
235         NT_STATUS_HAVE_NO_MEMORY(directory);
236
237         state = talloc(req, struct ipc_open_state);
238         NT_STATUS_HAVE_NO_MEMORY(state);
239
240         status = ntvfs_handle_new(ntvfs, req, &h);
241         NT_STATUS_NOT_OK_RETURN(status);
242
243         p = talloc(h, struct pipe_state);
244         NT_STATUS_HAVE_NO_MEMORY(p);
245
246         while (fname[0] == '\\') fname++;
247
248         p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
249         NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
250
251         p->handle = h;
252         p->ipriv = ipriv;
253
254         p->write_queue = tevent_queue_create(p, "ipc_write_queue");
255         NT_STATUS_HAVE_NO_MEMORY(p->write_queue);
256
257         p->read_queue = tevent_queue_create(p, "ipc_read_queue");
258         NT_STATUS_HAVE_NO_MEMORY(p->read_queue);
259
260         state->ipriv = ipriv;
261         state->p = p;
262         state->req = req;
263         state->oi = oi;
264
265         status = auth_convert_server_info_saminfo3(state,
266                                                    req->session_info->server_info,
267                                                    &state->info3);
268         NT_STATUS_NOT_OK_RETURN(status);
269
270         client_sa = ntvfs_get_peer_addr(ntvfs, state);
271         if (!client_sa) {
272                 return NT_STATUS_INTERNAL_ERROR;
273         }
274
275         server_sa = ntvfs_get_my_addr(ntvfs, state);
276         if (!server_sa) {
277                 return NT_STATUS_INTERNAL_ERROR;
278         }
279
280         ret = tsocket_address_inet_from_strings(state, "ip",
281                                                 client_sa->addr,
282                                                 client_sa->port,
283                                                 &client_addr);
284         if (ret == -1) {
285                 status = map_nt_error_from_unix(errno);
286                 return status;
287         }
288
289         ret = tsocket_address_inet_from_strings(state, "ip",
290                                                 server_sa->addr,
291                                                 server_sa->port,
292                                                 &server_addr);
293         if (ret == -1) {
294                 status = map_nt_error_from_unix(errno);
295                 return status;
296         }
297
298         subreq = tstream_npa_connect_send(p,
299                                           ipriv->ntvfs->ctx->event_ctx,
300                                           smb_ic,
301                                           directory,
302                                           fname,
303                                           client_addr,
304                                           NULL,
305                                           server_addr,
306                                           NULL,
307                                           state->info3,
308                                           req->session_info->session_key);
309         NT_STATUS_HAVE_NO_MEMORY(subreq);
310         tevent_req_set_callback(subreq, ipc_open_done, state);
311
312         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
313         return NT_STATUS_OK;
314 }
315
316 static void ipc_open_done(struct tevent_req *subreq)
317 {
318         struct ipc_open_state *state = tevent_req_callback_data(subreq,
319                                        struct ipc_open_state);
320         struct ipc_private *ipriv = state->ipriv;
321         struct pipe_state *p = state->p;
322         struct ntvfs_request *req = state->req;
323         union smb_open *oi = state->oi;
324         int ret;
325         int sys_errno;
326         NTSTATUS status;
327
328         ret = tstream_npa_connect_recv(subreq, &sys_errno,
329                                        p, &p->npipe,
330                                        &p->file_type,
331                                        &p->device_state,
332                                        &p->allocation_size);
333         TALLOC_FREE(subreq);
334         if (ret == -1) {
335                 status = map_nt_error_from_unix(sys_errno);
336                 goto reply;
337         }
338
339         DLIST_ADD(ipriv->pipe_list, p);
340         talloc_set_destructor(p, ipc_fd_destructor);
341
342         status = ntvfs_handle_set_backend_data(p->handle, ipriv->ntvfs, p);
343         if (!NT_STATUS_IS_OK(status)) {
344                 goto reply;
345         }
346
347         switch (oi->generic.level) {
348         case RAW_OPEN_NTCREATEX:
349                 ZERO_STRUCT(oi->ntcreatex.out);
350                 oi->ntcreatex.out.file.ntvfs    = p->handle;
351                 oi->ntcreatex.out.oplock_level  = 0;
352                 oi->ntcreatex.out.create_action = NTCREATEX_ACTION_EXISTED;
353                 oi->ntcreatex.out.create_time   = 0;
354                 oi->ntcreatex.out.access_time   = 0;
355                 oi->ntcreatex.out.write_time    = 0;
356                 oi->ntcreatex.out.change_time   = 0;
357                 oi->ntcreatex.out.attrib        = FILE_ATTRIBUTE_NORMAL;
358                 oi->ntcreatex.out.alloc_size    = p->allocation_size;
359                 oi->ntcreatex.out.size          = 0;
360                 oi->ntcreatex.out.file_type     = p->file_type;
361                 oi->ntcreatex.out.ipc_state     = p->device_state;
362                 oi->ntcreatex.out.is_directory  = 0;
363                 break;
364         case RAW_OPEN_OPENX:
365                 ZERO_STRUCT(oi->openx.out);
366                 oi->openx.out.file.ntvfs        = p->handle;
367                 oi->openx.out.attrib            = FILE_ATTRIBUTE_NORMAL;
368                 oi->openx.out.write_time        = 0;
369                 oi->openx.out.size              = 0;
370                 oi->openx.out.access            = 0;
371                 oi->openx.out.ftype             = p->file_type;
372                 oi->openx.out.devstate          = p->device_state;
373                 oi->openx.out.action            = 0;
374                 oi->openx.out.unique_fid        = 0;
375                 oi->openx.out.access_mask       = 0;
376                 oi->openx.out.unknown           = 0;
377                 break;
378         case RAW_OPEN_SMB2:
379                 ZERO_STRUCT(oi->smb2.out);
380                 oi->smb2.out.file.ntvfs         = p->handle;
381                 oi->smb2.out.oplock_level       = oi->smb2.in.oplock_level;
382                 oi->smb2.out.create_action      = NTCREATEX_ACTION_EXISTED;
383                 oi->smb2.out.create_time        = 0;
384                 oi->smb2.out.access_time        = 0;
385                 oi->smb2.out.write_time         = 0;
386                 oi->smb2.out.change_time        = 0;
387                 oi->smb2.out.alloc_size         = p->allocation_size;
388                 oi->smb2.out.size               = 0;
389                 oi->smb2.out.file_attr          = FILE_ATTRIBUTE_NORMAL;
390                 oi->smb2.out.reserved2          = 0;
391                 break;
392         default:
393                 break;
394         }
395
396 reply:
397         req->async_states->status = status;
398         req->async_states->send_fn(req);
399 }
400
401 /*
402   create a directory
403 */
404 static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
405                           struct ntvfs_request *req, union smb_mkdir *md)
406 {
407         return NT_STATUS_ACCESS_DENIED;
408 }
409
410 /*
411   remove a directory
412 */
413 static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
414                           struct ntvfs_request *req, struct smb_rmdir *rd)
415 {
416         return NT_STATUS_ACCESS_DENIED;
417 }
418
419 /*
420   rename a set of files
421 */
422 static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
423                            struct ntvfs_request *req, union smb_rename *ren)
424 {
425         return NT_STATUS_ACCESS_DENIED;
426 }
427
428 /*
429   copy a set of files
430 */
431 static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
432                          struct ntvfs_request *req, struct smb_copy *cp)
433 {
434         return NT_STATUS_ACCESS_DENIED;
435 }
436
437 struct ipc_readv_next_vector_state {
438         uint8_t *buf;
439         size_t len;
440         off_t ofs;
441         size_t remaining;
442 };
443
444 static void ipc_readv_next_vector_init(struct ipc_readv_next_vector_state *s,
445                                        uint8_t *buf, size_t len)
446 {
447         ZERO_STRUCTP(s);
448
449         s->buf = buf;
450         s->len = MIN(len, UINT16_MAX);
451         //DEBUG(0,("readv_next_vector_init[%u 0x%04X]\n", s->len, s->len));
452 }
453
454 static int ipc_readv_next_vector(struct tstream_context *stream,
455                                  void *private_data,
456                                  TALLOC_CTX *mem_ctx,
457                                  struct iovec **_vector,
458                                  size_t *count)
459 {
460         struct ipc_readv_next_vector_state *state =
461                 (struct ipc_readv_next_vector_state *)private_data;
462         struct iovec *vector;
463         ssize_t pending;
464         size_t wanted;
465
466         if (state->ofs == state->len) {
467                 *_vector = NULL;
468                 *count = 0;
469 //              DEBUG(0,("readv_next_vector done ofs[%u 0x%04X]\n",
470 //                      state->ofs, state->ofs));
471                 return 0;
472         }
473
474         pending = tstream_pending_bytes(stream);
475         if (pending == -1) {
476                 return -1;
477         }
478
479         if (pending == 0 && state->ofs != 0) {
480                 /* return a short read */
481                 *_vector = NULL;
482                 *count = 0;
483 //              DEBUG(0,("readv_next_vector short read ofs[%u 0x%04X]\n",
484 //                      state->ofs, state->ofs));
485                 return 0;
486         }
487
488         if (pending == 0) {
489                 /* we want at least one byte and recheck again */
490                 wanted = 1;
491         } else {
492                 size_t missing = state->len - state->ofs;
493                 if (pending > missing) {
494                         /* there's more available */
495                         state->remaining = pending - missing;
496                         wanted = missing;
497                 } else {
498                         /* read what we can get and recheck in the next cycle */
499                         wanted = pending;
500                 }
501         }
502
503         vector = talloc_array(mem_ctx, struct iovec, 1);
504         if (!vector) {
505                 return -1;
506         }
507
508         vector[0].iov_base = state->buf + state->ofs;
509         vector[0].iov_len = wanted;
510
511         state->ofs += wanted;
512
513         *_vector = vector;
514         *count = 1;
515         return 0;
516 }
517
518 struct ipc_read_state {
519         struct ipc_private *ipriv;
520         struct pipe_state *p;
521         struct ntvfs_request *req;
522         union smb_read *rd;
523         struct ipc_readv_next_vector_state next_vector;
524 };
525
526 static void ipc_read_done(struct tevent_req *subreq);
527
528 /*
529   read from a file
530 */
531 static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
532                          struct ntvfs_request *req, union smb_read *rd)
533 {
534         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
535                                     struct ipc_private);
536         struct pipe_state *p;
537         struct ipc_read_state *state;
538         struct tevent_req *subreq;
539
540         if (rd->generic.level != RAW_READ_GENERIC) {
541                 return ntvfs_map_read(ntvfs, req, rd);
542         }
543
544         p = pipe_state_find(ipriv, rd->readx.in.file.ntvfs);
545         if (!p) {
546                 return NT_STATUS_INVALID_HANDLE;
547         }
548
549         state = talloc(req, struct ipc_read_state);
550         NT_STATUS_HAVE_NO_MEMORY(state);
551
552         state->ipriv = ipriv;
553         state->p = p;
554         state->req = req;
555         state->rd = rd;
556
557         /* rd->readx.out.data is already allocated */
558         ipc_readv_next_vector_init(&state->next_vector,
559                                    rd->readx.out.data,
560                                    rd->readx.in.maxcnt);
561
562         subreq = tstream_readv_pdu_queue_send(req,
563                                               ipriv->ntvfs->ctx->event_ctx,
564                                               p->npipe,
565                                               p->read_queue,
566                                               ipc_readv_next_vector,
567                                               &state->next_vector);
568         NT_STATUS_HAVE_NO_MEMORY(subreq);
569         tevent_req_set_callback(subreq, ipc_read_done, state);
570
571         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
572         return NT_STATUS_OK;
573 }
574
575 static void ipc_read_done(struct tevent_req *subreq)
576 {
577         struct ipc_read_state *state =
578                 tevent_req_callback_data(subreq,
579                 struct ipc_read_state);
580         struct ntvfs_request *req = state->req;
581         union smb_read *rd = state->rd;
582         int ret;
583         int sys_errno;
584         NTSTATUS status;
585
586         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
587         TALLOC_FREE(subreq);
588         if (ret == -1) {
589                 status = map_nt_error_from_unix(sys_errno);
590                 goto reply;
591         }
592
593         status = NT_STATUS_OK;
594         if (state->next_vector.remaining > 0) {
595                 status = STATUS_BUFFER_OVERFLOW;
596         }
597
598         rd->readx.out.remaining = state->next_vector.remaining;
599         rd->readx.out.compaction_mode = 0;
600         rd->readx.out.nread = ret;
601
602 reply:
603         req->async_states->status = status;
604         req->async_states->send_fn(req);
605 }
606
607 struct example_ocor_state {
608         const char *string;
609 };
610
611 static struct tevent_coroutine_result *example_ocor_body(struct tevent_coroutine *coro,
612                                                          struct tevent_context *ev,
613                                                          void *private_data);
614
615 static struct tevent_req *example_ocor_send(TALLOC_CTX *mem_ctx,
616                                      struct tevent_context *ev,
617                                      const char *string)
618 {
619         struct tevent_req *req;
620         struct example_ocor_state *state;
621         struct tevent_coroutine *coro;
622
623         req = tevent_req_create(mem_ctx, &state, struct example_ocor_state);
624         if (req == NULL) {
625                 return NULL;
626         }
627
628         state->string = string;
629
630         coro = tevent_coroutine_create(req, ev, example_ocor_body);
631         if (tevent_req_nomem(coro, req)) {
632                 return tevent_req_post(req, ev);
633         }
634
635         return req;
636 }
637
638 static struct tevent_coroutine_result *example_ocor_body(struct tevent_coroutine *coro,
639                                                          struct tevent_context *ev,
640                                                          void *private_data)
641 {
642         struct example_ocor_state *state = talloc_get_type_abort(private_data,
643                                            struct example_ocor_state);
644         struct tevent_req *subreq;
645         bool ok;
646
647         DEBUG(0,("%s[%p]: 1. %s\n", __location__, coro, state->string));
648
649         subreq = tevent_wakeup_send(state, ev, timeval_current_ofs(0,500));
650         if (!tevent_coroutine_yield(coro, subreq)) {
651                 return tevent_coroutine_return(coro);
652         }
653         ok = tevent_wakeup_recv(subreq);
654         TALLOC_FREE(subreq);
655         if (!ok) {
656                 tevent_coroutine_error(coro, ENOTSUP);
657                 return tevent_coroutine_return(coro);
658         }
659
660         DEBUG(0,("%s[%p]: 2. %s wakeup[%d]\n", __location__, coro, state->string, ok));
661
662         tevent_coroutine_done(coro);
663         return tevent_coroutine_return(coro);
664 }
665
666 static int example_ocor_recv(struct tevent_req *req, int *perrno)
667 {
668         if (tevent_req_is_unix_error(req, perrno)) {
669                 return -1;
670         }
671
672         return 0;
673 }
674
675 struct example_coro_state {
676         const char *string;
677 };
678
679 static struct tevent_coroutine_result *example_coro_body(struct tevent_coroutine *coro,
680                                                          struct tevent_context *ev,
681                                                          void *private_data);
682
683 static struct tevent_req *example_coro_send(TALLOC_CTX *mem_ctx,
684                                      struct tevent_context *ev,
685                                      const char *string)
686 {
687         struct tevent_req *req;
688         struct example_coro_state *state;
689         struct tevent_coroutine *coro;
690
691         req = tevent_req_create(mem_ctx, &state, struct example_coro_state);
692         if (req == NULL) {
693                 return NULL;
694         }
695
696         state->string = string;
697
698         coro = tevent_coroutine_create(req, ev, example_coro_body);
699         if (tevent_req_nomem(coro, req)) {
700                 return tevent_req_post(req, ev);
701         }
702
703         return req;
704 }
705
706 static struct tevent_coroutine_result *example_coro_body(struct tevent_coroutine *coro,
707                                                          struct tevent_context *ev,
708                                                          void *private_data)
709 {
710         struct example_coro_state *state = talloc_get_type_abort(private_data,
711                                            struct example_coro_state);
712         struct tevent_req *subreq;
713         int ret;
714         int sys_errno;
715
716         DEBUG(0,("%s:%s[%p]: 1. %s\n", __location__, __FUNCTION__, coro, state->string));
717
718         subreq = example_ocor_send(state, ev, state->string);
719         if (!tevent_coroutine_yield(coro, subreq)) {
720                 return tevent_coroutine_return(coro);
721         }
722         ret = example_ocor_recv(subreq, &sys_errno);
723         TALLOC_FREE(subreq);
724         if (ret == -1) {
725                 tevent_coroutine_error(coro, sys_errno);
726                 return tevent_coroutine_return(coro);
727         }
728
729         DEBUG(0,("%s:%s[%p]: 2. %s example_ocor[%d]\n", __location__, __FUNCTION__, coro, state->string, ret));
730
731         subreq = example_ocor_send(state, ev, state->string);
732         if (!tevent_coroutine_yield(coro, subreq)) {
733                 return tevent_coroutine_return(coro);
734         }
735         ret = example_ocor_recv(subreq, &sys_errno);
736         TALLOC_FREE(subreq);
737         if (ret == -1) {
738                 tevent_coroutine_error(coro, sys_errno);
739                 return tevent_coroutine_return(coro);
740         }
741
742         DEBUG(0,("%s:%s[%p]: 3. %s example_ocor[%d]\n", __location__, __FUNCTION__, coro, state->string, ret));
743
744         tevent_coroutine_done(coro);
745         return tevent_coroutine_return(coro);
746 }
747
748 static int example_coro_recv(struct tevent_req *req, int *perrno)
749 {
750         if (tevent_req_is_unix_error(req, perrno)) {
751                 return -1;
752         }
753
754         return 0;
755 }
756
757 struct ipc_write_state {
758         struct ipc_private *ipriv;
759         struct pipe_state *p;
760         struct ntvfs_request *req;
761         union smb_write *wr;
762         struct iovec iov;
763 };
764
765 static void ipc_write_done(struct tevent_req *subreq);
766
767 static void ipc_write_coro_done(struct tevent_req *subreq);
768
769 /*
770   write to a file
771 */
772 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
773                           struct ntvfs_request *req, union smb_write *wr)
774 {
775         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
776                                     struct ipc_private);
777         struct pipe_state *p;
778         struct tevent_req *subreq;
779         struct ipc_write_state *state;
780
781         if (wr->generic.level != RAW_WRITE_GENERIC) {
782                 return ntvfs_map_write(ntvfs, req, wr);
783         }
784
785         p = pipe_state_find(ipriv, wr->writex.in.file.ntvfs);
786         if (!p) {
787                 return NT_STATUS_INVALID_HANDLE;
788         }
789
790         state = talloc(req, struct ipc_write_state);
791         NT_STATUS_HAVE_NO_MEMORY(state);
792
793         state->ipriv = ipriv;
794         state->p = p;
795         state->req = req;
796         state->wr = wr;
797         state->iov.iov_base = discard_const_p(void, wr->writex.in.data);
798         state->iov.iov_len = wr->writex.in.count;
799
800         subreq = example_coro_send(state,
801                                    ipriv->ntvfs->ctx->event_ctx,
802                                    "write_start");
803         NT_STATUS_HAVE_NO_MEMORY(subreq);
804         tevent_req_set_callback(subreq, ipc_write_coro_done, state);
805
806         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
807         return NT_STATUS_OK;
808 }
809
810 static void ipc_write_coro_done(struct tevent_req *subreq)
811 {
812         struct ipc_write_state *state =
813                 tevent_req_callback_data(subreq,
814                 struct ipc_write_state);
815         struct pipe_state *p = state->p;
816         struct ipc_private *ipriv = state->ipriv;
817         struct ntvfs_request *req = state->req;
818         int ret;
819         int sys_errno;
820         NTSTATUS status;
821
822         ret = example_coro_recv(subreq, &sys_errno);
823         TALLOC_FREE(subreq);
824         if (ret == -1) {
825                 status = map_nt_error_from_unix(sys_errno);
826                 goto reply;
827         }
828
829         subreq = tstream_writev_queue_send(state,
830                                            ipriv->ntvfs->ctx->event_ctx,
831                                            p->npipe,
832                                            p->write_queue,
833                                            &state->iov, 1);
834         if (!subreq) {
835                 status = NT_STATUS_NO_MEMORY;
836                 goto reply;
837         }
838         tevent_req_set_callback(subreq, ipc_write_done, state);
839         return;
840
841 reply:
842         req->async_states->status = status;
843         req->async_states->send_fn(req);
844 }
845
846 static void ipc_write_done(struct tevent_req *subreq)
847 {
848         struct ipc_write_state *state =
849                 tevent_req_callback_data(subreq,
850                 struct ipc_write_state);
851         struct ntvfs_request *req = state->req;
852         union smb_write *wr = state->wr;
853         int ret;
854         int sys_errno;
855         NTSTATUS status;
856
857         ret = tstream_writev_queue_recv(subreq, &sys_errno);
858         TALLOC_FREE(subreq);
859         if (ret == -1) {
860                 status = map_nt_error_from_unix(sys_errno);
861                 goto reply;
862         }
863
864         status = NT_STATUS_OK;
865
866         wr->writex.out.nwritten = ret;
867         wr->writex.out.remaining = 0;
868
869 reply:
870         req->async_states->status = status;
871         req->async_states->send_fn(req);
872 }
873
874 /*
875   seek in a file
876 */
877 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
878                          struct ntvfs_request *req,
879                          union smb_seek *io)
880 {
881         return NT_STATUS_ACCESS_DENIED;
882 }
883
884 /*
885   flush a file
886 */
887 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
888                           struct ntvfs_request *req,
889                           union smb_flush *io)
890 {
891         return NT_STATUS_ACCESS_DENIED;
892 }
893
894 /*
895   close a file
896 */
897 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
898                           struct ntvfs_request *req, union smb_close *io)
899 {
900         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
901                                     struct ipc_private);
902         struct pipe_state *p;
903
904         if (io->generic.level != RAW_CLOSE_CLOSE) {
905                 return ntvfs_map_close(ntvfs, req, io);
906         }
907
908         p = pipe_state_find(ipriv, io->close.in.file.ntvfs);
909         if (!p) {
910                 return NT_STATUS_INVALID_HANDLE;
911         }
912
913         talloc_free(p);
914
915         return NT_STATUS_OK;
916 }
917
918 /*
919   exit - closing files
920 */
921 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
922                          struct ntvfs_request *req)
923 {
924         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
925                                     struct ipc_private);
926         struct pipe_state *p, *next;
927         
928         for (p=ipriv->pipe_list; p; p=next) {
929                 next = p->next;
930                 if (p->handle->session_info == req->session_info &&
931                     p->handle->smbpid == req->smbpid) {
932                         talloc_free(p);
933                 }
934         }
935
936         return NT_STATUS_OK;
937 }
938
939 /*
940   logoff - closing files open by the user
941 */
942 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
943                            struct ntvfs_request *req)
944 {
945         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
946                                     struct ipc_private);
947         struct pipe_state *p, *next;
948         
949         for (p=ipriv->pipe_list; p; p=next) {
950                 next = p->next;
951                 if (p->handle->session_info == req->session_info) {
952                         talloc_free(p);
953                 }
954         }
955
956         return NT_STATUS_OK;
957 }
958
959 /*
960   setup for an async call
961 */
962 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
963                                 struct ntvfs_request *req,
964                                 void *private_data)
965 {
966         return NT_STATUS_OK;
967 }
968
969 /*
970   cancel an async call
971 */
972 static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
973                            struct ntvfs_request *req)
974 {
975         return NT_STATUS_UNSUCCESSFUL;
976 }
977
978 /*
979   lock a byte range
980 */
981 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
982                          struct ntvfs_request *req, union smb_lock *lck)
983 {
984         return NT_STATUS_ACCESS_DENIED;
985 }
986
987 /*
988   set info on a open file
989 */
990 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
991                                 struct ntvfs_request *req, union smb_setfileinfo *info)
992 {
993         return NT_STATUS_ACCESS_DENIED;
994 }
995
996 /*
997   query info on a open file
998 */
999 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
1000                               struct ntvfs_request *req, union smb_fileinfo *info)
1001 {
1002         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
1003                                     struct ipc_private);
1004         struct pipe_state *p = pipe_state_find(ipriv, info->generic.in.file.ntvfs);
1005         if (!p) {
1006                 return NT_STATUS_INVALID_HANDLE;
1007         }
1008         switch (info->generic.level) {
1009         case RAW_FILEINFO_GENERIC: 
1010         {
1011                 ZERO_STRUCT(info->generic.out);
1012                 info->generic.out.attrib = FILE_ATTRIBUTE_NORMAL;
1013                 info->generic.out.fname.s = strrchr(p->pipe_name, '\\');
1014                 info->generic.out.alloc_size = 4096;
1015                 info->generic.out.nlink = 1;
1016                 /* What the heck?  Match Win2k3: IPC$ pipes are delete pending */
1017                 info->generic.out.delete_pending = 1;
1018                 return NT_STATUS_OK;
1019         }
1020         case RAW_FILEINFO_ALT_NAME_INFO:
1021         case RAW_FILEINFO_ALT_NAME_INFORMATION:
1022         case RAW_FILEINFO_STREAM_INFO:
1023         case RAW_FILEINFO_STREAM_INFORMATION:
1024         case RAW_FILEINFO_COMPRESSION_INFO:
1025         case RAW_FILEINFO_COMPRESSION_INFORMATION:
1026         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
1027         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
1028                 return NT_STATUS_INVALID_PARAMETER;
1029         case  RAW_FILEINFO_ALL_EAS:
1030                 return NT_STATUS_ACCESS_DENIED;
1031         default:
1032                 return ntvfs_map_qfileinfo(ntvfs, req, info);
1033         }
1034         
1035         return NT_STATUS_ACCESS_DENIED;
1036 }
1037
1038
1039 /*
1040   return filesystem info
1041 */
1042 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
1043                            struct ntvfs_request *req, union smb_fsinfo *fs)
1044 {
1045         return NT_STATUS_ACCESS_DENIED;
1046 }
1047
1048 /*
1049   return print queue info
1050 */
1051 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
1052                         struct ntvfs_request *req, union smb_lpq *lpq)
1053 {
1054         return NT_STATUS_ACCESS_DENIED;
1055 }
1056
1057 /* 
1058    list files in a directory matching a wildcard pattern
1059 */
1060 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
1061                           struct ntvfs_request *req, union smb_search_first *io,
1062                           void *search_private, 
1063                           bool (*callback)(void *, const union smb_search_data *))
1064 {
1065         return NT_STATUS_ACCESS_DENIED;
1066 }
1067
1068 /* 
1069    continue listing files in a directory 
1070 */
1071 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
1072                          struct ntvfs_request *req, union smb_search_next *io,
1073                          void *search_private, 
1074                          bool (*callback)(void *, const union smb_search_data *))
1075 {
1076         return NT_STATUS_ACCESS_DENIED;
1077 }
1078
1079 /* 
1080    end listing files in a directory 
1081 */
1082 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
1083                           struct ntvfs_request *req, union smb_search_close *io)
1084 {
1085         return NT_STATUS_ACCESS_DENIED;
1086 }
1087
1088 struct ipc_trans_state {
1089         struct ipc_private *ipriv;
1090         struct pipe_state *p;
1091         struct ntvfs_request *req;
1092         struct smb_trans2 *trans;
1093         struct iovec writev_iov;
1094         struct ipc_readv_next_vector_state next_vector;
1095 };
1096
1097 static void ipc_trans_writev_done(struct tevent_req *subreq);
1098 static void ipc_trans_readv_done(struct tevent_req *subreq);
1099
1100 /* SMBtrans - handle a DCERPC command */
1101 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
1102                                struct ntvfs_request *req, struct smb_trans2 *trans)
1103 {
1104         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
1105                                     struct ipc_private);
1106         struct pipe_state *p;
1107         DATA_BLOB fnum_key;
1108         uint16_t fnum;
1109         struct ipc_trans_state *state;
1110         struct tevent_req *subreq;
1111
1112         /*
1113          * the fnum is in setup[1], a 16 bit value
1114          * the setup[*] values are already in host byteorder
1115          * but ntvfs_handle_search_by_wire_key() expects
1116          * network byteorder
1117          */
1118         SSVAL(&fnum, 0, trans->in.setup[1]);
1119         fnum_key = data_blob_const(&fnum, 2);
1120
1121         p = pipe_state_find_key(ipriv, req, &fnum_key);
1122         if (!p) {
1123                 return NT_STATUS_INVALID_HANDLE;
1124         }
1125
1126         /* TODO: check if this os the correct logic */
1127         if (tevent_queue_length(p->read_queue) > 0) {
1128                 return NT_STATUS_PIPE_BUSY;
1129         }
1130
1131         state = talloc(req, struct ipc_trans_state);
1132         NT_STATUS_HAVE_NO_MEMORY(state);
1133
1134         trans->out.setup_count = 0;
1135         trans->out.setup = NULL;
1136         trans->out.params = data_blob(NULL, 0);
1137         trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
1138         NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
1139
1140         state->ipriv = ipriv;
1141         state->p = p;
1142         state->req = req;
1143         state->trans = trans;
1144         state->writev_iov.iov_base = trans->in.data.data;
1145         state->writev_iov.iov_len = trans->in.data.length;
1146
1147         ipc_readv_next_vector_init(&state->next_vector,
1148                                    trans->out.data.data,
1149                                    trans->out.data.length);
1150
1151         subreq = tstream_writev_queue_send(state,
1152                                            ipriv->ntvfs->ctx->event_ctx,
1153                                            p->npipe,
1154                                            p->write_queue,
1155                                            &state->writev_iov, 1);
1156         NT_STATUS_HAVE_NO_MEMORY(subreq);
1157         tevent_req_set_callback(subreq, ipc_trans_writev_done, state);
1158
1159         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1160         return NT_STATUS_OK;
1161 }
1162
1163 static void ipc_trans_writev_done(struct tevent_req *subreq)
1164 {
1165         struct ipc_trans_state *state =
1166                 tevent_req_callback_data(subreq,
1167                 struct ipc_trans_state);
1168         struct ipc_private *ipriv = state->ipriv;
1169         struct pipe_state *p = state->p;
1170         struct ntvfs_request *req = state->req;
1171         int ret;
1172         int sys_errno;
1173         NTSTATUS status;
1174
1175         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1176         TALLOC_FREE(subreq);
1177         if (ret == 0) {
1178                 status = NT_STATUS_PIPE_DISCONNECTED;
1179                 goto reply;
1180         } else if (ret == -1) {
1181                 status = map_nt_error_from_unix(sys_errno);
1182                 goto reply;
1183         }
1184
1185         subreq = tstream_readv_pdu_queue_send(state,
1186                                               ipriv->ntvfs->ctx->event_ctx,
1187                                               p->npipe,
1188                                               p->read_queue,
1189                                               ipc_readv_next_vector,
1190                                               &state->next_vector);
1191         if (!subreq) {
1192                 status = NT_STATUS_NO_MEMORY;
1193                 goto reply;
1194         }
1195         tevent_req_set_callback(subreq, ipc_trans_readv_done, state);
1196         return;
1197
1198 reply:
1199         req->async_states->status = status;
1200         req->async_states->send_fn(req);
1201 }
1202
1203 static void ipc_trans_readv_done(struct tevent_req *subreq)
1204 {
1205         struct ipc_trans_state *state =
1206                 tevent_req_callback_data(subreq,
1207                 struct ipc_trans_state);
1208         struct ntvfs_request *req = state->req;
1209         struct smb_trans2 *trans = state->trans;
1210         int ret;
1211         int sys_errno;
1212         NTSTATUS status;
1213
1214         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
1215         TALLOC_FREE(subreq);
1216         if (ret == -1) {
1217                 status = map_nt_error_from_unix(sys_errno);
1218                 goto reply;
1219         }
1220
1221         status = NT_STATUS_OK;
1222         if (state->next_vector.remaining > 0) {
1223                 status = STATUS_BUFFER_OVERFLOW;
1224         }
1225
1226         trans->out.data.length = ret;
1227
1228 reply:
1229         req->async_states->status = status;
1230         req->async_states->send_fn(req);
1231 }
1232
1233 /* SMBtrans - set named pipe state */
1234 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
1235                                       struct ntvfs_request *req, struct smb_trans2 *trans)
1236 {
1237         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
1238                                     struct ipc_private);
1239         struct pipe_state *p;
1240         DATA_BLOB fnum_key;
1241
1242         /* the fnum is in setup[1] */
1243         fnum_key = data_blob_const(&trans->in.setup[1], sizeof(trans->in.setup[1]));
1244
1245         p = pipe_state_find_key(ipriv, req, &fnum_key);
1246         if (!p) {
1247                 return NT_STATUS_INVALID_HANDLE;
1248         }
1249
1250         if (trans->in.params.length != 2) {
1251                 return NT_STATUS_INVALID_PARAMETER;
1252         }
1253         // TODO...
1254         p->device_state = SVAL(trans->in.params.data, 0);
1255
1256         trans->out.setup_count = 0;
1257         trans->out.setup = NULL;
1258         trans->out.params = data_blob(NULL, 0);
1259         trans->out.data = data_blob(NULL, 0);
1260
1261         return NT_STATUS_OK;
1262 }
1263
1264
1265 /* SMBtrans - used to provide access to SMB pipes */
1266 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
1267                                 struct ntvfs_request *req, struct smb_trans2 *trans)
1268 {
1269         NTSTATUS status;
1270
1271         if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
1272                 return ipc_rap_call(req, ntvfs->ctx->event_ctx, ntvfs->ctx->lp_ctx, trans);
1273
1274         if (trans->in.setup_count != 2) {
1275                 return NT_STATUS_INVALID_PARAMETER;
1276         }
1277
1278         switch (trans->in.setup[0]) {
1279         case TRANSACT_SETNAMEDPIPEHANDLESTATE:
1280                 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
1281                 break;
1282         case TRANSACT_DCERPCCMD:
1283                 status = ipc_dcerpc_cmd(ntvfs, req, trans);
1284                 break;
1285         default:
1286                 status = NT_STATUS_INVALID_PARAMETER;
1287                 break;
1288         }
1289
1290         return status;
1291 }
1292
1293 struct ipc_ioctl_state {
1294         struct ipc_private *ipriv;
1295         struct pipe_state *p;
1296         struct ntvfs_request *req;
1297         union smb_ioctl *io;
1298         struct iovec writev_iov;
1299         struct ipc_readv_next_vector_state next_vector;
1300 };
1301
1302 static void ipc_ioctl_writev_done(struct tevent_req *subreq);
1303 static void ipc_ioctl_readv_done(struct tevent_req *subreq);
1304
1305 static NTSTATUS ipc_ioctl_smb2(struct ntvfs_module_context *ntvfs,
1306                                struct ntvfs_request *req, union smb_ioctl *io)
1307 {
1308         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
1309                                     struct ipc_private);
1310         struct pipe_state *p;
1311         struct ipc_ioctl_state *state;
1312         struct tevent_req *subreq;
1313
1314         switch (io->smb2.in.function) {
1315         case FSCTL_NAMED_PIPE_READ_WRITE:
1316                 break;
1317
1318         default:
1319                 return NT_STATUS_FS_DRIVER_REQUIRED;
1320         }
1321
1322         p = pipe_state_find(ipriv, io->smb2.in.file.ntvfs);
1323         if (!p) {
1324                 return NT_STATUS_INVALID_HANDLE;
1325         }
1326
1327         /* TODO: check if this os the correct logic */
1328         if (tevent_queue_length(p->read_queue) > 0) {
1329                 return NT_STATUS_PIPE_BUSY;
1330         }
1331
1332         state = talloc(req, struct ipc_ioctl_state);
1333         NT_STATUS_HAVE_NO_MEMORY(state);
1334
1335         io->smb2.out._pad       = 0;
1336         io->smb2.out.function   = io->smb2.in.function;
1337         io->smb2.out.unknown2   = 0;
1338         io->smb2.out.unknown3   = 0;
1339         io->smb2.out.in         = io->smb2.in.out;
1340         io->smb2.out.out = data_blob_talloc(req, NULL, io->smb2.in.max_response_size);
1341         NT_STATUS_HAVE_NO_MEMORY(io->smb2.out.out.data);
1342
1343         state->ipriv = ipriv;
1344         state->p = p;
1345         state->req = req;
1346         state->io = io;
1347         state->writev_iov.iov_base = io->smb2.in.out.data;
1348         state->writev_iov.iov_len = io->smb2.in.out.length;
1349
1350         ipc_readv_next_vector_init(&state->next_vector,
1351                                    io->smb2.out.out.data,
1352                                    io->smb2.out.out.length);
1353
1354         subreq = tstream_writev_queue_send(state,
1355                                            ipriv->ntvfs->ctx->event_ctx,
1356                                            p->npipe,
1357                                            p->write_queue,
1358                                            &state->writev_iov, 1);
1359         NT_STATUS_HAVE_NO_MEMORY(subreq);
1360         tevent_req_set_callback(subreq, ipc_ioctl_writev_done, state);
1361
1362         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1363         return NT_STATUS_OK;
1364 }
1365
1366 static void ipc_ioctl_writev_done(struct tevent_req *subreq)
1367 {
1368         struct ipc_ioctl_state *state =
1369                 tevent_req_callback_data(subreq,
1370                 struct ipc_ioctl_state);
1371         struct ipc_private *ipriv = state->ipriv;
1372         struct pipe_state *p = state->p;
1373         struct ntvfs_request *req = state->req;
1374         int ret;
1375         int sys_errno;
1376         NTSTATUS status;
1377
1378         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1379         TALLOC_FREE(subreq);
1380         if (ret == -1) {
1381                 status = map_nt_error_from_unix(sys_errno);
1382                 goto reply;
1383         }
1384
1385         subreq = tstream_readv_pdu_queue_send(state,
1386                                               ipriv->ntvfs->ctx->event_ctx,
1387                                               p->npipe,
1388                                               p->read_queue,
1389                                               ipc_readv_next_vector,
1390                                               &state->next_vector);
1391         if (!subreq) {
1392                 status = NT_STATUS_NO_MEMORY;
1393                 goto reply;
1394         }
1395         tevent_req_set_callback(subreq, ipc_ioctl_readv_done, state);
1396         return;
1397
1398 reply:
1399         req->async_states->status = status;
1400         req->async_states->send_fn(req);
1401 }
1402
1403 static void ipc_ioctl_readv_done(struct tevent_req *subreq)
1404 {
1405         struct ipc_ioctl_state *state =
1406                 tevent_req_callback_data(subreq,
1407                 struct ipc_ioctl_state);
1408         struct ntvfs_request *req = state->req;
1409         union smb_ioctl *io = state->io;
1410         int ret;
1411         int sys_errno;
1412         NTSTATUS status;
1413
1414         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
1415         TALLOC_FREE(subreq);
1416         if (ret == -1) {
1417                 status = map_nt_error_from_unix(sys_errno);
1418                 goto reply;
1419         }
1420
1421         status = NT_STATUS_OK;
1422         if (state->next_vector.remaining > 0) {
1423                 status = STATUS_BUFFER_OVERFLOW;
1424         }
1425
1426         io->smb2.out.out.length = ret;
1427
1428 reply:
1429         req->async_states->status = status;
1430         req->async_states->send_fn(req);
1431 }
1432
1433
1434 /*
1435   ioctl interface
1436 */
1437 static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
1438                           struct ntvfs_request *req, union smb_ioctl *io)
1439 {
1440         switch (io->generic.level) {
1441         case RAW_IOCTL_SMB2:
1442                 return ipc_ioctl_smb2(ntvfs, req, io);
1443
1444         case RAW_IOCTL_SMB2_NO_HANDLE:
1445                 return NT_STATUS_FS_DRIVER_REQUIRED;
1446
1447         default:
1448                 return NT_STATUS_ACCESS_DENIED;
1449         }
1450
1451         return NT_STATUS_ACCESS_DENIED;
1452 }
1453
1454
1455 /*
1456   initialialise the IPC backend, registering ourselves with the ntvfs subsystem
1457  */
1458 NTSTATUS ntvfs_ipc_init(void)
1459 {
1460         NTSTATUS ret;
1461         struct ntvfs_ops ops;
1462         NTVFS_CURRENT_CRITICAL_SIZES(vers);
1463
1464         ZERO_STRUCT(ops);
1465         
1466         /* fill in the name and type */
1467         ops.name = "default";
1468         ops.type = NTVFS_IPC;
1469
1470         /* fill in all the operations */
1471         ops.connect = ipc_connect;
1472         ops.disconnect = ipc_disconnect;
1473         ops.unlink = ipc_unlink;
1474         ops.chkpath = ipc_chkpath;
1475         ops.qpathinfo = ipc_qpathinfo;
1476         ops.setpathinfo = ipc_setpathinfo;
1477         ops.open = ipc_open;
1478         ops.mkdir = ipc_mkdir;
1479         ops.rmdir = ipc_rmdir;
1480         ops.rename = ipc_rename;
1481         ops.copy = ipc_copy;
1482         ops.ioctl = ipc_ioctl;
1483         ops.read = ipc_read;
1484         ops.write = ipc_write;
1485         ops.seek = ipc_seek;
1486         ops.flush = ipc_flush;  
1487         ops.close = ipc_close;
1488         ops.exit = ipc_exit;
1489         ops.lock = ipc_lock;
1490         ops.setfileinfo = ipc_setfileinfo;
1491         ops.qfileinfo = ipc_qfileinfo;
1492         ops.fsinfo = ipc_fsinfo;
1493         ops.lpq = ipc_lpq;
1494         ops.search_first = ipc_search_first;
1495         ops.search_next = ipc_search_next;
1496         ops.search_close = ipc_search_close;
1497         ops.trans = ipc_trans;
1498         ops.logoff = ipc_logoff;
1499         ops.async_setup = ipc_async_setup;
1500         ops.cancel = ipc_cancel;
1501
1502         /* register ourselves with the NTVFS subsystem. */
1503         ret = ntvfs_register(&ops, &vers);
1504
1505         if (!NT_STATUS_IS_OK(ret)) {
1506                 DEBUG(0,("Failed to register IPC backend!\n"));
1507                 return ret;
1508         }
1509
1510         return ret;
1511 }