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 "system/filesys.h"
30 #include "dlinklist.h"
31 #include "smb_server/smb_server.h"
33 #define IPC_BASE_FNUM 0x400
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 idr_context *idtree_fnum;
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;
49 struct dcesrv_connection *dce_conn;
51 /* we need to remember the session it was opened on,
52 as it is illegal to operate on someone elses fnum */
53 struct smbsrv_session *session;
55 /* we need to remember the client pid that
56 opened the file so SMBexit works */
64 find a open pipe give a file descriptor
66 static struct pipe_state *pipe_state_find(struct ipc_private *private, uint16_t fnum)
68 return idr_find(private->idtree_fnum, fnum);
73 connect to a share - always works
75 static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
76 struct smbsrv_request *req, const char *sharename)
79 struct smbsrv_tcon *tcon = req->tcon;
80 struct ipc_private *private;
82 tcon->fs_type = talloc_strdup(tcon, "IPC");
83 NT_STATUS_HAVE_NO_MEMORY(tcon->fs_type);
85 tcon->dev_type = talloc_strdup(tcon, "IPC");
86 NT_STATUS_HAVE_NO_MEMORY(tcon->dev_type);
88 /* prepare the private state for this connection */
89 private = talloc(tcon, struct ipc_private);
90 NT_STATUS_HAVE_NO_MEMORY(private);
92 ntvfs->private_data = private;
94 private->pipe_list = NULL;
96 private->idtree_fnum = idr_init(private);
97 NT_STATUS_HAVE_NO_MEMORY(private->idtree_fnum);
99 /* setup the DCERPC server subsystem */
100 status = dcesrv_init_ipc_context(private, &private->dcesrv);
101 NT_STATUS_NOT_OK_RETURN(status);
107 disconnect from a share
109 static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs,
110 struct smbsrv_tcon *tcon)
118 static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
119 struct smbsrv_request *req, struct smb_unlink *unl)
121 return NT_STATUS_ACCESS_DENIED;
126 ioctl interface - we don't do any
128 static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
129 struct smbsrv_request *req, union smb_ioctl *io)
131 return NT_STATUS_ACCESS_DENIED;
135 check if a directory exists
137 static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
138 struct smbsrv_request *req, struct smb_chkpath *cp)
140 return NT_STATUS_ACCESS_DENIED;
144 return info on a pathname
146 static NTSTATUS ipc_qpathinfo(struct ntvfs_module_context *ntvfs,
147 struct smbsrv_request *req, union smb_fileinfo *info)
149 return NT_STATUS_ACCESS_DENIED;
153 set info on a pathname
155 static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
156 struct smbsrv_request *req, union smb_setfileinfo *st)
158 return NT_STATUS_ACCESS_DENIED;
163 destroy a open pipe structure
165 static int ipc_fd_destructor(void *ptr)
167 struct pipe_state *p = ptr;
168 idr_remove(p->private->idtree_fnum, p->fnum);
169 DLIST_REMOVE(p->private->pipe_list, p);
175 open a file backend - used for MSRPC pipes
177 static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
178 struct smbsrv_request *req, const char *fname,
179 struct pipe_state **ps)
181 struct pipe_state *p;
183 struct dcerpc_binding *ep_description;
184 struct ipc_private *private = ntvfs->private_data;
186 struct stream_connection *srv_conn = req->smb_conn->connection;
188 if (!req->session || !req->session->session_info) {
189 return NT_STATUS_ACCESS_DENIED;
192 p = talloc(req, struct pipe_state);
193 NT_STATUS_HAVE_NO_MEMORY(p);
195 ep_description = talloc(req, struct dcerpc_binding);
196 NT_STATUS_HAVE_NO_MEMORY(ep_description);
198 while (fname[0] == '\\') fname++;
200 p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
201 NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
203 fnum = idr_get_new_above(private->idtree_fnum, p, IPC_BASE_FNUM, UINT16_MAX);
205 return NT_STATUS_TOO_MANY_OPENED_FILES;
209 p->ipc_state = 0x5ff;
212 we're all set, now ask the dcerpc server subsystem to open the
213 endpoint. At this stage the pipe isn't bound, so we don't
214 know what interface the user actually wants, just that they want
215 one of the interfaces attached to this pipe endpoint.
217 ep_description->transport = NCACN_NP;
218 ep_description->endpoint = talloc_reference(ep_description, p->pipe_name);
220 /* The session info is refcount-increased in the
221 * dcesrv_endpoint_search_connect() function
223 status = dcesrv_endpoint_search_connect(private->dcesrv,
226 req->session->session_info,
229 if (!NT_STATUS_IS_OK(status)) {
230 idr_remove(private->idtree_fnum, p->fnum);
234 DLIST_ADD(private->pipe_list, p);
236 p->smbpid = req->smbpid;
237 p->session = req->session;
238 p->private = private;
242 talloc_steal(private, p);
244 talloc_set_destructor(p, ipc_fd_destructor);
250 open a file with ntcreatex - used for MSRPC pipes
252 static NTSTATUS ipc_open_ntcreatex(struct ntvfs_module_context *ntvfs,
253 struct smbsrv_request *req, union smb_open *oi)
255 struct pipe_state *p;
258 status = ipc_open_generic(ntvfs, req, oi->ntcreatex.in.fname, &p);
259 if (!NT_STATUS_IS_OK(status)) {
263 ZERO_STRUCT(oi->ntcreatex.out);
264 oi->ntcreatex.out.fnum = p->fnum;
265 oi->ntcreatex.out.ipc_state = p->ipc_state;
266 oi->ntcreatex.out.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
272 open a file with openx - used for MSRPC pipes
274 static NTSTATUS ipc_open_openx(struct ntvfs_module_context *ntvfs,
275 struct smbsrv_request *req, union smb_open *oi)
277 struct pipe_state *p;
279 const char *fname = oi->openx.in.fname;
281 status = ipc_open_generic(ntvfs, req, fname, &p);
282 if (!NT_STATUS_IS_OK(status)) {
286 ZERO_STRUCT(oi->openx.out);
287 oi->openx.out.fnum = p->fnum;
288 oi->openx.out.ftype = 2;
289 oi->openx.out.devstate = p->ipc_state;
295 open a file - used for MSRPC pipes
297 static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
298 struct smbsrv_request *req, union smb_open *oi)
302 switch (oi->generic.level) {
303 case RAW_OPEN_NTCREATEX:
304 status = ipc_open_ntcreatex(ntvfs, req, oi);
307 status = ipc_open_openx(ntvfs, req, oi);
310 status = NT_STATUS_NOT_SUPPORTED;
320 static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
321 struct smbsrv_request *req, union smb_mkdir *md)
323 return NT_STATUS_ACCESS_DENIED;
329 static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
330 struct smbsrv_request *req, struct smb_rmdir *rd)
332 return NT_STATUS_ACCESS_DENIED;
336 rename a set of files
338 static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
339 struct smbsrv_request *req, union smb_rename *ren)
341 return NT_STATUS_ACCESS_DENIED;
347 static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
348 struct smbsrv_request *req, struct smb_copy *cp)
350 return NT_STATUS_ACCESS_DENIED;
356 static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
357 struct smbsrv_request *req, union smb_read *rd)
359 struct ipc_private *private = ntvfs->private_data;
362 struct pipe_state *p;
365 if (rd->generic.level != RAW_READ_GENERIC) {
366 return ntvfs_map_read(req, rd, ntvfs);
369 fnum = rd->readx.in.fnum;
371 p = pipe_state_find(private, fnum);
373 return NT_STATUS_INVALID_HANDLE;
376 data.length = rd->readx.in.maxcnt;
377 data.data = rd->readx.out.data;
378 if (data.length > UINT16_MAX) {
382 if (data.length != 0) {
383 status = dcesrv_output_blob(p->dce_conn, &data);
384 if (NT_STATUS_IS_ERR(status)) {
389 rd->readx.out.remaining = 0;
390 rd->readx.out.compaction_mode = 0;
391 rd->readx.out.nread = data.length;
399 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
400 struct smbsrv_request *req, union smb_write *wr)
402 struct ipc_private *private = ntvfs->private_data;
405 struct pipe_state *p;
408 if (wr->generic.level != RAW_WRITE_GENERIC) {
409 return ntvfs_map_write(req, wr, ntvfs);
412 fnum = wr->writex.in.fnum;
413 data.data = discard_const_p(void, wr->writex.in.data);
414 data.length = wr->writex.in.count;
416 p = pipe_state_find(private, fnum);
418 return NT_STATUS_INVALID_HANDLE;
421 status = dcesrv_input(p->dce_conn, &data);
422 if (!NT_STATUS_IS_OK(status)) {
426 wr->writex.out.nwritten = data.length;
427 wr->writex.out.remaining = 0;
435 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
436 struct smbsrv_request *req, struct smb_seek *io)
438 return NT_STATUS_ACCESS_DENIED;
444 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
445 struct smbsrv_request *req, struct smb_flush *io)
447 return NT_STATUS_ACCESS_DENIED;
453 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
454 struct smbsrv_request *req, union smb_close *io)
456 struct ipc_private *private = ntvfs->private_data;
457 struct pipe_state *p;
459 if (io->generic.level != RAW_CLOSE_CLOSE) {
460 return ntvfs_map_close(req, io, ntvfs);
463 p = pipe_state_find(private, io->close.in.fnum);
465 return NT_STATUS_INVALID_HANDLE;
476 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
477 struct smbsrv_request *req)
479 struct ipc_private *private = ntvfs->private_data;
480 struct pipe_state *p, *next;
482 for (p=private->pipe_list; p; p=next) {
484 if (p->smbpid == req->smbpid) {
493 logoff - closing files open by the user
495 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
496 struct smbsrv_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->session == req->session) {
512 setup for an async call
514 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
515 struct smbsrv_request *req,
524 static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
525 struct smbsrv_request *req)
527 return NT_STATUS_UNSUCCESSFUL;
533 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
534 struct smbsrv_request *req, union smb_lock *lck)
536 return NT_STATUS_ACCESS_DENIED;
540 set info on a open file
542 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
543 struct smbsrv_request *req, union smb_setfileinfo *info)
545 return NT_STATUS_ACCESS_DENIED;
549 query info on a open file
551 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
552 struct smbsrv_request *req, union smb_fileinfo *info)
554 return NT_STATUS_ACCESS_DENIED;
559 return filesystem info
561 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
562 struct smbsrv_request *req, union smb_fsinfo *fs)
564 return NT_STATUS_ACCESS_DENIED;
568 return print queue info
570 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
571 struct smbsrv_request *req, union smb_lpq *lpq)
573 return NT_STATUS_ACCESS_DENIED;
577 list files in a directory matching a wildcard pattern
579 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
580 struct smbsrv_request *req, union smb_search_first *io,
581 void *search_private,
582 BOOL (*callback)(void *, union smb_search_data *))
584 return NT_STATUS_ACCESS_DENIED;
588 continue listing files in a directory
590 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
591 struct smbsrv_request *req, union smb_search_next *io,
592 void *search_private,
593 BOOL (*callback)(void *, union smb_search_data *))
595 return NT_STATUS_ACCESS_DENIED;
599 end listing files in a directory
601 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
602 struct smbsrv_request *req, union smb_search_close *io)
604 return NT_STATUS_ACCESS_DENIED;
608 /* SMBtrans - handle a DCERPC command */
609 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
610 struct smbsrv_request *req, struct smb_trans2 *trans)
612 struct pipe_state *p;
613 struct ipc_private *private = ntvfs->private_data;
616 /* the fnum is in setup[1] */
617 p = pipe_state_find(private, trans->in.setup[1]);
619 return NT_STATUS_INVALID_HANDLE;
622 trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
623 if (!trans->out.data.data) {
624 return NT_STATUS_NO_MEMORY;
627 /* pass the data to the dcerpc server. Note that we don't
628 expect this to fail, and things like NDR faults are not
629 reported at this stage. Those sorts of errors happen in the
630 dcesrv_output stage */
631 status = dcesrv_input(p->dce_conn, &trans->in.data);
632 if (!NT_STATUS_IS_OK(status)) {
637 now ask the dcerpc system for some output. This doesn't yet handle
638 async calls. Again, we only expect NT_STATUS_OK. If the call fails then
639 the error is encoded at the dcerpc level
641 status = dcesrv_output_blob(p->dce_conn, &trans->out.data);
642 if (NT_STATUS_IS_ERR(status)) {
646 trans->out.setup_count = 0;
647 trans->out.setup = NULL;
648 trans->out.params = data_blob(NULL, 0);
654 /* SMBtrans - set named pipe state */
655 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
656 struct smbsrv_request *req, struct smb_trans2 *trans)
658 struct ipc_private *private = ntvfs->private_data;
659 struct pipe_state *p;
661 /* the fnum is in setup[1] */
662 p = pipe_state_find(private, trans->in.setup[1]);
664 return NT_STATUS_INVALID_HANDLE;
667 if (trans->in.params.length != 2) {
668 return NT_STATUS_INVALID_PARAMETER;
670 p->ipc_state = SVAL(trans->in.params.data, 0);
672 trans->out.setup_count = 0;
673 trans->out.setup = NULL;
674 trans->out.params = data_blob(NULL, 0);
675 trans->out.data = data_blob(NULL, 0);
681 /* SMBtrans - used to provide access to SMB pipes */
682 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
683 struct smbsrv_request *req, struct smb_trans2 *trans)
687 if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
688 return ipc_rap_call(req, trans);
690 if (trans->in.setup_count != 2) {
691 return NT_STATUS_INVALID_PARAMETER;
694 switch (trans->in.setup[0]) {
695 case TRANSACT_SETNAMEDPIPEHANDLESTATE:
696 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
698 case TRANSACT_DCERPCCMD:
699 status = ipc_dcerpc_cmd(ntvfs, req, trans);
702 status = NT_STATUS_INVALID_PARAMETER;
712 initialialise the IPC backend, registering ourselves with the ntvfs subsystem
714 NTSTATUS ntvfs_ipc_init(void)
717 struct ntvfs_ops ops;
721 /* fill in the name and type */
722 ops.name = "default";
723 ops.type = NTVFS_IPC;
725 /* fill in all the operations */
726 ops.connect = ipc_connect;
727 ops.disconnect = ipc_disconnect;
728 ops.unlink = ipc_unlink;
729 ops.chkpath = ipc_chkpath;
730 ops.qpathinfo = ipc_qpathinfo;
731 ops.setpathinfo = ipc_setpathinfo;
732 ops.openfile = ipc_open;
733 ops.mkdir = ipc_mkdir;
734 ops.rmdir = ipc_rmdir;
735 ops.rename = ipc_rename;
737 ops.ioctl = ipc_ioctl;
739 ops.write = ipc_write;
741 ops.flush = ipc_flush;
742 ops.close = ipc_close;
745 ops.setfileinfo = ipc_setfileinfo;
746 ops.qfileinfo = ipc_qfileinfo;
747 ops.fsinfo = ipc_fsinfo;
749 ops.search_first = ipc_search_first;
750 ops.search_next = ipc_search_next;
751 ops.search_close = ipc_search_close;
752 ops.trans = ipc_trans;
753 ops.logoff = ipc_logoff;
754 ops.async_setup = ipc_async_setup;
755 ops.cancel = ipc_cancel;
757 /* register ourselves with the NTVFS subsystem. */
758 ret = ntvfs_register(&ops);
760 if (!NT_STATUS_IS_OK(ret)) {
761 DEBUG(0,("Failed to register IPC backend!\n"));