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