libcli/util Rename common map_nt_error_from_unix to avoid duplicate symbol
[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 "../librpc/gen_ndr/rap.h"
31 #include "ntvfs/ipc/proto.h"
32 #include "libcli/raw/ioctl.h"
33 #include "param/param.h"
34 #include "../lib/tsocket/tsocket.h"
35 #include "../libcli/named_pipe_auth/npa_tstream.h"
36 #include "auth/auth.h"
37 #include "auth/auth_sam_reply.h"
38 #include "lib/socket/socket.h"
39 #include "auth/credentials/credentials.h"
40 #include "auth/credentials/credentials_krb5.h"
41 #include <gssapi/gssapi.h>
42 #include "system/locale.h"
43
44 /* this is the private structure used to keep the state of an open
45    ipc$ connection. It needs to keep information about all open
46    pipes */
47 struct ipc_private {
48         struct ntvfs_module_context *ntvfs;
49
50         /* a list of open pipes */
51         struct pipe_state {
52                 struct pipe_state *next, *prev;
53                 struct ipc_private *ipriv;
54                 const char *pipe_name;
55                 struct ntvfs_handle *handle;
56                 struct tstream_context *npipe;
57                 uint16_t file_type;
58                 uint16_t device_state;
59                 uint64_t allocation_size;
60                 struct tevent_queue *write_queue;
61                 struct tevent_queue *read_queue;
62         } *pipe_list;
63 };
64
65
66 /*
67   find a open pipe give a file handle
68 */
69 static struct pipe_state *pipe_state_find(struct ipc_private *ipriv, struct ntvfs_handle *handle)
70 {
71         struct pipe_state *s;
72         void *p;
73
74         p = ntvfs_handle_get_backend_data(handle, ipriv->ntvfs);
75         if (!p) return NULL;
76
77         s = talloc_get_type(p, struct pipe_state);
78         if (!s) return NULL;
79
80         return s;
81 }
82
83 /*
84   find a open pipe give a wire fnum
85 */
86 static struct pipe_state *pipe_state_find_key(struct ipc_private *ipriv, struct ntvfs_request *req, const DATA_BLOB *key)
87 {
88         struct ntvfs_handle *h;
89
90         h = ntvfs_handle_search_by_wire_key(ipriv->ntvfs, req, key);
91         if (!h) return NULL;
92
93         return pipe_state_find(ipriv, h);
94 }
95
96
97 /*
98   connect to a share - always works 
99 */
100 static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
101                             struct ntvfs_request *req,
102                             union smb_tcon* tcon)
103 {
104         struct ipc_private *ipriv;
105         const char *sharename;
106
107         switch (tcon->generic.level) {
108         case RAW_TCON_TCON:
109                 sharename = tcon->tcon.in.service;
110                 break;
111         case RAW_TCON_TCONX:
112                 sharename = tcon->tconx.in.path;
113                 break;
114         case RAW_TCON_SMB2:
115                 sharename = tcon->smb2.in.path;
116                 break;
117         default:
118                 return NT_STATUS_INVALID_LEVEL;
119         }
120
121         if (strncmp(sharename, "\\\\", 2) == 0) {
122                 char *p = strchr(sharename+2, '\\');
123                 if (p) {
124                         sharename = p + 1;
125                 }
126         }
127
128         ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "IPC");
129         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
130
131         ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "IPC");
132         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
133
134         if (tcon->generic.level == RAW_TCON_TCONX) {
135                 tcon->tconx.out.fs_type = ntvfs->ctx->fs_type;
136                 tcon->tconx.out.dev_type = ntvfs->ctx->dev_type;
137         }
138
139         /* prepare the private state for this connection */
140         ipriv = talloc(ntvfs, struct ipc_private);
141         NT_STATUS_HAVE_NO_MEMORY(ipriv);
142
143         ntvfs->private_data = ipriv;
144
145         ipriv->ntvfs = ntvfs;
146         ipriv->pipe_list = NULL;
147
148         return NT_STATUS_OK;
149 }
150
151 /*
152   disconnect from a share
153 */
154 static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs)
155 {
156         return NT_STATUS_OK;
157 }
158
159 /*
160   delete a file
161 */
162 static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
163                            struct ntvfs_request *req,
164                            union smb_unlink *unl)
165 {
166         return NT_STATUS_ACCESS_DENIED;
167 }
168
169 /*
170   check if a directory exists
171 */
172 static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
173                             struct ntvfs_request *req,
174                             union smb_chkpath *cp)
175 {
176         return NT_STATUS_ACCESS_DENIED;
177 }
178
179 /*
180   return info on a pathname
181 */
182 static NTSTATUS ipc_qpathinfo(struct ntvfs_module_context *ntvfs,
183                               struct ntvfs_request *req, union smb_fileinfo *info)
184 {
185         switch (info->generic.level) {
186         case  RAW_FILEINFO_GENERIC:
187                 return NT_STATUS_INVALID_DEVICE_REQUEST;
188         case RAW_FILEINFO_GETATTR:
189                 return NT_STATUS_ACCESS_DENIED;
190         default:
191                 return ntvfs_map_qpathinfo(ntvfs, req, info);
192         }
193 }
194
195 /*
196   set info on a pathname
197 */
198 static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
199                                 struct ntvfs_request *req, union smb_setfileinfo *st)
200 {
201         return NT_STATUS_ACCESS_DENIED;
202 }
203
204
205 /*
206   destroy a open pipe structure
207 */
208 static int ipc_fd_destructor(struct pipe_state *p)
209 {
210         DLIST_REMOVE(p->ipriv->pipe_list, p);
211         ntvfs_handle_remove_backend_data(p->handle, p->ipriv->ntvfs);
212         return 0;
213 }
214
215 struct ipc_open_state {
216         struct ipc_private *ipriv;
217         struct pipe_state *p;
218         struct ntvfs_request *req;
219         union smb_open *oi;
220         struct auth_session_info_transport *session_info_transport;
221 };
222
223 static void ipc_open_done(struct tevent_req *subreq);
224
225 /*
226   check the pipename is valid
227  */
228 static NTSTATUS validate_pipename(const char *name)
229 {
230         while (*name) {
231                 if (!isalnum(*name) && *name != '_') {
232                         return NT_STATUS_INVALID_PARAMETER;
233                 }
234                 name++;
235         }
236         return NT_STATUS_OK;
237 }
238
239 /*
240   open a file - used for MSRPC pipes
241 */
242 static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
243                          struct ntvfs_request *req, union smb_open *oi)
244 {
245         NTSTATUS status;
246         struct pipe_state *p;
247         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
248                                     struct ipc_private);
249         struct ntvfs_handle *h;
250         struct ipc_open_state *state;
251         struct tevent_req *subreq;
252         const char *fname;
253         const char *directory;
254         const struct tsocket_address *client_addr;
255         const struct tsocket_address *server_addr;
256
257         switch (oi->generic.level) {
258         case RAW_OPEN_NTCREATEX:
259         case RAW_OPEN_NTTRANS_CREATE:
260                 fname = oi->ntcreatex.in.fname;
261                 break;
262         case RAW_OPEN_OPENX:
263                 fname = oi->openx.in.fname;
264                 break;
265         case RAW_OPEN_SMB2:
266                 fname = oi->smb2.in.fname;
267                 break;
268         default:
269                 return NT_STATUS_NOT_SUPPORTED;
270         }
271
272         directory = talloc_asprintf(req, "%s/np",
273                                     lpcfg_ncalrpc_dir(ipriv->ntvfs->ctx->lp_ctx));
274         NT_STATUS_HAVE_NO_MEMORY(directory);
275
276         state = talloc(req, struct ipc_open_state);
277         NT_STATUS_HAVE_NO_MEMORY(state);
278
279         status = ntvfs_handle_new(ntvfs, req, &h);
280         NT_STATUS_NOT_OK_RETURN(status);
281
282         p = talloc(h, struct pipe_state);
283         NT_STATUS_HAVE_NO_MEMORY(p);
284
285         while (fname[0] == '\\') fname++;
286
287         /* check for valid characters in name */
288         fname = strlower_talloc(p, fname);
289
290         status = validate_pipename(fname);
291         NT_STATUS_NOT_OK_RETURN(status);
292
293         p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
294         NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
295
296         p->handle = h;
297         p->ipriv = ipriv;
298
299         p->write_queue = tevent_queue_create(p, "ipc_write_queue");
300         NT_STATUS_HAVE_NO_MEMORY(p->write_queue);
301
302         p->read_queue = tevent_queue_create(p, "ipc_read_queue");
303         NT_STATUS_HAVE_NO_MEMORY(p->read_queue);
304
305         state->ipriv = ipriv;
306         state->p = p;
307         state->req = req;
308         state->oi = oi;
309
310         status = auth_session_info_transport_from_session(state,
311                                                           req->session_info,
312                                                           ipriv->ntvfs->ctx->event_ctx,
313                                                           ipriv->ntvfs->ctx->lp_ctx,
314                                                           &state->session_info_transport);
315
316         NT_STATUS_NOT_OK_RETURN(status);
317
318         client_addr = ntvfs_get_local_address(ipriv->ntvfs);
319         server_addr = ntvfs_get_remote_address(ipriv->ntvfs);
320
321         subreq = tstream_npa_connect_send(p,
322                                           ipriv->ntvfs->ctx->event_ctx,
323                                           directory,
324                                           fname,
325                                           client_addr,
326                                           NULL,
327                                           server_addr,
328                                           NULL,
329                                           state->session_info_transport);
330         NT_STATUS_HAVE_NO_MEMORY(subreq);
331         tevent_req_set_callback(subreq, ipc_open_done, state);
332
333         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
334         return NT_STATUS_OK;
335 }
336
337 static void ipc_open_done(struct tevent_req *subreq)
338 {
339         struct ipc_open_state *state = tevent_req_callback_data(subreq,
340                                        struct ipc_open_state);
341         struct ipc_private *ipriv = state->ipriv;
342         struct pipe_state *p = state->p;
343         struct ntvfs_request *req = state->req;
344         union smb_open *oi = state->oi;
345         int ret;
346         int sys_errno;
347         NTSTATUS status;
348
349         ret = tstream_npa_connect_recv(subreq, &sys_errno,
350                                        p, &p->npipe,
351                                        &p->file_type,
352                                        &p->device_state,
353                                        &p->allocation_size);
354         TALLOC_FREE(subreq);
355         if (ret == -1) {
356                 status = map_nt_error_from_unix_common(sys_errno);
357                 goto reply;
358         }
359
360         DLIST_ADD(ipriv->pipe_list, p);
361         talloc_set_destructor(p, ipc_fd_destructor);
362
363         status = ntvfs_handle_set_backend_data(p->handle, ipriv->ntvfs, p);
364         if (!NT_STATUS_IS_OK(status)) {
365                 goto reply;
366         }
367
368         switch (oi->generic.level) {
369         case RAW_OPEN_NTCREATEX:
370                 ZERO_STRUCT(oi->ntcreatex.out);
371                 oi->ntcreatex.out.file.ntvfs    = p->handle;
372                 oi->ntcreatex.out.oplock_level  = 0;
373                 oi->ntcreatex.out.create_action = NTCREATEX_ACTION_EXISTED;
374                 oi->ntcreatex.out.create_time   = 0;
375                 oi->ntcreatex.out.access_time   = 0;
376                 oi->ntcreatex.out.write_time    = 0;
377                 oi->ntcreatex.out.change_time   = 0;
378                 oi->ntcreatex.out.attrib        = FILE_ATTRIBUTE_NORMAL;
379                 oi->ntcreatex.out.alloc_size    = p->allocation_size;
380                 oi->ntcreatex.out.size          = 0;
381                 oi->ntcreatex.out.file_type     = p->file_type;
382                 oi->ntcreatex.out.ipc_state     = p->device_state;
383                 oi->ntcreatex.out.is_directory  = 0;
384                 break;
385         case RAW_OPEN_OPENX:
386                 ZERO_STRUCT(oi->openx.out);
387                 oi->openx.out.file.ntvfs        = p->handle;
388                 oi->openx.out.attrib            = FILE_ATTRIBUTE_NORMAL;
389                 oi->openx.out.write_time        = 0;
390                 oi->openx.out.size              = 0;
391                 oi->openx.out.access            = 0;
392                 oi->openx.out.ftype             = p->file_type;
393                 oi->openx.out.devstate          = p->device_state;
394                 oi->openx.out.action            = 0;
395                 oi->openx.out.unique_fid        = 0;
396                 oi->openx.out.access_mask       = 0;
397                 oi->openx.out.unknown           = 0;
398                 break;
399         case RAW_OPEN_SMB2:
400                 ZERO_STRUCT(oi->smb2.out);
401                 oi->smb2.out.file.ntvfs         = p->handle;
402                 oi->smb2.out.oplock_level       = oi->smb2.in.oplock_level;
403                 oi->smb2.out.create_action      = NTCREATEX_ACTION_EXISTED;
404                 oi->smb2.out.create_time        = 0;
405                 oi->smb2.out.access_time        = 0;
406                 oi->smb2.out.write_time         = 0;
407                 oi->smb2.out.change_time        = 0;
408                 oi->smb2.out.alloc_size         = p->allocation_size;
409                 oi->smb2.out.size               = 0;
410                 oi->smb2.out.file_attr          = FILE_ATTRIBUTE_NORMAL;
411                 oi->smb2.out.reserved2          = 0;
412                 break;
413         default:
414                 break;
415         }
416
417 reply:
418         req->async_states->status = status;
419         req->async_states->send_fn(req);
420 }
421
422 /*
423   create a directory
424 */
425 static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
426                           struct ntvfs_request *req, union smb_mkdir *md)
427 {
428         return NT_STATUS_ACCESS_DENIED;
429 }
430
431 /*
432   remove a directory
433 */
434 static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
435                           struct ntvfs_request *req, struct smb_rmdir *rd)
436 {
437         return NT_STATUS_ACCESS_DENIED;
438 }
439
440 /*
441   rename a set of files
442 */
443 static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
444                            struct ntvfs_request *req, union smb_rename *ren)
445 {
446         return NT_STATUS_ACCESS_DENIED;
447 }
448
449 /*
450   copy a set of files
451 */
452 static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
453                          struct ntvfs_request *req, struct smb_copy *cp)
454 {
455         return NT_STATUS_ACCESS_DENIED;
456 }
457
458 struct ipc_readv_next_vector_state {
459         uint8_t *buf;
460         size_t len;
461         off_t ofs;
462         size_t remaining;
463 };
464
465 static void ipc_readv_next_vector_init(struct ipc_readv_next_vector_state *s,
466                                        uint8_t *buf, size_t len)
467 {
468         ZERO_STRUCTP(s);
469
470         s->buf = buf;
471         s->len = MIN(len, UINT16_MAX);
472 }
473
474 static int ipc_readv_next_vector(struct tstream_context *stream,
475                                  void *private_data,
476                                  TALLOC_CTX *mem_ctx,
477                                  struct iovec **_vector,
478                                  size_t *count)
479 {
480         struct ipc_readv_next_vector_state *state =
481                 (struct ipc_readv_next_vector_state *)private_data;
482         struct iovec *vector;
483         ssize_t pending;
484         size_t wanted;
485
486         if (state->ofs == state->len) {
487                 *_vector = NULL;
488                 *count = 0;
489                 return 0;
490         }
491
492         pending = tstream_pending_bytes(stream);
493         if (pending == -1) {
494                 return -1;
495         }
496
497         if (pending == 0 && state->ofs != 0) {
498                 /* return a short read */
499                 *_vector = NULL;
500                 *count = 0;
501                 return 0;
502         }
503
504         if (pending == 0) {
505                 /* we want at least one byte and recheck again */
506                 wanted = 1;
507         } else {
508                 size_t missing = state->len - state->ofs;
509                 if (pending > missing) {
510                         /* there's more available */
511                         state->remaining = pending - missing;
512                         wanted = missing;
513                 } else {
514                         /* read what we can get and recheck in the next cycle */
515                         wanted = pending;
516                 }
517         }
518
519         vector = talloc_array(mem_ctx, struct iovec, 1);
520         if (!vector) {
521                 return -1;
522         }
523
524         vector[0].iov_base = (char *) (state->buf + state->ofs);
525         vector[0].iov_len = wanted;
526
527         state->ofs += wanted;
528
529         *_vector = vector;
530         *count = 1;
531         return 0;
532 }
533
534 struct ipc_read_state {
535         struct ipc_private *ipriv;
536         struct pipe_state *p;
537         struct ntvfs_request *req;
538         union smb_read *rd;
539         struct ipc_readv_next_vector_state next_vector;
540 };
541
542 static void ipc_read_done(struct tevent_req *subreq);
543
544 /*
545   read from a file
546 */
547 static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
548                          struct ntvfs_request *req, union smb_read *rd)
549 {
550         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
551                                     struct ipc_private);
552         struct pipe_state *p;
553         struct ipc_read_state *state;
554         struct tevent_req *subreq;
555
556         if (rd->generic.level != RAW_READ_GENERIC) {
557                 return ntvfs_map_read(ntvfs, req, rd);
558         }
559
560         p = pipe_state_find(ipriv, rd->readx.in.file.ntvfs);
561         if (!p) {
562                 return NT_STATUS_INVALID_HANDLE;
563         }
564
565         state = talloc(req, struct ipc_read_state);
566         NT_STATUS_HAVE_NO_MEMORY(state);
567
568         state->ipriv = ipriv;
569         state->p = p;
570         state->req = req;
571         state->rd = rd;
572
573         /* rd->readx.out.data is already allocated */
574         ipc_readv_next_vector_init(&state->next_vector,
575                                    rd->readx.out.data,
576                                    rd->readx.in.maxcnt);
577
578         subreq = tstream_readv_pdu_queue_send(req,
579                                               ipriv->ntvfs->ctx->event_ctx,
580                                               p->npipe,
581                                               p->read_queue,
582                                               ipc_readv_next_vector,
583                                               &state->next_vector);
584         NT_STATUS_HAVE_NO_MEMORY(subreq);
585         tevent_req_set_callback(subreq, ipc_read_done, state);
586
587         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
588         return NT_STATUS_OK;
589 }
590
591 static void ipc_read_done(struct tevent_req *subreq)
592 {
593         struct ipc_read_state *state =
594                 tevent_req_callback_data(subreq,
595                 struct ipc_read_state);
596         struct ntvfs_request *req = state->req;
597         union smb_read *rd = state->rd;
598         int ret;
599         int sys_errno;
600         NTSTATUS status;
601
602         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
603         TALLOC_FREE(subreq);
604         if (ret == -1) {
605                 status = map_nt_error_from_unix_common(sys_errno);
606                 goto reply;
607         }
608
609         status = NT_STATUS_OK;
610         if (state->next_vector.remaining > 0) {
611                 status = STATUS_BUFFER_OVERFLOW;
612         }
613
614         rd->readx.out.remaining = state->next_vector.remaining;
615         rd->readx.out.compaction_mode = 0;
616         rd->readx.out.nread = ret;
617
618 reply:
619         req->async_states->status = status;
620         req->async_states->send_fn(req);
621 }
622
623 struct ipc_write_state {
624         struct ipc_private *ipriv;
625         struct pipe_state *p;
626         struct ntvfs_request *req;
627         union smb_write *wr;
628         struct iovec iov;
629 };
630
631 static void ipc_write_done(struct tevent_req *subreq);
632
633 /*
634   write to a file
635 */
636 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
637                           struct ntvfs_request *req, union smb_write *wr)
638 {
639         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
640                                     struct ipc_private);
641         struct pipe_state *p;
642         struct tevent_req *subreq;
643         struct ipc_write_state *state;
644
645         if (wr->generic.level != RAW_WRITE_GENERIC) {
646                 return ntvfs_map_write(ntvfs, req, wr);
647         }
648
649         p = pipe_state_find(ipriv, wr->writex.in.file.ntvfs);
650         if (!p) {
651                 return NT_STATUS_INVALID_HANDLE;
652         }
653
654         state = talloc(req, struct ipc_write_state);
655         NT_STATUS_HAVE_NO_MEMORY(state);
656
657         state->ipriv = ipriv;
658         state->p = p;
659         state->req = req;
660         state->wr = wr;
661         state->iov.iov_base = discard_const_p(void, wr->writex.in.data);
662         state->iov.iov_len = wr->writex.in.count;
663
664         subreq = tstream_writev_queue_send(state,
665                                            ipriv->ntvfs->ctx->event_ctx,
666                                            p->npipe,
667                                            p->write_queue,
668                                            &state->iov, 1);
669         NT_STATUS_HAVE_NO_MEMORY(subreq);
670         tevent_req_set_callback(subreq, ipc_write_done, state);
671
672         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
673         return NT_STATUS_OK;
674 }
675
676 static void ipc_write_done(struct tevent_req *subreq)
677 {
678         struct ipc_write_state *state =
679                 tevent_req_callback_data(subreq,
680                 struct ipc_write_state);
681         struct ntvfs_request *req = state->req;
682         union smb_write *wr = state->wr;
683         int ret;
684         int sys_errno;
685         NTSTATUS status;
686
687         ret = tstream_writev_queue_recv(subreq, &sys_errno);
688         TALLOC_FREE(subreq);
689         if (ret == -1) {
690                 status = map_nt_error_from_unix_common(sys_errno);
691                 goto reply;
692         }
693
694         status = NT_STATUS_OK;
695
696         wr->writex.out.nwritten = ret;
697         wr->writex.out.remaining = 0;
698
699 reply:
700         req->async_states->status = status;
701         req->async_states->send_fn(req);
702 }
703
704 /*
705   seek in a file
706 */
707 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
708                          struct ntvfs_request *req,
709                          union smb_seek *io)
710 {
711         return NT_STATUS_ACCESS_DENIED;
712 }
713
714 /*
715   flush a file
716 */
717 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
718                           struct ntvfs_request *req,
719                           union smb_flush *io)
720 {
721         return NT_STATUS_ACCESS_DENIED;
722 }
723
724 /*
725   close a file
726 */
727 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
728                           struct ntvfs_request *req, union smb_close *io)
729 {
730         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
731                                     struct ipc_private);
732         struct pipe_state *p;
733
734         if (io->generic.level != RAW_CLOSE_CLOSE) {
735                 return ntvfs_map_close(ntvfs, req, io);
736         }
737
738         p = pipe_state_find(ipriv, io->close.in.file.ntvfs);
739         if (!p) {
740                 return NT_STATUS_INVALID_HANDLE;
741         }
742
743         talloc_free(p);
744
745         return NT_STATUS_OK;
746 }
747
748 /*
749   exit - closing files
750 */
751 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
752                          struct ntvfs_request *req)
753 {
754         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
755                                     struct ipc_private);
756         struct pipe_state *p, *next;
757         
758         for (p=ipriv->pipe_list; p; p=next) {
759                 next = p->next;
760                 if (p->handle->session_info == req->session_info &&
761                     p->handle->smbpid == req->smbpid) {
762                         talloc_free(p);
763                 }
764         }
765
766         return NT_STATUS_OK;
767 }
768
769 /*
770   logoff - closing files open by the user
771 */
772 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
773                            struct ntvfs_request *req)
774 {
775         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
776                                     struct ipc_private);
777         struct pipe_state *p, *next;
778         
779         for (p=ipriv->pipe_list; p; p=next) {
780                 next = p->next;
781                 if (p->handle->session_info == req->session_info) {
782                         talloc_free(p);
783                 }
784         }
785
786         return NT_STATUS_OK;
787 }
788
789 /*
790   setup for an async call
791 */
792 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
793                                 struct ntvfs_request *req,
794                                 void *private_data)
795 {
796         return NT_STATUS_OK;
797 }
798
799 /*
800   cancel an async call
801 */
802 static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
803                            struct ntvfs_request *req)
804 {
805         return NT_STATUS_UNSUCCESSFUL;
806 }
807
808 /*
809   lock a byte range
810 */
811 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
812                          struct ntvfs_request *req, union smb_lock *lck)
813 {
814         return NT_STATUS_ACCESS_DENIED;
815 }
816
817 /*
818   set info on a open file
819 */
820 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
821                                 struct ntvfs_request *req, union smb_setfileinfo *info)
822 {
823         return NT_STATUS_ACCESS_DENIED;
824 }
825
826 /*
827   query info on a open file
828 */
829 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
830                               struct ntvfs_request *req, union smb_fileinfo *info)
831 {
832         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
833                                     struct ipc_private);
834         struct pipe_state *p = pipe_state_find(ipriv, info->generic.in.file.ntvfs);
835         if (!p) {
836                 return NT_STATUS_INVALID_HANDLE;
837         }
838         switch (info->generic.level) {
839         case RAW_FILEINFO_GENERIC: 
840         {
841                 ZERO_STRUCT(info->generic.out);
842                 info->generic.out.attrib = FILE_ATTRIBUTE_NORMAL;
843                 info->generic.out.fname.s = strrchr(p->pipe_name, '\\');
844                 info->generic.out.alloc_size = 4096;
845                 info->generic.out.nlink = 1;
846                 /* What the heck?  Match Win2k3: IPC$ pipes are delete pending */
847                 info->generic.out.delete_pending = 1;
848                 return NT_STATUS_OK;
849         }
850         case RAW_FILEINFO_ALT_NAME_INFO:
851         case RAW_FILEINFO_ALT_NAME_INFORMATION:
852         case RAW_FILEINFO_STREAM_INFO:
853         case RAW_FILEINFO_STREAM_INFORMATION:
854         case RAW_FILEINFO_COMPRESSION_INFO:
855         case RAW_FILEINFO_COMPRESSION_INFORMATION:
856         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
857         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
858                 return NT_STATUS_INVALID_PARAMETER;
859         case  RAW_FILEINFO_ALL_EAS:
860                 return NT_STATUS_ACCESS_DENIED;
861         default:
862                 return ntvfs_map_qfileinfo(ntvfs, req, info);
863         }
864 }
865
866
867 /*
868   return filesystem info
869 */
870 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
871                            struct ntvfs_request *req, union smb_fsinfo *fs)
872 {
873         return NT_STATUS_ACCESS_DENIED;
874 }
875
876 /*
877   return print queue info
878 */
879 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
880                         struct ntvfs_request *req, union smb_lpq *lpq)
881 {
882         return NT_STATUS_ACCESS_DENIED;
883 }
884
885 /* 
886    list files in a directory matching a wildcard pattern
887 */
888 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
889                           struct ntvfs_request *req, union smb_search_first *io,
890                           void *search_private, 
891                           bool (*callback)(void *, const union smb_search_data *))
892 {
893         return NT_STATUS_ACCESS_DENIED;
894 }
895
896 /* 
897    continue listing files in a directory 
898 */
899 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
900                          struct ntvfs_request *req, union smb_search_next *io,
901                          void *search_private, 
902                          bool (*callback)(void *, const union smb_search_data *))
903 {
904         return NT_STATUS_ACCESS_DENIED;
905 }
906
907 /* 
908    end listing files in a directory 
909 */
910 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
911                           struct ntvfs_request *req, union smb_search_close *io)
912 {
913         return NT_STATUS_ACCESS_DENIED;
914 }
915
916 struct ipc_trans_state {
917         struct ipc_private *ipriv;
918         struct pipe_state *p;
919         struct ntvfs_request *req;
920         struct smb_trans2 *trans;
921         struct iovec writev_iov;
922         struct ipc_readv_next_vector_state next_vector;
923 };
924
925 static void ipc_trans_writev_done(struct tevent_req *subreq);
926 static void ipc_trans_readv_done(struct tevent_req *subreq);
927
928 /* SMBtrans - handle a DCERPC command */
929 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
930                                struct ntvfs_request *req, struct smb_trans2 *trans)
931 {
932         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
933                                     struct ipc_private);
934         struct pipe_state *p;
935         DATA_BLOB fnum_key;
936         uint16_t fnum;
937         struct ipc_trans_state *state;
938         struct tevent_req *subreq;
939
940         /*
941          * the fnum is in setup[1], a 16 bit value
942          * the setup[*] values are already in host byteorder
943          * but ntvfs_handle_search_by_wire_key() expects
944          * network byteorder
945          */
946         SSVAL(&fnum, 0, trans->in.setup[1]);
947         fnum_key = data_blob_const(&fnum, 2);
948
949         p = pipe_state_find_key(ipriv, req, &fnum_key);
950         if (!p) {
951                 return NT_STATUS_INVALID_HANDLE;
952         }
953
954         /*
955          * Trans requests are only allowed
956          * if no other Trans or Read is active
957          */
958         if (tevent_queue_length(p->read_queue) > 0) {
959                 return NT_STATUS_PIPE_BUSY;
960         }
961
962         state = talloc(req, struct ipc_trans_state);
963         NT_STATUS_HAVE_NO_MEMORY(state);
964
965         trans->out.setup_count = 0;
966         trans->out.setup = NULL;
967         trans->out.params = data_blob(NULL, 0);
968         trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
969         NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
970
971         state->ipriv = ipriv;
972         state->p = p;
973         state->req = req;
974         state->trans = trans;
975         state->writev_iov.iov_base = (char *) trans->in.data.data;
976         state->writev_iov.iov_len = trans->in.data.length;
977
978         ipc_readv_next_vector_init(&state->next_vector,
979                                    trans->out.data.data,
980                                    trans->out.data.length);
981
982         subreq = tstream_writev_queue_send(state,
983                                            ipriv->ntvfs->ctx->event_ctx,
984                                            p->npipe,
985                                            p->write_queue,
986                                            &state->writev_iov, 1);
987         NT_STATUS_HAVE_NO_MEMORY(subreq);
988         tevent_req_set_callback(subreq, ipc_trans_writev_done, state);
989
990         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
991         return NT_STATUS_OK;
992 }
993
994 static void ipc_trans_writev_done(struct tevent_req *subreq)
995 {
996         struct ipc_trans_state *state =
997                 tevent_req_callback_data(subreq,
998                 struct ipc_trans_state);
999         struct ipc_private *ipriv = state->ipriv;
1000         struct pipe_state *p = state->p;
1001         struct ntvfs_request *req = state->req;
1002         int ret;
1003         int sys_errno;
1004         NTSTATUS status;
1005
1006         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1007         TALLOC_FREE(subreq);
1008         if (ret == 0) {
1009                 status = NT_STATUS_PIPE_DISCONNECTED;
1010                 goto reply;
1011         } else if (ret == -1) {
1012                 status = map_nt_error_from_unix_common(sys_errno);
1013                 goto reply;
1014         }
1015
1016         subreq = tstream_readv_pdu_queue_send(state,
1017                                               ipriv->ntvfs->ctx->event_ctx,
1018                                               p->npipe,
1019                                               p->read_queue,
1020                                               ipc_readv_next_vector,
1021                                               &state->next_vector);
1022         if (!subreq) {
1023                 status = NT_STATUS_NO_MEMORY;
1024                 goto reply;
1025         }
1026         tevent_req_set_callback(subreq, ipc_trans_readv_done, state);
1027         return;
1028
1029 reply:
1030         req->async_states->status = status;
1031         req->async_states->send_fn(req);
1032 }
1033
1034 static void ipc_trans_readv_done(struct tevent_req *subreq)
1035 {
1036         struct ipc_trans_state *state =
1037                 tevent_req_callback_data(subreq,
1038                 struct ipc_trans_state);
1039         struct ntvfs_request *req = state->req;
1040         struct smb_trans2 *trans = state->trans;
1041         int ret;
1042         int sys_errno;
1043         NTSTATUS status;
1044
1045         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
1046         TALLOC_FREE(subreq);
1047         if (ret == -1) {
1048                 status = map_nt_error_from_unix_common(sys_errno);
1049                 goto reply;
1050         }
1051
1052         status = NT_STATUS_OK;
1053         if (state->next_vector.remaining > 0) {
1054                 status = STATUS_BUFFER_OVERFLOW;
1055         }
1056
1057         trans->out.data.length = ret;
1058
1059 reply:
1060         req->async_states->status = status;
1061         req->async_states->send_fn(req);
1062 }
1063
1064 /* SMBtrans - set named pipe state */
1065 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
1066                                       struct ntvfs_request *req, struct smb_trans2 *trans)
1067 {
1068         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
1069                                     struct ipc_private);
1070         struct pipe_state *p;
1071         DATA_BLOB fnum_key;
1072
1073         /* the fnum is in setup[1] */
1074         fnum_key = data_blob_const(&trans->in.setup[1], sizeof(trans->in.setup[1]));
1075
1076         p = pipe_state_find_key(ipriv, req, &fnum_key);
1077         if (!p) {
1078                 return NT_STATUS_INVALID_HANDLE;
1079         }
1080
1081         if (trans->in.params.length != 2) {
1082                 return NT_STATUS_INVALID_PARAMETER;
1083         }
1084
1085         /*
1086          * TODO: pass this to the tstream_npa logic
1087          */
1088         p->device_state = SVAL(trans->in.params.data, 0);
1089
1090         trans->out.setup_count = 0;
1091         trans->out.setup = NULL;
1092         trans->out.params = data_blob(NULL, 0);
1093         trans->out.data = data_blob(NULL, 0);
1094
1095         return NT_STATUS_OK;
1096 }
1097
1098
1099 /* SMBtrans - used to provide access to SMB pipes */
1100 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
1101                                 struct ntvfs_request *req, struct smb_trans2 *trans)
1102 {
1103         NTSTATUS status;
1104
1105         if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
1106                 return ipc_rap_call(req, ntvfs->ctx->event_ctx, ntvfs->ctx->lp_ctx, trans);
1107
1108         if (trans->in.setup_count != 2) {
1109                 return NT_STATUS_INVALID_PARAMETER;
1110         }
1111
1112         switch (trans->in.setup[0]) {
1113         case TRANSACT_SETNAMEDPIPEHANDLESTATE:
1114                 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
1115                 break;
1116         case TRANSACT_DCERPCCMD:
1117                 status = ipc_dcerpc_cmd(ntvfs, req, trans);
1118                 break;
1119         default:
1120                 status = NT_STATUS_INVALID_PARAMETER;
1121                 break;
1122         }
1123
1124         return status;
1125 }
1126
1127 struct ipc_ioctl_state {
1128         struct ipc_private *ipriv;
1129         struct pipe_state *p;
1130         struct ntvfs_request *req;
1131         union smb_ioctl *io;
1132         struct iovec writev_iov;
1133         struct ipc_readv_next_vector_state next_vector;
1134 };
1135
1136 static void ipc_ioctl_writev_done(struct tevent_req *subreq);
1137 static void ipc_ioctl_readv_done(struct tevent_req *subreq);
1138
1139 static NTSTATUS ipc_ioctl_smb2(struct ntvfs_module_context *ntvfs,
1140                                struct ntvfs_request *req, union smb_ioctl *io)
1141 {
1142         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
1143                                     struct ipc_private);
1144         struct pipe_state *p;
1145         struct ipc_ioctl_state *state;
1146         struct tevent_req *subreq;
1147
1148         switch (io->smb2.in.function) {
1149         case FSCTL_NAMED_PIPE_READ_WRITE:
1150                 break;
1151
1152         default:
1153                 return NT_STATUS_FS_DRIVER_REQUIRED;
1154         }
1155
1156         p = pipe_state_find(ipriv, io->smb2.in.file.ntvfs);
1157         if (!p) {
1158                 return NT_STATUS_INVALID_HANDLE;
1159         }
1160
1161         /*
1162          * Trans requests are only allowed
1163          * if no other Trans or Read is active
1164          */
1165         if (tevent_queue_length(p->read_queue) > 0) {
1166                 return NT_STATUS_PIPE_BUSY;
1167         }
1168
1169         state = talloc(req, struct ipc_ioctl_state);
1170         NT_STATUS_HAVE_NO_MEMORY(state);
1171
1172         io->smb2.out._pad       = 0;
1173         io->smb2.out.function   = io->smb2.in.function;
1174         io->smb2.out.unknown2   = 0;
1175         io->smb2.out.unknown3   = 0;
1176         io->smb2.out.in         = io->smb2.in.out;
1177         io->smb2.out.out = data_blob_talloc(req, NULL, io->smb2.in.max_response_size);
1178         NT_STATUS_HAVE_NO_MEMORY(io->smb2.out.out.data);
1179
1180         state->ipriv = ipriv;
1181         state->p = p;
1182         state->req = req;
1183         state->io = io;
1184         state->writev_iov.iov_base = (char *) io->smb2.in.out.data;
1185         state->writev_iov.iov_len = io->smb2.in.out.length;
1186
1187         ipc_readv_next_vector_init(&state->next_vector,
1188                                    io->smb2.out.out.data,
1189                                    io->smb2.out.out.length);
1190
1191         subreq = tstream_writev_queue_send(state,
1192                                            ipriv->ntvfs->ctx->event_ctx,
1193                                            p->npipe,
1194                                            p->write_queue,
1195                                            &state->writev_iov, 1);
1196         NT_STATUS_HAVE_NO_MEMORY(subreq);
1197         tevent_req_set_callback(subreq, ipc_ioctl_writev_done, state);
1198
1199         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1200         return NT_STATUS_OK;
1201 }
1202
1203 static void ipc_ioctl_writev_done(struct tevent_req *subreq)
1204 {
1205         struct ipc_ioctl_state *state =
1206                 tevent_req_callback_data(subreq,
1207                 struct ipc_ioctl_state);
1208         struct ipc_private *ipriv = state->ipriv;
1209         struct pipe_state *p = state->p;
1210         struct ntvfs_request *req = state->req;
1211         int ret;
1212         int sys_errno;
1213         NTSTATUS status;
1214
1215         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1216         TALLOC_FREE(subreq);
1217         if (ret == -1) {
1218                 status = map_nt_error_from_unix_common(sys_errno);
1219                 goto reply;
1220         }
1221
1222         subreq = tstream_readv_pdu_queue_send(state,
1223                                               ipriv->ntvfs->ctx->event_ctx,
1224                                               p->npipe,
1225                                               p->read_queue,
1226                                               ipc_readv_next_vector,
1227                                               &state->next_vector);
1228         if (!subreq) {
1229                 status = NT_STATUS_NO_MEMORY;
1230                 goto reply;
1231         }
1232         tevent_req_set_callback(subreq, ipc_ioctl_readv_done, state);
1233         return;
1234
1235 reply:
1236         req->async_states->status = status;
1237         req->async_states->send_fn(req);
1238 }
1239
1240 static void ipc_ioctl_readv_done(struct tevent_req *subreq)
1241 {
1242         struct ipc_ioctl_state *state =
1243                 tevent_req_callback_data(subreq,
1244                 struct ipc_ioctl_state);
1245         struct ntvfs_request *req = state->req;
1246         union smb_ioctl *io = state->io;
1247         int ret;
1248         int sys_errno;
1249         NTSTATUS status;
1250
1251         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
1252         TALLOC_FREE(subreq);
1253         if (ret == -1) {
1254                 status = map_nt_error_from_unix_common(sys_errno);
1255                 goto reply;
1256         }
1257
1258         status = NT_STATUS_OK;
1259         if (state->next_vector.remaining > 0) {
1260                 status = STATUS_BUFFER_OVERFLOW;
1261         }
1262
1263         io->smb2.out.out.length = ret;
1264
1265 reply:
1266         req->async_states->status = status;
1267         req->async_states->send_fn(req);
1268 }
1269
1270 /*
1271   ioctl interface
1272 */
1273 static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
1274                           struct ntvfs_request *req, union smb_ioctl *io)
1275 {
1276         switch (io->generic.level) {
1277         case RAW_IOCTL_SMB2:
1278                 return ipc_ioctl_smb2(ntvfs, req, io);
1279
1280         case RAW_IOCTL_SMB2_NO_HANDLE:
1281                 return NT_STATUS_FS_DRIVER_REQUIRED;
1282
1283         default:
1284                 return NT_STATUS_ACCESS_DENIED;
1285         }
1286 }
1287
1288
1289 /*
1290   initialialise the IPC backend, registering ourselves with the ntvfs subsystem
1291  */
1292 NTSTATUS ntvfs_ipc_init(void)
1293 {
1294         NTSTATUS ret;
1295         struct ntvfs_ops ops;
1296         NTVFS_CURRENT_CRITICAL_SIZES(vers);
1297
1298         ZERO_STRUCT(ops);
1299         
1300         /* fill in the name and type */
1301         ops.name = "default";
1302         ops.type = NTVFS_IPC;
1303
1304         /* fill in all the operations */
1305         ops.connect = ipc_connect;
1306         ops.disconnect = ipc_disconnect;
1307         ops.unlink = ipc_unlink;
1308         ops.chkpath = ipc_chkpath;
1309         ops.qpathinfo = ipc_qpathinfo;
1310         ops.setpathinfo = ipc_setpathinfo;
1311         ops.open = ipc_open;
1312         ops.mkdir = ipc_mkdir;
1313         ops.rmdir = ipc_rmdir;
1314         ops.rename = ipc_rename;
1315         ops.copy = ipc_copy;
1316         ops.ioctl = ipc_ioctl;
1317         ops.read = ipc_read;
1318         ops.write = ipc_write;
1319         ops.seek = ipc_seek;
1320         ops.flush = ipc_flush;  
1321         ops.close = ipc_close;
1322         ops.exit = ipc_exit;
1323         ops.lock = ipc_lock;
1324         ops.setfileinfo = ipc_setfileinfo;
1325         ops.qfileinfo = ipc_qfileinfo;
1326         ops.fsinfo = ipc_fsinfo;
1327         ops.lpq = ipc_lpq;
1328         ops.search_first = ipc_search_first;
1329         ops.search_next = ipc_search_next;
1330         ops.search_close = ipc_search_close;
1331         ops.trans = ipc_trans;
1332         ops.logoff = ipc_logoff;
1333         ops.async_setup = ipc_async_setup;
1334         ops.cancel = ipc_cancel;
1335
1336         /* register ourselves with the NTVFS subsystem. */
1337         ret = ntvfs_register(&ops, &vers);
1338
1339         if (!NT_STATUS_IS_OK(ret)) {
1340                 DEBUG(0,("Failed to register IPC backend!\n"));
1341                 return ret;
1342         }
1343
1344         return ret;
1345 }