2 Unix SMB/CIFS implementation.
3 default IPC$ NTVFS backend
5 Copyright (C) Andrew Tridgell 2003
6 Copyright (C) Stefan (metze) Metzmacher 2004-2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 this implements the IPC$ backend, called by the NTVFS subsystem to
24 handle requests on IPC$ shares
29 #include "lib/util/dlinklist.h"
30 #include "ntvfs/ntvfs.h"
31 #include "libcli/rap/rap.h"
32 #include "ntvfs/ipc/proto.h"
33 #include "rpc_server/dcerpc_server.h"
34 #include "libcli/raw/ioctl.h"
36 /* this is the private structure used to keep the state of an open
37 ipc$ connection. It needs to keep information about all open
40 struct ntvfs_module_context *ntvfs;
42 struct dcesrv_context *dcesrv;
44 /* a list of open pipes */
46 struct pipe_state *next, *prev;
47 struct ipc_private *private;
48 const char *pipe_name;
49 struct ntvfs_handle *handle;
50 struct dcesrv_connection *dce_conn;
57 find a open pipe give a file handle
59 static struct pipe_state *pipe_state_find(struct ipc_private *private, struct ntvfs_handle *handle)
64 p = ntvfs_handle_get_backend_data(handle, private->ntvfs);
67 s = talloc_get_type(p, struct pipe_state);
74 find a open pipe give a wire fnum
76 static struct pipe_state *pipe_state_find_key(struct ipc_private *private, struct ntvfs_request *req, const DATA_BLOB *key)
78 struct ntvfs_handle *h;
80 h = ntvfs_handle_search_by_wire_key(private->ntvfs, req, key);
83 return pipe_state_find(private, h);
88 connect to a share - always works
90 static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
91 struct ntvfs_request *req, const char *sharename)
94 struct ipc_private *private;
96 ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "IPC");
97 NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
99 ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "IPC");
100 NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
102 /* prepare the private state for this connection */
103 private = talloc(ntvfs, struct ipc_private);
104 NT_STATUS_HAVE_NO_MEMORY(private);
106 ntvfs->private_data = private;
108 private->ntvfs = ntvfs;
109 private->pipe_list = NULL;
111 /* setup the DCERPC server subsystem */
112 status = dcesrv_init_ipc_context(private, &private->dcesrv);
113 NT_STATUS_NOT_OK_RETURN(status);
119 disconnect from a share
121 static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs)
129 static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
130 struct ntvfs_request *req,
131 union smb_unlink *unl)
133 return NT_STATUS_ACCESS_DENIED;
137 check if a directory exists
139 static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
140 struct ntvfs_request *req,
141 union smb_chkpath *cp)
143 return NT_STATUS_ACCESS_DENIED;
147 return info on a pathname
149 static NTSTATUS ipc_qpathinfo(struct ntvfs_module_context *ntvfs,
150 struct ntvfs_request *req, union smb_fileinfo *info)
152 return NT_STATUS_ACCESS_DENIED;
156 set info on a pathname
158 static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
159 struct ntvfs_request *req, union smb_setfileinfo *st)
161 return NT_STATUS_ACCESS_DENIED;
166 destroy a open pipe structure
168 static int ipc_fd_destructor(struct pipe_state *p)
170 DLIST_REMOVE(p->private->pipe_list, p);
174 static struct socket_address *ipc_get_my_addr(struct dcesrv_connection *dce_conn, TALLOC_CTX *mem_ctx)
176 struct ipc_private *private = dce_conn->transport.private_data;
178 return ntvfs_get_my_addr(private->ntvfs, mem_ctx);
181 static struct socket_address *ipc_get_peer_addr(struct dcesrv_connection *dce_conn, TALLOC_CTX *mem_ctx)
183 struct ipc_private *private = dce_conn->transport.private_data;
185 return ntvfs_get_peer_addr(private->ntvfs, mem_ctx);
189 open a file backend - used for MSRPC pipes
191 static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
192 struct ntvfs_request *req, const char *fname,
193 struct pipe_state **ps)
195 struct pipe_state *p;
197 struct dcerpc_binding *ep_description;
198 struct ipc_private *private = ntvfs->private_data;
199 struct ntvfs_handle *h;
201 status = ntvfs_handle_new(ntvfs, req, &h);
202 NT_STATUS_NOT_OK_RETURN(status);
204 p = talloc(h, struct pipe_state);
205 NT_STATUS_HAVE_NO_MEMORY(p);
207 ep_description = talloc(req, struct dcerpc_binding);
208 NT_STATUS_HAVE_NO_MEMORY(ep_description);
210 while (fname[0] == '\\') fname++;
212 p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
213 NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
216 p->ipc_state = 0x5ff;
219 we're all set, now ask the dcerpc server subsystem to open the
220 endpoint. At this stage the pipe isn't bound, so we don't
221 know what interface the user actually wants, just that they want
222 one of the interfaces attached to this pipe endpoint.
224 ep_description->transport = NCACN_NP;
225 ep_description->endpoint = talloc_reference(ep_description, p->pipe_name);
227 /* The session info is refcount-increased in the
228 * dcesrv_endpoint_search_connect() function
230 status = dcesrv_endpoint_search_connect(private->dcesrv,
234 ntvfs->ctx->event_ctx,
236 ntvfs->ctx->server_id,
239 NT_STATUS_NOT_OK_RETURN(status);
241 p->dce_conn->transport.private_data = private;
242 p->dce_conn->transport.report_output_data = NULL;
243 p->dce_conn->transport.get_my_addr = ipc_get_my_addr;
244 p->dce_conn->transport.get_peer_addr = ipc_get_peer_addr;
246 DLIST_ADD(private->pipe_list, p);
248 p->private = private;
250 talloc_set_destructor(p, ipc_fd_destructor);
252 status = ntvfs_handle_set_backend_data(h, private->ntvfs, p);
253 NT_STATUS_NOT_OK_RETURN(status);
260 open a file with ntcreatex - used for MSRPC pipes
262 static NTSTATUS ipc_open_ntcreatex(struct ntvfs_module_context *ntvfs,
263 struct ntvfs_request *req, union smb_open *oi)
265 struct pipe_state *p;
268 status = ipc_open_generic(ntvfs, req, oi->ntcreatex.in.fname, &p);
269 if (!NT_STATUS_IS_OK(status)) {
273 ZERO_STRUCT(oi->ntcreatex.out);
274 oi->ntcreatex.out.file.ntvfs= p->handle;
275 oi->ntcreatex.out.ipc_state = p->ipc_state;
276 oi->ntcreatex.out.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
282 open a file with openx - used for MSRPC pipes
284 static NTSTATUS ipc_open_openx(struct ntvfs_module_context *ntvfs,
285 struct ntvfs_request *req, union smb_open *oi)
287 struct pipe_state *p;
289 const char *fname = oi->openx.in.fname;
291 status = ipc_open_generic(ntvfs, req, fname, &p);
292 if (!NT_STATUS_IS_OK(status)) {
296 ZERO_STRUCT(oi->openx.out);
297 oi->openx.out.file.ntvfs= p->handle;
298 oi->openx.out.ftype = 2;
299 oi->openx.out.devstate = p->ipc_state;
305 open a file with SMB2 Create - used for MSRPC pipes
307 static NTSTATUS ipc_open_smb2(struct ntvfs_module_context *ntvfs,
308 struct ntvfs_request *req, union smb_open *oi)
310 struct pipe_state *p;
313 status = ipc_open_generic(ntvfs, req, oi->smb2.in.fname, &p);
314 NT_STATUS_NOT_OK_RETURN(status);
316 oi->smb2.out.file.ntvfs = p->handle;
317 oi->smb2.out.oplock_flags = oi->smb2.in.oplock_flags;
318 oi->smb2.out.create_action = NTCREATEX_ACTION_EXISTED;
319 oi->smb2.out.create_time = 0;
320 oi->smb2.out.access_time = 0;
321 oi->smb2.out.write_time = 0;
322 oi->smb2.out.change_time = 0;
323 oi->smb2.out.alloc_size = 4096;
324 oi->smb2.out.size = 0;
325 oi->smb2.out.file_attr = FILE_ATTRIBUTE_NORMAL;
326 oi->smb2.out._pad = 0;
327 oi->smb2.out.blob = data_blob(NULL, 0);
333 open a file - used for MSRPC pipes
335 static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
336 struct ntvfs_request *req, union smb_open *oi)
340 switch (oi->generic.level) {
341 case RAW_OPEN_NTCREATEX:
342 status = ipc_open_ntcreatex(ntvfs, req, oi);
345 status = ipc_open_openx(ntvfs, req, oi);
348 status = ipc_open_smb2(ntvfs, req, oi);
351 status = NT_STATUS_NOT_SUPPORTED;
361 static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
362 struct ntvfs_request *req, union smb_mkdir *md)
364 return NT_STATUS_ACCESS_DENIED;
370 static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
371 struct ntvfs_request *req, struct smb_rmdir *rd)
373 return NT_STATUS_ACCESS_DENIED;
377 rename a set of files
379 static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
380 struct ntvfs_request *req, union smb_rename *ren)
382 return NT_STATUS_ACCESS_DENIED;
388 static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
389 struct ntvfs_request *req, struct smb_copy *cp)
391 return NT_STATUS_ACCESS_DENIED;
394 static NTSTATUS ipc_readx_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
396 DATA_BLOB *blob = private_data;
398 if (out->length < blob->length) {
399 blob->length = out->length;
401 memcpy(blob->data, out->data, blob->length);
402 *nwritten = blob->length;
409 static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
410 struct ntvfs_request *req, union smb_read *rd)
412 struct ipc_private *private = ntvfs->private_data;
414 struct pipe_state *p;
415 NTSTATUS status = NT_STATUS_OK;
417 if (rd->generic.level != RAW_READ_GENERIC) {
418 return ntvfs_map_read(ntvfs, req, rd);
421 p = pipe_state_find(private, rd->readx.in.file.ntvfs);
423 return NT_STATUS_INVALID_HANDLE;
426 data.length = rd->readx.in.maxcnt;
427 data.data = rd->readx.out.data;
428 if (data.length > UINT16_MAX) {
429 data.length = UINT16_MAX;
432 if (data.length != 0) {
433 status = dcesrv_output(p->dce_conn, &data, ipc_readx_dcesrv_output);
434 if (NT_STATUS_IS_ERR(status)) {
439 rd->readx.out.remaining = 0;
440 rd->readx.out.compaction_mode = 0;
441 rd->readx.out.nread = data.length;
449 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
450 struct ntvfs_request *req, union smb_write *wr)
452 struct ipc_private *private = ntvfs->private_data;
454 struct pipe_state *p;
457 if (wr->generic.level != RAW_WRITE_GENERIC) {
458 return ntvfs_map_write(ntvfs, req, wr);
461 data.data = discard_const_p(void, wr->writex.in.data);
462 data.length = wr->writex.in.count;
464 p = pipe_state_find(private, wr->writex.in.file.ntvfs);
466 return NT_STATUS_INVALID_HANDLE;
469 status = dcesrv_input(p->dce_conn, &data);
470 if (!NT_STATUS_IS_OK(status)) {
474 wr->writex.out.nwritten = data.length;
475 wr->writex.out.remaining = 0;
483 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
484 struct ntvfs_request *req,
487 return NT_STATUS_ACCESS_DENIED;
493 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
494 struct ntvfs_request *req,
497 return NT_STATUS_ACCESS_DENIED;
503 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
504 struct ntvfs_request *req, union smb_close *io)
506 struct ipc_private *private = ntvfs->private_data;
507 struct pipe_state *p;
509 if (io->generic.level != RAW_CLOSE_CLOSE) {
510 return ntvfs_map_close(ntvfs, req, io);
513 p = pipe_state_find(private, io->close.in.file.ntvfs);
515 return NT_STATUS_INVALID_HANDLE;
526 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
527 struct ntvfs_request *req)
529 struct ipc_private *private = ntvfs->private_data;
530 struct pipe_state *p, *next;
532 for (p=private->pipe_list; p; p=next) {
534 if (p->handle->session_info == req->session_info &&
535 p->handle->smbpid == req->smbpid) {
544 logoff - closing files open by the user
546 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
547 struct ntvfs_request *req)
549 struct ipc_private *private = ntvfs->private_data;
550 struct pipe_state *p, *next;
552 for (p=private->pipe_list; p; p=next) {
554 if (p->handle->session_info == req->session_info) {
563 setup for an async call
565 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
566 struct ntvfs_request *req,
575 static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
576 struct ntvfs_request *req)
578 return NT_STATUS_UNSUCCESSFUL;
584 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
585 struct ntvfs_request *req, union smb_lock *lck)
587 return NT_STATUS_ACCESS_DENIED;
591 set info on a open file
593 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
594 struct ntvfs_request *req, union smb_setfileinfo *info)
596 return NT_STATUS_ACCESS_DENIED;
600 query info on a open file
602 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
603 struct ntvfs_request *req, union smb_fileinfo *info)
605 return NT_STATUS_ACCESS_DENIED;
610 return filesystem info
612 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
613 struct ntvfs_request *req, union smb_fsinfo *fs)
615 return NT_STATUS_ACCESS_DENIED;
619 return print queue info
621 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
622 struct ntvfs_request *req, union smb_lpq *lpq)
624 return NT_STATUS_ACCESS_DENIED;
628 list files in a directory matching a wildcard pattern
630 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
631 struct ntvfs_request *req, union smb_search_first *io,
632 void *search_private,
633 BOOL (*callback)(void *, union smb_search_data *))
635 return NT_STATUS_ACCESS_DENIED;
639 continue listing files in a directory
641 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
642 struct ntvfs_request *req, union smb_search_next *io,
643 void *search_private,
644 BOOL (*callback)(void *, union smb_search_data *))
646 return NT_STATUS_ACCESS_DENIED;
650 end listing files in a directory
652 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
653 struct ntvfs_request *req, union smb_search_close *io)
655 return NT_STATUS_ACCESS_DENIED;
658 static NTSTATUS ipc_trans_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
660 NTSTATUS status = NT_STATUS_OK;
661 DATA_BLOB *blob = private_data;
663 if (out->length > blob->length) {
664 status = STATUS_BUFFER_OVERFLOW;
667 if (out->length < blob->length) {
668 blob->length = out->length;
670 memcpy(blob->data, out->data, blob->length);
671 *nwritten = blob->length;
675 /* SMBtrans - handle a DCERPC command */
676 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
677 struct ntvfs_request *req, struct smb_trans2 *trans)
679 struct pipe_state *p;
680 struct ipc_private *private = ntvfs->private_data;
686 * the fnum is in setup[1], a 16 bit value
687 * the setup[*] values are already in host byteorder
688 * but ntvfs_handle_search_by_wire_key() expects
691 SSVAL(&fnum, 0, trans->in.setup[1]);
692 fnum_key = data_blob_const(&fnum, 2);
694 p = pipe_state_find_key(private, req, &fnum_key);
696 return NT_STATUS_INVALID_HANDLE;
699 trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
700 if (!trans->out.data.data) {
701 return NT_STATUS_NO_MEMORY;
704 /* pass the data to the dcerpc server. Note that we don't
705 expect this to fail, and things like NDR faults are not
706 reported at this stage. Those sorts of errors happen in the
707 dcesrv_output stage */
708 status = dcesrv_input(p->dce_conn, &trans->in.data);
709 if (!NT_STATUS_IS_OK(status)) {
714 now ask the dcerpc system for some output. This doesn't yet handle
715 async calls. Again, we only expect NT_STATUS_OK. If the call fails then
716 the error is encoded at the dcerpc level
718 status = dcesrv_output(p->dce_conn, &trans->out.data, ipc_trans_dcesrv_output);
719 if (NT_STATUS_IS_ERR(status)) {
723 trans->out.setup_count = 0;
724 trans->out.setup = NULL;
725 trans->out.params = data_blob(NULL, 0);
731 /* SMBtrans - set named pipe state */
732 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
733 struct ntvfs_request *req, struct smb_trans2 *trans)
735 struct ipc_private *private = ntvfs->private_data;
736 struct pipe_state *p;
739 /* the fnum is in setup[1] */
740 fnum_key = data_blob_const(&trans->in.setup[1], sizeof(trans->in.setup[1]));
742 p = pipe_state_find_key(private, req, &fnum_key);
744 return NT_STATUS_INVALID_HANDLE;
747 if (trans->in.params.length != 2) {
748 return NT_STATUS_INVALID_PARAMETER;
750 p->ipc_state = SVAL(trans->in.params.data, 0);
752 trans->out.setup_count = 0;
753 trans->out.setup = NULL;
754 trans->out.params = data_blob(NULL, 0);
755 trans->out.data = data_blob(NULL, 0);
761 /* SMBtrans - used to provide access to SMB pipes */
762 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
763 struct ntvfs_request *req, struct smb_trans2 *trans)
767 if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
768 return ipc_rap_call(req, trans);
770 if (trans->in.setup_count != 2) {
771 return NT_STATUS_INVALID_PARAMETER;
774 switch (trans->in.setup[0]) {
775 case TRANSACT_SETNAMEDPIPEHANDLESTATE:
776 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
778 case TRANSACT_DCERPCCMD:
779 status = ipc_dcerpc_cmd(ntvfs, req, trans);
782 status = NT_STATUS_INVALID_PARAMETER;
789 static NTSTATUS ipc_ioctl_smb2(struct ntvfs_module_context *ntvfs,
790 struct ntvfs_request *req, union smb_ioctl *io)
792 struct pipe_state *p;
793 struct ipc_private *private = ntvfs->private_data;
796 switch (io->smb2.in.function) {
797 case FSCTL_NAMED_PIPE_READ_WRITE:
801 return NT_STATUS_FS_DRIVER_REQUIRED;
804 p = pipe_state_find(private, io->smb2.in.file.ntvfs);
806 return NT_STATUS_INVALID_HANDLE;
809 io->smb2.out.out = data_blob_talloc(req, NULL, io->smb2.in.max_response_size);
810 NT_STATUS_HAVE_NO_MEMORY(io->smb2.out.out.data);
812 /* pass the data to the dcerpc server. Note that we don't
813 expect this to fail, and things like NDR faults are not
814 reported at this stage. Those sorts of errors happen in the
815 dcesrv_output stage */
816 status = dcesrv_input(p->dce_conn, &io->smb2.in.out);
817 NT_STATUS_NOT_OK_RETURN(status);
820 now ask the dcerpc system for some output. This doesn't yet handle
821 async calls. Again, we only expect NT_STATUS_OK. If the call fails then
822 the error is encoded at the dcerpc level
824 status = dcesrv_output(p->dce_conn, &io->smb2.out.out, ipc_trans_dcesrv_output);
825 NT_STATUS_IS_ERR_RETURN(status);
827 io->smb2.out._pad = 0;
828 io->smb2.out.function = io->smb2.in.function;
829 io->smb2.out.unknown2 = 0;
830 io->smb2.out.unknown3 = 0;
831 io->smb2.out.in = io->smb2.in.out;
839 static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
840 struct ntvfs_request *req, union smb_ioctl *io)
842 switch (io->generic.level) {
844 return ipc_ioctl_smb2(ntvfs, req, io);
846 case RAW_IOCTL_SMB2_NO_HANDLE:
847 return NT_STATUS_FS_DRIVER_REQUIRED;
850 return NT_STATUS_ACCESS_DENIED;
853 return NT_STATUS_ACCESS_DENIED;
858 initialialise the IPC backend, registering ourselves with the ntvfs subsystem
860 NTSTATUS ntvfs_ipc_init(void)
863 struct ntvfs_ops ops;
864 NTVFS_CURRENT_CRITICAL_SIZES(vers);
868 /* fill in the name and type */
869 ops.name = "default";
870 ops.type = NTVFS_IPC;
872 /* fill in all the operations */
873 ops.connect = ipc_connect;
874 ops.disconnect = ipc_disconnect;
875 ops.unlink = ipc_unlink;
876 ops.chkpath = ipc_chkpath;
877 ops.qpathinfo = ipc_qpathinfo;
878 ops.setpathinfo = ipc_setpathinfo;
880 ops.mkdir = ipc_mkdir;
881 ops.rmdir = ipc_rmdir;
882 ops.rename = ipc_rename;
884 ops.ioctl = ipc_ioctl;
886 ops.write = ipc_write;
888 ops.flush = ipc_flush;
889 ops.close = ipc_close;
892 ops.setfileinfo = ipc_setfileinfo;
893 ops.qfileinfo = ipc_qfileinfo;
894 ops.fsinfo = ipc_fsinfo;
896 ops.search_first = ipc_search_first;
897 ops.search_next = ipc_search_next;
898 ops.search_close = ipc_search_close;
899 ops.trans = ipc_trans;
900 ops.logoff = ipc_logoff;
901 ops.async_setup = ipc_async_setup;
902 ops.cancel = ipc_cancel;
904 /* register ourselves with the NTVFS subsystem. */
905 ret = ntvfs_register(&ops, &vers);
907 if (!NT_STATUS_IS_OK(ret)) {
908 DEBUG(0,("Failed to register IPC backend!\n"));