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