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 while (fname[0] == '\\') fname++;
197 p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
198 NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
200 fnum = idr_get_new_above(private->idtree_fnum, p, IPC_BASE_FNUM, UINT16_MAX);
202 return NT_STATUS_TOO_MANY_OPENED_FILES;
206 p->ipc_state = 0x5ff;
209 we're all set, now ask the dcerpc server subsystem to open the
210 endpoint. At this stage the pipe isn't bound, so we don't
211 know what interface the user actually wants, just that they want
212 one of the interfaces attached to this pipe endpoint.
214 ep_description.transport = NCACN_NP;
215 ep_description.endpoint = p->pipe_name;
217 /* The session info is refcount-increased in the
218 * dcesrv_endpoint_search_connect() function
220 status = dcesrv_endpoint_search_connect(private->dcesrv,
223 req->session->session_info,
226 if (!NT_STATUS_IS_OK(status)) {
227 idr_remove(private->idtree_fnum, p->fnum);
231 DLIST_ADD(private->pipe_list, p);
233 p->smbpid = req->smbpid;
234 p->session = req->session;
235 p->private = private;
239 talloc_steal(private, p);
241 talloc_set_destructor(p, ipc_fd_destructor);
247 open a file with ntcreatex - used for MSRPC pipes
249 static NTSTATUS ipc_open_ntcreatex(struct ntvfs_module_context *ntvfs,
250 struct smbsrv_request *req, union smb_open *oi)
252 struct pipe_state *p;
255 status = ipc_open_generic(ntvfs, req, oi->ntcreatex.in.fname, &p);
256 if (!NT_STATUS_IS_OK(status)) {
260 ZERO_STRUCT(oi->ntcreatex.out);
261 oi->ntcreatex.out.fnum = p->fnum;
262 oi->ntcreatex.out.ipc_state = p->ipc_state;
263 oi->ntcreatex.out.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
269 open a file with openx - used for MSRPC pipes
271 static NTSTATUS ipc_open_openx(struct ntvfs_module_context *ntvfs,
272 struct smbsrv_request *req, union smb_open *oi)
274 struct pipe_state *p;
276 const char *fname = oi->openx.in.fname;
278 status = ipc_open_generic(ntvfs, req, fname, &p);
279 if (!NT_STATUS_IS_OK(status)) {
283 ZERO_STRUCT(oi->openx.out);
284 oi->openx.out.fnum = p->fnum;
285 oi->openx.out.ftype = 2;
286 oi->openx.out.devstate = p->ipc_state;
292 open a file - used for MSRPC pipes
294 static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
295 struct smbsrv_request *req, union smb_open *oi)
299 switch (oi->generic.level) {
300 case RAW_OPEN_NTCREATEX:
301 status = ipc_open_ntcreatex(ntvfs, req, oi);
304 status = ipc_open_openx(ntvfs, req, oi);
307 status = NT_STATUS_NOT_SUPPORTED;
317 static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
318 struct smbsrv_request *req, union smb_mkdir *md)
320 return NT_STATUS_ACCESS_DENIED;
326 static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
327 struct smbsrv_request *req, struct smb_rmdir *rd)
329 return NT_STATUS_ACCESS_DENIED;
333 rename a set of files
335 static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
336 struct smbsrv_request *req, union smb_rename *ren)
338 return NT_STATUS_ACCESS_DENIED;
344 static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
345 struct smbsrv_request *req, struct smb_copy *cp)
347 return NT_STATUS_ACCESS_DENIED;
353 static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
354 struct smbsrv_request *req, union smb_read *rd)
356 struct ipc_private *private = ntvfs->private_data;
359 struct pipe_state *p;
362 if (rd->generic.level != RAW_READ_GENERIC) {
363 return ntvfs_map_read(req, rd, ntvfs);
366 fnum = rd->readx.in.fnum;
368 p = pipe_state_find(private, fnum);
370 return NT_STATUS_INVALID_HANDLE;
373 data.length = rd->readx.in.maxcnt;
374 data.data = rd->readx.out.data;
375 if (data.length > UINT16_MAX) {
379 if (data.length != 0) {
380 status = dcesrv_output_blob(p->dce_conn, &data);
381 if (NT_STATUS_IS_ERR(status)) {
386 rd->readx.out.remaining = 0;
387 rd->readx.out.compaction_mode = 0;
388 rd->readx.out.nread = data.length;
396 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
397 struct smbsrv_request *req, union smb_write *wr)
399 struct ipc_private *private = ntvfs->private_data;
402 struct pipe_state *p;
405 if (wr->generic.level != RAW_WRITE_GENERIC) {
406 return ntvfs_map_write(req, wr, ntvfs);
409 fnum = wr->writex.in.fnum;
410 data.data = discard_const_p(void, wr->writex.in.data);
411 data.length = wr->writex.in.count;
413 p = pipe_state_find(private, fnum);
415 return NT_STATUS_INVALID_HANDLE;
418 status = dcesrv_input(p->dce_conn, &data);
419 if (!NT_STATUS_IS_OK(status)) {
423 wr->writex.out.nwritten = data.length;
424 wr->writex.out.remaining = 0;
432 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
433 struct smbsrv_request *req, struct smb_seek *io)
435 return NT_STATUS_ACCESS_DENIED;
441 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
442 struct smbsrv_request *req, struct smb_flush *io)
444 return NT_STATUS_ACCESS_DENIED;
450 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
451 struct smbsrv_request *req, union smb_close *io)
453 struct ipc_private *private = ntvfs->private_data;
454 struct pipe_state *p;
456 if (io->generic.level != RAW_CLOSE_CLOSE) {
457 return ntvfs_map_close(req, io, ntvfs);
460 p = pipe_state_find(private, io->close.in.fnum);
462 return NT_STATUS_INVALID_HANDLE;
473 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
474 struct smbsrv_request *req)
476 struct ipc_private *private = ntvfs->private_data;
477 struct pipe_state *p, *next;
479 for (p=private->pipe_list; p; p=next) {
481 if (p->smbpid == req->smbpid) {
490 logoff - closing files open by the user
492 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
493 struct smbsrv_request *req)
495 struct ipc_private *private = ntvfs->private_data;
496 struct pipe_state *p, *next;
498 for (p=private->pipe_list; p; p=next) {
500 if (p->session == req->session) {
509 setup for an async call
511 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
512 struct smbsrv_request *req,
521 static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
522 struct smbsrv_request *req)
524 return NT_STATUS_UNSUCCESSFUL;
530 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
531 struct smbsrv_request *req, union smb_lock *lck)
533 return NT_STATUS_ACCESS_DENIED;
537 set info on a open file
539 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
540 struct smbsrv_request *req, union smb_setfileinfo *info)
542 return NT_STATUS_ACCESS_DENIED;
546 query info on a open file
548 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
549 struct smbsrv_request *req, union smb_fileinfo *info)
551 return NT_STATUS_ACCESS_DENIED;
556 return filesystem info
558 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
559 struct smbsrv_request *req, union smb_fsinfo *fs)
561 return NT_STATUS_ACCESS_DENIED;
565 return print queue info
567 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
568 struct smbsrv_request *req, union smb_lpq *lpq)
570 return NT_STATUS_ACCESS_DENIED;
574 list files in a directory matching a wildcard pattern
576 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
577 struct smbsrv_request *req, union smb_search_first *io,
578 void *search_private,
579 BOOL (*callback)(void *, union smb_search_data *))
581 return NT_STATUS_ACCESS_DENIED;
585 continue listing files in a directory
587 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
588 struct smbsrv_request *req, union smb_search_next *io,
589 void *search_private,
590 BOOL (*callback)(void *, union smb_search_data *))
592 return NT_STATUS_ACCESS_DENIED;
596 end listing files in a directory
598 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
599 struct smbsrv_request *req, union smb_search_close *io)
601 return NT_STATUS_ACCESS_DENIED;
605 /* SMBtrans - handle a DCERPC command */
606 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
607 struct smbsrv_request *req, struct smb_trans2 *trans)
609 struct pipe_state *p;
610 struct ipc_private *private = ntvfs->private_data;
613 /* the fnum is in setup[1] */
614 p = pipe_state_find(private, trans->in.setup[1]);
616 return NT_STATUS_INVALID_HANDLE;
619 trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
620 if (!trans->out.data.data) {
621 return NT_STATUS_NO_MEMORY;
624 /* pass the data to the dcerpc server. Note that we don't
625 expect this to fail, and things like NDR faults are not
626 reported at this stage. Those sorts of errors happen in the
627 dcesrv_output stage */
628 status = dcesrv_input(p->dce_conn, &trans->in.data);
629 if (!NT_STATUS_IS_OK(status)) {
634 now ask the dcerpc system for some output. This doesn't yet handle
635 async calls. Again, we only expect NT_STATUS_OK. If the call fails then
636 the error is encoded at the dcerpc level
638 status = dcesrv_output_blob(p->dce_conn, &trans->out.data);
639 if (NT_STATUS_IS_ERR(status)) {
643 trans->out.setup_count = 0;
644 trans->out.setup = NULL;
645 trans->out.params = data_blob(NULL, 0);
651 /* SMBtrans - set named pipe state */
652 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
653 struct smbsrv_request *req, struct smb_trans2 *trans)
655 struct ipc_private *private = ntvfs->private_data;
656 struct pipe_state *p;
658 /* the fnum is in setup[1] */
659 p = pipe_state_find(private, trans->in.setup[1]);
661 return NT_STATUS_INVALID_HANDLE;
664 if (trans->in.params.length != 2) {
665 return NT_STATUS_INVALID_PARAMETER;
667 p->ipc_state = SVAL(trans->in.params.data, 0);
669 trans->out.setup_count = 0;
670 trans->out.setup = NULL;
671 trans->out.params = data_blob(NULL, 0);
672 trans->out.data = data_blob(NULL, 0);
678 /* SMBtrans - used to provide access to SMB pipes */
679 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
680 struct smbsrv_request *req, struct smb_trans2 *trans)
684 if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
685 return ipc_rap_call(req, trans);
687 if (trans->in.setup_count != 2) {
688 return NT_STATUS_INVALID_PARAMETER;
691 switch (trans->in.setup[0]) {
692 case TRANSACT_SETNAMEDPIPEHANDLESTATE:
693 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
695 case TRANSACT_DCERPCCMD:
696 status = ipc_dcerpc_cmd(ntvfs, req, trans);
699 status = NT_STATUS_INVALID_PARAMETER;
709 initialialise the IPC backend, registering ourselves with the ntvfs subsystem
711 NTSTATUS ntvfs_ipc_init(void)
714 struct ntvfs_ops ops;
718 /* fill in the name and type */
719 ops.name = "default";
720 ops.type = NTVFS_IPC;
722 /* fill in all the operations */
723 ops.connect = ipc_connect;
724 ops.disconnect = ipc_disconnect;
725 ops.unlink = ipc_unlink;
726 ops.chkpath = ipc_chkpath;
727 ops.qpathinfo = ipc_qpathinfo;
728 ops.setpathinfo = ipc_setpathinfo;
729 ops.openfile = ipc_open;
730 ops.mkdir = ipc_mkdir;
731 ops.rmdir = ipc_rmdir;
732 ops.rename = ipc_rename;
734 ops.ioctl = ipc_ioctl;
736 ops.write = ipc_write;
738 ops.flush = ipc_flush;
739 ops.close = ipc_close;
742 ops.setfileinfo = ipc_setfileinfo;
743 ops.qfileinfo = ipc_qfileinfo;
744 ops.fsinfo = ipc_fsinfo;
746 ops.search_first = ipc_search_first;
747 ops.search_next = ipc_search_next;
748 ops.search_close = ipc_search_close;
749 ops.trans = ipc_trans;
750 ops.logoff = ipc_logoff;
751 ops.async_setup = ipc_async_setup;
752 ops.cancel = ipc_cancel;
754 /* register ourselves with the NTVFS subsystem. */
755 ret = ntvfs_register(&ops);
757 if (!NT_STATUS_IS_OK(ret)) {
758 DEBUG(0,("Failed to register IPC backend!\n"));