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
30 /* this is the private structure used to keep the state of an open
31 ipc$ connection. It needs to keep information about all open
38 /* a list of open pipes */
40 struct pipe_state *next, *prev;
42 const char *pipe_name;
44 struct dcesrv_connection *dce_conn;
52 find the next fnum available on this connection
54 static uint16_t find_next_fnum(struct ipc_private *ipc)
59 if (ipc->num_open == 0xFFFF) {
64 ret = ipc->next_fnum++;
66 for (p=ipc->pipe_list; p; p=p->next) {
77 shutdown a single pipe. Called on a close or disconnect
79 static void pipe_shutdown(struct ipc_private *private, struct pipe_state *p)
81 TALLOC_CTX *mem_ctx = private->pipe_list->mem_ctx;
82 dcesrv_endpoint_disconnect(private->pipe_list->dce_conn);
83 DLIST_REMOVE(private->pipe_list, private->pipe_list);
84 talloc_destroy(mem_ctx);
89 find a open pipe give a file descriptor
91 static struct pipe_state *pipe_state_find(struct ipc_private *private, uint16_t fnum)
95 for (p=private->pipe_list; p; p=p->next) {
96 if (p->fnum == fnum) {
106 connect to a share - always works
108 static NTSTATUS ipc_connect(struct request_context *req, const char *sharename)
110 struct tcon_context *conn = req->conn;
111 struct ipc_private *private;
113 conn->fs_type = talloc_strdup(conn->mem_ctx, "IPC");
114 conn->dev_type = talloc_strdup(conn->mem_ctx, "IPC");
116 /* prepare the private state for this connection */
117 private = talloc(conn->mem_ctx, sizeof(struct ipc_private));
119 return NT_STATUS_NO_MEMORY;
121 conn->ntvfs_private = (void *)private;
123 private->pipe_list = NULL;
124 private->next_fnum = 1;
125 private->num_open = 0;
131 disconnect from a share
133 static NTSTATUS ipc_disconnect(struct tcon_context *tcon)
135 struct ipc_private *private = tcon->ntvfs_private;
137 /* close any pipes that are open. Discard any unread data */
138 while (private->pipe_list) {
139 pipe_shutdown(private, private->pipe_list);
148 static NTSTATUS ipc_unlink(struct request_context *req, struct smb_unlink *unl)
150 return NT_STATUS_ACCESS_DENIED;
155 ioctl interface - we don't do any
157 static NTSTATUS ipc_ioctl(struct request_context *req, union smb_ioctl *io)
159 return NT_STATUS_ACCESS_DENIED;
163 check if a directory exists
165 static NTSTATUS ipc_chkpath(struct request_context *req, struct smb_chkpath *cp)
167 return NT_STATUS_ACCESS_DENIED;
171 return info on a pathname
173 static NTSTATUS ipc_qpathinfo(struct request_context *req, union smb_fileinfo *info)
175 return NT_STATUS_ACCESS_DENIED;
179 set info on a pathname
181 static NTSTATUS ipc_setpathinfo(struct request_context *req, union smb_setfileinfo *st)
183 return NT_STATUS_ACCESS_DENIED;
189 open a file backend - used for MSRPC pipes
191 static NTSTATUS ipc_open_generic(struct request_context *req, const char *fname,
192 struct pipe_state **ps)
194 struct pipe_state *p;
197 struct dcesrv_ep_description ep_description;
198 struct ipc_private *private = req->conn->ntvfs_private;
200 mem_ctx = talloc_init("ipc_open '%s'", fname);
202 return NT_STATUS_NO_MEMORY;
205 p = talloc(mem_ctx, sizeof(struct pipe_state));
207 talloc_destroy(mem_ctx);
208 return NT_STATUS_NO_MEMORY;
210 p->mem_ctx = mem_ctx;
212 p->pipe_name = talloc_strdup(mem_ctx, fname);
214 talloc_destroy(mem_ctx);
215 return NT_STATUS_NO_MEMORY;
218 p->fnum = find_next_fnum(private);
220 talloc_destroy(mem_ctx);
221 return NT_STATUS_TOO_MANY_OPENED_FILES;
224 while (p->pipe_name[0] == '\\') {
227 p->ipc_state = 0x5ff;
230 we're all set, now ask the dcerpc server subsystem to open the
231 endpoint. At this stage the pipe isn't bound, so we don't
232 know what interface the user actually wants, just that they want
233 one of the interfaces attached to this pipe endpoint.
235 TODO: note that we aren't passing any credentials here. We
236 will need to do that once the credentials infrastructure is
240 ep_description.type = ENDPOINT_SMB;
241 ep_description.info.smb_pipe = p->pipe_name;
243 status = dcesrv_endpoint_search_connect(&req->smb->dcesrv, &ep_description, &p->dce_conn);
244 if (!NT_STATUS_IS_OK(status)) {
245 talloc_destroy(mem_ctx);
251 DLIST_ADD(private->pipe_list, p);
255 /* tell the RPC layer the transport session key */
256 if (req->user_ctx->vuser) {
257 /* TODO: Fix this to push more than just a session key
258 * down - we need the entire session_info, reference counted... */
259 dcesrv_set_session_key(p->dce_conn, req->user_ctx->vuser->session_info->session_key);
266 open a file with ntcreatex - used for MSRPC pipes
268 static NTSTATUS ipc_open_ntcreatex(struct request_context *req, union smb_open *oi)
270 struct pipe_state *p;
273 status = ipc_open_generic(req, oi->ntcreatex.in.fname, &p);
274 if (!NT_STATUS_IS_OK(status)) {
278 ZERO_STRUCT(oi->ntcreatex.out);
279 oi->ntcreatex.out.fnum = p->fnum;
280 oi->ntcreatex.out.ipc_state = p->ipc_state;
286 open a file with openx - used for MSRPC pipes
288 static NTSTATUS ipc_open_openx(struct request_context *req, union smb_open *oi)
290 struct pipe_state *p;
292 const char *fname = oi->openx.in.fname;
294 if (strncasecmp(fname, "PIPE\\", 5) != 0) {
295 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
300 status = ipc_open_generic(req, fname, &p);
301 if (!NT_STATUS_IS_OK(status)) {
305 ZERO_STRUCT(oi->openx.out);
306 oi->openx.out.fnum = p->fnum;
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 request_context *req, union smb_open *oi)
320 switch (oi->generic.level) {
321 case RAW_OPEN_NTCREATEX:
322 status = ipc_open_ntcreatex(req, oi);
325 status = ipc_open_openx(req, oi);
328 status = NT_STATUS_NOT_SUPPORTED;
338 static NTSTATUS ipc_mkdir(struct request_context *req, union smb_mkdir *md)
340 return NT_STATUS_ACCESS_DENIED;
346 static NTSTATUS ipc_rmdir(struct request_context *req, struct smb_rmdir *rd)
348 return NT_STATUS_ACCESS_DENIED;
352 rename a set of files
354 static NTSTATUS ipc_rename(struct request_context *req, union smb_rename *ren)
356 return NT_STATUS_ACCESS_DENIED;
362 static NTSTATUS ipc_copy(struct request_context *req, struct smb_copy *cp)
364 return NT_STATUS_ACCESS_DENIED;
370 static NTSTATUS ipc_read(struct request_context *req, union smb_read *rd)
372 struct ipc_private *private = req->conn->ntvfs_private;
375 struct pipe_state *p;
378 switch (rd->generic.level) {
380 fnum = rd->read.in.fnum;
381 data.length = rd->read.in.count;
382 data.data = rd->read.out.data;
385 fnum = rd->readx.in.fnum;
386 data.length = rd->readx.in.maxcnt;
387 data.data = rd->readx.out.data;
390 return NT_STATUS_NOT_SUPPORTED;
393 p = pipe_state_find(private, fnum);
395 return NT_STATUS_INVALID_HANDLE;
398 status = dcesrv_output_blob(p->dce_conn, &data);
399 if (!NT_STATUS_IS_OK(status)) {
403 switch (rd->generic.level) {
405 rd->read.out.nread = data.length;
408 rd->readx.out.remaining = 0;
409 rd->readx.out.compaction_mode = 0;
410 rd->readx.out.nread = data.length;
413 return NT_STATUS_NOT_SUPPORTED;
422 static NTSTATUS ipc_write(struct request_context *req, union smb_write *wr)
424 struct ipc_private *private = req->conn->ntvfs_private;
427 struct pipe_state *p;
430 switch (wr->generic.level) {
431 case RAW_WRITE_WRITE:
432 fnum = wr->write.in.fnum;
433 data.data = wr->write.in.data;
434 data.length = wr->write.in.count;
437 case RAW_WRITE_WRITEX:
438 fnum = wr->writex.in.fnum;
439 data.data = wr->writex.in.data;
440 data.length = wr->writex.in.count;
444 return NT_STATUS_NOT_SUPPORTED;
447 p = pipe_state_find(private, fnum);
449 return NT_STATUS_INVALID_HANDLE;
452 status = dcesrv_input(p->dce_conn, &data);
453 if (!NT_STATUS_IS_OK(status)) {
457 switch (wr->generic.level) {
458 case RAW_WRITE_WRITE:
459 wr->write.out.nwritten = data.length;
461 case RAW_WRITE_WRITEX:
462 wr->writex.out.nwritten = data.length;
463 wr->writex.out.remaining = 0;
466 return NT_STATUS_NOT_SUPPORTED;
475 static NTSTATUS ipc_seek(struct request_context *req, struct smb_seek *io)
477 return NT_STATUS_ACCESS_DENIED;
483 static NTSTATUS ipc_flush(struct request_context *req, struct smb_flush *io)
485 return NT_STATUS_ACCESS_DENIED;
491 static NTSTATUS ipc_close(struct request_context *req, union smb_close *io)
493 struct ipc_private *private = req->conn->ntvfs_private;
494 struct pipe_state *p;
496 if (io->generic.level != RAW_CLOSE_CLOSE) {
497 return NT_STATUS_ACCESS_DENIED;
500 p = pipe_state_find(private, io->close.in.fnum);
502 return NT_STATUS_INVALID_HANDLE;
505 pipe_shutdown(private, p);
512 exit - closing files?
514 static NTSTATUS ipc_exit(struct request_context *req)
516 return NT_STATUS_ACCESS_DENIED;
522 static NTSTATUS ipc_lock(struct request_context *req, union smb_lock *lck)
524 return NT_STATUS_ACCESS_DENIED;
528 set info on a open file
530 static NTSTATUS ipc_setfileinfo(struct request_context *req, union smb_setfileinfo *info)
532 return NT_STATUS_ACCESS_DENIED;
536 query info on a open file
538 static NTSTATUS ipc_qfileinfo(struct request_context *req, union smb_fileinfo *info)
540 return NT_STATUS_ACCESS_DENIED;
545 return filesystem info
547 static NTSTATUS ipc_fsinfo(struct request_context *req, union smb_fsinfo *fs)
549 return NT_STATUS_ACCESS_DENIED;
553 return print queue info
555 static NTSTATUS ipc_lpq(struct request_context *req, union smb_lpq *lpq)
557 return NT_STATUS_ACCESS_DENIED;
561 list files in a directory matching a wildcard pattern
563 NTSTATUS ipc_search_first(struct request_context *req, union smb_search_first *io,
564 void *search_private,
565 BOOL (*callback)(void *, union smb_search_data *))
567 return NT_STATUS_ACCESS_DENIED;
571 continue listing files in a directory
573 NTSTATUS ipc_search_next(struct request_context *req, union smb_search_next *io,
574 void *search_private,
575 BOOL (*callback)(void *, union smb_search_data *))
577 return NT_STATUS_ACCESS_DENIED;
581 end listing files in a directory
583 NTSTATUS ipc_search_close(struct request_context *req, union smb_search_close *io)
585 return NT_STATUS_ACCESS_DENIED;
589 /* SMBtrans - handle a DCERPC command */
590 static NTSTATUS ipc_dcerpc_cmd(struct request_context *req, struct smb_trans2 *trans)
592 struct pipe_state *p;
593 struct ipc_private *private = req->conn->ntvfs_private;
596 /* the fnum is in setup[1] */
597 p = pipe_state_find(private, trans->in.setup[1]);
599 return NT_STATUS_INVALID_HANDLE;
602 trans->out.data = data_blob_talloc(req->mem_ctx, NULL, trans->in.max_data);
603 if (!trans->out.data.data) {
604 return NT_STATUS_NO_MEMORY;
607 /* pass the data to the dcerpc server. Note that we don't
608 expect this to fail, and things like NDR faults are not
609 reported at this stage. Those sorts of errors happen in the
610 dcesrv_output stage */
611 status = dcesrv_input(p->dce_conn, &trans->in.data);
612 if (!NT_STATUS_IS_OK(status)) {
617 now ask the dcerpc system for some output. This doesn't yet handle
618 async calls. Again, we only expect NT_STATUS_OK. If the call fails then
619 the error is encoded at the dcerpc level
621 status = dcesrv_output_blob(p->dce_conn, &trans->out.data);
622 if (!NT_STATUS_IS_OK(status)) {
626 trans->out.setup_count = 0;
627 trans->out.setup = NULL;
628 trans->out.params = data_blob(NULL, 0);
634 /* SMBtrans - set named pipe state */
635 static NTSTATUS ipc_set_nm_pipe_state(struct request_context *req, struct smb_trans2 *trans)
637 struct pipe_state *p;
638 struct ipc_private *private = req->conn->ntvfs_private;
640 /* the fnum is in setup[1] */
641 p = pipe_state_find(private, trans->in.setup[1]);
643 return NT_STATUS_INVALID_HANDLE;
646 if (trans->in.params.length != 2) {
647 return NT_STATUS_INVALID_PARAMETER;
649 p->ipc_state = SVAL(trans->in.params.data, 0);
651 trans->out.setup_count = 0;
652 trans->out.setup = NULL;
653 trans->out.params = data_blob(NULL, 0);
654 trans->out.data = data_blob(NULL, 0);
660 /* SMBtrans - used to provide access to SMB pipes */
661 static NTSTATUS ipc_trans(struct request_context *req, struct smb_trans2 *trans)
665 if (trans->in.setup_count != 2) {
666 return NT_STATUS_INVALID_PARAMETER;
669 switch (trans->in.setup[0]) {
670 case TRANSACT_SETNAMEDPIPEHANDLESTATE:
671 status = ipc_set_nm_pipe_state(req, trans);
673 case TRANSACT_DCERPCCMD:
674 status = ipc_dcerpc_cmd(req, trans);
677 status = NT_STATUS_INVALID_PARAMETER;
687 initialialise the IPC backend, registering ourselves with the ntvfs subsystem
689 NTSTATUS ntvfs_ipc_init(void)
692 struct ntvfs_ops ops;
696 /* fill in the name and type */
697 ops.name = "default";
698 ops.type = NTVFS_IPC;
700 /* fill in all the operations */
701 ops.connect = ipc_connect;
702 ops.disconnect = ipc_disconnect;
703 ops.unlink = ipc_unlink;
704 ops.chkpath = ipc_chkpath;
705 ops.qpathinfo = ipc_qpathinfo;
706 ops.setpathinfo = ipc_setpathinfo;
708 ops.mkdir = ipc_mkdir;
709 ops.rmdir = ipc_rmdir;
710 ops.rename = ipc_rename;
712 ops.ioctl = ipc_ioctl;
714 ops.write = ipc_write;
716 ops.flush = ipc_flush;
717 ops.close = ipc_close;
720 ops.setfileinfo = ipc_setfileinfo;
721 ops.qfileinfo = ipc_qfileinfo;
722 ops.fsinfo = ipc_fsinfo;
724 ops.search_first = ipc_search_first;
725 ops.search_next = ipc_search_next;
726 ops.search_close = ipc_search_close;
727 ops.trans = ipc_trans;
729 /* register ourselves with the NTVFS subsystem. */
730 ret = register_backend("ntvfs", &ops);
732 if (!NT_STATUS_IS_OK(ret)) {
733 DEBUG(0,("Failed to register IPC backend!\n"));