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 "ntvfs/ntvfs.h"
31 #include "libcli/rap/rap.h"
32 #include "ntvfs/ipc/proto.h"
33 #include "rpc_server/dcerpc_server.h"
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 ntvfs_module_context *ntvfs;
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;
48 struct ntvfs_handle *handle;
49 struct dcesrv_connection *dce_conn;
56 find a open pipe give a file handle
58 static struct pipe_state *pipe_state_find(struct ipc_private *private, struct ntvfs_handle *handle)
63 p = ntvfs_handle_get_backend_data(handle, private->ntvfs);
66 s = talloc_get_type(p, struct pipe_state);
73 find a open pipe give a wire fnum
75 static struct pipe_state *pipe_state_find_key(struct ipc_private *private, struct ntvfs_request *req, const DATA_BLOB *key)
77 struct ntvfs_handle *h;
79 h = ntvfs_handle_search_by_wire_key(private->ntvfs, req, key);
82 return pipe_state_find(private, h);
87 connect to a share - always works
89 static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
90 struct ntvfs_request *req, const char *sharename)
93 struct ipc_private *private;
95 ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "IPC");
96 NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
98 ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "IPC");
99 NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
101 /* prepare the private state for this connection */
102 private = talloc(ntvfs, struct ipc_private);
103 NT_STATUS_HAVE_NO_MEMORY(private);
105 ntvfs->private_data = private;
107 private->ntvfs = ntvfs;
108 private->pipe_list = NULL;
110 /* setup the DCERPC server subsystem */
111 status = dcesrv_init_ipc_context(private, &private->dcesrv);
112 NT_STATUS_NOT_OK_RETURN(status);
118 disconnect from a share
120 static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs)
128 static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
129 struct ntvfs_request *req,
130 union smb_unlink *unl)
132 return NT_STATUS_ACCESS_DENIED;
137 ioctl interface - we don't do any
139 static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
140 struct ntvfs_request *req, union smb_ioctl *io)
142 return NT_STATUS_ACCESS_DENIED;
146 check if a directory exists
148 static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
149 struct ntvfs_request *req,
150 union smb_chkpath *cp)
152 return NT_STATUS_ACCESS_DENIED;
156 return info on a pathname
158 static NTSTATUS ipc_qpathinfo(struct ntvfs_module_context *ntvfs,
159 struct ntvfs_request *req, union smb_fileinfo *info)
161 return NT_STATUS_ACCESS_DENIED;
165 set info on a pathname
167 static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
168 struct ntvfs_request *req, union smb_setfileinfo *st)
170 return NT_STATUS_ACCESS_DENIED;
175 destroy a open pipe structure
177 static int ipc_fd_destructor(struct pipe_state *p)
179 DLIST_REMOVE(p->private->pipe_list, p);
183 static struct socket_address *ipc_get_my_addr(struct dcesrv_connection *dce_conn, TALLOC_CTX *mem_ctx)
185 struct ipc_private *private = dce_conn->transport.private_data;
187 return ntvfs_get_my_addr(private->ntvfs, mem_ctx);
190 static struct socket_address *ipc_get_peer_addr(struct dcesrv_connection *dce_conn, TALLOC_CTX *mem_ctx)
192 struct ipc_private *private = dce_conn->transport.private_data;
194 return ntvfs_get_peer_addr(private->ntvfs, mem_ctx);
198 open a file backend - used for MSRPC pipes
200 static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
201 struct ntvfs_request *req, const char *fname,
202 struct pipe_state **ps)
204 struct pipe_state *p;
206 struct dcerpc_binding *ep_description;
207 struct ipc_private *private = ntvfs->private_data;
208 struct ntvfs_handle *h;
210 status = ntvfs_handle_new(ntvfs, req, &h);
211 NT_STATUS_NOT_OK_RETURN(status);
213 p = talloc(h, struct pipe_state);
214 NT_STATUS_HAVE_NO_MEMORY(p);
216 ep_description = talloc(req, struct dcerpc_binding);
217 NT_STATUS_HAVE_NO_MEMORY(ep_description);
219 while (fname[0] == '\\') fname++;
221 p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
222 NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
225 p->ipc_state = 0x5ff;
228 we're all set, now ask the dcerpc server subsystem to open the
229 endpoint. At this stage the pipe isn't bound, so we don't
230 know what interface the user actually wants, just that they want
231 one of the interfaces attached to this pipe endpoint.
233 ep_description->transport = NCACN_NP;
234 ep_description->endpoint = talloc_reference(ep_description, p->pipe_name);
236 /* The session info is refcount-increased in the
237 * dcesrv_endpoint_search_connect() function
239 status = dcesrv_endpoint_search_connect(private->dcesrv,
243 ntvfs->ctx->event_ctx,
245 ntvfs->ctx->server_id,
248 NT_STATUS_NOT_OK_RETURN(status);
250 p->dce_conn->transport.private_data = private;
251 p->dce_conn->transport.report_output_data = NULL;
252 p->dce_conn->transport.get_my_addr = ipc_get_my_addr;
253 p->dce_conn->transport.get_peer_addr = ipc_get_peer_addr;
255 DLIST_ADD(private->pipe_list, p);
257 p->private = private;
259 talloc_set_destructor(p, ipc_fd_destructor);
261 status = ntvfs_handle_set_backend_data(h, private->ntvfs, p);
262 NT_STATUS_NOT_OK_RETURN(status);
269 open a file with ntcreatex - used for MSRPC pipes
271 static NTSTATUS ipc_open_ntcreatex(struct ntvfs_module_context *ntvfs,
272 struct ntvfs_request *req, union smb_open *oi)
274 struct pipe_state *p;
277 status = ipc_open_generic(ntvfs, req, oi->ntcreatex.in.fname, &p);
278 if (!NT_STATUS_IS_OK(status)) {
282 ZERO_STRUCT(oi->ntcreatex.out);
283 oi->ntcreatex.out.file.ntvfs= p->handle;
284 oi->ntcreatex.out.ipc_state = p->ipc_state;
285 oi->ntcreatex.out.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
291 open a file with openx - used for MSRPC pipes
293 static NTSTATUS ipc_open_openx(struct ntvfs_module_context *ntvfs,
294 struct ntvfs_request *req, union smb_open *oi)
296 struct pipe_state *p;
298 const char *fname = oi->openx.in.fname;
300 status = ipc_open_generic(ntvfs, req, fname, &p);
301 if (!NT_STATUS_IS_OK(status)) {
305 ZERO_STRUCT(oi->openx.out);
306 oi->openx.out.file.ntvfs= p->handle;
307 oi->openx.out.ftype = 2;
308 oi->openx.out.devstate = p->ipc_state;
314 open a file - used for MSRPC pipes
316 static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
317 struct ntvfs_request *req, union smb_open *oi)
321 switch (oi->generic.level) {
322 case RAW_OPEN_NTCREATEX:
323 status = ipc_open_ntcreatex(ntvfs, req, oi);
326 status = ipc_open_openx(ntvfs, req, oi);
329 status = NT_STATUS_NOT_SUPPORTED;
339 static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
340 struct ntvfs_request *req, union smb_mkdir *md)
342 return NT_STATUS_ACCESS_DENIED;
348 static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
349 struct ntvfs_request *req, struct smb_rmdir *rd)
351 return NT_STATUS_ACCESS_DENIED;
355 rename a set of files
357 static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
358 struct ntvfs_request *req, union smb_rename *ren)
360 return NT_STATUS_ACCESS_DENIED;
366 static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
367 struct ntvfs_request *req, struct smb_copy *cp)
369 return NT_STATUS_ACCESS_DENIED;
372 static NTSTATUS ipc_readx_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
374 DATA_BLOB *blob = private_data;
376 if (out->length < blob->length) {
377 blob->length = out->length;
379 memcpy(blob->data, out->data, blob->length);
380 *nwritten = blob->length;
387 static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
388 struct ntvfs_request *req, union smb_read *rd)
390 struct ipc_private *private = ntvfs->private_data;
392 struct pipe_state *p;
393 NTSTATUS status = NT_STATUS_OK;
395 if (rd->generic.level != RAW_READ_GENERIC) {
396 return ntvfs_map_read(ntvfs, req, rd);
399 p = pipe_state_find(private, rd->readx.in.file.ntvfs);
401 return NT_STATUS_INVALID_HANDLE;
404 data.length = rd->readx.in.maxcnt;
405 data.data = rd->readx.out.data;
406 if (data.length > UINT16_MAX) {
407 data.length = UINT16_MAX;
410 if (data.length != 0) {
411 status = dcesrv_output(p->dce_conn, &data, ipc_readx_dcesrv_output);
412 if (NT_STATUS_IS_ERR(status)) {
417 rd->readx.out.remaining = 0;
418 rd->readx.out.compaction_mode = 0;
419 rd->readx.out.nread = data.length;
427 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
428 struct ntvfs_request *req, union smb_write *wr)
430 struct ipc_private *private = ntvfs->private_data;
432 struct pipe_state *p;
435 if (wr->generic.level != RAW_WRITE_GENERIC) {
436 return ntvfs_map_write(ntvfs, req, wr);
439 data.data = discard_const_p(void, wr->writex.in.data);
440 data.length = wr->writex.in.count;
442 p = pipe_state_find(private, wr->writex.in.file.ntvfs);
444 return NT_STATUS_INVALID_HANDLE;
447 status = dcesrv_input(p->dce_conn, &data);
448 if (!NT_STATUS_IS_OK(status)) {
452 wr->writex.out.nwritten = data.length;
453 wr->writex.out.remaining = 0;
461 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
462 struct ntvfs_request *req,
465 return NT_STATUS_ACCESS_DENIED;
471 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
472 struct ntvfs_request *req,
475 return NT_STATUS_ACCESS_DENIED;
481 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
482 struct ntvfs_request *req, union smb_close *io)
484 struct ipc_private *private = ntvfs->private_data;
485 struct pipe_state *p;
487 if (io->generic.level != RAW_CLOSE_CLOSE) {
488 return ntvfs_map_close(ntvfs, req, io);
491 p = pipe_state_find(private, io->close.in.file.ntvfs);
493 return NT_STATUS_INVALID_HANDLE;
504 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
505 struct ntvfs_request *req)
507 struct ipc_private *private = ntvfs->private_data;
508 struct pipe_state *p, *next;
510 for (p=private->pipe_list; p; p=next) {
512 if (p->handle->session_info == req->session_info &&
513 p->handle->smbpid == req->smbpid) {
522 logoff - closing files open by the user
524 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
525 struct ntvfs_request *req)
527 struct ipc_private *private = ntvfs->private_data;
528 struct pipe_state *p, *next;
530 for (p=private->pipe_list; p; p=next) {
532 if (p->handle->session_info == req->session_info) {
541 setup for an async call
543 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
544 struct ntvfs_request *req,
553 static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
554 struct ntvfs_request *req)
556 return NT_STATUS_UNSUCCESSFUL;
562 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
563 struct ntvfs_request *req, union smb_lock *lck)
565 return NT_STATUS_ACCESS_DENIED;
569 set info on a open file
571 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
572 struct ntvfs_request *req, union smb_setfileinfo *info)
574 return NT_STATUS_ACCESS_DENIED;
578 query info on a open file
580 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
581 struct ntvfs_request *req, union smb_fileinfo *info)
583 return NT_STATUS_ACCESS_DENIED;
588 return filesystem info
590 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
591 struct ntvfs_request *req, union smb_fsinfo *fs)
593 return NT_STATUS_ACCESS_DENIED;
597 return print queue info
599 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
600 struct ntvfs_request *req, union smb_lpq *lpq)
602 return NT_STATUS_ACCESS_DENIED;
606 list files in a directory matching a wildcard pattern
608 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
609 struct ntvfs_request *req, union smb_search_first *io,
610 void *search_private,
611 BOOL (*callback)(void *, union smb_search_data *))
613 return NT_STATUS_ACCESS_DENIED;
617 continue listing files in a directory
619 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
620 struct ntvfs_request *req, union smb_search_next *io,
621 void *search_private,
622 BOOL (*callback)(void *, union smb_search_data *))
624 return NT_STATUS_ACCESS_DENIED;
628 end listing files in a directory
630 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
631 struct ntvfs_request *req, union smb_search_close *io)
633 return NT_STATUS_ACCESS_DENIED;
636 static NTSTATUS ipc_trans_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
638 NTSTATUS status = NT_STATUS_OK;
639 DATA_BLOB *blob = private_data;
641 if (out->length > blob->length) {
642 status = STATUS_BUFFER_OVERFLOW;
645 if (out->length < blob->length) {
646 blob->length = out->length;
648 memcpy(blob->data, out->data, blob->length);
649 *nwritten = blob->length;
653 /* SMBtrans - handle a DCERPC command */
654 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
655 struct ntvfs_request *req, struct smb_trans2 *trans)
657 struct pipe_state *p;
658 struct ipc_private *private = ntvfs->private_data;
664 * the fnum is in setup[1], a 16 bit value
665 * the setup[*] values are already in host byteorder
666 * but ntvfs_handle_search_by_wire_key() expects
669 SSVAL(&fnum, 0, trans->in.setup[1]);
670 fnum_key = data_blob_const(&fnum, 2);
672 p = pipe_state_find_key(private, req, &fnum_key);
674 return NT_STATUS_INVALID_HANDLE;
677 trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
678 if (!trans->out.data.data) {
679 return NT_STATUS_NO_MEMORY;
682 /* pass the data to the dcerpc server. Note that we don't
683 expect this to fail, and things like NDR faults are not
684 reported at this stage. Those sorts of errors happen in the
685 dcesrv_output stage */
686 status = dcesrv_input(p->dce_conn, &trans->in.data);
687 if (!NT_STATUS_IS_OK(status)) {
692 now ask the dcerpc system for some output. This doesn't yet handle
693 async calls. Again, we only expect NT_STATUS_OK. If the call fails then
694 the error is encoded at the dcerpc level
696 status = dcesrv_output(p->dce_conn, &trans->out.data, ipc_trans_dcesrv_output);
697 if (NT_STATUS_IS_ERR(status)) {
701 trans->out.setup_count = 0;
702 trans->out.setup = NULL;
703 trans->out.params = data_blob(NULL, 0);
709 /* SMBtrans - set named pipe state */
710 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
711 struct ntvfs_request *req, struct smb_trans2 *trans)
713 struct ipc_private *private = ntvfs->private_data;
714 struct pipe_state *p;
717 /* the fnum is in setup[1] */
718 fnum_key = data_blob_const(&trans->in.setup[1], sizeof(trans->in.setup[1]));
720 p = pipe_state_find_key(private, req, &fnum_key);
722 return NT_STATUS_INVALID_HANDLE;
725 if (trans->in.params.length != 2) {
726 return NT_STATUS_INVALID_PARAMETER;
728 p->ipc_state = SVAL(trans->in.params.data, 0);
730 trans->out.setup_count = 0;
731 trans->out.setup = NULL;
732 trans->out.params = data_blob(NULL, 0);
733 trans->out.data = data_blob(NULL, 0);
739 /* SMBtrans - used to provide access to SMB pipes */
740 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
741 struct ntvfs_request *req, struct smb_trans2 *trans)
745 if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
746 return ipc_rap_call(req, trans);
748 if (trans->in.setup_count != 2) {
749 return NT_STATUS_INVALID_PARAMETER;
752 switch (trans->in.setup[0]) {
753 case TRANSACT_SETNAMEDPIPEHANDLESTATE:
754 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
756 case TRANSACT_DCERPCCMD:
757 status = ipc_dcerpc_cmd(ntvfs, req, trans);
760 status = NT_STATUS_INVALID_PARAMETER;
770 initialialise the IPC backend, registering ourselves with the ntvfs subsystem
772 NTSTATUS ntvfs_ipc_init(void)
775 struct ntvfs_ops ops;
776 NTVFS_CURRENT_CRITICAL_SIZES(vers);
780 /* fill in the name and type */
781 ops.name = "default";
782 ops.type = NTVFS_IPC;
784 /* fill in all the operations */
785 ops.connect = ipc_connect;
786 ops.disconnect = ipc_disconnect;
787 ops.unlink = ipc_unlink;
788 ops.chkpath = ipc_chkpath;
789 ops.qpathinfo = ipc_qpathinfo;
790 ops.setpathinfo = ipc_setpathinfo;
792 ops.mkdir = ipc_mkdir;
793 ops.rmdir = ipc_rmdir;
794 ops.rename = ipc_rename;
796 ops.ioctl = ipc_ioctl;
798 ops.write = ipc_write;
800 ops.flush = ipc_flush;
801 ops.close = ipc_close;
804 ops.setfileinfo = ipc_setfileinfo;
805 ops.qfileinfo = ipc_qfileinfo;
806 ops.fsinfo = ipc_fsinfo;
808 ops.search_first = ipc_search_first;
809 ops.search_next = ipc_search_next;
810 ops.search_close = ipc_search_close;
811 ops.trans = ipc_trans;
812 ops.logoff = ipc_logoff;
813 ops.async_setup = ipc_async_setup;
814 ops.cancel = ipc_cancel;
816 /* register ourselves with the NTVFS subsystem. */
817 ret = ntvfs_register(&ops, &vers);
819 if (!NT_STATUS_IS_OK(ret)) {
820 DEBUG(0,("Failed to register IPC backend!\n"));