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 "smb_server/smb_server.h"
31 #include "ntvfs/ntvfs.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 idr_context *idtree_fnum;
43 struct dcesrv_context *dcesrv;
45 /* a list of open pipes */
47 struct pipe_state *next, *prev;
48 struct ipc_private *private;
49 const char *pipe_name;
51 struct dcesrv_connection *dce_conn;
53 /* we need to remember the session it was opened on,
54 as it is illegal to operate on someone elses fnum */
55 struct smbsrv_session *session;
57 /* we need to remember the client pid that
58 opened the file so SMBexit works */
66 find a open pipe give a file descriptor
68 static struct pipe_state *pipe_state_find(struct ipc_private *private, uint16_t fnum)
70 return idr_find(private->idtree_fnum, fnum);
75 connect to a share - always works
77 static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
78 struct smbsrv_request *req, const char *sharename)
81 struct smbsrv_tcon *tcon = req->tcon;
82 struct ipc_private *private;
84 tcon->fs_type = talloc_strdup(tcon, "IPC");
85 NT_STATUS_HAVE_NO_MEMORY(tcon->fs_type);
87 tcon->dev_type = talloc_strdup(tcon, "IPC");
88 NT_STATUS_HAVE_NO_MEMORY(tcon->dev_type);
90 /* prepare the private state for this connection */
91 private = talloc(ntvfs, struct ipc_private);
92 NT_STATUS_HAVE_NO_MEMORY(private);
94 ntvfs->private_data = private;
96 private->pipe_list = NULL;
98 private->idtree_fnum = idr_init(private);
99 NT_STATUS_HAVE_NO_MEMORY(private->idtree_fnum);
101 /* setup the DCERPC server subsystem */
102 status = dcesrv_init_ipc_context(private, &private->dcesrv);
103 NT_STATUS_NOT_OK_RETURN(status);
109 disconnect from a share
111 static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs,
112 struct smbsrv_tcon *tcon)
120 static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
121 struct smbsrv_request *req, struct smb_unlink *unl)
123 return NT_STATUS_ACCESS_DENIED;
128 ioctl interface - we don't do any
130 static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
131 struct smbsrv_request *req, union smb_ioctl *io)
133 return NT_STATUS_ACCESS_DENIED;
137 check if a directory exists
139 static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
140 struct smbsrv_request *req, struct 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 smbsrv_request *req, union smb_fileinfo *info)
151 return NT_STATUS_ACCESS_DENIED;
155 set info on a pathname
157 static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
158 struct smbsrv_request *req, union smb_setfileinfo *st)
160 return NT_STATUS_ACCESS_DENIED;
165 destroy a open pipe structure
167 static int ipc_fd_destructor(void *ptr)
169 struct pipe_state *p = ptr;
170 idr_remove(p->private->idtree_fnum, p->fnum);
171 DLIST_REMOVE(p->private->pipe_list, p);
177 open a file backend - used for MSRPC pipes
179 static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
180 struct smbsrv_request *req, const char *fname,
181 struct pipe_state **ps)
183 struct pipe_state *p;
185 struct dcerpc_binding *ep_description;
186 struct ipc_private *private = ntvfs->private_data;
188 struct stream_connection *srv_conn = req->smb_conn->connection;
190 if (!req->session || !req->session->session_info) {
191 return NT_STATUS_ACCESS_DENIED;
194 p = talloc(req, struct pipe_state);
195 NT_STATUS_HAVE_NO_MEMORY(p);
197 ep_description = talloc(req, struct dcerpc_binding);
198 NT_STATUS_HAVE_NO_MEMORY(ep_description);
200 while (fname[0] == '\\') fname++;
202 p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
203 NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
205 fnum = idr_get_new_above(private->idtree_fnum, p, IPC_BASE_FNUM, UINT16_MAX);
207 return NT_STATUS_TOO_MANY_OPENED_FILES;
211 p->ipc_state = 0x5ff;
214 we're all set, now ask the dcerpc server subsystem to open the
215 endpoint. At this stage the pipe isn't bound, so we don't
216 know what interface the user actually wants, just that they want
217 one of the interfaces attached to this pipe endpoint.
219 ep_description->transport = NCACN_NP;
220 ep_description->endpoint = talloc_reference(ep_description, p->pipe_name);
222 /* The session info is refcount-increased in the
223 * dcesrv_endpoint_search_connect() function
225 status = dcesrv_endpoint_search_connect(private->dcesrv,
228 req->session->session_info,
231 if (!NT_STATUS_IS_OK(status)) {
232 idr_remove(private->idtree_fnum, p->fnum);
236 DLIST_ADD(private->pipe_list, p);
238 p->smbpid = req->smbpid;
239 p->session = req->session;
240 p->private = private;
244 talloc_steal(private, p);
246 talloc_set_destructor(p, ipc_fd_destructor);
252 open a file with ntcreatex - used for MSRPC pipes
254 static NTSTATUS ipc_open_ntcreatex(struct ntvfs_module_context *ntvfs,
255 struct smbsrv_request *req, union smb_open *oi)
257 struct pipe_state *p;
260 status = ipc_open_generic(ntvfs, req, oi->ntcreatex.in.fname, &p);
261 if (!NT_STATUS_IS_OK(status)) {
265 ZERO_STRUCT(oi->ntcreatex.out);
266 oi->ntcreatex.out.fnum = p->fnum;
267 oi->ntcreatex.out.ipc_state = p->ipc_state;
268 oi->ntcreatex.out.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
274 open a file with openx - used for MSRPC pipes
276 static NTSTATUS ipc_open_openx(struct ntvfs_module_context *ntvfs,
277 struct smbsrv_request *req, union smb_open *oi)
279 struct pipe_state *p;
281 const char *fname = oi->openx.in.fname;
283 status = ipc_open_generic(ntvfs, req, fname, &p);
284 if (!NT_STATUS_IS_OK(status)) {
288 ZERO_STRUCT(oi->openx.out);
289 oi->openx.out.fnum = p->fnum;
290 oi->openx.out.ftype = 2;
291 oi->openx.out.devstate = p->ipc_state;
297 open a file - used for MSRPC pipes
299 static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
300 struct smbsrv_request *req, union smb_open *oi)
304 switch (oi->generic.level) {
305 case RAW_OPEN_NTCREATEX:
306 status = ipc_open_ntcreatex(ntvfs, req, oi);
309 status = ipc_open_openx(ntvfs, req, oi);
312 status = NT_STATUS_NOT_SUPPORTED;
322 static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
323 struct smbsrv_request *req, union smb_mkdir *md)
325 return NT_STATUS_ACCESS_DENIED;
331 static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
332 struct smbsrv_request *req, struct smb_rmdir *rd)
334 return NT_STATUS_ACCESS_DENIED;
338 rename a set of files
340 static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
341 struct smbsrv_request *req, union smb_rename *ren)
343 return NT_STATUS_ACCESS_DENIED;
349 static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
350 struct smbsrv_request *req, struct smb_copy *cp)
352 return NT_STATUS_ACCESS_DENIED;
355 static NTSTATUS ipc_readx_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
357 DATA_BLOB *blob = private_data;
359 if (out->length < blob->length) {
360 blob->length = out->length;
362 memcpy(blob->data, out->data, blob->length);
363 *nwritten = blob->length;
370 static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
371 struct smbsrv_request *req, union smb_read *rd)
373 struct ipc_private *private = ntvfs->private_data;
376 struct pipe_state *p;
377 NTSTATUS status = NT_STATUS_OK;
379 if (rd->generic.level != RAW_READ_GENERIC) {
380 return ntvfs_map_read(req, rd, ntvfs);
383 fnum = rd->readx.in.fnum;
385 p = pipe_state_find(private, fnum);
387 return NT_STATUS_INVALID_HANDLE;
390 data.length = rd->readx.in.maxcnt;
391 data.data = rd->readx.out.data;
392 if (data.length > UINT16_MAX) {
393 data.length = UINT16_MAX;
396 if (data.length != 0) {
397 status = dcesrv_output(p->dce_conn, &data, ipc_readx_dcesrv_output);
398 if (NT_STATUS_IS_ERR(status)) {
403 rd->readx.out.remaining = 0;
404 rd->readx.out.compaction_mode = 0;
405 rd->readx.out.nread = data.length;
413 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
414 struct smbsrv_request *req, union smb_write *wr)
416 struct ipc_private *private = ntvfs->private_data;
419 struct pipe_state *p;
422 if (wr->generic.level != RAW_WRITE_GENERIC) {
423 return ntvfs_map_write(req, wr, ntvfs);
426 fnum = wr->writex.in.fnum;
427 data.data = discard_const_p(void, wr->writex.in.data);
428 data.length = wr->writex.in.count;
430 p = pipe_state_find(private, fnum);
432 return NT_STATUS_INVALID_HANDLE;
435 status = dcesrv_input(p->dce_conn, &data);
436 if (!NT_STATUS_IS_OK(status)) {
440 wr->writex.out.nwritten = data.length;
441 wr->writex.out.remaining = 0;
449 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
450 struct smbsrv_request *req, struct smb_seek *io)
452 return NT_STATUS_ACCESS_DENIED;
458 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
459 struct smbsrv_request *req, struct smb_flush *io)
461 return NT_STATUS_ACCESS_DENIED;
467 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
468 struct smbsrv_request *req, union smb_close *io)
470 struct ipc_private *private = ntvfs->private_data;
471 struct pipe_state *p;
473 if (io->generic.level != RAW_CLOSE_CLOSE) {
474 return ntvfs_map_close(req, io, ntvfs);
477 p = pipe_state_find(private, io->close.in.fnum);
479 return NT_STATUS_INVALID_HANDLE;
490 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
491 struct smbsrv_request *req)
493 struct ipc_private *private = ntvfs->private_data;
494 struct pipe_state *p, *next;
496 for (p=private->pipe_list; p; p=next) {
498 if (p->smbpid == req->smbpid) {
507 logoff - closing files open by the user
509 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
510 struct smbsrv_request *req)
512 struct ipc_private *private = ntvfs->private_data;
513 struct pipe_state *p, *next;
515 for (p=private->pipe_list; p; p=next) {
517 if (p->session == req->session) {
526 setup for an async call
528 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
529 struct smbsrv_request *req,
538 static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
539 struct smbsrv_request *req)
541 return NT_STATUS_UNSUCCESSFUL;
547 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
548 struct smbsrv_request *req, union smb_lock *lck)
550 return NT_STATUS_ACCESS_DENIED;
554 set info on a open file
556 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
557 struct smbsrv_request *req, union smb_setfileinfo *info)
559 return NT_STATUS_ACCESS_DENIED;
563 query info on a open file
565 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
566 struct smbsrv_request *req, union smb_fileinfo *info)
568 return NT_STATUS_ACCESS_DENIED;
573 return filesystem info
575 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
576 struct smbsrv_request *req, union smb_fsinfo *fs)
578 return NT_STATUS_ACCESS_DENIED;
582 return print queue info
584 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
585 struct smbsrv_request *req, union smb_lpq *lpq)
587 return NT_STATUS_ACCESS_DENIED;
591 list files in a directory matching a wildcard pattern
593 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
594 struct smbsrv_request *req, union smb_search_first *io,
595 void *search_private,
596 BOOL (*callback)(void *, union smb_search_data *))
598 return NT_STATUS_ACCESS_DENIED;
602 continue listing files in a directory
604 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
605 struct smbsrv_request *req, union smb_search_next *io,
606 void *search_private,
607 BOOL (*callback)(void *, union smb_search_data *))
609 return NT_STATUS_ACCESS_DENIED;
613 end listing files in a directory
615 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
616 struct smbsrv_request *req, union smb_search_close *io)
618 return NT_STATUS_ACCESS_DENIED;
621 static NTSTATUS ipc_trans_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
623 NTSTATUS status = NT_STATUS_OK;
624 DATA_BLOB *blob = private_data;
626 if (out->length > blob->length) {
627 status = STATUS_BUFFER_OVERFLOW;
630 if (out->length < blob->length) {
631 blob->length = out->length;
633 memcpy(blob->data, out->data, blob->length);
634 *nwritten = blob->length;
638 /* SMBtrans - handle a DCERPC command */
639 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
640 struct smbsrv_request *req, struct smb_trans2 *trans)
642 struct pipe_state *p;
643 struct ipc_private *private = ntvfs->private_data;
646 /* the fnum is in setup[1] */
647 p = pipe_state_find(private, trans->in.setup[1]);
649 return NT_STATUS_INVALID_HANDLE;
652 trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
653 if (!trans->out.data.data) {
654 return NT_STATUS_NO_MEMORY;
657 /* pass the data to the dcerpc server. Note that we don't
658 expect this to fail, and things like NDR faults are not
659 reported at this stage. Those sorts of errors happen in the
660 dcesrv_output stage */
661 status = dcesrv_input(p->dce_conn, &trans->in.data);
662 if (!NT_STATUS_IS_OK(status)) {
667 now ask the dcerpc system for some output. This doesn't yet handle
668 async calls. Again, we only expect NT_STATUS_OK. If the call fails then
669 the error is encoded at the dcerpc level
671 status = dcesrv_output(p->dce_conn, &trans->out.data, ipc_trans_dcesrv_output);
672 if (NT_STATUS_IS_ERR(status)) {
676 trans->out.setup_count = 0;
677 trans->out.setup = NULL;
678 trans->out.params = data_blob(NULL, 0);
684 /* SMBtrans - set named pipe state */
685 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
686 struct smbsrv_request *req, struct smb_trans2 *trans)
688 struct ipc_private *private = ntvfs->private_data;
689 struct pipe_state *p;
691 /* the fnum is in setup[1] */
692 p = pipe_state_find(private, trans->in.setup[1]);
694 return NT_STATUS_INVALID_HANDLE;
697 if (trans->in.params.length != 2) {
698 return NT_STATUS_INVALID_PARAMETER;
700 p->ipc_state = SVAL(trans->in.params.data, 0);
702 trans->out.setup_count = 0;
703 trans->out.setup = NULL;
704 trans->out.params = data_blob(NULL, 0);
705 trans->out.data = data_blob(NULL, 0);
711 /* SMBtrans - used to provide access to SMB pipes */
712 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
713 struct smbsrv_request *req, struct smb_trans2 *trans)
717 if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
718 return ipc_rap_call(req, trans);
720 if (trans->in.setup_count != 2) {
721 return NT_STATUS_INVALID_PARAMETER;
724 switch (trans->in.setup[0]) {
725 case TRANSACT_SETNAMEDPIPEHANDLESTATE:
726 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
728 case TRANSACT_DCERPCCMD:
729 status = ipc_dcerpc_cmd(ntvfs, req, trans);
732 status = NT_STATUS_INVALID_PARAMETER;
742 initialialise the IPC backend, registering ourselves with the ntvfs subsystem
744 NTSTATUS ntvfs_ipc_init(void)
747 struct ntvfs_ops ops;
751 /* fill in the name and type */
752 ops.name = "default";
753 ops.type = NTVFS_IPC;
755 /* fill in all the operations */
756 ops.connect = ipc_connect;
757 ops.disconnect = ipc_disconnect;
758 ops.unlink = ipc_unlink;
759 ops.chkpath = ipc_chkpath;
760 ops.qpathinfo = ipc_qpathinfo;
761 ops.setpathinfo = ipc_setpathinfo;
762 ops.openfile = ipc_open;
763 ops.mkdir = ipc_mkdir;
764 ops.rmdir = ipc_rmdir;
765 ops.rename = ipc_rename;
767 ops.ioctl = ipc_ioctl;
769 ops.write = ipc_write;
771 ops.flush = ipc_flush;
772 ops.close = ipc_close;
775 ops.setfileinfo = ipc_setfileinfo;
776 ops.qfileinfo = ipc_qfileinfo;
777 ops.fsinfo = ipc_fsinfo;
779 ops.search_first = ipc_search_first;
780 ops.search_next = ipc_search_next;
781 ops.search_close = ipc_search_close;
782 ops.trans = ipc_trans;
783 ops.logoff = ipc_logoff;
784 ops.async_setup = ipc_async_setup;
785 ops.cancel = ipc_cancel;
787 /* register ourselves with the NTVFS subsystem. */
788 ret = ntvfs_register(&ops);
790 if (!NT_STATUS_IS_OK(ret)) {
791 DEBUG(0,("Failed to register IPC backend!\n"));