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 "libcli/rap/rap.h"
33 #include "ntvfs/ipc/proto.h"
34 #include "rpc_server/dcerpc_server.h"
36 #define IPC_BASE_FNUM 0x400
38 /* this is the private structure used to keep the state of an open
39 ipc$ connection. It needs to keep information about all open
42 struct idr_context *idtree_fnum;
44 struct dcesrv_context *dcesrv;
46 /* a list of open pipes */
48 struct pipe_state *next, *prev;
49 struct ipc_private *private;
50 const char *pipe_name;
52 struct dcesrv_connection *dce_conn;
54 /* we need to remember the session it was opened on,
55 as it is illegal to operate on someone elses fnum */
56 struct smbsrv_session *session;
58 /* we need to remember the client pid that
59 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)
71 return idr_find(private->idtree_fnum, fnum);
76 connect to a share - always works
78 static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
79 struct ntvfs_request *req, const char *sharename)
82 struct smbsrv_tcon *tcon = req->tcon;
83 struct ipc_private *private;
85 tcon->fs_type = talloc_strdup(tcon, "IPC");
86 NT_STATUS_HAVE_NO_MEMORY(tcon->fs_type);
88 tcon->dev_type = talloc_strdup(tcon, "IPC");
89 NT_STATUS_HAVE_NO_MEMORY(tcon->dev_type);
91 /* prepare the private state for this connection */
92 private = talloc(ntvfs, struct ipc_private);
93 NT_STATUS_HAVE_NO_MEMORY(private);
95 ntvfs->private_data = private;
97 private->pipe_list = NULL;
99 private->idtree_fnum = idr_init(private);
100 NT_STATUS_HAVE_NO_MEMORY(private->idtree_fnum);
102 /* setup the DCERPC server subsystem */
103 status = dcesrv_init_ipc_context(private, &private->dcesrv);
104 NT_STATUS_NOT_OK_RETURN(status);
110 disconnect from a share
112 static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs)
120 static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
121 struct ntvfs_request *req,
122 union smb_unlink *unl)
124 return NT_STATUS_ACCESS_DENIED;
129 ioctl interface - we don't do any
131 static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
132 struct ntvfs_request *req, union smb_ioctl *io)
134 return NT_STATUS_ACCESS_DENIED;
138 check if a directory exists
140 static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
141 struct ntvfs_request *req,
142 union smb_chkpath *cp)
144 return NT_STATUS_ACCESS_DENIED;
148 return info on a pathname
150 static NTSTATUS ipc_qpathinfo(struct ntvfs_module_context *ntvfs,
151 struct ntvfs_request *req, union smb_fileinfo *info)
153 return NT_STATUS_ACCESS_DENIED;
157 set info on a pathname
159 static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
160 struct ntvfs_request *req, union smb_setfileinfo *st)
162 return NT_STATUS_ACCESS_DENIED;
167 destroy a open pipe structure
169 static int ipc_fd_destructor(void *ptr)
171 struct pipe_state *p = ptr;
172 idr_remove(p->private->idtree_fnum, p->fnum);
173 DLIST_REMOVE(p->private->pipe_list, p);
179 open a file backend - used for MSRPC pipes
181 static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
182 struct ntvfs_request *req, const char *fname,
183 struct pipe_state **ps)
185 struct pipe_state *p;
187 struct dcerpc_binding *ep_description;
188 struct ipc_private *private = ntvfs->private_data;
190 struct stream_connection *srv_conn = req->smb_conn->connection;
192 if (!req->session || !req->session->session_info) {
193 return NT_STATUS_ACCESS_DENIED;
196 p = talloc(req, struct pipe_state);
197 NT_STATUS_HAVE_NO_MEMORY(p);
199 ep_description = talloc(req, struct dcerpc_binding);
200 NT_STATUS_HAVE_NO_MEMORY(ep_description);
202 while (fname[0] == '\\') fname++;
204 p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
205 NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
207 fnum = idr_get_new_above(private->idtree_fnum, p, IPC_BASE_FNUM, UINT16_MAX);
209 return NT_STATUS_TOO_MANY_OPENED_FILES;
213 p->ipc_state = 0x5ff;
216 we're all set, now ask the dcerpc server subsystem to open the
217 endpoint. At this stage the pipe isn't bound, so we don't
218 know what interface the user actually wants, just that they want
219 one of the interfaces attached to this pipe endpoint.
221 ep_description->transport = NCACN_NP;
222 ep_description->endpoint = talloc_reference(ep_description, p->pipe_name);
224 /* The session info is refcount-increased in the
225 * dcesrv_endpoint_search_connect() function
227 status = dcesrv_endpoint_search_connect(private->dcesrv,
230 req->session->session_info,
234 if (!NT_STATUS_IS_OK(status)) {
235 idr_remove(private->idtree_fnum, p->fnum);
239 DLIST_ADD(private->pipe_list, p);
241 p->smbpid = req->smbpid;
242 p->session = req->session;
243 p->private = private;
247 talloc_steal(private, p);
249 talloc_set_destructor(p, ipc_fd_destructor);
255 open a file with ntcreatex - used for MSRPC pipes
257 static NTSTATUS ipc_open_ntcreatex(struct ntvfs_module_context *ntvfs,
258 struct ntvfs_request *req, union smb_open *oi)
260 struct pipe_state *p;
263 status = ipc_open_generic(ntvfs, req, oi->ntcreatex.in.fname, &p);
264 if (!NT_STATUS_IS_OK(status)) {
268 ZERO_STRUCT(oi->ntcreatex.out);
269 oi->ntcreatex.out.file.fnum = p->fnum;
270 oi->ntcreatex.out.ipc_state = p->ipc_state;
271 oi->ntcreatex.out.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
277 open a file with openx - used for MSRPC pipes
279 static NTSTATUS ipc_open_openx(struct ntvfs_module_context *ntvfs,
280 struct ntvfs_request *req, union smb_open *oi)
282 struct pipe_state *p;
284 const char *fname = oi->openx.in.fname;
286 status = ipc_open_generic(ntvfs, req, fname, &p);
287 if (!NT_STATUS_IS_OK(status)) {
291 ZERO_STRUCT(oi->openx.out);
292 oi->openx.out.file.fnum = p->fnum;
293 oi->openx.out.ftype = 2;
294 oi->openx.out.devstate = p->ipc_state;
300 open a file - used for MSRPC pipes
302 static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
303 struct ntvfs_request *req, union smb_open *oi)
307 switch (oi->generic.level) {
308 case RAW_OPEN_NTCREATEX:
309 status = ipc_open_ntcreatex(ntvfs, req, oi);
312 status = ipc_open_openx(ntvfs, req, oi);
315 status = NT_STATUS_NOT_SUPPORTED;
325 static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
326 struct ntvfs_request *req, union smb_mkdir *md)
328 return NT_STATUS_ACCESS_DENIED;
334 static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
335 struct ntvfs_request *req, struct smb_rmdir *rd)
337 return NT_STATUS_ACCESS_DENIED;
341 rename a set of files
343 static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
344 struct ntvfs_request *req, union smb_rename *ren)
346 return NT_STATUS_ACCESS_DENIED;
352 static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
353 struct ntvfs_request *req, struct smb_copy *cp)
355 return NT_STATUS_ACCESS_DENIED;
358 static NTSTATUS ipc_readx_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
360 DATA_BLOB *blob = private_data;
362 if (out->length < blob->length) {
363 blob->length = out->length;
365 memcpy(blob->data, out->data, blob->length);
366 *nwritten = blob->length;
373 static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
374 struct ntvfs_request *req, union smb_read *rd)
376 struct ipc_private *private = ntvfs->private_data;
379 struct pipe_state *p;
380 NTSTATUS status = NT_STATUS_OK;
382 if (rd->generic.level != RAW_READ_GENERIC) {
383 return ntvfs_map_read(ntvfs, req, rd);
386 fnum = rd->readx.in.file.fnum;
388 p = pipe_state_find(private, fnum);
390 return NT_STATUS_INVALID_HANDLE;
393 data.length = rd->readx.in.maxcnt;
394 data.data = rd->readx.out.data;
395 if (data.length > UINT16_MAX) {
396 data.length = UINT16_MAX;
399 if (data.length != 0) {
400 status = dcesrv_output(p->dce_conn, &data, ipc_readx_dcesrv_output);
401 if (NT_STATUS_IS_ERR(status)) {
406 rd->readx.out.remaining = 0;
407 rd->readx.out.compaction_mode = 0;
408 rd->readx.out.nread = data.length;
416 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
417 struct ntvfs_request *req, union smb_write *wr)
419 struct ipc_private *private = ntvfs->private_data;
422 struct pipe_state *p;
425 if (wr->generic.level != RAW_WRITE_GENERIC) {
426 return ntvfs_map_write(ntvfs, req, wr);
429 fnum = wr->writex.in.file.fnum;
430 data.data = discard_const_p(void, wr->writex.in.data);
431 data.length = wr->writex.in.count;
433 p = pipe_state_find(private, fnum);
435 return NT_STATUS_INVALID_HANDLE;
438 status = dcesrv_input(p->dce_conn, &data);
439 if (!NT_STATUS_IS_OK(status)) {
443 wr->writex.out.nwritten = data.length;
444 wr->writex.out.remaining = 0;
452 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
453 struct ntvfs_request *req,
456 return NT_STATUS_ACCESS_DENIED;
462 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
463 struct ntvfs_request *req,
466 return NT_STATUS_ACCESS_DENIED;
472 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
473 struct ntvfs_request *req, union smb_close *io)
475 struct ipc_private *private = ntvfs->private_data;
476 struct pipe_state *p;
478 if (io->generic.level != RAW_CLOSE_CLOSE) {
479 return ntvfs_map_close(ntvfs, req, io);
482 p = pipe_state_find(private, io->close.in.file.fnum);
484 return NT_STATUS_INVALID_HANDLE;
495 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
496 struct ntvfs_request *req)
498 struct ipc_private *private = ntvfs->private_data;
499 struct pipe_state *p, *next;
501 for (p=private->pipe_list; p; p=next) {
503 if (p->smbpid == req->smbpid) {
512 logoff - closing files open by the user
514 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
515 struct ntvfs_request *req)
517 struct ipc_private *private = ntvfs->private_data;
518 struct pipe_state *p, *next;
520 for (p=private->pipe_list; p; p=next) {
522 if (p->session == req->session) {
531 setup for an async call
533 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
534 struct ntvfs_request *req,
543 static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
544 struct ntvfs_request *req)
546 return NT_STATUS_UNSUCCESSFUL;
552 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
553 struct ntvfs_request *req, union smb_lock *lck)
555 return NT_STATUS_ACCESS_DENIED;
559 set info on a open file
561 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
562 struct ntvfs_request *req, union smb_setfileinfo *info)
564 return NT_STATUS_ACCESS_DENIED;
568 query info on a open file
570 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
571 struct ntvfs_request *req, union smb_fileinfo *info)
573 return NT_STATUS_ACCESS_DENIED;
578 return filesystem info
580 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
581 struct ntvfs_request *req, union smb_fsinfo *fs)
583 return NT_STATUS_ACCESS_DENIED;
587 return print queue info
589 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
590 struct ntvfs_request *req, union smb_lpq *lpq)
592 return NT_STATUS_ACCESS_DENIED;
596 list files in a directory matching a wildcard pattern
598 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
599 struct ntvfs_request *req, union smb_search_first *io,
600 void *search_private,
601 BOOL (*callback)(void *, union smb_search_data *))
603 return NT_STATUS_ACCESS_DENIED;
607 continue listing files in a directory
609 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
610 struct ntvfs_request *req, union smb_search_next *io,
611 void *search_private,
612 BOOL (*callback)(void *, union smb_search_data *))
614 return NT_STATUS_ACCESS_DENIED;
618 end listing files in a directory
620 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
621 struct ntvfs_request *req, union smb_search_close *io)
623 return NT_STATUS_ACCESS_DENIED;
626 static NTSTATUS ipc_trans_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
628 NTSTATUS status = NT_STATUS_OK;
629 DATA_BLOB *blob = private_data;
631 if (out->length > blob->length) {
632 status = STATUS_BUFFER_OVERFLOW;
635 if (out->length < blob->length) {
636 blob->length = out->length;
638 memcpy(blob->data, out->data, blob->length);
639 *nwritten = blob->length;
643 /* SMBtrans - handle a DCERPC command */
644 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
645 struct ntvfs_request *req, struct smb_trans2 *trans)
647 struct pipe_state *p;
648 struct ipc_private *private = ntvfs->private_data;
651 /* the fnum is in setup[1] */
652 p = pipe_state_find(private, trans->in.setup[1]);
654 return NT_STATUS_INVALID_HANDLE;
657 trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
658 if (!trans->out.data.data) {
659 return NT_STATUS_NO_MEMORY;
662 /* pass the data to the dcerpc server. Note that we don't
663 expect this to fail, and things like NDR faults are not
664 reported at this stage. Those sorts of errors happen in the
665 dcesrv_output stage */
666 status = dcesrv_input(p->dce_conn, &trans->in.data);
667 if (!NT_STATUS_IS_OK(status)) {
672 now ask the dcerpc system for some output. This doesn't yet handle
673 async calls. Again, we only expect NT_STATUS_OK. If the call fails then
674 the error is encoded at the dcerpc level
676 status = dcesrv_output(p->dce_conn, &trans->out.data, ipc_trans_dcesrv_output);
677 if (NT_STATUS_IS_ERR(status)) {
681 trans->out.setup_count = 0;
682 trans->out.setup = NULL;
683 trans->out.params = data_blob(NULL, 0);
689 /* SMBtrans - set named pipe state */
690 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
691 struct ntvfs_request *req, struct smb_trans2 *trans)
693 struct ipc_private *private = ntvfs->private_data;
694 struct pipe_state *p;
696 /* the fnum is in setup[1] */
697 p = pipe_state_find(private, trans->in.setup[1]);
699 return NT_STATUS_INVALID_HANDLE;
702 if (trans->in.params.length != 2) {
703 return NT_STATUS_INVALID_PARAMETER;
705 p->ipc_state = SVAL(trans->in.params.data, 0);
707 trans->out.setup_count = 0;
708 trans->out.setup = NULL;
709 trans->out.params = data_blob(NULL, 0);
710 trans->out.data = data_blob(NULL, 0);
716 /* SMBtrans - used to provide access to SMB pipes */
717 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
718 struct ntvfs_request *req, struct smb_trans2 *trans)
722 if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
723 return ipc_rap_call(req, trans);
725 if (trans->in.setup_count != 2) {
726 return NT_STATUS_INVALID_PARAMETER;
729 switch (trans->in.setup[0]) {
730 case TRANSACT_SETNAMEDPIPEHANDLESTATE:
731 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
733 case TRANSACT_DCERPCCMD:
734 status = ipc_dcerpc_cmd(ntvfs, req, trans);
737 status = NT_STATUS_INVALID_PARAMETER;
747 initialialise the IPC backend, registering ourselves with the ntvfs subsystem
749 NTSTATUS ntvfs_ipc_init(void)
752 struct ntvfs_ops ops;
756 /* fill in the name and type */
757 ops.name = "default";
758 ops.type = NTVFS_IPC;
760 /* fill in all the operations */
761 ops.connect = ipc_connect;
762 ops.disconnect = ipc_disconnect;
763 ops.unlink = ipc_unlink;
764 ops.chkpath = ipc_chkpath;
765 ops.qpathinfo = ipc_qpathinfo;
766 ops.setpathinfo = ipc_setpathinfo;
768 ops.mkdir = ipc_mkdir;
769 ops.rmdir = ipc_rmdir;
770 ops.rename = ipc_rename;
772 ops.ioctl = ipc_ioctl;
774 ops.write = ipc_write;
776 ops.flush = ipc_flush;
777 ops.close = ipc_close;
780 ops.setfileinfo = ipc_setfileinfo;
781 ops.qfileinfo = ipc_qfileinfo;
782 ops.fsinfo = ipc_fsinfo;
784 ops.search_first = ipc_search_first;
785 ops.search_next = ipc_search_next;
786 ops.search_close = ipc_search_close;
787 ops.trans = ipc_trans;
788 ops.logoff = ipc_logoff;
789 ops.async_setup = ipc_async_setup;
790 ops.cancel = ipc_cancel;
792 /* register ourselves with the NTVFS subsystem. */
793 ret = ntvfs_register(&ops);
795 if (!NT_STATUS_IS_OK(ret)) {
796 DEBUG(0,("Failed to register IPC backend!\n"));