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