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