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,
232 if (!NT_STATUS_IS_OK(status)) {
233 idr_remove(private->idtree_fnum, p->fnum);
237 DLIST_ADD(private->pipe_list, p);
239 p->smbpid = req->smbpid;
240 p->session = req->session;
241 p->private = private;
245 talloc_steal(private, p);
247 talloc_set_destructor(p, ipc_fd_destructor);
253 open a file with ntcreatex - used for MSRPC pipes
255 static NTSTATUS ipc_open_ntcreatex(struct ntvfs_module_context *ntvfs,
256 struct smbsrv_request *req, union smb_open *oi)
258 struct pipe_state *p;
261 status = ipc_open_generic(ntvfs, req, oi->ntcreatex.in.fname, &p);
262 if (!NT_STATUS_IS_OK(status)) {
266 ZERO_STRUCT(oi->ntcreatex.out);
267 oi->ntcreatex.out.fnum = p->fnum;
268 oi->ntcreatex.out.ipc_state = p->ipc_state;
269 oi->ntcreatex.out.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
275 open a file with openx - used for MSRPC pipes
277 static NTSTATUS ipc_open_openx(struct ntvfs_module_context *ntvfs,
278 struct smbsrv_request *req, union smb_open *oi)
280 struct pipe_state *p;
282 const char *fname = oi->openx.in.fname;
284 status = ipc_open_generic(ntvfs, req, fname, &p);
285 if (!NT_STATUS_IS_OK(status)) {
289 ZERO_STRUCT(oi->openx.out);
290 oi->openx.out.fnum = p->fnum;
291 oi->openx.out.ftype = 2;
292 oi->openx.out.devstate = p->ipc_state;
298 open a file - used for MSRPC pipes
300 static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
301 struct smbsrv_request *req, union smb_open *oi)
305 switch (oi->generic.level) {
306 case RAW_OPEN_NTCREATEX:
307 status = ipc_open_ntcreatex(ntvfs, req, oi);
310 status = ipc_open_openx(ntvfs, req, oi);
313 status = NT_STATUS_NOT_SUPPORTED;
323 static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
324 struct smbsrv_request *req, union smb_mkdir *md)
326 return NT_STATUS_ACCESS_DENIED;
332 static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
333 struct smbsrv_request *req, struct smb_rmdir *rd)
335 return NT_STATUS_ACCESS_DENIED;
339 rename a set of files
341 static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
342 struct smbsrv_request *req, union smb_rename *ren)
344 return NT_STATUS_ACCESS_DENIED;
350 static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
351 struct smbsrv_request *req, struct smb_copy *cp)
353 return NT_STATUS_ACCESS_DENIED;
356 static NTSTATUS ipc_readx_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
358 DATA_BLOB *blob = private_data;
360 if (out->length < blob->length) {
361 blob->length = out->length;
363 memcpy(blob->data, out->data, blob->length);
364 *nwritten = blob->length;
371 static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
372 struct smbsrv_request *req, union smb_read *rd)
374 struct ipc_private *private = ntvfs->private_data;
377 struct pipe_state *p;
378 NTSTATUS status = NT_STATUS_OK;
380 if (rd->generic.level != RAW_READ_GENERIC) {
381 return ntvfs_map_read(req, rd, ntvfs);
384 fnum = rd->readx.in.fnum;
386 p = pipe_state_find(private, fnum);
388 return NT_STATUS_INVALID_HANDLE;
391 data.length = rd->readx.in.maxcnt;
392 data.data = rd->readx.out.data;
393 if (data.length > UINT16_MAX) {
394 data.length = UINT16_MAX;
397 if (data.length != 0) {
398 status = dcesrv_output(p->dce_conn, &data, ipc_readx_dcesrv_output);
399 if (NT_STATUS_IS_ERR(status)) {
404 rd->readx.out.remaining = 0;
405 rd->readx.out.compaction_mode = 0;
406 rd->readx.out.nread = data.length;
414 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
415 struct smbsrv_request *req, union smb_write *wr)
417 struct ipc_private *private = ntvfs->private_data;
420 struct pipe_state *p;
423 if (wr->generic.level != RAW_WRITE_GENERIC) {
424 return ntvfs_map_write(req, wr, ntvfs);
427 fnum = wr->writex.in.fnum;
428 data.data = discard_const_p(void, wr->writex.in.data);
429 data.length = wr->writex.in.count;
431 p = pipe_state_find(private, fnum);
433 return NT_STATUS_INVALID_HANDLE;
436 status = dcesrv_input(p->dce_conn, &data);
437 if (!NT_STATUS_IS_OK(status)) {
441 wr->writex.out.nwritten = data.length;
442 wr->writex.out.remaining = 0;
450 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
451 struct smbsrv_request *req, struct smb_seek *io)
453 return NT_STATUS_ACCESS_DENIED;
459 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
460 struct smbsrv_request *req, struct smb_flush *io)
462 return NT_STATUS_ACCESS_DENIED;
468 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
469 struct smbsrv_request *req, union smb_close *io)
471 struct ipc_private *private = ntvfs->private_data;
472 struct pipe_state *p;
474 if (io->generic.level != RAW_CLOSE_CLOSE) {
475 return ntvfs_map_close(req, io, ntvfs);
478 p = pipe_state_find(private, io->close.in.fnum);
480 return NT_STATUS_INVALID_HANDLE;
491 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
492 struct smbsrv_request *req)
494 struct ipc_private *private = ntvfs->private_data;
495 struct pipe_state *p, *next;
497 for (p=private->pipe_list; p; p=next) {
499 if (p->smbpid == req->smbpid) {
508 logoff - closing files open by the user
510 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
511 struct smbsrv_request *req)
513 struct ipc_private *private = ntvfs->private_data;
514 struct pipe_state *p, *next;
516 for (p=private->pipe_list; p; p=next) {
518 if (p->session == req->session) {
527 setup for an async call
529 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
530 struct smbsrv_request *req,
539 static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
540 struct smbsrv_request *req)
542 return NT_STATUS_UNSUCCESSFUL;
548 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
549 struct smbsrv_request *req, union smb_lock *lck)
551 return NT_STATUS_ACCESS_DENIED;
555 set info on a open file
557 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
558 struct smbsrv_request *req, union smb_setfileinfo *info)
560 return NT_STATUS_ACCESS_DENIED;
564 query info on a open file
566 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
567 struct smbsrv_request *req, union smb_fileinfo *info)
569 return NT_STATUS_ACCESS_DENIED;
574 return filesystem info
576 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
577 struct smbsrv_request *req, union smb_fsinfo *fs)
579 return NT_STATUS_ACCESS_DENIED;
583 return print queue info
585 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
586 struct smbsrv_request *req, union smb_lpq *lpq)
588 return NT_STATUS_ACCESS_DENIED;
592 list files in a directory matching a wildcard pattern
594 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
595 struct smbsrv_request *req, union smb_search_first *io,
596 void *search_private,
597 BOOL (*callback)(void *, union smb_search_data *))
599 return NT_STATUS_ACCESS_DENIED;
603 continue listing files in a directory
605 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
606 struct smbsrv_request *req, union smb_search_next *io,
607 void *search_private,
608 BOOL (*callback)(void *, union smb_search_data *))
610 return NT_STATUS_ACCESS_DENIED;
614 end listing files in a directory
616 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
617 struct smbsrv_request *req, union smb_search_close *io)
619 return NT_STATUS_ACCESS_DENIED;
622 static NTSTATUS ipc_trans_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
624 NTSTATUS status = NT_STATUS_OK;
625 DATA_BLOB *blob = private_data;
627 if (out->length > blob->length) {
628 status = STATUS_BUFFER_OVERFLOW;
631 if (out->length < blob->length) {
632 blob->length = out->length;
634 memcpy(blob->data, out->data, blob->length);
635 *nwritten = blob->length;
639 /* SMBtrans - handle a DCERPC command */
640 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
641 struct smbsrv_request *req, struct smb_trans2 *trans)
643 struct pipe_state *p;
644 struct ipc_private *private = ntvfs->private_data;
647 /* the fnum is in setup[1] */
648 p = pipe_state_find(private, trans->in.setup[1]);
650 return NT_STATUS_INVALID_HANDLE;
653 trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
654 if (!trans->out.data.data) {
655 return NT_STATUS_NO_MEMORY;
658 /* pass the data to the dcerpc server. Note that we don't
659 expect this to fail, and things like NDR faults are not
660 reported at this stage. Those sorts of errors happen in the
661 dcesrv_output stage */
662 status = dcesrv_input(p->dce_conn, &trans->in.data);
663 if (!NT_STATUS_IS_OK(status)) {
668 now ask the dcerpc system for some output. This doesn't yet handle
669 async calls. Again, we only expect NT_STATUS_OK. If the call fails then
670 the error is encoded at the dcerpc level
672 status = dcesrv_output(p->dce_conn, &trans->out.data, ipc_trans_dcesrv_output);
673 if (NT_STATUS_IS_ERR(status)) {
677 trans->out.setup_count = 0;
678 trans->out.setup = NULL;
679 trans->out.params = data_blob(NULL, 0);
685 /* SMBtrans - set named pipe state */
686 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
687 struct smbsrv_request *req, struct smb_trans2 *trans)
689 struct ipc_private *private = ntvfs->private_data;
690 struct pipe_state *p;
692 /* the fnum is in setup[1] */
693 p = pipe_state_find(private, trans->in.setup[1]);
695 return NT_STATUS_INVALID_HANDLE;
698 if (trans->in.params.length != 2) {
699 return NT_STATUS_INVALID_PARAMETER;
701 p->ipc_state = SVAL(trans->in.params.data, 0);
703 trans->out.setup_count = 0;
704 trans->out.setup = NULL;
705 trans->out.params = data_blob(NULL, 0);
706 trans->out.data = data_blob(NULL, 0);
712 /* SMBtrans - used to provide access to SMB pipes */
713 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
714 struct smbsrv_request *req, struct smb_trans2 *trans)
718 if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
719 return ipc_rap_call(req, trans);
721 if (trans->in.setup_count != 2) {
722 return NT_STATUS_INVALID_PARAMETER;
725 switch (trans->in.setup[0]) {
726 case TRANSACT_SETNAMEDPIPEHANDLESTATE:
727 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
729 case TRANSACT_DCERPCCMD:
730 status = ipc_dcerpc_cmd(ntvfs, req, trans);
733 status = NT_STATUS_INVALID_PARAMETER;
743 initialialise the IPC backend, registering ourselves with the ntvfs subsystem
745 NTSTATUS ntvfs_ipc_init(void)
748 struct ntvfs_ops ops;
752 /* fill in the name and type */
753 ops.name = "default";
754 ops.type = NTVFS_IPC;
756 /* fill in all the operations */
757 ops.connect = ipc_connect;
758 ops.disconnect = ipc_disconnect;
759 ops.unlink = ipc_unlink;
760 ops.chkpath = ipc_chkpath;
761 ops.qpathinfo = ipc_qpathinfo;
762 ops.setpathinfo = ipc_setpathinfo;
763 ops.openfile = ipc_open;
764 ops.mkdir = ipc_mkdir;
765 ops.rmdir = ipc_rmdir;
766 ops.rename = ipc_rename;
768 ops.ioctl = ipc_ioctl;
770 ops.write = ipc_write;
772 ops.flush = ipc_flush;
773 ops.close = ipc_close;
776 ops.setfileinfo = ipc_setfileinfo;
777 ops.qfileinfo = ipc_qfileinfo;
778 ops.fsinfo = ipc_fsinfo;
780 ops.search_first = ipc_search_first;
781 ops.search_next = ipc_search_next;
782 ops.search_close = ipc_search_close;
783 ops.trans = ipc_trans;
784 ops.logoff = ipc_logoff;
785 ops.async_setup = ipc_async_setup;
786 ops.cancel = ipc_cancel;
788 /* register ourselves with the NTVFS subsystem. */
789 ret = ntvfs_register(&ops);
791 if (!NT_STATUS_IS_OK(ret)) {
792 DEBUG(0,("Failed to register IPC backend!\n"));