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 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 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);
259 open a file with ntcreatex - used for MSRPC pipes
261 static NTSTATUS ipc_open_ntcreatex(struct request_context *req, union smb_open *oi)
263 struct pipe_state *p;
266 status = ipc_open_generic(req, oi->ntcreatex.in.fname, &p);
267 if (!NT_STATUS_IS_OK(status)) {
271 ZERO_STRUCT(oi->ntcreatex.out);
272 oi->ntcreatex.out.fnum = p->fnum;
273 oi->ntcreatex.out.ipc_state = p->ipc_state;
279 open a file with openx - used for MSRPC pipes
281 static NTSTATUS ipc_open_openx(struct request_context *req, union smb_open *oi)
283 struct pipe_state *p;
285 const char *fname = oi->openx.in.fname;
287 if (strncasecmp(fname, "PIPE\\", 5) != 0) {
288 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
293 status = ipc_open_generic(req, fname, &p);
294 if (!NT_STATUS_IS_OK(status)) {
298 ZERO_STRUCT(oi->openx.out);
299 oi->openx.out.fnum = p->fnum;
300 oi->openx.out.ftype = 2;
301 oi->openx.out.devstate = p->ipc_state;
307 open a file - used for MSRPC pipes
309 static NTSTATUS ipc_open(struct request_context *req, union smb_open *oi)
313 switch (oi->generic.level) {
314 case RAW_OPEN_NTCREATEX:
315 status = ipc_open_ntcreatex(req, oi);
318 status = ipc_open_openx(req, oi);
321 status = NT_STATUS_NOT_SUPPORTED;
331 static NTSTATUS ipc_mkdir(struct request_context *req, union smb_mkdir *md)
333 return NT_STATUS_ACCESS_DENIED;
339 static NTSTATUS ipc_rmdir(struct request_context *req, struct smb_rmdir *rd)
341 return NT_STATUS_ACCESS_DENIED;
345 rename a set of files
347 static NTSTATUS ipc_rename(struct request_context *req, union smb_rename *ren)
349 return NT_STATUS_ACCESS_DENIED;
355 static NTSTATUS ipc_copy(struct request_context *req, struct smb_copy *cp)
357 return NT_STATUS_ACCESS_DENIED;
363 static NTSTATUS ipc_read(struct request_context *req, union smb_read *rd)
365 struct ipc_private *private = req->conn->ntvfs_private;
368 struct pipe_state *p;
371 switch (rd->generic.level) {
373 fnum = rd->read.in.fnum;
374 data.length = rd->read.in.count;
375 data.data = rd->read.out.data;
378 fnum = rd->readx.in.fnum;
379 data.length = rd->readx.in.maxcnt;
380 data.data = rd->readx.out.data;
383 return NT_STATUS_NOT_SUPPORTED;
386 p = pipe_state_find(private, fnum);
388 return NT_STATUS_INVALID_HANDLE;
391 status = dcesrv_output_blob(p->dce_conn, &data);
392 if (!NT_STATUS_IS_OK(status)) {
396 switch (rd->generic.level) {
398 rd->read.out.nread = data.length;
401 rd->readx.out.remaining = 0;
402 rd->readx.out.compaction_mode = 0;
403 rd->readx.out.nread = data.length;
406 return NT_STATUS_NOT_SUPPORTED;
415 static NTSTATUS ipc_write(struct request_context *req, union smb_write *wr)
417 struct ipc_private *private = req->conn->ntvfs_private;
420 struct pipe_state *p;
423 switch (wr->generic.level) {
424 case RAW_WRITE_WRITE:
425 fnum = wr->write.in.fnum;
426 data.data = wr->write.in.data;
427 data.length = wr->write.in.count;
430 case RAW_WRITE_WRITEX:
431 fnum = wr->writex.in.fnum;
432 data.data = wr->writex.in.data;
433 data.length = wr->writex.in.count;
437 return NT_STATUS_NOT_SUPPORTED;
440 p = pipe_state_find(private, fnum);
442 return NT_STATUS_INVALID_HANDLE;
445 status = dcesrv_input(p->dce_conn, &data);
446 if (!NT_STATUS_IS_OK(status)) {
450 switch (wr->generic.level) {
451 case RAW_WRITE_WRITE:
452 wr->write.out.nwritten = data.length;
454 case RAW_WRITE_WRITEX:
455 wr->writex.out.nwritten = data.length;
456 wr->writex.out.remaining = 0;
459 return NT_STATUS_NOT_SUPPORTED;
468 static NTSTATUS ipc_seek(struct request_context *req, struct smb_seek *io)
470 return NT_STATUS_ACCESS_DENIED;
476 static NTSTATUS ipc_flush(struct request_context *req, struct smb_flush *io)
478 return NT_STATUS_ACCESS_DENIED;
484 static NTSTATUS ipc_close(struct request_context *req, union smb_close *io)
486 struct ipc_private *private = req->conn->ntvfs_private;
487 struct pipe_state *p;
489 if (io->generic.level != RAW_CLOSE_CLOSE) {
490 return NT_STATUS_ACCESS_DENIED;
493 p = pipe_state_find(private, io->close.in.fnum);
495 return NT_STATUS_INVALID_HANDLE;
498 pipe_shutdown(private, p);
505 exit - closing files?
507 static NTSTATUS ipc_exit(struct request_context *req)
509 return NT_STATUS_ACCESS_DENIED;
515 static NTSTATUS ipc_lock(struct request_context *req, union smb_lock *lck)
517 return NT_STATUS_ACCESS_DENIED;
521 set info on a open file
523 static NTSTATUS ipc_setfileinfo(struct request_context *req, union smb_setfileinfo *info)
525 return NT_STATUS_ACCESS_DENIED;
529 query info on a open file
531 static NTSTATUS ipc_qfileinfo(struct request_context *req, union smb_fileinfo *info)
533 return NT_STATUS_ACCESS_DENIED;
538 return filesystem info
540 static NTSTATUS ipc_fsinfo(struct request_context *req, union smb_fsinfo *fs)
542 return NT_STATUS_ACCESS_DENIED;
546 return print queue info
548 static NTSTATUS ipc_lpq(struct request_context *req, union smb_lpq *lpq)
550 return NT_STATUS_ACCESS_DENIED;
554 list files in a directory matching a wildcard pattern
556 NTSTATUS ipc_search_first(struct request_context *req, union smb_search_first *io,
557 void *search_private,
558 BOOL (*callback)(void *, union smb_search_data *))
560 return NT_STATUS_ACCESS_DENIED;
564 continue listing files in a directory
566 NTSTATUS ipc_search_next(struct request_context *req, union smb_search_next *io,
567 void *search_private,
568 BOOL (*callback)(void *, union smb_search_data *))
570 return NT_STATUS_ACCESS_DENIED;
574 end listing files in a directory
576 NTSTATUS ipc_search_close(struct request_context *req, union smb_search_close *io)
578 return NT_STATUS_ACCESS_DENIED;
582 /* SMBtrans - handle a DCERPC command */
583 static NTSTATUS ipc_dcerpc_cmd(struct request_context *req, struct smb_trans2 *trans)
585 struct pipe_state *p;
586 struct ipc_private *private = req->conn->ntvfs_private;
589 /* the fnum is in setup[1] */
590 p = pipe_state_find(private, trans->in.setup[1]);
592 return NT_STATUS_INVALID_HANDLE;
595 trans->out.data = data_blob_talloc(req->mem_ctx, NULL, trans->in.max_data);
596 if (!trans->out.data.data) {
597 return NT_STATUS_NO_MEMORY;
600 /* pass the data to the dcerpc server. Note that we don't
601 expect this to fail, and things like NDR faults are not
602 reported at this stage. Those sorts of errors happen in the
603 dcesrv_output stage */
604 status = dcesrv_input(p->dce_conn, &trans->in.data);
605 if (!NT_STATUS_IS_OK(status)) {
610 now ask the dcerpc system for some output. This doesn't yet handle
611 async calls. Again, we only expect NT_STATUS_OK. If the call fails then
612 the error is encoded at the dcerpc level
614 status = dcesrv_output_blob(p->dce_conn, &trans->out.data);
615 if (!NT_STATUS_IS_OK(status)) {
619 trans->out.setup_count = 0;
620 trans->out.setup = NULL;
621 trans->out.params = data_blob(NULL, 0);
627 /* SMBtrans - set named pipe state */
628 static NTSTATUS ipc_set_nm_pipe_state(struct request_context *req, struct smb_trans2 *trans)
630 struct pipe_state *p;
631 struct ipc_private *private = req->conn->ntvfs_private;
633 /* the fnum is in setup[1] */
634 p = pipe_state_find(private, trans->in.setup[1]);
636 return NT_STATUS_INVALID_HANDLE;
639 if (trans->in.params.length != 2) {
640 return NT_STATUS_INVALID_PARAMETER;
642 p->ipc_state = SVAL(trans->in.params.data, 0);
644 trans->out.setup_count = 0;
645 trans->out.setup = NULL;
646 trans->out.params = data_blob(NULL, 0);
647 trans->out.data = data_blob(NULL, 0);
653 /* SMBtrans - used to provide access to SMB pipes */
654 static NTSTATUS ipc_trans(struct request_context *req, struct smb_trans2 *trans)
658 if (trans->in.setup_count != 2) {
659 return NT_STATUS_INVALID_PARAMETER;
662 switch (trans->in.setup[0]) {
663 case TRANSACT_SETNAMEDPIPEHANDLESTATE:
664 status = ipc_set_nm_pipe_state(req, trans);
666 case TRANSACT_DCERPCCMD:
667 status = ipc_dcerpc_cmd(req, trans);
670 status = NT_STATUS_INVALID_PARAMETER;
680 initialialise the IPC backend, registering ourselves with the ntvfs subsystem
682 NTSTATUS ntvfs_ipc_init(void)
685 struct ntvfs_ops ops;
689 /* fill in the name and type */
690 ops.name = "default";
691 ops.type = NTVFS_IPC;
693 /* fill in all the operations */
694 ops.connect = ipc_connect;
695 ops.disconnect = ipc_disconnect;
696 ops.unlink = ipc_unlink;
697 ops.chkpath = ipc_chkpath;
698 ops.qpathinfo = ipc_qpathinfo;
699 ops.setpathinfo = ipc_setpathinfo;
701 ops.mkdir = ipc_mkdir;
702 ops.rmdir = ipc_rmdir;
703 ops.rename = ipc_rename;
705 ops.ioctl = ipc_ioctl;
707 ops.write = ipc_write;
709 ops.flush = ipc_flush;
710 ops.close = ipc_close;
713 ops.setfileinfo = ipc_setfileinfo;
714 ops.qfileinfo = ipc_qfileinfo;
715 ops.fsinfo = ipc_fsinfo;
717 ops.search_first = ipc_search_first;
718 ops.search_next = ipc_search_next;
719 ops.search_close = ipc_search_close;
720 ops.trans = ipc_trans;
722 /* register ourselves with the NTVFS subsystem. */
723 ret = register_backend("ntvfs", &ops);
725 if (!NT_STATUS_IS_OK(ret)) {
726 DEBUG(0,("Failed to register IPC backend!\n"));