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 "rpc_server/dcerpc_server.h"
34 #define IPC_BASE_FNUM 0x400
36 /* this is the private structure used to keep the state of an open
37 ipc$ connection. It needs to keep information about all open
40 struct idr_context *idtree_fnum;
42 struct dcesrv_context *dcesrv;
44 /* a list of open pipes */
46 struct pipe_state *next, *prev;
47 struct ipc_private *private;
48 const char *pipe_name;
50 struct dcesrv_connection *dce_conn;
52 /* we need to remember the session it was opened on,
53 as it is illegal to operate on someone elses fnum */
54 struct smbsrv_session *session;
56 /* we need to remember the client pid that
57 opened the file so SMBexit works */
65 find a open pipe give a file descriptor
67 static struct pipe_state *pipe_state_find(struct ipc_private *private, uint16_t fnum)
69 return idr_find(private->idtree_fnum, fnum);
74 connect to a share - always works
76 static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
77 struct smbsrv_request *req, const char *sharename)
80 struct smbsrv_tcon *tcon = req->tcon;
81 struct ipc_private *private;
83 tcon->fs_type = talloc_strdup(tcon, "IPC");
84 NT_STATUS_HAVE_NO_MEMORY(tcon->fs_type);
86 tcon->dev_type = talloc_strdup(tcon, "IPC");
87 NT_STATUS_HAVE_NO_MEMORY(tcon->dev_type);
89 /* prepare the private state for this connection */
90 private = talloc(ntvfs, struct ipc_private);
91 NT_STATUS_HAVE_NO_MEMORY(private);
93 ntvfs->private_data = private;
95 private->pipe_list = NULL;
97 private->idtree_fnum = idr_init(private);
98 NT_STATUS_HAVE_NO_MEMORY(private->idtree_fnum);
100 /* setup the DCERPC server subsystem */
101 status = dcesrv_init_ipc_context(private, &private->dcesrv);
102 NT_STATUS_NOT_OK_RETURN(status);
108 disconnect from a share
110 static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs,
111 struct smbsrv_tcon *tcon)
119 static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
120 struct smbsrv_request *req, struct smb_unlink *unl)
122 return NT_STATUS_ACCESS_DENIED;
127 ioctl interface - we don't do any
129 static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
130 struct smbsrv_request *req, union smb_ioctl *io)
132 return NT_STATUS_ACCESS_DENIED;
136 check if a directory exists
138 static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
139 struct smbsrv_request *req, struct smb_chkpath *cp)
141 return NT_STATUS_ACCESS_DENIED;
145 return info on a pathname
147 static NTSTATUS ipc_qpathinfo(struct ntvfs_module_context *ntvfs,
148 struct smbsrv_request *req, union smb_fileinfo *info)
150 return NT_STATUS_ACCESS_DENIED;
154 set info on a pathname
156 static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
157 struct smbsrv_request *req, union smb_setfileinfo *st)
159 return NT_STATUS_ACCESS_DENIED;
164 destroy a open pipe structure
166 static int ipc_fd_destructor(void *ptr)
168 struct pipe_state *p = ptr;
169 idr_remove(p->private->idtree_fnum, p->fnum);
170 DLIST_REMOVE(p->private->pipe_list, p);
176 open a file backend - used for MSRPC pipes
178 static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
179 struct smbsrv_request *req, const char *fname,
180 struct pipe_state **ps)
182 struct pipe_state *p;
184 struct dcerpc_binding *ep_description;
185 struct ipc_private *private = ntvfs->private_data;
187 struct stream_connection *srv_conn = req->smb_conn->connection;
189 if (!req->session || !req->session->session_info) {
190 return NT_STATUS_ACCESS_DENIED;
193 p = talloc(req, struct pipe_state);
194 NT_STATUS_HAVE_NO_MEMORY(p);
196 ep_description = talloc(req, struct dcerpc_binding);
197 NT_STATUS_HAVE_NO_MEMORY(ep_description);
199 while (fname[0] == '\\') fname++;
201 p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
202 NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
204 fnum = idr_get_new_above(private->idtree_fnum, p, IPC_BASE_FNUM, UINT16_MAX);
206 return NT_STATUS_TOO_MANY_OPENED_FILES;
210 p->ipc_state = 0x5ff;
213 we're all set, now ask the dcerpc server subsystem to open the
214 endpoint. At this stage the pipe isn't bound, so we don't
215 know what interface the user actually wants, just that they want
216 one of the interfaces attached to this pipe endpoint.
218 ep_description->transport = NCACN_NP;
219 ep_description->endpoint = talloc_reference(ep_description, p->pipe_name);
221 /* The session info is refcount-increased in the
222 * dcesrv_endpoint_search_connect() function
224 status = dcesrv_endpoint_search_connect(private->dcesrv,
227 req->session->session_info,
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;
267 oi->ntcreatex.out.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
273 open a file with openx - used for MSRPC pipes
275 static NTSTATUS ipc_open_openx(struct ntvfs_module_context *ntvfs,
276 struct smbsrv_request *req, union smb_open *oi)
278 struct pipe_state *p;
280 const char *fname = oi->openx.in.fname;
282 status = ipc_open_generic(ntvfs, req, fname, &p);
283 if (!NT_STATUS_IS_OK(status)) {
287 ZERO_STRUCT(oi->openx.out);
288 oi->openx.out.fnum = p->fnum;
289 oi->openx.out.ftype = 2;
290 oi->openx.out.devstate = p->ipc_state;
296 open a file - used for MSRPC pipes
298 static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
299 struct smbsrv_request *req, union smb_open *oi)
303 switch (oi->generic.level) {
304 case RAW_OPEN_NTCREATEX:
305 status = ipc_open_ntcreatex(ntvfs, req, oi);
308 status = ipc_open_openx(ntvfs, req, oi);
311 status = NT_STATUS_NOT_SUPPORTED;
321 static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
322 struct smbsrv_request *req, union smb_mkdir *md)
324 return NT_STATUS_ACCESS_DENIED;
330 static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
331 struct smbsrv_request *req, struct smb_rmdir *rd)
333 return NT_STATUS_ACCESS_DENIED;
337 rename a set of files
339 static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
340 struct smbsrv_request *req, union smb_rename *ren)
342 return NT_STATUS_ACCESS_DENIED;
348 static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
349 struct smbsrv_request *req, struct smb_copy *cp)
351 return NT_STATUS_ACCESS_DENIED;
354 static NTSTATUS ipc_readx_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
356 DATA_BLOB *blob = private_data;
358 if (out->length < blob->length) {
359 blob->length = out->length;
361 memcpy(blob->data, out->data, blob->length);
362 *nwritten = blob->length;
369 static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
370 struct smbsrv_request *req, union smb_read *rd)
372 struct ipc_private *private = ntvfs->private_data;
375 struct pipe_state *p;
376 NTSTATUS status = NT_STATUS_OK;
378 if (rd->generic.level != RAW_READ_GENERIC) {
379 return ntvfs_map_read(req, rd, ntvfs);
382 fnum = rd->readx.in.fnum;
384 p = pipe_state_find(private, fnum);
386 return NT_STATUS_INVALID_HANDLE;
389 data.length = rd->readx.in.maxcnt;
390 data.data = rd->readx.out.data;
391 if (data.length > UINT16_MAX) {
392 data.length = UINT16_MAX;
395 if (data.length != 0) {
396 status = dcesrv_output(p->dce_conn, &data, ipc_readx_dcesrv_output);
397 if (NT_STATUS_IS_ERR(status)) {
402 rd->readx.out.remaining = 0;
403 rd->readx.out.compaction_mode = 0;
404 rd->readx.out.nread = data.length;
412 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
413 struct smbsrv_request *req, union smb_write *wr)
415 struct ipc_private *private = ntvfs->private_data;
418 struct pipe_state *p;
421 if (wr->generic.level != RAW_WRITE_GENERIC) {
422 return ntvfs_map_write(req, wr, ntvfs);
425 fnum = wr->writex.in.fnum;
426 data.data = discard_const_p(void, wr->writex.in.data);
427 data.length = wr->writex.in.count;
429 p = pipe_state_find(private, fnum);
431 return NT_STATUS_INVALID_HANDLE;
434 status = dcesrv_input(p->dce_conn, &data);
435 if (!NT_STATUS_IS_OK(status)) {
439 wr->writex.out.nwritten = data.length;
440 wr->writex.out.remaining = 0;
448 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
449 struct smbsrv_request *req, struct smb_seek *io)
451 return NT_STATUS_ACCESS_DENIED;
457 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
458 struct smbsrv_request *req, struct smb_flush *io)
460 return NT_STATUS_ACCESS_DENIED;
466 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
467 struct smbsrv_request *req, union smb_close *io)
469 struct ipc_private *private = ntvfs->private_data;
470 struct pipe_state *p;
472 if (io->generic.level != RAW_CLOSE_CLOSE) {
473 return ntvfs_map_close(req, io, ntvfs);
476 p = pipe_state_find(private, io->close.in.fnum);
478 return NT_STATUS_INVALID_HANDLE;
489 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
490 struct smbsrv_request *req)
492 struct ipc_private *private = ntvfs->private_data;
493 struct pipe_state *p, *next;
495 for (p=private->pipe_list; p; p=next) {
497 if (p->smbpid == req->smbpid) {
506 logoff - closing files open by the user
508 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
509 struct smbsrv_request *req)
511 struct ipc_private *private = ntvfs->private_data;
512 struct pipe_state *p, *next;
514 for (p=private->pipe_list; p; p=next) {
516 if (p->session == req->session) {
525 setup for an async call
527 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
528 struct smbsrv_request *req,
537 static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
538 struct smbsrv_request *req)
540 return NT_STATUS_UNSUCCESSFUL;
546 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
547 struct smbsrv_request *req, union smb_lock *lck)
549 return NT_STATUS_ACCESS_DENIED;
553 set info on a open file
555 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
556 struct smbsrv_request *req, union smb_setfileinfo *info)
558 return NT_STATUS_ACCESS_DENIED;
562 query info on a open file
564 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
565 struct smbsrv_request *req, union smb_fileinfo *info)
567 return NT_STATUS_ACCESS_DENIED;
572 return filesystem info
574 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
575 struct smbsrv_request *req, union smb_fsinfo *fs)
577 return NT_STATUS_ACCESS_DENIED;
581 return print queue info
583 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
584 struct smbsrv_request *req, union smb_lpq *lpq)
586 return NT_STATUS_ACCESS_DENIED;
590 list files in a directory matching a wildcard pattern
592 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
593 struct smbsrv_request *req, union smb_search_first *io,
594 void *search_private,
595 BOOL (*callback)(void *, union smb_search_data *))
597 return NT_STATUS_ACCESS_DENIED;
601 continue listing files in a directory
603 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
604 struct smbsrv_request *req, union smb_search_next *io,
605 void *search_private,
606 BOOL (*callback)(void *, union smb_search_data *))
608 return NT_STATUS_ACCESS_DENIED;
612 end listing files in a directory
614 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
615 struct smbsrv_request *req, union smb_search_close *io)
617 return NT_STATUS_ACCESS_DENIED;
620 static NTSTATUS ipc_trans_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
622 NTSTATUS status = NT_STATUS_OK;
623 DATA_BLOB *blob = private_data;
625 if (out->length > blob->length) {
626 status = STATUS_BUFFER_OVERFLOW;
629 if (out->length < blob->length) {
630 blob->length = out->length;
632 memcpy(blob->data, out->data, blob->length);
633 *nwritten = blob->length;
637 /* SMBtrans - handle a DCERPC command */
638 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
639 struct smbsrv_request *req, struct smb_trans2 *trans)
641 struct pipe_state *p;
642 struct ipc_private *private = ntvfs->private_data;
645 /* the fnum is in setup[1] */
646 p = pipe_state_find(private, trans->in.setup[1]);
648 return NT_STATUS_INVALID_HANDLE;
651 trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
652 if (!trans->out.data.data) {
653 return NT_STATUS_NO_MEMORY;
656 /* pass the data to the dcerpc server. Note that we don't
657 expect this to fail, and things like NDR faults are not
658 reported at this stage. Those sorts of errors happen in the
659 dcesrv_output stage */
660 status = dcesrv_input(p->dce_conn, &trans->in.data);
661 if (!NT_STATUS_IS_OK(status)) {
666 now ask the dcerpc system for some output. This doesn't yet handle
667 async calls. Again, we only expect NT_STATUS_OK. If the call fails then
668 the error is encoded at the dcerpc level
670 status = dcesrv_output(p->dce_conn, &trans->out.data, ipc_trans_dcesrv_output);
671 if (NT_STATUS_IS_ERR(status)) {
675 trans->out.setup_count = 0;
676 trans->out.setup = NULL;
677 trans->out.params = data_blob(NULL, 0);
683 /* SMBtrans - set named pipe state */
684 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
685 struct smbsrv_request *req, struct smb_trans2 *trans)
687 struct ipc_private *private = ntvfs->private_data;
688 struct pipe_state *p;
690 /* the fnum is in setup[1] */
691 p = pipe_state_find(private, trans->in.setup[1]);
693 return NT_STATUS_INVALID_HANDLE;
696 if (trans->in.params.length != 2) {
697 return NT_STATUS_INVALID_PARAMETER;
699 p->ipc_state = SVAL(trans->in.params.data, 0);
701 trans->out.setup_count = 0;
702 trans->out.setup = NULL;
703 trans->out.params = data_blob(NULL, 0);
704 trans->out.data = data_blob(NULL, 0);
710 /* SMBtrans - used to provide access to SMB pipes */
711 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
712 struct smbsrv_request *req, struct smb_trans2 *trans)
716 if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
717 return ipc_rap_call(req, trans);
719 if (trans->in.setup_count != 2) {
720 return NT_STATUS_INVALID_PARAMETER;
723 switch (trans->in.setup[0]) {
724 case TRANSACT_SETNAMEDPIPEHANDLESTATE:
725 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
727 case TRANSACT_DCERPCCMD:
728 status = ipc_dcerpc_cmd(ntvfs, req, trans);
731 status = NT_STATUS_INVALID_PARAMETER;
741 initialialise the IPC backend, registering ourselves with the ntvfs subsystem
743 NTSTATUS ntvfs_ipc_init(void)
746 struct ntvfs_ops ops;
750 /* fill in the name and type */
751 ops.name = "default";
752 ops.type = NTVFS_IPC;
754 /* fill in all the operations */
755 ops.connect = ipc_connect;
756 ops.disconnect = ipc_disconnect;
757 ops.unlink = ipc_unlink;
758 ops.chkpath = ipc_chkpath;
759 ops.qpathinfo = ipc_qpathinfo;
760 ops.setpathinfo = ipc_setpathinfo;
761 ops.openfile = ipc_open;
762 ops.mkdir = ipc_mkdir;
763 ops.rmdir = ipc_rmdir;
764 ops.rename = ipc_rename;
766 ops.ioctl = ipc_ioctl;
768 ops.write = ipc_write;
770 ops.flush = ipc_flush;
771 ops.close = ipc_close;
774 ops.setfileinfo = ipc_setfileinfo;
775 ops.qfileinfo = ipc_qfileinfo;
776 ops.fsinfo = ipc_fsinfo;
778 ops.search_first = ipc_search_first;
779 ops.search_next = ipc_search_next;
780 ops.search_close = ipc_search_close;
781 ops.trans = ipc_trans;
782 ops.logoff = ipc_logoff;
783 ops.async_setup = ipc_async_setup;
784 ops.cancel = ipc_cancel;
786 /* register ourselves with the NTVFS subsystem. */
787 ret = ntvfs_register(&ops);
789 if (!NT_STATUS_IS_OK(ret)) {
790 DEBUG(0,("Failed to register IPC backend!\n"));