2 Unix SMB/CIFS implementation.
3 default IPC$ NTVFS backend
5 Copyright (C) Andrew Tridgell 2003
6 Copyright (C) Stefan (metze) Metzmacher 2004
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"
32 /* this is the private structure used to keep the state of an open
33 ipc$ connection. It needs to keep information about all open
36 struct idr_context *idtree_fnum;
38 /* a list of open pipes */
40 struct pipe_state *next, *prev;
41 struct ipc_private *private;
42 const char *pipe_name;
44 struct dcesrv_connection *dce_conn;
46 /* we need to remember the session it was opened on,
47 as it is illegal to operate on someone elses fnum */
48 struct smbsrv_session *session;
50 /* we need to remember the client pid that
51 opened the file so SMBexit works */
59 find a open pipe give a file descriptor
61 static struct pipe_state *pipe_state_find(struct ipc_private *private, uint16_t fnum)
63 return idr_find(private->idtree_fnum, fnum);
68 connect to a share - always works
70 static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
71 struct smbsrv_request *req, const char *sharename)
73 struct smbsrv_tcon *tcon = req->tcon;
74 struct ipc_private *private;
76 tcon->fs_type = talloc_strdup(tcon, "IPC");
77 tcon->dev_type = talloc_strdup(tcon, "IPC");
79 /* prepare the private state for this connection */
80 private = talloc_p(tcon, struct ipc_private);
82 return NT_STATUS_NO_MEMORY;
84 ntvfs->private_data = private;
86 private->pipe_list = NULL;
88 private->idtree_fnum = idr_init(private);
89 if (private->idtree_fnum == NULL) {
90 return NT_STATUS_NO_MEMORY;
97 disconnect from a share
99 static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs,
100 struct smbsrv_tcon *tcon)
102 struct ipc_private *private = ntvfs->private_data;
104 /* close any pipes that are open. Discard any unread data */
105 while (private->pipe_list) {
106 talloc_free(private->pipe_list);
115 static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
116 struct smbsrv_request *req, struct smb_unlink *unl)
118 return NT_STATUS_ACCESS_DENIED;
123 ioctl interface - we don't do any
125 static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
126 struct smbsrv_request *req, union smb_ioctl *io)
128 return NT_STATUS_ACCESS_DENIED;
132 check if a directory exists
134 static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
135 struct smbsrv_request *req, struct smb_chkpath *cp)
137 return NT_STATUS_ACCESS_DENIED;
141 return info on a pathname
143 static NTSTATUS ipc_qpathinfo(struct ntvfs_module_context *ntvfs,
144 struct smbsrv_request *req, union smb_fileinfo *info)
146 return NT_STATUS_ACCESS_DENIED;
150 set info on a pathname
152 static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
153 struct smbsrv_request *req, union smb_setfileinfo *st)
155 return NT_STATUS_ACCESS_DENIED;
160 destroy a open pipe structure
162 static int ipc_fd_destructor(void *ptr)
164 struct pipe_state *p = ptr;
165 idr_remove(p->private->idtree_fnum, p->fnum);
166 DLIST_REMOVE(p->private->pipe_list, p);
167 talloc_free(p->dce_conn);
173 open a file backend - used for MSRPC pipes
175 static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
176 struct smbsrv_request *req, const char *fname,
177 struct pipe_state **ps)
179 struct pipe_state *p;
181 struct dcerpc_binding ep_description;
182 struct auth_session_info *session_info = NULL;
183 struct ipc_private *private = ntvfs->private_data;
186 p = talloc_p(req, struct pipe_state);
188 return NT_STATUS_NO_MEMORY;
191 while (fname[0] == '\\') fname++;
193 p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
195 return NT_STATUS_NO_MEMORY;
198 fnum = idr_get_new(private->idtree_fnum, p, UINT16_MAX);
200 return NT_STATUS_TOO_MANY_OPENED_FILES;
204 p->ipc_state = 0x5ff;
207 we're all set, now ask the dcerpc server subsystem to open the
208 endpoint. At this stage the pipe isn't bound, so we don't
209 know what interface the user actually wants, just that they want
210 one of the interfaces attached to this pipe endpoint.
212 TODO: note that we aren't passing any credentials here. We
213 will need to do that once the credentials infrastructure is
216 ep_description.transport = NCACN_NP;
217 ep_description.endpoint = p->pipe_name;
219 /* tell the RPC layer the session_info */
221 /* The session info is refcount-increased in the
222 dcesrv_endpoint_search_connect() function */
223 session_info = req->session->session_info;
226 status = dcesrv_endpoint_search_connect(req->smb_conn->dcesrv,
230 if (!NT_STATUS_IS_OK(status)) {
231 idr_remove(private->idtree_fnum, p->fnum);
235 DLIST_ADD(private->pipe_list, p);
237 p->smbpid = req->smbpid;
238 p->session = req->session;
239 p->private = private;
243 talloc_steal(private, p);
245 talloc_set_destructor(p, ipc_fd_destructor);
251 open a file with ntcreatex - used for MSRPC pipes
253 static NTSTATUS ipc_open_ntcreatex(struct ntvfs_module_context *ntvfs,
254 struct smbsrv_request *req, union smb_open *oi)
256 struct pipe_state *p;
259 status = ipc_open_generic(ntvfs, req, oi->ntcreatex.in.fname, &p);
260 if (!NT_STATUS_IS_OK(status)) {
264 ZERO_STRUCT(oi->ntcreatex.out);
265 oi->ntcreatex.out.fnum = p->fnum;
266 oi->ntcreatex.out.ipc_state = p->ipc_state;
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_lock(struct ntvfs_module_context *ntvfs,
525 struct smbsrv_request *req, union smb_lock *lck)
527 return NT_STATUS_ACCESS_DENIED;
531 set info on a open file
533 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
534 struct smbsrv_request *req, union smb_setfileinfo *info)
536 return NT_STATUS_ACCESS_DENIED;
540 query info on a open file
542 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
543 struct smbsrv_request *req, union smb_fileinfo *info)
545 return NT_STATUS_ACCESS_DENIED;
550 return filesystem info
552 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
553 struct smbsrv_request *req, union smb_fsinfo *fs)
555 return NT_STATUS_ACCESS_DENIED;
559 return print queue info
561 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
562 struct smbsrv_request *req, union smb_lpq *lpq)
564 return NT_STATUS_ACCESS_DENIED;
568 list files in a directory matching a wildcard pattern
570 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
571 struct smbsrv_request *req, union smb_search_first *io,
572 void *search_private,
573 BOOL (*callback)(void *, union smb_search_data *))
575 return NT_STATUS_ACCESS_DENIED;
579 continue listing files in a directory
581 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
582 struct smbsrv_request *req, union smb_search_next *io,
583 void *search_private,
584 BOOL (*callback)(void *, union smb_search_data *))
586 return NT_STATUS_ACCESS_DENIED;
590 end listing files in a directory
592 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
593 struct smbsrv_request *req, union smb_search_close *io)
595 return NT_STATUS_ACCESS_DENIED;
599 /* SMBtrans - handle a DCERPC command */
600 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
601 struct smbsrv_request *req, struct smb_trans2 *trans)
603 struct pipe_state *p;
604 struct ipc_private *private = ntvfs->private_data;
607 /* the fnum is in setup[1] */
608 p = pipe_state_find(private, trans->in.setup[1]);
610 return NT_STATUS_INVALID_HANDLE;
613 trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
614 if (!trans->out.data.data) {
615 return NT_STATUS_NO_MEMORY;
618 /* pass the data to the dcerpc server. Note that we don't
619 expect this to fail, and things like NDR faults are not
620 reported at this stage. Those sorts of errors happen in the
621 dcesrv_output stage */
622 status = dcesrv_input(p->dce_conn, &trans->in.data);
623 if (!NT_STATUS_IS_OK(status)) {
628 now ask the dcerpc system for some output. This doesn't yet handle
629 async calls. Again, we only expect NT_STATUS_OK. If the call fails then
630 the error is encoded at the dcerpc level
632 status = dcesrv_output_blob(p->dce_conn, &trans->out.data);
633 if (NT_STATUS_IS_ERR(status)) {
637 trans->out.setup_count = 0;
638 trans->out.setup = NULL;
639 trans->out.params = data_blob(NULL, 0);
645 /* SMBtrans - set named pipe state */
646 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
647 struct smbsrv_request *req, struct smb_trans2 *trans)
649 struct ipc_private *private = ntvfs->private_data;
650 struct pipe_state *p;
652 /* the fnum is in setup[1] */
653 p = pipe_state_find(private, trans->in.setup[1]);
655 return NT_STATUS_INVALID_HANDLE;
658 if (trans->in.params.length != 2) {
659 return NT_STATUS_INVALID_PARAMETER;
661 p->ipc_state = SVAL(trans->in.params.data, 0);
663 trans->out.setup_count = 0;
664 trans->out.setup = NULL;
665 trans->out.params = data_blob(NULL, 0);
666 trans->out.data = data_blob(NULL, 0);
672 /* SMBtrans - used to provide access to SMB pipes */
673 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
674 struct smbsrv_request *req, struct smb_trans2 *trans)
678 if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
679 return ipc_rap_call(req, trans);
681 if (trans->in.setup_count != 2) {
682 return NT_STATUS_INVALID_PARAMETER;
685 switch (trans->in.setup[0]) {
686 case TRANSACT_SETNAMEDPIPEHANDLESTATE:
687 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
689 case TRANSACT_DCERPCCMD:
690 status = ipc_dcerpc_cmd(ntvfs, req, trans);
693 status = NT_STATUS_INVALID_PARAMETER;
703 initialialise the IPC backend, registering ourselves with the ntvfs subsystem
705 NTSTATUS ntvfs_ipc_init(void)
708 struct ntvfs_ops ops;
712 /* fill in the name and type */
713 ops.name = "default";
714 ops.type = NTVFS_IPC;
716 /* fill in all the operations */
717 ops.connect = ipc_connect;
718 ops.disconnect = ipc_disconnect;
719 ops.unlink = ipc_unlink;
720 ops.chkpath = ipc_chkpath;
721 ops.qpathinfo = ipc_qpathinfo;
722 ops.setpathinfo = ipc_setpathinfo;
723 ops.openfile = ipc_open;
724 ops.mkdir = ipc_mkdir;
725 ops.rmdir = ipc_rmdir;
726 ops.rename = ipc_rename;
728 ops.ioctl = ipc_ioctl;
730 ops.write = ipc_write;
732 ops.flush = ipc_flush;
733 ops.close = ipc_close;
736 ops.setfileinfo = ipc_setfileinfo;
737 ops.qfileinfo = ipc_qfileinfo;
738 ops.fsinfo = ipc_fsinfo;
740 ops.search_first = ipc_search_first;
741 ops.search_next = ipc_search_next;
742 ops.search_close = ipc_search_close;
743 ops.trans = ipc_trans;
744 ops.logoff = ipc_logoff;
745 ops.async_setup = ipc_async_setup;
747 /* register ourselves with the NTVFS subsystem. */
748 ret = register_backend("ntvfs", &ops);
750 if (!NT_STATUS_IS_OK(ret)) {
751 DEBUG(0,("Failed to register IPC backend!\n"));