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