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         tevent_coroutine_run(coro);
636         if (!tevent_req_is_in_progress(req)) {
637                 return tevent_req_post(req, ev);
638         }
639
640         return req;
641 }
642
643 static struct tevent_coroutine_result *example_ocor_body(struct tevent_coroutine *coro,
644                                                          struct tevent_context *ev,
645                                                          void *private_data)
646 {
647         struct example_ocor_state *state = talloc_get_type_abort(private_data,
648                                            struct example_ocor_state);
649         struct tevent_req *subreq;
650         bool ok;
651
652         DEBUG(0,("%s[%p]: 1. %s\n", __location__, coro, state->string));
653
654         subreq = tevent_wakeup_send(state, ev, timeval_current_ofs(0,500));
655         if (tevent_coroutine_nomem(subreq, coro)) {
656                 return tevent_coroutine_return(coro);
657         }
658         tevent_coroutine_yield(coro, subreq);
659         ok = tevent_wakeup_recv(subreq);
660
661         DEBUG(0,("%s[%p]: 2. %s wakeup[%d]\n", __location__, coro, state->string, ok));
662
663         tevent_coroutine_done(coro);
664         return tevent_coroutine_return(coro);
665 }
666
667 static int example_ocor_recv(struct tevent_req *req, int *perrno)
668 {
669         if (tevent_req_is_unix_error(req, perrno)) {
670                 return -1;
671         }
672
673         return 0;
674 }
675
676 struct example_coro_state {
677         const char *string;
678 };
679
680 static struct tevent_coroutine_result *example_coro_body(struct tevent_coroutine *coro,
681                                                          struct tevent_context *ev,
682                                                          void *private_data);
683
684 static struct tevent_req *example_coro_send(TALLOC_CTX *mem_ctx,
685                                      struct tevent_context *ev,
686                                      const char *string)
687 {
688         struct tevent_req *req;
689         struct example_coro_state *state;
690         struct tevent_coroutine *coro;
691
692         req = tevent_req_create(mem_ctx, &state, struct example_coro_state);
693         if (req == NULL) {
694                 return NULL;
695         }
696
697         state->string = string;
698
699         coro = tevent_coroutine_create(req, ev, example_coro_body);
700         if (tevent_req_nomem(coro, req)) {
701                 return tevent_req_post(req, ev);
702         }
703
704         tevent_coroutine_run(coro);
705         if (!tevent_req_is_in_progress(req)) {
706                 return tevent_req_post(req, ev);
707         }
708
709         return req;
710 }
711
712 static struct tevent_coroutine_result *example_coro_body(struct tevent_coroutine *coro,
713                                                          struct tevent_context *ev,
714                                                          void *private_data)
715 {
716         struct example_coro_state *state = talloc_get_type_abort(private_data,
717                                            struct example_coro_state);
718         struct tevent_req *subreq;
719         int ret;
720         int sys_errno;
721
722         DEBUG(0,("%s:%s[%p]: 1. %s\n", __location__, __FUNCTION__, coro, state->string));
723
724         subreq = example_ocor_send(state, ev, state->string);
725         if (tevent_coroutine_nomem(subreq, coro)) {
726                 return tevent_coroutine_return(coro);
727         }
728         tevent_coroutine_yield(coro, subreq);
729         ret = example_ocor_recv(subreq, &sys_errno);
730         if (ret == -1) {
731                 tevent_coroutine_error(coro, sys_errno);
732                 return tevent_coroutine_return(coro);
733         }
734
735         DEBUG(0,("%s:%s[%p]: 2. %s example_ocor[%d]\n", __location__, __FUNCTION__, coro, state->string, ret));
736
737         tevent_coroutine_done(coro);
738         return tevent_coroutine_return(coro);
739 }
740
741 static int example_coro_recv(struct tevent_req *req, int *perrno)
742 {
743         if (tevent_req_is_unix_error(req, perrno)) {
744                 return -1;
745         }
746
747         return 0;
748 }
749
750 struct ipc_write_state {
751         struct ipc_private *ipriv;
752         struct pipe_state *p;
753         struct ntvfs_request *req;
754         union smb_write *wr;
755         struct iovec iov;
756 };
757
758 static void ipc_write_done(struct tevent_req *subreq);
759
760 static void ipc_write_coro_done(struct tevent_req *subreq);
761
762 /*
763   write to a file
764 */
765 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
766                           struct ntvfs_request *req, union smb_write *wr)
767 {
768         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
769                                     struct ipc_private);
770         struct pipe_state *p;
771         struct tevent_req *subreq;
772         struct ipc_write_state *state;
773
774         if (wr->generic.level != RAW_WRITE_GENERIC) {
775                 return ntvfs_map_write(ntvfs, req, wr);
776         }
777
778         p = pipe_state_find(ipriv, wr->writex.in.file.ntvfs);
779         if (!p) {
780                 return NT_STATUS_INVALID_HANDLE;
781         }
782
783         state = talloc(req, struct ipc_write_state);
784         NT_STATUS_HAVE_NO_MEMORY(state);
785
786         state->ipriv = ipriv;
787         state->p = p;
788         state->req = req;
789         state->wr = wr;
790         state->iov.iov_base = discard_const_p(void, wr->writex.in.data);
791         state->iov.iov_len = wr->writex.in.count;
792
793         subreq = example_coro_send(state,
794                                    ipriv->ntvfs->ctx->event_ctx,
795                                    "write_start");
796         NT_STATUS_HAVE_NO_MEMORY(subreq);
797         tevent_req_set_callback(subreq, ipc_write_coro_done, state);
798
799         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
800         return NT_STATUS_OK;
801 }
802
803 static void ipc_write_coro_done(struct tevent_req *subreq)
804 {
805         struct ipc_write_state *state =
806                 tevent_req_callback_data(subreq,
807                 struct ipc_write_state);
808         struct pipe_state *p = state->p;
809         struct ipc_private *ipriv = state->ipriv;
810         struct ntvfs_request *req = state->req;
811         int ret;
812         int sys_errno;
813         NTSTATUS status;
814
815         ret = example_coro_recv(subreq, &sys_errno);
816         TALLOC_FREE(subreq);
817         if (ret == -1) {
818                 status = map_nt_error_from_unix(sys_errno);
819                 goto reply;
820         }
821
822         subreq = tstream_writev_queue_send(state,
823                                            ipriv->ntvfs->ctx->event_ctx,
824                                            p->npipe,
825                                            p->write_queue,
826                                            &state->iov, 1);
827         if (!subreq) {
828                 status = NT_STATUS_NO_MEMORY;
829                 goto reply;
830         }
831         tevent_req_set_callback(subreq, ipc_write_done, state);
832         return;
833
834 reply:
835         req->async_states->status = status;
836         req->async_states->send_fn(req);
837 }
838
839 static void ipc_write_done(struct tevent_req *subreq)
840 {
841         struct ipc_write_state *state =
842                 tevent_req_callback_data(subreq,
843                 struct ipc_write_state);
844         struct ntvfs_request *req = state->req;
845         union smb_write *wr = state->wr;
846         int ret;
847         int sys_errno;
848         NTSTATUS status;
849
850         ret = tstream_writev_queue_recv(subreq, &sys_errno);
851         TALLOC_FREE(subreq);
852         if (ret == -1) {
853                 status = map_nt_error_from_unix(sys_errno);
854                 goto reply;
855         }
856
857         status = NT_STATUS_OK;
858
859         wr->writex.out.nwritten = ret;
860         wr->writex.out.remaining = 0;
861
862 reply:
863         req->async_states->status = status;
864         req->async_states->send_fn(req);
865 }
866
867 /*
868   seek in a file
869 */
870 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
871                          struct ntvfs_request *req,
872                          union smb_seek *io)
873 {
874         return NT_STATUS_ACCESS_DENIED;
875 }
876
877 /*
878   flush a file
879 */
880 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
881                           struct ntvfs_request *req,
882                           union smb_flush *io)
883 {
884         return NT_STATUS_ACCESS_DENIED;
885 }
886
887 /*
888   close a file
889 */
890 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
891                           struct ntvfs_request *req, union smb_close *io)
892 {
893         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
894                                     struct ipc_private);
895         struct pipe_state *p;
896
897         if (io->generic.level != RAW_CLOSE_CLOSE) {
898                 return ntvfs_map_close(ntvfs, req, io);
899         }
900
901         p = pipe_state_find(ipriv, io->close.in.file.ntvfs);
902         if (!p) {
903                 return NT_STATUS_INVALID_HANDLE;
904         }
905
906         talloc_free(p);
907
908         return NT_STATUS_OK;
909 }
910
911 /*
912   exit - closing files
913 */
914 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
915                          struct ntvfs_request *req)
916 {
917         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
918                                     struct ipc_private);
919         struct pipe_state *p, *next;
920         
921         for (p=ipriv->pipe_list; p; p=next) {
922                 next = p->next;
923                 if (p->handle->session_info == req->session_info &&
924                     p->handle->smbpid == req->smbpid) {
925                         talloc_free(p);
926                 }
927         }
928
929         return NT_STATUS_OK;
930 }
931
932 /*
933   logoff - closing files open by the user
934 */
935 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
936                            struct ntvfs_request *req)
937 {
938         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
939                                     struct ipc_private);
940         struct pipe_state *p, *next;
941         
942         for (p=ipriv->pipe_list; p; p=next) {
943                 next = p->next;
944                 if (p->handle->session_info == req->session_info) {
945                         talloc_free(p);
946                 }
947         }
948
949         return NT_STATUS_OK;
950 }
951
952 /*
953   setup for an async call
954 */
955 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
956                                 struct ntvfs_request *req,
957                                 void *private_data)
958 {
959         return NT_STATUS_OK;
960 }
961
962 /*
963   cancel an async call
964 */
965 static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
966                            struct ntvfs_request *req)
967 {
968         return NT_STATUS_UNSUCCESSFUL;
969 }
970
971 /*
972   lock a byte range
973 */
974 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
975                          struct ntvfs_request *req, union smb_lock *lck)
976 {
977         return NT_STATUS_ACCESS_DENIED;
978 }
979
980 /*
981   set info on a open file
982 */
983 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
984                                 struct ntvfs_request *req, union smb_setfileinfo *info)
985 {
986         return NT_STATUS_ACCESS_DENIED;
987 }
988
989 /*
990   query info on a open file
991 */
992 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
993                               struct ntvfs_request *req, union smb_fileinfo *info)
994 {
995         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
996                                     struct ipc_private);
997         struct pipe_state *p = pipe_state_find(ipriv, info->generic.in.file.ntvfs);
998         if (!p) {
999                 return NT_STATUS_INVALID_HANDLE;
1000         }
1001         switch (info->generic.level) {
1002         case RAW_FILEINFO_GENERIC: 
1003         {
1004                 ZERO_STRUCT(info->generic.out);
1005                 info->generic.out.attrib = FILE_ATTRIBUTE_NORMAL;
1006                 info->generic.out.fname.s = strrchr(p->pipe_name, '\\');
1007                 info->generic.out.alloc_size = 4096;
1008                 info->generic.out.nlink = 1;
1009                 /* What the heck?  Match Win2k3: IPC$ pipes are delete pending */
1010                 info->generic.out.delete_pending = 1;
1011                 return NT_STATUS_OK;
1012         }
1013         case RAW_FILEINFO_ALT_NAME_INFO:
1014         case RAW_FILEINFO_ALT_NAME_INFORMATION:
1015         case RAW_FILEINFO_STREAM_INFO:
1016         case RAW_FILEINFO_STREAM_INFORMATION:
1017         case RAW_FILEINFO_COMPRESSION_INFO:
1018         case RAW_FILEINFO_COMPRESSION_INFORMATION:
1019         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
1020         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
1021                 return NT_STATUS_INVALID_PARAMETER;
1022         case  RAW_FILEINFO_ALL_EAS:
1023                 return NT_STATUS_ACCESS_DENIED;
1024         default:
1025                 return ntvfs_map_qfileinfo(ntvfs, req, info);
1026         }
1027         
1028         return NT_STATUS_ACCESS_DENIED;
1029 }
1030
1031
1032 /*
1033   return filesystem info
1034 */
1035 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
1036                            struct ntvfs_request *req, union smb_fsinfo *fs)
1037 {
1038         return NT_STATUS_ACCESS_DENIED;
1039 }
1040
1041 /*
1042   return print queue info
1043 */
1044 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
1045                         struct ntvfs_request *req, union smb_lpq *lpq)
1046 {
1047         return NT_STATUS_ACCESS_DENIED;
1048 }
1049
1050 /* 
1051    list files in a directory matching a wildcard pattern
1052 */
1053 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
1054                           struct ntvfs_request *req, union smb_search_first *io,
1055                           void *search_private, 
1056                           bool (*callback)(void *, const union smb_search_data *))
1057 {
1058         return NT_STATUS_ACCESS_DENIED;
1059 }
1060
1061 /* 
1062    continue listing files in a directory 
1063 */
1064 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
1065                          struct ntvfs_request *req, union smb_search_next *io,
1066                          void *search_private, 
1067                          bool (*callback)(void *, const union smb_search_data *))
1068 {
1069         return NT_STATUS_ACCESS_DENIED;
1070 }
1071
1072 /* 
1073    end listing files in a directory 
1074 */
1075 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
1076                           struct ntvfs_request *req, union smb_search_close *io)
1077 {
1078         return NT_STATUS_ACCESS_DENIED;
1079 }
1080
1081 struct ipc_trans_state {
1082         struct ipc_private *ipriv;
1083         struct pipe_state *p;
1084         struct ntvfs_request *req;
1085         struct smb_trans2 *trans;
1086         struct iovec writev_iov;
1087         struct ipc_readv_next_vector_state next_vector;
1088 };
1089
1090 static void ipc_trans_writev_done(struct tevent_req *subreq);
1091 static void ipc_trans_readv_done(struct tevent_req *subreq);
1092
1093 /* SMBtrans - handle a DCERPC command */
1094 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
1095                                struct ntvfs_request *req, struct smb_trans2 *trans)
1096 {
1097         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
1098                                     struct ipc_private);
1099         struct pipe_state *p;
1100         DATA_BLOB fnum_key;
1101         uint16_t fnum;
1102         struct ipc_trans_state *state;
1103         struct tevent_req *subreq;
1104
1105         /*
1106          * the fnum is in setup[1], a 16 bit value
1107          * the setup[*] values are already in host byteorder
1108          * but ntvfs_handle_search_by_wire_key() expects
1109          * network byteorder
1110          */
1111         SSVAL(&fnum, 0, trans->in.setup[1]);
1112         fnum_key = data_blob_const(&fnum, 2);
1113
1114         p = pipe_state_find_key(ipriv, req, &fnum_key);
1115         if (!p) {
1116                 return NT_STATUS_INVALID_HANDLE;
1117         }
1118
1119         /* TODO: check if this os the correct logic */
1120         if (tevent_queue_length(p->read_queue) > 0) {
1121                 return NT_STATUS_PIPE_BUSY;
1122         }
1123
1124         state = talloc(req, struct ipc_trans_state);
1125         NT_STATUS_HAVE_NO_MEMORY(state);
1126
1127         trans->out.setup_count = 0;
1128         trans->out.setup = NULL;
1129         trans->out.params = data_blob(NULL, 0);
1130         trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
1131         NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
1132
1133         state->ipriv = ipriv;
1134         state->p = p;
1135         state->req = req;
1136         state->trans = trans;
1137         state->writev_iov.iov_base = trans->in.data.data;
1138         state->writev_iov.iov_len = trans->in.data.length;
1139
1140         ipc_readv_next_vector_init(&state->next_vector,
1141                                    trans->out.data.data,
1142                                    trans->out.data.length);
1143
1144         subreq = tstream_writev_queue_send(state,
1145                                            ipriv->ntvfs->ctx->event_ctx,
1146                                            p->npipe,
1147                                            p->write_queue,
1148                                            &state->writev_iov, 1);
1149         NT_STATUS_HAVE_NO_MEMORY(subreq);
1150         tevent_req_set_callback(subreq, ipc_trans_writev_done, state);
1151
1152         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1153         return NT_STATUS_OK;
1154 }
1155
1156 static void ipc_trans_writev_done(struct tevent_req *subreq)
1157 {
1158         struct ipc_trans_state *state =
1159                 tevent_req_callback_data(subreq,
1160                 struct ipc_trans_state);
1161         struct ipc_private *ipriv = state->ipriv;
1162         struct pipe_state *p = state->p;
1163         struct ntvfs_request *req = state->req;
1164         int ret;
1165         int sys_errno;
1166         NTSTATUS status;
1167
1168         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1169         TALLOC_FREE(subreq);
1170         if (ret == 0) {
1171                 status = NT_STATUS_PIPE_DISCONNECTED;
1172                 goto reply;
1173         } else if (ret == -1) {
1174                 status = map_nt_error_from_unix(sys_errno);
1175                 goto reply;
1176         }
1177
1178         subreq = tstream_readv_pdu_queue_send(state,
1179                                               ipriv->ntvfs->ctx->event_ctx,
1180                                               p->npipe,
1181                                               p->read_queue,
1182                                               ipc_readv_next_vector,
1183                                               &state->next_vector);
1184         if (!subreq) {
1185                 status = NT_STATUS_NO_MEMORY;
1186                 goto reply;
1187         }
1188         tevent_req_set_callback(subreq, ipc_trans_readv_done, state);
1189         return;
1190
1191 reply:
1192         req->async_states->status = status;
1193         req->async_states->send_fn(req);
1194 }
1195
1196 static void ipc_trans_readv_done(struct tevent_req *subreq)
1197 {
1198         struct ipc_trans_state *state =
1199                 tevent_req_callback_data(subreq,
1200                 struct ipc_trans_state);
1201         struct ntvfs_request *req = state->req;
1202         struct smb_trans2 *trans = state->trans;
1203         int ret;
1204         int sys_errno;
1205         NTSTATUS status;
1206
1207         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
1208         TALLOC_FREE(subreq);
1209         if (ret == -1) {
1210                 status = map_nt_error_from_unix(sys_errno);
1211                 goto reply;
1212         }
1213
1214         status = NT_STATUS_OK;
1215         if (state->next_vector.remaining > 0) {
1216                 status = STATUS_BUFFER_OVERFLOW;
1217         }
1218
1219         trans->out.data.length = ret;
1220
1221 reply:
1222         req->async_states->status = status;
1223         req->async_states->send_fn(req);
1224 }
1225
1226 /* SMBtrans - set named pipe state */
1227 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
1228                                       struct ntvfs_request *req, struct smb_trans2 *trans)
1229 {
1230         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
1231                                     struct ipc_private);
1232         struct pipe_state *p;
1233         DATA_BLOB fnum_key;
1234
1235         /* the fnum is in setup[1] */
1236         fnum_key = data_blob_const(&trans->in.setup[1], sizeof(trans->in.setup[1]));
1237
1238         p = pipe_state_find_key(ipriv, req, &fnum_key);
1239         if (!p) {
1240                 return NT_STATUS_INVALID_HANDLE;
1241         }
1242
1243         if (trans->in.params.length != 2) {
1244                 return NT_STATUS_INVALID_PARAMETER;
1245         }
1246         // TODO...
1247         p->device_state = SVAL(trans->in.params.data, 0);
1248
1249         trans->out.setup_count = 0;
1250         trans->out.setup = NULL;
1251         trans->out.params = data_blob(NULL, 0);
1252         trans->out.data = data_blob(NULL, 0);
1253
1254         return NT_STATUS_OK;
1255 }
1256
1257
1258 /* SMBtrans - used to provide access to SMB pipes */
1259 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
1260                                 struct ntvfs_request *req, struct smb_trans2 *trans)
1261 {
1262         NTSTATUS status;
1263
1264         if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
1265                 return ipc_rap_call(req, ntvfs->ctx->event_ctx, ntvfs->ctx->lp_ctx, trans);
1266
1267         if (trans->in.setup_count != 2) {
1268                 return NT_STATUS_INVALID_PARAMETER;
1269         }
1270
1271         switch (trans->in.setup[0]) {
1272         case TRANSACT_SETNAMEDPIPEHANDLESTATE:
1273                 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
1274                 break;
1275         case TRANSACT_DCERPCCMD:
1276                 status = ipc_dcerpc_cmd(ntvfs, req, trans);
1277                 break;
1278         default:
1279                 status = NT_STATUS_INVALID_PARAMETER;
1280                 break;
1281         }
1282
1283         return status;
1284 }
1285
1286 struct ipc_ioctl_state {
1287         struct ipc_private *ipriv;
1288         struct pipe_state *p;
1289         struct ntvfs_request *req;
1290         union smb_ioctl *io;
1291         struct iovec writev_iov;
1292         struct ipc_readv_next_vector_state next_vector;
1293 };
1294
1295 static void ipc_ioctl_writev_done(struct tevent_req *subreq);
1296 static void ipc_ioctl_readv_done(struct tevent_req *subreq);
1297
1298 static NTSTATUS ipc_ioctl_smb2(struct ntvfs_module_context *ntvfs,
1299                                struct ntvfs_request *req, union smb_ioctl *io)
1300 {
1301         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
1302                                     struct ipc_private);
1303         struct pipe_state *p;
1304         struct ipc_ioctl_state *state;
1305         struct tevent_req *subreq;
1306
1307         switch (io->smb2.in.function) {
1308         case FSCTL_NAMED_PIPE_READ_WRITE:
1309                 break;
1310
1311         default:
1312                 return NT_STATUS_FS_DRIVER_REQUIRED;
1313         }
1314
1315         p = pipe_state_find(ipriv, io->smb2.in.file.ntvfs);
1316         if (!p) {
1317                 return NT_STATUS_INVALID_HANDLE;
1318         }
1319
1320         /* TODO: check if this os the correct logic */
1321         if (tevent_queue_length(p->read_queue) > 0) {
1322                 return NT_STATUS_PIPE_BUSY;
1323         }
1324
1325         state = talloc(req, struct ipc_ioctl_state);
1326         NT_STATUS_HAVE_NO_MEMORY(state);
1327
1328         io->smb2.out._pad       = 0;
1329         io->smb2.out.function   = io->smb2.in.function;
1330         io->smb2.out.unknown2   = 0;
1331         io->smb2.out.unknown3   = 0;
1332         io->smb2.out.in         = io->smb2.in.out;
1333         io->smb2.out.out = data_blob_talloc(req, NULL, io->smb2.in.max_response_size);
1334         NT_STATUS_HAVE_NO_MEMORY(io->smb2.out.out.data);
1335
1336         state->ipriv = ipriv;
1337         state->p = p;
1338         state->req = req;
1339         state->io = io;
1340         state->writev_iov.iov_base = io->smb2.in.out.data;
1341         state->writev_iov.iov_len = io->smb2.in.out.length;
1342
1343         ipc_readv_next_vector_init(&state->next_vector,
1344                                    io->smb2.out.out.data,
1345                                    io->smb2.out.out.length);
1346
1347         subreq = tstream_writev_queue_send(state,
1348                                            ipriv->ntvfs->ctx->event_ctx,
1349                                            p->npipe,
1350                                            p->write_queue,
1351                                            &state->writev_iov, 1);
1352         NT_STATUS_HAVE_NO_MEMORY(subreq);
1353         tevent_req_set_callback(subreq, ipc_ioctl_writev_done, state);
1354
1355         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1356         return NT_STATUS_OK;
1357 }
1358
1359 static void ipc_ioctl_writev_done(struct tevent_req *subreq)
1360 {
1361         struct ipc_ioctl_state *state =
1362                 tevent_req_callback_data(subreq,
1363                 struct ipc_ioctl_state);
1364         struct ipc_private *ipriv = state->ipriv;
1365         struct pipe_state *p = state->p;
1366         struct ntvfs_request *req = state->req;
1367         int ret;
1368         int sys_errno;
1369         NTSTATUS status;
1370
1371         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1372         TALLOC_FREE(subreq);
1373         if (ret == -1) {
1374                 status = map_nt_error_from_unix(sys_errno);
1375                 goto reply;
1376         }
1377
1378         subreq = tstream_readv_pdu_queue_send(state,
1379                                               ipriv->ntvfs->ctx->event_ctx,
1380                                               p->npipe,
1381                                               p->read_queue,
1382                                               ipc_readv_next_vector,
1383                                               &state->next_vector);
1384         if (!subreq) {
1385                 status = NT_STATUS_NO_MEMORY;
1386                 goto reply;
1387         }
1388         tevent_req_set_callback(subreq, ipc_ioctl_readv_done, state);
1389         return;
1390
1391 reply:
1392         req->async_states->status = status;
1393         req->async_states->send_fn(req);
1394 }
1395
1396 static void ipc_ioctl_readv_done(struct tevent_req *subreq)
1397 {
1398         struct ipc_ioctl_state *state =
1399                 tevent_req_callback_data(subreq,
1400                 struct ipc_ioctl_state);
1401         struct ntvfs_request *req = state->req;
1402         union smb_ioctl *io = state->io;
1403         int ret;
1404         int sys_errno;
1405         NTSTATUS status;
1406
1407         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
1408         TALLOC_FREE(subreq);
1409         if (ret == -1) {
1410                 status = map_nt_error_from_unix(sys_errno);
1411                 goto reply;
1412         }
1413
1414         status = NT_STATUS_OK;
1415         if (state->next_vector.remaining > 0) {
1416                 status = STATUS_BUFFER_OVERFLOW;
1417         }
1418
1419         io->smb2.out.out.length = ret;
1420
1421 reply:
1422         req->async_states->status = status;
1423         req->async_states->send_fn(req);
1424 }
1425
1426
1427 /*
1428   ioctl interface
1429 */
1430 static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
1431                           struct ntvfs_request *req, union smb_ioctl *io)
1432 {
1433         switch (io->generic.level) {
1434         case RAW_IOCTL_SMB2:
1435                 return ipc_ioctl_smb2(ntvfs, req, io);
1436
1437         case RAW_IOCTL_SMB2_NO_HANDLE:
1438                 return NT_STATUS_FS_DRIVER_REQUIRED;
1439
1440         default:
1441                 return NT_STATUS_ACCESS_DENIED;
1442         }
1443
1444         return NT_STATUS_ACCESS_DENIED;
1445 }
1446
1447
1448 /*
1449   initialialise the IPC backend, registering ourselves with the ntvfs subsystem
1450  */
1451 NTSTATUS ntvfs_ipc_init(void)
1452 {
1453         NTSTATUS ret;
1454         struct ntvfs_ops ops;
1455         NTVFS_CURRENT_CRITICAL_SIZES(vers);
1456
1457         ZERO_STRUCT(ops);
1458         
1459         /* fill in the name and type */
1460         ops.name = "default";
1461         ops.type = NTVFS_IPC;
1462
1463         /* fill in all the operations */
1464         ops.connect = ipc_connect;
1465         ops.disconnect = ipc_disconnect;
1466         ops.unlink = ipc_unlink;
1467         ops.chkpath = ipc_chkpath;
1468         ops.qpathinfo = ipc_qpathinfo;
1469         ops.setpathinfo = ipc_setpathinfo;
1470         ops.open = ipc_open;
1471         ops.mkdir = ipc_mkdir;
1472         ops.rmdir = ipc_rmdir;
1473         ops.rename = ipc_rename;
1474         ops.copy = ipc_copy;
1475         ops.ioctl = ipc_ioctl;
1476         ops.read = ipc_read;
1477         ops.write = ipc_write;
1478         ops.seek = ipc_seek;
1479         ops.flush = ipc_flush;  
1480         ops.close = ipc_close;
1481         ops.exit = ipc_exit;
1482         ops.lock = ipc_lock;
1483         ops.setfileinfo = ipc_setfileinfo;
1484         ops.qfileinfo = ipc_qfileinfo;
1485         ops.fsinfo = ipc_fsinfo;
1486         ops.lpq = ipc_lpq;
1487         ops.search_first = ipc_search_first;
1488         ops.search_next = ipc_search_next;
1489         ops.search_close = ipc_search_close;
1490         ops.trans = ipc_trans;
1491         ops.logoff = ipc_logoff;
1492         ops.async_setup = ipc_async_setup;
1493         ops.cancel = ipc_cancel;
1494
1495         /* register ourselves with the NTVFS subsystem. */
1496         ret = ntvfs_register(&ops, &vers);
1497
1498         if (!NT_STATUS_IS_OK(ret)) {
1499                 DEBUG(0,("Failed to register IPC backend!\n"));
1500                 return ret;
1501         }
1502
1503         return ret;
1504 }