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