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 "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"
35 #define IPC_BASE_FNUM 0x400
37 /* this is the private structure used to keep the state of an open
38 ipc$ connection. It needs to keep information about all open
41 struct ntvfs_module_context *ntvfs;
43 struct idr_context *idtree_fnum;
45 struct dcesrv_context *dcesrv;
47 /* a list of open pipes */
49 struct pipe_state *next, *prev;
50 struct ipc_private *private;
51 const char *pipe_name;
53 struct dcesrv_connection *dce_conn;
55 /* we need to remember the session it was opened on,
56 as it is illegal to operate on someone elses fnum */
57 struct auth_session_info *session_info;
59 /* we need to remember the client pid that
60 opened the file so SMBexit works */
67 find a open pipe give a file descriptor
69 static struct pipe_state *pipe_state_find(struct ipc_private *private, uint16_t fnum,
70 struct auth_session_info *session_info)
75 p = idr_find(private->idtree_fnum, fnum);
78 s = talloc_get_type(p, struct pipe_state);
80 if (s->session_info != session_info) {
89 connect to a share - always works
91 static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
92 struct ntvfs_request *req, const char *sharename)
95 struct ipc_private *private;
97 ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "IPC");
98 NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
100 ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "IPC");
101 NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
103 /* prepare the private state for this connection */
104 private = talloc(ntvfs, struct ipc_private);
105 NT_STATUS_HAVE_NO_MEMORY(private);
107 ntvfs->private_data = private;
109 private->ntvfs = ntvfs;
110 private->pipe_list = NULL;
112 private->idtree_fnum = idr_init(private);
113 NT_STATUS_HAVE_NO_MEMORY(private->idtree_fnum);
115 /* setup the DCERPC server subsystem */
116 status = dcesrv_init_ipc_context(private, &private->dcesrv);
117 NT_STATUS_NOT_OK_RETURN(status);
123 disconnect from a share
125 static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs)
133 static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
134 struct ntvfs_request *req,
135 union smb_unlink *unl)
137 return NT_STATUS_ACCESS_DENIED;
142 ioctl interface - we don't do any
144 static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
145 struct ntvfs_request *req, union smb_ioctl *io)
147 return NT_STATUS_ACCESS_DENIED;
151 check if a directory exists
153 static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
154 struct ntvfs_request *req,
155 union smb_chkpath *cp)
157 return NT_STATUS_ACCESS_DENIED;
161 return info on a pathname
163 static NTSTATUS ipc_qpathinfo(struct ntvfs_module_context *ntvfs,
164 struct ntvfs_request *req, union smb_fileinfo *info)
166 return NT_STATUS_ACCESS_DENIED;
170 set info on a pathname
172 static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
173 struct ntvfs_request *req, union smb_setfileinfo *st)
175 return NT_STATUS_ACCESS_DENIED;
180 destroy a open pipe structure
182 static int ipc_fd_destructor(void *ptr)
184 struct pipe_state *p = ptr;
185 idr_remove(p->private->idtree_fnum, p->fnum);
186 DLIST_REMOVE(p->private->pipe_list, p);
190 static struct socket_address *ipc_get_my_addr(struct dcesrv_connection *dce_conn, TALLOC_CTX *mem_ctx)
192 struct ipc_private *private = dce_conn->transport.private_data;
194 return ntvfs_get_my_addr(private->ntvfs, mem_ctx);
197 static struct socket_address *ipc_get_peer_addr(struct dcesrv_connection *dce_conn, TALLOC_CTX *mem_ctx)
199 struct ipc_private *private = dce_conn->transport.private_data;
201 return ntvfs_get_peer_addr(private->ntvfs, mem_ctx);
205 open a file backend - used for MSRPC pipes
207 static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
208 struct ntvfs_request *req, const char *fname,
209 struct pipe_state **ps)
211 struct pipe_state *p;
213 struct dcerpc_binding *ep_description;
214 struct ipc_private *private = ntvfs->private_data;
217 p = talloc(req, struct pipe_state);
218 NT_STATUS_HAVE_NO_MEMORY(p);
220 ep_description = talloc(req, struct dcerpc_binding);
221 NT_STATUS_HAVE_NO_MEMORY(ep_description);
223 while (fname[0] == '\\') fname++;
225 p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
226 NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
228 fnum = idr_get_new_above(private->idtree_fnum, p, IPC_BASE_FNUM, UINT16_MAX);
230 return NT_STATUS_TOO_MANY_OPENED_FILES;
234 p->ipc_state = 0x5ff;
237 we're all set, now ask the dcerpc server subsystem to open the
238 endpoint. At this stage the pipe isn't bound, so we don't
239 know what interface the user actually wants, just that they want
240 one of the interfaces attached to this pipe endpoint.
242 ep_description->transport = NCACN_NP;
243 ep_description->endpoint = talloc_reference(ep_description, p->pipe_name);
245 /* The session info is refcount-increased in the
246 * dcesrv_endpoint_search_connect() function
248 status = dcesrv_endpoint_search_connect(private->dcesrv,
252 ntvfs->ctx->event_ctx,
255 if (!NT_STATUS_IS_OK(status)) {
256 idr_remove(private->idtree_fnum, p->fnum);
260 p->dce_conn->transport.private_data = private;
261 p->dce_conn->transport.report_output_data = NULL;
262 p->dce_conn->transport.get_my_addr = ipc_get_my_addr;
263 p->dce_conn->transport.get_peer_addr = ipc_get_peer_addr;
265 DLIST_ADD(private->pipe_list, p);
267 p->smbpid = req->smbpid;
268 p->session_info = req->session_info;
269 p->private = private;
273 talloc_steal(private, p);
275 talloc_set_destructor(p, ipc_fd_destructor);
281 open a file with ntcreatex - used for MSRPC pipes
283 static NTSTATUS ipc_open_ntcreatex(struct ntvfs_module_context *ntvfs,
284 struct ntvfs_request *req, union smb_open *oi)
286 struct pipe_state *p;
289 status = ipc_open_generic(ntvfs, req, oi->ntcreatex.in.fname, &p);
290 if (!NT_STATUS_IS_OK(status)) {
294 ZERO_STRUCT(oi->ntcreatex.out);
295 oi->ntcreatex.out.file.fnum = p->fnum;
296 oi->ntcreatex.out.ipc_state = p->ipc_state;
297 oi->ntcreatex.out.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
303 open a file with openx - used for MSRPC pipes
305 static NTSTATUS ipc_open_openx(struct ntvfs_module_context *ntvfs,
306 struct ntvfs_request *req, union smb_open *oi)
308 struct pipe_state *p;
310 const char *fname = oi->openx.in.fname;
312 status = ipc_open_generic(ntvfs, req, fname, &p);
313 if (!NT_STATUS_IS_OK(status)) {
317 ZERO_STRUCT(oi->openx.out);
318 oi->openx.out.file.fnum = p->fnum;
319 oi->openx.out.ftype = 2;
320 oi->openx.out.devstate = p->ipc_state;
326 open a file - used for MSRPC pipes
328 static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
329 struct ntvfs_request *req, union smb_open *oi)
333 switch (oi->generic.level) {
334 case RAW_OPEN_NTCREATEX:
335 status = ipc_open_ntcreatex(ntvfs, req, oi);
338 status = ipc_open_openx(ntvfs, req, oi);
341 status = NT_STATUS_NOT_SUPPORTED;
351 static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
352 struct ntvfs_request *req, union smb_mkdir *md)
354 return NT_STATUS_ACCESS_DENIED;
360 static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
361 struct ntvfs_request *req, struct smb_rmdir *rd)
363 return NT_STATUS_ACCESS_DENIED;
367 rename a set of files
369 static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
370 struct ntvfs_request *req, union smb_rename *ren)
372 return NT_STATUS_ACCESS_DENIED;
378 static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
379 struct ntvfs_request *req, struct smb_copy *cp)
381 return NT_STATUS_ACCESS_DENIED;
384 static NTSTATUS ipc_readx_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
386 DATA_BLOB *blob = private_data;
388 if (out->length < blob->length) {
389 blob->length = out->length;
391 memcpy(blob->data, out->data, blob->length);
392 *nwritten = blob->length;
399 static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
400 struct ntvfs_request *req, union smb_read *rd)
402 struct ipc_private *private = ntvfs->private_data;
405 struct pipe_state *p;
406 NTSTATUS status = NT_STATUS_OK;
408 if (rd->generic.level != RAW_READ_GENERIC) {
409 return ntvfs_map_read(ntvfs, req, rd);
412 fnum = rd->readx.in.file.fnum;
414 p = pipe_state_find(private, fnum, req->session_info);
416 return NT_STATUS_INVALID_HANDLE;
419 data.length = rd->readx.in.maxcnt;
420 data.data = rd->readx.out.data;
421 if (data.length > UINT16_MAX) {
422 data.length = UINT16_MAX;
425 if (data.length != 0) {
426 status = dcesrv_output(p->dce_conn, &data, ipc_readx_dcesrv_output);
427 if (NT_STATUS_IS_ERR(status)) {
432 rd->readx.out.remaining = 0;
433 rd->readx.out.compaction_mode = 0;
434 rd->readx.out.nread = data.length;
442 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
443 struct ntvfs_request *req, union smb_write *wr)
445 struct ipc_private *private = ntvfs->private_data;
448 struct pipe_state *p;
451 if (wr->generic.level != RAW_WRITE_GENERIC) {
452 return ntvfs_map_write(ntvfs, req, wr);
455 fnum = wr->writex.in.file.fnum;
456 data.data = discard_const_p(void, wr->writex.in.data);
457 data.length = wr->writex.in.count;
459 p = pipe_state_find(private, fnum, req->session_info);
461 return NT_STATUS_INVALID_HANDLE;
464 status = dcesrv_input(p->dce_conn, &data);
465 if (!NT_STATUS_IS_OK(status)) {
469 wr->writex.out.nwritten = data.length;
470 wr->writex.out.remaining = 0;
478 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
479 struct ntvfs_request *req,
482 return NT_STATUS_ACCESS_DENIED;
488 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
489 struct ntvfs_request *req,
492 return NT_STATUS_ACCESS_DENIED;
498 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
499 struct ntvfs_request *req, union smb_close *io)
501 struct ipc_private *private = ntvfs->private_data;
502 struct pipe_state *p;
504 if (io->generic.level != RAW_CLOSE_CLOSE) {
505 return ntvfs_map_close(ntvfs, req, io);
508 p = pipe_state_find(private, io->close.in.file.fnum, req->session_info);
510 return NT_STATUS_INVALID_HANDLE;
521 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
522 struct ntvfs_request *req)
524 struct ipc_private *private = ntvfs->private_data;
525 struct pipe_state *p, *next;
527 for (p=private->pipe_list; p; p=next) {
529 if (p->session_info == req->session_info &&
530 p->smbpid == req->smbpid) {
539 logoff - closing files open by the user
541 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
542 struct ntvfs_request *req)
544 struct ipc_private *private = ntvfs->private_data;
545 struct pipe_state *p, *next;
547 for (p=private->pipe_list; p; p=next) {
549 if (p->session_info == req->session_info) {
558 setup for an async call
560 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
561 struct ntvfs_request *req,
570 static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
571 struct ntvfs_request *req)
573 return NT_STATUS_UNSUCCESSFUL;
579 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
580 struct ntvfs_request *req, union smb_lock *lck)
582 return NT_STATUS_ACCESS_DENIED;
586 set info on a open file
588 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
589 struct ntvfs_request *req, union smb_setfileinfo *info)
591 return NT_STATUS_ACCESS_DENIED;
595 query info on a open file
597 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
598 struct ntvfs_request *req, union smb_fileinfo *info)
600 return NT_STATUS_ACCESS_DENIED;
605 return filesystem info
607 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
608 struct ntvfs_request *req, union smb_fsinfo *fs)
610 return NT_STATUS_ACCESS_DENIED;
614 return print queue info
616 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
617 struct ntvfs_request *req, union smb_lpq *lpq)
619 return NT_STATUS_ACCESS_DENIED;
623 list files in a directory matching a wildcard pattern
625 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
626 struct ntvfs_request *req, union smb_search_first *io,
627 void *search_private,
628 BOOL (*callback)(void *, union smb_search_data *))
630 return NT_STATUS_ACCESS_DENIED;
634 continue listing files in a directory
636 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
637 struct ntvfs_request *req, union smb_search_next *io,
638 void *search_private,
639 BOOL (*callback)(void *, union smb_search_data *))
641 return NT_STATUS_ACCESS_DENIED;
645 end listing files in a directory
647 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
648 struct ntvfs_request *req, union smb_search_close *io)
650 return NT_STATUS_ACCESS_DENIED;
653 static NTSTATUS ipc_trans_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
655 NTSTATUS status = NT_STATUS_OK;
656 DATA_BLOB *blob = private_data;
658 if (out->length > blob->length) {
659 status = STATUS_BUFFER_OVERFLOW;
662 if (out->length < blob->length) {
663 blob->length = out->length;
665 memcpy(blob->data, out->data, blob->length);
666 *nwritten = blob->length;
670 /* SMBtrans - handle a DCERPC command */
671 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
672 struct ntvfs_request *req, struct smb_trans2 *trans)
674 struct pipe_state *p;
675 struct ipc_private *private = ntvfs->private_data;
678 /* the fnum is in setup[1] */
679 p = pipe_state_find(private, trans->in.setup[1], req->session_info);
681 return NT_STATUS_INVALID_HANDLE;
684 trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
685 if (!trans->out.data.data) {
686 return NT_STATUS_NO_MEMORY;
689 /* pass the data to the dcerpc server. Note that we don't
690 expect this to fail, and things like NDR faults are not
691 reported at this stage. Those sorts of errors happen in the
692 dcesrv_output stage */
693 status = dcesrv_input(p->dce_conn, &trans->in.data);
694 if (!NT_STATUS_IS_OK(status)) {
699 now ask the dcerpc system for some output. This doesn't yet handle
700 async calls. Again, we only expect NT_STATUS_OK. If the call fails then
701 the error is encoded at the dcerpc level
703 status = dcesrv_output(p->dce_conn, &trans->out.data, ipc_trans_dcesrv_output);
704 if (NT_STATUS_IS_ERR(status)) {
708 trans->out.setup_count = 0;
709 trans->out.setup = NULL;
710 trans->out.params = data_blob(NULL, 0);
716 /* SMBtrans - set named pipe state */
717 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
718 struct ntvfs_request *req, struct smb_trans2 *trans)
720 struct ipc_private *private = ntvfs->private_data;
721 struct pipe_state *p;
723 /* the fnum is in setup[1] */
724 p = pipe_state_find(private, trans->in.setup[1], req->session_info);
726 return NT_STATUS_INVALID_HANDLE;
729 if (trans->in.params.length != 2) {
730 return NT_STATUS_INVALID_PARAMETER;
732 p->ipc_state = SVAL(trans->in.params.data, 0);
734 trans->out.setup_count = 0;
735 trans->out.setup = NULL;
736 trans->out.params = data_blob(NULL, 0);
737 trans->out.data = data_blob(NULL, 0);
743 /* SMBtrans - used to provide access to SMB pipes */
744 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
745 struct ntvfs_request *req, struct smb_trans2 *trans)
749 if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
750 return ipc_rap_call(req, trans);
752 if (trans->in.setup_count != 2) {
753 return NT_STATUS_INVALID_PARAMETER;
756 switch (trans->in.setup[0]) {
757 case TRANSACT_SETNAMEDPIPEHANDLESTATE:
758 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
760 case TRANSACT_DCERPCCMD:
761 status = ipc_dcerpc_cmd(ntvfs, req, trans);
764 status = NT_STATUS_INVALID_PARAMETER;
774 initialialise the IPC backend, registering ourselves with the ntvfs subsystem
776 NTSTATUS ntvfs_ipc_init(void)
779 struct ntvfs_ops ops;
783 /* fill in the name and type */
784 ops.name = "default";
785 ops.type = NTVFS_IPC;
787 /* fill in all the operations */
788 ops.connect = ipc_connect;
789 ops.disconnect = ipc_disconnect;
790 ops.unlink = ipc_unlink;
791 ops.chkpath = ipc_chkpath;
792 ops.qpathinfo = ipc_qpathinfo;
793 ops.setpathinfo = ipc_setpathinfo;
795 ops.mkdir = ipc_mkdir;
796 ops.rmdir = ipc_rmdir;
797 ops.rename = ipc_rename;
799 ops.ioctl = ipc_ioctl;
801 ops.write = ipc_write;
803 ops.flush = ipc_flush;
804 ops.close = ipc_close;
807 ops.setfileinfo = ipc_setfileinfo;
808 ops.qfileinfo = ipc_qfileinfo;
809 ops.fsinfo = ipc_fsinfo;
811 ops.search_first = ipc_search_first;
812 ops.search_next = ipc_search_next;
813 ops.search_close = ipc_search_close;
814 ops.trans = ipc_trans;
815 ops.logoff = ipc_logoff;
816 ops.async_setup = ipc_async_setup;
817 ops.cancel = ipc_cancel;
819 /* register ourselves with the NTVFS subsystem. */
820 ret = ntvfs_register(&ops);
822 if (!NT_STATUS_IS_OK(ret)) {
823 DEBUG(0,("Failed to register IPC backend!\n"));