6ef380c4ebf20df8fddcbf906c3f7b1ec4e3a896
[jelmer/samba4-debian.git] / source / ntvfs / ipc / vfs_ipc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    default IPC$ NTVFS backend
4
5    Copyright (C) Andrew Tridgell 2003
6    Copyright (C) Stefan (metze) Metzmacher 2004-2005
7
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.
12    
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.
17    
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.
21 */
22 /*
23   this implements the IPC$ backend, called by the NTVFS subsystem to
24   handle requests on IPC$ shares
25 */
26
27
28 #include "includes.h"
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"
34
35 #define IPC_BASE_FNUM 0x400
36
37 /* this is the private structure used to keep the state of an open
38    ipc$ connection. It needs to keep information about all open
39    pipes */
40 struct ipc_private {
41         struct ntvfs_module_context *ntvfs;
42
43         struct idr_context *idtree_fnum;
44
45         struct dcesrv_context *dcesrv;
46
47         /* a list of open pipes */
48         struct pipe_state {
49                 struct pipe_state *next, *prev;
50                 struct ipc_private *private;
51                 const char *pipe_name;
52                 uint16_t fnum;
53                 struct dcesrv_connection *dce_conn;
54                 uint16_t ipc_state;
55                 /* we need to remember the session it was opened on,
56                    as it is illegal to operate on someone elses fnum */
57                 struct auth_session_info *session_info;
58
59                 /* we need to remember the client pid that 
60                    opened the file so SMBexit works */
61                 uint16_t smbpid;
62         } *pipe_list;
63 };
64
65
66 /*
67   find a open pipe give a file descriptor
68 */
69 static struct pipe_state *pipe_state_find(struct ipc_private *private, uint16_t fnum,
70                                           struct auth_session_info *session_info)
71 {
72         struct pipe_state *s;
73         void *p;
74
75         p = idr_find(private->idtree_fnum, fnum);
76         if (!p) return NULL;
77
78         s = talloc_get_type(p, struct pipe_state);
79
80         if (s->session_info != session_info) {
81                 return NULL;
82         }
83
84         return s;
85 }
86
87
88 /*
89   connect to a share - always works 
90 */
91 static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
92                             struct ntvfs_request *req, const char *sharename)
93 {
94         NTSTATUS status;
95         struct ipc_private *private;
96
97         ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "IPC");
98         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
99
100         ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "IPC");
101         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
102
103         /* prepare the private state for this connection */
104         private = talloc(ntvfs, struct ipc_private);
105         NT_STATUS_HAVE_NO_MEMORY(private);
106
107         ntvfs->private_data = private;
108
109         private->ntvfs = ntvfs;
110         private->pipe_list = NULL;
111
112         private->idtree_fnum = idr_init(private);
113         NT_STATUS_HAVE_NO_MEMORY(private->idtree_fnum);
114
115         /* setup the DCERPC server subsystem */
116         status = dcesrv_init_ipc_context(private, &private->dcesrv);
117         NT_STATUS_NOT_OK_RETURN(status);
118
119         return NT_STATUS_OK;
120 }
121
122 /*
123   disconnect from a share
124 */
125 static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs)
126 {
127         return NT_STATUS_OK;
128 }
129
130 /*
131   delete a file
132 */
133 static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
134                            struct ntvfs_request *req,
135                            union smb_unlink *unl)
136 {
137         return NT_STATUS_ACCESS_DENIED;
138 }
139
140
141 /*
142   ioctl interface - we don't do any
143 */
144 static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
145                           struct ntvfs_request *req, union smb_ioctl *io)
146 {
147         return NT_STATUS_ACCESS_DENIED;
148 }
149
150 /*
151   check if a directory exists
152 */
153 static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
154                             struct ntvfs_request *req,
155                             union smb_chkpath *cp)
156 {
157         return NT_STATUS_ACCESS_DENIED;
158 }
159
160 /*
161   return info on a pathname
162 */
163 static NTSTATUS ipc_qpathinfo(struct ntvfs_module_context *ntvfs,
164                               struct ntvfs_request *req, union smb_fileinfo *info)
165 {
166         return NT_STATUS_ACCESS_DENIED;
167 }
168
169 /*
170   set info on a pathname
171 */
172 static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
173                                 struct ntvfs_request *req, union smb_setfileinfo *st)
174 {
175         return NT_STATUS_ACCESS_DENIED;
176 }
177
178
179 /*
180   destroy a open pipe structure
181 */
182 static int ipc_fd_destructor(void *ptr)
183 {
184         struct pipe_state *p = ptr;
185         idr_remove(p->private->idtree_fnum, p->fnum);
186         DLIST_REMOVE(p->private->pipe_list, p);
187         return 0;
188 }
189
190 static struct socket_address *ipc_get_my_addr(struct dcesrv_connection *dce_conn, TALLOC_CTX *mem_ctx)
191 {
192         struct ipc_private *private = dce_conn->transport.private_data;
193
194         return ntvfs_get_my_addr(private->ntvfs, mem_ctx);
195 }
196
197 static struct socket_address *ipc_get_peer_addr(struct dcesrv_connection *dce_conn, TALLOC_CTX *mem_ctx)
198 {
199         struct ipc_private *private = dce_conn->transport.private_data;
200
201         return ntvfs_get_peer_addr(private->ntvfs, mem_ctx);
202 }
203
204 /*
205   open a file backend - used for MSRPC pipes
206 */
207 static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
208                                  struct ntvfs_request *req, const char *fname, 
209                                  struct pipe_state **ps)
210 {
211         struct pipe_state *p;
212         NTSTATUS status;
213         struct dcerpc_binding *ep_description;
214         struct ipc_private *private = ntvfs->private_data;
215         int fnum;
216
217         p = talloc(req, struct pipe_state);
218         NT_STATUS_HAVE_NO_MEMORY(p);
219
220         ep_description = talloc(req, struct dcerpc_binding);
221         NT_STATUS_HAVE_NO_MEMORY(ep_description);
222
223         while (fname[0] == '\\') fname++;
224
225         p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
226         NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
227
228         fnum = idr_get_new_above(private->idtree_fnum, p, IPC_BASE_FNUM, UINT16_MAX);
229         if (fnum == -1) {
230                 return NT_STATUS_TOO_MANY_OPENED_FILES;
231         }
232
233         p->fnum = fnum;
234         p->ipc_state = 0x5ff;
235
236         /*
237           we're all set, now ask the dcerpc server subsystem to open the 
238           endpoint. At this stage the pipe isn't bound, so we don't
239           know what interface the user actually wants, just that they want
240           one of the interfaces attached to this pipe endpoint.
241         */
242         ep_description->transport = NCACN_NP;
243         ep_description->endpoint = talloc_reference(ep_description, p->pipe_name);
244
245         /* The session info is refcount-increased in the 
246          * dcesrv_endpoint_search_connect() function
247          */
248         status = dcesrv_endpoint_search_connect(private->dcesrv,
249                                                 p,
250                                                 ep_description, 
251                                                 req->session_info,
252                                                 ntvfs->ctx->event_ctx,
253                                                 0,
254                                                 &p->dce_conn);
255         if (!NT_STATUS_IS_OK(status)) {
256                 idr_remove(private->idtree_fnum, p->fnum);
257                 return status;
258         }
259
260         p->dce_conn->transport.private_data             = private;
261         p->dce_conn->transport.report_output_data       = NULL;
262         p->dce_conn->transport.get_my_addr              = ipc_get_my_addr;
263         p->dce_conn->transport.get_peer_addr            = ipc_get_peer_addr;
264         
265         DLIST_ADD(private->pipe_list, p);
266
267         p->smbpid = req->smbpid;
268         p->session_info = req->session_info;
269         p->private = private;
270
271         *ps = p;
272
273         talloc_steal(private, p);
274
275         talloc_set_destructor(p, ipc_fd_destructor);
276
277         return NT_STATUS_OK;
278 }
279
280 /*
281   open a file with ntcreatex - used for MSRPC pipes
282 */
283 static NTSTATUS ipc_open_ntcreatex(struct ntvfs_module_context *ntvfs,
284                                    struct ntvfs_request *req, union smb_open *oi)
285 {
286         struct pipe_state *p;
287         NTSTATUS status;
288
289         status = ipc_open_generic(ntvfs, req, oi->ntcreatex.in.fname, &p);
290         if (!NT_STATUS_IS_OK(status)) {
291                 return status;
292         }
293
294         ZERO_STRUCT(oi->ntcreatex.out);
295         oi->ntcreatex.out.file.fnum = p->fnum;
296         oi->ntcreatex.out.ipc_state = p->ipc_state;
297         oi->ntcreatex.out.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
298
299         return status;
300 }
301
302 /*
303   open a file with openx - used for MSRPC pipes
304 */
305 static NTSTATUS ipc_open_openx(struct ntvfs_module_context *ntvfs,
306                                struct ntvfs_request *req, union smb_open *oi)
307 {
308         struct pipe_state *p;
309         NTSTATUS status;
310         const char *fname = oi->openx.in.fname;
311
312         status = ipc_open_generic(ntvfs, req, fname, &p);
313         if (!NT_STATUS_IS_OK(status)) {
314                 return status;
315         }
316
317         ZERO_STRUCT(oi->openx.out);
318         oi->openx.out.file.fnum = p->fnum;
319         oi->openx.out.ftype     = 2;
320         oi->openx.out.devstate  = p->ipc_state;
321         
322         return status;
323 }
324
325 /*
326   open a file - used for MSRPC pipes
327 */
328 static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
329                                 struct ntvfs_request *req, union smb_open *oi)
330 {
331         NTSTATUS status;
332
333         switch (oi->generic.level) {
334         case RAW_OPEN_NTCREATEX:
335                 status = ipc_open_ntcreatex(ntvfs, req, oi);
336                 break;
337         case RAW_OPEN_OPENX:
338                 status = ipc_open_openx(ntvfs, req, oi);
339                 break;
340         default:
341                 status = NT_STATUS_NOT_SUPPORTED;
342                 break;
343         }
344
345         return status;
346 }
347
348 /*
349   create a directory
350 */
351 static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
352                           struct ntvfs_request *req, union smb_mkdir *md)
353 {
354         return NT_STATUS_ACCESS_DENIED;
355 }
356
357 /*
358   remove a directory
359 */
360 static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
361                           struct ntvfs_request *req, struct smb_rmdir *rd)
362 {
363         return NT_STATUS_ACCESS_DENIED;
364 }
365
366 /*
367   rename a set of files
368 */
369 static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
370                            struct ntvfs_request *req, union smb_rename *ren)
371 {
372         return NT_STATUS_ACCESS_DENIED;
373 }
374
375 /*
376   copy a set of files
377 */
378 static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
379                          struct ntvfs_request *req, struct smb_copy *cp)
380 {
381         return NT_STATUS_ACCESS_DENIED;
382 }
383
384 static NTSTATUS ipc_readx_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
385 {
386         DATA_BLOB *blob = private_data;
387
388         if (out->length < blob->length) {
389                 blob->length = out->length;
390         }
391         memcpy(blob->data, out->data, blob->length);
392         *nwritten = blob->length;
393         return NT_STATUS_OK;
394 }
395
396 /*
397   read from a file
398 */
399 static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
400                          struct ntvfs_request *req, union smb_read *rd)
401 {
402         struct ipc_private *private = ntvfs->private_data;
403         DATA_BLOB data;
404         uint16_t fnum;
405         struct pipe_state *p;
406         NTSTATUS status = NT_STATUS_OK;
407
408         if (rd->generic.level != RAW_READ_GENERIC) {
409                 return ntvfs_map_read(ntvfs, req, rd);
410         }
411
412         fnum = rd->readx.in.file.fnum;
413
414         p = pipe_state_find(private, fnum, req->session_info);
415         if (!p) {
416                 return NT_STATUS_INVALID_HANDLE;
417         }
418
419         data.length = rd->readx.in.maxcnt;
420         data.data = rd->readx.out.data;
421         if (data.length > UINT16_MAX) {
422                 data.length = UINT16_MAX;
423         }
424
425         if (data.length != 0) {
426                 status = dcesrv_output(p->dce_conn, &data, ipc_readx_dcesrv_output);
427                 if (NT_STATUS_IS_ERR(status)) {
428                         return status;
429                 }
430         }
431
432         rd->readx.out.remaining = 0;
433         rd->readx.out.compaction_mode = 0;
434         rd->readx.out.nread = data.length;
435
436         return status;
437 }
438
439 /*
440   write to a file
441 */
442 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
443                           struct ntvfs_request *req, union smb_write *wr)
444 {
445         struct ipc_private *private = ntvfs->private_data;
446         DATA_BLOB data;
447         uint16_t fnum;
448         struct pipe_state *p;
449         NTSTATUS status;
450
451         if (wr->generic.level != RAW_WRITE_GENERIC) {
452                 return ntvfs_map_write(ntvfs, req, wr);
453         }
454
455         fnum = wr->writex.in.file.fnum;
456         data.data = discard_const_p(void, wr->writex.in.data);
457         data.length = wr->writex.in.count;
458
459         p = pipe_state_find(private, fnum, req->session_info);
460         if (!p) {
461                 return NT_STATUS_INVALID_HANDLE;
462         }
463
464         status = dcesrv_input(p->dce_conn, &data);
465         if (!NT_STATUS_IS_OK(status)) {
466                 return status;
467         }
468
469         wr->writex.out.nwritten = data.length;
470         wr->writex.out.remaining = 0;
471
472         return NT_STATUS_OK;
473 }
474
475 /*
476   seek in a file
477 */
478 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
479                          struct ntvfs_request *req,
480                          union smb_seek *io)
481 {
482         return NT_STATUS_ACCESS_DENIED;
483 }
484
485 /*
486   flush a file
487 */
488 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
489                           struct ntvfs_request *req,
490                           union smb_flush *io)
491 {
492         return NT_STATUS_ACCESS_DENIED;
493 }
494
495 /*
496   close a file
497 */
498 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
499                           struct ntvfs_request *req, union smb_close *io)
500 {
501         struct ipc_private *private = ntvfs->private_data;
502         struct pipe_state *p;
503
504         if (io->generic.level != RAW_CLOSE_CLOSE) {
505                 return ntvfs_map_close(ntvfs, req, io);
506         }
507
508         p = pipe_state_find(private, io->close.in.file.fnum, req->session_info);
509         if (!p) {
510                 return NT_STATUS_INVALID_HANDLE;
511         }
512
513         talloc_free(p);
514
515         return NT_STATUS_OK;
516 }
517
518 /*
519   exit - closing files
520 */
521 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
522                          struct ntvfs_request *req)
523 {
524         struct ipc_private *private = ntvfs->private_data;
525         struct pipe_state *p, *next;
526         
527         for (p=private->pipe_list; p; p=next) {
528                 next = p->next;
529                 if (p->session_info == req->session_info &&
530                     p->smbpid == req->smbpid) {
531                         talloc_free(p);
532                 }
533         }
534
535         return NT_STATUS_OK;
536 }
537
538 /*
539   logoff - closing files open by the user
540 */
541 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
542                            struct ntvfs_request *req)
543 {
544         struct ipc_private *private = ntvfs->private_data;
545         struct pipe_state *p, *next;
546         
547         for (p=private->pipe_list; p; p=next) {
548                 next = p->next;
549                 if (p->session_info == req->session_info) {
550                         talloc_free(p);
551                 }
552         }
553
554         return NT_STATUS_OK;
555 }
556
557 /*
558   setup for an async call
559 */
560 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
561                                 struct ntvfs_request *req,
562                                 void *private)
563 {
564         return NT_STATUS_OK;
565 }
566
567 /*
568   cancel an async call
569 */
570 static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
571                            struct ntvfs_request *req)
572 {
573         return NT_STATUS_UNSUCCESSFUL;
574 }
575
576 /*
577   lock a byte range
578 */
579 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
580                          struct ntvfs_request *req, union smb_lock *lck)
581 {
582         return NT_STATUS_ACCESS_DENIED;
583 }
584
585 /*
586   set info on a open file
587 */
588 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
589                                 struct ntvfs_request *req, union smb_setfileinfo *info)
590 {
591         return NT_STATUS_ACCESS_DENIED;
592 }
593
594 /*
595   query info on a open file
596 */
597 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
598                               struct ntvfs_request *req, union smb_fileinfo *info)
599 {
600         return NT_STATUS_ACCESS_DENIED;
601 }
602
603
604 /*
605   return filesystem info
606 */
607 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
608                            struct ntvfs_request *req, union smb_fsinfo *fs)
609 {
610         return NT_STATUS_ACCESS_DENIED;
611 }
612
613 /*
614   return print queue info
615 */
616 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
617                         struct ntvfs_request *req, union smb_lpq *lpq)
618 {
619         return NT_STATUS_ACCESS_DENIED;
620 }
621
622 /* 
623    list files in a directory matching a wildcard pattern
624 */
625 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
626                           struct ntvfs_request *req, union smb_search_first *io,
627                           void *search_private, 
628                           BOOL (*callback)(void *, union smb_search_data *))
629 {
630         return NT_STATUS_ACCESS_DENIED;
631 }
632
633 /* 
634    continue listing files in a directory 
635 */
636 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
637                          struct ntvfs_request *req, union smb_search_next *io,
638                          void *search_private, 
639                          BOOL (*callback)(void *, union smb_search_data *))
640 {
641         return NT_STATUS_ACCESS_DENIED;
642 }
643
644 /* 
645    end listing files in a directory 
646 */
647 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
648                           struct ntvfs_request *req, union smb_search_close *io)
649 {
650         return NT_STATUS_ACCESS_DENIED;
651 }
652
653 static NTSTATUS ipc_trans_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
654 {
655         NTSTATUS status = NT_STATUS_OK;
656         DATA_BLOB *blob = private_data;
657
658         if (out->length > blob->length) {
659                 status = STATUS_BUFFER_OVERFLOW;
660         }
661
662         if (out->length < blob->length) {
663                 blob->length = out->length;
664         }
665         memcpy(blob->data, out->data, blob->length);
666         *nwritten = blob->length;
667         return status;
668 }
669
670 /* SMBtrans - handle a DCERPC command */
671 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
672                                struct ntvfs_request *req, struct smb_trans2 *trans)
673 {
674         struct pipe_state *p;
675         struct ipc_private *private = ntvfs->private_data;
676         NTSTATUS status;
677
678         /* the fnum is in setup[1] */
679         p = pipe_state_find(private, trans->in.setup[1], req->session_info);
680         if (!p) {
681                 return NT_STATUS_INVALID_HANDLE;
682         }
683
684         trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
685         if (!trans->out.data.data) {
686                 return NT_STATUS_NO_MEMORY;
687         }
688
689         /* pass the data to the dcerpc server. Note that we don't
690            expect this to fail, and things like NDR faults are not
691            reported at this stage. Those sorts of errors happen in the
692            dcesrv_output stage */
693         status = dcesrv_input(p->dce_conn, &trans->in.data);
694         if (!NT_STATUS_IS_OK(status)) {
695                 return status;
696         }
697
698         /*
699           now ask the dcerpc system for some output. This doesn't yet handle
700           async calls. Again, we only expect NT_STATUS_OK. If the call fails then
701           the error is encoded at the dcerpc level
702         */
703         status = dcesrv_output(p->dce_conn, &trans->out.data, ipc_trans_dcesrv_output);
704         if (NT_STATUS_IS_ERR(status)) {
705                 return status;
706         }
707
708         trans->out.setup_count = 0;
709         trans->out.setup = NULL;
710         trans->out.params = data_blob(NULL, 0);
711
712         return status;
713 }
714
715
716 /* SMBtrans - set named pipe state */
717 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
718                                 struct ntvfs_request *req, struct smb_trans2 *trans)
719 {
720         struct ipc_private *private = ntvfs->private_data;
721         struct pipe_state *p;
722
723         /* the fnum is in setup[1] */
724         p = pipe_state_find(private, trans->in.setup[1], req->session_info);
725         if (!p) {
726                 return NT_STATUS_INVALID_HANDLE;
727         }
728
729         if (trans->in.params.length != 2) {
730                 return NT_STATUS_INVALID_PARAMETER;
731         }
732         p->ipc_state = SVAL(trans->in.params.data, 0);
733
734         trans->out.setup_count = 0;
735         trans->out.setup = NULL;
736         trans->out.params = data_blob(NULL, 0);
737         trans->out.data = data_blob(NULL, 0);
738
739         return NT_STATUS_OK;
740 }
741
742
743 /* SMBtrans - used to provide access to SMB pipes */
744 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
745                                 struct ntvfs_request *req, struct smb_trans2 *trans)
746 {
747         NTSTATUS status;
748
749         if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
750                 return ipc_rap_call(req, trans);
751
752         if (trans->in.setup_count != 2) {
753                 return NT_STATUS_INVALID_PARAMETER;
754         }
755
756         switch (trans->in.setup[0]) {
757         case TRANSACT_SETNAMEDPIPEHANDLESTATE:
758                 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
759                 break;
760         case TRANSACT_DCERPCCMD:
761                 status = ipc_dcerpc_cmd(ntvfs, req, trans);
762                 break;
763         default:
764                 status = NT_STATUS_INVALID_PARAMETER;
765                 break;
766         }
767
768         return status;
769 }
770
771
772
773 /*
774   initialialise the IPC backend, registering ourselves with the ntvfs subsystem
775  */
776 NTSTATUS ntvfs_ipc_init(void)
777 {
778         NTSTATUS ret;
779         struct ntvfs_ops ops;
780         NTVFS_CURRENT_CRITICAL_SIZES(vers);
781
782         ZERO_STRUCT(ops);
783         
784         /* fill in the name and type */
785         ops.name = "default";
786         ops.type = NTVFS_IPC;
787
788         /* fill in all the operations */
789         ops.connect = ipc_connect;
790         ops.disconnect = ipc_disconnect;
791         ops.unlink = ipc_unlink;
792         ops.chkpath = ipc_chkpath;
793         ops.qpathinfo = ipc_qpathinfo;
794         ops.setpathinfo = ipc_setpathinfo;
795         ops.open = ipc_open;
796         ops.mkdir = ipc_mkdir;
797         ops.rmdir = ipc_rmdir;
798         ops.rename = ipc_rename;
799         ops.copy = ipc_copy;
800         ops.ioctl = ipc_ioctl;
801         ops.read = ipc_read;
802         ops.write = ipc_write;
803         ops.seek = ipc_seek;
804         ops.flush = ipc_flush;  
805         ops.close = ipc_close;
806         ops.exit = ipc_exit;
807         ops.lock = ipc_lock;
808         ops.setfileinfo = ipc_setfileinfo;
809         ops.qfileinfo = ipc_qfileinfo;
810         ops.fsinfo = ipc_fsinfo;
811         ops.lpq = ipc_lpq;
812         ops.search_first = ipc_search_first;
813         ops.search_next = ipc_search_next;
814         ops.search_close = ipc_search_close;
815         ops.trans = ipc_trans;
816         ops.logoff = ipc_logoff;
817         ops.async_setup = ipc_async_setup;
818         ops.cancel = ipc_cancel;
819
820         /* register ourselves with the NTVFS subsystem. */
821         ret = ntvfs_register(&ops, &vers);
822
823         if (!NT_STATUS_IS_OK(ret)) {
824                 DEBUG(0,("Failed to register IPC backend!\n"));
825                 return ret;
826         }
827
828         return ret;
829 }