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 3 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, see <http://www.gnu.org/licenses/>.
22 this implements the IPC$ backend, called by the NTVFS subsystem to
23 handle requests on IPC$ shares
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 "rpc_server/dcerpc_server.h"
33 #include "libcli/raw/ioctl.h"
35 /* this is the private structure used to keep the state of an open
36 ipc$ connection. It needs to keep information about all open
39 struct ntvfs_module_context *ntvfs;
41 struct dcesrv_context *dcesrv;
43 /* a list of open pipes */
45 struct pipe_state *next, *prev;
46 struct ipc_private *private;
47 const char *pipe_name;
48 struct ntvfs_handle *handle;
49 struct dcesrv_connection *dce_conn;
56 find a open pipe give a file handle
58 static struct pipe_state *pipe_state_find(struct ipc_private *private, struct ntvfs_handle *handle)
63 p = ntvfs_handle_get_backend_data(handle, private->ntvfs);
66 s = talloc_get_type(p, struct pipe_state);
73 find a open pipe give a wire fnum
75 static struct pipe_state *pipe_state_find_key(struct ipc_private *private, struct ntvfs_request *req, const DATA_BLOB *key)
77 struct ntvfs_handle *h;
79 h = ntvfs_handle_search_by_wire_key(private->ntvfs, req, key);
82 return pipe_state_find(private, h);
87 connect to a share - always works
89 static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
90 struct ntvfs_request *req, const char *sharename)
93 struct ipc_private *private;
95 ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "IPC");
96 NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
98 ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "IPC");
99 NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
101 /* prepare the private state for this connection */
102 private = talloc(ntvfs, struct ipc_private);
103 NT_STATUS_HAVE_NO_MEMORY(private);
105 ntvfs->private_data = private;
107 private->ntvfs = ntvfs;
108 private->pipe_list = NULL;
110 /* setup the DCERPC server subsystem */
111 status = dcesrv_init_ipc_context(private, &private->dcesrv);
112 NT_STATUS_NOT_OK_RETURN(status);
118 disconnect from a share
120 static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs)
128 static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
129 struct ntvfs_request *req,
130 union smb_unlink *unl)
132 return NT_STATUS_ACCESS_DENIED;
136 check if a directory exists
138 static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
139 struct ntvfs_request *req,
140 union smb_chkpath *cp)
142 return NT_STATUS_ACCESS_DENIED;
146 return info on a pathname
148 static NTSTATUS ipc_qpathinfo(struct ntvfs_module_context *ntvfs,
149 struct ntvfs_request *req, union smb_fileinfo *info)
151 switch (info->generic.level) {
152 case RAW_FILEINFO_GENERIC:
153 return NT_STATUS_INVALID_DEVICE_REQUEST;
154 case RAW_FILEINFO_GETATTR:
155 return NT_STATUS_ACCESS_DENIED;
157 return ntvfs_map_qpathinfo(ntvfs, req, info);
162 set info on a pathname
164 static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
165 struct ntvfs_request *req, union smb_setfileinfo *st)
167 return NT_STATUS_ACCESS_DENIED;
172 destroy a open pipe structure
174 static int ipc_fd_destructor(struct pipe_state *p)
176 DLIST_REMOVE(p->private->pipe_list, p);
177 ntvfs_handle_remove_backend_data(p->handle, p->private->ntvfs);
181 static struct socket_address *ipc_get_my_addr(struct dcesrv_connection *dce_conn, TALLOC_CTX *mem_ctx)
183 struct ipc_private *private = dce_conn->transport.private_data;
185 return ntvfs_get_my_addr(private->ntvfs, mem_ctx);
188 static struct socket_address *ipc_get_peer_addr(struct dcesrv_connection *dce_conn, TALLOC_CTX *mem_ctx)
190 struct ipc_private *private = dce_conn->transport.private_data;
192 return ntvfs_get_peer_addr(private->ntvfs, mem_ctx);
196 open a file backend - used for MSRPC pipes
198 static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
199 struct ntvfs_request *req, const char *fname,
200 struct pipe_state **ps)
202 struct pipe_state *p;
204 struct dcerpc_binding *ep_description;
205 struct ipc_private *private = ntvfs->private_data;
206 struct ntvfs_handle *h;
208 status = ntvfs_handle_new(ntvfs, req, &h);
209 NT_STATUS_NOT_OK_RETURN(status);
211 p = talloc(h, struct pipe_state);
212 NT_STATUS_HAVE_NO_MEMORY(p);
214 ep_description = talloc(req, struct dcerpc_binding);
215 NT_STATUS_HAVE_NO_MEMORY(ep_description);
217 while (fname[0] == '\\') fname++;
219 p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
220 NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
223 p->ipc_state = 0x5ff;
226 we're all set, now ask the dcerpc server subsystem to open the
227 endpoint. At this stage the pipe isn't bound, so we don't
228 know what interface the user actually wants, just that they want
229 one of the interfaces attached to this pipe endpoint.
231 ep_description->transport = NCACN_NP;
232 ep_description->endpoint = talloc_reference(ep_description, p->pipe_name);
234 /* The session info is refcount-increased in the
235 * dcesrv_endpoint_search_connect() function
237 status = dcesrv_endpoint_search_connect(private->dcesrv,
241 ntvfs->ctx->event_ctx,
243 ntvfs->ctx->server_id,
246 NT_STATUS_NOT_OK_RETURN(status);
248 p->dce_conn->transport.private_data = private;
249 p->dce_conn->transport.report_output_data = NULL;
250 p->dce_conn->transport.get_my_addr = ipc_get_my_addr;
251 p->dce_conn->transport.get_peer_addr = ipc_get_peer_addr;
253 DLIST_ADD(private->pipe_list, p);
255 p->private = private;
257 talloc_set_destructor(p, ipc_fd_destructor);
259 status = ntvfs_handle_set_backend_data(h, private->ntvfs, p);
260 NT_STATUS_NOT_OK_RETURN(status);
267 open a file with ntcreatex - used for MSRPC pipes
269 static NTSTATUS ipc_open_ntcreatex(struct ntvfs_module_context *ntvfs,
270 struct ntvfs_request *req, union smb_open *oi)
272 struct pipe_state *p;
275 status = ipc_open_generic(ntvfs, req, oi->ntcreatex.in.fname, &p);
276 if (!NT_STATUS_IS_OK(status)) {
280 ZERO_STRUCT(oi->ntcreatex.out);
281 oi->ntcreatex.out.file.ntvfs= p->handle;
282 oi->ntcreatex.out.ipc_state = p->ipc_state;
283 oi->ntcreatex.out.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
289 open a file with openx - used for MSRPC pipes
291 static NTSTATUS ipc_open_openx(struct ntvfs_module_context *ntvfs,
292 struct ntvfs_request *req, union smb_open *oi)
294 struct pipe_state *p;
296 const char *fname = oi->openx.in.fname;
298 status = ipc_open_generic(ntvfs, req, fname, &p);
299 if (!NT_STATUS_IS_OK(status)) {
303 ZERO_STRUCT(oi->openx.out);
304 oi->openx.out.file.ntvfs= p->handle;
305 oi->openx.out.ftype = 2;
306 oi->openx.out.devstate = p->ipc_state;
312 open a file with SMB2 Create - used for MSRPC pipes
314 static NTSTATUS ipc_open_smb2(struct ntvfs_module_context *ntvfs,
315 struct ntvfs_request *req, union smb_open *oi)
317 struct pipe_state *p;
320 status = ipc_open_generic(ntvfs, req, oi->smb2.in.fname, &p);
321 NT_STATUS_NOT_OK_RETURN(status);
323 oi->smb2.out.file.ntvfs = p->handle;
324 oi->smb2.out.oplock_flags = oi->smb2.in.oplock_flags;
325 oi->smb2.out.create_action = NTCREATEX_ACTION_EXISTED;
326 oi->smb2.out.create_time = 0;
327 oi->smb2.out.access_time = 0;
328 oi->smb2.out.write_time = 0;
329 oi->smb2.out.change_time = 0;
330 oi->smb2.out.alloc_size = 4096;
331 oi->smb2.out.size = 0;
332 oi->smb2.out.file_attr = FILE_ATTRIBUTE_NORMAL;
333 oi->smb2.out._pad = 0;
334 oi->smb2.out.blob = data_blob(NULL, 0);
340 open a file - used for MSRPC pipes
342 static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
343 struct ntvfs_request *req, union smb_open *oi)
347 switch (oi->generic.level) {
348 case RAW_OPEN_NTCREATEX:
349 status = ipc_open_ntcreatex(ntvfs, req, oi);
352 status = ipc_open_openx(ntvfs, req, oi);
355 status = ipc_open_smb2(ntvfs, req, oi);
358 status = NT_STATUS_NOT_SUPPORTED;
368 static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
369 struct ntvfs_request *req, union smb_mkdir *md)
371 return NT_STATUS_ACCESS_DENIED;
377 static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
378 struct ntvfs_request *req, struct smb_rmdir *rd)
380 return NT_STATUS_ACCESS_DENIED;
384 rename a set of files
386 static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
387 struct ntvfs_request *req, union smb_rename *ren)
389 return NT_STATUS_ACCESS_DENIED;
395 static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
396 struct ntvfs_request *req, struct smb_copy *cp)
398 return NT_STATUS_ACCESS_DENIED;
401 static NTSTATUS ipc_readx_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
403 DATA_BLOB *blob = private_data;
405 if (out->length < blob->length) {
406 blob->length = out->length;
408 memcpy(blob->data, out->data, blob->length);
409 *nwritten = blob->length;
416 static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
417 struct ntvfs_request *req, union smb_read *rd)
419 struct ipc_private *private = ntvfs->private_data;
421 struct pipe_state *p;
422 NTSTATUS status = NT_STATUS_OK;
424 if (rd->generic.level != RAW_READ_GENERIC) {
425 return ntvfs_map_read(ntvfs, req, rd);
428 p = pipe_state_find(private, rd->readx.in.file.ntvfs);
430 return NT_STATUS_INVALID_HANDLE;
433 data.length = rd->readx.in.maxcnt;
434 data.data = rd->readx.out.data;
435 if (data.length > UINT16_MAX) {
436 data.length = UINT16_MAX;
439 if (data.length != 0) {
440 status = dcesrv_output(p->dce_conn, &data, ipc_readx_dcesrv_output);
441 if (NT_STATUS_IS_ERR(status)) {
446 rd->readx.out.remaining = 0;
447 rd->readx.out.compaction_mode = 0;
448 rd->readx.out.nread = data.length;
456 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
457 struct ntvfs_request *req, union smb_write *wr)
459 struct ipc_private *private = ntvfs->private_data;
461 struct pipe_state *p;
464 if (wr->generic.level != RAW_WRITE_GENERIC) {
465 return ntvfs_map_write(ntvfs, req, wr);
468 data.data = discard_const_p(void, wr->writex.in.data);
469 data.length = wr->writex.in.count;
471 p = pipe_state_find(private, wr->writex.in.file.ntvfs);
473 return NT_STATUS_INVALID_HANDLE;
476 status = dcesrv_input(p->dce_conn, &data);
477 if (!NT_STATUS_IS_OK(status)) {
481 wr->writex.out.nwritten = data.length;
482 wr->writex.out.remaining = 0;
490 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
491 struct ntvfs_request *req,
494 return NT_STATUS_ACCESS_DENIED;
500 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
501 struct ntvfs_request *req,
504 return NT_STATUS_ACCESS_DENIED;
510 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
511 struct ntvfs_request *req, union smb_close *io)
513 struct ipc_private *private = ntvfs->private_data;
514 struct pipe_state *p;
516 if (io->generic.level != RAW_CLOSE_CLOSE) {
517 return ntvfs_map_close(ntvfs, req, io);
520 p = pipe_state_find(private, io->close.in.file.ntvfs);
522 return NT_STATUS_INVALID_HANDLE;
533 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
534 struct ntvfs_request *req)
536 struct ipc_private *private = ntvfs->private_data;
537 struct pipe_state *p, *next;
539 for (p=private->pipe_list; p; p=next) {
541 if (p->handle->session_info == req->session_info &&
542 p->handle->smbpid == req->smbpid) {
551 logoff - closing files open by the user
553 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
554 struct ntvfs_request *req)
556 struct ipc_private *private = ntvfs->private_data;
557 struct pipe_state *p, *next;
559 for (p=private->pipe_list; p; p=next) {
561 if (p->handle->session_info == req->session_info) {
570 setup for an async call
572 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
573 struct ntvfs_request *req,
582 static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
583 struct ntvfs_request *req)
585 return NT_STATUS_UNSUCCESSFUL;
591 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
592 struct ntvfs_request *req, union smb_lock *lck)
594 return NT_STATUS_ACCESS_DENIED;
598 set info on a open file
600 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
601 struct ntvfs_request *req, union smb_setfileinfo *info)
603 return NT_STATUS_ACCESS_DENIED;
607 query info on a open file
609 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
610 struct ntvfs_request *req, union smb_fileinfo *info)
612 struct ipc_private *private = ntvfs->private_data;
613 struct pipe_state *p = pipe_state_find(private, info->generic.in.file.ntvfs);
615 return NT_STATUS_INVALID_HANDLE;
617 switch (info->generic.level) {
618 case RAW_FILEINFO_GENERIC:
620 ZERO_STRUCT(info->generic.out);
621 info->generic.out.attrib = FILE_ATTRIBUTE_NORMAL;
622 info->generic.out.fname.s = strrchr(p->pipe_name, '\\');
623 info->generic.out.alloc_size = 4096;
624 info->generic.out.nlink = 1;
625 /* What the heck? Match Win2k3: IPC$ pipes are delete pending */
626 info->generic.out.delete_pending = 1;
629 case RAW_FILEINFO_ALT_NAME_INFO:
630 case RAW_FILEINFO_ALT_NAME_INFORMATION:
631 case RAW_FILEINFO_STREAM_INFO:
632 case RAW_FILEINFO_STREAM_INFORMATION:
633 case RAW_FILEINFO_COMPRESSION_INFO:
634 case RAW_FILEINFO_COMPRESSION_INFORMATION:
635 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
636 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
637 return NT_STATUS_INVALID_PARAMETER;
638 case RAW_FILEINFO_ALL_EAS:
639 return NT_STATUS_ACCESS_DENIED;
641 return ntvfs_map_qfileinfo(ntvfs, req, info);
644 return NT_STATUS_ACCESS_DENIED;
649 return filesystem info
651 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
652 struct ntvfs_request *req, union smb_fsinfo *fs)
654 return NT_STATUS_ACCESS_DENIED;
658 return print queue info
660 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
661 struct ntvfs_request *req, union smb_lpq *lpq)
663 return NT_STATUS_ACCESS_DENIED;
667 list files in a directory matching a wildcard pattern
669 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
670 struct ntvfs_request *req, union smb_search_first *io,
671 void *search_private,
672 bool (*callback)(void *, const union smb_search_data *))
674 return NT_STATUS_ACCESS_DENIED;
678 continue listing files in a directory
680 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
681 struct ntvfs_request *req, union smb_search_next *io,
682 void *search_private,
683 bool (*callback)(void *, const union smb_search_data *))
685 return NT_STATUS_ACCESS_DENIED;
689 end listing files in a directory
691 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
692 struct ntvfs_request *req, union smb_search_close *io)
694 return NT_STATUS_ACCESS_DENIED;
697 static NTSTATUS ipc_trans_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
699 NTSTATUS status = NT_STATUS_OK;
700 DATA_BLOB *blob = private_data;
702 if (out->length > blob->length) {
703 status = STATUS_BUFFER_OVERFLOW;
706 if (out->length < blob->length) {
707 blob->length = out->length;
709 memcpy(blob->data, out->data, blob->length);
710 *nwritten = blob->length;
714 /* SMBtrans - handle a DCERPC command */
715 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
716 struct ntvfs_request *req, struct smb_trans2 *trans)
718 struct pipe_state *p;
719 struct ipc_private *private = ntvfs->private_data;
725 * the fnum is in setup[1], a 16 bit value
726 * the setup[*] values are already in host byteorder
727 * but ntvfs_handle_search_by_wire_key() expects
730 SSVAL(&fnum, 0, trans->in.setup[1]);
731 fnum_key = data_blob_const(&fnum, 2);
733 p = pipe_state_find_key(private, req, &fnum_key);
735 return NT_STATUS_INVALID_HANDLE;
738 trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
739 if (!trans->out.data.data) {
740 return NT_STATUS_NO_MEMORY;
743 /* pass the data to the dcerpc server. Note that we don't
744 expect this to fail, and things like NDR faults are not
745 reported at this stage. Those sorts of errors happen in the
746 dcesrv_output stage */
747 status = dcesrv_input(p->dce_conn, &trans->in.data);
748 if (!NT_STATUS_IS_OK(status)) {
753 now ask the dcerpc system for some output. This doesn't yet handle
754 async calls. Again, we only expect NT_STATUS_OK. If the call fails then
755 the error is encoded at the dcerpc level
757 status = dcesrv_output(p->dce_conn, &trans->out.data, ipc_trans_dcesrv_output);
758 if (NT_STATUS_IS_ERR(status)) {
762 trans->out.setup_count = 0;
763 trans->out.setup = NULL;
764 trans->out.params = data_blob(NULL, 0);
770 /* SMBtrans - set named pipe state */
771 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
772 struct ntvfs_request *req, struct smb_trans2 *trans)
774 struct ipc_private *private = ntvfs->private_data;
775 struct pipe_state *p;
778 /* the fnum is in setup[1] */
779 fnum_key = data_blob_const(&trans->in.setup[1], sizeof(trans->in.setup[1]));
781 p = pipe_state_find_key(private, req, &fnum_key);
783 return NT_STATUS_INVALID_HANDLE;
786 if (trans->in.params.length != 2) {
787 return NT_STATUS_INVALID_PARAMETER;
789 p->ipc_state = SVAL(trans->in.params.data, 0);
791 trans->out.setup_count = 0;
792 trans->out.setup = NULL;
793 trans->out.params = data_blob(NULL, 0);
794 trans->out.data = data_blob(NULL, 0);
800 /* SMBtrans - used to provide access to SMB pipes */
801 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
802 struct ntvfs_request *req, struct smb_trans2 *trans)
806 if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
807 return ipc_rap_call(req, trans);
809 if (trans->in.setup_count != 2) {
810 return NT_STATUS_INVALID_PARAMETER;
813 switch (trans->in.setup[0]) {
814 case TRANSACT_SETNAMEDPIPEHANDLESTATE:
815 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
817 case TRANSACT_DCERPCCMD:
818 status = ipc_dcerpc_cmd(ntvfs, req, trans);
821 status = NT_STATUS_INVALID_PARAMETER;
828 static NTSTATUS ipc_ioctl_smb2(struct ntvfs_module_context *ntvfs,
829 struct ntvfs_request *req, union smb_ioctl *io)
831 struct pipe_state *p;
832 struct ipc_private *private = ntvfs->private_data;
835 switch (io->smb2.in.function) {
836 case FSCTL_NAMED_PIPE_READ_WRITE:
840 return NT_STATUS_FS_DRIVER_REQUIRED;
843 p = pipe_state_find(private, io->smb2.in.file.ntvfs);
845 return NT_STATUS_INVALID_HANDLE;
848 io->smb2.out.out = data_blob_talloc(req, NULL, io->smb2.in.max_response_size);
849 NT_STATUS_HAVE_NO_MEMORY(io->smb2.out.out.data);
851 /* pass the data to the dcerpc server. Note that we don't
852 expect this to fail, and things like NDR faults are not
853 reported at this stage. Those sorts of errors happen in the
854 dcesrv_output stage */
855 status = dcesrv_input(p->dce_conn, &io->smb2.in.out);
856 NT_STATUS_NOT_OK_RETURN(status);
859 now ask the dcerpc system for some output. This doesn't yet handle
860 async calls. Again, we only expect NT_STATUS_OK. If the call fails then
861 the error is encoded at the dcerpc level
863 status = dcesrv_output(p->dce_conn, &io->smb2.out.out, ipc_trans_dcesrv_output);
864 NT_STATUS_IS_ERR_RETURN(status);
866 io->smb2.out._pad = 0;
867 io->smb2.out.function = io->smb2.in.function;
868 io->smb2.out.unknown2 = 0;
869 io->smb2.out.unknown3 = 0;
870 io->smb2.out.in = io->smb2.in.out;
878 static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
879 struct ntvfs_request *req, union smb_ioctl *io)
881 switch (io->generic.level) {
883 return ipc_ioctl_smb2(ntvfs, req, io);
885 case RAW_IOCTL_SMB2_NO_HANDLE:
886 return NT_STATUS_FS_DRIVER_REQUIRED;
889 return NT_STATUS_ACCESS_DENIED;
892 return NT_STATUS_ACCESS_DENIED;
897 initialialise the IPC backend, registering ourselves with the ntvfs subsystem
899 NTSTATUS ntvfs_ipc_init(void)
902 struct ntvfs_ops ops;
903 NTVFS_CURRENT_CRITICAL_SIZES(vers);
907 /* fill in the name and type */
908 ops.name = "default";
909 ops.type = NTVFS_IPC;
911 /* fill in all the operations */
912 ops.connect = ipc_connect;
913 ops.disconnect = ipc_disconnect;
914 ops.unlink = ipc_unlink;
915 ops.chkpath = ipc_chkpath;
916 ops.qpathinfo = ipc_qpathinfo;
917 ops.setpathinfo = ipc_setpathinfo;
919 ops.mkdir = ipc_mkdir;
920 ops.rmdir = ipc_rmdir;
921 ops.rename = ipc_rename;
923 ops.ioctl = ipc_ioctl;
925 ops.write = ipc_write;
927 ops.flush = ipc_flush;
928 ops.close = ipc_close;
931 ops.setfileinfo = ipc_setfileinfo;
932 ops.qfileinfo = ipc_qfileinfo;
933 ops.fsinfo = ipc_fsinfo;
935 ops.search_first = ipc_search_first;
936 ops.search_next = ipc_search_next;
937 ops.search_close = ipc_search_close;
938 ops.trans = ipc_trans;
939 ops.logoff = ipc_logoff;
940 ops.async_setup = ipc_async_setup;
941 ops.cancel = ipc_cancel;
943 /* register ourselves with the NTVFS subsystem. */
944 ret = ntvfs_register(&ops, &vers);
946 if (!NT_STATUS_IS_OK(ret)) {
947 DEBUG(0,("Failed to register IPC backend!\n"));